diff --git a/.editorconfig b/.editorconfig index c8d511ec..05d09a66 100644 --- a/.editorconfig +++ b/.editorconfig @@ -14,3 +14,8 @@ trim_trailing_whitespace = true [{CMakeLists.txt,*.cmake}] indent_size = 2 +insert_final_newline = true + +[*.{json,xml.in,desktop.in}] +indent_size = 2 +insert_final_newline = true diff --git a/.gitattributes b/.gitattributes index 232342c7..04926c6b 100644 --- a/.gitattributes +++ b/.gitattributes @@ -5,3 +5,7 @@ *.html text eol=lf diff=html *.mdp binary *.mak text eol=crlf +**/*.ico binary +**/*.png binary +**/*.svg text eol=lf +**/*.desktop text eol=lf diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7d688877..0aefef65 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,6 +25,7 @@ jobs: build: name: ${{ matrix.name }} runs-on: ${{ matrix.os }} + container: ${{ matrix.container || '' }} defaults: run: shell: ${{ matrix.shell || 'sh' }} @@ -33,14 +34,19 @@ jobs: fail-fast: false matrix: include: - - { name: 'Linux', os: 'ubuntu-latest', dx5: false, config: true, build-type: 'Debug', linux: true, werror: true, clang-tidy: true } - - { name: 'MSVC (x86)', os: 'windows-latest', dx5: true, config: false, build-type: 'Debug', msvc: true, werror: false, clang-tidy: false, vc-arch: 'amd64_x86' } - - { name: 'MSVC (x64)', os: 'windows-latest', dx5: false, config: false, build-type: 'Debug', msvc: true, werror: false, clang-tidy: false, vc-arch: 'amd64' } - - { name: 'MSVC (arm64)', os: 'windows-latest', dx5: false, config: false, build-type: 'Debug', msvc: true, werror: false, clang-tidy: false, vc-arch: 'amd64_arm64' } - - { name: 'msys2 mingw32', os: 'windows-latest', dx5: false, config: false, build-type: 'Debug', mingw: true, werror: true, clang-tidy: true, msystem: 'mingw32', msys-env: 'mingw-w64-i686', shell: 'msys2 {0}' } - - { name: 'msys2 mingw64', os: 'windows-latest', dx5: false, config: true, build-type: 'Debug', mingw: true, werror: true, clang-tidy: true, msystem: 'mingw64', msys-env: 'mingw-w64-x86_64', shell: 'msys2 {0}' } - - { name: 'macOS', os: 'macos-latest', dx5: false, config: true, build-type: 'Debug', brew: true, werror: true, clang-tidy: false } - - { name: 'Emscripten', os: 'ubuntu-latest', dx5: false, config: false, build-type: 'Debug', emsdk: true, werror: true, clang-tidy: false, cmake-wrapper: 'emcmake' } + - { name: 'Linux', os: 'ubuntu-latest', generator: 'Ninja', dx5: false, config: true, linux: true, werror: true, clang-tidy: true } + - { name: 'Linux (Debug)', os: 'ubuntu-latest', generator: 'Ninja', dx5: false, config: true, linux: true, werror: true, clang-tidy: true, debug: true } + - { name: 'MSVC (x86)', os: 'windows-latest', generator: 'Ninja', dx5: true, config: false, msvc: true, werror: false, clang-tidy: false, vc-arch: 'amd64_x86' } + - { name: 'MSVC (x64)', os: 'windows-latest', generator: 'Ninja', dx5: false, config: true, msvc: true, werror: false, clang-tidy: false, vc-arch: 'amd64' } + - { name: 'MSVC (x64 Debug)', os: 'windows-latest', generator: 'Ninja', dx5: false, config: true, msvc: true, werror: false, clang-tidy: false, vc-arch: 'amd64', debug: true } + - { name: 'MSVC (arm64)', os: 'windows-latest', generator: 'Ninja', dx5: false, config: false, msvc: true, werror: false, clang-tidy: false, vc-arch: 'amd64_arm64' } + - { name: 'msys2 mingw32', os: 'windows-latest', generator: 'Ninja', dx5: false, config: false, mingw: true, werror: true, clang-tidy: true, msystem: 'mingw32', msys-env: 'mingw-w64-i686', shell: 'msys2 {0}' } + - { name: 'msys2 mingw64', os: 'windows-latest', generator: 'Ninja', dx5: false, config: true, mingw: true, werror: true, clang-tidy: true, msystem: 'mingw64', msys-env: 'mingw-w64-x86_64', shell: 'msys2 {0}' } + - { name: 'macOS', os: 'macos-latest', generator: 'Ninja', dx5: false, config: true, brew: true, werror: true, clang-tidy: false } + - { name: 'iOS', os: 'macos-15', generator: 'Xcode', dx5: false, config: false, brew: true, werror: true, clang-tidy: false, cmake-args: '-DCMAKE_SYSTEM_NAME=iOS' } + - { 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: '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} steps: - name: Setup vcvars if: ${{ !!matrix.msvc }} @@ -59,6 +65,20 @@ jobs: ${{ matrix.msys-env }}-ninja ${{ matrix.msys-env }}-clang-tools-extra ${{ (matrix.config && format('{0}-qt6-base', matrix.msys-env)) || '' }} + - name: Install Qt + if: ${{ !!matrix.msvc && matrix.config }} + uses: jurplel/install-qt-action@v4 + with: + cache: 'true' + + - name: Install 3DS dependencies + if: ${{ matrix.n3ds }} + run: | + wget https://github.com/diasurgical/bannertool/releases/download/1.2.0/bannertool.zip + unzip -j "bannertool.zip" "linux-x86_64/bannertool" -d "/opt/devkitpro/tools/bin" + wget https://github.com/3DSGuy/Project_CTR/releases/download/makerom-v0.18/makerom-v0.18-ubuntu_x86_64.zip + unzip "makerom-v0.18-ubuntu_x86_64.zip" "makerom" -d "/opt/devkitpro/tools/bin" + chmod a+x /opt/devkitpro/tools/bin/makerom - name: Install Linux dependencies (apt-get) if: ${{ matrix.linux }} @@ -66,8 +86,8 @@ jobs: sudo apt-get update sudo apt-get install -y \ libx11-dev libxext-dev libxrandr-dev libxrender-dev libxfixes-dev libxi-dev libxinerama-dev \ - libxcursor-dev libwayland-dev libxkbcommon-dev wayland-protocols libgl1-mesa-dev libglew-dev qt6-base-dev \ - libasound2-dev + libxcursor-dev libwayland-dev libxkbcommon-dev wayland-protocols libgl1-mesa-dev qt6-base-dev \ + libasound2-dev qt6-xdgdesktopportal-platformtheme - name: Install macOS dependencies (brew) if: ${{ matrix.brew }} @@ -88,27 +108,106 @@ jobs: - name: Configure (CMake) run: | - ${{ matrix.cmake-wrapper || '' }} cmake -S . -B build -GNinja \ - -DCMAKE_BUILD_TYPE=${{ matrix.build-type }} \ + ${{ matrix.cmake-wrapper || '' }} cmake -S . -B build -G "${{ matrix.generator }}" \ + ${{ matrix.cmake-args || '' }} \ + -DCMAKE_BUILD_TYPE=Release \ -DISLE_USE_DX5=${{ !!matrix.dx5 }} \ - -DISLE_BUILD_CONFIG=${{ matrix.config }} \ + -DISLE_BUILD_CONFIG=${{ !!matrix.config }} \ -DENABLE_CLANG_TIDY=${{ !!matrix.clang-tidy }} \ -DISLE_WERROR=${{ !!matrix.werror }} \ + -DISLE_DEBUG=${{ matrix.debug || 'OFF' }} \ -Werror=dev - name: Build (CMake) - run: cmake --build build --verbose + run: cmake --build build --verbose --config Release - name: Package (CPack) + if: ${{ !matrix.n3ds }} run: | cd build - cpack . + success=0 + max_tries=10 + for i in $(seq $max_tries); do + cpack . && success=1 + if test $success = 1; then + break + fi + echo "Package creation failed. Sleep 1 second and try again." + sleep 1 + done + if test $success = 0; then + echo "Package creation failed after $max_tries attempts." + exit 1 + fi + + - name: Install linuxdeploy + if: ${{ matrix.linux }} + id: install-linuxdeploy + uses: miurahr/install-linuxdeploy-action@v1.8.0 + with: + plugins: qt appimage + + - name: Package (AppImage) + if: ${{ matrix.linux }} + run: | + cd build && \ + export LD_LIBRARY_PATH=".:$LD_LIBRARY_PATH" && \ + NO_STRIP=1 ${{ steps.install-linuxdeploy.outputs.linuxdeploy }} \ + -p qt \ + -e isle \ + -e isle-config \ + -d packaging/linux/org.legoisland.Isle.desktop \ + -i icons/org.legoisland.Isle.svg \ + --custom-apprun=../packaging/linux/appimage/AppRun \ + --appdir packaging/linux/appimage/AppDir \ + --output appimage && \ + mv *.AppImage dist/ + + - name: Package (3DS) + if: ${{ matrix.n3ds }} + run: | + cd build + mkdir dist + mv *.3dsx dist/ + mv *.cia dist/ - name: Upload Build Artifacts uses: actions/upload-artifact@v4 with: - name: '${{ matrix.name }} ${{ matrix.build-type }}' - path: build/dist/isle-* + name: '${{ matrix.name }}' + path: | + build/dist/isle-* + build/dist/*.AppImage + build/dist/*.3dsx + build/dist/*.cia + + flatpak: + name: "Flatpak (${{ matrix.arch }})" + runs-on: ${{ matrix.os }} + + strategy: + fail-fast: false + matrix: + include: + - arch: x86_64 + os: ubuntu-latest + + - arch: aarch64 + os: ubuntu-22.04-arm + + container: + image: ghcr.io/flathub-infra/flatpak-github-actions:kde-6.8 + options: --privileged + + steps: + - uses: actions/checkout@v4 + + - name: Build Flatpak + uses: flatpak/flatpak-github-actions/flatpak-builder@v6 + with: + bundle: org.legoisland.Isle.${{ matrix.arch }}.flatpak + manifest-path: packaging/linux/flatpak/org.legoisland.Isle.json + arch: ${{ matrix.arch }} ncc: name: 'C++' @@ -148,3 +247,30 @@ jobs: LEGO1/omni/src/video/flic.cpp \ $action_headers \ --path LEGO1/omni LEGO1/lego/legoomni + + release: + name: 'Release' + if: ${{ github.event_name == 'push' && github.ref_name == 'master' }} + runs-on: ubuntu-latest + needs: + - build + - flatpak + steps: + - name: Download All Artifacts + uses: actions/download-artifact@main + with: + pattern: "*" + path: Release + merge-multiple: true + + - name: Checkout uploadtool + uses: actions/checkout@v4 + with: + repository: 'probonopd/uploadtool' + path: 'uploadtool' + + - name: Upload Continuous Release + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + ./uploadtool/upload.sh Release/* diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml new file mode 100644 index 00000000..ca316590 --- /dev/null +++ b/.github/workflows/docker.yml @@ -0,0 +1,55 @@ +name: Docker + +on: + push: + branches: ['master'] + +env: + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }}-emscripten + +jobs: + publish-emscripten: + name: Publish web port + env: + IMAGE_NAME: ${{ github.repository }}-emscripten + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + attestations: write + id-token: write + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Log in to the Container registry + uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + + - name: Build and push Docker image + id: push + uses: docker/build-push-action@f2a1d5e99d037542a71f64918e516c093c6f3fc4 + with: + file: docker/emscripten/Dockerfile + context: . + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + + - name: Generate artifact attestation + uses: actions/attest-build-provenance@v2 + with: + subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME}} + subject-digest: ${{ steps.push.outputs.digest }} + push-to-registry: true diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml deleted file mode 100644 index 0e4c6cc9..00000000 --- a/.github/workflows/release.yml +++ /dev/null @@ -1,116 +0,0 @@ -name: Release - -on: - push: - branches: - - master - -jobs: - build: - name: ${{ matrix.name }} - runs-on: ${{ matrix.os }} - defaults: - run: - shell: ${{ matrix.shell || 'sh' }} - - strategy: - fail-fast: false - matrix: - include: - - { name: 'Linux', os: 'ubuntu-latest', dx5: false, config: true, build-type: 'Release', linux: true, werror: true, clang-tidy: false } - - { name: 'Windows', os: 'windows-latest', dx5: false, config: false, build-type: 'Release', msvc: true, werror: false, clang-tidy: false, vc-arch: 'amd64' } - - { name: 'macOS', os: 'macos-latest', dx5: false, config: true, build-type: 'Release', brew: true, werror: true, clang-tidy: false } - steps: - - name: Setup vcvars - if: ${{ !!matrix.msvc }} - uses: ilammy/msvc-dev-cmd@v1 - with: - arch: ${{ matrix.vc-arch }} - - - name: Set up MSYS2 - if: ${{ !!matrix.msystem }} - uses: msys2/setup-msys2@v2 - with: - msystem: ${{ matrix.msystem }} - install: >- - ${{ matrix.msys-env }}-cc - ${{ matrix.msys-env }}-cmake - ${{ matrix.msys-env }}-ninja - ${{ matrix.msys-env }}-clang-tools-extra - ${{ (matrix.config && format('{0}-qt6-base', matrix.msys-env)) || '' }} - - - name: Install Linux dependencies (apt-get) - if: ${{ matrix.linux }} - run: | - sudo apt-get update - sudo apt-get install -y \ - libx11-dev libxext-dev libxrandr-dev libxrender-dev libxfixes-dev libxi-dev libxinerama-dev \ - libxcursor-dev libwayland-dev libxkbcommon-dev wayland-protocols libgl1-mesa-dev libglew-dev qt6-base-dev \ - libasound2-dev - - - name: Install macOS dependencies (brew) - if: ${{ matrix.brew }} - run: | - brew update - brew install cmake ninja llvm qt6 - echo "LLVM_ROOT=$(brew --prefix llvm)/bin" >> $GITHUB_ENV - - - name: Setup Emscripten - uses: mymindstorm/setup-emsdk@master - if: ${{ matrix.emsdk }} - - - name: Setup ninja - if: ${{ matrix.msvc }} - uses: ashutoshvarma/setup-ninja@master - - - uses: actions/checkout@v4 - - - name: Configure (CMake) - run: | - ${{ matrix.cmake-wrapper || '' }} cmake -S . -B build -GNinja \ - -DCMAKE_BUILD_TYPE=${{ matrix.build-type }} \ - -DISLE_USE_DX5=${{ !!matrix.dx5 }} \ - -DISLE_BUILD_CONFIG=${{ matrix.config }} \ - -DENABLE_CLANG_TIDY=${{ !!matrix.clang-tidy }} \ - -DISLE_WERROR=${{ !!matrix.werror }} \ - -DISLE_DEBUG=OFF \ - -Werror=dev - - - name: Build (CMake) - run: cmake --build build --verbose - - - name: Package (CPack) - run: | - cd build - cpack . - - - name: Upload Artifact - uses: actions/upload-artifact@main - with: - name: Release-${{ matrix.name }} - path: | - build/dist/isle-* - - release: - name: 'Release' - runs-on: ubuntu-latest - needs: build - steps: - - name: Download All Artifacts - uses: actions/download-artifact@main - with: - pattern: Release-* - path: Release - merge-multiple: true - - - name: Checkout uploadtool - uses: actions/checkout@v4 - with: - repository: 'probonopd/uploadtool' - path: 'uploadtool' - - - name: Upload Continuous Release - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - ./uploadtool/upload.sh Release/* diff --git a/.gitignore b/.gitignore index 662466db..1610ba3d 100644 --- a/.gitignore +++ b/.gitignore @@ -30,3 +30,9 @@ LEGO1.DLL # Kate - Text /.cache + +# Flatpak build cache +**/.flatpak-builder/ + +# Flatpak build dir +**/flatpak-build/ diff --git a/.pylintrc b/.pylintrc index ab83fceb..68704fad 100644 --- a/.pylintrc +++ b/.pylintrc @@ -88,7 +88,7 @@ persistent=yes # Minimum Python version to use for version dependent checks. Will default to # the version used to run pylint. -py-version=3.11 +py-version=3.12 # Discover python modules and packages in the file system subtree. recursive=no diff --git a/cmake/Findiniparser.cmake b/CMake/Findiniparser.cmake similarity index 100% rename from cmake/Findiniparser.cmake rename to CMake/Findiniparser.cmake diff --git a/CMake/detectcpu.cmake b/CMake/detectcpu.cmake new file mode 100644 index 00000000..e0b6feae --- /dev/null +++ b/CMake/detectcpu.cmake @@ -0,0 +1,156 @@ +function(DetectTargetCPUArchitectures DETECTED_ARCHS) + + set(known_archs EMSCRIPTEN ARM32 ARM64 ARM64EC LOONGARCH64 POWERPC32 POWERPC64 X86 X64) + + if(APPLE AND CMAKE_OSX_ARCHITECTURES) + foreach(known_arch IN LISTS known_archs) + set(CPU_${known_arch} "0" PARENT_SCOPE) + endforeach() + set(detected_archs) + foreach(osx_arch IN LISTS CMAKE_OSX_ARCHITECTURES) + if(osx_arch STREQUAL "x86_64") + set(CPU_X64 "1" PARENT_SCOPE) + list(APPEND detected_archs "X64") + elseif(osx_arch STREQUAL "arm64") + set(CPU_ARM64 "1" PARENT_SCOPE) + list(APPEND detected_archs "ARM64") + endif() + endforeach() + set("${DETECTED_ARCHS}" "${detected_archs}" PARENT_SCOPE) + return() + endif() + + set(detected_archs) + foreach(known_arch IN LISTS known_archs) + if(CPU_${known_arch}) + list(APPEND detected_archs "${known_arch}") + endif() + endforeach() + + if(detected_archs) + set("${DETECTED_ARCHS}" "${detected_archs}" PARENT_SCOPE) + return() + endif() + + set(arch_check_ARM32 "defined(__arm__) || defined(_M_ARM)") + set(arch_check_ARM64 "defined(__aarch64__) || defined(_M_ARM64)") + set(arch_check_ARM64EC "defined(_M_ARM64EC)") + set(arch_check_EMSCRIPTEN "defined(__EMSCRIPTEN__)") + set(arch_check_LOONGARCH64 "defined(__loongarch64)") + set(arch_check_POWERPC32 "(defined(__PPC__) || defined(__powerpc__)) && !defined(__powerpc64__)") + set(arch_check_POWERPC64 "defined(__PPC64__) || defined(__powerpc64__)") + set(arch_check_X86 "defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__) ||defined( __i386) || defined(_M_IX86)") + set(arch_check_X64 "(defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) || defined(_M_AMD64)) && !defined(_M_ARM64EC)") + + set(src_vars "") + set(src_main "") + foreach(known_arch IN LISTS known_archs) + set(detected_${known_arch} "0") + + string(APPEND src_vars " +#if ${arch_check_${known_arch}} +#define ARCH_${known_arch} \"1\" +#else +#define ARCH_${known_arch} \"0\" +#endif +const char *arch_${known_arch} = \"INFO<${known_arch}=\" ARCH_${known_arch} \">\"; +") + string(APPEND src_main " + result += arch_${known_arch}[argc];") + endforeach() + + set(src_arch_detect "${src_vars} +int main(int argc, char *argv[]) { + int result = 0; + (void)argv; +${src_main} + return result; +}") + + if(CMAKE_C_COMPILER) + set(ext ".c") + elseif(CMAKE_CXX_COMPILER) + set(ext ".cpp") + else() + enable_language(C) + set(ext ".c") + endif() + set(path_src_arch_detect "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/CMakeTmp/detect_arch${ext}") + file(WRITE "${path_src_arch_detect}" "${src_arch_detect}") + set(path_dir_arch_detect "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/CMakeTmp/detect_arch") + set(path_bin_arch_detect "${path_dir_arch_detect}/bin") + + set(detected_archs) + + set(msg "Detecting Target CPU Architecture") + message(STATUS "${msg}") + + include(CMakePushCheckState) + + set(CMAKE_TRY_COMPILE_TARGET_TYPE "STATIC_LIBRARY") + + cmake_push_check_state(RESET) + try_compile(CPU_CHECK_ALL + "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/CMakeTmp/detect_arch" + SOURCES "${path_src_arch_detect}" + COPY_FILE "${path_bin_arch_detect}" + ) + cmake_pop_check_state() + if(NOT CPU_CHECK_ALL) + message(STATUS "${msg} - ") + message(WARNING "Failed to compile source detecting the target CPU architecture") + else() + set(re "INFO<([A-Z0-9]+)=([01])>") + file(STRINGS "${path_bin_arch_detect}" infos REGEX "${re}") + + foreach(info_arch_01 IN LISTS infos) + string(REGEX MATCH "${re}" A "${info_arch_01}") + if(NOT "${CMAKE_MATCH_1}" IN_LIST known_archs) + message(WARNING "Unknown architecture: \"${CMAKE_MATCH_1}\"") + continue() + endif() + set(arch "${CMAKE_MATCH_1}") + set(arch_01 "${CMAKE_MATCH_2}") + set(detected_${arch} "${arch_01}") + endforeach() + + foreach(known_arch IN LISTS known_archs) + if(detected_${known_arch}) + list(APPEND detected_archs ${known_arch}) + endif() + endforeach() + endif() + + if(detected_archs) + foreach(known_arch IN LISTS known_archs) + set("CPU_${known_arch}" "${detected_${known_arch}}" CACHE BOOL "Detected architecture ${known_arch}") + endforeach() + message(STATUS "${msg} - ${detected_archs}") + else() + include(CheckCSourceCompiles) + cmake_push_check_state(RESET) + foreach(known_arch IN LISTS known_archs) + if(NOT detected_archs) + set(cache_variable "CPU_${known_arch}") + set(test_src " + int main(int argc, char *argv[]) { + #if ${arch_check_${known_arch}} + return 0; + #else + choke + #endif + } + ") + check_c_source_compiles("${test_src}" "${cache_variable}") + if(${cache_variable}) + set(CPU_${known_arch} "1" CACHE BOOL "Detected architecture ${known_arch}") + set(detected_archs ${known_arch}) + else() + set(CPU_${known_arch} "0" CACHE BOOL "Detected architecture ${known_arch}") + endif() + endif() + endforeach() + cmake_pop_check_state() + endif() + set("${DETECTED_ARCHS}" "${detected_archs}" PARENT_SCOPE) +endfunction() diff --git a/CMakeLists.txt b/CMakeLists.txt index 334580c0..143f3068 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,9 +2,19 @@ cmake_minimum_required(VERSION 3.25...4.0 FATAL_ERROR) project(isle LANGUAGES CXX C VERSION 0.1) +if (IOS) + set(CMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED NO) + set(CMAKE_OSX_DEPLOYMENT_TARGET "12.0") + add_compile_definitions(IOS) +endif() + +if (WINDOWS_STORE) + add_compile_definitions(WINDOWS_STORE) +endif() + if (EMSCRIPTEN) add_compile_options(-pthread) - add_link_options(-sALLOW_MEMORY_GROWTH=1 -sMAXIMUM_MEMORY=2gb -sUSE_PTHREADS=1 -sPROXY_TO_PTHREAD=1 -sPTHREAD_POOL_SIZE_STRICT=0 -sFORCE_FILESYSTEM=1 -sWASMFS=1 -sEXIT_RUNTIME=1) + add_link_options(-sUSE_WEBGL2=1 -sMIN_WEBGL_VERSION=2 -sALLOW_MEMORY_GROWTH=1 -sMAXIMUM_MEMORY=2gb -sUSE_PTHREADS=1 -sPROXY_TO_PTHREAD=1 -sOFFSCREENCANVAS_SUPPORT=1 -sPTHREAD_POOL_SIZE_STRICT=0 -sFORCE_FILESYSTEM=1 -sWASMFS=1 -sEXIT_RUNTIME=1) set(SDL_PTHREADS ON CACHE BOOL "Enable SDL pthreads" FORCE) endif() @@ -13,6 +23,9 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake") include(CheckCXXSourceCompiles) include(CMakeDependentOption) include(CMakePushCheckState) +include(CMake/detectcpu.cmake) + +DetectTargetCPUArchitectures(ISLE_CPUS) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) @@ -26,7 +39,7 @@ else() endif() find_program(SDL_SHADERCROSS_BIN NAMES "shadercross") -find_package(Python3 3.11 COMPONENTS Interpreter) +find_package(Python3 3.12 COMPONENTS Interpreter) option(ISLE_BUILD_APP "Build isle application" ON) option(ISLE_ASAN "Enable Address Sanitizer" OFF) @@ -35,7 +48,8 @@ option(ISLE_WERROR "Treat warnings as errors" OFF) option(ISLE_DEBUG "Enable imgui debug" ON) 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_BUILD_CONFIG "Build CONFIG.EXE application" ON "MSVC OR ISLE_MINIWIN" OFF) +cmake_dependent_option(ISLE_EXTENSIONS "Use extensions" ON "NOT ISLE_USE_DX5" OFF) +cmake_dependent_option(ISLE_BUILD_CONFIG "Build CONFIG.EXE application" ON "MSVC OR ISLE_MINIWIN;NOT NINTENDO_3DS;NOT WINDOWS_STORE" OFF) cmake_dependent_option(ISLE_COMPILE_SHADERS "Compile shaders" ON "SDL_SHADERCROSS_BIN;TARGET Python3::Interpreter" OFF) option(CMAKE_POSITION_INDEPENDENT_CODE "Build with -fPIC" ON) option(ENABLE_CLANG_TIDY "Enable clang-tidy") @@ -48,50 +62,60 @@ message(STATUS "Isle app: ${ISLE_BUILD_APP}") message(STATUS "Config app: ${ISLE_BUILD_CONFIG}") message(STATUS "Internal DirectX5 SDK: ${ISLE_USE_DX5}") message(STATUS "Internal miniwin: ${ISLE_MINIWIN}") +message(STATUS "Isle extensions: ${ISLE_EXTENSIONS}") message(STATUS "Isle debugging: ${ISLE_DEBUG}") message(STATUS "Compile shaders: ${ISLE_COMPILE_SHADERS}") add_library(Isle::iniparser INTERFACE IMPORTED) if (DOWNLOAD_DEPENDENCIES) - # FetchContent downloads and configures dependencies - message(STATUS "Fetching SDL3 and iniparser. This might take a while...") - include(FetchContent) + # FetchContent downloads and configures dependencies + message(STATUS "Fetching SDL3 and iniparser. This might take a while...") + include(FetchContent) + if (WINDOWS_STORE) + FetchContent_Declare( + SDL3 + GIT_REPOSITORY "https://github.com/Helloyunho/SDL3-uwp.git" + GIT_TAG "main" + EXCLUDE_FROM_ALL + ) + else() FetchContent_Declare( SDL3 GIT_REPOSITORY "https://github.com/libsdl-org/SDL.git" GIT_TAG "main" EXCLUDE_FROM_ALL ) - FetchContent_MakeAvailable(SDL3) + endif() + FetchContent_MakeAvailable(SDL3) - FetchContent_Declare( - iniparser - GIT_REPOSITORY "https://gitlab.com/iniparser/iniparser.git" - GIT_TAG "main" - EXCLUDE_FROM_ALL - ) - block() - set(BUILD_DOCS off) - set(BUILD_SHARED_LIBS off) - FetchContent_MakeAvailable(iniparser) - target_link_libraries(Isle::iniparser INTERFACE iniparser-static) - endblock() + FetchContent_Declare( + iniparser + GIT_REPOSITORY "https://gitlab.com/iniparser/iniparser.git" + GIT_TAG "main" + EXCLUDE_FROM_ALL + ) + block() + set(BUILD_DOCS off) + set(BUILD_SHARED_LIBS off) + FetchContent_MakeAvailable(iniparser) + target_link_libraries(Isle::iniparser INTERFACE iniparser-static) + endblock() else() - # find_package looks for already-installed system packages. - # Configure with `-DCMAKE_PREFIX_PATH="/path/to/package1;/path/to/package2"` - # to add search paths. - find_package(SDL3 CONFIG REQUIRED) + # find_package looks for already-installed system packages. + # Configure with `-DCMAKE_PREFIX_PATH="/path/to/package1;/path/to/package2"` + # to add search paths. + find_package(SDL3 CONFIG REQUIRED) - find_package(iniparser REQUIRED CONFIG COMPONENTS shared) - target_link_libraries(Isle::iniparser INTERFACE iniparser-shared) + find_package(iniparser REQUIRED CONFIG COMPONENTS shared) + target_link_libraries(Isle::iniparser INTERFACE iniparser-shared) endif() set(CMAKE_EXPORT_COMPILE_COMMANDS ON) if (ENABLE_CLANG_TIDY) - find_program(CLANG_TIDY_BIN NAMES "clang-tidy" ENV "LLVM_ROOT" REQUIRED) - set(CMAKE_C_CLANG_TIDY "${CLANG_TIDY_BIN}") - set(CMAKE_CXX_CLANG_TIDY "${CLANG_TIDY_BIN}") + find_program(CLANG_TIDY_BIN NAMES "clang-tidy" ENV "LLVM_ROOT" REQUIRED) + set(CMAKE_C_CLANG_TIDY "${CLANG_TIDY_BIN}") + set(CMAKE_CXX_CLANG_TIDY "${CLANG_TIDY_BIN}") endif() if (ISLE_ASAN) @@ -109,26 +133,26 @@ add_subdirectory(miniwin EXCLUDE_FROM_ALL) set(isle_targets) function(add_cxx_warning WARNING) - if (ISLE_WERROR) - set(compiler_option "-Werror=${WARNING}") - else() - set(compiler_option "-W${WARNING}") - endif() - string(MAKE_C_IDENTIFIER "COMPILER_SUPPORTS${compiler_option}" varname) + if (ISLE_WERROR) + set(compiler_option "-Werror=${WARNING}") + else() + set(compiler_option "-W${WARNING}") + endif() + string(MAKE_C_IDENTIFIER "COMPILER_SUPPORTS${compiler_option}" varname) - cmake_push_check_state(RESET) - set(CMAKE_REQUIRED_FLAGS "${compiler_option} ") - if (MSVC) - string(APPEND CMAKE_REQUIRED_FLAGS "/WX") - else() - string(APPEND CMAKE_REQUIRED_FLAGS "-Werror") - endif() - check_cxx_source_compiles("int main() { return 0; }" ${varname}) - cmake_pop_check_state() + cmake_push_check_state(RESET) + set(CMAKE_REQUIRED_FLAGS "${compiler_option} ") + if (MSVC) + string(APPEND CMAKE_REQUIRED_FLAGS "/WX") + else() + string(APPEND CMAKE_REQUIRED_FLAGS "-Werror") + endif() + check_cxx_source_compiles("int main() { return 0; }" ${varname}) + cmake_pop_check_state() - if (${varname}) - add_compile_options(${compiler_option}) - endif() + if (${varname}) + add_compile_options(${compiler_option}) + endif() endfunction() add_subdirectory(3rdparty EXCLUDE_FROM_ALL SYSTEM) @@ -148,6 +172,7 @@ add_library(lego1 target_precompile_headers(lego1 PRIVATE "LEGO1/lego1_pch.h") set_property(TARGET lego1 PROPERTY DEFINE_SYMBOL "LEGO1_DLL") target_include_directories(lego1 PUBLIC "$") +target_include_directories(lego1 PUBLIC "$") target_include_directories(lego1 PUBLIC "$") target_include_directories(lego1 PUBLIC "$") target_include_directories(lego1 PUBLIC "$") @@ -156,6 +181,8 @@ target_include_directories(lego1 PUBLIC "$:DirectX5::DirectX5>) +# Allow unconditional include of miniwin/miniwind3d.h +target_link_libraries(lego1 PRIVATE miniwin-headers) if(WIN32) set_property(TARGET lego1 PROPERTY PREFIX "") endif() @@ -286,10 +313,10 @@ target_sources(lego1 PRIVATE LEGO1/omni/src/common/mxcompositepresenter.cpp LEGO1/omni/src/common/mxcore.cpp LEGO1/omni/src/common/mxdebug.cpp - LEGO1/omni/src/common/mxmediamanager.cpp LEGO1/omni/src/common/mxmediapresenter.cpp LEGO1/omni/src/common/mxmisc.cpp LEGO1/omni/src/common/mxobjectfactory.cpp + LEGO1/omni/src/common/mxpresentationmanager.cpp LEGO1/omni/src/common/mxpresenter.cpp LEGO1/omni/src/common/mxstring.cpp LEGO1/omni/src/common/mxticklemanager.cpp @@ -435,9 +462,6 @@ target_sources(lego1 PRIVATE LEGO1/lego/legoomni/src/race/raceskel.cpp LEGO1/lego/legoomni/src/video/legoanimpresenter.cpp LEGO1/lego/legoomni/src/video/legoflctexturepresenter.cpp - LEGO1/lego/legoomni/src/video/legohideanimpresenter.cpp - LEGO1/lego/legoomni/src/video/legolocomotionanimpresenter.cpp - LEGO1/lego/legoomni/src/video/legoloopinganimpresenter.cpp LEGO1/lego/legoomni/src/video/legomodelpresenter.cpp LEGO1/lego/legoomni/src/video/legopalettepresenter.cpp LEGO1/lego/legoomni/src/video/legopartpresenter.cpp @@ -465,11 +489,22 @@ if (NOT ISLE_MINIWIN) target_compile_definitions(lego1 PRIVATE DIRECTINPUT_VERSION=0x0500) endif() +if (ISLE_EXTENSIONS) + target_compile_definitions(lego1 PUBLIC EXTENSIONS) + target_sources(lego1 PRIVATE + extensions/src/extensions.cpp + extensions/src/textureloader.cpp + ) +endif() + if (ISLE_BUILD_APP) add_executable(isle WIN32 ISLE/res/isle.rc ISLE/isleapp.cpp ISLE/islefiles.cpp + ${CMAKE_SOURCE_DIR}/ISLE/res/arrow_bmp.h + ${CMAKE_SOURCE_DIR}/ISLE/res/busy_bmp.h + ${CMAKE_SOURCE_DIR}/ISLE/res/no_bmp.h ) list(APPEND isle_targets isle) if (WIN32) @@ -490,6 +525,9 @@ if (ISLE_BUILD_APP) # Allow unconditional include of miniwin/miniwindevice.h target_link_libraries(isle PRIVATE miniwin-headers) + # Vector math + target_link_libraries(isle PRIVATE Vec::Vec) + # Link DSOUND and WINMM if (WIN32) target_link_libraries(isle PRIVATE winmm) @@ -513,19 +551,71 @@ if (ISLE_BUILD_APP) endif() if(EMSCRIPTEN) target_sources(isle PRIVATE + ISLE/emscripten/config.cpp ISLE/emscripten/events.cpp ISLE/emscripten/filesystem.cpp + ISLE/emscripten/haptic.cpp ISLE/emscripten/messagebox.cpp + ISLE/emscripten/window.cpp ) target_compile_definitions(isle PRIVATE "ISLE_EMSCRIPTEN_HOST=\"${ISLE_EMSCRIPTEN_HOST}\"") set_property(TARGET isle PROPERTY SUFFIX ".html") endif() + if(NINTENDO_3DS) + target_sources(isle PRIVATE + ISLE/3ds/apthooks.cpp + ISLE/3ds/config.cpp + ) + endif() + if(WINDOWS_STORE) + target_sources(isle PRIVATE + ISLE/xbox_one_series/config.cpp + ) + endif() + if (IOS) + target_sources(isle PRIVATE + ISLE/ios/config.cpp + ) + endif() + if(Python3_FOUND) + if(NOT DEFINED PYTHON_PIL_AVAILABLE) + execute_process( + COMMAND ${Python3_EXECUTABLE} -c "import PIL; print('pil')" + RESULT_VARIABLE PIL_RESULT + OUTPUT_VARIABLE PIL_OUTPUT + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + if(PIL_RESULT EQUAL 0 AND PIL_OUTPUT STREQUAL "pil") + set(PIL_AVAILABLE 1) + else() + message(STATUS "Python PIL not found, using pre-generated headers.") + set(PIL_AVAILABLE 0) + endif() + set(PYTHON_PIL_AVAILABLE ${PIL_AVAILABLE} CACHE BOOL "Is Python3 Pillow available?") + endif() + if(PYTHON_PIL_AVAILABLE) + add_custom_command( + OUTPUT + ${CMAKE_SOURCE_DIR}/ISLE/res/arrow_bmp.h + ${CMAKE_SOURCE_DIR}/ISLE/res/busy_bmp.h + ${CMAKE_SOURCE_DIR}/ISLE/res/no_bmp.h + COMMAND ${Python3_EXECUTABLE} tools/curpng2h.py ISLE/res/arrow.png ISLE/res/busy.png ISLE/res/no.png + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + DEPENDS + ${CMAKE_SOURCE_DIR}/tools/curpng2h.py + ${CMAKE_SOURCE_DIR}/ISLE/res/arrow.png + ${CMAKE_SOURCE_DIR}/ISLE/res/busy.png + ${CMAKE_SOURCE_DIR}/ISLE/res/no.png + ) + endif() + endif() endif() if (ISLE_BUILD_CONFIG) find_package(Qt6 REQUIRED COMPONENTS Core Widgets) qt_standard_project_setup() - qt_add_executable(config WIN32 + qt_add_executable(isle-config WIN32 LEGO1/mxdirectx/mxdirectxinfo.cpp LEGO1/mxdirectx/legodxinfo.cpp CONFIG/config.cpp @@ -535,22 +625,22 @@ if (ISLE_BUILD_CONFIG) CONFIG/res/config.rc CONFIG/res/config.qrc ) - target_link_libraries(config PRIVATE Qt6::Core Qt6::Widgets) - set_property(TARGET config PROPERTY AUTOMOC ON) - set_property(TARGET config PROPERTY AUTORCC ON) - set_property(TARGET config PROPERTY AUTOUIC ON) - set_property(TARGET config PROPERTY AUTOUIC_SEARCH_PATHS "${CMAKE_CURRENT_SOURCE_DIR}/CONFIG/res") - list(APPEND isle_targets config) - target_compile_definitions(config PRIVATE _AFXDLL MXDIRECTX_FOR_CONFIG) - target_include_directories(config PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/LEGO1") - target_include_directories(config PUBLIC "$") + target_link_libraries(isle-config PRIVATE Qt6::Core Qt6::Widgets) + set_property(TARGET isle-config PROPERTY AUTOMOC ON) + set_property(TARGET isle-config PROPERTY AUTORCC ON) + set_property(TARGET isle-config PROPERTY AUTOUIC ON) + set_property(TARGET isle-config PROPERTY AUTOUIC_SEARCH_PATHS "${CMAKE_CURRENT_SOURCE_DIR}/CONFIG/res") + list(APPEND isle_targets isle-config) + target_compile_definitions(isle-config PRIVATE _AFXDLL MXDIRECTX_FOR_CONFIG) + target_include_directories(isle-config PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/LEGO1") + target_include_directories(isle-config PUBLIC "$") if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 14) - target_link_libraries(config PRIVATE DirectX5::DirectX5) + target_link_libraries(isle-config PRIVATE DirectX5::DirectX5) endif() - target_compile_definitions(config PRIVATE DIRECT3D_VERSION=0x500) - target_link_libraries(config PRIVATE SDL3::SDL3 Isle::iniparser) + target_compile_definitions(isle-config PRIVATE DIRECT3D_VERSION=0x500) + target_link_libraries(isle-config PRIVATE SDL3::SDL3 Isle::iniparser) if (NOT ISLE_MINIWIN) - target_link_libraries(config PRIVATE ddraw dxguid) + target_link_libraries(isle-config PRIVATE ddraw dxguid) endif() endif() @@ -564,8 +654,14 @@ if (MSVC) if (TARGET isle) target_compile_definitions(isle PRIVATE "_CRT_SECURE_NO_WARNINGS") endif() - if (TARGET config) - target_compile_definitions(config PRIVATE "_CRT_SECURE_NO_WARNINGS") + if (TARGET isle-config) + target_compile_definitions(isle-config PRIVATE "_CRT_SECURE_NO_WARNINGS") + endif() + if (TARGET iniparser-static) + target_compile_definitions(iniparser-static PRIVATE "_CRT_SECURE_NO_WARNINGS") + endif() + if (TARGET libsmacker) + target_compile_definitions(libsmacker PRIVATE "_CRT_SECURE_NO_WARNINGS") endif() endif() # Visual Studio 2017 version 15.7 needs "/Zc:__cplusplus" for __cplusplus @@ -574,8 +670,8 @@ if (MSVC) if (TARGET isle) target_compile_options(isle PRIVATE "-Zc:__cplusplus") endif() - if (TARGET config) - target_compile_options(config PRIVATE "-Zc:__cplusplus") + if (TARGET isle-config) + target_compile_options(isle-config PRIVATE "-Zc:__cplusplus") endif() endif() endif() @@ -624,17 +720,46 @@ else() include(GNUInstallDirs) endif() -set(ISLE_PACKAGE_NAME "${CMAKE_SYSTEM_NAME}-${CMAKE_SYSTEM_PROCESSOR}" CACHE STRING "Platform name of the package") +string(REPLACE ";" "-" ISLE_CPUS_STRING "${ISLE_CPUS}") +string(TOLOWER "${ISLE_CPUS_STRING}" ISLE_CPUS_STRING) +if (WINDOWS_STORE) + set(ISLE_PACKAGE_NAME "Xbox_One_Series_XS-${ISLE_CPUS_STRING}" CACHE STRING "Platform name of the package") +else() + set(ISLE_PACKAGE_NAME "${CMAKE_SYSTEM_NAME}-${ISLE_CPUS_STRING}" CACHE STRING "Platform name of the package") +endif() if(BUILD_SHARED_LIBS) list(APPEND install_extra_targets lego1) endif() -install(TARGETS isle ${install_extra_targets} - RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" - LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" -) -if (ISLE_BUILD_CONFIG) - install(TARGETS config +if (NOT (NINTENDO_3DS OR WINDOWS_STORE)) + install(TARGETS isle ${install_extra_targets} RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" + LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" + BUNDLE DESTINATION "." + ) +endif() +if (ISLE_BUILD_CONFIG) + if(WIN32) + find_program(WINDEPLOYQT_EXECUTABLE windeployqt) + if(WINDEPLOYQT_EXECUTABLE) + install(CODE "message(STATUS \"Running windeployqt with minimal dependencies\") + execute_process(COMMAND \"${WINDEPLOYQT_EXECUTABLE}\" + \"$\" + --dir QTLibs + --no-compiler-runtime + --no-opengl-sw + --no-system-d3d-compiler + --no-translations + --no-quick-import + )" + ) + install(DIRECTORY "Build/QTLibs/" DESTINATION "${CMAKE_INSTALL_BINDIR}") + else() + message(STATUS "windeployqt not found: Qt binaries will not be installed") + endif() + endif() + install(TARGETS isle-config + RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" + BUNDLE DESTINATION "." ) endif() if(EMSCRIPTEN) @@ -643,11 +768,77 @@ if(EMSCRIPTEN) ) endif() +add_subdirectory(packaging) + set(CPACK_PACKAGE_DIRECTORY "dist") -set(CPACK_PACKAGE_FILE_NAME "isle-${PROJECT_VERSION}-${ISLE_PACKAGE_NAME}-${CMAKE_SYSTEM_PROCESSOR}") -if(MSVC) +set(CPACK_PACKAGE_FILE_NAME "isle-${PROJECT_VERSION}-${ISLE_PACKAGE_NAME}") +if(NINTENDO_3DS) + find_program(BANNERTOOL bannertool) + find_program(MAKEROM makerom) + + ctr_generate_smdh(isle.smdh + NAME "LEGO Island" + TITLE "LEGO Island" + DESCRIPTION "LEGO Island for the Nintendo 3DS" + AUTHOR "isledecomp/isle-portable" + VERSION "${PROJECT_VERSION}" + ICON "${CMAKE_SOURCE_DIR}/packaging/3ds/icon.png" + ) + + ctr_create_3dsx(isle SMDH isle.smdh) + if(BANNERTOOL AND MAKEROM) + add_custom_command( + OUTPUT "isle.bnr" + COMMAND "${BANNERTOOL}" makebanner + -i "${CMAKE_SOURCE_DIR}/packaging/3ds/banner.png" + -a "${CMAKE_SOURCE_DIR}/packaging/3ds/banner.wav" + -o "isle.bnr" + DEPENDS "${CMAKE_SOURCE_DIR}/packaging/3ds/banner.png" "${CMAKE_SOURCE_DIR}/packaging/3ds/banner.wav" + VERBATIM + ) + + add_custom_command( + OUTPUT "isle.cia" + COMMAND "${MAKEROM}" + -f cia + -exefslogo + -o "isle.cia" + -rsf "${CMAKE_SOURCE_DIR}/packaging/3ds/template.rsf" + -major "${CMAKE_PROJECT_VERSION_MAJOR}" + -minor "${CMAKE_PROJECT_VERSION_MINOR}" + -micro 0 + -icon "isle.smdh" + -banner "isle.bnr" + -elf "isle.elf" + DEPENDS "${CMAKE_SOURCE_DIR}/packaging/3ds/template.rsf" "isle.smdh" "isle.bnr" + COMMENT "Building CIA executable target isle.cia" + VERBATIM + ) + + add_custom_target("isle_cia" ALL DEPENDS "isle.cia" isle) + install(FILES "$/isle.cia" DESTINATION "${CMAKE_INSTALL_BINDIR}") + endif() + install(FILES "$/isle.3dsx" DESTINATION "${CMAKE_INSTALL_BINDIR}") +endif() +if(WINDOWS_STORE) + install( + DIRECTORY + "${CMAKE_BINARY_DIR}/AppPackages/isle/" + DESTINATION "${CMAKE_INSTALL_BINDIR}" + FILES_MATCHING PATTERN "*/Dependencies/x64/Microsoft.VCLibs.x64*.14.00.appx" + PATTERN "*/*.msix" + PATTERN "*/*.msixbundle") +endif() +if(MSVC OR IOS) set(CPACK_GENERATOR ZIP) + if(IOS) + set(CPACK_ARCHIVE_FILE_EXTENSION ".ipa") + set(CPACK_INCLUDE_TOPLEVEL_DIRECTORY OFF) + endif() +elseif(APPLE AND NOT IOS) + set(CPACK_GENERATOR DragNDrop) else() set(CPACK_GENERATOR TGZ) endif() + include(CPack) diff --git a/CONFIG/MainDlg.cpp b/CONFIG/MainDlg.cpp index b90f1f66..5ae140c3 100644 --- a/CONFIG/MainDlg.cpp +++ b/CONFIG/MainDlg.cpp @@ -11,6 +11,10 @@ #include "res/resource.h" #include +#include +#include +#include +#include #include #include @@ -52,13 +56,21 @@ CMainDialog::CMainDialog(QWidget* pParent) : QDialog(pParent) this, &CMainDialog::OnRadiobuttonTextureHighQuality ); + + connect(m_ui->windowedRadioButton, &QRadioButton::toggled, this, &CMainDialog::OnRadioWindowed); + connect(m_ui->fullscreenRadioButton, &QRadioButton::toggled, this, &CMainDialog::OnRadioFullscreen); + connect(m_ui->exFullscreenRadioButton, &QRadioButton::toggled, this, &CMainDialog::OnRadioExclusiveFullscreen); connect(m_ui->devicesList, &QListWidget::currentRowChanged, this, &CMainDialog::OnList3DevicesSelectionChanged); connect(m_ui->musicCheckBox, &QCheckBox::toggled, this, &CMainDialog::OnCheckboxMusic); connect(m_ui->sound3DCheckBox, &QCheckBox::toggled, this, &CMainDialog::OnCheckbox3DSound); - connect(m_ui->joystickCheckBox, &QCheckBox::toggled, this, &CMainDialog::OnCheckboxJoystick); - connect(m_ui->fullscreenCheckBox, &QCheckBox::toggled, this, &CMainDialog::OnCheckboxFullscreen); + connect(m_ui->rumbleCheckBox, &QCheckBox::toggled, this, &CMainDialog::OnCheckboxRumble); + connect(m_ui->textureCheckBox, &QCheckBox::toggled, this, &CMainDialog::OnCheckboxTexture); + connect(m_ui->touchComboBox, &QComboBox::currentIndexChanged, this, &CMainDialog::TouchControlsChanged); + connect(m_ui->transitionTypeComboBox, &QComboBox::currentIndexChanged, this, &CMainDialog::TransitionTypeChanged); + connect(m_ui->exFullResComboBox, &QComboBox::currentIndexChanged, this, &CMainDialog::ExclusiveResolutionChanged); connect(m_ui->okButton, &QPushButton::clicked, this, &CMainDialog::accept); connect(m_ui->cancelButton, &QPushButton::clicked, this, &CMainDialog::reject); + connect(m_ui->launchButton, &QPushButton::clicked, this, &CMainDialog::launch); connect(m_ui->dataPathOpen, &QPushButton::clicked, this, &CMainDialog::SelectDataPathDialog); connect(m_ui->savePathOpen, &QPushButton::clicked, this, &CMainDialog::SelectSavePathDialog); @@ -66,10 +78,57 @@ CMainDialog::CMainDialog(QWidget* pParent) : QDialog(pParent) connect(m_ui->dataPath, &QLineEdit::editingFinished, this, &CMainDialog::DataPathEdited); connect(m_ui->savePath, &QLineEdit::editingFinished, this, &CMainDialog::SavePathEdited); + connect(m_ui->texturePathOpen, &QPushButton::clicked, this, &CMainDialog::SelectTexturePathDialog); + connect(m_ui->texturePath, &QLineEdit::editingFinished, this, &CMainDialog::TexturePathEdited); + connect(m_ui->maxLoDSlider, &QSlider::valueChanged, this, &CMainDialog::MaxLoDChanged); + connect(m_ui->maxLoDSlider, &QSlider::sliderMoved, this, &CMainDialog::MaxLoDChanged); connect(m_ui->maxActorsSlider, &QSlider::valueChanged, this, &CMainDialog::MaxActorsChanged); + connect(m_ui->maxActorsSlider, &QSlider::sliderMoved, this, &CMainDialog::MaxActorsChanged); + + connect(m_ui->msaaSlider, &QSlider::valueChanged, this, &CMainDialog::MSAAChanged); + connect(m_ui->msaaSlider, &QSlider::sliderMoved, this, &CMainDialog::MSAAChanged); + connect(m_ui->AFSlider, &QSlider::valueChanged, this, &CMainDialog::AFChanged); + connect(m_ui->AFSlider, &QSlider::sliderMoved, this, &CMainDialog::AFChanged); + + connect(m_ui->aspectRatioComboBox, &QComboBox::currentIndexChanged, this, &CMainDialog::AspectRatioChanged); + connect(m_ui->xResSpinBox, &QSpinBox::valueChanged, this, &CMainDialog::XResChanged); + connect(m_ui->yResSpinBox, &QSpinBox::valueChanged, this, &CMainDialog::YResChanged); + connect(m_ui->framerateSpinBox, &QSpinBox::valueChanged, this, &CMainDialog::FramerateChanged); layout()->setSizeConstraint(QLayout::SetFixedSize); + + if (currentConfigApp->m_ram_quality_limit != 0) { + m_modified = true; + const QString ramError = QString("Insufficient RAM!"); + m_ui->sound3DCheckBox->setChecked(false); + m_ui->sound3DCheckBox->setEnabled(false); + m_ui->sound3DCheckBox->setToolTip(ramError); + m_ui->modelQualityHighRadioButton->setEnabled(false); + m_ui->modelQualityHighRadioButton->setToolTip(ramError); + m_ui->modelQualityLowRadioButton->setEnabled(true); + if (currentConfigApp->m_ram_quality_limit == 2) { + m_ui->modelQualityLowRadioButton->setChecked(true); + m_ui->modelQualityMediumRadioButton->setEnabled(false); + m_ui->modelQualityMediumRadioButton->setToolTip(ramError); + m_ui->maxLoDSlider->setMaximum(30); + m_ui->maxActorsSlider->setMaximum(15); + } + else { + m_ui->modelQualityMediumRadioButton->setChecked(true); + m_ui->modelQualityMediumRadioButton->setEnabled(true); + m_ui->maxLoDSlider->setMaximum(40); + m_ui->maxActorsSlider->setMaximum(30); + } + } + else { + m_ui->sound3DCheckBox->setEnabled(true); + m_ui->modelQualityLowRadioButton->setEnabled(true); + m_ui->modelQualityMediumRadioButton->setEnabled(true); + m_ui->modelQualityHighRadioButton->setEnabled(true); + m_ui->maxLoDSlider->setMaximum(60); + m_ui->maxActorsSlider->setMaximum(40); + } } CMainDialog::~CMainDialog() @@ -87,7 +146,7 @@ bool CMainDialog::OnInitDialog() int device_i = 0; int selected = 0; char device_name[256]; - const list& driver_list = enumerator->GetDriverList(); + const list& driver_list = enumerator->m_ddInfo; for (list::const_iterator it_driver = driver_list.begin(); it_driver != driver_list.end(); it_driver++) { const MxDriver& driver = *it_driver; for (list::const_iterator it_device = driver.m_devices.begin(); @@ -111,7 +170,27 @@ bool CMainDialog::OnInitDialog() m_ui->devicesList->setCurrentRow(selected); m_ui->maxLoDSlider->setValue((int) currentConfigApp->m_max_lod * 10); + m_ui->LoDNum->setNum((int) currentConfigApp->m_max_lod * 10); m_ui->maxActorsSlider->setValue(currentConfigApp->m_max_actors); + m_ui->maxActorsNum->setNum(currentConfigApp->m_max_actors); + + m_ui->exFullResComboBox->clear(); + + int displayModeCount; + displayModes = SDL_GetFullscreenDisplayModes(SDL_GetPrimaryDisplay(), &displayModeCount); + + for (int i = 0; i < displayModeCount; ++i) { + QString mode = + QString("%1x%2 @ %3Hz").arg(displayModes[i]->w).arg(displayModes[i]->h).arg(displayModes[i]->refresh_rate); + m_ui->exFullResComboBox->addItem(mode); + + if ((displayModes[i]->w == currentConfigApp->m_exf_x_res) && + (displayModes[i]->h == currentConfigApp->m_exf_y_res) && + (displayModes[i]->refresh_rate == currentConfigApp->m_exf_fps)) { + m_ui->exFullResComboBox->setCurrentIndex(i); + } + } + UpdateInterface(); return true; } @@ -155,6 +234,30 @@ void CMainDialog::accept() QDialog::accept(); } +void CMainDialog::launch() +{ + if (m_modified) { + currentConfigApp->WriteRegisterSettings(); + } + + QDir::setCurrent(QCoreApplication::applicationDirPath()); + + QMessageBox msgBox = QMessageBox( + QMessageBox::Warning, + QString("Error!"), + QString("Unable to locate isle executable!"), + QMessageBox::Close + ); + + if (!QProcess::startDetached("./isle")) { // Check in isle-config directory + if (!QProcess::startDetached("isle")) { // Check in $PATH + msgBox.exec(); + } + } + + QDialog::accept(); +} + // FUNCTION: CONFIG 0x00404360 void CMainDialog::UpdateInterface() { @@ -182,11 +285,46 @@ void CMainDialog::UpdateInterface() else { m_ui->textureQualityHighRadioButton->setChecked(true); } - m_ui->joystickCheckBox->setChecked(currentConfigApp->m_use_joystick); + if (currentConfigApp->m_exclusive_full_screen) { + m_ui->exFullscreenRadioButton->setChecked(true); + m_ui->resolutionBox->setEnabled(false); + m_ui->exFullResContainer->setEnabled(true); + } + else { + m_ui->resolutionBox->setEnabled(true); + m_ui->exFullResContainer->setEnabled(false); + if (currentConfigApp->m_full_screen) { + m_ui->fullscreenRadioButton->setChecked(true); + } + else { + m_ui->windowedRadioButton->setChecked(true); + } + } m_ui->musicCheckBox->setChecked(currentConfigApp->m_music); - m_ui->fullscreenCheckBox->setChecked(currentConfigApp->m_full_screen); + m_ui->rumbleCheckBox->setChecked(currentConfigApp->m_haptic); + m_ui->touchComboBox->setCurrentIndex(currentConfigApp->m_touch_scheme); + m_ui->transitionTypeComboBox->setCurrentIndex(currentConfigApp->m_transition_type); m_ui->dataPath->setText(QString::fromStdString(currentConfigApp->m_cd_path)); m_ui->savePath->setText(QString::fromStdString(currentConfigApp->m_save_path)); + + m_ui->textureCheckBox->setChecked(currentConfigApp->m_texture_load); + m_ui->texturePath->setText(QString::fromStdString(currentConfigApp->m_texture_path)); + m_ui->texturePath->setEnabled(currentConfigApp->m_texture_load); + m_ui->texturePathOpen->setEnabled(currentConfigApp->m_texture_load); + + m_ui->aspectRatioComboBox->setCurrentIndex(currentConfigApp->m_aspect_ratio); + m_ui->xResSpinBox->setValue(currentConfigApp->m_x_res); + m_ui->yResSpinBox->setValue(currentConfigApp->m_y_res); + m_ui->framerateSpinBox->setValue(static_cast(std::round(1000.0f / currentConfigApp->m_frame_delta))); + + m_ui->maxLoDSlider->setValue((int) (currentConfigApp->m_max_lod * 10)); + m_ui->LoDNum->setNum(currentConfigApp->m_max_lod); + m_ui->maxActorsSlider->setValue(currentConfigApp->m_max_actors); + m_ui->maxActorsNum->setNum(currentConfigApp->m_max_actors); + m_ui->msaaSlider->setValue(log2(currentConfigApp->m_msaa)); + m_ui->msaaNum->setNum(currentConfigApp->m_msaa); + m_ui->AFSlider->setValue(log2(currentConfigApp->m_anisotropy)); + m_ui->AFNum->setNum(currentConfigApp->m_anisotropy); } // FUNCTION: CONFIG 0x004045e0 @@ -246,12 +384,40 @@ void CMainDialog::OnRadiobuttonTextureHighQuality(bool checked) } } -// FUNCTION: CONFIG 0x00404790 -void CMainDialog::OnCheckboxJoystick(bool checked) +void CMainDialog::OnRadioWindowed(bool checked) { - currentConfigApp->m_use_joystick = checked; - m_modified = true; - UpdateInterface(); + if (checked) { + currentConfigApp->m_full_screen = false; + currentConfigApp->m_exclusive_full_screen = false; + m_ui->resolutionBox->setEnabled(true); + m_ui->exFullResContainer->setEnabled(false); + m_modified = true; + UpdateInterface(); + } +} + +void CMainDialog::OnRadioFullscreen(bool checked) +{ + if (checked) { + currentConfigApp->m_full_screen = true; + currentConfigApp->m_exclusive_full_screen = false; + m_ui->resolutionBox->setEnabled(true); + m_ui->exFullResContainer->setEnabled(false); + m_modified = true; + UpdateInterface(); + } +} + +void CMainDialog::OnRadioExclusiveFullscreen(bool checked) +{ + if (checked) { + currentConfigApp->m_full_screen = true; + currentConfigApp->m_exclusive_full_screen = true; + m_ui->resolutionBox->setEnabled(false); + m_ui->exFullResContainer->setEnabled(true); + m_modified = true; + UpdateInterface(); + } } // FUNCTION: CONFIG 0x004048c0 @@ -262,9 +428,39 @@ void CMainDialog::OnCheckboxMusic(bool checked) UpdateInterface(); } -void CMainDialog::OnCheckboxFullscreen(bool checked) +void CMainDialog::OnCheckboxRumble(bool checked) { - currentConfigApp->m_full_screen = checked; + currentConfigApp->m_haptic = checked; + m_modified = true; + UpdateInterface(); +} + +void CMainDialog::OnCheckboxTexture(bool checked) +{ + currentConfigApp->m_texture_load = checked; + m_modified = true; + UpdateInterface(); +} + +void CMainDialog::TouchControlsChanged(int index) +{ + currentConfigApp->m_touch_scheme = index; + m_modified = true; + UpdateInterface(); +} + +void CMainDialog::TransitionTypeChanged(int index) +{ + currentConfigApp->m_transition_type = index; + m_modified = true; + UpdateInterface(); +} + +void CMainDialog::ExclusiveResolutionChanged(int index) +{ + currentConfigApp->m_exf_x_res = displayModes[index]->w; + currentConfigApp->m_exf_y_res = displayModes[index]->h; + currentConfigApp->m_exf_fps = displayModes[index]->refresh_rate; m_modified = true; UpdateInterface(); } @@ -341,10 +537,112 @@ void CMainDialog::MaxLoDChanged(int value) { currentConfigApp->m_max_lod = static_cast(value) / 10.0f; m_modified = true; + UpdateInterface(); } void CMainDialog::MaxActorsChanged(int value) { currentConfigApp->m_max_actors = value; m_modified = true; + UpdateInterface(); +} + +void CMainDialog::MSAAChanged(int value) +{ + currentConfigApp->m_msaa = exp2(value); + m_modified = true; + UpdateInterface(); +} + +void CMainDialog::AFChanged(int value) +{ + currentConfigApp->m_anisotropy = exp2(value); + m_modified = true; + UpdateInterface(); +} + +void CMainDialog::SelectTexturePathDialog() +{ + QString texture_path = QString::fromStdString(currentConfigApp->m_texture_path); + texture_path = QFileDialog::getExistingDirectory( + this, + tr("Open Directory"), + texture_path, + QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks + ); + + QDir texture_dir = QDir(texture_path); + + if (texture_dir.exists()) { + currentConfigApp->m_texture_path = texture_dir.absolutePath().toStdString(); + m_modified = true; + } + UpdateInterface(); +} + +void CMainDialog::TexturePathEdited() +{ + QDir texture_dir = QDir(m_ui->texturePath->text()); + + if (texture_dir.exists()) { + currentConfigApp->m_texture_path = texture_dir.absolutePath().toStdString(); + m_modified = true; + } + UpdateInterface(); +} + +void CMainDialog::AspectRatioChanged(int index) +{ + currentConfigApp->m_aspect_ratio = index; + EnsureAspectRatio(); + m_modified = true; + UpdateInterface(); +} + +void CMainDialog::XResChanged(int i) +{ + currentConfigApp->m_x_res = i; + m_modified = true; + UpdateInterface(); +} + +void CMainDialog::YResChanged(int i) +{ + currentConfigApp->m_y_res = i; + EnsureAspectRatio(); + m_modified = true; + UpdateInterface(); +} + +void CMainDialog::EnsureAspectRatio() +{ + if (currentConfigApp->m_aspect_ratio != 3) { + m_ui->xResSpinBox->setReadOnly(true); + switch (currentConfigApp->m_aspect_ratio) { + case 0: { + float standardAspect = 4.0f / 3.0f; + currentConfigApp->m_x_res = static_cast(std::round((currentConfigApp->m_y_res) * standardAspect)); + break; + } + case 1: { + float wideAspect = 16.0f / 9.0f; + currentConfigApp->m_x_res = static_cast(std::round((currentConfigApp->m_y_res) * wideAspect)); + break; + } + case 2: { + currentConfigApp->m_x_res = currentConfigApp->m_y_res; + break; + } + } + } + else { + m_ui->xResSpinBox->setReadOnly(false); + } +} + +void CMainDialog::FramerateChanged(int i) +{ + currentConfigApp->m_frame_delta = (1000.0f / static_cast(i)); + m_modified = true; + UpdateInterface(); } diff --git a/CONFIG/MainDlg.h b/CONFIG/MainDlg.h index 65782037..0aaeeb12 100644 --- a/CONFIG/MainDlg.h +++ b/CONFIG/MainDlg.h @@ -7,6 +7,7 @@ #include #include +#include namespace Ui { @@ -29,6 +30,7 @@ class CMainDialog : public QDialog { bool m_modified = false; bool m_advanced = false; Ui::MainDialog* m_ui = nullptr; + SDL_DisplayMode** displayModes; void keyReleaseEvent(QKeyEvent* event) override; bool OnInitDialog(); @@ -40,17 +42,33 @@ private slots: void OnRadiobuttonModelHighQuality(bool checked); void OnRadiobuttonTextureLowQuality(bool checked); void OnRadiobuttonTextureHighQuality(bool checked); - void OnCheckboxJoystick(bool checked); + void OnRadioWindowed(bool checked); + void OnRadioFullscreen(bool checked); + void OnRadioExclusiveFullscreen(bool checked); void OnCheckboxMusic(bool checked); - void OnCheckboxFullscreen(bool checked); + void OnCheckboxRumble(bool checked); + void OnCheckboxTexture(bool checked); + void TouchControlsChanged(int index); + void TransitionTypeChanged(int index); + void ExclusiveResolutionChanged(int index); void accept() override; void reject() override; + void launch(); void SelectDataPathDialog(); void SelectSavePathDialog(); void DataPathEdited(); void SavePathEdited(); void MaxLoDChanged(int value); void MaxActorsChanged(int value); + void MSAAChanged(int value); + void AFChanged(int value); + void SelectTexturePathDialog(); + void TexturePathEdited(); + void XResChanged(int i); + void YResChanged(int i); + void AspectRatioChanged(int index); + void EnsureAspectRatio(); + void FramerateChanged(int i); }; // SYNTHETIC: CONFIG 0x00403de0 diff --git a/CONFIG/config.cpp b/CONFIG/config.cpp index bd38e669..766cecd4 100644 --- a/CONFIG/config.cpp +++ b/CONFIG/config.cpp @@ -56,12 +56,27 @@ bool CConfigApp::InitInstance() return false; } m_device_enumerator = new LegoDeviceEnumerate; - if (m_device_enumerator->DoEnumerate()) { + SDL_Window* window = SDL_CreateWindow("Test window", 640, 480, SDL_WINDOW_HIDDEN | SDL_WINDOW_OPENGL); + HWND hWnd; +#ifdef MINIWIN + hWnd = reinterpret_cast(window); +#else + hWnd = (HWND) SDL_GetPointerProperty(SDL_GetWindowProperties(window), SDL_PROP_WINDOW_WIN32_HWND_POINTER, NULL); +#endif + if (m_device_enumerator->DoEnumerate(hWnd)) { return FALSE; } + SDL_DestroyWindow(window); + m_aspect_ratio = 0; + m_exf_x_res = m_x_res = 640; + m_exf_y_res = m_y_res = 480; + m_exf_fps = 60.00f; + m_frame_delta = 10.0f; m_driver = NULL; m_device = NULL; m_full_screen = TRUE; + m_exclusive_full_screen = FALSE; + m_transition_type = 3; // 3: Mosaic m_wide_view_angle = TRUE; m_use_joystick = TRUE; m_music = TRUE; @@ -69,8 +84,15 @@ bool CConfigApp::InitInstance() m_3d_video_ram = FALSE; m_joystick_index = -1; m_display_bit_depth = 16; + m_msaa = 1; + m_anisotropy = 1; + m_haptic = TRUE; + m_touch_scheme = 2; + m_texture_load = TRUE; + m_texture_path = "/textures/"; int totalRamMiB = SDL_GetSystemRAM(); if (totalRamMiB < 12) { + m_ram_quality_limit = 2; m_3d_sound = FALSE; m_model_quality = 0; m_texture_quality = 1; @@ -78,6 +100,7 @@ bool CConfigApp::InitInstance() m_max_actors = 5; } else if (totalRamMiB < 20) { + m_ram_quality_limit = 1; m_3d_sound = FALSE; m_model_quality = 1; m_texture_quality = 1; @@ -85,6 +108,7 @@ bool CConfigApp::InitInstance() m_max_actors = 10; } else { + m_ram_quality_limit = 0; m_model_quality = 2; m_3d_sound = TRUE; m_texture_quality = 1; @@ -113,7 +137,7 @@ D3DCOLORMODEL CConfigApp::GetHardwareDeviceColorModel() const // FUNCTION: CONFIG 0x00403410 bool CConfigApp::IsPrimaryDriver() const { - return m_driver == &m_device_enumerator->GetDriverList().front(); + return m_driver == &m_device_enumerator->m_ddInfo.front(); } // FUNCTION: CONFIG 0x00403430 @@ -145,6 +169,9 @@ bool CConfigApp::ReadRegisterSettings() m_display_bit_depth = iniparser_getint(dict, "isle:Display Bit Depth", -1); m_flip_surfaces = iniparser_getboolean(dict, "isle:Flip Surfaces", m_flip_surfaces); m_full_screen = iniparser_getboolean(dict, "isle:Full Screen", m_full_screen); + m_exclusive_full_screen = iniparser_getboolean(dict, "isle:Exclusive Full Screen", m_exclusive_full_screen); + m_transition_type = iniparser_getint(dict, "isle:Transition Type", m_transition_type); + m_touch_scheme = iniparser_getint(dict, "isle:Touch Scheme", m_touch_scheme); m_3d_video_ram = iniparser_getboolean(dict, "isle:Back Buffers in Video RAM", m_3d_video_ram); m_wide_view_angle = iniparser_getboolean(dict, "isle:Wide View Angle", m_wide_view_angle); m_3d_sound = iniparser_getboolean(dict, "isle:3DSound", m_3d_sound); @@ -152,10 +179,22 @@ bool CConfigApp::ReadRegisterSettings() m_model_quality = iniparser_getint(dict, "isle:Island Quality", m_model_quality); m_texture_quality = iniparser_getint(dict, "isle:Island Texture", m_texture_quality); m_use_joystick = iniparser_getboolean(dict, "isle:UseJoystick", m_use_joystick); + m_haptic = iniparser_getboolean(dict, "isle:Haptic", m_haptic); m_music = iniparser_getboolean(dict, "isle:Music", m_music); m_joystick_index = iniparser_getint(dict, "isle:JoystickIndex", m_joystick_index); m_max_lod = iniparser_getdouble(dict, "isle:Max LOD", m_max_lod); m_max_actors = iniparser_getint(dict, "isle:Max Allowed Extras", m_max_actors); + m_msaa = iniparser_getint(dict, "isle:MSAA", m_msaa); + m_anisotropy = iniparser_getint(dict, "isle:Anisotropic", m_anisotropy); + m_texture_load = iniparser_getboolean(dict, "extensions:texture loader", m_texture_load); + m_texture_path = iniparser_getstring(dict, "texture loader:texture path", m_texture_path.c_str()); + m_aspect_ratio = iniparser_getint(dict, "isle:Aspect Ratio", m_aspect_ratio); + m_x_res = iniparser_getint(dict, "isle:Horizontal Resolution", m_x_res); + m_y_res = iniparser_getint(dict, "isle:Vertical Resolution", m_y_res); + m_exf_x_res = iniparser_getint(dict, "isle:Exclusive X Resolution", m_exf_x_res); + m_exf_y_res = iniparser_getint(dict, "isle:Exclusive Y Resolution", m_exf_y_res); + m_exf_fps = iniparser_getdouble(dict, "isle:Exclusive Framerate", m_exf_fps); + m_frame_delta = iniparser_getdouble(dict, "isle:Frame Delta", m_frame_delta); iniparser_freedict(dict); return true; } @@ -212,7 +251,7 @@ bool CConfigApp::ValidateSettings() is_modified = TRUE; } - if (m_max_lod < 0.0f || m_max_lod > 5.0f) { + if (m_max_lod < 0.0f || m_max_lod > 6.0f) { m_max_lod = 3.5f; is_modified = TRUE; } @@ -220,6 +259,42 @@ bool CConfigApp::ValidateSettings() m_max_actors = 20; is_modified = TRUE; } + if (!m_use_joystick) { + m_use_joystick = true; + is_modified = TRUE; + } + if (m_touch_scheme < 0 || m_touch_scheme > 2) { + m_touch_scheme = 2; + is_modified = TRUE; + } + if (m_exclusive_full_screen && !m_full_screen) { + m_full_screen = TRUE; + is_modified = TRUE; + } + if (!(m_msaa & (m_msaa - 1))) { // Check if MSAA is power of 2 (1, 2, 4, 8, etc) + m_msaa = exp2(round(log2(m_msaa))); // Closest power of 2 + is_modified = TRUE; + } + if (m_msaa > 16) { + m_msaa = 16; + is_modified = TRUE; + } + else if (m_msaa < 1) { + m_msaa = 1; + is_modified = TRUE; + } + if (!(m_anisotropy & (m_anisotropy - 1))) { // Check if anisotropy is power of 2 (1, 2, 4, 8, etc) + m_anisotropy = exp2(round(log2(m_anisotropy))); // Closest power of 2 + is_modified = TRUE; + } + if (m_anisotropy > 16) { + m_anisotropy = 16; + is_modified = TRUE; + } + else if (m_anisotropy < 1) { + m_anisotropy = 1; + is_modified = TRUE; + } return is_modified; } @@ -288,6 +363,8 @@ void CConfigApp::WriteRegisterSettings() const dictionary* dict = dictionary_new(0); iniparser_set(dict, "isle", NULL); + iniparser_set(dict, "extensions", NULL); + iniparser_set(dict, "texture loader", NULL); if (m_device_enumerator->FormatDeviceName(buffer, m_driver, m_device) >= 0) { iniparser_set(dict, "isle:3D Device ID", buffer); } @@ -296,17 +373,27 @@ void CConfigApp::WriteRegisterSettings() const iniparser_set(dict, "isle:savepath", m_save_path.c_str()); SetIniInt(dict, "isle:Display Bit Depth", m_display_bit_depth); + SetIniInt(dict, "isle:MSAA", m_msaa); + SetIniInt(dict, "isle:Anisotropic", m_anisotropy); SetIniBool(dict, "isle:Flip Surfaces", m_flip_surfaces); SetIniBool(dict, "isle:Full Screen", m_full_screen); + SetIniBool(dict, "isle:Exclusive Full Screen", m_exclusive_full_screen); SetIniBool(dict, "isle:Wide View Angle", m_wide_view_angle); + SetIniInt(dict, "isle:Transition Type", m_transition_type); + SetIniInt(dict, "isle:Touch Scheme", m_touch_scheme); + SetIniBool(dict, "isle:3DSound", m_3d_sound); SetIniBool(dict, "isle:Music", m_music); + SetIniBool(dict, "isle:Haptic", m_haptic); SetIniBool(dict, "isle:UseJoystick", m_use_joystick); SetIniInt(dict, "isle:JoystickIndex", m_joystick_index); SetIniBool(dict, "isle:Draw Cursor", m_draw_cursor); + SetIniBool(dict, "extensions:texture loader", m_texture_load); + iniparser_set(dict, "texture loader:texture path", m_texture_path.c_str()); + SetIniBool(dict, "isle:Back Buffers in Video RAM", m_3d_video_ram); SetIniInt(dict, "isle:Island Quality", m_model_quality); @@ -315,6 +402,14 @@ void CConfigApp::WriteRegisterSettings() const iniparser_set(dict, "isle:Max LOD", std::to_string(m_max_lod).c_str()); SetIniInt(dict, "isle:Max Allowed Extras", m_max_actors); + SetIniInt(dict, "isle:Aspect Ratio", m_aspect_ratio); + SetIniInt(dict, "isle:Horizontal Resolution", m_x_res); + SetIniInt(dict, "isle:Vertical Resolution", m_y_res); + SetIniInt(dict, "isle:Exclusive X Resolution", m_exf_x_res); + SetIniInt(dict, "isle:Exclusive Y Resolution", m_exf_y_res); + iniparser_set(dict, "isle:Exclusive Framerate", std::to_string(m_exf_fps).c_str()); + iniparser_set(dict, "isle:Frame Delta", std::to_string(m_frame_delta).c_str()); + #undef SetIniBool #undef SetIniInt diff --git a/CONFIG/config.h b/CONFIG/config.h index a621655a..c0dcb851 100644 --- a/CONFIG/config.h +++ b/CONFIG/config.h @@ -59,27 +59,43 @@ class CConfigApp { // DECLARE_MESSAGE_MAP() public: + int m_aspect_ratio; + int m_x_res; + int m_y_res; + int m_exf_x_res; + int m_exf_y_res; + float m_exf_fps; + float m_frame_delta; LegoDeviceEnumerate* m_device_enumerator; MxDriver* m_driver; Direct3DDeviceInfo* m_device; int m_display_bit_depth; + int m_msaa; + int m_anisotropy; bool m_flip_surfaces; bool m_full_screen; + bool m_exclusive_full_screen; + int m_transition_type; bool m_3d_video_ram; bool m_wide_view_angle; bool m_3d_sound; bool m_draw_cursor; bool m_use_joystick; + bool m_haptic; int m_joystick_index; int m_model_quality; int m_texture_quality; bool m_music; + bool m_texture_load; + std::string m_texture_path; std::string m_iniPath; std::string m_base_path; std::string m_cd_path; std::string m_save_path; float m_max_lod; int m_max_actors; + int m_touch_scheme; + int m_ram_quality_limit; }; extern CConfigApp g_theApp; diff --git a/CONFIG/res/maindialog.ui b/CONFIG/res/maindialog.ui index 78c5a174..e395159b 100644 --- a/CONFIG/res/maindialog.ui +++ b/CONFIG/res/maindialog.ui @@ -6,8 +6,8 @@ 0 0 - 575 - 600 + 600 + 480 @@ -23,7 +23,7 @@ :/lego1.png:/lego1.png - + @@ -56,443 +56,1043 @@ false - - Qt::AlignCenter + + fullscreenRadioContainer_2 + + + 0 + 0 + + - - - - 0 - 0 - + + + 0 - - - 0 - - - 0 - - - - - - 0 - 0 - - - - - 55 - 16777215 - - - - Open - - - - - - - - 0 - 0 - - - - - 55 - 16777215 - - - - Open - - - - - - - - 0 - 0 - - - - Save Path: - - - Qt::PlainText - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Path to the game data files. Set this to the CD image root. - - - - - - - Folder where save files are kept. - - - - - - - - 0 - 0 - - - - Data Path: - - - Qt::PlainText - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - - - - 0 - 80 - - - - - 0 - - - 0 - - - - - - 16777215 - 120 - - - - Set 3D model detail level. - - - Island Model Quality - - + + + Game + + + + - + + + Enable 3D positional audio effects. + - Low + 3D Sound - - - Medium + + + Enable in-game background music. - - - - - High + Music - - - - - - - 0 - 70 - - - - Maximum Level of Detail (LOD). A higher setting will cause higher quality textures to be drawn regardless of distance. - - - Maximum LOD - - - Qt::AlignCenter - - - - - - 50 - - - 5 - - - 10 - - - 35 - - - false - - - Qt::Horizontal - - - QSlider::TicksBothSides - - - 10 - - - - - - - - - - Set texture detail level. - - - Island Texture Quality - - - - 0 + + + + + Qt::Orientation::Vertical - - 0 + + + 20 + 40 + - - - - Fast - - - - - - - High - - - - - - - - - - Maximum number of LEGO actors to exist in the world at a time. The game will gradually increase the number of actors until this maximum is reached and while performance is acceptable. - - - Maximum Actors (5..40) - - - Qt::AlignCenter - - - - - - 5 - - - 40 - - - 5 - - - 20 - - - 20 - - - false - - - Qt::Horizontal - - - QSlider::TicksBothSides - - - 5 - - - - - - - - - - - - - - - - Enable 3D positional audio effects. - - - 3D Sound - - - - - - - Enable in-game background music. - - - Music - - - - - - - Enable joystick and gamepad support for LEGO Island. - - - Use Joystick - - - - - - - Toggle fullscreen display mode. - - - Fullscreen - - - - - - - - - - - 16777215 - 225 - - - - 3D graphics device used to render the game. - - - - - - Qt::AlignCenter - - - false - - - - 6 - - - 6 - - - 6 - - - 6 - - - - - - 0 - 0 - - - - - 0 - 25 - - - - Direct 3D Devices - - - Qt::AlignCenter - - - - - - - true - - - - 0 - 0 - - - - - 16777215 - 125 - - - - QAbstractItemView::NoEditTriggers - - - true - - - QAbstractItemView::SelectRows - - - - + + + + + + + 0 + 0 + + + + Sets the transition effect to be used in game. + + + Transition Type + + + + + + Mosaic + + + 3 + + + + Idle - Broken + + + + + No Animation + + + + + Dissolve + + + + + Mosaic + + + + + Wipe Down + + + + + Windows + + + + + Unknown - Broken + + + + + + + + + + + + 0 + 0 + + + + + 0 + + + 0 + + + + + Folder where save files are kept. + + + + + + + Path to the game data files. +Set this to the CD image root. + + + + + + + + 0 + 0 + + + + Data Path: + + + Qt::TextFormat::PlainText + + + + + + + + 0 + 0 + + + + + 50 + 16777215 + + + + Open + + + + + + + + 0 + 0 + + + + Save Path: + + + Qt::TextFormat::PlainText + + + + + + + + 0 + 0 + + + + + 50 + 16777215 + + + + Open + + + + + + + + + + + Graphics + + + + + + + 0 + 0 + + + + + 0 + 70 + + + + Maximum Level of Detail (LOD). +A higher setting will cause higher quality textures to be drawn regardless of distance. + + + Maximum LOD + + + + + + + 0 + 0 + + + + 60 + + + 5 + + + 10 + + + 35 + + + false + + + Qt::Orientation::Horizontal + + + QSlider::TickPosition::NoTicks + + + 10 + + + + + + + + 0 + 0 + + + + + 20 + 0 + + + + + 20 + 16777215 + + + + 3.5 + + + + + + + + + + + 0 + 0 + + + + 3D graphics device used to render the game. + + + Graphics Devices + + + false + + + + 6 + + + 6 + + + 6 + + + 6 + + + + + true + + + + 0 + 0 + + + + + 16777215 + 100 + + + + QAbstractItemView::EditTrigger::NoEditTriggers + + + true + + + QAbstractItemView::SelectionBehavior::SelectItems + + + + + + + + + + true + + + + 0 + 0 + + + + Set texture detail level. + + + Island Texture Quality + + + false + + + + 0 + + + 0 + + + + + Fast + + + + + + + High + + + + + + + + + + + 0 + 0 + + + + Maximum number of LEGO actors to exist in the world at a time. +The game will gradually increase the number of actors until this maximum is reached and while performance is acceptable. + + + Maximum Actors + + + + + + + 0 + 0 + + + + 5 + + + 40 + + + 5 + + + 20 + + + 20 + + + false + + + Qt::Orientation::Horizontal + + + QSlider::TickPosition::NoTicks + + + 5 + + + + + + + + 0 + 0 + + + + + 20 + 0 + + + + + 20 + 16777215 + + + + 20 + + + + + + + + + + + 0 + 0 + + + + Set 3D model detail level. + + + Island Model Quality + + + + + + Broken, not recommended. + + + color: rgb(255, 0, 0); + + + Low - BROKEN! + + + + + + + Medium + + + + + + + High + + + + + + + + + + + Display + + + + + + General + + + + + + + 0 + 0 + + + + <html><head/><body><p><span style=" font-weight:700;">Windowed:</span> Runs in a window, the initial resolution of which is dictated by Windowed Resolution. </p><p><span style=" font-weight:700;">Fullscreen:</span> Runs in a borderless window that consumes the entire screen. </p><p><span style=" font-weight:700;">Exclusive Fullscreen:</span> Grants the app full control of the display for better performance and lower input lag. May cause slower alt-tabbing.</p></body></html> + + + + 6 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Windowed + + + + + + + Fullscreen + + + + + + + Exclusive Fullscreen + + + + + + + + + + <html><head/><body><p>Maximum framerate. Values above 100fps are untested.</p></body></html> + + + fps + + + Max Framerate: + + + 200 + + + 100 + + + + + + + + + + Windowed Resolution + + + + + + <html><head/><body><p>The aspect ratio you intend to use.<br/>Select <span style=" font-weight:700;">Custom</span> to define your own width and height.<br/>Has no effect on the game itself.</p></body></html> + + + 0 + + + + Standard (4:3) + + + + + Widescreen (16:9) + + + + + Square (1:1) + + + + + Custom + + + + + + + + + + + 0 + 0 + + + + <html><head/><body><p>Horizontal resolution. </p><p>Locked to aspect ratio, unless <span style=" font-weight:700;">Custom</span> is select as the aspect ratio.</p></body></html> + + + Qt::AlignmentFlag::AlignCenter + + + true + + + 10000 + + + 640 + + + 10 + + + + + + + + 0 + 0 + + + + x + + + Qt::AlignmentFlag::AlignCenter + + + + + + + true + + + + 0 + 0 + + + + <html><head/><body><p>Vertical resolution. </p><p>If an aspect ratio other than <span style=" font-weight:700;">Custom</span> is selected, this directly affects the horizontal resolution.</p></body></html> + + + Qt::AlignmentFlag::AlignCenter + + + 10000 + + + 480 + + + + + + + + + + + + false + + + Exclusive Fullscreen Resolution + + + + + + Resolution + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + MSAA + + + + + + 0 + + + 4 + + + 1 + + + Qt::Orientation::Horizontal + + + QSlider::TickPosition::TicksBothSides + + + 1 + + + + + + + + 16 + 0 + + + + 1 + + + Qt::AlignmentFlag::AlignCenter + + + + + + + + + + Anisotropic Filtering + + + + + + 0 + + + 4 + + + 1 + + + Qt::Orientation::Horizontal + + + QSlider::TickPosition::TicksBothSides + + + 1 + + + + + + + + 16 + 0 + + + + 1 + + + Qt::AlignmentFlag::AlignCenter + + + + + + + + + + + + + + Controls + + + + + + <html><head/><body><p><span style=" font-weight:600;">Virtual Gamepad (Recommended):</span> Slide your finger to move and turn.</p><p><span style=" font-weight:600;">Virtual Arrow Keys:</span> Tap screen areas to move. The top moves forward, the bottom turns or moves back.</p><p><span style=" font-weight:600;">Virtual Mouse:</span> Emulates classic mouse controls with touch.</p></body></html> + + + Touch Control Scheme + + + + + + 2 + + + + Virtual Mouse + + + + + Virtual Arrow Keys + + + + + Virtual Gamepad + + + + + + + + + + + true + + + Enable controller rumble. + + + Rumble + + + true + + + + + + + Qt::Orientation::Vertical + + + + 20 + 40 + + + + + + + + + Extensions + + + + + + Settings for Texture Loader extension. + + + Texture Loader + + + + + + Enabled + + + + + + + false + + + Path to texture replacements. + + + textures/ + + + + + + + false + + + + 0 + 0 + + + + + 50 + 16777215 + + + + Open + + + + + + + + + + Qt::Orientation::Vertical + + + + 20 + 40 + + + + + + + + + 0 + 0 + + - 30 + 10 0 @@ -508,8 +1108,11 @@ + + Save configuration and close the config tool. + - OK + Save and Exit true @@ -517,9 +1120,22 @@ - + + + Save configuration and launch LEGO Island. + - Cancel + Save and Launch + + + + + + + Discard changed settings and close the config tool. + + + Exit without saving @@ -532,10 +1148,14 @@ + tabWidget dataPath dataPathOpen savePath savePathOpen + transitionTypeComboBox + sound3DCheckBox + musicCheckBox textureQualityFastRadioButton textureQualityHighRadioButton modelQualityLowRadioButton @@ -543,11 +1163,24 @@ modelQualityHighRadioButton maxLoDSlider maxActorsSlider - sound3DCheckBox - musicCheckBox - joystickCheckBox devicesList + windowedRadioButton + fullscreenRadioButton + exFullscreenRadioButton + framerateSpinBox + aspectRatioComboBox + xResSpinBox + yResSpinBox + exFullResComboBox + msaaSlider + AFSlider + touchComboBox + rumbleCheckBox + textureCheckBox + texturePath + texturePathOpen okButton + launchButton cancelButton diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 61b8cf68..8be43bce 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -6,12 +6,7 @@ If you feel fit to contribute, feel free to create a pull request! Someone will Please keep your pull requests small and understandable; you may be able to shoot ahead and make a lot of progress in a short amount of time, but this is a collaborative project, so you must allow others to catch up and follow along. Large pull requests become significantly more unwieldy to review, and as such make it exponentially more likely for a mistake or error to go undetected. They also make it harder to merge other pull requests because the more files you modify, the more likely it is for a merge conflict to occur. A general guideline is to keep submissions limited to one class at a time. Sometimes two or more classes may be too interlinked for this to be feasible, so this is not a hard rule, however if your PR is starting to modify more than 10 or so files, it's probably getting too big. -This repository has a single goal: achieving platform independence. Consequently, contributions that do not support this goal cannot be accepted. Examples of out-of-scope contributions include: - -* Improving code efficiency or performance without addressing platform compatibility -* Replacing `MxString` with `std::string` -* Fixing gameplay bugs -* Enhancing audio or video quality +This repository has achieving platform independence as its primary goal, with limited support for light modding (using [`extensions`](/extensions)). Any changes that modify code in `LEGO1` are unlikely to be accepted, unless they directly serve to increase platform compatibility. If in doubt, please contact us in the [Matrix chatroom](https://matrix.to/#/#isledecomp:matrix.org). diff --git a/ISLE/3ds/apthooks.cpp b/ISLE/3ds/apthooks.cpp new file mode 100644 index 00000000..3cd9c3e1 --- /dev/null +++ b/ISLE/3ds/apthooks.cpp @@ -0,0 +1,30 @@ +#include "apthooks.h" + +#include "legomain.h" +#include "misc.h" + +aptHookCookie g_aptCookie; + +void N3DS_AptHookCallback(APT_HookType hookType, void* param) +{ + switch (hookType) { + case APTHOOK_ONSLEEP: + case APTHOOK_ONSUSPEND: + Lego()->Pause(); + break; + case APTHOOK_ONWAKEUP: + case APTHOOK_ONRESTORE: + Lego()->Resume(); + break; + case APTHOOK_ONEXIT: + Lego()->CloseMainWindow(); + break; + default: + break; + } +} + +void N3DS_SetupAptHooks() +{ + aptHook(&g_aptCookie, N3DS_AptHookCallback, NULL); +} diff --git a/ISLE/3ds/apthooks.h b/ISLE/3ds/apthooks.h new file mode 100644 index 00000000..7bfa30f7 --- /dev/null +++ b/ISLE/3ds/apthooks.h @@ -0,0 +1,9 @@ +#ifndef N3DS_APTHOOKS_H +#define N3DS_APTHOOKS_H + +#include <3ds.h> + +void N3DS_AptHookCallback(APT_HookType hookType, void* param); +void N3DS_SetupAptHooks(); + +#endif // N3DS_APTHOOKS_H diff --git a/ISLE/3ds/config.cpp b/ISLE/3ds/config.cpp new file mode 100644 index 00000000..88318565 --- /dev/null +++ b/ISLE/3ds/config.cpp @@ -0,0 +1,19 @@ +#include "config.h" + +#include +#include + +void N3DS_SetupDefaultConfigOverrides(dictionary* p_dictionary) +{ + SDL_Log("Overriding default config for 3DS"); + + // We are currently not bundling the assets into romfs. + // User must place assets in sdmc:/3ds/isle where + // sdmc:/3ds/isle/LEGO/SCRIPTS/CREDITS.si exists, for example. + iniparser_set(p_dictionary, "isle:diskpath", "sdmc:/3ds/isle/LEGO/disk"); + iniparser_set(p_dictionary, "isle:cdpath", "sdmc:/3ds/isle"); + + // TODO: Save path: can we use libctru FS save data functions? Would be neat, especially for CIA install + // Extra / at the end causes some issues + iniparser_set(p_dictionary, "isle:savepath", "sdmc:/3ds/isle"); +} diff --git a/ISLE/3ds/config.h b/ISLE/3ds/config.h new file mode 100644 index 00000000..64d3a1b0 --- /dev/null +++ b/ISLE/3ds/config.h @@ -0,0 +1,8 @@ +#ifndef N3DS_CONFIG_H +#define N3DS_CONFIG_H + +#include "dictionary.h" + +void N3DS_SetupDefaultConfigOverrides(dictionary* p_dictionary); + +#endif // N3DS_CONFIG_H diff --git a/ISLE/emscripten/config.cpp b/ISLE/emscripten/config.cpp new file mode 100644 index 00000000..58a42704 --- /dev/null +++ b/ISLE/emscripten/config.cpp @@ -0,0 +1,27 @@ +#include "config.h" + +#include "filesystem.h" +#include "window.h" + +#include +#include +#include + +void Emscripten_SetupDefaultConfigOverrides(dictionary* p_dictionary) +{ + SDL_Log("Overriding default config for Emscripten"); + + iniparser_set(p_dictionary, "isle:diskpath", Emscripten_bundledPath); + iniparser_set(p_dictionary, "isle:cdpath", Emscripten_streamPath); + iniparser_set(p_dictionary, "isle:savepath", Emscripten_savePath); + iniparser_set(p_dictionary, "isle:Full Screen", "false"); + iniparser_set(p_dictionary, "isle:Flip Surfaces", "true"); + + // Emscripten-only for now + Emscripten_SetScaleAspect(iniparser_getboolean(p_dictionary, "isle:Original Aspect Ratio", true)); + Emscripten_SetOriginalResolution(iniparser_getboolean(p_dictionary, "isle:Original Resolution", true)); + + // clang-format off + MAIN_THREAD_EM_ASM({JSEvents.fullscreenEnabled = function() { return false; }}); +// clang-format on +} diff --git a/ISLE/emscripten/config.h b/ISLE/emscripten/config.h new file mode 100644 index 00000000..255888c0 --- /dev/null +++ b/ISLE/emscripten/config.h @@ -0,0 +1,8 @@ +#ifndef EMSCRIPTEN_CONFIG_H +#define EMSCRIPTEN_CONFIG_H + +#include "dictionary.h" + +void Emscripten_SetupDefaultConfigOverrides(dictionary* p_dictionary); + +#endif // EMSCRIPTEN_CONFIG_H diff --git a/ISLE/emscripten/libwasmfs_fetch.js.patch b/ISLE/emscripten/emscripten.patch similarity index 60% rename from ISLE/emscripten/libwasmfs_fetch.js.patch rename to ISLE/emscripten/emscripten.patch index eb16caf0..a24a67bd 100644 --- a/ISLE/emscripten/libwasmfs_fetch.js.patch +++ b/ISLE/emscripten/emscripten.patch @@ -1,5 +1,43 @@ +diff --git a/src/lib/libhtml5.js b/src/lib/libhtml5.js +index da08765e7..24e5da22e 100644 +--- a/src/lib/libhtml5.js ++++ b/src/lib/libhtml5.js +@@ -1182,6 +1182,7 @@ var LibraryHTML5 = { + + $registerRestoreOldStyle__deps: ['$getCanvasElementSize', '$setCanvasElementSize', '$currentFullscreenStrategy'], + $registerRestoreOldStyle: (canvas) => { ++ return; + var canvasSize = getCanvasElementSize(canvas); + var oldWidth = canvasSize[0]; + var oldHeight = canvasSize[1]; +@@ -1326,9 +1327,9 @@ var LibraryHTML5 = { + var topMargin; + + if (inAspectRatioFixedFullscreenMode) { +- if (w*y < x*h) h = (w * y / x) | 0; +- else if (w*y > x*h) w = (h * x / y) | 0; +- topMargin = ((screenHeight - h) / 2) | 0; ++ if (w*y < x*h) h = Math.round(w * y / x) | 0; ++ else if (w*y > x*h) w = Math.round(h * x / y) | 0; ++ topMargin = Math.round((screenHeight - h) / 2) | 0; + } + + if (inPixelPerfectFullscreenMode) { +diff --git a/src/lib/libpthread.js b/src/lib/libpthread.js +index 6d979627e..97e3f8684 100644 +--- a/src/lib/libpthread.js ++++ b/src/lib/libpthread.js +@@ -697,7 +697,7 @@ var LibraryPThread = { + { + transferredCanvasNames = UTF8ToString(transferredCanvasNames).trim(); + } +- transferredCanvasNames = transferredCanvasNames ? transferredCanvasNames.split(',') : []; ++ transferredCanvasNames = transferredCanvasNames && !Module['disableOffscreenCanvases'] ? transferredCanvasNames.split(',') : []; + #if GL_DEBUG + dbg(`pthread_create: transferredCanvasNames="${transferredCanvasNames}"`); + #endif diff --git a/src/lib/libwasmfs_fetch.js b/src/lib/libwasmfs_fetch.js -index e8c9f7e21..1c0eea957 100644 +index e8c9f7e21..caf1971d2 100644 --- a/src/lib/libwasmfs_fetch.js +++ b/src/lib/libwasmfs_fetch.js @@ -38,36 +38,7 @@ addToLibrary({ @@ -89,7 +127,21 @@ index e8c9f7e21..1c0eea957 100644 return Promise.resolve(); } -@@ -164,6 +156,21 @@ addToLibrary({ +@@ -156,14 +148,31 @@ addToLibrary({ + return readLength; + }, + getSize: async (file) => { +- try { +- await getFileRange(file, 0, 0); +- } catch (failedResponse) { +- return 0; ++ if (!(file in wasmFS$JSMemoryRanges)) { ++ try { ++ await getFileRange(file, undefined, undefined); ++ } catch (failedResponse) { ++ return 0; ++ } + } return wasmFS$JSMemoryRanges[file].size; }, }; @@ -112,3 +164,27 @@ index e8c9f7e21..1c0eea957 100644 }, - }); +diff --git a/src/preamble.js b/src/preamble.js +index 572694517..44e65c823 100644 +--- a/src/preamble.js ++++ b/src/preamble.js +@@ -1062,3 +1062,19 @@ function getCompilerSetting(name) { + // dynamic linker as symbols are loaded. + var asyncifyStubs = {}; + #endif ++ ++if (typeof document !== "undefined") { ++ (async () => { ++ try { ++ await navigator.storage.getDirectory(); ++ Module["disableOpfs"] = false; ++ } catch (e) { ++ Module["disableOpfs"] = true; ++ } ++ console.log("disableOpfs: " + Module["disableOpfs"]); ++ })(); ++ ++ Module["disableOffscreenCanvases"] ||= !document.createElement('canvas').getContext('webgl'); ++ console.log("disableOffscreenCanvases: " + Module["disableOffscreenCanvases"]); ++} ++ diff --git a/ISLE/emscripten/events.cpp b/ISLE/emscripten/events.cpp index 5cf67e51..436c1b64 100644 --- a/ISLE/emscripten/events.cpp +++ b/ISLE/emscripten/events.cpp @@ -36,3 +36,11 @@ void Emscripten_SendPresenterProgress(MxDSAction* p_action, MxPresenter::TickleS Emscripten_SendEvent("presenterProgress", buf); } + +void Emscripten_SendExtensionProgress(const char* p_extension, MxU32 p_progress) +{ + char buf[128]; + SDL_snprintf(buf, sizeof(buf), "{\"name\": \"%s\", \"progress\": %d}", p_extension, p_progress); + + Emscripten_SendEvent("extensionProgress", buf); +} diff --git a/ISLE/emscripten/events.h b/ISLE/emscripten/events.h index fac59cad..a22d7b55 100644 --- a/ISLE/emscripten/events.h +++ b/ISLE/emscripten/events.h @@ -4,5 +4,6 @@ #include "mxpresenter.h" void Emscripten_SendPresenterProgress(MxDSAction* p_action, MxPresenter::TickleState p_tickleState); +void Emscripten_SendExtensionProgress(const char* p_extension, MxU32 p_progress); #endif // EMSCRIPTEN_EVENTS_H diff --git a/ISLE/emscripten/filesystem.cpp b/ISLE/emscripten/filesystem.cpp index 395242a1..740802b8 100644 --- a/ISLE/emscripten/filesystem.cpp +++ b/ISLE/emscripten/filesystem.cpp @@ -1,22 +1,32 @@ #include "filesystem.h" +#include "events.h" +#include "extensions/textureloader.h" #include "legogamestate.h" #include "misc.h" #include "mxomni.h" #include #include +#include #include static backend_t opfs = nullptr; static backend_t fetchfs = nullptr; extern const char* g_files[46]; +extern const char* g_textures[120]; -void Emscripten_SetupConfig(const char* p_iniConfig) +bool Emscripten_OPFSDisabled() { - if (!p_iniConfig || !*p_iniConfig) { - return; + return MAIN_THREAD_EM_ASM_INT({return !!Module["disableOpfs"]}); +} + +bool Emscripten_SetupConfig(const char* p_iniConfig) +{ + if (Emscripten_OPFSDisabled()) { + SDL_Log("OPFS is disabled; ignoring .ini path"); + return false; } opfs = wasmfs_create_opfs_backend(); @@ -28,11 +38,13 @@ void Emscripten_SetupConfig(const char* p_iniConfig) wasmfs_create_directory(iniConfig.GetData(), 0644, opfs); *parse = '/'; } + + return true; } void Emscripten_SetupFilesystem() { - fetchfs = wasmfs_create_fetch_backend((MxString(Emscripten_streamHost) + MxString("/LEGO")).GetData(), 512 * 1024); + fetchfs = wasmfs_create_fetch_backend((MxString(Emscripten_streamHost) + "/LEGO").GetData(), 512 * 1024); wasmfs_create_directory("/LEGO", 0644, fetchfs); wasmfs_create_directory("/LEGO/Scripts", 0644, fetchfs); @@ -62,11 +74,42 @@ void Emscripten_SetupFilesystem() } }; + const auto preloadFile = [](const char* p_path) -> bool { + size_t length = 0; + void* data = SDL_LoadFile(p_path, &length); + if (data) { + SDL_free(data); + } + return length > 0; + }; + for (const char* file : g_files) { registerFile(file); } - if (GameState()->GetSavePath() && *GameState()->GetSavePath()) { +#ifdef EXTENSIONS + if (Extensions::TextureLoader::enabled) { + MxString directory = + MxString("/LEGO") + Extensions::TextureLoader::options["texture loader:texture path"].c_str(); + Extensions::TextureLoader::options["texture loader:texture path"] = directory.GetData(); + wasmfs_create_directory(directory.GetData(), 0644, fetchfs); + + MxU32 i = 0; + Emscripten_SendExtensionProgress("HD Textures", 0); + for (const char* file : g_textures) { + MxString path = directory + "/" + file + ".bmp"; + registerFile(path.GetData()); + + if (!preloadFile(path.GetData())) { + Extensions::TextureLoader::excludedFiles.emplace_back(file); + } + + Emscripten_SendExtensionProgress("HD Textures", (++i * 100) / sizeOfArray(g_textures)); + } + } +#endif + + if (GameState()->GetSavePath() && *GameState()->GetSavePath() && !Emscripten_OPFSDisabled()) { if (!opfs) { opfs = wasmfs_create_opfs_backend(); } diff --git a/ISLE/emscripten/filesystem.h b/ISLE/emscripten/filesystem.h index 131df1c8..ad78a349 100644 --- a/ISLE/emscripten/filesystem.h +++ b/ISLE/emscripten/filesystem.h @@ -10,7 +10,7 @@ inline static const char* Emscripten_savePath = "/save"; inline static const char* Emscripten_streamPath = "/"; inline static const char* Emscripten_streamHost = ISLE_EMSCRIPTEN_HOST; -void Emscripten_SetupConfig(const char* p_iniConfig); +bool Emscripten_SetupConfig(const char* p_iniConfig); void Emscripten_SetupFilesystem(); #endif // EMSCRIPTEN_FILESYSTEM_H diff --git a/ISLE/emscripten/haptic.cpp b/ISLE/emscripten/haptic.cpp new file mode 100644 index 00000000..4a7244e5 --- /dev/null +++ b/ISLE/emscripten/haptic.cpp @@ -0,0 +1,55 @@ +#include "haptic.h" + +#include "compat.h" +#include "lego/sources/misc/legoutil.h" +#include "legoinputmanager.h" +#include "misc.h" + +#include + +void Emscripten_HandleRumbleEvent(float p_lowFrequencyRumble, float p_highFrequencyRumble, MxU32 p_milliseconds) +{ + std::visit( + overloaded{ + [](LegoInputManager::SDL_KeyboardID_v p_id) {}, + [](LegoInputManager::SDL_MouseID_v p_id) {}, + [p_lowFrequencyRumble, p_highFrequencyRumble, p_milliseconds](LegoInputManager::SDL_JoystickID_v p_id) { + const char* name = SDL_GetJoystickNameForID((SDL_JoystickID) p_id); + if (name) { + MAIN_THREAD_EM_ASM( + { + const name = UTF8ToString($0); + const gamepads = navigator.getGamepads(); + for (const gamepad of gamepads) { + if (gamepad && gamepad.connected && gamepad.id == name && gamepad.vibrationActuator) { + gamepad.vibrationActuator.playEffect("dual-rumble", { + startDelay : 0, + weakMagnitude : $1, + strongMagnitude : $2, + duration : $3, + }); + break; + } + } + }, + name, + SDL_clamp(p_lowFrequencyRumble, 0, 1), + SDL_clamp(p_highFrequencyRumble, 0, 1), + p_milliseconds + ); + } + }, + [p_milliseconds](LegoInputManager::SDL_TouchID_v p_id) { + MAIN_THREAD_EM_ASM( + { + if (navigator.vibrate) { + navigator.vibrate($0); + } + }, + p_milliseconds + ); + } + }, + InputManager()->GetLastInputMethod() + ); +} diff --git a/ISLE/emscripten/haptic.h b/ISLE/emscripten/haptic.h new file mode 100644 index 00000000..51605128 --- /dev/null +++ b/ISLE/emscripten/haptic.h @@ -0,0 +1,8 @@ +#ifndef EMSCRIPTEN_HAPTIC_H +#define EMSCRIPTEN_HAPTIC_H + +#include "mxtypes.h" + +void Emscripten_HandleRumbleEvent(float p_lowFrequencyRumble, float p_highFrequencyRumble, MxU32 p_milliseconds); + +#endif // EMSCRIPTEN_HAPTIC_H diff --git a/ISLE/emscripten/window.cpp b/ISLE/emscripten/window.cpp new file mode 100644 index 00000000..fd8b144c --- /dev/null +++ b/ISLE/emscripten/window.cpp @@ -0,0 +1,99 @@ +#include "window.h" + +#include "mxtypes.h" + +#include +#include +#include + +double g_fullWidth; +double g_fullHeight; +bool g_scaleAspect = true; +bool g_originalResolution = true; + +extern MxS32 g_targetWidth; +extern MxS32 g_targetHeight; + +void Emscripten_SetupWindow(SDL_Window* p_window) +{ + EmscriptenFullscreenStrategy strategy; + strategy.scaleMode = g_scaleAspect ? EMSCRIPTEN_FULLSCREEN_SCALE_ASPECT : EMSCRIPTEN_FULLSCREEN_SCALE_STRETCH; + strategy.canvasResolutionScaleMode = EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_HIDEF; + strategy.filteringMode = EMSCRIPTEN_FULLSCREEN_FILTERING_DEFAULT; + strategy.canvasResizedCallbackUserData = p_window; + strategy.canvasResizedCallback = [](int eventType, const void* reserved, void* userData) -> bool { + int width, height; + emscripten_get_canvas_element_size("canvas", &width, &height); + emscripten_get_element_css_size("#canvas", &g_fullWidth, &g_fullHeight); + + if (g_originalResolution) { + SDL_SetWindowSize((SDL_Window*) userData, g_targetWidth, g_targetHeight); + } + else { + SDL_SetWindowSize((SDL_Window*) userData, width, height); + } + + SDL_Log( + "Emscripten: window size %dx%d, canvas size %dx%d, scale aspect %s, original resolution %s", + width, + height, + (int) g_fullWidth, + (int) g_fullHeight, + g_scaleAspect ? "TRUE" : "FALSE", + g_originalResolution ? "TRUE" : "FALSE" + ); + return true; + }; + + emscripten_enter_soft_fullscreen("canvas", &strategy); +} + +void Emscripten_SetScaleAspect(bool p_scaleAspect) +{ + g_scaleAspect = p_scaleAspect; +} + +void Emscripten_SetOriginalResolution(bool p_originalResolution) +{ + g_originalResolution = p_originalResolution; +} + +void Emscripten_ConvertEventToRenderCoordinates(SDL_Event* event) +{ + if (!g_scaleAspect) { + return; + } + + switch (event->type) { + case SDL_EVENT_MOUSE_MOTION: { + const float scale = std::min(g_fullWidth / g_targetWidth, g_fullHeight / g_targetHeight); + const float widthRatio = (g_targetWidth * scale) / g_fullWidth; + const float heightRatio = (g_targetHeight * scale) / g_fullHeight; + event->motion.x = (event->motion.x - (g_targetWidth * (1.0f - widthRatio) / 2.0f)) / widthRatio; + event->motion.y = (event->motion.y - (g_targetHeight * (1.0f - heightRatio) / 2.0f)) / heightRatio; + break; + } + case SDL_EVENT_MOUSE_BUTTON_DOWN: + case SDL_EVENT_MOUSE_BUTTON_UP: { + const float scale = std::min(g_fullWidth / g_targetWidth, g_fullHeight / g_targetHeight); + const float widthRatio = (g_targetWidth * scale) / g_fullWidth; + const float heightRatio = (g_targetHeight * scale) / g_fullHeight; + event->button.x = (event->button.x - (g_targetWidth * (1.0f - widthRatio) / 2.0f)) / widthRatio; + event->button.y = (event->button.y - (g_targetHeight * (1.0f - heightRatio) / 2.0f)) / heightRatio; + break; + } + case SDL_EVENT_FINGER_MOTION: + case SDL_EVENT_FINGER_DOWN: + case SDL_EVENT_FINGER_UP: + case SDL_EVENT_FINGER_CANCELED: { + const float scale = std::min(g_fullWidth / g_targetWidth, g_fullHeight / g_targetHeight); + const float widthRatio = (g_targetWidth * scale) / g_fullWidth; + const float heightRatio = (g_targetHeight * scale) / g_fullHeight; + event->tfinger.x = (event->tfinger.x * g_targetWidth - (g_targetWidth * (1.0f - widthRatio) / 2.0f)) / + widthRatio / g_targetWidth; + event->tfinger.y = (event->tfinger.y * g_targetHeight - (g_targetHeight * (1.0f - heightRatio) / 2.0f)) / + heightRatio / g_targetHeight; + break; + } + } +} diff --git a/ISLE/emscripten/window.h b/ISLE/emscripten/window.h new file mode 100644 index 00000000..01b13ae4 --- /dev/null +++ b/ISLE/emscripten/window.h @@ -0,0 +1,11 @@ +#ifndef EMSCRIPTEN_WINDOW_H +#define EMSCRIPTEN_WINDOW_H + +#include + +void Emscripten_SetupWindow(SDL_Window* p_window); +void Emscripten_SetScaleAspect(bool p_scaleAspect); +void Emscripten_SetOriginalResolution(bool p_originalResolution); +void Emscripten_ConvertEventToRenderCoordinates(SDL_Event* event); + +#endif // EMSCRIPTEN_WINDOW_H diff --git a/ISLE/ios/config.cpp b/ISLE/ios/config.cpp new file mode 100644 index 00000000..ee9349fa --- /dev/null +++ b/ISLE/ios/config.cpp @@ -0,0 +1,25 @@ +#include "config.h" + +#include +#include +#include + +void IOS_SetupDefaultConfigOverrides(dictionary* p_dictionary) +{ + SDL_Log("Overriding default config for iOS"); + + // Use DevelopmentFiles path for disk and cd paths + // It's good to use that path since user can easily + // connect through SMB and copy the files + const char* documentFolder = SDL_GetUserFolder(SDL_FOLDER_DOCUMENTS); + char* diskPath = new char[strlen(documentFolder) + strlen("isle") + 1](); + strcpy(diskPath, documentFolder); + strcat(diskPath, "isle"); + + if (!SDL_GetPathInfo(diskPath, NULL)) { + SDL_CreateDirectory(diskPath); + } + + iniparser_set(p_dictionary, "isle:diskpath", diskPath); + iniparser_set(p_dictionary, "isle:cdpath", diskPath); +} diff --git a/ISLE/ios/config.h b/ISLE/ios/config.h new file mode 100644 index 00000000..53caf824 --- /dev/null +++ b/ISLE/ios/config.h @@ -0,0 +1,8 @@ +#ifndef IOS_CONFIG_H +#define IOS_CONFIG_H + +#include "dictionary.h" + +void IOS_SetupDefaultConfigOverrides(dictionary* p_dictionary); + +#endif // IOS_CONFIG_H diff --git a/ISLE/isleapp.cpp b/ISLE/isleapp.cpp index 2ca33577..9ede5d74 100644 --- a/ISLE/isleapp.cpp +++ b/ISLE/isleapp.cpp @@ -28,13 +28,19 @@ #include "mxtransitionmanager.h" #include "mxutilities.h" #include "mxvariabletable.h" +#include "res/arrow_bmp.h" +#include "res/busy_bmp.h" #include "res/isle_bmp.h" +#include "res/no_bmp.h" #include "res/resource.h" #include "roi/legoroi.h" #include "tgl/d3drm/impl.h" #include "viewmanager/viewmanager.h" +#include +#include #include +#include #define SDL_MAIN_USE_CALLBACKS #include @@ -45,9 +51,25 @@ #include #ifdef __EMSCRIPTEN__ +#include "emscripten/config.h" #include "emscripten/events.h" #include "emscripten/filesystem.h" +#include "emscripten/haptic.h" #include "emscripten/messagebox.h" +#include "emscripten/window.h" +#endif + +#ifdef __3DS__ +#include "3ds/apthooks.h" +#include "3ds/config.h" +#endif + +#ifdef WINDOWS_STORE +#include "xbox_one_series/config.h" +#endif + +#ifdef IOS +#include "ios/config.h" #endif DECOMP_SIZE_ASSERT(IsleApp, 0x8c) @@ -82,6 +104,17 @@ MxS32 g_targetDepth = 16; // GLOBAL: ISLE 0x410064 MxS32 g_reqEnableRMDevice = FALSE; +MxFloat g_lastJoystickMouseX = 0; +MxFloat g_lastJoystickMouseY = 0; +MxFloat g_lastMouseX = 320; +MxFloat g_lastMouseY = 240; +MxBool g_mouseWarped = FALSE; + +bool g_dpadUp = false; +bool g_dpadDown = false; +bool g_dpadLeft = false; +bool g_dpadRight = false; + // STRING: ISLE 0x4101dc #define WINDOW_TITLE "LEGO®" @@ -96,11 +129,7 @@ IsleApp::IsleApp() m_cdPath = NULL; m_deviceId = NULL; m_savePath = NULL; -#ifdef __EMSCRIPTEN__ - m_fullScreen = FALSE; -#else m_fullScreen = TRUE; -#endif m_flipSurfaces = FALSE; m_backBuffersInVram = TRUE; m_using8bit = FALSE; @@ -109,8 +138,6 @@ IsleApp::IsleApp() m_drawCursor = FALSE; m_use3dSound = TRUE; m_useMusic = TRUE; - m_useJoystick = TRUE; - m_joystickIndex = 0; m_wideViewAngle = TRUE; m_islandQuality = 2; m_islandTexture = 1; @@ -134,12 +161,29 @@ IsleApp::IsleApp() m_cursorBusy = NULL; m_cursorNo = NULL; m_cursorCurrent = NULL; + m_cursorArrowBitmap = NULL; + m_cursorBusyBitmap = NULL; + m_cursorNoBitmap = NULL; + m_cursorCurrentBitmap = NULL; LegoOmni::CreateInstance(); m_iniPath = NULL; m_maxLod = RealtimeView::GetUserMaxLOD(); m_maxAllowedExtras = m_islandQuality <= 1 ? 10 : 20; + m_transitionType = MxTransitionManager::e_mosaic; + m_cursorSensitivity = 4; + m_touchScheme = LegoInputManager::e_gamepad; + m_haptic = TRUE; + m_xRes = 640; + m_yRes = 480; + m_exclusiveXRes = m_xRes; + m_exclusiveYRes = m_yRes; + m_exclusiveFrameRate = 60.00f; + m_frameRate = 100.0f; + m_exclusiveFullScreen = FALSE; + m_msaaSamples = 0; + m_anisotropic = 0.0f; } // FUNCTION: ISLE 0x4011a0 @@ -244,7 +288,7 @@ void IsleApp::SetupVideoFlags( m_videoParam.Flags().SetLacksLightSupport(!hasLightSupport); m_videoParam.Flags().SetF1bit7(param_7); m_videoParam.Flags().SetWideViewAngle(wideViewAngle); - m_videoParam.Flags().SetF2bit1(1); + m_videoParam.Flags().SetEnabled(TRUE); m_videoParam.SetDeviceName(deviceId); if (using8bit) { m_videoParam.Flags().Set16Bit(0); @@ -261,7 +305,7 @@ 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"); - if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK)) { + if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_GAMEPAD | SDL_INIT_HAPTIC)) { char buffer[256]; SDL_snprintf( buffer, @@ -280,7 +324,8 @@ SDL_AppResult SDL_AppInit(void** appstate, int argc, char** argv) // Create global app instance g_isle = new IsleApp(); - if (g_isle->ParseArguments(argc, argv) != SUCCESS) { + switch (g_isle->ParseArguments(argc, argv)) { + case SDL_APP_FAILURE: Any_ShowSimpleMessageBox( SDL_MESSAGEBOX_ERROR, "LEGO® Island Error", @@ -288,6 +333,10 @@ SDL_AppResult SDL_AppInit(void** appstate, int argc, char** argv) window ); return SDL_APP_FAILURE; + case SDL_APP_SUCCESS: + return SDL_APP_SUCCESS; + case SDL_APP_CONTINUE: + break; } // Create window @@ -304,6 +353,23 @@ SDL_AppResult SDL_AppInit(void** appstate, int argc, char** argv) // Get reference to window *appstate = g_isle->GetWindowHandle(); + // Currently, SDL doesn't send SDL_EVENT_MOUSE_ADDED at startup (unlike for gamepads) + // This will probably be fixed in the future: https://github.com/libsdl-org/SDL/issues/12815 + { + int count; + SDL_MouseID* mice = SDL_GetMice(&count); + + if (mice) { + for (int i = 0; i < count; i++) { + if (InputManager()) { + InputManager()->AddMouse(mice[i]); + } + } + + SDL_free(mice); + } + } + #ifdef __EMSCRIPTEN__ SDL_AddEventWatch( [](void* userdata, SDL_Event* event) -> bool { @@ -316,6 +382,9 @@ SDL_AppResult SDL_AppInit(void** appstate, int argc, char** argv) }, NULL ); +#endif +#ifdef __3DS__ + N3DS_SetupAptHooks(); #endif return SDL_APP_CONTINUE; } @@ -367,6 +436,8 @@ SDL_AppResult SDL_AppIterate(void* appstate) if (g_mousemoved) { g_mousemoved = FALSE; } + + g_isle->MoveVirtualMouseViaJoystick(); } return SDL_APP_CONTINUE; @@ -382,26 +453,27 @@ SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event) return SDL_APP_CONTINUE; } - // [library:window] - // Remaining functionality to be implemented: - // WM_TIMER - use SDL_Timer functionality instead - -#ifdef __EMSCRIPTEN__ - // Workaround for the fact we are getting both mouse & touch events on mobile devices running Emscripten. - // On desktops, we are only getting mouse events, but a touch device (pen_input) may also be present... - // See: https://github.com/libsdl-org/SDL/issues/13161 - static bool detectedTouchEvents = false; -#endif + if (InputManager()) { + InputManager()->UpdateLastInputMethod(event); + } switch (event->type) { case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED: case SDL_EVENT_MOUSE_MOTION: case SDL_EVENT_MOUSE_BUTTON_DOWN: case SDL_EVENT_MOUSE_BUTTON_UP: + case SDL_EVENT_FINGER_MOTION: + case SDL_EVENT_FINGER_DOWN: + case SDL_EVENT_FINGER_UP: + case SDL_EVENT_FINGER_CANCELED: IDirect3DRMMiniwinDevice* device = GetD3DRMMiniwinDevice(); if (device && !device->ConvertEventToRenderCoordinates(event)) { SDL_Log("Failed to convert event coordinates: %s", SDL_GetError()); } + +#ifdef __EMSCRIPTEN__ + Emscripten_ConvertEventToRenderCoordinates(event); +#endif break; } @@ -422,6 +494,7 @@ SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event) } break; case SDL_EVENT_WINDOW_CLOSE_REQUESTED: + case SDL_EVENT_QUIT: if (!g_closed) { delete g_isle; g_isle = NULL; @@ -435,7 +508,7 @@ SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event) SDL_Keycode keyCode = event->key.key; - if (event->key.mod == SDL_KMOD_LALT && keyCode == SDLK_RETURN) { + if ((event->key.mod & SDL_KMOD_LALT) && keyCode == SDLK_RETURN) { SDL_SetWindowFullscreen(window, !(SDL_GetWindowFlags(window) & SDL_WINDOW_FULLSCREEN)); } else { @@ -445,12 +518,155 @@ SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event) } break; } - case SDL_EVENT_MOUSE_MOTION: -#ifdef __EMSCRIPTEN__ - if (detectedTouchEvents) { + case SDL_EVENT_KEYBOARD_ADDED: + if (InputManager()) { + InputManager()->AddKeyboard(event->kdevice.which); + } + break; + case SDL_EVENT_KEYBOARD_REMOVED: + if (InputManager()) { + InputManager()->RemoveKeyboard(event->kdevice.which); + } + break; + case SDL_EVENT_MOUSE_ADDED: + if (InputManager()) { + InputManager()->AddMouse(event->mdevice.which); + } + break; + case SDL_EVENT_MOUSE_REMOVED: + if (InputManager()) { + InputManager()->RemoveMouse(event->mdevice.which); + } + break; + case SDL_EVENT_GAMEPAD_ADDED: + if (InputManager()) { + InputManager()->AddJoystick(event->jdevice.which); + } + break; + case SDL_EVENT_GAMEPAD_REMOVED: + if (InputManager()) { + InputManager()->RemoveJoystick(event->jdevice.which); + } + break; + case SDL_EVENT_GAMEPAD_BUTTON_DOWN: { + switch (event->gbutton.button) { + case SDL_GAMEPAD_BUTTON_DPAD_UP: + g_dpadUp = true; + break; + case SDL_GAMEPAD_BUTTON_DPAD_DOWN: + g_dpadDown = true; + break; + case SDL_GAMEPAD_BUTTON_DPAD_LEFT: + g_dpadLeft = true; + break; + case SDL_GAMEPAD_BUTTON_DPAD_RIGHT: + g_dpadRight = true; + break; + case SDL_GAMEPAD_BUTTON_EAST: + g_mousedown = TRUE; + if (InputManager()) { + InputManager()->QueueEvent( + c_notificationButtonDown, + LegoEventNotificationParam::c_lButtonState, + g_lastMouseX, + g_lastMouseY, + 0 + ); + } + break; + + case SDL_GAMEPAD_BUTTON_SOUTH: + if (InputManager()) { + InputManager()->QueueEvent(c_notificationKeyPress, SDLK_SPACE, 0, 0, SDLK_SPACE); + } + break; + + case SDL_GAMEPAD_BUTTON_START: + if (InputManager()) { + InputManager()->QueueEvent(c_notificationKeyPress, SDLK_ESCAPE, 0, 0, SDLK_ESCAPE); + } break; } -#endif + break; + } + + case SDL_EVENT_GAMEPAD_BUTTON_UP: { + switch (event->gbutton.button) { + case SDL_GAMEPAD_BUTTON_DPAD_UP: + g_dpadUp = false; + break; + case SDL_GAMEPAD_BUTTON_DPAD_DOWN: + g_dpadDown = false; + break; + case SDL_GAMEPAD_BUTTON_DPAD_LEFT: + g_dpadLeft = false; + break; + case SDL_GAMEPAD_BUTTON_DPAD_RIGHT: + g_dpadRight = false; + break; + case SDL_GAMEPAD_BUTTON_EAST: + g_mousedown = FALSE; + if (InputManager()) { + InputManager()->QueueEvent( + c_notificationButtonUp, + LegoEventNotificationParam::c_lButtonState, + g_lastMouseX, + g_lastMouseY, + 0 + ); + } + break; + } + break; + } + case SDL_EVENT_GAMEPAD_AXIS_MOTION: { + MxS16 axisValue = 0; + if (event->gaxis.value < -8000 || event->gaxis.value > 8000) { + // Ignore small axis values + axisValue = event->gaxis.value; + } + if (event->gaxis.axis == SDL_GAMEPAD_AXIS_RIGHTX) { + g_lastJoystickMouseX = ((MxFloat) axisValue) / SDL_JOYSTICK_AXIS_MAX * g_isle->GetCursorSensitivity(); + } + else if (event->gaxis.axis == SDL_GAMEPAD_AXIS_RIGHTY) { + g_lastJoystickMouseY = ((MxFloat) axisValue) / SDL_JOYSTICK_AXIS_MAX * g_isle->GetCursorSensitivity(); + } + else if (event->gaxis.axis == SDL_GAMEPAD_AXIS_RIGHT_TRIGGER) { + if (axisValue != 0 && !g_mousedown) { + g_mousedown = TRUE; + + if (InputManager()) { + InputManager()->QueueEvent( + c_notificationButtonDown, + LegoEventNotificationParam::c_lButtonState, + g_lastMouseX, + g_lastMouseY, + 0 + ); + } + } + else if (axisValue == 0 && g_mousedown) { + g_mousedown = FALSE; + + if (InputManager()) { + InputManager()->QueueEvent( + c_notificationButtonUp, + LegoEventNotificationParam::c_lButtonState, + g_lastMouseX, + g_lastMouseY, + 0 + ); + } + } + } + break; + } + case SDL_EVENT_MOUSE_MOTION: + if (g_mouseWarped) { + g_mouseWarped = FALSE; + break; + } + g_mousemoved = TRUE; if (InputManager()) { @@ -463,34 +679,41 @@ SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event) ); } - if (g_isle->GetDrawCursor()) { - VideoManager()->MoveCursor(Min((MxS32) event->motion.x, 639), Min((MxS32) event->motion.y, 479)); + g_lastMouseX = event->motion.x; + g_lastMouseY = event->motion.y; + + SDL_ShowCursor(); + g_isle->SetDrawCursor(FALSE); + if (VideoManager()) { + VideoManager()->SetCursorBitmap(NULL); } break; case SDL_EVENT_FINGER_MOTION: { -#ifdef __EMSCRIPTEN__ - detectedTouchEvents = true; -#endif g_mousemoved = TRUE; - float x = SDL_clamp(event->tfinger.x, 0, 1) * 640; - float y = SDL_clamp(event->tfinger.y, 0, 1) * 480; + float x = SDL_clamp(event->tfinger.x, 0, 1) * g_targetWidth; + float y = SDL_clamp(event->tfinger.y, 0, 1) * g_targetHeight; if (InputManager()) { - InputManager()->QueueEvent(c_notificationMouseMove, LegoEventNotificationParam::c_lButtonState, x, y, 0); + MxU8 modifier = LegoEventNotificationParam::c_lButtonState; + if (InputManager()->HandleTouchEvent(event, g_isle->GetTouchScheme())) { + modifier |= LegoEventNotificationParam::c_motionHandled; + } + + InputManager()->QueueEvent(c_notificationMouseMove, modifier, x, y, 0); } - if (g_isle->GetDrawCursor()) { - VideoManager()->MoveCursor(Min((MxS32) x, 639), Min((MxS32) y, 479)); + g_lastMouseX = x; + g_lastMouseY = y; + + SDL_HideCursor(); + g_isle->SetDrawCursor(FALSE); + if (VideoManager()) { + VideoManager()->SetCursorBitmap(NULL); } break; } case SDL_EVENT_MOUSE_BUTTON_DOWN: -#ifdef __EMSCRIPTEN__ - if (detectedTouchEvents) { - break; - } -#endif g_mousedown = TRUE; if (InputManager()) { @@ -504,31 +727,27 @@ SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event) } break; case SDL_EVENT_FINGER_DOWN: { -#ifdef __EMSCRIPTEN__ - detectedTouchEvents = true; -#endif g_mousedown = TRUE; - float x = SDL_clamp(event->tfinger.x, 0, 1) * 640; - float y = SDL_clamp(event->tfinger.y, 0, 1) * 480; + float x = SDL_clamp(event->tfinger.x, 0, 1) * g_targetWidth; + float y = SDL_clamp(event->tfinger.y, 0, 1) * g_targetHeight; if (InputManager()) { + InputManager()->HandleTouchEvent(event, g_isle->GetTouchScheme()); InputManager()->QueueEvent(c_notificationButtonDown, LegoEventNotificationParam::c_lButtonState, x, y, 0); } + + g_lastMouseX = x; + g_lastMouseY = y; + + SDL_HideCursor(); + g_isle->SetDrawCursor(FALSE); + if (VideoManager()) { + VideoManager()->SetCursorBitmap(NULL); + } break; } case SDL_EVENT_MOUSE_BUTTON_UP: -#ifdef __EMSCRIPTEN__ - if (detectedTouchEvents) { - // Abusing the fact (bug?) that we are always getting mouse events on Emscripten. - // This functionality should be enabled in a more general way with touch events, - // but SDL touch event's don't have a "double tap" indicator right now. - if (event->button.clicks == 2) { - InputManager()->QueueEvent(c_notificationKeyPress, SDLK_SPACE, 0, 0, SDLK_SPACE); - } - break; - } -#endif g_mousedown = FALSE; if (InputManager()) { @@ -541,23 +760,21 @@ SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event) ); } break; - case SDL_EVENT_FINGER_UP: { -#ifdef __EMSCRIPTEN__ - detectedTouchEvents = true; -#endif + case SDL_EVENT_FINGER_UP: + case SDL_EVENT_FINGER_CANCELED: { g_mousedown = FALSE; - float x = SDL_clamp(event->tfinger.x, 0, 1) * 640; - float y = SDL_clamp(event->tfinger.y, 0, 1) * 480; + float x = SDL_clamp(event->tfinger.x, 0, 1) * g_targetWidth; + float y = SDL_clamp(event->tfinger.y, 0, 1) * g_targetHeight; + + g_isle->DetectDoubleTap(event->tfinger); if (InputManager()) { + InputManager()->HandleTouchEvent(event, g_isle->GetTouchScheme()); InputManager()->QueueEvent(c_notificationButtonUp, 0, x, y, 0); } break; } - case SDL_EVENT_QUIT: - return SDL_APP_SUCCESS; - break; } if (event->user.type == g_legoSdlEvents.m_windowsMessage) { @@ -588,9 +805,41 @@ SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event) if (!g_isle->GetGameStarted() && action && state == MxPresenter::e_ready && !SDL_strncmp(action->GetObjectName(), "Lego_Smk", 8)) { g_isle->SetGameStarted(TRUE); + +#ifdef __EMSCRIPTEN__ + Emscripten_SetupWindow((SDL_Window*) g_isle->GetWindowHandle()); +#endif + SDL_Log("Game started"); } } + else if (event->user.type == g_legoSdlEvents.m_gameEvent) { + auto rumble = [](float p_strength, float p_lowFrequencyRumble, float p_highFrequencyRumble, MxU32 p_milliseconds + ) { + if (g_isle->GetHaptic() && + !InputManager() + ->HandleRumbleEvent(p_strength, p_lowFrequencyRumble, p_highFrequencyRumble, p_milliseconds)) { +// Platform-specific handling +#ifdef __EMSCRIPTEN__ + Emscripten_HandleRumbleEvent(p_lowFrequencyRumble, p_highFrequencyRumble, p_milliseconds); +#endif + } + }; + + switch (event->user.code) { + case e_hitActor: + rumble(0.5f, 0.5f, 0.5f, 700); + break; + case e_skeletonKick: + rumble(0.8f, 0.8f, 0.8f, 2500); + break; + case e_raceFinished: + case e_goodEnding: + case e_badEnding: + rumble(1.0f, 1.0f, 1.0f, 3000); + break; + } + } return SDL_APP_CONTINUE; } @@ -651,18 +900,39 @@ MxResult IsleApp::SetupWindow() m_cursorBusy = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_WAIT); m_cursorNo = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_NOT_ALLOWED); SDL_SetCursor(m_cursorCurrent); + m_cursorCurrentBitmap = m_cursorArrowBitmap = &arrow_cursor; + m_cursorBusyBitmap = &busy_cursor; + m_cursorNoBitmap = &no_cursor; SDL_PropertiesID props = SDL_CreateProperties(); SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_WIDTH_NUMBER, g_targetWidth); 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); -#ifdef MINIWIN +#if defined(MINIWIN) && !defined(__3DS__) && !defined(WINDOWS_STORE) 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); #endif window = SDL_CreateWindowWithProperties(props); + SDL_SetPointerProperty(SDL_GetWindowProperties(window), ISLE_PROP_WINDOW_CREATE_VIDEO_PARAM, &m_videoParam); + + if (m_exclusiveFullScreen && m_fullScreen) { + SDL_DisplayMode closestMode; + SDL_DisplayID displayID = SDL_GetDisplayForWindow(window); + if (SDL_GetClosestFullscreenDisplayMode( + displayID, + m_exclusiveXRes, + m_exclusiveYRes, + m_exclusiveFrameRate, + true, + &closestMode + )) { + SDL_SetWindowFullscreenMode(window, &closestMode); + } + } + #ifdef MINIWIN m_windowHandle = reinterpret_cast(window); #else @@ -703,6 +973,7 @@ MxResult IsleApp::SetupWindow() return FAILURE; } + DetectGameVersion(); GameState()->SerializePlayersInfo(LegoStorage::c_read); GameState()->SerializeScoreHistory(LegoStorage::c_read); @@ -725,11 +996,11 @@ MxResult IsleApp::SetupWindow() LegoBuildingManager::configureLegoBuildingManager(m_islandQuality); LegoROI::configureLegoROI(iVar10); LegoAnimationManager::configureLegoAnimationManager(m_maxAllowedExtras); + MxTransitionManager::configureMxTransitionManager(m_transitionType); RealtimeView::SetUserMaxLOD(m_maxLod); if (LegoOmni::GetInstance()) { - if (LegoOmni::GetInstance()->GetInputManager()) { - LegoOmni::GetInstance()->GetInputManager()->SetUseJoystick(m_useJoystick); - LegoOmni::GetInstance()->GetInputManager()->SetJoystickIndex(m_joystickIndex); + if (LegoOmni::GetInstance()->GetVideoManager()) { + LegoOmni::GetInstance()->GetVideoManager()->SetCursorBitmap(m_cursorCurrentBitmap); } MxDirect3D* d3d = LegoOmni::GetInstance()->GetVideoManager()->GetDirect3D(); if (d3d) { @@ -752,8 +1023,19 @@ MxResult IsleApp::SetupWindow() // FUNCTION: ISLE 0x4028d0 bool IsleApp::LoadConfig() { +#ifdef IOS + const char* prefPath = SDL_GetUserFolder(SDL_FOLDER_DOCUMENTS); +#else char* prefPath = SDL_GetPrefPath("isledecomp", "isle"); +#endif char* iniConfig; + +#ifdef __EMSCRIPTEN__ + if (m_iniPath && !Emscripten_SetupConfig(m_iniPath)) { + m_iniPath = NULL; + } +#endif + if (m_iniPath) { iniConfig = new char[strlen(m_iniPath) + 1]; strcpy(iniConfig, m_iniPath); @@ -769,10 +1051,6 @@ bool IsleApp::LoadConfig() } SDL_Log("Reading configuration from \"%s\"", iniConfig); -#ifdef __EMSCRIPTEN__ - Emscripten_SetupConfig(iniConfig); -#endif - dictionary* dict = iniparser_load(iniConfig); // [library:config] @@ -807,14 +1085,14 @@ bool IsleApp::LoadConfig() iniparser_set(dict, "isle:Flip Surfaces", m_flipSurfaces ? "true" : "false"); iniparser_set(dict, "isle:Full Screen", m_fullScreen ? "true" : "false"); + iniparser_set(dict, "isle:Exclusive Full Screen", m_exclusiveFullScreen ? "true" : "false"); iniparser_set(dict, "isle:Wide View Angle", m_wideViewAngle ? "true" : "false"); iniparser_set(dict, "isle:3DSound", m_use3dSound ? "true" : "false"); iniparser_set(dict, "isle:Music", m_useMusic ? "true" : "false"); - iniparser_set(dict, "isle:UseJoystick", m_useJoystick ? "true" : "false"); - iniparser_set(dict, "isle:JoystickIndex", SDL_itoa(m_joystickIndex, buf, 10)); - iniparser_set(dict, "isle:Draw Cursor", m_drawCursor ? "true" : "false"); + SDL_snprintf(buf, sizeof(buf), "%f", m_cursorSensitivity); + iniparser_set(dict, "isle:Cursor Sensitivity", buf); iniparser_set(dict, "isle:Back Buffers in Video RAM", "-1"); @@ -823,26 +1101,47 @@ bool IsleApp::LoadConfig() SDL_snprintf(buf, sizeof(buf), "%f", m_maxLod); iniparser_set(dict, "isle:Max LOD", buf); iniparser_set(dict, "isle:Max Allowed Extras", SDL_itoa(m_maxAllowedExtras, buf, 10)); + iniparser_set(dict, "isle:Transition Type", SDL_itoa(m_transitionType, buf, 10)); + iniparser_set(dict, "isle:Touch Scheme", SDL_itoa(m_touchScheme, buf, 10)); + iniparser_set(dict, "isle:Haptic", m_haptic ? "true" : "false"); + iniparser_set(dict, "isle:Horizontal Resolution", SDL_itoa(m_xRes, buf, 10)); + iniparser_set(dict, "isle:Vertical Resolution", SDL_itoa(m_yRes, buf, 10)); + iniparser_set(dict, "isle:Exclusive X Resolution", SDL_itoa(m_exclusiveXRes, buf, 10)); + iniparser_set(dict, "isle:Exclusive Y Resolution", SDL_itoa(m_exclusiveYRes, buf, 10)); + iniparser_set(dict, "isle:Exclusive Framerate", SDL_itoa(m_exclusiveFrameRate, buf, 10)); + iniparser_set(dict, "isle:Frame Delta", SDL_itoa(m_frameDelta, buf, 10)); +#ifdef EXTENSIONS + iniparser_set(dict, "extensions", NULL); + for (const char* key : Extensions::availableExtensions) { + iniparser_set(dict, key, "false"); + } +#endif + +#ifdef __3DS__ + N3DS_SetupDefaultConfigOverrides(dict); +#endif +#ifdef WINDOWS_STORE + XBONE_SetupDefaultConfigOverrides(dict); +#endif +#ifdef IOS + IOS_SetupDefaultConfigOverrides(dict); +#endif iniparser_dump_ini(dict, iniFP); SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "New config written at '%s'", iniConfig); fclose(iniFP); } #ifdef __EMSCRIPTEN__ - const char* hdPath = Emscripten_bundledPath; -#else - const char* hdPath = iniparser_getstring(dict, "isle:diskpath", SDL_GetBasePath()); + Emscripten_SetupDefaultConfigOverrides(dict); #endif + + const char* hdPath = iniparser_getstring(dict, "isle:diskpath", SDL_GetBasePath()); m_hdPath = new char[strlen(hdPath) + 1]; strcpy(m_hdPath, hdPath); MxOmni::SetHD(m_hdPath); -#ifdef __EMSCRIPTEN__ - const char* cdPath = Emscripten_streamPath; -#else const char* cdPath = iniparser_getstring(dict, "isle:cdpath", MxOmni::GetCD()); -#endif m_cdPath = new char[strlen(cdPath) + 1]; strcpy(m_cdPath, cdPath); MxOmni::SetCD(m_cdPath); @@ -853,12 +1152,11 @@ bool IsleApp::LoadConfig() m_flipSurfaces = iniparser_getboolean(dict, "isle:Flip Surfaces", m_flipSurfaces); m_fullScreen = iniparser_getboolean(dict, "isle:Full Screen", m_fullScreen); + m_exclusiveFullScreen = iniparser_getboolean(dict, "isle:Exclusive Full Screen", m_exclusiveFullScreen); m_wideViewAngle = iniparser_getboolean(dict, "isle:Wide View Angle", m_wideViewAngle); m_use3dSound = iniparser_getboolean(dict, "isle:3DSound", m_use3dSound); m_useMusic = iniparser_getboolean(dict, "isle:Music", m_useMusic); - m_useJoystick = iniparser_getboolean(dict, "isle:UseJoystick", m_useJoystick); - m_joystickIndex = iniparser_getint(dict, "isle:JoystickIndex", m_joystickIndex); - m_drawCursor = iniparser_getboolean(dict, "isle:Draw Cursor", m_drawCursor); + m_cursorSensitivity = iniparser_getdouble(dict, "isle:Cursor Sensitivity", m_cursorSensitivity); MxS32 backBuffersInVRAM = iniparser_getboolean(dict, "isle:Back Buffers in Video RAM", -1); if (backBuffersInVRAM != -1) { @@ -879,6 +1177,22 @@ bool IsleApp::LoadConfig() m_islandTexture = iniparser_getint(dict, "isle:Island Texture", m_islandTexture); m_maxLod = iniparser_getdouble(dict, "isle:Max LOD", m_maxLod); m_maxAllowedExtras = iniparser_getint(dict, "isle:Max Allowed Extras", m_maxAllowedExtras); + m_transitionType = + (MxTransitionManager::TransitionType) iniparser_getint(dict, "isle:Transition Type", m_transitionType); + m_touchScheme = (LegoInputManager::TouchScheme) iniparser_getint(dict, "isle:Touch Scheme", m_touchScheme); + m_haptic = iniparser_getboolean(dict, "isle:Haptic", m_haptic); + m_xRes = iniparser_getint(dict, "isle:Horizontal Resolution", m_xRes); + m_yRes = iniparser_getint(dict, "isle:Vertical Resolution", m_yRes); + m_exclusiveXRes = iniparser_getint(dict, "isle:Exclusive X Resolution", m_exclusiveXRes); + m_exclusiveYRes = iniparser_getint(dict, "isle:Exclusive Y Resolution", m_exclusiveXRes); + m_exclusiveFrameRate = iniparser_getdouble(dict, "isle:Exclusive Framerate", m_exclusiveFrameRate); + if (!m_fullScreen) { + 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(std::round(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))); const char* deviceId = iniparser_getstring(dict, "isle:3D Device ID", NULL); if (deviceId != NULL) { @@ -889,17 +1203,33 @@ bool IsleApp::LoadConfig() // [library:config] // The original game does not save any data if no savepath is given. // Instead, we use SDLs prefPath as a default fallback and always save data. -#ifdef __EMSCRIPTEN__ - const char* savePath = Emscripten_savePath; -#else const char* savePath = iniparser_getstring(dict, "isle:savepath", prefPath); -#endif m_savePath = new char[strlen(savePath) + 1]; strcpy(m_savePath, savePath); +#ifdef EXTENSIONS + for (const char* key : Extensions::availableExtensions) { + if (iniparser_getboolean(dict, key, 0)) { + std::vector extensionKeys; + const char* section = SDL_strchr(key, ':') + 1; + extensionKeys.resize(iniparser_getsecnkeys(dict, section)); + iniparser_getseckeys(dict, section, extensionKeys.data()); + + std::map extensionDict; + for (const char* key : extensionKeys) { + extensionDict[key] = iniparser_getstring(dict, key, NULL); + } + + Extensions::Enable(key, std::move(extensionDict)); + } + } +#endif + iniparser_freedict(dict); delete[] iniConfig; +#ifndef IOS SDL_free(prefPath); +#endif return true; } @@ -1003,15 +1333,19 @@ void IsleApp::SetupCursor(Cursor p_cursor) switch (p_cursor) { case e_cursorArrow: m_cursorCurrent = m_cursorArrow; + m_cursorCurrentBitmap = m_cursorArrowBitmap; break; case e_cursorBusy: m_cursorCurrent = m_cursorBusy; + m_cursorCurrentBitmap = m_cursorBusyBitmap; break; case e_cursorNo: m_cursorCurrent = m_cursorNo; + m_cursorCurrentBitmap = m_cursorNoBitmap; break; case e_cursorNone: m_cursorCurrent = NULL; + m_cursorCurrentBitmap = NULL; case e_cursorUnused3: case e_cursorUnused4: case e_cursorUnused5: @@ -1023,16 +1357,21 @@ void IsleApp::SetupCursor(Cursor p_cursor) break; } - if (m_cursorCurrent != NULL) { - SDL_SetCursor(m_cursorCurrent); - SDL_ShowCursor(); + if (g_isle->GetDrawCursor()) { + VideoManager()->SetCursorBitmap(m_cursorCurrentBitmap); } else { - SDL_HideCursor(); + if (m_cursorCurrent != NULL) { + SDL_SetCursor(m_cursorCurrent); + SDL_ShowCursor(); + } + else { + SDL_HideCursor(); + } } } -MxResult IsleApp::ParseArguments(int argc, char** argv) +SDL_AppResult IsleApp::ParseArguments(int argc, char** argv) { for (int i = 1, consumed; i < argc; i += consumed) { consumed = -1; @@ -1049,13 +1388,29 @@ MxResult IsleApp::ParseArguments(int argc, char** argv) #endif consumed = 1; } + else if (strcmp(argv[i], "--help") == 0) { + DisplayArgumentHelp(); + return SDL_APP_SUCCESS; + } if (consumed <= 0) { SDL_Log("Invalid argument(s): %s", argv[i]); - return FAILURE; + DisplayArgumentHelp(); + return SDL_APP_FAILURE; } } - return SUCCESS; + return SDL_APP_CONTINUE; +} + +void IsleApp::DisplayArgumentHelp() +{ + SDL_Log("Usage: isle [options]"); + SDL_Log("Options:"); + SDL_Log(" --ini Set custom path to .ini config"); +#ifdef ISLE_DEBUG + SDL_Log(" --debug Launch in debug mode"); +#endif + SDL_Log(" --help Show this help message"); } MxResult IsleApp::VerifyFilesystem() @@ -1098,6 +1453,34 @@ MxResult IsleApp::VerifyFilesystem() return SUCCESS; } +void IsleApp::DetectGameVersion() +{ + const char* file = "/lego/scripts/infocntr/infomain.si"; + SDL_PathInfo info; + bool success = false; + + MxString path = MxString(m_hdPath) + file; + path.MapPathToFilesystem(); + if (!(success = SDL_GetPathInfo(path.GetData(), &info))) { + path = MxString(m_cdPath) + file; + path.MapPathToFilesystem(); + success = SDL_GetPathInfo(path.GetData(), &info); + } + + assert(success); + + // File sizes of INFOMAIN.SI in English 1.0 and Japanese 1.0 + Lego()->SetVersion10(info.size == 58130432 || info.size == 57737216); + + if (Lego()->IsVersion10()) { + SDL_Log("Detected game version 1.0"); + SDL_SetWindowTitle(reinterpret_cast(m_windowHandle), "Lego Island"); + } + else { + SDL_Log("Detected game version 1.1"); + } +} + IDirect3DRMMiniwinDevice* GetD3DRMMiniwinDevice() { LegoVideoManager* videoManager = LegoOmni::GetInstance()->GetVideoManager(); @@ -1126,3 +1509,80 @@ IDirect3DRMMiniwinDevice* GetD3DRMMiniwinDevice() } return d3drmMiniwinDev; } + +void IsleApp::MoveVirtualMouseViaJoystick() +{ + float dpadX = 0.0f; + float dpadY = 0.0f; + + if (g_dpadLeft) { + dpadX -= m_cursorSensitivity; + } + if (g_dpadRight) { + dpadX += m_cursorSensitivity; + } + if (g_dpadUp) { + dpadY -= m_cursorSensitivity; + } + if (g_dpadDown) { + dpadY += m_cursorSensitivity; + } + + // Use joystick axis if non-zero, else fall back to dpad + float moveX = (g_lastJoystickMouseX != 0) ? g_lastJoystickMouseX : dpadX; + float moveY = (g_lastJoystickMouseY != 0) ? g_lastJoystickMouseY : dpadY; + + if (moveX != 0 || moveY != 0) { + g_mousemoved = TRUE; + + g_lastMouseX = SDL_clamp(g_lastMouseX + moveX, 0, g_targetWidth); + g_lastMouseY = SDL_clamp(g_lastMouseY + moveY, 0, g_targetHeight); + + if (InputManager()) { + InputManager()->QueueEvent( + c_notificationMouseMove, + g_mousedown ? LegoEventNotificationParam::c_lButtonState : 0, + g_lastMouseX, + g_lastMouseY, + 0 + ); + } + + SDL_HideCursor(); + g_isle->SetDrawCursor(TRUE); + if (VideoManager()) { + VideoManager()->SetCursorBitmap(m_cursorCurrentBitmap); + VideoManager()->MoveCursor(Min((MxS32) g_lastMouseX, 639), Min((MxS32) g_lastMouseY, 479)); + } + IDirect3DRMMiniwinDevice* device = GetD3DRMMiniwinDevice(); + if (device) { + Sint32 x, y; + device->ConvertRenderToWindowCoordinates(g_lastMouseX, g_lastMouseY, x, y); + g_mouseWarped = TRUE; + SDL_WarpMouseInWindow(window, x, y); + } + } +} + +void IsleApp::DetectDoubleTap(const SDL_TouchFingerEvent& p_event) +{ + typedef std::pair> LastTap; + + const MxU32 doubleTapMs = 500; + const float doubleTapDist = 0.001; + static LastTap lastTap = {0, {0, 0}}; + + LastTap currentTap = {p_event.timestamp, {p_event.x, p_event.y}}; + if (SDL_NS_TO_MS(currentTap.first - lastTap.first) < doubleTapMs && + DISTSQRD2(currentTap.second, lastTap.second) < doubleTapDist) { + + if (InputManager()) { + InputManager()->QueueEvent(c_notificationKeyPress, SDLK_SPACE, 0, 0, SDLK_SPACE); + } + + lastTap = {0, {0, 0}}; + } + else { + lastTap = currentTap; + } +} diff --git a/ISLE/isleapp.h b/ISLE/isleapp.h index d76a291b..66e8e6e1 100644 --- a/ISLE/isleapp.h +++ b/ISLE/isleapp.h @@ -1,8 +1,11 @@ #ifndef ISLEAPP_H #define ISLEAPP_H +#include "cursor.h" #include "lego1_export.h" +#include "legoinputmanager.h" #include "legoutils.h" +#include "mxtransitionmanager.h" #include "mxtypes.h" #include "mxvideoparam.h" @@ -50,19 +53,26 @@ class IsleApp { SDL_Cursor* GetCursorNo() { return m_cursorNo; } MxS32 GetDrawCursor() { return m_drawCursor; } MxS32 GetGameStarted() { return m_gameStarted; } + MxFloat GetCursorSensitivity() { return m_cursorSensitivity; } + LegoInputManager::TouchScheme GetTouchScheme() { return m_touchScheme; } + MxBool GetHaptic() { return m_haptic; } void SetWindowActive(MxS32 p_windowActive) { m_windowActive = p_windowActive; } void SetGameStarted(MxS32 p_gameStarted) { m_gameStarted = p_gameStarted; } + void SetDrawCursor(MxS32 p_drawCursor) { m_drawCursor = p_drawCursor; } - MxResult ParseArguments(int argc, char** argv); + SDL_AppResult ParseArguments(int argc, char** argv); MxResult VerifyFilesystem(); + void DetectGameVersion(); + void MoveVirtualMouseViaJoystick(); + void DetectDoubleTap(const SDL_TouchFingerEvent& p_event); private: char* m_hdPath; // 0x00 char* m_cdPath; // 0x04 char* m_deviceId; // 0x08 char* m_savePath; // 0x0c - MxS32 m_fullScreen; // 0x10 + MxBool m_fullScreen; // 0x10 MxS32 m_flipSurfaces; // 0x14 MxS32 m_backBuffersInVram; // 0x18 MxS32 m_using8bit; // 0x1c @@ -70,8 +80,6 @@ class IsleApp { MxS32 m_hasLightSupport; // 0x24 MxS32 m_use3dSound; // 0x28 MxS32 m_useMusic; // 0x2c - MxS32 m_useJoystick; // 0x30 - MxS32 m_joystickIndex; // 0x34 MxS32 m_wideViewAngle; // 0x38 MxS32 m_islandQuality; // 0x3c MxS32 m_islandTexture; // 0x40 @@ -85,14 +93,33 @@ class IsleApp { SDL_Cursor* m_cursorBusy; // 0x80 SDL_Cursor* m_cursorNo; // 0x84 SDL_Cursor* m_cursorCurrent; // 0x88 + const CursorBitmap* m_cursorArrowBitmap; + const CursorBitmap* m_cursorBusyBitmap; + const CursorBitmap* m_cursorNoBitmap; + const CursorBitmap* m_cursorCurrentBitmap; char* m_mediaPath; + MxFloat m_cursorSensitivity; + void DisplayArgumentHelp(); char* m_iniPath; MxFloat m_maxLod; MxU32 m_maxAllowedExtras; + MxTransitionManager::TransitionType m_transitionType; + LegoInputManager::TouchScheme m_touchScheme; + MxBool m_haptic; + MxS32 m_xRes; + MxS32 m_yRes; + MxS32 m_exclusiveXRes; + MxS32 m_exclusiveYRes; + MxFloat m_exclusiveFrameRate; + MxFloat m_frameRate; + MxBool m_exclusiveFullScreen; + MxU32 m_msaaSamples; + MxFloat m_anisotropic; }; extern IsleApp* g_isle; +extern MxS32 g_closed; extern IDirect3DRMMiniwinDevice* GetD3DRMMiniwinDevice(); diff --git a/ISLE/isledebug.cpp b/ISLE/isledebug.cpp index a8950fa3..5b9bd590 100644 --- a/ISLE/isledebug.cpp +++ b/ISLE/isledebug.cpp @@ -46,7 +46,7 @@ class DebugViewer { if (plantManager->m_numEntries) { if (ImGui::BeginTable("Animated Entries", 4, ImGuiTableFlags_Borders)) { ImGui::TableSetupColumn("ROI Name"); - ImGui::TableSetupColumn("ROI m_unk0x100"); + ImGui::TableSetupColumn("ROI m_sharedLodList"); ImGui::TableSetupColumn("Entity Name"); ImGui::TableSetupColumn("Time"); ImGui::TableHeadersRow(); @@ -55,7 +55,7 @@ class DebugViewer { ImGui::TableNextRow(); ImGui::Text("%s", entry->m_roi->m_name); ImGui::TableNextColumn(); - ImGui::Text("%d", entry->m_roi->m_unk0x100); + ImGui::Text("%d", entry->m_roi->m_sharedLodList); ImGui::TableNextColumn(); ImGui::Text("%s", entry->m_roi->m_entity->ClassName()); ImGui::TableNextColumn(); @@ -75,7 +75,7 @@ class DebugViewer { if (buildingManager->m_numEntries) { if (ImGui::BeginTable("Animated Entries", 6, ImGuiTableFlags_Borders)) { ImGui::TableSetupColumn("ROI Name"); - ImGui::TableSetupColumn("ROI m_unk0x100"); + ImGui::TableSetupColumn("ROI m_sharedLodList"); ImGui::TableSetupColumn("Entity Name"); ImGui::TableSetupColumn("Time"); ImGui::TableSetupColumn("Y"); @@ -86,13 +86,13 @@ class DebugViewer { ImGui::TableNextRow(); ImGui::Text("%s", entry->m_roi->m_name); ImGui::TableNextColumn(); - ImGui::Text("%d", entry->m_roi->m_unk0x100); + ImGui::Text("%d", entry->m_roi->m_sharedLodList); ImGui::TableNextColumn(); ImGui::Text("%s", entry->m_roi->m_entity->ClassName()); ImGui::TableNextColumn(); ImGui::Text("%d", entry->m_time); ImGui::TableNextColumn(); - ImGui::Text("%d", entry->m_y); + ImGui::Text("%f", entry->m_y); ImGui::TableNextColumn(); ImGui::Text("%d", entry->m_muted); } @@ -135,7 +135,7 @@ class DebugViewer { ImGui::Text("unk0x70: %u", videoManager->m_unk0x70); ImGui::Text("Dither: %d", videoManager->m_dither); ImGui::Text("BufferCount: %u", videoManager->m_bufferCount); - ImGui::Text("Paused: %f", videoManager->m_paused); + ImGui::Text("Paused: %d", videoManager->m_paused); ImGui::Text("back: %g", videoManager->m_back); ImGui::Text("front: %g", videoManager->m_front); ImGui::Text("cameraWidth: %g", videoManager->m_cameraWidth); @@ -309,7 +309,7 @@ void IsleDebug_Render() if (ImGui::TreeNode("Sound Manager")) { LegoSoundManager* soundManager = lego->GetSoundManager(); Sint32 oldVolume = soundManager->GetVolume(); - Sint32 volume = oldVolume; + int volume = oldVolume; ImGui::SliderInt("volume", &volume, 0, 100); if (volume != oldVolume) { soundManager->SetVolume(volume); diff --git a/ISLE/islefiles.cpp b/ISLE/islefiles.cpp index 6e0bb482..c6f4566d 100644 --- a/ISLE/islefiles.cpp +++ b/ISLE/islefiles.cpp @@ -46,3 +46,24 @@ const char* g_files[46] = { "/LEGO/data/WORLD.WDB", "/LEGO/data/testinf.dta", }; + +const char* g_textures[120] = { + "bank01.gif", "beach.gif", "black.gif", "bowtie.gif", "brela_01.gif", "bth1chst.gif", "bth2chst.gif", + "capch.gif", "capdb.gif", "capjs.gif", "capmd.gif", "caprc.gif", "cave_24x.gif", "caverocx.gif", + "caverokx.gif", "cheker01.gif", "construct.gif", "copchest.gif", "dbfrfn.gif", "doctor.gif", "dogface.gif", + "dummy.gif", "e.gif", "flowers.gif", "fruit.gif", "gasroad.gif", "gdface.gif", "g.gif", + "grassx.gif", "infochst.gif", "infoface.gif", "jailpad.gif", "jfrnt.gif", "jsfrnt4.gif", "jsfrnt.gif", + "jside.gif", "jswnsh5.gif", "jswnsh.gif", "l6.gif", "l.gif", "mamachst.gif", "mamaface.gif", + "mamamap.gif", "mech.gif", "medic01.gif", "mitesx.gif", "mustache.gif", "nickchst.gif", "nickface.gif", + "nickmap.gif", "nopizza.gif", "norachst.gif", "noraface.gif", "noramap.gif", "nwcurve.gif", "octan01.gif", + "octsq01.gif", "o.gif", "papachst.gif", "papaface.gif", "papamap.gif", "pebblesx.gif", "pepperha.gif", + "peppizza.gif", "peppmap.gif", "peprchst.gif", "peprface.gif", "pianokys.gif", "pizcurve.gif", "pizza01.gif", + "pizza.gif", "polbar01.gif", "polbla01.gif", "polkadot.gif", "polwhi01.gif", "postchst.gif", "post.gif", + "rac1chst.gif", "rac2chst.gif", "radar.gif", "raddis01.gif", "rcback.gif", "rc-butn.gif", "rcfrnt5.gif", + "rcfrnt6.gif", "rcfrnt7.gif", "rcfrnt.gif", "rcside1.gif", "rcside2.gif", "rcside3.gif", "rctail.gif", + "redskul.gif", "relrel01.gif", "road1way.gif", "road3wa2.gif", "road3wa3.gif", "road3way.gif", "road4way.gif", + "roadstr8.gif", "rockx.gif", "roofpiz.gif", "sandredx.gif", "se_curve.gif", "shftchst.gif", "shftface2.gif", + "shftface.gif", "shldwn02.gif", "skull.gif", "smile.gif", "smileshd.gif", "supr2_01.gif", "tightcrv.gif", + "unkchst.gif", "val_02.gif", "vest.gif", "water2x.gif", "w_curve.gif", "wnbars.gif", "woman.gif", + "womanshd.gif" +}; diff --git a/ISLE/res/arrow.png b/ISLE/res/arrow.png new file mode 100644 index 00000000..eaa08ca6 Binary files /dev/null and b/ISLE/res/arrow.png differ diff --git a/ISLE/res/arrow_bmp.h b/ISLE/res/arrow_bmp.h new file mode 100644 index 00000000..84e3452d --- /dev/null +++ b/ISLE/res/arrow_bmp.h @@ -0,0 +1,37 @@ +#pragma once + +// Generated from ISLE/res/arrow.png +// Dimensions: 32x32 +// This file is auto-generated, do not edit it. + +#include "cursor.h" + +static const unsigned char arrow_data[] = { + 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, + 0x48, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, + 0x41, 0x00, 0x00, 0x00, 0x40, 0x80, 0x00, 0x00, 0x40, 0x40, 0x00, 0x00, + 0x40, 0x20, 0x00, 0x00, 0x41, 0xF0, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, + 0x54, 0x80, 0x00, 0x00, 0x64, 0x80, 0x00, 0x00, 0x42, 0x40, 0x00, 0x00, + 0x02, 0x40, 0x00, 0x00, 0x01, 0x20, 0x00, 0x00, 0x01, 0x20, 0x00, 0x00, + 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +static const unsigned char arrow_mask[] = { + 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, + 0x78, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, + 0x7F, 0x00, 0x00, 0x00, 0x7F, 0x80, 0x00, 0x00, 0x7F, 0xC0, 0x00, 0x00, + 0x7F, 0xE0, 0x00, 0x00, 0x7F, 0xF0, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x00, + 0x77, 0x80, 0x00, 0x00, 0x67, 0x80, 0x00, 0x00, 0x43, 0xC0, 0x00, 0x00, + 0x03, 0xC0, 0x00, 0x00, 0x01, 0xE0, 0x00, 0x00, 0x01, 0xE0, 0x00, 0x00, + 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +static const CursorBitmap arrow_cursor = { 32, 32, arrow_data, arrow_mask }; diff --git a/ISLE/res/busy.png b/ISLE/res/busy.png new file mode 100644 index 00000000..cd8f5bf1 Binary files /dev/null and b/ISLE/res/busy.png differ diff --git a/ISLE/res/busy_bmp.h b/ISLE/res/busy_bmp.h new file mode 100644 index 00000000..020512bc --- /dev/null +++ b/ISLE/res/busy_bmp.h @@ -0,0 +1,37 @@ +#pragma once + +// Generated from ISLE/res/busy.png +// Dimensions: 32x32 +// This file is auto-generated, do not edit it. + +#include "cursor.h" + +static const unsigned char busy_data[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0x00, + 0x00, 0x40, 0x01, 0x00, 0x00, 0x7F, 0xFF, 0x00, 0x00, 0x20, 0x02, 0x00, + 0x00, 0x20, 0x02, 0x00, 0x00, 0x20, 0x02, 0x00, 0x00, 0x22, 0xA2, 0x00, + 0x00, 0x11, 0x44, 0x00, 0x00, 0x08, 0x88, 0x00, 0x00, 0x04, 0x10, 0x00, + 0x00, 0x02, 0x20, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x02, 0x20, 0x00, + 0x00, 0x02, 0x20, 0x00, 0x00, 0x04, 0x10, 0x00, 0x00, 0x08, 0x88, 0x00, + 0x00, 0x10, 0x04, 0x00, 0x00, 0x20, 0x82, 0x00, 0x00, 0x21, 0x42, 0x00, + 0x00, 0x22, 0xA2, 0x00, 0x00, 0x25, 0x52, 0x00, 0x00, 0x7F, 0xFF, 0x00, + 0x00, 0x40, 0x01, 0x00, 0x00, 0x7F, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +static const unsigned char busy_mask[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0x00, + 0x00, 0x7F, 0xFF, 0x00, 0x00, 0x7F, 0xFF, 0x00, 0x00, 0x3F, 0xFE, 0x00, + 0x00, 0x3F, 0xFE, 0x00, 0x00, 0x3F, 0xFE, 0x00, 0x00, 0x3F, 0xFE, 0x00, + 0x00, 0x1F, 0xFC, 0x00, 0x00, 0x0F, 0xF8, 0x00, 0x00, 0x07, 0xF0, 0x00, + 0x00, 0x03, 0xE0, 0x00, 0x00, 0x03, 0xE0, 0x00, 0x00, 0x03, 0xE0, 0x00, + 0x00, 0x03, 0xE0, 0x00, 0x00, 0x07, 0xF0, 0x00, 0x00, 0x0F, 0xF8, 0x00, + 0x00, 0x1F, 0xFC, 0x00, 0x00, 0x3F, 0xFE, 0x00, 0x00, 0x3F, 0xFE, 0x00, + 0x00, 0x3F, 0xFE, 0x00, 0x00, 0x3F, 0xFE, 0x00, 0x00, 0x7F, 0xFF, 0x00, + 0x00, 0x7F, 0xFF, 0x00, 0x00, 0x7F, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +static const CursorBitmap busy_cursor = { 32, 32, busy_data, busy_mask }; diff --git a/ISLE/res/no.png b/ISLE/res/no.png new file mode 100644 index 00000000..968adccd Binary files /dev/null and b/ISLE/res/no.png differ diff --git a/ISLE/res/no_bmp.h b/ISLE/res/no_bmp.h new file mode 100644 index 00000000..a4ebe829 --- /dev/null +++ b/ISLE/res/no_bmp.h @@ -0,0 +1,37 @@ +#pragma once + +// Generated from ISLE/res/no.png +// Dimensions: 32x32 +// This file is auto-generated, do not edit it. + +#include "cursor.h" + +static const unsigned char no_data[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xE0, 0x00, 0x00, 0x1F, 0xF8, 0x00, + 0x00, 0x3C, 0x3C, 0x00, 0x00, 0x70, 0x0E, 0x00, 0x00, 0xF8, 0x07, 0x00, + 0x00, 0xDC, 0x03, 0x00, 0x01, 0xCE, 0x03, 0x80, 0x01, 0x87, 0x01, 0x80, + 0x01, 0x83, 0x81, 0x80, 0x01, 0x81, 0xC1, 0x80, 0x01, 0x80, 0xE1, 0x80, + 0x01, 0xC0, 0x73, 0x80, 0x00, 0xC0, 0x3B, 0x00, 0x00, 0xE0, 0x1F, 0x00, + 0x00, 0x70, 0x0E, 0x00, 0x00, 0x3C, 0x1C, 0x00, 0x00, 0x1F, 0xF8, 0x00, + 0x00, 0x07, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +static const unsigned char no_mask[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x07, 0xE0, 0x00, 0x00, 0x1F, 0xF8, 0x00, 0x00, 0x3F, 0xFC, 0x00, + 0x00, 0x7F, 0xFE, 0x00, 0x00, 0xFC, 0x3F, 0x00, 0x01, 0xFC, 0x0F, 0x80, + 0x01, 0xFE, 0x07, 0x80, 0x03, 0xFF, 0x07, 0xC0, 0x03, 0xCF, 0x83, 0xC0, + 0x03, 0xC7, 0xC3, 0xC0, 0x03, 0xC3, 0xE3, 0xC0, 0x03, 0xC1, 0xF3, 0xC0, + 0x03, 0xE0, 0xFF, 0xC0, 0x01, 0xE0, 0x7F, 0x80, 0x01, 0xF0, 0x3F, 0x80, + 0x00, 0xFC, 0x1F, 0x00, 0x00, 0x7F, 0xFE, 0x00, 0x00, 0x3F, 0xFC, 0x00, + 0x00, 0x1F, 0xF8, 0x00, 0x00, 0x07, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +static const CursorBitmap no_cursor = { 32, 32, no_data, no_mask }; diff --git a/ISLE/xbox_one_series/config.cpp b/ISLE/xbox_one_series/config.cpp new file mode 100644 index 00000000..72ea32af --- /dev/null +++ b/ISLE/xbox_one_series/config.cpp @@ -0,0 +1,18 @@ +#include "config.h" + +#include +#include + +void XBONE_SetupDefaultConfigOverrides(dictionary* p_dictionary) +{ + SDL_Log("Overriding default config for Xbox One/Series"); + + // Use DevelopmentFiles path for disk and cd paths + // It's good to use that path since user can easily + // connect through SMB and copy the files + iniparser_set(p_dictionary, "isle:diskpath", "D:\\DevelopmentFiles\\isle\\"); + iniparser_set(p_dictionary, "isle:cdpath", "D:\\DevelopmentFiles\\isle\\"); + + // Enable cursor by default + iniparser_set(p_dictionary, "isle:Draw Cursor", "true"); +} diff --git a/ISLE/xbox_one_series/config.h b/ISLE/xbox_one_series/config.h new file mode 100644 index 00000000..bdfcb010 --- /dev/null +++ b/ISLE/xbox_one_series/config.h @@ -0,0 +1,8 @@ +#ifndef XBOX_ONE_SERIES_CONFIG_H +#define XBOX_ONE_SERIES_CONFIG_H + +#include "dictionary.h" + +void XBONE_SetupDefaultConfigOverrides(dictionary* p_dictionary); + +#endif // XBOX_ONE_SERIES_CONFIG_H diff --git a/LEGO1/cursor.h b/LEGO1/cursor.h new file mode 100644 index 00000000..171972c2 --- /dev/null +++ b/LEGO1/cursor.h @@ -0,0 +1,8 @@ +#pragma once + +typedef struct CursorBitmap { + int width; + int height; + const unsigned char* data; + const unsigned char* mask; +} CursorBitmap; diff --git a/LEGO1/lego/legoomni/include/act3.h b/LEGO1/lego/legoomni/include/act3.h index dc81160c..28129b4b 100644 --- a/LEGO1/lego/legoomni/include/act3.h +++ b/LEGO1/lego/legoomni/include/act3.h @@ -20,12 +20,12 @@ class MxQuaternionTransformer; struct Act3ListElement { MxU32 m_objectId; // 0x00 undefined4 m_unk0x04; // 0x04 - undefined m_unk0x08; // 0x08 + MxBool m_hasStarted; // 0x08 Act3ListElement() {} - Act3ListElement(MxU32 p_objectId, undefined4 p_unk0x04, undefined p_unk0x08) - : m_objectId(p_objectId), m_unk0x04(p_unk0x04), m_unk0x08(p_unk0x08) + Act3ListElement(MxU32 p_objectId, undefined4 p_unk0x04, MxBool p_hasStarted) + : m_objectId(p_objectId), m_unk0x04(p_unk0x04), m_hasStarted(p_hasStarted) { } @@ -36,12 +36,18 @@ struct Act3ListElement { // SIZE 0x10 class Act3List : private list { public: + enum InsertMode { + e_replaceAction = 1, + e_queueAction = 2, + e_onlyIfEmpty = 3 + }; + Act3List() { m_unk0x0c = 0; } - void Insert(MxS32 p_objectId, MxS32 p_option); - void FUN_10071fa0(); + void Insert(MxS32 p_objectId, InsertMode p_option); + void DeleteActionWrapper(); void Clear(); - void FUN_100720d0(MxU32 p_objectId); + void RemoveByObjectIdOrFirst(MxU32 p_objectId); private: undefined4 m_unk0x0c; // 0x0c @@ -129,7 +135,7 @@ class Act3 : public LegoWorld { void RemoveDonut(Act3Ammo& p_p); MxResult ShootPizza(LegoPathController* p_controller, Vector3& p_location, Vector3& p_direction, Vector3& p_up); MxResult ShootDonut(LegoPathController* p_controller, Vector3& p_location, Vector3& p_direction, Vector3& p_up); - void FUN_10072ad0(undefined4 p_param1); + void TriggerHitSound(undefined4 p_param1); MxResult FUN_10073360(Act3Ammo& p_ammo, const Vector3& p_param2); MxResult FUN_10073390(Act3Ammo& p_ammo, const Vector3& p_param2); void SetBrickster(Act3Brickster* p_brickster); @@ -168,12 +174,12 @@ class Act3 : public LegoWorld { Helicopter* m_copter; // 0x420c Act3Shark* m_shark; // 0x4210 MxFloat m_time; // 0x4214 - MxU8 m_unk0x4218; // 0x4218 - MxU8 m_unk0x4219; // 0x4219 - MxU8 m_unk0x421a; // 0x421a - MxU8 m_unk0x421b; // 0x421b - MxU8 m_unk0x421c; // 0x421c - MxU8 m_unk0x421d; // 0x421d + MxU8 m_pizzaHitSound; // 0x4218 + MxU8 m_pizzaMissSound; // 0x4219 + MxU8 m_copDonutSound; // 0x421a + MxU8 m_donutMissSound; // 0x421b + MxU8 m_islanderSound; // 0x421c + MxU8 m_bricksterDonutSound; // 0x421d undefined m_unk0x421e; // 0x421e Act3List m_unk0x4220; // 0x4220 MxPresenter* m_helicopterDots[15]; // 0x4230 diff --git a/LEGO1/lego/legoomni/include/act3ammo.h b/LEGO1/lego/legoomni/include/act3ammo.h index ee4e3dc1..e80aa6b0 100644 --- a/LEGO1/lego/legoomni/include/act3ammo.h +++ b/LEGO1/lego/legoomni/include/act3ammo.h @@ -90,7 +90,7 @@ class Act3Ammo : public LegoPathActor { // Act3Ammo::`scalar deleting destructor' private: - MxResult FUN_10053db0(float p_param1, const Matrix4& p_param2); + MxResult FUN_10053db0(float p_param1, Matrix4& p_param2); static Mx3DPointFloat g_unk0x10104f08; diff --git a/LEGO1/lego/legoomni/include/ambulance.h b/LEGO1/lego/legoomni/include/ambulance.h index 97e6ba38..4f0a0623 100644 --- a/LEGO1/lego/legoomni/include/ambulance.h +++ b/LEGO1/lego/legoomni/include/ambulance.h @@ -11,6 +11,12 @@ class MxEndActionNotificationParam; // SIZE 0x24 class AmbulanceMissionState : public LegoState { public: + enum { + e_ready = 0, + e_enteredAmbulance = 1, + e_prepareAmbulance = 2, + }; + AmbulanceMissionState(); // FUNCTION: LEGO1 0x10037440 @@ -125,18 +131,18 @@ class AmbulanceMissionState : public LegoState { // SYNTHETIC: LEGO1 0x100376c0 // AmbulanceMissionState::`scalar deleting destructor' - undefined4 m_unk0x08; // 0x08 - MxLong m_startTime; // 0x0c - MxS16 m_peScore; // 0x10 - MxS16 m_maScore; // 0x12 - MxS16 m_paScore; // 0x14 - MxS16 m_niScore; // 0x16 - MxS16 m_laScore; // 0x18 - MxS16 m_peHighScore; // 0x1a - MxS16 m_maHighScore; // 0x1c - MxS16 m_paHighScore; // 0x1e - MxS16 m_niHighScore; // 0x20 - MxS16 m_laHighScore; // 0x22 + MxU32 m_state; // 0x08 + MxLong m_startTime; // 0x0c + MxS16 m_peScore; // 0x10 + MxS16 m_maScore; // 0x12 + MxS16 m_paScore; // 0x14 + MxS16 m_niScore; // 0x16 + MxS16 m_laScore; // 0x18 + MxS16 m_peHighScore; // 0x1a + MxS16 m_maHighScore; // 0x1c + MxS16 m_paHighScore; // 0x1e + MxS16 m_niHighScore; // 0x20 + MxS16 m_laHighScore; // 0x22 }; // VTABLE: LEGO1 0x100d71a8 @@ -177,15 +183,21 @@ class Ambulance : public IslePathActor { virtual MxLong HandleEndAction(MxEndActionNotificationParam& p_param); // vtable+0xf4 void CreateState(); - void FUN_10036e60(); + void Init(); void ActivateSceneActions(); void StopActions(); - void FUN_10037250(); + void Reset(); // SYNTHETIC: LEGO1 0x10036130 // Ambulance::`scalar deleting destructor' private: + enum { + e_none = 0, + e_waiting = 1, + e_finished = 3, + }; + void PlayAnimation(IsleScript::Script p_objectId); void PlayFinalAnimation(IsleScript::Script p_objectId); void StopAction(IsleScript::Script p_objectId); @@ -196,10 +208,10 @@ class Ambulance : public IslePathActor { AmbulanceMissionState* m_state; // 0x164 MxS16 m_unk0x168; // 0x168 MxS16 m_actorId; // 0x16a - MxS16 m_unk0x16c; // 0x16c - MxS16 m_unk0x16e; // 0x16e - MxS16 m_unk0x170; // 0x170 - MxS16 m_unk0x172; // 0x172 + MxS16 m_atPoliceTask; // 0x16c + MxS16 m_atBeachTask; // 0x16e + MxS16 m_taskState; // 0x170 + MxS16 m_enableRandomAudio; // 0x172 IsleScript::Script m_lastAction; // 0x174 IsleScript::Script m_lastAnimation; // 0x178 MxFloat m_fuel; // 0x17c diff --git a/LEGO1/lego/legoomni/include/carrace.h b/LEGO1/lego/legoomni/include/carrace.h index 03e7a958..7a3b2f6f 100644 --- a/LEGO1/lego/legoomni/include/carrace.h +++ b/LEGO1/lego/legoomni/include/carrace.h @@ -52,13 +52,13 @@ class CarRace : public LegoRace { return !strcmp(p_name, CarRace::ClassName()) || LegoRace::IsA(p_name); } - MxResult Create(MxDSAction& p_dsAction) override; // vtable+0x18 - void ReadyWorld() override; // vtable+0x50 - MxBool Escape() override; // vtable+0x64 - MxLong HandleClick(LegoEventNotificationParam&) override; // vtable+0x6c - MxLong HandlePathStruct(LegoPathStructNotificationParam&) override; // vtable+0x70 - MxLong HandleEndAction(MxEndActionNotificationParam&) override; // vtable+0x74 - MxLong HandleType0Notification(MxNotificationParam&) override; // vtable+0x78 + MxResult Create(MxDSAction& p_dsAction) override; // vtable+0x18 + void ReadyWorld() override; // vtable+0x50 + MxBool Escape() override; // vtable+0x64 + MxLong HandleControl(LegoControlManagerNotificationParam&) override; // vtable+0x6c + MxLong HandlePathStruct(LegoPathStructNotificationParam&) override; // vtable+0x70 + MxLong HandleEndAction(MxEndActionNotificationParam&) override; // vtable+0x74 + MxLong HandleType0Notification(MxNotificationParam&) override; // vtable+0x78 // FUNCTION: BETA10 0x100cd060 RaceSkel* GetSkeleton() { return m_skeleton; } diff --git a/LEGO1/lego/legoomni/include/hospital.h b/LEGO1/lego/legoomni/include/hospital.h index 8629c2c2..be198776 100644 --- a/LEGO1/lego/legoomni/include/hospital.h +++ b/LEGO1/lego/legoomni/include/hospital.h @@ -123,7 +123,7 @@ class Hospital : public LegoWorld { MxLong m_copLedAnimTimer; // 0x11c MxLong m_pizzaLedAnimTimer; // 0x120 MxLong m_time; // 0x124 - undefined m_unk0x128; // 0x128 + MxBool m_exited; // 0x128 }; #endif // HOSPITAL_H diff --git a/LEGO1/lego/legoomni/include/infocenter.h b/LEGO1/lego/legoomni/include/infocenter.h index 470bdc31..aa0befd1 100644 --- a/LEGO1/lego/legoomni/include/infocenter.h +++ b/LEGO1/lego/legoomni/include/infocenter.h @@ -78,10 +78,20 @@ class InfocenterState : public LegoState { // SIZE 0x18 struct InfocenterMapEntry { + enum { + e_infocenter = 3, + e_jetrace = 10, + e_carrace = 11, + e_pizzeria = 12, + e_garage = 13, + e_hospital = 14, + e_police = 15, + }; + InfocenterMapEntry(); MxStillPresenter* m_destCtl; // 0x00 - undefined4 m_unk0x04; // 0x04 + MxU32 m_target; // 0x04 MxRect m_area; // 0x08 }; @@ -154,7 +164,7 @@ class Infocenter : public LegoWorld { void PlayCutscene(Cutscene p_entityId, MxBool p_scale); void StopCutscene(); - void FUN_10070d10(MxS32 p_x, MxS32 p_y); + void UpdateEnabledGlowControl(MxS32 p_x, MxS32 p_y); void StartCredits(); void StopCredits(); @@ -173,12 +183,12 @@ class Infocenter : public LegoWorld { Radio m_radio; // 0x10c MxStillPresenter* m_dragPresenter; // 0x11c InfocenterMapEntry m_glowInfo[7]; // 0x120 - MxS16 m_unk0x1c8; // 0x1c8 + MxS16 m_enabledGlowControl; // 0x1c8 MxStillPresenter* m_frame; // 0x1cc MxS16 m_infoManDialogueTimer; // 0x1d0 MxS16 m_bookAnimationTimer; // 0x1d2 - MxU16 m_unk0x1d4; // 0x1d4 - MxS16 m_unk0x1d6; // 0x1d6 + MxU16 m_playingMovieCounter; // 0x1d4 + MxS16 m_bigInfoBlinkTimer; // 0x1d6 }; #endif // INFOCENTER_H diff --git a/LEGO1/lego/legoomni/include/isle.h b/LEGO1/lego/legoomni/include/isle.h index 2c6c8091..53edd931 100644 --- a/LEGO1/lego/legoomni/include/isle.h +++ b/LEGO1/lego/legoomni/include/isle.h @@ -34,6 +34,21 @@ class Act1State : public LegoState { c_floor3 }; + enum { + e_none = 0, + e_initial = 1, + e_elevator = 2, + e_pizza = 3, + e_helicopter = 4, + e_transitionToJetski = 5, + e_transitionToRacecar = 6, + e_transitionToTowtrack = 7, + e_towtrack = 8, + e_transitionToAmbulance = 9, + e_ambulance = 10, + e_jukebox = 11, + }; + Act1State(); // FUNCTION: LEGO1 0x100338a0 @@ -58,11 +73,11 @@ class Act1State : public LegoState { void RemoveActors(); void PlaceActors(); - MxU32 GetUnknown18() { return m_unk0x018; } + MxU32 GetState() { return m_state; } ElevatorFloor GetElevatorFloor() { return (ElevatorFloor) m_elevFloor; } MxU8 GetUnknown21() { return m_unk0x021; } - void SetUnknown18(MxU32 p_unk0x18) { m_unk0x018 = p_unk0x18; } + void SetState(MxU32 p_state) { m_state = p_state; } void SetElevatorFloor(ElevatorFloor p_elevFloor) { m_elevFloor = p_elevFloor; } void SetUnknown21(MxU8 p_unk0x21) { m_unk0x021 = p_unk0x21; } @@ -73,7 +88,7 @@ class Act1State : public LegoState { Playlist m_cptClickDialogue; // 0x008 IsleScript::Script m_currentCptClickDialogue; // 0x014 - MxU32 m_unk0x018; // 0x018 + MxU32 m_state; // 0x018 MxS16 m_elevFloor; // 0x01c MxBool m_unk0x01e; // 0x01e MxBool m_unk0x01f; // 0x01f diff --git a/LEGO1/lego/legoomni/include/jetskirace.h b/LEGO1/lego/legoomni/include/jetskirace.h index 7542d851..61407cce 100644 --- a/LEGO1/lego/legoomni/include/jetskirace.h +++ b/LEGO1/lego/legoomni/include/jetskirace.h @@ -29,12 +29,12 @@ class JetskiRace : public LegoRace { return !strcmp(p_name, JetskiRace::ClassName()) || LegoRace::IsA(p_name); } - MxResult Create(MxDSAction& p_dsAction) override; // vtable+0x18 - void ReadyWorld() override; // vtable+0x50 - MxBool Escape() override; // vtable+0x64 - MxLong HandleClick(LegoEventNotificationParam&) override; // vtable+0x6c - MxLong HandlePathStruct(LegoPathStructNotificationParam&) override; // vtable+0x70 - MxLong HandleEndAction(MxEndActionNotificationParam&) override; // vtable+0x74 + MxResult Create(MxDSAction& p_dsAction) override; // vtable+0x18 + void ReadyWorld() override; // vtable+0x50 + MxBool Escape() override; // vtable+0x64 + MxLong HandleControl(LegoControlManagerNotificationParam&) override; // vtable+0x6c + MxLong HandlePathStruct(LegoPathStructNotificationParam&) override; // vtable+0x70 + MxLong HandleEndAction(MxEndActionNotificationParam&) override; // vtable+0x74 void FUN_10016930(MxS32 p_param1, MxS16 p_param2); diff --git a/LEGO1/lego/legoomni/include/legoanimationmanager.h b/LEGO1/lego/legoomni/include/legoanimationmanager.h index 94bdc9fa..4b764d0b 100644 --- a/LEGO1/lego/legoomni/include/legoanimationmanager.h +++ b/LEGO1/lego/legoomni/include/legoanimationmanager.h @@ -304,4 +304,7 @@ class LegoAnimationManager : public MxCore { // TEMPLATE: LEGO1 0x10061750 // MxListCursor::MxListCursor +// TEMPLATE: BETA10 0x1004b5d0 +// MxListCursor::Next + #endif // LEGOANIMATIONMANAGER_H diff --git a/LEGO1/lego/legoomni/include/legoanimpresenter.h b/LEGO1/lego/legoomni/include/legoanimpresenter.h index 85917cbc..6e983144 100644 --- a/LEGO1/lego/legoomni/include/legoanimpresenter.h +++ b/LEGO1/lego/legoomni/include/legoanimpresenter.h @@ -2,6 +2,7 @@ #define LEGOANIMPRESENTER_H #include "legoroilist.h" +#include "legoroimaplist.h" #include "mxatom.h" #include "mxvideopresenter.h" @@ -92,7 +93,11 @@ class LegoAnimPresenter : public MxVideoPresenter { const char* GetActionObjectName(); void SetCurrentWorld(LegoWorld* p_currentWorld) { m_currentWorld = p_currentWorld; } + + // FUNCTION: BETA10 0x1005aad0 void SetUnknown0x0cTo1() { m_unk0x9c = 1; } + + // FUNCTION: BETA10 0x1005ab00 void SetUnknown0xa0(Matrix4* p_unk0xa0) { m_unk0xa0 = p_unk0xa0; } LegoAnim* GetAnimation() { return m_anim; } @@ -121,7 +126,7 @@ class LegoAnimPresenter : public MxVideoPresenter { void SubstituteVariables(); void FUN_1006b900(LegoAnim* p_anim, MxLong p_time, Matrix4* p_matrix); void FUN_1006b9a0(LegoAnim* p_anim, MxLong p_time, Matrix4* p_matrix); - void FUN_1006c8a0(MxBool p_bool); + void SetDisabled(MxBool p_disabled); LegoAnim* m_anim; // 0x64 LegoROI** m_roiMap; // 0x68 @@ -143,14 +148,191 @@ class LegoAnimPresenter : public MxVideoPresenter { MxS16 m_unk0x9c; // 0x9c Matrix4* m_unk0xa0; // 0xa0 + // SYNTHETIC: LEGO1 0x10068650 + // LegoAnimPresenter::`scalar deleting destructor' + public: float m_unk0xa4; // 0xa4 Mx3DPointFloat m_unk0xa8; // 0xa8 }; +// VTABLE: LEGO1 0x100d4900 +// SIZE 0xc0 +class LegoLoopingAnimPresenter : public LegoAnimPresenter { +public: + // FUNCTION: BETA10 0x1005c6f0 + static const char* HandlerClassName() + { + // STRING: LEGO1 0x100f0700 + return "LegoLoopingAnimPresenter"; + } + + // FUNCTION: LEGO1 0x1000c9a0 + // FUNCTION: BETA10 0x1005c6c0 + const char* ClassName() const override // vtable+0x0c + { + return HandlerClassName(); + } + + // FUNCTION: LEGO1 0x1000c9b0 + MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, ClassName()) || LegoAnimPresenter::IsA(p_name); + } + + void StreamingTickle() override; // vtable+0x20 + void PutFrame() override; // vtable+0x6c + + // SYNTHETIC: LEGO1 0x1006d000 + // LegoLoopingAnimPresenter::~LegoLoopingAnimPresenter + + // SYNTHETIC: LEGO1 0x1000f440 + // LegoLoopingAnimPresenter::`scalar deleting destructor' + +private: + undefined4 m_unk0xbc; // 0xbc +}; + +class LegoAnimActor; + +// VTABLE: LEGO1 0x100d9170 +// SIZE 0xd8 +class LegoLocomotionAnimPresenter : public LegoLoopingAnimPresenter { +public: + LegoLocomotionAnimPresenter(); + ~LegoLocomotionAnimPresenter() override; + + // FUNCTION: BETA10 0x1005c4e0 + static const char* HandlerClassName() + { + // STRING: LEGO1 0x100f06e4 + return "LegoLocomotionAnimPresenter"; + } + + // FUNCTION: LEGO1 0x1006ce50 + // FUNCTION: BETA10 0x1005c4b0 + const char* ClassName() const override // vtable+0x0c + { + return HandlerClassName(); + } + + // FUNCTION: LEGO1 0x1006ce60 + MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, ClassName()) || LegoLoopingAnimPresenter::IsA(p_name); + } + + void ReadyTickle() override; // vtable+0x18 + void StartingTickle() override; // vtable+0x1c + void StreamingTickle() override; // vtable+0x20 + MxResult AddToManager() override; // vtable+0x34 + void Destroy() override; // vtable+0x38 + void EndAction() override; // vtable+0x40 + void PutFrame() override; // vtable+0x6c + MxResult CreateAnim(MxStreamChunk* p_chunk) override; // vtable+0x88 + + void FUN_1006d680(LegoAnimActor* p_actor, MxFloat p_value); + + void DecrementUnknown0xd4() + { + if (m_unk0xd4) { + --m_unk0xd4; + } + } + + undefined2 GetUnknown0xd4() { return m_unk0xd4; } + + // SYNTHETIC: LEGO1 0x1006cfe0 + // LegoLocomotionAnimPresenter::`scalar deleting destructor' + +private: + void Init(); + void Destroy(MxBool p_fromDestructor); + + undefined4 m_unk0xc0; // 0xc0 + undefined4* m_unk0xc4; // 0xc4 + LegoROIMapList* m_roiMapList; // 0xc8 + MxS32 m_unk0xcc; // 0xcc + MxS32 m_unk0xd0; // 0xd0 + undefined2 m_unk0xd4; // 0xd4 +}; + +class LegoPathBoundary; + +struct LegoHideAnimStructComparator { + MxBool operator()(const char* const& p_a, const char* const& p_b) const { return strcmp(p_a, p_b) < 0; } +}; + +// SIZE 0x08 +struct LegoHideAnimStruct { + LegoPathBoundary* m_boundary; // 0x00 + MxU32 m_index; // 0x04 +}; + +typedef map LegoHideAnimStructMap; + +// VTABLE: LEGO1 0x100d9278 +// SIZE 0xc4 +class LegoHideAnimPresenter : public LegoLoopingAnimPresenter { +public: + LegoHideAnimPresenter(); + ~LegoHideAnimPresenter() override; + + // FUNCTION: LEGO1 0x1006d860 + void VTable0x8c() override {} // vtable+0x8c + + // FUNCTION: LEGO1 0x1006d870 + void VTable0x90() override {} // vtable+0x90 + + // FUNCTION: BETA10 0x1005d4a0 + static const char* HandlerClassName() + { + // STRING: LEGO1 0x100f06cc + return "LegoHideAnimPresenter"; + } + + // FUNCTION: LEGO1 0x1006d880 + // FUNCTION: BETA10 0x1005d470 + const char* ClassName() const override // vtable+0x0c + { + return HandlerClassName(); + } + + // FUNCTION: LEGO1 0x1006d890 + MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, ClassName()) || LegoAnimPresenter::IsA(p_name); + } + + void ReadyTickle() override; // vtable+0x18 + void StartingTickle() override; // vtable+0x18 + MxResult AddToManager() override; // vtable+0x34 + void Destroy() override; // vtable+0x38 + void EndAction() override; // vtable+0x40 + void PutFrame() override; // vtable+0x6c + + void FUN_1006db40(LegoTime p_time); + + // SYNTHETIC: LEGO1 0x1006d9d0 + // LegoHideAnimPresenter::`scalar deleting destructor' + +private: + void Init(); + void Destroy(MxBool p_fromDestructor); + void FUN_1006db60(LegoTreeNode* p_node, LegoTime p_time); + void FUN_1006dc10(); + void FUN_1006e3f0(LegoHideAnimStructMap& p_map, LegoTreeNode* p_node); + void FUN_1006e470( + LegoHideAnimStructMap& p_map, + LegoAnimNodeData* p_data, + const char* p_name, + LegoPathBoundary* p_boundary + ); + + LegoPathBoundary** m_boundaryMap; // 0xc0 +}; + // clang-format off -// SYNTHETIC: LEGO1 0x10068650 -// LegoAnimPresenter::`scalar deleting destructor' // TEMPLATE: LEGO1 0x100689c0 // map >::~map > @@ -208,6 +390,33 @@ class LegoAnimPresenter : public MxVideoPresenter { // GLOBAL: LEGO1 0x100f7688 // _Tree,map >::_Kfn,LegoAnimStructComparator,allocator >::_Nil + +// TEMPLATE: LEGO1 0x1006ddb0 +// _Tree,map >::_Kfn,LegoHideAnimStructComparator,allocator >::~_Tree,map >::_Kfn,LegoHideAnimStructComparator,allocator >::iterator::_Inc + +// TEMPLATE: LEGO1 0x1006dec0 +// _Tree,map >::_Kfn,LegoHideAnimStructComparator,allocator >::erase + +// TEMPLATE: LEGO1 0x1006e310 +// _Tree,map >::_Kfn,LegoHideAnimStructComparator,allocator >::_Erase + +// TEMPLATE: LEGO1 0x1006e350 +// Map::~Map + +// TEMPLATE: LEGO1 0x1006e3a0 +// map >::~map > + +// TEMPLATE: LEGO1 0x1006e6d0 +// _Tree,map >::_Kfn,LegoHideAnimStructComparator,allocator >::iterator::_Dec + +// TEMPLATE: LEGO1 0x1006e720 +// _Tree,map >::_Kfn,LegoHideAnimStructComparator,allocator >::_Insert + +// GLOBAL: LEGO1 0x100f768c +// _Tree,map >::_Kfn,LegoHideAnimStructComparator,allocator >::_Nil // clang-format on #endif // LEGOANIMPRESENTER_H diff --git a/LEGO1/lego/legoomni/include/legobuildingmanager.h b/LEGO1/lego/legoomni/include/legobuildingmanager.h index 5dd83221..4d27695c 100644 --- a/LEGO1/lego/legoomni/include/legobuildingmanager.h +++ b/LEGO1/lego/legoomni/include/legobuildingmanager.h @@ -79,7 +79,7 @@ class LegoBuildingManager : public MxCore { MxBool SwitchMove(LegoEntity* p_entity); MxBool SwitchMood(LegoEntity* p_entity); MxU32 GetAnimationId(LegoEntity* p_entity); - MxU32 GetSoundId(LegoEntity* p_entity, MxBool p_state); + MxU32 GetSoundId(LegoEntity* p_entity, MxBool p_basedOnMood); MxBool DecrementCounter(LegoEntity* p_entity); MxBool DecrementCounter(MxS32 p_index); MxBool DecrementCounter(LegoBuildingInfo* p_data); diff --git a/LEGO1/lego/legoomni/include/legocachesoundmanager.h b/LEGO1/lego/legoomni/include/legocachesoundmanager.h index 2f9f851b..642ef087 100644 --- a/LEGO1/lego/legoomni/include/legocachesoundmanager.h +++ b/LEGO1/lego/legoomni/include/legocachesoundmanager.h @@ -48,10 +48,13 @@ typedef set Set100d6b4c; typedef list List100d6b4c; // VTABLE: LEGO1 0x100d6b4c +// VTABLE: BETA10 0x101becac // SIZE 0x20 class LegoCacheSoundManager { public: + // FUNCTION: BETA10 0x100d0a60 LegoCacheSoundManager() {} + ~LegoCacheSoundManager(); virtual MxResult Tickle(); // vtable+0x00 @@ -68,6 +71,9 @@ class LegoCacheSoundManager { List100d6b4c m_list; // 0x14 }; +// SYNTHETIC: BETA10 0x100d06b0 +// LegoCacheSoundManager::`scalar deleting destructor' + // TODO: Function names subject to change. // clang-format off diff --git a/LEGO1/lego/legoomni/include/legocameracontroller.h b/LEGO1/lego/legoomni/include/legocameracontroller.h index 4dcb6c39..cf4e8f0a 100644 --- a/LEGO1/lego/legoomni/include/legocameracontroller.h +++ b/LEGO1/lego/legoomni/include/legocameracontroller.h @@ -38,17 +38,17 @@ class LegoCameraController : public LegoPointOfViewController { virtual MxResult Create(); // vtable+0x44 void SetWorldTransform(const Vector3& p_at, const Vector3& p_dir, const Vector3& p_up); - void FUN_10012290(float p_angle); - void FUN_10012320(float p_angle); - MxResult FUN_100123b0(Matrix4& p_matrix); - void FUN_100123e0(const Matrix4& p_transform, MxU32 p_und); + void RotateZ(float p_angle); + void RotateY(float p_angle); + MxResult GetPointOfView(Matrix4& p_matrix); + void TransformPointOfView(const Matrix4& p_transform, MxU32 p_multiply); Mx3DPointFloat GetWorldUp(); Mx3DPointFloat GetWorldLocation(); Mx3DPointFloat GetWorldDirection(); private: - MxMatrix m_matrix1; // 0x38 - MxMatrix m_matrix2; // 0x80 + MxMatrix m_currentTransform; // 0x38 + MxMatrix m_originalTransform; // 0x80 }; // SYNTHETIC: LEGO1 0x10011f50 diff --git a/LEGO1/lego/legoomni/include/legocarbuild.h b/LEGO1/lego/legoomni/include/legocarbuild.h index 916a5937..e15f8598 100644 --- a/LEGO1/lego/legoomni/include/legocarbuild.h +++ b/LEGO1/lego/legoomni/include/legocarbuild.h @@ -137,11 +137,11 @@ class LegoCarBuild : public LegoWorld { void FUN_10022f00(); void FUN_10022f30(); void FUN_10023130(MxLong p_x, MxLong p_y); - void FUN_100236d0(); + void AddSelectedPartToBuild(); undefined4 FUN_10024250(LegoEventNotificationParam* p_param); void FUN_100243a0(); undefined4 FUN_10024480(MxActionNotificationParam* p_param); - undefined4 FUN_100244e0(MxLong p_x, MxLong p_y); + undefined4 SelectPartFromMousePosition(MxLong p_x, MxLong p_y); undefined4 FUN_100246e0(MxLong p_x, MxLong p_y); MxS32 FUN_10024850(MxLong p_x, MxLong p_y); undefined4 FUN_10024890(MxParam* p_param); @@ -184,7 +184,7 @@ class LegoCarBuild : public LegoWorld { MxU8 m_unk0x109; // 0x109 MxU16 m_unk0x10a; // 0x10a Uint64 m_unk0x10c; // 0x10c - LegoROI* m_unk0x110; // 0x110 + LegoROI* m_selectedPart; // 0x110 BoundingSphere m_unk0x114; // 0x114 MxMatrix m_unk0x12c; // 0x12c undefined m_unk0x174; // 0x174 @@ -202,10 +202,10 @@ class LegoCarBuild : public LegoWorld { MxS32 m_unk0x290[2]; // 0x290 MxS32 m_unk0x298[2]; // 0x298 - MxFloat m_unk0x2a0; // 0x2a0 - Mx4DPointFloat m_unk0x2a4; // 0x2a4 - Mx4DPointFloat m_unk0x2bc; // 0x2bc - MxBool m_unk0x2d4; // 0x2d4 + MxFloat m_unk0x2a0; // 0x2a0 + Mx4DPointFloat m_unk0x2a4; // 0x2a4 + Mx4DPointFloat m_unk0x2bc; // 0x2bc + MxBool m_selectedPartIsPlaced; // 0x2d4 // variable names verified by BETA10 0x1006b27a MxStillPresenter* m_ColorBook_Bitmap; // 0x2dc diff --git a/LEGO1/lego/legoomni/include/legocarbuildpresenter.h b/LEGO1/lego/legoomni/include/legocarbuildpresenter.h index a13c1adf..31423e32 100644 --- a/LEGO1/lego/legoomni/include/legocarbuildpresenter.h +++ b/LEGO1/lego/legoomni/include/legocarbuildpresenter.h @@ -77,11 +77,11 @@ class LegoCarBuildAnimPresenter : public LegoAnimPresenter { void FUN_10079050(MxS16 p_index); void SwapNodesByName(LegoChar* p_param1, LegoChar* p_param2); void InitBuildPlatform(); - void FUN_100795d0(LegoChar* p_param); - void FUN_10079680(LegoChar* p_param); + void HideBuildPartByName(LegoChar* p_param); + void ShowBuildPartByName(LegoChar* p_param); LegoAnimNodeData* FindNodeDataByName(LegoTreeNode* p_treeNode, const LegoChar* p_name); LegoTreeNode* FindNodeByName(LegoTreeNode* p_treeNode, const LegoChar* p_name); - void FUN_10079790(const LegoChar* p_name); + void AddPartToBuildByName(const LegoChar* p_name); void RotateAroundYAxis(MxFloat p_angle); MxBool FUN_10079c30(const LegoChar* p_name); MxBool PartIsPlaced(const LegoChar* p_name); diff --git a/LEGO1/lego/legoomni/include/legocharactermanager.h b/LEGO1/lego/legoomni/include/legocharactermanager.h index 2f9d9551..4443ca8a 100644 --- a/LEGO1/lego/legoomni/include/legocharactermanager.h +++ b/LEGO1/lego/legoomni/include/legocharactermanager.h @@ -48,6 +48,7 @@ struct LegoActorInfo; typedef map LegoCharacterMap; // VTABLE: LEGO1 0x100da878 +// VTABLE: BETA10 0x101bc028 // SIZE 0x24 class CustomizeAnimFileVariable : public MxVariable { public: @@ -88,7 +89,7 @@ class LegoCharacterManager { MxBool SwitchMove(LegoROI* p_roi); MxBool SwitchMood(LegoROI* p_roi); MxU32 GetAnimationId(LegoROI* p_roi); - MxU32 GetSoundId(LegoROI* p_roi, MxBool p_und); + MxU32 GetSoundId(LegoROI* p_roi, MxBool p_basedOnMood); MxU8 GetMood(LegoROI* p_roi); LegoROI* CreateAutoROI(const char* p_name, const char* p_lodName, MxBool p_createEntity); MxResult UpdateBoundingSphereAndBox(LegoROI* p_roi); diff --git a/LEGO1/lego/legoomni/include/legocontrolmanager.h b/LEGO1/lego/legoomni/include/legocontrolmanager.h index 828a1f6e..680bef59 100644 --- a/LEGO1/lego/legoomni/include/legocontrolmanager.h +++ b/LEGO1/lego/legoomni/include/legocontrolmanager.h @@ -24,11 +24,11 @@ class LegoControlManagerNotificationParam : public LegoEventNotificationParam { void SetClickedObjectId(MxS32 p_clickedObjectId) { m_clickedObjectId = p_clickedObjectId; } void SetClickedAtom(const char* p_clickedAtom) { m_clickedAtom = p_clickedAtom; } - void SetUnknown0x28(MxS16 p_unk0x28) { m_unk0x28 = p_unk0x28; } + void SetEnabledChild(MxS16 p_enabledChild) { m_enabledChild = p_enabledChild; } MxS32 m_clickedObjectId; // 0x20 const char* m_clickedAtom; // 0x24 - MxS16 m_unk0x28; // 0x28 + MxS16 m_enabledChild; // 0x28 }; // SYNTHETIC: LEGO1 0x10028bf0 @@ -66,27 +66,33 @@ class LegoControlManager : public MxCore { return !strcmp(p_name, LegoControlManager::ClassName()) || MxCore::IsA(p_name); } - void FUN_10028df0(MxPresenterList* p_presenterList); + void SetPresenterList(MxPresenterList* p_presenterList); void Register(MxCore* p_listener); void Unregister(MxCore* p_listener); - MxBool FUN_10029210(LegoEventNotificationParam& p_param, MxPresenter* p_presenter); - void FUN_100293c0(MxU32 p_objectId, const char* p_atom, MxS16 p_unk0x4e); - MxControlPresenter* FUN_100294e0(MxS32 p_x, MxS32 p_y); - MxBool FUN_10029630(); - MxBool FUN_10029750(); - void FUN_100292e0(); + MxBool HandleButtonDown(LegoEventNotificationParam& p_param, MxPresenter* p_presenter); + void UpdateEnabledChild(MxU32 p_objectId, const char* p_atom, MxS16 p_enabledChild); + MxControlPresenter* GetControlAt(MxS32 p_x, MxS32 p_y); + MxBool HandleButtonDown(); + MxBool HandleButtonUp(); + void Notify(); - undefined4 GetUnknown0x0c() { return m_unk0x0c; } - undefined GetUnknown0x10() { return m_unk0x10; } + MxU32 HandleUpNextTickle() { return m_handleUpNextTickle; } + MxBool IsSecondButtonDown() { return m_secondButtonDown; } // SYNTHETIC: LEGO1 0x10028d40 // LegoControlManager::`scalar deleting destructor' private: - undefined4 m_unk0x08; // 0x08 - undefined4 m_unk0x0c; // 0x0c - MxBool m_unk0x10; // 0x10 - MxPresenter* m_unk0x14; // 0x14 + enum { + e_idle = 0, + e_waitNextTickle = 1, + e_tickled = 2, + }; + + MxU32 m_buttonDownState; // 0x08 + MxU32 m_handleUpNextTickle; // 0x0c + MxBool m_secondButtonDown; // 0x10 + MxPresenter* m_handledPresenter; // 0x14 LegoControlManagerNotificationParam m_event; // 0x18 MxPresenterList* m_presenterList; // 0x44 LegoNotifyList m_notifyList; // 0x48 diff --git a/LEGO1/lego/legoomni/include/legoentity.h b/LEGO1/lego/legoomni/include/legoentity.h index eecf6867..a6d9d9ee 100644 --- a/LEGO1/lego/legoomni/include/legoentity.h +++ b/LEGO1/lego/legoomni/include/legoentity.h @@ -28,7 +28,7 @@ class LegoEntity : public MxEntity { }; enum { - c_altBit1 = 0x01 + c_disabled = 0x01 }; LegoEntity() { Init(); } @@ -68,13 +68,13 @@ class LegoEntity : public MxEntity { // FUNCTION: BETA10 0x10013260 virtual void SetWorldSpeed(MxFloat p_worldSpeed) { m_worldSpeed = p_worldSpeed; } // vtable+0x30 - virtual void ClickSound(MxBool p_und); // vtable+0x34 - virtual void ClickAnimation(); // vtable+0x38 - virtual void SwitchVariant(); // vtable+0x3c - virtual void SwitchSound(); // vtable+0x40 - virtual void SwitchMove(); // vtable+0x44 - virtual void SwitchColor(LegoROI* p_roi); // vtable+0x48 - virtual void SwitchMood(); // vtable+0x4c + virtual void ClickSound(MxBool p_basedOnMood); // vtable+0x34 + virtual void ClickAnimation(); // vtable+0x38 + virtual void SwitchVariant(); // vtable+0x3c + virtual void SwitchSound(); // vtable+0x40 + virtual void SwitchMove(); // vtable+0x44 + virtual void SwitchColor(LegoROI* p_roi); // vtable+0x48 + virtual void SwitchMood(); // vtable+0x4c void FUN_10010c30(); void SetType(MxU8 p_type); @@ -83,7 +83,7 @@ class LegoEntity : public MxEntity { Mx3DPointFloat GetWorldUp(); Mx3DPointFloat GetWorldPosition(); - MxBool GetUnknown0x10IsSet(MxU8 p_flag) { return m_unk0x10 & p_flag; } + MxBool IsInteraction(MxU8 p_flag) { return m_interaction & p_flag; } MxBool GetFlagsIsSet(MxU8 p_flag) { return m_flags & p_flag; } MxU8 GetFlags() { return m_flags; } @@ -101,14 +101,14 @@ class LegoEntity : public MxEntity { void SetFlags(MxU8 p_flags) { m_flags = p_flags; } void SetFlag(MxU8 p_flag) { m_flags |= p_flag; } void ClearFlag(MxU8 p_flag) { m_flags &= ~p_flag; } - void SetUnknown0x10Flag(MxU8 p_flag) { m_unk0x10 |= p_flag; } - void ClearUnknown0x10Flag(MxU8 p_flag) { m_unk0x10 &= ~p_flag; } + void SetInteractionFlag(MxU8 p_flag) { m_interaction |= p_flag; } + void ClearInteractionFlag(MxU8 p_flag) { m_interaction &= ~p_flag; } protected: void Init(); void SetWorld(); - MxU8 m_unk0x10; // 0x10 + MxU8 m_interaction; // 0x10 MxU8 m_flags; // 0x11 Mx3DPointFloat m_worldLocation; // 0x14 Mx3DPointFloat m_worldDirection; // 0x28 diff --git a/LEGO1/lego/legoomni/include/legoeventnotificationparam.h b/LEGO1/lego/legoomni/include/legoeventnotificationparam.h index a88c62f0..5569280c 100644 --- a/LEGO1/lego/legoomni/include/legoeventnotificationparam.h +++ b/LEGO1/lego/legoomni/include/legoeventnotificationparam.h @@ -18,6 +18,7 @@ class LegoEventNotificationParam : public MxNotificationParam { c_rButtonState = 2, c_modKey1 = 4, c_modKey2 = 8, + c_motionHandled = 16, }; // FUNCTION: LEGO1 0x10028690 diff --git a/LEGO1/lego/legoomni/include/legogamestate.h b/LEGO1/lego/legoomni/include/legogamestate.h index 28e5b47d..44d5bc27 100644 --- a/LEGO1/lego/legoomni/include/legogamestate.h +++ b/LEGO1/lego/legoomni/include/legogamestate.h @@ -30,6 +30,7 @@ struct InternationalCharacter { }; // VTABLE: LEGO1 0x100d74a8 +// VTABLE: BETA10 0x101bc4f0 // SIZE 0x30 class LegoBackgroundColor : public MxVariable { public: @@ -50,9 +51,11 @@ class LegoBackgroundColor : public MxVariable { }; // VTABLE: LEGO1 0x100d74b8 +// VTABLE: BETA10 0x101bc500 // SIZE 0x24 class LegoFullScreenMovie : public MxVariable { public: + LegoFullScreenMovie(); LegoFullScreenMovie(const char* p_key, const char* p_value); void SetValue(const char* p_option) override; // vtable+0x04 @@ -110,19 +113,19 @@ class LegoGameState { e_dunecarbuild, e_jetskibuild, e_racecarbuild, - e_unk40, + e_helicopterSpawn, e_unk41, e_unk42, - e_unk43, - e_unk44, - e_unk45, + e_dunebuggySpawn, + e_racecarSpawn, + e_jetskiSpawn, e_act2main, e_act3script, e_unk48, e_unk49, e_unk50, e_unk51, - e_unk52, + e_towTrackHookedUp, e_jukeboxw, e_jukeboxExterior, e_unk55, diff --git a/LEGO1/lego/legoomni/include/legohideanimpresenter.h b/LEGO1/lego/legoomni/include/legohideanimpresenter.h deleted file mode 100644 index b2bbb7b8..00000000 --- a/LEGO1/lego/legoomni/include/legohideanimpresenter.h +++ /dev/null @@ -1,111 +0,0 @@ -#ifndef LEGOHIDEANIMPRESENTER_H -#define LEGOHIDEANIMPRESENTER_H - -#include "decomp.h" -#include "legoloopinganimpresenter.h" - -class LegoPathBoundary; - -struct LegoHideAnimStructComparator { - MxBool operator()(const char* const& p_a, const char* const& p_b) const { return strcmp(p_a, p_b) < 0; } -}; - -// SIZE 0x08 -struct LegoHideAnimStruct { - LegoPathBoundary* m_boundary; // 0x00 - MxU32 m_index; // 0x04 -}; - -typedef map LegoHideAnimStructMap; - -// VTABLE: LEGO1 0x100d9278 -// SIZE 0xc4 -class LegoHideAnimPresenter : public LegoLoopingAnimPresenter { -public: - LegoHideAnimPresenter(); - ~LegoHideAnimPresenter() override; - - // FUNCTION: LEGO1 0x1006d860 - void VTable0x8c() override {} // vtable+0x8c - - // FUNCTION: LEGO1 0x1006d870 - void VTable0x90() override {} // vtable+0x90 - - // FUNCTION: BETA10 0x1005d4a0 - static const char* HandlerClassName() - { - // STRING: LEGO1 0x100f06cc - return "LegoHideAnimPresenter"; - } - - // FUNCTION: LEGO1 0x1006d880 - // FUNCTION: BETA10 0x1005d470 - const char* ClassName() const override // vtable+0x0c - { - return HandlerClassName(); - } - - // FUNCTION: LEGO1 0x1006d890 - MxBool IsA(const char* p_name) const override // vtable+0x10 - { - return !strcmp(p_name, ClassName()) || LegoAnimPresenter::IsA(p_name); - } - - void ReadyTickle() override; // vtable+0x18 - void StartingTickle() override; // vtable+0x18 - MxResult AddToManager() override; // vtable+0x34 - void Destroy() override; // vtable+0x38 - void EndAction() override; // vtable+0x40 - void PutFrame() override; // vtable+0x6c - - void FUN_1006db40(LegoTime p_time); - -private: - void Init(); - void Destroy(MxBool p_fromDestructor); - void FUN_1006db60(LegoTreeNode* p_node, LegoTime p_time); - void FUN_1006dc10(); - void FUN_1006e3f0(LegoHideAnimStructMap& p_map, LegoTreeNode* p_node); - void FUN_1006e470( - LegoHideAnimStructMap& p_map, - LegoAnimNodeData* p_data, - const char* p_name, - LegoPathBoundary* p_boundary - ); - - LegoPathBoundary** m_boundaryMap; // 0xc0 -}; - -// clang-format off -// SYNTHETIC: LEGO1 0x1006d9d0 -// LegoHideAnimPresenter::`scalar deleting destructor' - -// TEMPLATE: LEGO1 0x1006ddb0 -// _Tree,map >::_Kfn,LegoHideAnimStructComparator,allocator >::~_Tree,map >::_Kfn,LegoHideAnimStructComparator,allocator >::iterator::_Inc - -// TEMPLATE: LEGO1 0x1006dec0 -// _Tree,map >::_Kfn,LegoHideAnimStructComparator,allocator >::erase - -// TEMPLATE: LEGO1 0x1006e310 -// _Tree,map >::_Kfn,LegoHideAnimStructComparator,allocator >::_Erase - -// TEMPLATE: LEGO1 0x1006e350 -// Map::~Map - -// TEMPLATE: LEGO1 0x1006e3a0 -// map >::~map > - -// TEMPLATE: LEGO1 0x1006e6d0 -// _Tree,map >::_Kfn,LegoHideAnimStructComparator,allocator >::iterator::_Dec - -// TEMPLATE: LEGO1 0x1006e720 -// _Tree,map >::_Kfn,LegoHideAnimStructComparator,allocator >::_Insert - -// GLOBAL: LEGO1 0x100f768c -// _Tree,map >::_Kfn,LegoHideAnimStructComparator,allocator >::_Nil -// clang-format on - -#endif // LEGOHIDEANIMPRESENTER_H diff --git a/LEGO1/lego/legoomni/include/legoinputmanager.h b/LEGO1/lego/legoomni/include/legoinputmanager.h index 7ccad404..04ac7294 100644 --- a/LEGO1/lego/legoomni/include/legoinputmanager.h +++ b/LEGO1/lego/legoomni/include/legoinputmanager.h @@ -8,6 +8,7 @@ #include "mxpresenter.h" #include "mxqueue.h" +#include #include #include #include @@ -18,12 +19,15 @@ #include #endif +#include +#include + class LegoCameraController; class LegoControlManager; class LegoWorld; -extern MxS32 g_unk0x100f31b0; -extern const char* g_unk0x100f31b4; +extern MxS32 g_clickedObjectId; +extern const char* g_clickedAtom; // VTABLE: LEGO1 0x100d87b8 // class MxCollection @@ -89,6 +93,13 @@ class LegoInputManager : public MxPresenter { c_upOrDown = c_up | c_down }; + enum TouchScheme { + e_none = -1, + e_mouse = 0, + e_arrowKeys, + e_gamepad, + }; + LegoInputManager(); ~LegoInputManager() override; @@ -108,7 +119,7 @@ class LegoInputManager : public MxPresenter { MxResult Create(HWND p_hwnd); void Destroy() override; - MxResult GetJoystick(); + LEGO1_EXPORT MxResult GetJoystick(); MxResult GetJoystickState(MxU32* p_joystickX, MxU32* p_joystickY, MxU32* p_povPosition); void StartAutoDragTimer(); void StopAutoDragTimer(); @@ -121,9 +132,8 @@ class LegoInputManager : public MxPresenter { void SetUnknown88(MxBool p_unk0x88) { m_unk0x88 = p_unk0x88; } void SetUnknown335(MxBool p_unk0x335) { m_unk0x335 = p_unk0x335; } void SetUnknown336(MxBool p_unk0x336) { m_unk0x336 = p_unk0x336; } - void SetUseJoystick(MxBool p_useJoystick) { m_useJoystick = p_useJoystick; } - void SetJoystickIndex(MxS32 p_joystickIndex) { m_joystickIndex = p_joystickIndex; } + // FUNCTION: BETA10 0x1002e290 void DisableInputProcessing() { m_unk0x88 = TRUE; @@ -144,11 +154,31 @@ class LegoInputManager : public MxPresenter { void GetKeyboardState(); MxResult GetNavigationKeyStates(MxU32& p_keyFlags); MxResult GetNavigationTouchStates(MxU32& p_keyFlags); + LEGO1_EXPORT void AddKeyboard(SDL_KeyboardID p_keyboardID); + LEGO1_EXPORT void RemoveKeyboard(SDL_KeyboardID p_keyboardID); + LEGO1_EXPORT void AddMouse(SDL_MouseID p_mouseID); + LEGO1_EXPORT void RemoveMouse(SDL_MouseID p_mouseID); + LEGO1_EXPORT void AddJoystick(SDL_JoystickID p_joystickID); + LEGO1_EXPORT void RemoveJoystick(SDL_JoystickID p_joystickID); + LEGO1_EXPORT MxBool HandleTouchEvent(SDL_Event* p_event, TouchScheme p_touchScheme); + LEGO1_EXPORT MxBool + HandleRumbleEvent(float p_strength, float p_lowFrequencyRumble, float p_highFrequencyRumble, MxU32 p_milliseconds); + LEGO1_EXPORT void UpdateLastInputMethod(SDL_Event* p_event); + const auto& GetLastInputMethod() { return m_lastInputMethod; } + + // clang-format off + enum class SDL_KeyboardID_v : SDL_KeyboardID {}; + enum class SDL_MouseID_v : SDL_MouseID {}; + enum class SDL_JoystickID_v : SDL_JoystickID {}; + enum class SDL_TouchID_v : SDL_TouchID {}; + // clang-format on // SYNTHETIC: LEGO1 0x1005b8d0 // LegoInputManager::`scalar deleting destructor' private: + void InitializeHaptics(); + MxCriticalSection m_criticalSection; // 0x58 LegoNotifyList* m_keyboardNotifyList; // 0x5c LegoCameraController* m_camera; // 0x60 @@ -165,12 +195,18 @@ class LegoInputManager : public MxPresenter { MxBool m_unk0x88; // 0x88 const bool* m_keyboardState; MxBool m_unk0x195; // 0x195 - SDL_JoystickID* m_joyids; - SDL_Joystick* m_joystick; - MxS32 m_joystickIndex; // 0x19c - MxBool m_useJoystick; // 0x334 - MxBool m_unk0x335; // 0x335 - MxBool m_unk0x336; // 0x336 + MxBool m_unk0x335; // 0x335 + MxBool m_unk0x336; // 0x336 + + TouchScheme m_touchScheme = e_none; + SDL_Point m_touchVirtualThumb = {0, 0}; + SDL_FPoint m_touchVirtualThumbOrigin; + std::map m_touchFlags; + std::map> m_keyboards; + std::map> m_mice; + std::map> m_joysticks; + std::map m_otherHaptics; + std::variant m_lastInputMethod; }; // TEMPLATE: LEGO1 0x10028850 diff --git a/LEGO1/lego/legoomni/include/legolocomotionanimpresenter.h b/LEGO1/lego/legoomni/include/legolocomotionanimpresenter.h deleted file mode 100644 index df2f872e..00000000 --- a/LEGO1/lego/legoomni/include/legolocomotionanimpresenter.h +++ /dev/null @@ -1,71 +0,0 @@ -#ifndef LEGOLOCOMOTIONANIMPRESENTER_H -#define LEGOLOCOMOTIONANIMPRESENTER_H - -#include "legoloopinganimpresenter.h" -#include "legoroimaplist.h" - -class LegoAnimActor; - -// VTABLE: LEGO1 0x100d9170 -// SIZE 0xd8 -class LegoLocomotionAnimPresenter : public LegoLoopingAnimPresenter { -public: - LegoLocomotionAnimPresenter(); - ~LegoLocomotionAnimPresenter() override; - - // FUNCTION: BETA10 0x1005c4e0 - static const char* HandlerClassName() - { - // STRING: LEGO1 0x100f06e4 - return "LegoLocomotionAnimPresenter"; - } - - // FUNCTION: LEGO1 0x1006ce50 - // FUNCTION: BETA10 0x1005c4b0 - const char* ClassName() const override // vtable+0x0c - { - return HandlerClassName(); - } - - // FUNCTION: LEGO1 0x1006ce60 - MxBool IsA(const char* p_name) const override // vtable+0x10 - { - return !strcmp(p_name, ClassName()) || LegoLoopingAnimPresenter::IsA(p_name); - } - - void ReadyTickle() override; // vtable+0x18 - void StartingTickle() override; // vtable+0x1c - void StreamingTickle() override; // vtable+0x20 - MxResult AddToManager() override; // vtable+0x34 - void Destroy() override; // vtable+0x38 - void EndAction() override; // vtable+0x40 - void PutFrame() override; // vtable+0x6c - MxResult CreateAnim(MxStreamChunk* p_chunk) override; // vtable+0x88 - - // SYNTHETIC: LEGO1 0x1006cfe0 - // LegoLocomotionAnimPresenter::`scalar deleting destructor' - - void FUN_1006d680(LegoAnimActor* p_actor, MxFloat p_value); - - void DecrementUnknown0xd4() - { - if (m_unk0xd4) { - --m_unk0xd4; - } - } - - undefined2 GetUnknown0xd4() { return m_unk0xd4; } - -private: - void Init(); - void Destroy(MxBool p_fromDestructor); - - undefined4 m_unk0xc0; // 0xc0 - undefined4* m_unk0xc4; // 0xc4 - LegoROIMapList* m_roiMapList; // 0xc8 - MxS32 m_unk0xcc; // 0xcc - MxS32 m_unk0xd0; // 0xd0 - undefined2 m_unk0xd4; // 0xd4 -}; - -#endif // LEGOLOCOMOTIONANIMPRESENTER_H diff --git a/LEGO1/lego/legoomni/include/legoloopinganimpresenter.h b/LEGO1/lego/legoomni/include/legoloopinganimpresenter.h deleted file mode 100644 index 8952cbba..00000000 --- a/LEGO1/lego/legoomni/include/legoloopinganimpresenter.h +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef LEGOLOOPINGANIMPRESENTER_H -#define LEGOLOOPINGANIMPRESENTER_H - -#include "legoanimpresenter.h" - -// VTABLE: LEGO1 0x100d4900 -// SIZE 0xc0 -class LegoLoopingAnimPresenter : public LegoAnimPresenter { -public: - // FUNCTION: BETA10 0x1005c6f0 - static const char* HandlerClassName() - { - // STRING: LEGO1 0x100f0700 - return "LegoLoopingAnimPresenter"; - } - - // FUNCTION: LEGO1 0x1000c9a0 - // FUNCTION: BETA10 0x1005c6c0 - const char* ClassName() const override // vtable+0x0c - { - return HandlerClassName(); - } - - // FUNCTION: LEGO1 0x1000c9b0 - MxBool IsA(const char* p_name) const override // vtable+0x10 - { - return !strcmp(p_name, ClassName()) || LegoAnimPresenter::IsA(p_name); - } - - void StreamingTickle() override; // vtable+0x20 - void PutFrame() override; // vtable+0x6c - -private: - undefined4 m_unk0xbc; // 0xbc -}; - -// SYNTHETIC: LEGO1 0x1006d000 -// LegoLoopingAnimPresenter::~LegoLoopingAnimPresenter - -// SYNTHETIC: LEGO1 0x1000f440 -// LegoLoopingAnimPresenter::`scalar deleting destructor' - -#endif // LEGOLOOPINGANIMPRESENTER_H diff --git a/LEGO1/lego/legoomni/include/legomain.h b/LEGO1/lego/legoomni/include/legomain.h index fa9a91c5..7d4fd5b2 100644 --- a/LEGO1/lego/legoomni/include/legomain.h +++ b/LEGO1/lego/legoomni/include/legomain.h @@ -134,7 +134,7 @@ class LegoOmni : public MxOmni { LegoROI* FindROI(const char* p_name); void AddWorld(LegoWorld* p_world); void DeleteWorld(LegoWorld* p_world); - void FUN_1005b4f0(MxBool p_disable, MxU16 p_flags); + void Disable(MxBool p_disable, MxU16 p_flags); LEGO1_EXPORT void CreateBackgroundAudio(); LEGO1_EXPORT void RemoveWorld(const MxAtomId& p_atom, MxLong p_objectId); MxResult RegisterWorlds(); @@ -185,8 +185,8 @@ class LegoOmni : public MxOmni { // FUNCTION: BETA10 0x100d55c0 void SetExit(MxBool p_exit) { m_exit = p_exit; } - MxResult StartActionIfUnknown0x13c(MxDSAction& p_dsAction) { return m_unk0x13c ? Start(&p_dsAction) : SUCCESS; } - void SetUnknown13c(MxBool p_unk0x13c) { m_unk0x13c = p_unk0x13c; } + MxResult StartActionIfInitialized(MxDSAction& p_dsAction) { return m_initialized ? Start(&p_dsAction) : SUCCESS; } + void SetInitialized(MxBool p_unk0x13c) { m_initialized = p_unk0x13c; } void CloseMainWindow() { @@ -200,6 +200,9 @@ class LegoOmni : public MxOmni { SDL_PushEvent(&event); } + void SetVersion10(MxBool p_version10) { m_version10 = p_version10; } + MxBool IsVersion10() { return m_version10; } + // SYNTHETIC: LEGO1 0x10058b30 // LegoOmni::`scalar deleting destructor' @@ -221,9 +224,10 @@ class LegoOmni : public MxOmni { MxDSAction m_action; // 0xa0 MxBackgroundAudioManager* m_bkgAudioManager; // 0x134 MxTransitionManager* m_transitionManager; // 0x138 + MxBool m_version10; public: - MxBool m_unk0x13c; // 0x13c + MxBool m_initialized; // 0x13c }; #endif // LEGOMAIN_H diff --git a/LEGO1/lego/legoomni/include/legomodelpresenter.h b/LEGO1/lego/legoomni/include/legomodelpresenter.h index 075ba3be..950bdb7e 100644 --- a/LEGO1/lego/legoomni/include/legomodelpresenter.h +++ b/LEGO1/lego/legoomni/include/legomodelpresenter.h @@ -47,7 +47,7 @@ class LegoModelPresenter : public MxVideoPresenter { void ReadyTickle() override; // vtable+0x18 void ParseExtra() override; // vtable+0x30 - MxResult FUN_1007ff70(MxDSChunk& p_chunk, LegoEntity* p_entity, MxBool p_roiVisible, LegoWorld* p_world); + MxResult CreateROI(MxDSChunk& p_chunk, LegoEntity* p_entity, MxBool p_roiVisible, LegoWorld* p_world); void Reset() { diff --git a/LEGO1/lego/legoomni/include/legopartpresenter.h b/LEGO1/lego/legoomni/include/legopartpresenter.h index 7ff7692d..3c3fc2f1 100644 --- a/LEGO1/lego/legoomni/include/legopartpresenter.h +++ b/LEGO1/lego/legoomni/include/legopartpresenter.h @@ -4,6 +4,7 @@ #include "lego1_export.h" #include "legonamedpartlist.h" #include "mxmediapresenter.h" +#include "viewmanager/viewlodlist.h" // VTABLE: LEGO1 0x100d4df0 // SIZE 0x54 @@ -50,10 +51,21 @@ class LegoPartPresenter : public MxMediaPresenter { MxResult Read(MxDSChunk& p_chunk); void Store(); + static void Release() + { + for (auto* lodList : g_lodLists) { + lodList->Release(); + } + + g_lodLists.clear(); + } + private: void Destroy(MxBool p_fromDestructor); LegoNamedPartList* m_parts; // 0x50 + + static vector g_lodLists; }; #endif // LEGOPARTPRESENTER_H diff --git a/LEGO1/lego/legoomni/include/legopathactor.h b/LEGO1/lego/legoomni/include/legopathactor.h index 6566c6fb..8df0e9db 100644 --- a/LEGO1/lego/legoomni/include/legopathactor.h +++ b/LEGO1/lego/legoomni/include/legopathactor.h @@ -13,7 +13,7 @@ struct LegoPathEdgeContainer; struct LegoOrientedEdge; class LegoWEEdge; -extern MxLong g_unk0x100f3308; +extern MxLong g_timeLastHitSoundPlayed; extern const char* g_strHIT_WALL_SOUND; // VTABLE: LEGO1 0x100d6e28 diff --git a/LEGO1/lego/legoomni/include/legopathboundary.h b/LEGO1/lego/legoomni/include/legopathboundary.h index 05d0487c..2bc304f0 100644 --- a/LEGO1/lego/legoomni/include/legopathboundary.h +++ b/LEGO1/lego/legoomni/include/legopathboundary.h @@ -75,7 +75,7 @@ class LegoPathBoundary : public LegoWEGEdge { // _Tree >::_Kfn,LegoPathActorSetCompare,allocator >::erase // TEMPLATE: LEGO1 0x1002c440 -// TEMPLATE: BETA10 0x100b6480 +// TEMPLATE: BETA10 0x10020480 // _Tree >::_Kfn,LegoPathActorSetCompare,allocator >::find // TEMPLATE: LEGO1 0x1002c4c0 @@ -190,6 +190,12 @@ class LegoPathBoundary : public LegoWEGEdge { // TEMPLATE: BETA10 0x10082b40 // _Tree >::_Kfn,LegoAnimPresenterSetCompare,allocator >::const_iterator::operator* +// TEMPLATE: BETA10 0x100b6440 +// set >::find + +// TEMPLATE: BETA10 0x100b6480 +// _Tree >::_Kfn,LegoAnimPresenterSetCompare,allocator >::find + // TEMPLATE: BETA10 0x10021dc0 // ??0?$Set@PAVLegoPathActor@@ULegoPathActorSetCompare@@@@QAE@ABV0@@Z diff --git a/LEGO1/lego/legoomni/include/legophonemepresenter.h b/LEGO1/lego/legoomni/include/legophonemepresenter.h index e470f6b7..4a6a3c05 100644 --- a/LEGO1/lego/legoomni/include/legophonemepresenter.h +++ b/LEGO1/lego/legoomni/include/legophonemepresenter.h @@ -42,9 +42,9 @@ class LegoPhonemePresenter : public MxFlcPresenter { MxS32 m_rectCount; // 0x68 LegoTextureInfo* m_textureInfo; // 0x6c - MxBool m_unk0x70; // 0x70 + MxBool m_reusedPhoneme; // 0x70 MxString m_roiName; // 0x74 - MxBool m_unk0x84; // 0x84 + MxBool m_isPartOfAnimMM; // 0x84 }; // TEMPLATE: LEGO1 0x1004eb20 diff --git a/LEGO1/lego/legoomni/include/legoplantmanager.h b/LEGO1/lego/legoomni/include/legoplantmanager.h index 1e17d6f4..3cdb5105 100644 --- a/LEGO1/lego/legoomni/include/legoplantmanager.h +++ b/LEGO1/lego/legoomni/include/legoplantmanager.h @@ -49,12 +49,12 @@ class LEGO1_EXPORT LegoPlantManager : public MxCore { MxBool SwitchMove(LegoEntity* p_entity); MxBool SwitchMood(LegoEntity* p_entity); MxU32 GetAnimationId(LegoEntity* p_entity); - MxU32 GetSoundId(LegoEntity* p_entity, MxBool p_state); + MxU32 GetSoundId(LegoEntity* p_entity, MxBool p_basedOnMood); LegoPlantInfo* GetInfoArray(MxS32& p_length); LegoEntity* CreatePlant(MxS32 p_index, LegoWorld* p_world, LegoOmni::World p_worldId); MxBool DecrementCounter(LegoEntity* p_entity); void ScheduleAnimation(LegoEntity* p_entity, MxLong p_length); - MxResult FUN_10026410(); + MxResult DetermineBoundaries(); void ClearCounters(); void SetInitialCounters(); @@ -77,11 +77,11 @@ class LEGO1_EXPORT LegoPlantManager : public MxCore { static MxS32 g_maxMove[4]; static MxU32 g_maxSound; - LegoOmni::World m_worldId; // 0x08 - undefined m_unk0x0c; // 0x0c - AnimEntry* m_entries[5]; // 0x10 - MxS8 m_numEntries; // 0x24 - LegoWorld* m_world; // 0x28 + LegoOmni::World m_worldId; // 0x08 + MxBool m_boundariesDetermined; // 0x0c + AnimEntry* m_entries[5]; // 0x10 + MxS8 m_numEntries; // 0x24 + LegoWorld* m_world; // 0x28 friend class DebugViewer; }; diff --git a/LEGO1/lego/legoomni/include/legorace.h b/LEGO1/lego/legoomni/include/legorace.h index 55d43785..e1b93211 100644 --- a/LEGO1/lego/legoomni/include/legorace.h +++ b/LEGO1/lego/legoomni/include/legorace.h @@ -11,7 +11,7 @@ #include "mxtypes.h" class Act1State; -class LegoEventNotificationParam; +class LegoControlManagerNotificationParam; class LegoPathActor; class MxEndActionNotificationParam; class MxNotificationParam; @@ -117,7 +117,7 @@ class LegoRace : public LegoWorld { MxResult Create(MxDSAction& p_dsAction) override; // vtable+0x18 - virtual MxLong HandleClick(LegoEventNotificationParam&) = 0; // vtable+0x6c + virtual MxLong HandleControl(LegoControlManagerNotificationParam&) = 0; // vtable+0x6c // FUNCTION: LEGO1 0x10015b70 virtual MxLong HandlePathStruct(LegoPathStructNotificationParam&) { return 0; } // vtable+0x70 diff --git a/LEGO1/lego/legoomni/include/legoracers.h b/LEGO1/lego/legoomni/include/legoracers.h index 76d1071d..3c8ffe07 100644 --- a/LEGO1/lego/legoomni/include/legoracers.h +++ b/LEGO1/lego/legoomni/include/legoracers.h @@ -144,10 +144,10 @@ class LegoRaceCar : public LegoCarRaceActor, public LegoRaceMap { MxResult VTable0x9c() override; // vtable+0x9c virtual void SetMaxLinearVelocity(float p_maxLinearVelocity); - virtual void FUN_10012ff0(float p_param); + virtual void KickCamera(float p_param); virtual MxU32 HandleSkeletonKicks(float p_param1); - static void FUN_10012de0(); + static void InitYouCantStopSound(); static void InitSoundIndices(); // SYNTHETIC: LEGO1 0x10014240 @@ -155,7 +155,7 @@ class LegoRaceCar : public LegoCarRaceActor, public LegoRaceMap { private: undefined m_userState; // 0x54 - float m_unk0x58; // 0x58 + float m_kickStart; // 0x58 Mx3DPointFloat m_unk0x5c; // 0x5c // Names verified by BETA10 0x100cb4a9 diff --git a/LEGO1/lego/legoomni/include/legoracespecial.h b/LEGO1/lego/legoomni/include/legoracespecial.h index fab200aa..fa9dd51d 100644 --- a/LEGO1/lego/legoomni/include/legoracespecial.h +++ b/LEGO1/lego/legoomni/include/legoracespecial.h @@ -44,8 +44,11 @@ class LegoCarRaceActor : public virtual LegoRaceActor { Vector3& p_v3 ) override; // vtable+0x6c void Animate(float p_time) override; // vtable+0x70 - void SwitchBoundary(LegoPathBoundary*& p_boundary, LegoOrientedEdge*& p_edge, float& p_unk0xe4) - override; // vtable+0x98 + void SwitchBoundary( + LegoPathBoundary*& p_boundary, + LegoOrientedEdge*& p_edge, + float& p_unk0xe4 + ) override; // vtable+0x98 MxResult VTable0x9c() override; // vtable+0x9c // LegoCarRaceActor vtable @@ -83,7 +86,7 @@ class LegoCarRaceActor : public virtual LegoRaceActor { protected: MxFloat m_unk0x08; // 0x08 - MxU8 m_unk0x0c; // 0x0c + MxU8 m_animState; // 0x0c // Could be a multiplier for the maximum speed when going straight MxFloat m_unk0x10; // 0x10 diff --git a/LEGO1/lego/legoomni/include/legosoundmanager.h b/LEGO1/lego/legoomni/include/legosoundmanager.h index 9c03b06d..f503bf6e 100644 --- a/LEGO1/lego/legoomni/include/legosoundmanager.h +++ b/LEGO1/lego/legoomni/include/legosoundmanager.h @@ -17,15 +17,15 @@ class LegoSoundManager : public MxSoundManager { void Destroy() override; // vtable+0x18 MxResult Create(MxU32 p_frequencyMS, MxBool p_createThread) override; // vtable+0x30 - // SYNTHETIC: LEGO1 0x10029920 - // SYNTHETIC: BETA10 0x100d0660 - // LegoSoundManager::`scalar deleting destructor' - void UpdateListener(const float* p_position, const float* p_direction, const float* p_up, const float* p_velocity); // FUNCTION: BETA10 0x1000f350 LegoCacheSoundManager* GetCacheSoundManager() { return m_cacheSoundManager; } + // SYNTHETIC: LEGO1 0x10029920 + // SYNTHETIC: BETA10 0x100d0660 + // LegoSoundManager::`scalar deleting destructor' + private: void Init(); void Destroy(MxBool p_fromDestructor); diff --git a/LEGO1/lego/legoomni/include/legotraninfolist.h b/LEGO1/lego/legoomni/include/legotraninfolist.h index 06cd2558..0bfe4bd8 100644 --- a/LEGO1/lego/legoomni/include/legotraninfolist.h +++ b/LEGO1/lego/legoomni/include/legotraninfolist.h @@ -28,9 +28,11 @@ class LegoTranInfoList : public MxPtrList { // class MxPtrListCursor // VTABLE: LEGO1 0x100d8d20 +// VTABLE: BETA10 0x101bad70 // SIZE 0x10 class LegoTranInfoListCursor : public MxPtrListCursor { public: + // FUNCTION: BETA10 0x100496d0 LegoTranInfoListCursor(LegoTranInfoList* p_list) : MxPtrListCursor(p_list) {} }; @@ -62,9 +64,14 @@ class LegoTranInfoListCursor : public MxPtrListCursor { // MxPtrList::`scalar deleting destructor' // SYNTHETIC: LEGO1 0x100612f0 +// SYNTHETIC: BETA10 0x100498c0 // LegoTranInfoListCursor::`scalar deleting destructor' +// SYNTHETIC: BETA10 0x10049770 +// MxPtrListCursor::MxPtrListCursor + // FUNCTION: LEGO1 0x10061360 +// FUNCTION: BETA10 0x10049910 // MxPtrListCursor::~MxPtrListCursor // SYNTHETIC: LEGO1 0x100613b0 @@ -77,6 +84,7 @@ class LegoTranInfoListCursor : public MxPtrListCursor { // MxListCursor::~MxListCursor // FUNCTION: LEGO1 0x100614e0 +// FUNCTION: BETA10 0x10049ab0 // LegoTranInfoListCursor::~LegoTranInfoListCursor #endif // LEGOTRANINFOLIST_H diff --git a/LEGO1/lego/legoomni/include/legoutils.h b/LEGO1/lego/legoomni/include/legoutils.h index 3862465f..849662df 100644 --- a/LEGO1/lego/legoomni/include/legoutils.h +++ b/LEGO1/lego/legoomni/include/legoutils.h @@ -32,6 +32,14 @@ enum Cursor { e_cursorNone }; +enum GameEvent { + e_hitActor, + e_skeletonKick, + e_raceFinished, + e_badEnding, + e_goodEnding +}; + class BoundingSphere; class MxAtomId; class LegoEntity; @@ -49,28 +57,29 @@ LegoROI* PickROI(MxLong p_x, MxLong p_y); LegoROI* PickRootROI(MxLong p_x, MxLong p_y); void RotateY(LegoROI* p_roi, MxFloat p_angle); MxBool SpheresIntersect(const BoundingSphere& p_sphere1, const BoundingSphere& p_sphere2); -MxBool FUN_1003ded0(MxFloat p_param1[2], MxFloat p_param2[3], MxFloat p_param3[3]); +MxBool CalculateRayOriginDirection(MxFloat p_coordinates[2], MxFloat p_direction[3], MxFloat p_origin[3]); MxBool TransformWorldToScreen(const MxFloat p_world[3], MxFloat p_screen[4]); MxS16 CountTotalTreeNodes(LegoTreeNode* p_node); LegoTreeNode* GetTreeNode(LegoTreeNode* p_node, MxU32 p_index); -void FUN_1003e050(LegoAnimPresenter* p_presenter); +void CalculateViewFromAnimation(LegoAnimPresenter* p_presenter); Extra::ActionType MatchActionString(const char*); void InvokeAction(Extra::ActionType p_actionId, const MxAtomId& p_pAtom, MxS32 p_streamId, LegoEntity* p_sender); void SetCameraControllerFromIsle(); void ConvertHSVToRGB(float p_h, float p_s, float p_v, float* p_rOut, float* p_bOut, float* p_gOut); void PlayCamAnim(LegoPathActor* p_actor, MxBool p_unused, MxU32 p_location, MxBool p_bool); -void FUN_1003eda0(); +void ResetViewVelocity(); MxBool RemoveFromCurrentWorld(const MxAtomId& p_atomId, MxS32 p_id); void EnableAnimations(MxBool p_enable); void SetAppCursor(Cursor p_cursor); -MxBool FUN_1003ef60(); +MxBool CanExit(); MxBool RemoveFromWorld(MxAtomId& p_entityAtom, MxS32 p_entityId, MxAtomId& p_worldAtom, MxS32 p_worldEntityId); MxS32 UpdateLightPosition(MxS32 p_increase); void SetLightPosition(MxS32 p_index); LegoNamedTexture* ReadNamedTexture(LegoStorage* p_storage); void WriteDefaultTexture(LegoStorage* p_storage, const char* p_name); void WriteNamedTexture(LegoStorage* p_storage, LegoNamedTexture* p_namedTexture); -void FUN_1003f930(LegoNamedTexture* p_namedTexture); +void LoadFromNamedTexture(LegoNamedTexture* p_namedTexture); +void EmitGameEvent(GameEvent p_event); // FUNCTION: BETA10 0x100260a0 inline void StartIsleAction(IsleScript::Script p_objectId) diff --git a/LEGO1/lego/legoomni/include/legovariables.h b/LEGO1/lego/legoomni/include/legovariables.h index 9447a5f9..873ef34c 100644 --- a/LEGO1/lego/legoomni/include/legovariables.h +++ b/LEGO1/lego/legoomni/include/legovariables.h @@ -17,41 +17,60 @@ extern const char* g_varVISIBILITY; extern const char* g_varCAMERALOCATION; extern const char* g_varCURSOR; extern const char* g_varWHOAMI; +extern const char* g_varDEBUG; // VTABLE: LEGO1 0x100d86c8 +// VTABLE: BETA10 0x101bc980 // SIZE 0x24 class VisibilityVariable : public MxVariable { public: + // FUNCTION: BETA10 0x10093470 VisibilityVariable() { m_key = g_varVISIBILITY; } void SetValue(const char* p_value) override; // vtable+0x04 }; // VTABLE: LEGO1 0x100d86b8 +// VTABLE: BETA10 0x101bc990 // SIZE 0x24 class CameraLocationVariable : public MxVariable { public: + // FUNCTION: BETA10 0x10093510 CameraLocationVariable() { m_key = g_varCAMERALOCATION; } void SetValue(const char* p_value) override; // vtable+0x04 }; // VTABLE: LEGO1 0x100d86a8 +// VTABLE: BETA10 0x101bc9a0 // SIZE 0x24 class CursorVariable : public MxVariable { public: + // FUNCTION: BETA10 0x100935b0 CursorVariable() { m_key = g_varCURSOR; } void SetValue(const char* p_value) override; // vtable+0x04 }; // VTABLE: LEGO1 0x100d8698 +// VTABLE: BETA10 0x101bc9b0 // SIZE 0x24 class WhoAmIVariable : public MxVariable { public: + // FUNCTION: BETA10 0x10093650 WhoAmIVariable() { m_key = g_varWHOAMI; } void SetValue(const char* p_value) override; // vtable+0x04 }; +// VTABLE: BETA10 0x101bc9c0 +// SIZE 0x24 +class DebugVariable : public MxVariable { +public: + // FUNCTION: BETA10 0x100936f0 + DebugVariable() { m_key = g_varDEBUG; } + + void SetValue(const char* p_value) override; // vtable+0x04 +}; + #endif // LEGOVARIABLES_H diff --git a/LEGO1/lego/legoomni/include/legovideomanager.h b/LEGO1/lego/legoomni/include/legovideomanager.h index 6c12d863..ff5f9ae3 100644 --- a/LEGO1/lego/legoomni/include/legovideomanager.h +++ b/LEGO1/lego/legoomni/include/legovideomanager.h @@ -1,6 +1,7 @@ #ifndef LEGOVIDEOMANAGER_H #define LEGOVIDEOMANAGER_H +#include "cursor.h" #include "decomp.h" #include "lego1_export.h" #include "legophonemelist.h" @@ -37,6 +38,7 @@ class LegoVideoManager : public MxVideoManager { void EnableFullScreenMovie(MxBool p_enable); LEGO1_EXPORT void EnableFullScreenMovie(MxBool p_enable, MxBool p_scale); LEGO1_EXPORT void MoveCursor(MxS32 p_cursorX, MxS32 p_cursorY); + LEGO1_EXPORT void SetCursorBitmap(const CursorBitmap* p_cursorBitmap); void ToggleFPS(MxBool p_visible); MxResult Tickle() override; // vtable+0x08 @@ -68,7 +70,9 @@ class LegoVideoManager : public MxVideoManager { MxBool GetRender3D() { return m_render3d; } double GetElapsedSeconds() { return m_elapsedSeconds; } + // FUNCTION: BETA10 0x1002e290 void SetRender3D(MxBool p_render3d) { m_render3d = p_render3d; } + void SetUnk0x554(MxBool p_unk0x554) { m_unk0x554 = p_unk0x554; } private: diff --git a/LEGO1/lego/legoomni/include/misc.h b/LEGO1/lego/legoomni/include/misc.h index b9f0fb5f..8e294343 100644 --- a/LEGO1/lego/legoomni/include/misc.h +++ b/LEGO1/lego/legoomni/include/misc.h @@ -49,11 +49,11 @@ LegoPlantManager* PlantManager(); LegoBuildingManager* BuildingManager(); LegoTextureContainer* TextureContainer(); ViewLODListManager* GetViewLODListManager(); -void FUN_10015820(MxBool p_disable, MxU16 p_flags); +void Disable(MxBool p_disable, MxU16 p_flags); LegoROI* FindROI(const char* p_name); void SetROIVisible(const char* p_name, MxBool p_visible); void SetUserActor(LegoPathActor* p_userActor); -MxResult StartActionIfUnknown0x13c(MxDSAction& p_dsAction); +MxResult StartActionIfInitialized(MxDSAction& p_dsAction); void DeleteAction(); LegoWorld* FindWorld(const MxAtomId& p_atom, MxS32 p_entityid); MxDSAction& GetCurrentAction(); diff --git a/LEGO1/lego/legoomni/include/mxcontrolpresenter.h b/LEGO1/lego/legoomni/include/mxcontrolpresenter.h index 8ecfeacf..d3d2a96a 100644 --- a/LEGO1/lego/legoomni/include/mxcontrolpresenter.h +++ b/LEGO1/lego/legoomni/include/mxcontrolpresenter.h @@ -44,21 +44,28 @@ class MxControlPresenter : public MxCompositePresenter { void EndAction() override; // vtable+0x40 MxBool HasTickleStatePassed(TickleState p_tickleState) override; // vtable+0x48 void Enable(MxBool p_enable) override; // vtable+0x54 - virtual void VTable0x6c(MxS16 p_unk0x4e); // vtable+0x6c + virtual void UpdateEnabledChild(MxS16 p_enabledChild); // vtable+0x6c - MxBool FUN_10044480(LegoControlManagerNotificationParam* p_param, MxPresenter* p_presenter); - MxBool FUN_10044270(MxS32 p_x, MxS32 p_y, MxPresenter* p_presenter); + MxBool Notify(LegoControlManagerNotificationParam* p_param, MxPresenter* p_presenter); + MxBool CheckButtonDown(MxS32 p_x, MxS32 p_y, MxPresenter* p_presenter); - MxS16 GetUnknown0x4e() { return m_unk0x4e; } + MxS16 GetEnabledChild() { return m_enabledChild; } private: - MxS16 m_unk0x4c; // 0x4c - MxS16 m_unk0x4e; // 0x4e - MxBool m_unk0x50; // 0x50 - MxS16 m_unk0x52; // 0x52 - MxS16 m_unk0x54; // 0x54 - MxS16 m_unk0x56; // 0x56 - MxS16* m_states; // 0x58 + enum { + e_none, + e_toggle, + e_grid, + e_map, + }; + + MxS16 m_style; // 0x4c + MxS16 m_enabledChild; // 0x4e + MxBool m_unk0x50; // 0x50 + MxS16 m_columnsOrRows; // 0x52 + MxS16 m_rowsOrColumns; // 0x54 + MxS16 m_stateOrCellIndex; // 0x56 + MxS16* m_states; // 0x58 }; // SYNTHETIC: LEGO1 0x100440f0 diff --git a/LEGO1/lego/legoomni/include/mxtransitionmanager.h b/LEGO1/lego/legoomni/include/mxtransitionmanager.h index 50b80055..dd9dc9ed 100644 --- a/LEGO1/lego/legoomni/include/mxtransitionmanager.h +++ b/LEGO1/lego/legoomni/include/mxtransitionmanager.h @@ -55,6 +55,8 @@ class MxTransitionManager : public MxCore { TransitionType GetTransitionType() { return m_mode; } + LEGO1_EXPORT static void configureMxTransitionManager(TransitionType p_transitionManagerConfig); + // SYNTHETIC: LEGO1 0x1004b9e0 // MxTransitionManager::`scalar deleting destructor' diff --git a/LEGO1/lego/legoomni/include/towtrack.h b/LEGO1/lego/legoomni/include/towtrack.h index 812751bf..e9e41418 100644 --- a/LEGO1/lego/legoomni/include/towtrack.h +++ b/LEGO1/lego/legoomni/include/towtrack.h @@ -12,6 +12,13 @@ class MxEndActionNotificationParam; // SIZE 0x28 class TowTrackMissionState : public LegoState { public: + enum { + e_none = 0, + e_started = 1, + e_hookedUp = 2, + e_hookingUp = 3, + }; + TowTrackMissionState(); // FUNCTION: LEGO1 0x1004dde0 @@ -126,19 +133,19 @@ class TowTrackMissionState : public LegoState { // SYNTHETIC: LEGO1 0x1004e060 // TowTrackMissionState::`scalar deleting destructor' - undefined4 m_unk0x08; // 0x08 - MxLong m_startTime; // 0x0c - MxBool m_unk0x10; // 0x10 - MxS16 m_peScore; // 0x12 - MxS16 m_maScore; // 0x14 - MxS16 m_paScore; // 0x16 - MxS16 m_niScore; // 0x18 - MxS16 m_laScore; // 0x1a - MxS16 m_peHighScore; // 0x1c - MxS16 m_maHighScore; // 0x1e - MxS16 m_paHighScore; // 0x20 - MxS16 m_niHighScore; // 0x22 - MxS16 m_laHighScore; // 0x24 + MxU32 m_state; // 0x08 + MxLong m_startTime; // 0x0c + MxBool m_takingTooLong; // 0x10 + MxS16 m_peScore; // 0x12 + MxS16 m_maScore; // 0x14 + MxS16 m_paScore; // 0x16 + MxS16 m_niScore; // 0x18 + MxS16 m_laScore; // 0x1a + MxS16 m_peHighScore; // 0x1c + MxS16 m_maHighScore; // 0x1e + MxS16 m_paHighScore; // 0x20 + MxS16 m_niHighScore; // 0x22 + MxS16 m_laHighScore; // 0x24 }; // VTABLE: LEGO1 0x100d7ee0 @@ -174,10 +181,10 @@ class TowTrack : public IslePathActor { virtual MxLong HandleEndAction(MxEndActionNotificationParam& p_param); // vtable+0xf0 void CreateState(); - void FUN_1004dab0(); + void Init(); void ActivateSceneActions(); void StopActions(); - void FUN_1004dbe0(); + void Reset(); // SYNTHETIC: LEGO1 0x1004c950 // TowTrack::`scalar deleting destructor' @@ -192,8 +199,8 @@ class TowTrack : public IslePathActor { TowTrackMissionState* m_state; // 0x164 MxS16 m_unk0x168; // 0x168 MxS16 m_actorId; // 0x16a - MxS16 m_unk0x16c; // 0x16c - MxS16 m_unk0x16e; // 0x16e + MxS16 m_treeBlockageTriggered; // 0x16c + MxS16 m_speedComplaintTriggered; // 0x16e IsleScript::Script m_lastAction; // 0x170 IsleScript::Script m_lastAnimation; // 0x174 MxFloat m_fuel; // 0x178 diff --git a/LEGO1/lego/legoomni/src/actors/act2actor.cpp b/LEGO1/lego/legoomni/src/actors/act2actor.cpp index 726f3838..799b196a 100644 --- a/LEGO1/lego/legoomni/src/actors/act2actor.cpp +++ b/LEGO1/lego/legoomni/src/actors/act2actor.cpp @@ -631,7 +631,7 @@ MxU32 Act2Actor::FUN_10019700(MxFloat p_param) MxFloat time = p_param - (m_unk0x2c - m_shootAnim->GetDuration()); for (MxS32 i = 0; i < root->GetNumChildren(); i++) { - LegoROI::FUN_100a8e80(root->GetChild(i), matrix, time, m_shootAnim->GetROIMap()); + LegoROI::ApplyAnimationTransformation(root->GetChild(i), matrix, time, m_shootAnim->GetROIMap()); } return FALSE; diff --git a/LEGO1/lego/legoomni/src/actors/act3actors.cpp b/LEGO1/lego/legoomni/src/actors/act3actors.cpp index e7706b03..2926466f 100644 --- a/LEGO1/lego/legoomni/src/actors/act3actors.cpp +++ b/LEGO1/lego/legoomni/src/actors/act3actors.cpp @@ -4,9 +4,9 @@ #include "act3ammo.h" #include "anim/legoanim.h" #include "define.h" +#include "legoanimpresenter.h" #include "legobuildingmanager.h" #include "legocachesoundmanager.h" -#include "legolocomotionanimpresenter.h" #include "legopathedgecontainer.h" #include "legoplantmanager.h" #include "legoplants.h" @@ -580,7 +580,7 @@ void Act3Brickster::Animate(float p_time) } if (m_unk0x54 < p_time) { - ((Act3*) m_world)->FUN_10072ad0(5); + ((Act3*) m_world)->TriggerHitSound(5); m_unk0x54 = p_time + 15000.0f; } @@ -596,7 +596,7 @@ void Act3Brickster::Animate(float p_time) assert(SoundManager()->GetCacheSoundManager()); if (m_unk0x58 >= 8) { - ((Act3*) m_world)->FUN_10072ad0(6); + ((Act3*) m_world)->TriggerHitSound(6); } else { SoundManager()->GetCacheSoundManager()->Play("eatpz", NULL, FALSE); @@ -639,7 +639,7 @@ void Act3Brickster::Animate(float p_time) float time = p_time - (m_unk0x50 - m_shootAnim->GetDuration()); for (MxS32 i = 0; i < root->GetNumChildren(); i++) { - LegoROI::FUN_100a8e80(root->GetChild(i), local70, time, m_shootAnim->GetROIMap()); + LegoROI::ApplyAnimationTransformation(root->GetChild(i), local70, time, m_shootAnim->GetROIMap()); } } @@ -686,7 +686,7 @@ void Act3Brickster::Animate(float p_time) float time = p_time - (m_unk0x50 - m_shootAnim->GetDuration()); for (MxS32 i = 0; i < root->GetNumChildren(); i++) { - LegoROI::FUN_100a8e80(root->GetChild(i), locale4, time, m_shootAnim->GetROIMap()); + LegoROI::ApplyAnimationTransformation(root->GetChild(i), locale4, time, m_shootAnim->GetROIMap()); } } @@ -1187,7 +1187,7 @@ void Act3Shark::Animate(float p_time) vec = m_unk0x3c; LegoTreeNode* node = m_unk0x34->GetAnimTreePtr()->GetRoot(); - LegoROI::FUN_100a8e80(node, mat, duration, m_unk0x34->GetROIMap()); + LegoROI::ApplyAnimationTransformation(node, mat, duration, m_unk0x34->GetROIMap()); } else { roiMap[1] = m_unk0x38; diff --git a/LEGO1/lego/legoomni/src/actors/act3ammo.cpp b/LEGO1/lego/legoomni/src/actors/act3ammo.cpp index 04e0e93c..4ab1a27b 100644 --- a/LEGO1/lego/legoomni/src/actors/act3ammo.cpp +++ b/LEGO1/lego/legoomni/src/actors/act3ammo.cpp @@ -200,7 +200,7 @@ MxResult Act3Ammo::FUN_10053d30(LegoPathController* p_p, MxFloat p_unk0x19c) // FUNCTION: LEGO1 0x10053db0 // FUNCTION: BETA10 0x1001e0f0 -MxResult Act3Ammo::FUN_10053db0(float p_param1, const Matrix4& p_param2) +MxResult Act3Ammo::FUN_10053db0(float p_param1, Matrix4& p_param2) { float local34 = p_param1 * p_param1; @@ -378,12 +378,14 @@ void Act3Ammo::Animate(float p_time) if (IsBit4()) { if (IsPizza()) { m_world->RemovePizza(*this); - m_world->FUN_10072ad0(2); + m_world->TriggerHitSound(2); } else { m_world->RemoveDonut(*this); - m_world->FUN_10072ad0(4); + m_world->TriggerHitSound(4); } + + return; } else { if (IsPizza()) { @@ -394,89 +396,99 @@ void Act3Ammo::Animate(float p_time) assert(SoundManager()->GetCacheSoundManager()); SoundManager()->GetCacheSoundManager()->Play("stickdn", NULL, FALSE); } + } - LegoPathActorSet& plpas = m_boundary->GetActors(); - LegoPathActorSet lpas(plpas); + LegoPathActorSet& plpas = m_boundary->GetActors(); + LegoPathActorSet lpas(plpas); - for (LegoPathActorSet::iterator itpa = lpas.begin(); itpa != lpas.end(); itpa++) { - if (plpas.find(*itpa) != plpas.end() && this != *itpa) { - LegoROI* r = (*itpa)->GetROI(); - assert(r); + for (LegoPathActorSet::iterator itpa = lpas.begin(); itpa != lpas.end(); itpa++) { + if (plpas.find(*itpa) == plpas.end()) { + continue; + } - if (!strncmp(r->GetName(), "pammo", 5)) { - Mx3DPointFloat local1c8; - Mx3DPointFloat local1b4; + if (this == *itpa) { + continue; + } - local1c8 = r->GetLocal2World()[3]; - local1b4 = m_roi->GetLocal2World()[3]; + LegoROI* r = (*itpa)->GetROI(); + assert(r); - local1b4 -= local1c8; + if (!strncmp(r->GetName(), "pammo", 5)) { + Mx3DPointFloat local1c8; + Mx3DPointFloat local1b4; - float radius = r->GetWorldBoundingSphere().Radius(); - if (local1b4.LenSquared() <= radius * radius) { - MxS32 index = -1; - if (sscanf(r->GetName(), "pammo%d", &index) != 1) { - assert(0); - } + local1c8 = r->GetLocal2World()[3]; + local1b4 = m_roi->GetLocal2World()[3]; - assert(m_world); + local1b4 -= local1c8; - if (m_world->m_pizzas[index].IsValid() && !m_world->m_pizzas[index].IsSharkFood()) { - m_world->EatPizza(index); - m_world->m_brickster->FUN_100417c0(); - } - - if (IsDonut()) { - assert(SoundManager()->GetCacheSoundManager()); - SoundManager()->GetCacheSoundManager()->Play("dnhitpz", NULL, FALSE); - m_world->RemoveDonut(*this); - local14 = TRUE; - break; - } - } + float radius = r->GetWorldBoundingSphere().Radius(); + if (local1b4.LenSquared() <= radius * radius) { + MxS32 index = -1; + if (sscanf(r->GetName(), "pammo%d", &index) != 1) { + assert(0); } - else if (!strncmp(r->GetName(), "dammo", 5)) { - Mx3DPointFloat local1f8; - Mx3DPointFloat local1e4; - local1f8 = r->GetLocal2World()[3]; - local1e4 = m_roi->GetLocal2World()[3]; + assert(m_world); - local1e4 -= local1f8; +#ifdef BETA10 + m_world->EatPizza(index); +#else + if (m_world->m_pizzas[index].IsValid() && !m_world->m_pizzas[index].IsSharkFood()) { + m_world->EatPizza(index); + m_world->m_brickster->FUN_100417c0(); + } +#endif - float radius = r->GetWorldBoundingSphere().Radius(); - if (local1e4.LenSquared() <= radius * radius) { - MxS32 index = -1; - if (sscanf(r->GetName(), "dammo%d", &index) != 1) { - assert(0); - } - - assert(m_world); - - m_world->EatDonut(index); - - if (IsPizza()) { - assert(SoundManager()->GetCacheSoundManager()); - SoundManager()->GetCacheSoundManager()->Play("pzhitdn", NULL, FALSE); - m_world->RemovePizza(*this); - local14 = TRUE; - break; - } - } + if (IsDonut()) { + assert(SoundManager()->GetCacheSoundManager()); + SoundManager()->GetCacheSoundManager()->Play("dnhitpz", NULL, FALSE); + m_world->RemoveDonut(*this); + local14 = TRUE; + break; } } } + else if (!strncmp(r->GetName(), "dammo", 5)) { + Mx3DPointFloat local1f8; + Mx3DPointFloat local1e4; - if (!local14) { - if (IsPizza()) { - m_world->FUN_10073360(*this, local68); - } - else { - m_world->FUN_10073390(*this, local68); - } + local1f8 = r->GetLocal2World()[3]; + local1e4 = m_roi->GetLocal2World()[3]; - m_worldSpeed = -1.0f; + local1e4 -= local1f8; + + float radius = r->GetWorldBoundingSphere().Radius(); + if (local1e4.LenSquared() <= radius * radius) { + MxS32 index = -1; + if (sscanf(r->GetName(), "dammo%d", &index) != 1) { + assert(0); + } + + assert(m_world); + + m_world->EatDonut(index); + + if (IsPizza()) { + assert(SoundManager()->GetCacheSoundManager()); + SoundManager()->GetCacheSoundManager()->Play("pzhitdn", NULL, FALSE); + m_world->RemovePizza(*this); + local14 = TRUE; + break; + } + } } } + + if (!local14) { + if (IsPizza()) { + m_world->FUN_10073360(*this, local68); + } + else { + m_world->FUN_10073390(*this, local68); + } + + m_worldSpeed = -1.0f; + } } } diff --git a/LEGO1/lego/legoomni/src/actors/ambulance.cpp b/LEGO1/lego/legoomni/src/actors/ambulance.cpp index c4bded70..0d2b89cc 100644 --- a/LEGO1/lego/legoomni/src/actors/ambulance.cpp +++ b/LEGO1/lego/legoomni/src/actors/ambulance.cpp @@ -40,11 +40,11 @@ Ambulance::Ambulance() m_state = NULL; m_unk0x168 = 0; m_actorId = -1; - m_unk0x16c = 0; - m_unk0x16e = 0; - m_unk0x170 = 0; + m_atPoliceTask = 0; + m_atBeachTask = 0; + m_taskState = Ambulance::e_none; m_lastAction = IsleScript::c_noneIsle; - m_unk0x172 = 0; + m_enableRandomAudio = 0; m_lastAnimation = IsleScript::c_noneIsle; m_fuel = 1.0; } @@ -73,7 +73,7 @@ MxResult Ambulance::Create(MxDSAction& p_dsAction) m_state = (AmbulanceMissionState*) GameState()->GetState("AmbulanceMissionState"); if (!m_state) { m_state = new AmbulanceMissionState(); - m_state->m_unk0x08 = 0; + m_state->m_state = AmbulanceMissionState::e_ready; GameState()->RegisterState(m_state); } } @@ -173,25 +173,25 @@ MxLong Ambulance::HandleEndAction(MxEndActionNotificationParam& p_param) m_lastAction = IsleScript::c_noneIsle; } else if (objectId == IsleScript::c_hho027en_RunAnim) { - m_state->m_unk0x08 = 1; + m_state->m_state = AmbulanceMissionState::e_enteredAmbulance; CurrentWorld()->PlaceActor(UserActor()); HandleClick(); - m_unk0x172 = 0; + m_enableRandomAudio = 0; TickleManager()->RegisterClient(this, 40000); } else if (objectId == IsleScript::c_hpz047pe_RunAnim || objectId == IsleScript::c_hpz048pe_RunAnim || objectId == IsleScript::c_hpz049bd_RunAnim || objectId == IsleScript::c_hpz053pa_RunAnim) { - if (m_unk0x170 == 3) { + if (m_taskState == Ambulance::e_finished) { PlayAnimation(IsleScript::c_hpz055pa_RunAnim); - m_unk0x170 = 0; + m_taskState = Ambulance::e_none; } else { PlayAnimation(IsleScript::c_hpz053pa_RunAnim); } } else if (objectId == IsleScript::c_hpz050bd_RunAnim || objectId == IsleScript::c_hpz052ma_RunAnim) { - if (m_unk0x170 == 3) { + if (m_taskState == Ambulance::e_finished) { PlayAnimation(IsleScript::c_hpz057ma_RunAnim); - m_unk0x170 = 0; + m_taskState = Ambulance::e_none; } else { PlayAnimation(IsleScript::c_hpz052ma_RunAnim); @@ -201,21 +201,21 @@ MxLong Ambulance::HandleEndAction(MxEndActionNotificationParam& p_param) CurrentWorld()->PlaceActor(UserActor()); HandleClick(); SpawnPlayer(LegoGameState::e_pizzeriaExterior, TRUE, 0); - m_unk0x172 = 0; + m_enableRandomAudio = 0; TickleManager()->RegisterClient(this, 40000); - if (m_unk0x16c != 0) { + if (m_atPoliceTask != 0) { StopActions(); } } else if (objectId == IsleScript::c_hps116bd_RunAnim || objectId == IsleScript::c_hps118re_RunAnim) { - if (objectId == IsleScript::c_hps116bd_RunAnim && m_unk0x170 != 3) { + if (objectId == IsleScript::c_hps116bd_RunAnim && m_taskState != Ambulance::e_finished) { PlayAction(IsleScript::c_Avo923In_PlayWav); } - if (m_unk0x170 == 3) { + if (m_taskState == Ambulance::e_finished) { PlayAnimation(IsleScript::c_hps117bd_RunAnim); - m_unk0x170 = 0; + m_taskState = Ambulance::e_none; } else { PlayAnimation(IsleScript::c_hps118re_RunAnim); @@ -225,15 +225,15 @@ MxLong Ambulance::HandleEndAction(MxEndActionNotificationParam& p_param) CurrentWorld()->PlaceActor(UserActor()); HandleClick(); SpawnPlayer(LegoGameState::e_policeExited, TRUE, 0); - m_unk0x172 = 0; + m_enableRandomAudio = 0; TickleManager()->RegisterClient(this, 40000); - if (m_unk0x16e != 0) { + if (m_atBeachTask != 0) { StopActions(); } } else if (objectId == IsleScript::c_hho142cl_RunAnim || objectId == IsleScript::c_hho143cl_RunAnim || objectId == IsleScript::c_hho144cl_RunAnim) { - FUN_10037250(); + Reset(); } } @@ -244,18 +244,18 @@ MxLong Ambulance::HandleEndAction(MxEndActionNotificationParam& p_param) // FUNCTION: BETA10 0x100230bf MxLong Ambulance::HandleButtonDown(LegoControlManagerNotificationParam& p_param) { - if (m_unk0x170 == 1) { + if (m_taskState == Ambulance::e_waiting) { LegoROI* roi = PickROI(p_param.GetX(), p_param.GetY()); if (roi != NULL && !SDL_strcasecmp(roi->GetName(), "ps-gate")) { - m_unk0x170 = 3; + m_taskState = Ambulance::e_finished; return 1; } roi = PickRootROI(p_param.GetX(), p_param.GetY()); if (roi != NULL && !SDL_strcasecmp(roi->GetName(), "gd")) { - m_unk0x170 = 3; + m_taskState = Ambulance::e_finished; return 1; } } @@ -273,9 +273,9 @@ MxLong Ambulance::HandlePathStruct(LegoPathStructNotificationParam& p_param) } if (p_param.GetTrigger() == LegoPathStruct::c_camAnim && p_param.GetData() == 0x0b) { - if (m_unk0x16e != 0) { - if (m_unk0x16c != 0) { - m_state->m_unk0x08 = 2; + if (m_atBeachTask != 0) { + if (m_atPoliceTask != 0) { + m_state->m_state = AmbulanceMissionState::e_prepareAmbulance; if (m_lastAction != IsleScript::c_noneIsle) { InvokeAction(Extra::e_stop, *g_isleScript, m_lastAction, NULL); @@ -300,7 +300,7 @@ MxLong Ambulance::HandlePathStruct(LegoPathStructNotificationParam& p_param) return 0; } - if (m_unk0x16e != 0) { + if (m_atBeachTask != 0) { if (m_lastAction != IsleScript::c_noneIsle) { InvokeAction(Extra::e_stop, *g_isleScript, m_lastAction, NULL); } @@ -310,7 +310,7 @@ MxLong Ambulance::HandlePathStruct(LegoPathStructNotificationParam& p_param) } } - if (m_unk0x16c != 0) { + if (m_atPoliceTask != 0) { if (m_lastAction != IsleScript::c_noneIsle) { InvokeAction(Extra::e_stop, *g_isleScript, m_lastAction, NULL); } @@ -318,9 +318,9 @@ MxLong Ambulance::HandlePathStruct(LegoPathStructNotificationParam& p_param) PlayAction(IsleScript::c_Avo915In_PlayWav); } } - else if (p_param.GetTrigger() == LegoPathStruct::c_s && p_param.GetData() == 0x131 && m_unk0x16e == 0) { - m_unk0x16e = 1; - m_unk0x170 = 1; + else if (p_param.GetTrigger() == LegoPathStruct::c_s && p_param.GetData() == 0x131 && m_atBeachTask == 0) { + m_atBeachTask = 1; + m_taskState = Ambulance::e_waiting; if (m_lastAction != IsleScript::c_noneIsle) { InvokeAction(Extra::e_stop, *g_isleScript, m_lastAction, NULL); @@ -348,9 +348,9 @@ MxLong Ambulance::HandlePathStruct(LegoPathStructNotificationParam& p_param) break; } } - else if (p_param.GetTrigger() == LegoPathStruct::c_camAnim && (p_param.GetData() == 0x22 || p_param.GetData() == 0x23 || p_param.GetData() == 0x24) && m_unk0x16c == 0) { - m_unk0x16c = 1; - m_unk0x170 = 1; + else if (p_param.GetTrigger() == LegoPathStruct::c_camAnim && (p_param.GetData() == 0x22 || p_param.GetData() == 0x23 || p_param.GetData() == 0x24) && m_atPoliceTask == 0) { + m_atPoliceTask = 1; + m_taskState = Ambulance::e_waiting; if (m_lastAction != IsleScript::c_noneIsle) { InvokeAction(Extra::e_stop, *g_isleScript, m_lastAction, NULL); @@ -367,15 +367,15 @@ MxLong Ambulance::HandlePathStruct(LegoPathStructNotificationParam& p_param) // FUNCTION: BETA10 0x10023506 MxLong Ambulance::HandleClick() { - if (((Act1State*) GameState()->GetState("Act1State"))->m_unk0x018 != 10) { + if (((Act1State*) GameState()->GetState("Act1State"))->m_state != Act1State::e_ambulance) { return 1; } - if (m_state->m_unk0x08 == 2) { + if (m_state->m_state == AmbulanceMissionState::e_prepareAmbulance) { return 1; } - FUN_10015820(TRUE, 0); + Disable(TRUE, 0); ((Isle*) CurrentWorld())->SetDestLocation(LegoGameState::e_ambulance); TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); @@ -390,7 +390,7 @@ MxLong Ambulance::HandleClick() InvokeAction(Extra::e_start, *g_isleScript, IsleScript::c_AmbulanceDashboard, NULL); ControlManager()->Register(this); - if (m_state->m_unk0x08 == 1) { + if (m_state->m_state == AmbulanceMissionState::e_enteredAmbulance) { SpawnPlayer(LegoGameState::e_hospitalExited, TRUE, 0); m_state->m_startTime = Timer()->GetTime(); InvokeAction(Extra::e_start, *g_isleScript, IsleScript::c_pns018rd_RunAnim, NULL); @@ -401,9 +401,9 @@ MxLong Ambulance::HandleClick() // FUNCTION: LEGO1 0x10036e60 // FUNCTION: BETA10 0x100236bb -void Ambulance::FUN_10036e60() +void Ambulance::Init() { - m_state->m_unk0x08 = 2; + m_state->m_state = AmbulanceMissionState::e_prepareAmbulance; PlayAnimation(IsleScript::c_hho027en_RunAnim); m_lastAction = IsleScript::c_noneIsle; m_lastAnimation = IsleScript::c_noneIsle; @@ -414,7 +414,7 @@ void Ambulance::Exit() { GameState()->m_currentArea = LegoGameState::e_hospitalExterior; StopActions(); - FUN_10037250(); + Reset(); Leave(); } @@ -440,7 +440,7 @@ MxLong Ambulance::HandleControl(LegoControlManagerNotificationParam& p_param) { MxLong result = 0; - if (p_param.m_unk0x28 == 1) { + if (p_param.m_enabledChild == 1) { switch (p_param.m_clickedObjectId) { case IsleScript::c_AmbulanceArms_Ctl: Exit(); @@ -457,7 +457,7 @@ MxLong Ambulance::HandleControl(LegoControlManagerNotificationParam& p_param) case IsleScript::c_AmbulanceHorn_Ctl: MxSoundPresenter* presenter = (MxSoundPresenter*) CurrentWorld()->Find("MxSoundPresenter", "AmbulanceHorn_Sound"); - presenter->Enable(p_param.m_unk0x28); + presenter->Enable(p_param.m_enabledChild); break; } } @@ -470,11 +470,11 @@ void Ambulance::ActivateSceneActions() { PlayMusic(JukeboxScript::c_Hospital_Music); - if (m_state->m_unk0x08 == 1) { - m_state->m_unk0x08 = 0; + if (m_state->m_state == AmbulanceMissionState::e_enteredAmbulance) { + m_state->m_state = AmbulanceMissionState::e_ready; PlayAction(IsleScript::c_ham033cl_PlayWav); } - else if (m_unk0x16c != 0 && m_unk0x16e != 0) { + else if (m_atPoliceTask != 0 && m_atBeachTask != 0) { IsleScript::Script objectId; switch (SDL_rand(2)) { @@ -516,8 +516,8 @@ void Ambulance::ActivateSceneActions() // FUNCTION: BETA10 0x100237df MxResult Ambulance::Tickle() { - if (m_unk0x172 == 0) { - m_unk0x172 = 1; + if (m_enableRandomAudio == 0) { + m_enableRandomAudio = 1; } else if (m_lastAction == IsleScript::c_noneIsle) { IsleScript::Script objectId; @@ -574,14 +574,14 @@ void Ambulance::StopActions() } // FUNCTION: LEGO1 0x10037250 -void Ambulance::FUN_10037250() +void Ambulance::Reset() { StopAction(m_lastAction); BackgroundAudioManager()->RaiseVolume(); - ((Act1State*) GameState()->GetState("Act1State"))->m_unk0x018 = 0; - m_state->m_unk0x08 = 0; - m_unk0x16e = 0; - m_unk0x16c = 0; + ((Act1State*) GameState()->GetState("Act1State"))->m_state = Act1State::e_none; + m_state->m_state = AmbulanceMissionState::e_ready; + m_atBeachTask = 0; + m_atPoliceTask = 0; g_isleFlags |= Isle::c_playMusic; AnimationManager()->EnableCamAnims(TRUE); AnimationManager()->FUN_1005f6d0(TRUE); @@ -629,7 +629,7 @@ void Ambulance::PlayAction(IsleScript::Script p_objectId) // FUNCTION: LEGO1 0x100373a0 AmbulanceMissionState::AmbulanceMissionState() { - m_unk0x08 = 0; + m_state = AmbulanceMissionState::e_ready; m_startTime = 0; m_peScore = 0; m_maScore = 0; diff --git a/LEGO1/lego/legoomni/src/actors/bike.cpp b/LEGO1/lego/legoomni/src/actors/bike.cpp index 0d480ad0..fbdce39e 100644 --- a/LEGO1/lego/legoomni/src/actors/bike.cpp +++ b/LEGO1/lego/legoomni/src/actors/bike.cpp @@ -52,9 +52,9 @@ void Bike::Exit() // FUNCTION: LEGO1 0x100769a0 MxLong Bike::HandleClick() { - if (FUN_1003ef60()) { + if (CanExit()) { Act1State* state = (Act1State*) GameState()->GetState("Act1State"); - FUN_10015820(TRUE, 0); + Disable(TRUE, 0); ((Isle*) CurrentWorld())->SetDestLocation(LegoGameState::Area::e_bike); TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, TRUE); @@ -81,7 +81,7 @@ MxLong Bike::HandleControl(LegoControlManagerNotificationParam& p_param) { MxLong result = 0; - if (p_param.m_unk0x28 == 1) { + if (p_param.m_enabledChild == 1) { switch (p_param.m_clickedObjectId) { case IsleScript::c_BikeArms_Ctl: Exit(); @@ -97,7 +97,7 @@ MxLong Bike::HandleControl(LegoControlManagerNotificationParam& p_param) case IsleScript::c_BikeHorn_Ctl: MxSoundPresenter* presenter = (MxSoundPresenter*) CurrentWorld()->Find("MxSoundPresenter", "BikeHorn_Sound"); - presenter->Enable(p_param.m_unk0x28); + presenter->Enable(p_param.m_enabledChild); break; } } diff --git a/LEGO1/lego/legoomni/src/actors/buildings.cpp b/LEGO1/lego/legoomni/src/actors/buildings.cpp index ea7069cc..b9e736c4 100644 --- a/LEGO1/lego/legoomni/src/actors/buildings.cpp +++ b/LEGO1/lego/legoomni/src/actors/buildings.cpp @@ -53,7 +53,7 @@ MxLong InfoCenterEntity::HandleClick(LegoEventNotificationParam& p_param) isle->SetDestLocation(LegoGameState::Area::e_infomain); Act1State* act1state = (Act1State*) GameState()->GetState("Act1State"); - act1state->SetUnknown18(0); + act1state->SetState(Act1State::e_none); break; } case LegoGameState::Act::e_act2: { @@ -80,11 +80,11 @@ MxLong InfoCenterEntity::HandleClick(LegoEventNotificationParam& p_param) // FUNCTION: LEGO1 0x100151d0 MxLong GasStationEntity::HandleClick(LegoEventNotificationParam& p_param) { - if (FUN_1003ef60()) { + if (CanExit()) { Act1State* state = (Act1State*) GameState()->GetState("Act1State"); - if (state->GetUnknown18() != 8) { - state->SetUnknown18(0); + if (state->GetState() != Act1State::e_towtrack) { + state->SetState(Act1State::e_none); if (UserActor()->GetActorId() != GameState()->GetActorId()) { ((IslePathActor*) UserActor())->Exit(); @@ -104,11 +104,11 @@ MxLong GasStationEntity::HandleClick(LegoEventNotificationParam& p_param) // FUNCTION: LEGO1 0x10015270 MxLong HospitalEntity::HandleClick(LegoEventNotificationParam& p_param) { - if (FUN_1003ef60()) { + if (CanExit()) { Act1State* act1State = (Act1State*) GameState()->GetState("Act1State"); - if (act1State->GetUnknown18() != 10) { - act1State->SetUnknown18(0); + if (act1State->GetState() != Act1State::e_ambulance) { + act1State->SetState(Act1State::e_none); if (UserActor()->GetActorId() != GameState()->GetActorId()) { ((IslePathActor*) UserActor())->Exit(); @@ -128,11 +128,11 @@ MxLong HospitalEntity::HandleClick(LegoEventNotificationParam& p_param) // FUNCTION: LEGO1 0x10015310 MxLong PoliceEntity::HandleClick(LegoEventNotificationParam& p_param) { - if (FUN_1003ef60()) { + if (CanExit()) { Act1State* state = (Act1State*) GameState()->GetState("Act1State"); - if (state->GetUnknown18() != 10) { - state->SetUnknown18(0); + if (state->GetState() != Act1State::e_ambulance) { + state->SetState(Act1State::e_none); if (UserActor()->GetActorId() != GameState()->GetActorId()) { ((IslePathActor*) UserActor())->Exit(); @@ -152,9 +152,9 @@ MxLong PoliceEntity::HandleClick(LegoEventNotificationParam& p_param) // FUNCTION: LEGO1 0x100153b0 MxLong BeachHouseEntity::HandleClick(LegoEventNotificationParam& p_param) { - if (FUN_1003ef60()) { + if (CanExit()) { Act1State* state = (Act1State*) GameState()->GetState("Act1State"); - state->SetUnknown18(0); + state->SetState(Act1State::e_none); if (UserActor()->GetActorId() != GameState()->GetActorId()) { ((IslePathActor*) UserActor())->Exit(); @@ -173,9 +173,9 @@ MxLong BeachHouseEntity::HandleClick(LegoEventNotificationParam& p_param) // FUNCTION: LEGO1 0x10015450 MxLong RaceStandsEntity::HandleClick(LegoEventNotificationParam& p_param) { - if (FUN_1003ef60()) { + if (CanExit()) { Act1State* state = (Act1State*) GameState()->GetState("Act1State"); - state->SetUnknown18(0); + state->SetState(Act1State::e_none); if (UserActor()->GetActorId() != GameState()->GetActorId()) { ((IslePathActor*) UserActor())->Exit(); @@ -195,7 +195,7 @@ MxLong RaceStandsEntity::HandleClick(LegoEventNotificationParam& p_param) // FUNCTION: BETA10 0x100256e8 MxLong JailEntity::HandleClick(LegoEventNotificationParam& p_param) { - if (FUN_1003ef60()) { + if (CanExit()) { PlayCamAnim(UserActor(), FALSE, 18, TRUE); } diff --git a/LEGO1/lego/legoomni/src/actors/bumpbouy.cpp b/LEGO1/lego/legoomni/src/actors/bumpbouy.cpp index 371e4257..03c93f7b 100644 --- a/LEGO1/lego/legoomni/src/actors/bumpbouy.cpp +++ b/LEGO1/lego/legoomni/src/actors/bumpbouy.cpp @@ -45,7 +45,7 @@ MxLong BumpBouy::Notify(MxParam& p_param) Act1State* isleState = (Act1State*) GameState()->GetState("Act1State"); assert(isleState); - isleState->m_unk0x018 = 5; + isleState->m_state = Act1State::e_transitionToJetski; Isle* isle = (Isle*) FindWorld(*g_isleScript, IsleScript::c__Isle); assert(isle); diff --git a/LEGO1/lego/legoomni/src/actors/dunebuggy.cpp b/LEGO1/lego/legoomni/src/actors/dunebuggy.cpp index 049c7f86..5b701c46 100644 --- a/LEGO1/lego/legoomni/src/actors/dunebuggy.cpp +++ b/LEGO1/lego/legoomni/src/actors/dunebuggy.cpp @@ -91,11 +91,11 @@ void DuneBuggy::Exit() // FUNCTION: LEGO1 0x10068060 MxLong DuneBuggy::HandleClick() { - if (!FUN_1003ef60()) { + if (!CanExit()) { return 1; } - FUN_10015820(TRUE, 0); + Disable(TRUE, 0); ((Isle*) CurrentWorld())->SetDestLocation(LegoGameState::Area::e_dunecar); TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, TRUE); @@ -124,7 +124,7 @@ MxLong DuneBuggy::HandleControl(LegoControlManagerNotificationParam& p_param) { MxLong result = 0; - if (p_param.m_unk0x28 == 1) { + if (p_param.m_enabledChild == 1) { switch (p_param.m_clickedObjectId) { case IsleScript::c_DuneCarArms_Ctl: Exit(); @@ -140,7 +140,7 @@ MxLong DuneBuggy::HandleControl(LegoControlManagerNotificationParam& p_param) case IsleScript::c_DuneCarHorn_Ctl: MxSoundPresenter* presenter = (MxSoundPresenter*) CurrentWorld()->Find("MxSoundPresenter", "DuneCarHorn_Sound"); - presenter->Enable(p_param.m_unk0x28); + presenter->Enable(p_param.m_enabledChild); break; } } diff --git a/LEGO1/lego/legoomni/src/actors/helicopter.cpp b/LEGO1/lego/legoomni/src/actors/helicopter.cpp index bf9eb9d0..fc2addb3 100644 --- a/LEGO1/lego/legoomni/src/actors/helicopter.cpp +++ b/LEGO1/lego/legoomni/src/actors/helicopter.cpp @@ -82,7 +82,7 @@ void Helicopter::Exit() if (GameState()->GetCurrentAct() == LegoGameState::e_act1) { SpawnPlayer( - LegoGameState::e_unk40, + LegoGameState::e_helicopterSpawn, TRUE, IslePathActor::c_spawnBit1 | IslePathActor::c_playMusic | IslePathActor::c_spawnBit3 ); @@ -121,7 +121,7 @@ void Helicopter::Exit() // FUNCTION: BETA10 0x1002a3db MxLong Helicopter::HandleClick() { - if (!FUN_1003ef60()) { + if (!CanExit()) { return 1; } @@ -148,7 +148,7 @@ MxLong Helicopter::HandleClick() IslePathActor::c_spawnBit1 | IslePathActor::c_playMusic | IslePathActor::c_spawnBit3 ); ((Isle*) CurrentWorld())->SetDestLocation(LegoGameState::e_copter); - FUN_10015820(TRUE, 0); + Disable(TRUE, 0); TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, TRUE); SetActorState(c_disabled); PlayMusic(JukeboxScript::c_Jail_Music); @@ -189,7 +189,7 @@ MxLong Helicopter::HandleControl(LegoControlManagerNotificationParam& p_param) break; } - if (p_param.m_unk0x28 == 1) { + if (p_param.m_enabledChild == 1) { MxU32 isPizza = FALSE; switch (p_param.m_clickedObjectId) { @@ -214,7 +214,7 @@ MxLong Helicopter::HandleControl(LegoControlManagerNotificationParam& p_param) Act1State* act1State = (Act1State*) GameState()->GetState("Act1State"); assert(act1State); if (m_state->m_unk0x08 == 0) { - act1State->m_unk0x018 = 4; + act1State->m_state = Act1State::e_helicopter; m_state->m_unk0x08 = 1; m_world->RemoveActor(this); InvokeAction(Extra::ActionType::e_start, script, IsleScript::c_HelicopterTakeOff_Anim, NULL); @@ -318,7 +318,7 @@ MxLong Helicopter::HandleEndAnim(LegoEndAnimNotificationParam& p_param) if (GameState()->GetCurrentAct() == LegoGameState::e_act1) { Act1State* act1State = (Act1State*) GameState()->GetState("Act1State"); assert(act1State); - act1State->m_unk0x018 = 4; + act1State->m_state = Act1State::e_helicopter; SpawnPlayer( LegoGameState::e_unk42, TRUE, @@ -359,7 +359,7 @@ MxLong Helicopter::HandleEndAnim(LegoEndAnimNotificationParam& p_param) if (GameState()->GetCurrentAct() == LegoGameState::e_act1) { Act1State* act1State = (Act1State*) GameState()->GetState("Act1State"); assert(act1State); - act1State->m_unk0x018 = 0; + act1State->m_state = Act1State::e_none; SpawnPlayer( LegoGameState::e_unk41, TRUE, @@ -426,7 +426,7 @@ void Helicopter::Animate(float p_time) v2 *= f2; v2 += v1; - m_world->GetCameraController()->FUN_100123e0(mat, 0); + m_world->GetCameraController()->TransformPointOfView(mat, 0); } else { if (m_state->m_unk0x08 == 4) { @@ -459,7 +459,7 @@ void Helicopter::FUN_100042a0(const Matrix4& p_matrix) // the typecast makes this function match for unknown reasons Vector3 vec6((const float*) m_unk0x1a8[3]); // locala0 // esp+0x28 - m_world->GetCameraController()->FUN_100123b0(local48); + m_world->GetCameraController()->GetPointOfView(local48); m_unk0x1a8.SetIdentity(); local90 = p_matrix; diff --git a/LEGO1/lego/legoomni/src/actors/islepathactor.cpp b/LEGO1/lego/legoomni/src/actors/islepathactor.cpp index fbd57206..d366761e 100644 --- a/LEGO1/lego/legoomni/src/actors/islepathactor.cpp +++ b/LEGO1/lego/legoomni/src/actors/islepathactor.cpp @@ -153,7 +153,7 @@ void IslePathActor::Exit() FUN_1001b660(); FUN_10010c30(); - FUN_1003eda0(); + ResetViewVelocity(); } // GLOBAL: LEGO1 0x10102b28 @@ -355,7 +355,7 @@ void IslePathActor::RegisterSpawnLocations() JukeboxScript::c_PoliceStation_Music ); g_spawnLocations[16] = SpawnLocation( - LegoGameState::e_unk40, + LegoGameState::e_helicopterSpawn, g_isleScript, 0, "edg02_51", @@ -379,7 +379,7 @@ void IslePathActor::RegisterSpawnLocations() JukeboxScript::c_noneJukebox ); g_spawnLocations[18] = SpawnLocation( - LegoGameState::e_unk43, + LegoGameState::e_dunebuggySpawn, g_isleScript, 0, "edg02_35", @@ -391,7 +391,7 @@ void IslePathActor::RegisterSpawnLocations() JukeboxScript::c_noneJukebox ); g_spawnLocations[19] = SpawnLocation( - LegoGameState::e_unk44, + LegoGameState::e_racecarSpawn, g_isleScript, 0, "EDG03_01", @@ -403,7 +403,7 @@ void IslePathActor::RegisterSpawnLocations() JukeboxScript::c_noneJukebox ); g_spawnLocations[20] = SpawnLocation( - LegoGameState::e_unk45, + LegoGameState::e_jetskiSpawn, g_isleScript, 0, "edg10_70", @@ -475,7 +475,7 @@ void IslePathActor::RegisterSpawnLocations() JukeboxScript::c_noneJukebox ); g_spawnLocations[26] = SpawnLocation( - LegoGameState::e_unk52, + LegoGameState::e_towTrackHookedUp, g_isleScript, 0, "edg02_19", @@ -598,7 +598,7 @@ void IslePathActor::SpawnPlayer(LegoGameState::Area p_area, MxBool p_enter, MxU8 } if (m_cameraFlag) { - FUN_1003eda0(); + ResetViewVelocity(); } if (p_flags & c_playMusic && g_spawnLocations[i].m_music != JukeboxScript::c_noneJukebox) { @@ -632,7 +632,7 @@ void IslePathActor::VTable0xec(MxMatrix p_transform, LegoPathBoundary* p_boundar m_roi->SetLocal2World(p_transform); if (m_cameraFlag) { - FUN_1003eda0(); + ResetViewVelocity(); FUN_10010c30(); } } diff --git a/LEGO1/lego/legoomni/src/actors/jetski.cpp b/LEGO1/lego/legoomni/src/actors/jetski.cpp index 2c57c76e..cdde06ee 100644 --- a/LEGO1/lego/legoomni/src/actors/jetski.cpp +++ b/LEGO1/lego/legoomni/src/actors/jetski.cpp @@ -69,7 +69,7 @@ void Jetski::Animate(float p_time) // FUNCTION: LEGO1 0x1007e6f0 void Jetski::Exit() { - SpawnPlayer(LegoGameState::e_unk45, FALSE, c_spawnBit1 | c_playMusic | c_spawnBit3); + SpawnPlayer(LegoGameState::e_jetskiSpawn, FALSE, c_spawnBit1 | c_playMusic | c_spawnBit3); IslePathActor::Exit(); GameState()->m_currentArea = LegoGameState::e_jetski; RemoveFromWorld(); @@ -83,11 +83,11 @@ void Jetski::Exit() MxLong Jetski::HandleClick() { #ifndef BETA10 - if (!FUN_1003ef60()) { + if (!CanExit()) { return 1; } - FUN_10015820(TRUE, 0); + Disable(TRUE, 0); ((Isle*) CurrentWorld())->SetDestLocation(LegoGameState::Area::e_jetski); TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, TRUE); @@ -139,7 +139,7 @@ void Jetski::RemoveFromWorld() // FUNCTION: LEGO1 0x1007e8e0 MxLong Jetski::HandleControl(LegoControlManagerNotificationParam& p_param) { - if (p_param.m_unk0x28 == 1 && CurrentWorld()->IsA("Isle")) { + if (p_param.m_enabledChild == 1 && CurrentWorld()->IsA("Isle")) { switch (p_param.m_clickedObjectId) { case IsleScript::c_JetskiArms_Ctl: Exit(); @@ -164,7 +164,7 @@ void Jetski::ActivateSceneActions() PlayMusic(JukeboxScript::c_JetskiRace_Music); Act1State* act1state = (Act1State*) GameState()->GetState("Act1State"); - if (!act1state->m_unk0x018) { + if (!act1state->m_state) { if (act1state->m_unk0x022) { PlayCamAnim(this, FALSE, 68, TRUE); } diff --git a/LEGO1/lego/legoomni/src/actors/jukeboxentity.cpp b/LEGO1/lego/legoomni/src/actors/jukeboxentity.cpp index ecf0bec8..c92aec79 100644 --- a/LEGO1/lego/legoomni/src/actors/jukeboxentity.cpp +++ b/LEGO1/lego/legoomni/src/actors/jukeboxentity.cpp @@ -36,7 +36,7 @@ MxLong JukeBoxEntity::Notify(MxParam& p_param) MxNotificationParam& param = (MxNotificationParam&) p_param; if (param.GetNotification() == c_notificationClick) { - if (!FUN_1003ef60()) { + if (!CanExit()) { return 1; } diff --git a/LEGO1/lego/legoomni/src/actors/motorcycle.cpp b/LEGO1/lego/legoomni/src/actors/motorcycle.cpp index 6a20d6f3..3a4229b3 100644 --- a/LEGO1/lego/legoomni/src/actors/motorcycle.cpp +++ b/LEGO1/lego/legoomni/src/actors/motorcycle.cpp @@ -86,11 +86,11 @@ void Motocycle::Exit() // FUNCTION: LEGO1 0x10035c50 MxLong Motocycle::HandleClick() { - if (!FUN_1003ef60()) { + if (!CanExit()) { return 1; } - FUN_10015820(TRUE, 0); + Disable(TRUE, 0); ((Isle*) CurrentWorld())->SetDestLocation(LegoGameState::Area::e_motocycle); TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, TRUE); @@ -117,7 +117,7 @@ MxLong Motocycle::HandleControl(LegoControlManagerNotificationParam& p_param) { MxLong result = 0; - if (p_param.m_unk0x28 == 1) { + if (p_param.m_enabledChild == 1) { switch (p_param.m_clickedObjectId) { case IsleScript::c_MotoBikeArms_Ctl: Exit(); diff --git a/LEGO1/lego/legoomni/src/actors/pizza.cpp b/LEGO1/lego/legoomni/src/actors/pizza.cpp index 18da7fca..422cf87f 100644 --- a/LEGO1/lego/legoomni/src/actors/pizza.cpp +++ b/LEGO1/lego/legoomni/src/actors/pizza.cpp @@ -182,7 +182,7 @@ void Pizza::FUN_10038220(IsleScript::Script p_objectId) AnimationManager()->FUN_10064740(NULL); m_mission = m_state->GetMission(GameState()->GetActorId()); m_state->m_unk0x0c = 1; - m_act1state->m_unk0x018 = 3; + m_act1state->m_state = Act1State::e_pizza; m_mission->m_startTime = INT_MIN; g_isleFlags &= ~Isle::c_playMusic; AnimationManager()->EnableCamAnims(FALSE); @@ -200,7 +200,7 @@ void Pizza::FUN_100382b0() InvokeAction(Extra::e_stop, *g_isleScript, m_speechAction, NULL); } - m_act1state->m_unk0x018 = 0; + m_act1state->m_state = Act1State::e_none; m_state->m_unk0x0c = 0; UserActor()->SetActorState(LegoPathActor::c_initial); g_isleFlags |= Isle::c_playMusic; @@ -245,7 +245,7 @@ MxLong Pizza::HandleClick() } if (m_state->m_unk0x0c == 2) { - m_act1state->m_unk0x018 = 3; + m_act1state->m_state = Act1State::e_pizza; if (m_skateBoard == NULL) { m_skateBoard = (SkateBoard*) m_world->Find(m_atomId, IsleScript::c_SkateBoard_Actor); @@ -558,7 +558,7 @@ MxLong Pizza::HandleEndAction(MxEndActionNotificationParam& p_param) break; case 8: if (m_state->GetPlayedAction() == objectId) { - m_act1state->m_unk0x018 = 0; + m_act1state->m_state = Act1State::e_none; m_state->m_unk0x0c = 0; GameState()->m_currentArea = LegoGameState::e_isle; TickleManager()->UnregisterClient(this); diff --git a/LEGO1/lego/legoomni/src/actors/pizzeria.cpp b/LEGO1/lego/legoomni/src/actors/pizzeria.cpp index a040f337..3b5f8923 100644 --- a/LEGO1/lego/legoomni/src/actors/pizzeria.cpp +++ b/LEGO1/lego/legoomni/src/actors/pizzeria.cpp @@ -69,7 +69,7 @@ void Pizzeria::CreateState() // FUNCTION: BETA10 0x100efc91 MxLong Pizzeria::HandleClick() { - if (FUN_1003ef60() && m_pizzaMissionState->m_unk0x0c == 0) { + if (CanExit() && m_pizzaMissionState->m_unk0x0c == 0) { if (UserActor()->GetActorId() != GameState()->GetActorId()) { if (!UserActor()->IsA("SkateBoard")) { ((IslePathActor*) UserActor())->Exit(); diff --git a/LEGO1/lego/legoomni/src/actors/racecar.cpp b/LEGO1/lego/legoomni/src/actors/racecar.cpp index f511f524..ff9eb293 100644 --- a/LEGO1/lego/legoomni/src/actors/racecar.cpp +++ b/LEGO1/lego/legoomni/src/actors/racecar.cpp @@ -40,7 +40,7 @@ MxResult RaceCar::Create(MxDSAction& p_dsAction) // FUNCTION: LEGO1 0x100284d0 MxLong RaceCar::HandleClick() { - if (!FUN_1003ef60()) { + if (!CanExit()) { return 1; } diff --git a/LEGO1/lego/legoomni/src/actors/radio.cpp b/LEGO1/lego/legoomni/src/actors/radio.cpp index 2df84506..104ba823 100644 --- a/LEGO1/lego/legoomni/src/actors/radio.cpp +++ b/LEGO1/lego/legoomni/src/actors/radio.cpp @@ -131,7 +131,7 @@ void Radio::Stop() MxControlPresenter* presenter = (MxControlPresenter*) world->Find(world->GetAtomId(), IsleScript::c_Radio_Ctl); if (presenter) { - presenter->VTable0x6c(0); + presenter->UpdateEnabledChild(0); } BackgroundAudioManager()->Stop(); diff --git a/LEGO1/lego/legoomni/src/actors/skateboard.cpp b/LEGO1/lego/legoomni/src/actors/skateboard.cpp index 18d2810d..17730148 100644 --- a/LEGO1/lego/legoomni/src/actors/skateboard.cpp +++ b/LEGO1/lego/legoomni/src/actors/skateboard.cpp @@ -56,7 +56,7 @@ MxResult SkateBoard::Create(MxDSAction& p_dsAction) // FUNCTION: LEGO1 0x10010050 void SkateBoard::Exit() { - if (m_act1state->m_unk0x018 == 3) { + if (m_act1state->m_state == Act1State::e_pizza) { Pizza* pizza = (Pizza*) CurrentWorld()->Find(*g_isleScript, IsleScript::c_Pizza_Actor); pizza->StopActions(); pizza->FUN_100382b0(); @@ -75,11 +75,11 @@ MxLong SkateBoard::HandleClick() { Act1State* state = (Act1State*) GameState()->GetState("Act1State"); - if (!FUN_1003ef60() && state->m_unk0x018 != 3) { + if (!CanExit() && state->m_state != Act1State::e_pizza) { return 1; } - FUN_10015820(TRUE, 0); + Disable(TRUE, 0); ((Isle*) CurrentWorld())->SetDestLocation(LegoGameState::Area::e_skateboard); TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, TRUE); @@ -110,7 +110,7 @@ MxLong SkateBoard::HandleControl(LegoControlManagerNotificationParam& p_param) { MxU32 result = 0; - if (p_param.m_unk0x28 == 1 && p_param.m_clickedObjectId == IsleScript::c_SkateArms_Ctl) { + if (p_param.m_enabledChild == 1 && p_param.m_clickedObjectId == IsleScript::c_SkateArms_Ctl) { Exit(); GameState()->m_currentArea = LegoGameState::Area::e_vehicleExited; result = 1; @@ -148,7 +148,7 @@ MxLong SkateBoard::HandleNotification0() // FUNCTION: LEGO1 0x10010510 void SkateBoard::ActivateSceneActions() { - if (m_act1state->m_unk0x018 != 3) { + if (m_act1state->m_state != Act1State::e_pizza) { PlayMusic(JukeboxScript::c_BeachBlvd_Music); if (!m_act1state->m_unk0x022) { diff --git a/LEGO1/lego/legoomni/src/actors/towtrack.cpp b/LEGO1/lego/legoomni/src/actors/towtrack.cpp index 6143ccf8..bf6b29bc 100644 --- a/LEGO1/lego/legoomni/src/actors/towtrack.cpp +++ b/LEGO1/lego/legoomni/src/actors/towtrack.cpp @@ -34,9 +34,9 @@ TowTrack::TowTrack() m_unk0x168 = 0; m_actorId = -1; m_state = NULL; - m_unk0x16c = 0; + m_treeBlockageTriggered = 0; m_lastAction = IsleScript::c_noneIsle; - m_unk0x16e = 0; + m_speedComplaintTriggered = 0; m_lastAnimation = IsleScript::c_noneIsle; m_maxLinearVel = 40.0; m_fuel = 1.0; @@ -64,7 +64,7 @@ MxResult TowTrack::Create(MxDSAction& p_dsAction) m_state = (TowTrackMissionState*) GameState()->GetState("TowTrackMissionState"); if (!m_state) { m_state = new TowTrackMissionState(); - m_state->m_unk0x08 = 0; + m_state->m_state = TowTrackMissionState::e_none; GameState()->RegisterState(m_state); } } @@ -98,9 +98,10 @@ void TowTrack::Animate(float p_time) sprintf(buf, "%g", m_fuel); VariableTable()->SetVariable(g_varTOWFUEL, buf); - if (p_time - m_state->m_startTime > 100000.0f && m_state->m_unk0x08 == 1 && !m_state->m_unk0x10) { + if (p_time - m_state->m_startTime > 100000.0f && m_state->m_state == TowTrackMissionState::e_started && + !m_state->m_takingTooLong) { PlayAction(IsleScript::c_Avo909In_PlayWav); - m_state->m_unk0x10 = TRUE; + m_state->m_takingTooLong = TRUE; } } } @@ -190,7 +191,7 @@ MxLong TowTrack::HandleEndAction(MxEndActionNotificationParam& p_param) } } else if (objectId == IsleScript::c_wrt074sl_RunAnim || objectId == IsleScript::c_wrt075rh_RunAnim || objectId == IsleScript::c_wrt076df_RunAnim || objectId == IsleScript::c_wrt078ni_RunAnim) { - m_state->m_unk0x08 = 2; + m_state->m_state = TowTrackMissionState::e_hookedUp; CurrentWorld()->PlaceActor(UserActor()); HandleClick(); } @@ -274,7 +275,7 @@ MxLong TowTrack::HandleEndAction(MxEndActionNotificationParam& p_param) m_state->UpdateScore(LegoState::e_yellow, m_actorId); } else if (objectId == IsleScript::c_wgs098nu_RunAnim || objectId == IsleScript::c_wgs099nu_RunAnim || objectId == IsleScript::c_wgs100nu_RunAnim || objectId == IsleScript::c_wgs101nu_RunAnim || objectId == IsleScript::c_wgs102nu_RunAnim || objectId == IsleScript::c_wgs085nu_RunAnim || objectId == IsleScript::c_wgs086nu_RunAnim || objectId == IsleScript::c_wgs087nu_RunAnim || objectId == IsleScript::c_wgs088nu_RunAnim || objectId == IsleScript::c_wgs089nu_RunAnim || objectId == IsleScript::c_wgs091nu_RunAnim || objectId == IsleScript::c_wgs092nu_RunAnim || objectId == IsleScript::c_wgs093nu_RunAnim || objectId == IsleScript::c_wgs094nu_RunAnim || objectId == IsleScript::c_wgs095nu_RunAnim) { - ((Act1State*) GameState()->GetState("Act1State"))->m_unk0x018 = 0; + ((Act1State*) GameState()->GetState("Act1State"))->m_state = Act1State::e_none; AnimationManager()->FUN_1005f6d0(TRUE); g_isleFlags |= Isle::c_playMusic; AnimationManager()->EnableCamAnims(TRUE); @@ -299,10 +300,10 @@ MxLong TowTrack::HandlePathStruct(LegoPathStructNotificationParam& p_param) return 0; } - if (m_state->m_unk0x08 == 2 && + if (m_state->m_state == TowTrackMissionState::e_hookedUp && ((p_param.GetTrigger() == LegoPathStruct::c_camAnim && (p_param.GetData() == 9 || p_param.GetData() == 8)) || (p_param.GetTrigger() == LegoPathStruct::c_w && p_param.GetData() == 0x169))) { - m_state->m_unk0x08 = 0; + m_state->m_state = TowTrackMissionState::e_none; MxLong time = Timer()->GetTime() - m_state->m_startTime; Leave(); @@ -317,8 +318,8 @@ MxLong TowTrack::HandlePathStruct(LegoPathStructNotificationParam& p_param) PlayFinalAnimation(IsleScript::c_wgs097nu_RunAnim); } } - else if (m_state->m_unk0x08 == 1 && p_param.GetTrigger() == LegoPathStruct::c_camAnim && p_param.GetData() == 0x37) { - m_state->m_unk0x08 = 3; + else if (m_state->m_state == TowTrackMissionState::e_started && p_param.GetTrigger() == LegoPathStruct::c_camAnim && p_param.GetData() == 0x37) { + m_state->m_state = TowTrackMissionState::e_hookingUp; StopActions(); if (m_lastAction != IsleScript::c_noneIsle) { @@ -328,20 +329,20 @@ MxLong TowTrack::HandlePathStruct(LegoPathStructNotificationParam& p_param) Leave(); PlayFinalAnimation(IsleScript::c_wrt060bm_RunAnim); } - else if (p_param.GetTrigger() == LegoPathStruct::c_w && m_state->m_unk0x08 == 1) { + else if (p_param.GetTrigger() == LegoPathStruct::c_w && m_state->m_state == TowTrackMissionState::e_started) { if (p_param.GetData() == 0x15f) { - if (m_unk0x16c == 0) { - m_unk0x16c = 1; + if (m_treeBlockageTriggered == 0) { + m_treeBlockageTriggered = 1; InvokeAction(Extra::e_start, *g_isleScript, IsleScript::c_wns050p1_RunAnim, NULL); } } else if (p_param.GetData() == 0x160) { - if (m_unk0x16e == 0) { - m_unk0x16e = 1; + if (m_speedComplaintTriggered == 0) { + m_speedComplaintTriggered = 1; InvokeAction(Extra::e_start, *g_isleScript, IsleScript::c_wns046mg_RunAnim, NULL); } - if (!m_state->m_unk0x10 && m_lastAction == IsleScript::c_noneIsle) { + if (!m_state->m_takingTooLong && m_lastAction == IsleScript::c_noneIsle) { if (m_actorId < LegoActor::c_pepper || m_actorId > LegoActor::c_laura) { m_actorId = LegoActor::c_laura; } @@ -405,15 +406,15 @@ MxLong TowTrack::HandlePathStruct(LegoPathStructNotificationParam& p_param) // FUNCTION: LEGO1 0x1004d690 MxLong TowTrack::HandleClick() { - if (((Act1State*) GameState()->GetState("Act1State"))->m_unk0x018 != 8) { + if (((Act1State*) GameState()->GetState("Act1State"))->m_state != Act1State::e_towtrack) { return 1; } - if (m_state->m_unk0x08 == 3) { + if (m_state->m_state == TowTrackMissionState::e_hookingUp) { return 1; } - FUN_10015820(TRUE, 0); + Disable(TRUE, 0); ((Isle*) CurrentWorld())->SetDestLocation(LegoGameState::e_towtrack); TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); @@ -428,12 +429,12 @@ MxLong TowTrack::HandleClick() InvokeAction(Extra::e_start, *g_isleScript, IsleScript::c_TowTrackDashboard, NULL); ControlManager()->Register(this); - if (m_state->m_unk0x08 == 0) { + if (m_state->m_state == TowTrackMissionState::e_none) { return 1; } - if (m_state->m_unk0x08 == 2) { - SpawnPlayer(LegoGameState::e_unk52, TRUE, 0); + if (m_state->m_state == TowTrackMissionState::e_hookedUp) { + SpawnPlayer(LegoGameState::e_towTrackHookedUp, TRUE, 0); FindROI("rcred")->SetVisibility(FALSE); } else { @@ -441,7 +442,7 @@ MxLong TowTrack::HandleClick() m_lastAction = IsleScript::c_noneIsle; m_lastAnimation = IsleScript::c_noneIsle; m_state->m_startTime = Timer()->GetTime(); - m_state->m_unk0x10 = FALSE; + m_state->m_takingTooLong = FALSE; InvokeAction(Extra::e_start, *g_isleScript, IsleScript::c_wns057rd_RunAnim, NULL); InvokeAction(Extra::e_start, *g_isleScript, IsleScript::c_wns048p1_RunAnim, NULL); InvokeAction(Extra::e_start, *g_isleScript, IsleScript::c_wns049p1_RunAnim, NULL); @@ -459,7 +460,7 @@ void TowTrack::Exit() { GameState()->m_currentArea = LegoGameState::e_garageExterior; StopActions(); - FUN_1004dbe0(); + Reset(); Leave(); } @@ -484,7 +485,7 @@ MxLong TowTrack::HandleControl(LegoControlManagerNotificationParam& p_param) { MxLong result = 0; - if (p_param.m_unk0x28 == 1) { + if (p_param.m_enabledChild == 1) { switch (p_param.m_clickedObjectId) { case IsleScript::c_TowTrackArms_Ctl: Exit(); @@ -500,7 +501,7 @@ MxLong TowTrack::HandleControl(LegoControlManagerNotificationParam& p_param) break; case IsleScript::c_TowHorn_Ctl: MxSoundPresenter* presenter = (MxSoundPresenter*) CurrentWorld()->Find("MxSoundPresenter", "TowHorn_Sound"); - presenter->Enable(p_param.m_unk0x28); + presenter->Enable(p_param.m_enabledChild); break; } } @@ -509,9 +510,9 @@ MxLong TowTrack::HandleControl(LegoControlManagerNotificationParam& p_param) } // FUNCTION: LEGO1 0x1004dab0 -void TowTrack::FUN_1004dab0() +void TowTrack::Init() { - m_state->m_unk0x08 = 1; + m_state->m_state = TowTrackMissionState::e_started; HandleClick(); } @@ -520,8 +521,8 @@ void TowTrack::ActivateSceneActions() { PlayMusic(JukeboxScript::c_JBMusic2); - if (m_state->m_unk0x08 != 0) { - if (m_state->m_unk0x08 == 2) { + if (m_state->m_state != TowTrackMissionState::e_none) { + if (m_state->m_state == TowTrackMissionState::e_hookedUp) { PlayAction(IsleScript::c_wrt082na_PlayWav); } else { @@ -545,22 +546,22 @@ void TowTrack::StopActions() } // FUNCTION: LEGO1 0x1004dbe0 -void TowTrack::FUN_1004dbe0() +void TowTrack::Reset() { if (m_lastAction != -1) { InvokeAction(Extra::e_stop, *g_isleScript, m_lastAction, NULL); } - ((Act1State*) GameState()->GetState("Act1State"))->m_unk0x018 = 0; - m_state->m_unk0x08 = 0; + ((Act1State*) GameState()->GetState("Act1State"))->m_state = Act1State::e_none; + m_state->m_state = TowTrackMissionState::e_none; g_isleFlags |= Isle::c_playMusic; AnimationManager()->EnableCamAnims(TRUE); AnimationManager()->FUN_1005f6d0(TRUE); m_state->m_startTime = INT_MIN; - m_state->m_unk0x10 = FALSE; + m_state->m_takingTooLong = FALSE; m_state = NULL; - m_unk0x16c = 0; - m_unk0x16e = 0; + m_treeBlockageTriggered = 0; + m_speedComplaintTriggered = 0; } // FUNCTION: LEGO1 0x1004dc80 @@ -595,9 +596,9 @@ void TowTrack::PlayAction(IsleScript::Script p_objectId) // FUNCTION: LEGO1 0x1004dd30 TowTrackMissionState::TowTrackMissionState() { - m_unk0x08 = 0; + m_state = TowTrackMissionState::e_none; m_startTime = 0; - m_unk0x10 = FALSE; + m_takingTooLong = FALSE; m_peScore = 0; m_maScore = 0; m_paScore = 0; diff --git a/LEGO1/lego/legoomni/src/audio/legocachesoundmanager.cpp b/LEGO1/lego/legoomni/src/audio/legocachesoundmanager.cpp index 34be4519..cd235b61 100644 --- a/LEGO1/lego/legoomni/src/audio/legocachesoundmanager.cpp +++ b/LEGO1/lego/legoomni/src/audio/legocachesoundmanager.cpp @@ -7,6 +7,7 @@ DECOMP_SIZE_ASSERT(LegoCacheSoundEntry, 0x08) DECOMP_SIZE_ASSERT(LegoCacheSoundManager, 0x20) // FUNCTION: LEGO1 0x1003cf20 +// STUB: BETA10 0x100d0700 LegoCacheSoundManager::~LegoCacheSoundManager() { LegoCacheSound* sound; @@ -28,6 +29,7 @@ LegoCacheSoundManager::~LegoCacheSoundManager() } // FUNCTION: LEGO1 0x1003d050 +// STUB: BETA10 0x100652f0 MxResult LegoCacheSoundManager::Tickle() { #ifdef COMPAT_MODE diff --git a/LEGO1/lego/legoomni/src/audio/legoloadcachesoundpresenter.cpp b/LEGO1/lego/legoomni/src/audio/legoloadcachesoundpresenter.cpp index 8adb79df..a9b60d66 100644 --- a/LEGO1/lego/legoomni/src/audio/legoloadcachesoundpresenter.cpp +++ b/LEGO1/lego/legoomni/src/audio/legoloadcachesoundpresenter.cpp @@ -98,7 +98,7 @@ void LegoLoadCacheSoundPresenter::DoneTickle() // FUNCTION: LEGO1 0x10018700 MxResult LegoLoadCacheSoundPresenter::PutData() { - m_criticalSection.Enter(); + ENTER(m_criticalSection); if (m_currentTickleState == e_done) { m_cacheSound = SoundManager()->GetCacheSoundManager()->ManageSoundEntry(m_cacheSound); diff --git a/LEGO1/lego/legoomni/src/audio/legosoundmanager.cpp b/LEGO1/lego/legoomni/src/audio/legosoundmanager.cpp index 1d53e64d..d5bd05af 100644 --- a/LEGO1/lego/legoomni/src/audio/legosoundmanager.cpp +++ b/LEGO1/lego/legoomni/src/audio/legosoundmanager.cpp @@ -9,24 +9,28 @@ DECOMP_SIZE_ASSERT(LegoSoundManager, 0x44) // FUNCTION: LEGO1 0x100298a0 +// FUNCTION: BETA10 0x100cffb0 LegoSoundManager::LegoSoundManager() { Init(); } // FUNCTION: LEGO1 0x10029940 +// FUNCTION: BETA10 0x100d0027 LegoSoundManager::~LegoSoundManager() { Destroy(TRUE); } // FUNCTION: LEGO1 0x100299a0 +// FUNCTION: BETA10 0x100d0099 void LegoSoundManager::Init() { m_cacheSoundManager = NULL; } // FUNCTION: LEGO1 0x100299b0 +// FUNCTION: BETA10 0x100d00c9 void LegoSoundManager::Destroy(MxBool p_fromDestructor) { delete m_cacheSoundManager; @@ -41,17 +45,19 @@ void LegoSoundManager::Destroy(MxBool p_fromDestructor) // FUNCTION: BETA10 0x100d0129 MxResult LegoSoundManager::Create(MxU32 p_frequencyMS, MxBool p_createThread) { - MxBool locked = FALSE; MxResult result = FAILURE; + MxBool locked = FALSE; - if (MxSoundManager::Create(10, FALSE) == SUCCESS) { - m_criticalSection.Enter(); - locked = TRUE; - m_cacheSoundManager = new LegoCacheSoundManager; - assert(m_cacheSoundManager); - result = SUCCESS; + if (MxSoundManager::Create(10, FALSE) != SUCCESS) { + goto done; } + ENTER(m_criticalSection); + locked = TRUE; + m_cacheSoundManager = new LegoCacheSoundManager; + assert(m_cacheSoundManager); + result = SUCCESS; + done: if (result != SUCCESS) { Destroy(); diff --git a/LEGO1/lego/legoomni/src/build/legocarbuild.cpp b/LEGO1/lego/legoomni/src/build/legocarbuild.cpp index e69415f6..ab456f39 100644 --- a/LEGO1/lego/legoomni/src/build/legocarbuild.cpp +++ b/LEGO1/lego/legoomni/src/build/legocarbuild.cpp @@ -96,9 +96,9 @@ MxS16 LegoCarBuild::g_unk0x100f11cc = -1; LegoCarBuild::LegoCarBuild() { m_unk0x100 = 0; - m_unk0x110 = 0; + m_selectedPart = 0; m_unk0xf8 = c_unknownminusone; - m_unk0x2d4 = FALSE; + m_selectedPartIsPlaced = FALSE; m_animPresenter = NULL; m_ColorBook_Bitmap = NULL; m_Yellow_Ctl = NULL; @@ -138,7 +138,7 @@ LegoCarBuild::LegoCarBuild() LegoCarBuild::~LegoCarBuild() { m_unk0x100 = 0; - m_unk0x110 = NULL; + m_selectedPart = NULL; if (m_animPresenter) { m_animPresenter->SetShelfState(LegoCarBuildAnimPresenter::e_selected); @@ -291,7 +291,7 @@ void LegoCarBuild::InitPresenters() // FUNCTION: LEGO1 0x10022f00 void LegoCarBuild::FUN_10022f00() { - if (m_unk0x110) { + if (m_selectedPart) { VTable0x6c(); m_animPresenter->SetShelfState(LegoCarBuildAnimPresenter::e_selected); m_unk0x100 = 5; @@ -302,18 +302,18 @@ void LegoCarBuild::FUN_10022f00() // FUNCTION: BETA10 0x1006b835 void LegoCarBuild::FUN_10022f30() { - if (m_unk0x110) { + if (m_selectedPart) { FUN_10024f70(FALSE); FUN_100250e0(FALSE); - if (m_animPresenter->PartIsPlaced(m_unk0x110->GetName())) { + if (m_animPresenter->PartIsPlaced(m_selectedPart->GetName())) { m_PlaceBrick_Sound->Enable(FALSE); m_PlaceBrick_Sound->Enable(TRUE); } m_animPresenter->SetShelfState(LegoCarBuildAnimPresenter::e_stopped); m_animPresenter->PutFrame(); - m_unk0x110 = NULL; + m_selectedPart = NULL; m_unk0x100 = 0; } } @@ -323,8 +323,8 @@ void LegoCarBuild::FUN_10022f30() void LegoCarBuild::VTable0x6c() { m_unk0x178 = m_unk0x1c0; - m_unk0x110->WrappedSetLocal2WorldWithWorldDataUpdate(m_unk0x178); - m_unk0x2a4 = Vector4(m_unk0x110->GetWorldPosition()); + m_selectedPart->WrappedSetLocal2WorldWithWorldDataUpdate(m_unk0x178); + m_unk0x2a4 = Vector4(m_selectedPart->GetWorldPosition()); VTable0x70(); } @@ -363,7 +363,7 @@ void LegoCarBuild::VTable0x70() // FUNCTION: BETA10 0x1006bb22 void LegoCarBuild::FUN_10023130(MxLong p_x, MxLong p_y) { - if (m_unk0x110) { + if (m_selectedPart) { MxFloat pfVar3[2]; MxFloat local30[3]; MxFloat local84[3]; @@ -374,7 +374,7 @@ void LegoCarBuild::FUN_10023130(MxLong p_x, MxLong p_y) pfVar3[0] = p_x; pfVar3[1] = p_y; - if (FUN_1003ded0(pfVar3, local30, local84)) { + if (CalculateRayOriginDirection(pfVar3, local30, local84)) { MxFloat local18[3]; MxFloat local8c[2]; @@ -411,7 +411,7 @@ void LegoCarBuild::FUN_10023130(MxLong p_x, MxLong p_y) local78[3][2] = m_unk0x178[3][2] + local18[2]; local78[3][3] = 1.0; - m_unk0x110->WrappedSetLocal2WorldWithWorldDataUpdate(local78); + m_selectedPart->WrappedSetLocal2WorldWithWorldDataUpdate(local78); } } } @@ -424,7 +424,7 @@ void LegoCarBuild::VTable0x74(MxFloat p_param1[2], MxFloat p_param2[3]) MxFloat local20[3]; MxFloat local14[3]; - FUN_1003ded0(p_param1, local14, local20); + CalculateRayOriginDirection(p_param1, local14, local20); fVar1 = (m_unk0x2a4[2] - local20[2]) / local14[2]; p_param2[0] = (fVar1 * local14[0] + local20[0]) - m_unk0x2a4[0]; @@ -440,7 +440,7 @@ void LegoCarBuild::VTable0x78(MxFloat p_param1[2], MxFloat p_param2[3]) MxFloat local18[3]; MxFloat localc[3]; - FUN_1003ded0(p_param1, local18, localc); + CalculateRayOriginDirection(p_param1, local18, localc); p_param2[2] = m_unk0x2a4[2] + (m_unk0x2bc[2] - m_unk0x2a4[2]) * ((p_param1[1] - m_unk0x290[1]) / (m_unk0x298[1] - m_unk0x290[1])); @@ -456,7 +456,7 @@ void LegoCarBuild::VTable0x7c(MxFloat p_param1[2], MxFloat p_param2[3]) { MxFloat local18[3]; MxFloat localc[3]; - FUN_1003ded0(p_param1, local18, localc); + CalculateRayOriginDirection(p_param1, local18, localc); MxFloat fVar1 = (m_unk0x2bc[1] - localc[1]) / local18[1]; p_param2[0] = fVar1 * local18[0] - m_unk0x2a4[0] + localc[0]; @@ -477,18 +477,18 @@ void LegoCarBuild::VTable0x80(MxFloat p_param1[2], MxFloat p_param2[2], MxFloat // FUNCTION: LEGO1 0x100236d0 // FUNCTION: BETA10 0x1006c076 -void LegoCarBuild::FUN_100236d0() +void LegoCarBuild::AddSelectedPartToBuild() { MxS32 pLVar2; FUN_10024f70(FALSE); FUN_100250e0(FALSE); - m_animPresenter->FUN_10079790(m_unk0x110->GetName()); + m_animPresenter->AddPartToBuildByName(m_selectedPart->GetName()); m_animPresenter->SetShelfState(LegoCarBuildAnimPresenter::e_stopped); - m_unk0x110 = NULL; + m_selectedPart = NULL; m_unk0x100 = 0; - if (m_animPresenter->AllPartsPlaced()) { + if (m_animPresenter->AllPartsPlaced() && !Lego()->IsVersion10()) { // Note the code duplication with LEGO1 0x10025ee0 switch (m_carId) { case 1: @@ -544,15 +544,15 @@ MxResult LegoCarBuild::Tickle() FUN_10024f50(); } - if (m_unk0x110) { - if (m_animPresenter->PartIsPlaced(m_unk0x110->GetName())) { + if (m_selectedPart) { + if (m_animPresenter->PartIsPlaced(m_selectedPart->GetName())) { FUN_10022f30(); } } } - if (m_unk0x100 == 5 && m_unk0x110) { - RotateY(m_unk0x110, g_unk0x100d65a4); + if (m_unk0x100 == 5 && m_selectedPart) { + RotateY(m_selectedPart, g_unk0x100d65a4); } if (m_unk0x10a) { @@ -690,7 +690,7 @@ MxLong LegoCarBuild::Notify(MxParam& p_param) if (((m_buildState->m_animationState != 4) && (m_buildState->m_animationState != 6)) && (m_buildState->m_animationState != 2)) { m_buildState->m_animationState = LegoVehicleBuildState::e_unknown0; - result = FUN_100244e0( + result = SelectPartFromMousePosition( ((LegoEventNotificationParam&) p_param).GetX(), ((LegoEventNotificationParam&) p_param).GetY() ); @@ -820,7 +820,7 @@ undefined4 LegoCarBuild::FUN_10024480(MxActionNotificationParam* p_param) // FUNCTION: LEGO1 0x100244e0 // FUNCTION: BETA10 0x1006cfb6 -undefined4 LegoCarBuild::FUN_100244e0(MxLong p_x, MxLong p_y) +undefined4 LegoCarBuild::SelectPartFromMousePosition(MxLong p_x, MxLong p_y) { m_unk0x250[0] = p_x; m_unk0x250[1] = p_y; @@ -831,34 +831,34 @@ undefined4 LegoCarBuild::FUN_100244e0(MxLong p_x, MxLong p_y) return 0; } - if (m_unk0x110 != roi) { + if (m_selectedPart != roi) { FUN_10022f30(); - m_unk0x110 = roi; + m_selectedPart = roi; FUN_10024f70(TRUE); FUN_100250e0(TRUE); } - if (m_unk0x100 == 5 && m_animPresenter->PartIsPlaced(m_unk0x110->GetName())) { - m_unk0x2d4 = TRUE; + if (m_unk0x100 == 5 && m_animPresenter->PartIsPlaced(m_selectedPart->GetName())) { + m_selectedPartIsPlaced = TRUE; } else { - m_unk0x2d4 = FALSE; + m_selectedPartIsPlaced = FALSE; } FUN_10025450(); VTable0x70(); - if (m_animPresenter->PartIsPlaced(m_unk0x110->GetName())) { + if (m_animPresenter->PartIsPlaced(m_selectedPart->GetName())) { if (m_unk0x100 != 5) { m_unk0x250[0] += m_unk0x290[0] - m_unk0x298[0]; m_unk0x250[1] += m_unk0x290[1] - m_unk0x298[1]; } if (m_unk0x100 == 0) { - m_unk0x114 = m_unk0x110->GetWorldBoundingSphere(); + m_unk0x114 = m_selectedPart->GetWorldBoundingSphere(); } } else { - if (m_animPresenter->FUN_10079c30(m_unk0x110->GetName())) { + if (m_animPresenter->FUN_10079c30(m_selectedPart->GetName())) { m_unk0x114 = m_animPresenter->FUN_10079e20(); } } @@ -895,21 +895,21 @@ undefined4 LegoCarBuild::FUN_100246e0(MxLong p_x, MxLong p_y) result = 1; break; case 6: - if (m_animPresenter->PartIsPlaced(m_unk0x110->GetName()) && - SpheresIntersect(m_unk0x114, m_unk0x110->GetWorldBoundingSphere())) { + if (m_animPresenter->PartIsPlaced(m_selectedPart->GetName()) && + SpheresIntersect(m_unk0x114, m_selectedPart->GetWorldBoundingSphere())) { FUN_10024f70(FALSE); FUN_100250e0(FALSE); m_unk0x100 = 0; - m_unk0x110 = NULL; + m_selectedPart = NULL; m_PlaceBrick_Sound->Enable(FALSE); m_PlaceBrick_Sound->Enable(TRUE); m_animPresenter->SetShelfState(LegoCarBuildAnimPresenter::e_stopped); } - else if (m_animPresenter->FUN_10079c30(m_unk0x110->GetName())) { - if (SpheresIntersect(m_unk0x114, m_unk0x110->GetWorldBoundingSphere())) { + else if (m_animPresenter->FUN_10079c30(m_selectedPart->GetName())) { + if (SpheresIntersect(m_unk0x114, m_selectedPart->GetWorldBoundingSphere())) { m_PlaceBrick_Sound->Enable(FALSE); m_PlaceBrick_Sound->Enable(TRUE); - FUN_100236d0(); + AddSelectedPartToBuild(); } else { VTable0x6c(); @@ -956,7 +956,7 @@ undefined4 LegoCarBuild::FUN_10024890(MxParam* p_param) LegoControlManagerNotificationParam* param = (LegoControlManagerNotificationParam*) p_param; assert(m_buildState); - if (param->m_unk0x28) { + if (param->m_enabledChild) { switch (param->m_clickedObjectId) { // The enum values are all identical between CopterScript, DunecarScript, JetskiScript, and RacecarScript case CopterScript::c_Info_Ctl: @@ -1012,7 +1012,7 @@ undefined4 LegoCarBuild::FUN_10024890(MxParam* p_param) case CopterScript::c_Platform_Ctl: FUN_10024f50(); m_unk0xf8 = c_unknown8; - m_unk0xfc = param->m_unk0x28; + m_unk0xfc = param->m_enabledChild; result = 1; break; default: @@ -1024,7 +1024,7 @@ undefined4 LegoCarBuild::FUN_10024890(MxParam* p_param) (m_Decals_Ctl5 && m_Decals_Ctl5->GetAction()->GetObjectId() == param->m_clickedObjectId) || (m_Decals_Ctl6 && m_Decals_Ctl6->GetAction()->GetObjectId() == param->m_clickedObjectId) || (m_Decals_Ctl7 && m_Decals_Ctl7->GetAction()->GetObjectId() == param->m_clickedObjectId)) { - m_animPresenter->SetPartObjectIdByName(m_unk0x110->GetName(), param->m_clickedObjectId); + m_animPresenter->SetPartObjectIdByName(m_selectedPart->GetName(), param->m_clickedObjectId); m_Decal_Sound->Enable(FALSE); m_Decal_Sound->Enable(TRUE); } @@ -1054,7 +1054,7 @@ undefined4 LegoCarBuild::FUN_10024890(MxParam* p_param) LegoControlManagerNotificationParam* param = (LegoControlManagerNotificationParam*) p_param; assert(m_buildState); - if (param->m_unk0x28) { + if (param->m_enabledChild) { switch (param->m_clickedObjectId) { case CopterScript::c_Info_Ctl: m_animPresenter->SetShelfState(LegoCarBuildAnimPresenter::e_selected); @@ -1116,7 +1116,7 @@ undefined4 LegoCarBuild::FUN_10024890(MxParam* p_param) case CopterScript::c_Platform_Ctl: FUN_10024f50(); m_unk0xf8 = c_unknown8; - m_unk0xfc = param->m_unk0x28; + m_unk0xfc = param->m_enabledChild; result = 1; break; default: @@ -1128,7 +1128,7 @@ undefined4 LegoCarBuild::FUN_10024890(MxParam* p_param) (m_Decals_Ctl5 && m_Decals_Ctl5->GetAction()->GetObjectId() == param->m_clickedObjectId) || (m_Decals_Ctl6 && m_Decals_Ctl6->GetAction()->GetObjectId() == param->m_clickedObjectId) || (m_Decals_Ctl7 && m_Decals_Ctl7->GetAction()->GetObjectId() == param->m_clickedObjectId)) { - m_animPresenter->SetPartObjectIdByName(m_unk0x110->GetName(), param->m_clickedObjectId); + m_animPresenter->SetPartObjectIdByName(m_selectedPart->GetName(), param->m_clickedObjectId); m_Decal_Sound->Enable(FALSE); m_Decal_Sound->Enable(TRUE); } @@ -1233,7 +1233,7 @@ undefined4 LegoCarBuild::FUN_10024c20(MxNotificationParam* p_param) jukeboxScript = JukeboxScript::c_RaceCarBuild_Music; } - m_unk0x338 = SoundManager()->FUN_100aebd0(*g_jukeboxScript, jukeboxScript); + m_unk0x338 = SoundManager()->FindPresenter(*g_jukeboxScript, jukeboxScript); if (m_unk0x338) { BackgroundAudioManager()->SetPendingPresenter(m_unk0x338, 5, MxPresenter::e_repeating); @@ -1252,11 +1252,11 @@ undefined4 LegoCarBuild::FUN_10024c20(MxNotificationParam* p_param) // FUNCTION: LEGO1 0x10024ef0 void LegoCarBuild::FUN_10024ef0() { - FUN_1003eda0(); + ResetViewVelocity(); m_buildState->m_animationState = LegoVehicleBuildState::e_cutscene; FUN_10025720(FUN_10025d70()); m_buildState->m_unk0x4c += 1; - FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + Disable(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); } // FUNCTION: LEGO1 0x10024f30 @@ -1271,7 +1271,7 @@ void LegoCarBuild::FUN_10024f30() // FUNCTION: BETA10 0x1006dfce void LegoCarBuild::FUN_10024f50() { - m_unk0x2d4 = FALSE; + m_selectedPartIsPlaced = FALSE; m_animPresenter->RotateAroundYAxis(g_rotationAngleStepYAxis); } @@ -1279,7 +1279,7 @@ void LegoCarBuild::FUN_10024f50() // FUNCTION: BETA10 0x1006e002 void LegoCarBuild::FUN_10024f70(MxBool p_enabled) { - if (m_animPresenter->StringEndsOnY(m_unk0x110->GetName())) { + if (m_animPresenter->StringEndsOnY(m_selectedPart->GetName())) { SetPresentersEnabled(p_enabled); } } @@ -1314,31 +1314,31 @@ void LegoCarBuild::TogglePresentersEnabled() // FUNCTION: BETA10 0x1006e124 void LegoCarBuild::FUN_100250e0(MxBool p_enabled) { - if (m_animPresenter->StringDoesNotEndOnZero(m_unk0x110->GetName()) && m_Decals_Ctl) { - if (SDL_strncasecmp(m_unk0x110->GetName(), "JSFRNT", strlen("JSFRNT")) == 0) { + if (m_animPresenter->StringDoesNotEndOnZero(m_selectedPart->GetName()) && m_Decals_Ctl) { + if (SDL_strncasecmp(m_selectedPart->GetName(), "JSFRNT", strlen("JSFRNT")) == 0) { m_Decal_Bitmap->Enable(p_enabled); m_Decals_Ctl->Enable(p_enabled); m_Decals_Ctl1->Enable(p_enabled); m_Decals_Ctl2->Enable(p_enabled); m_Decals_Ctl3->Enable(p_enabled); } - else if (SDL_strncasecmp(m_unk0x110->GetName(), "JSWNSH", strlen("JSWNSH")) == 0) { + else if (SDL_strncasecmp(m_selectedPart->GetName(), "JSWNSH", strlen("JSWNSH")) == 0) { m_Decal_Bitmap->Enable(p_enabled); m_Decals_Ctl4->Enable(p_enabled); m_Decals_Ctl5->Enable(p_enabled); m_Decals_Ctl6->Enable(p_enabled); m_Decals_Ctl7->Enable(p_enabled); } - else if (SDL_strncasecmp(m_unk0x110->GetName(), "RCBACK", strlen("RCBACK")) == 0) { + else if (SDL_strncasecmp(m_selectedPart->GetName(), "RCBACK", strlen("RCBACK")) == 0) { m_Decals_Ctl1->Enable(p_enabled); } - else if (SDL_strncasecmp(m_unk0x110->GetName(), "RCTAIL", strlen("RCTAIL")) == 0) { + else if (SDL_strncasecmp(m_selectedPart->GetName(), "RCTAIL", strlen("RCTAIL")) == 0) { m_Decals_Ctl2->Enable(p_enabled); } - else if (m_Decals_Ctl1 && SDL_strncasecmp(m_unk0x110->GetName(), "chljety", strlen("chljety")) == 0) { + else if (m_Decals_Ctl1 && SDL_strncasecmp(m_selectedPart->GetName(), "chljety", strlen("chljety")) == 0) { m_Decals_Ctl1->Enable(p_enabled); } - else if (m_Decals_Ctl2 && SDL_strncasecmp(m_unk0x110->GetName(), "chrjety", strlen("chrjety")) == 0) { + else if (m_Decals_Ctl2 && SDL_strncasecmp(m_selectedPart->GetName(), "chrjety", strlen("chrjety")) == 0) { m_Decals_Ctl2->Enable(p_enabled); } else if (m_Decals_Ctl) { @@ -1354,7 +1354,7 @@ void LegoCarBuild::FUN_10025350(MxS32 p_objectId) const LegoChar* color; LegoChar buffer[256]; - if (!m_unk0x110) { + if (!m_selectedPart) { return; } @@ -1382,8 +1382,8 @@ void LegoCarBuild::FUN_10025350(MxS32 p_objectId) m_Paint_Sound->Enable(FALSE); m_Paint_Sound->Enable(TRUE); - m_unk0x110->FUN_100a93b0(color); - sprintf(buffer, "c_%s", m_unk0x110->GetName()); + m_selectedPart->FUN_100a93b0(color); + sprintf(buffer, "c_%s", m_selectedPart->GetName()); VariableTable()->SetVariable(buffer, color); } @@ -1391,7 +1391,7 @@ void LegoCarBuild::FUN_10025350(MxS32 p_objectId) // FUNCTION: BETA10 0x1006e599 void LegoCarBuild::FUN_10025450() { - m_unk0x12c = m_unk0x110->GetLocal2World(); + m_unk0x12c = m_selectedPart->GetLocal2World(); m_unk0x1c0 = m_unk0x12c; Vector3 lastColumnOfUnk0x1c0(m_unk0x1c0[3]); @@ -1404,10 +1404,10 @@ void LegoCarBuild::FUN_10025450() MxMatrix* unk0x178 = &m_unk0x178; *unk0x178 = m_unk0x12c; - if (m_animPresenter->PartIsPlaced(m_unk0x110->GetName())) { - m_unk0x2a4 = Vector4(m_unk0x110->GetWorldPosition()); + if (m_animPresenter->PartIsPlaced(m_selectedPart->GetName())) { + m_unk0x2a4 = Vector4(m_selectedPart->GetWorldPosition()); - if (!m_unk0x2d4) { + if (!m_selectedPartIsPlaced) { m_unk0x2bc = m_unk0x2a4; m_unk0x208 = m_unk0x12c; @@ -1421,17 +1421,17 @@ void LegoCarBuild::FUN_10025450() else { const LegoChar* wiredName; - if (!m_animPresenter->FUN_10079c30(m_unk0x110->GetName())) { - wiredName = m_animPresenter->GetWiredNameByPartName(m_unk0x110->GetName()); + if (!m_animPresenter->FUN_10079c30(m_selectedPart->GetName())) { + wiredName = m_animPresenter->GetWiredNameByPartName(m_selectedPart->GetName()); } else { wiredName = m_animPresenter->GetWiredNameOfLastPlacedPart(); } - LegoROI* parentROI = (LegoROI*) m_unk0x110->GetParentROI(); + LegoROI* parentROI = (LegoROI*) m_selectedPart->GetParentROI(); m_unk0x208 = parentROI->FindChildROI(wiredName, parentROI)->GetLocal2World(); m_unk0x2bc = Vector4(parentROI->FindChildROI(wiredName, parentROI)->GetWorldPosition()); - m_unk0x2a4 = Vector4(m_unk0x110->GetWorldPosition()); + m_unk0x2a4 = Vector4(m_selectedPart->GetWorldPosition()); m_unk0x2a4[2] += (m_unk0x1c0[3][2] - m_unk0x12c[3][2]); m_unk0x178[3][2] = m_unk0x1c0[3][2]; @@ -1653,8 +1653,8 @@ void LegoCarBuild::FUN_10025db0(const char* p_param1, undefined4 p_param2) } } else { - if (m_unk0x33c->GetUnknown0x4e() != sVar3) { - m_unk0x33c->VTable0x6c(sVar3); + if (m_unk0x33c->GetEnabledChild() != sVar3) { + m_unk0x33c->UpdateEnabledChild(sVar3); } g_unk0x100f11cc = -1; @@ -1667,7 +1667,7 @@ void LegoCarBuild::FUN_10025e40() { SetPresentersEnabled(m_presentersEnabled); if (m_unk0x33c && m_Yellow_Ctl != m_unk0x33c) { - m_unk0x33c->VTable0x6c(0); + m_unk0x33c->UpdateEnabledChild(0); } } diff --git a/LEGO1/lego/legoomni/src/build/legocarbuildpresenter.cpp b/LEGO1/lego/legoomni/src/build/legocarbuildpresenter.cpp index a76987dd..a3adac06 100644 --- a/LEGO1/lego/legoomni/src/build/legocarbuildpresenter.cpp +++ b/LEGO1/lego/legoomni/src/build/legocarbuildpresenter.cpp @@ -204,15 +204,15 @@ void LegoCarBuildAnimPresenter::StreamingTickle() for (i = 0; i < m_numberOfParts; i++) { if (m_placedPartCount == i) { - FUN_10079680(m_parts[i].m_wiredName); + ShowBuildPartByName(m_parts[i].m_wiredName); } else { - FUN_100795d0(m_parts[i].m_wiredName); + HideBuildPartByName(m_parts[i].m_wiredName); } if (i < m_placedPartCount) { FUN_10079050(i); - FUN_10079680(m_parts[i].m_name); + ShowBuildPartByName(m_parts[i].m_name); } LegoChar* name = m_parts[i].m_wiredName; @@ -321,7 +321,7 @@ MxResult LegoCarBuildAnimPresenter::Serialize(LegoStorage* p_storage) void LegoCarBuildAnimPresenter::FUN_10079050(MxS16 p_index) { SwapNodesByName(m_parts[p_index].m_wiredName, m_parts[p_index].m_name); - FUN_100795d0(m_parts[p_index].m_wiredName); + HideBuildPartByName(m_parts[p_index].m_wiredName); } // FUNCTION: LEGO1 0x10079090 @@ -447,7 +447,7 @@ void LegoCarBuildAnimPresenter::InitBuildPlatform() // FUNCTION: LEGO1 0x100795d0 // FUNCTION: BETA10 0x10071d96 -void LegoCarBuildAnimPresenter::FUN_100795d0(LegoChar* p_param) +void LegoCarBuildAnimPresenter::HideBuildPartByName(LegoChar* p_param) { LegoAnimNodeData* data = FindNodeDataByName(m_anim->GetRoot(), p_param); @@ -469,7 +469,7 @@ void LegoCarBuildAnimPresenter::FUN_100795d0(LegoChar* p_param) // FUNCTION: LEGO1 0x10079680 // FUNCTION: BETA10 0x10071ec5 -void LegoCarBuildAnimPresenter::FUN_10079680(LegoChar* p_param) +void LegoCarBuildAnimPresenter::ShowBuildPartByName(LegoChar* p_param) { LegoAnimNodeData* data = FindNodeDataByName(m_anim->GetRoot(), p_param); @@ -536,7 +536,7 @@ LegoTreeNode* LegoCarBuildAnimPresenter::FindNodeByName(LegoTreeNode* p_treeNode // FUNCTION: LEGO1 0x10079790 // FUNCTION: BETA10 0x100720a3 -void LegoCarBuildAnimPresenter::FUN_10079790(const LegoChar* p_name) +void LegoCarBuildAnimPresenter::AddPartToBuildByName(const LegoChar* p_name) { MxS16 i; LegoChar buffer[40]; @@ -559,7 +559,7 @@ void LegoCarBuildAnimPresenter::FUN_10079790(const LegoChar* p_name) ((LegoCarBuild*) m_currentWorld)->SetPlacedPartCount(m_placedPartCount); if (m_placedPartCount < m_numberOfParts) { - FUN_10079680(m_parts[m_placedPartCount].m_wiredName); + ShowBuildPartByName(m_parts[m_placedPartCount].m_wiredName); } } diff --git a/LEGO1/lego/legoomni/src/common/legoanimationmanager.cpp b/LEGO1/lego/legoomni/src/common/legoanimationmanager.cpp index 665c6459..330b4179 100644 --- a/LEGO1/lego/legoomni/src/common/legoanimationmanager.cpp +++ b/LEGO1/lego/legoomni/src/common/legoanimationmanager.cpp @@ -11,7 +11,6 @@ #include "legoentitylist.h" #include "legoextraactor.h" #include "legogamestate.h" -#include "legolocomotionanimpresenter.h" #include "legomain.h" #include "legonavcontroller.h" #include "legoroilist.h" @@ -20,6 +19,7 @@ #include "legoworld.h" #include "misc.h" #include "mxbackgroundaudiomanager.h" +#include "mxdebug.h" #include "mxmisc.h" #include "mxnotificationmanager.h" #include "mxticklemanager.h" @@ -1021,7 +1021,7 @@ MxResult LegoAnimationManager::FUN_100605e0( action.SetUnknown24(-1); action.AppendExtra(strlen(buf) + 1, buf); - if (StartActionIfUnknown0x13c(action) == SUCCESS) { + if (StartActionIfInitialized(action) == SUCCESS) { BackgroundAudioManager()->LowerVolume(); tranInfo->m_flags |= LegoTranInfo::c_bit2; animInfo.m_unk0x22++; @@ -1088,7 +1088,7 @@ MxResult LegoAnimationManager::FUN_100609f0(MxU32 p_objectId, MxMatrix* p_matrix action.SetUnknown24(-1); action.AppendExtra(strlen(buf) + 1, buf); - if (StartActionIfUnknown0x13c(action) == SUCCESS) { + if (StartActionIfInitialized(action) == SUCCESS) { BackgroundAudioManager()->LowerVolume(); info->m_flags |= LegoTranInfo::c_bit2; m_animRunning = TRUE; @@ -1131,7 +1131,7 @@ MxResult LegoAnimationManager::StartEntityAction(MxDSAction& p_dsAction, LegoEnt } } - if (LegoOmni::GetInstance()->StartActionIfUnknown0x13c(p_dsAction) == SUCCESS) { + if (LegoOmni::GetInstance()->StartActionIfInitialized(p_dsAction) == SUCCESS) { result = SUCCESS; } @@ -1155,7 +1155,7 @@ MxResult LegoAnimationManager::FUN_10060dc0( MxResult result = FAILURE; MxBool found = FALSE; - if (!Lego()->m_unk0x13c) { + if (!Lego()->m_initialized) { return SUCCESS; } @@ -1192,7 +1192,7 @@ MxResult LegoAnimationManager::FUN_10060dc0( // FUNCTION: BETA10 0x1004206c void LegoAnimationManager::CameraTriggerFire(LegoPathActor* p_actor, MxBool, MxU32 p_location, MxBool p_bool) { - if (Lego()->m_unk0x13c && m_enableCamAnims && !m_animRunning) { + if (Lego()->m_initialized && m_enableCamAnims && !m_animRunning) { LegoLocation* location = LegoNavController::GetLocation(p_location); if (location != NULL) { @@ -1231,12 +1231,10 @@ void LegoAnimationManager::CameraTriggerFire(LegoPathActor* p_actor, MxBool, MxU } } -// FUNCTION: LEGO1 0x10061010 +#ifdef BETA10 // FUNCTION: BETA10 0x100422cc void LegoAnimationManager::FUN_10061010(MxBool p_und) { - MxBool unk0x39 = FALSE; - FUN_10064b50(-1); if (m_tranInfoList != NULL) { @@ -1244,17 +1242,47 @@ void LegoAnimationManager::FUN_10061010(MxBool p_und) LegoTranInfo* tranInfo; while (cursor.Next(tranInfo)) { - if (tranInfo->m_presenter != NULL) { - // TODO: Match - MxU32 flags = tranInfo->m_flags; + if (tranInfo->m_unk0x14 && tranInfo->m_location != -1) { + MxTrace("Releasing user from %d\n", tranInfo->m_objectId); + if (tranInfo->m_presenter != NULL) { + tranInfo->m_presenter->FUN_1004b8c0(); + } + + tranInfo->m_unk0x14 = FALSE; + } + else { + MxTrace("Stopping %d\n", tranInfo->m_objectId); + + if (tranInfo->m_presenter != NULL) { + tranInfo->m_presenter->FUN_1004b840(); + } + } + } + } + + m_animRunning = FALSE; + m_unk0x404 = Timer()->GetTime(); +} +#else +// FUNCTION: LEGO1 0x10061010 +void LegoAnimationManager::FUN_10061010(MxBool p_und) +{ + MxBool animRunning = FALSE; + FUN_10064b50(-1); + + if (m_tranInfoList != NULL) { + LegoTranInfoListCursor cursor(m_tranInfoList); + LegoTranInfo* tranInfo; + + while (cursor.Next(tranInfo)) { + if (tranInfo->m_presenter) { + // LINE: LEGO1 0x100610e6 if (tranInfo->m_unk0x14 && tranInfo->m_location != -1 && p_und) { - LegoAnim* anim; - - if (tranInfo->m_presenter->GetPresenter() != NULL && - (anim = tranInfo->m_presenter->GetPresenter()->GetAnimation()) != NULL && - anim->GetCamAnim() != NULL) { - if (flags & LegoTranInfo::c_bit2) { + if (tranInfo->m_presenter->GetPresenter() && + tranInfo->m_presenter->GetPresenter()->GetAnimation() && + tranInfo->m_presenter->GetPresenter()->GetAnimation()->GetCamAnim()) { + if (tranInfo->m_flags & LegoTranInfo::c_bit2) { BackgroundAudioManager()->RaiseVolume(); tranInfo->m_flags &= ~LegoTranInfo::c_bit2; } @@ -1263,37 +1291,43 @@ void LegoAnimationManager::FUN_10061010(MxBool p_und) tranInfo->m_unk0x14 = FALSE; } else { + MxTrace("Releasing user from %d\n", tranInfo->m_objectId); + // LINE: LEGO1 0x10061137 tranInfo->m_presenter->FUN_1004b8c0(); + animRunning = TRUE; tranInfo->m_unk0x14 = FALSE; - unk0x39 = TRUE; } } else { - if (flags & LegoTranInfo::c_bit2) { + if (tranInfo->m_flags & LegoTranInfo::c_bit2) { + // LINE: LEGO1 0x10061150 BackgroundAudioManager()->RaiseVolume(); tranInfo->m_flags &= ~LegoTranInfo::c_bit2; } + MxTrace("Stopping %d\n", tranInfo->m_objectId); tranInfo->m_presenter->FUN_1004b840(); } } else { if (m_tranInfoList2 != NULL) { LegoTranInfoListCursor cursor(m_tranInfoList2); - if (!cursor.Find(tranInfo)) { + // TODO: For some reason, the embedded `MxListEntry` constructor is not inlined. + // This may be the key for getting this function to match correctly. m_tranInfoList2->Append(tranInfo); } } - unk0x39 = TRUE; + animRunning = TRUE; } } } - m_animRunning = unk0x39; + m_animRunning = animRunning; m_unk0x404 = Timer()->GetTime(); } +#endif // FUNCTION: LEGO1 0x10061530 void LegoAnimationManager::FUN_10061530() diff --git a/LEGO1/lego/legoomni/src/common/legoanimmmpresenter.cpp b/LEGO1/lego/legoomni/src/common/legoanimmmpresenter.cpp index dfa55d51..af32a238 100644 --- a/LEGO1/lego/legoomni/src/common/legoanimmmpresenter.cpp +++ b/LEGO1/lego/legoomni/src/common/legoanimmmpresenter.cpp @@ -400,7 +400,7 @@ MxBool LegoAnimMMPresenter::FUN_1004b610(MxLong p_time) } } - m_action->SetUnknown90(Timer()->GetTime()); + m_action->SetTimeStarted(Timer()->GetTime()); if (m_compositePresenter != NULL) { m_compositePresenter->VTable0x60(this); @@ -425,6 +425,21 @@ MxBool LegoAnimMMPresenter::FUN_1004b6b0(MxLong p_time) // FUNCTION: BETA10 0x1004ce18 MxBool LegoAnimMMPresenter::FUN_1004b6d0(MxLong p_time) { +#ifdef BETA10 + switch (m_unk0x58) { + case 0: + break; + case 1: + break; + case 2: + break; + case 3: + break; + case 4: + break; + } +#endif + LegoROI* viewROI = VideoManager()->GetViewROI(); LegoPathActor* actor = UserActor(); @@ -455,9 +470,13 @@ MxBool LegoAnimMMPresenter::FUN_1004b6d0(MxLong p_time) m_world->PlaceActor(actor); } +#ifdef BETA10 + actor->VTable0xa8(); +#else if (m_tranInfo->m_unk0x29) { actor->VTable0xa8(); } +#endif } actor->SetActorState(LegoPathActor::c_initial); @@ -491,9 +510,11 @@ void LegoAnimMMPresenter::FUN_1004b840() FUN_1004b6d0(0); EndAction(); +#ifndef BETA10 if (action != NULL) { Streamer()->FUN_100b98f0(action); } +#endif } // FUNCTION: LEGO1 0x1004b8b0 diff --git a/LEGO1/lego/legoomni/src/common/legobuildingmanager.cpp b/LEGO1/lego/legoomni/src/common/legobuildingmanager.cpp index d46b8a49..8dae5d61 100644 --- a/LEGO1/lego/legoomni/src/common/legobuildingmanager.cpp +++ b/LEGO1/lego/legoomni/src/common/legobuildingmanager.cpp @@ -199,10 +199,10 @@ LegoBuildingInfo g_buildingInfoInit[16] = { MxU32 LegoBuildingManager::g_maxSound = 6; // GLOBAL: LEGO1 0x100f373c -MxU32 g_unk0x100f373c = 0x3c; +MxU32 g_buildingSoundIdOffset = 0x3c; // GLOBAL: LEGO1 0x100f3740 -MxU32 g_unk0x100f3740 = 0x42; +MxU32 g_buildingSoundIdMoodOffset = 0x42; // clang-format off // GLOBAL: LEGO1 0x100f3788 @@ -227,6 +227,8 @@ LegoBuildingInfo g_buildingInfo[16]; // GLOBAL: LEGO1 0x100f3748 MxS32 LegoBuildingManager::g_maxMove[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 0}; +#define HAUS1_INDEX 12 + // FUNCTION: LEGO1 0x1002f8b0 void LegoBuildingManager::configureLegoBuildingManager(MxS32 p_buildingManagerConfig) { @@ -392,6 +394,9 @@ MxResult LegoBuildingManager::Read(LegoStorage* p_storage) m_nextVariant = 0; } + // Bugfix: allow Pepper to change variant building after save game load + g_buildingInfo[HAUS1_INDEX].m_variant = g_buildingInfoVariants[m_nextVariant]; + result = SUCCESS; done: @@ -461,7 +466,7 @@ MxBool LegoBuildingManager::SwitchVariant(LegoEntity* p_entity) roi->SetVisibility(FALSE); info->m_variant = g_buildingInfoVariants[m_nextVariant]; - CreateBuilding(12, CurrentWorld()); + CreateBuilding(HAUS1_INDEX, CurrentWorld()); if (info->m_entity != NULL) { info->m_entity->GetROI()->SetVisibility(TRUE); @@ -548,7 +553,7 @@ MxU32 LegoBuildingManager::GetAnimationId(LegoEntity* p_entity) // FUNCTION: LEGO1 0x1002ff40 // FUNCTION: BETA10 0x10064398 -MxU32 LegoBuildingManager::GetSoundId(LegoEntity* p_entity, MxBool p_state) +MxU32 LegoBuildingManager::GetSoundId(LegoEntity* p_entity, MxBool p_basedOnMood) { LegoBuildingInfo* info = GetInfo(p_entity); @@ -556,12 +561,12 @@ MxU32 LegoBuildingManager::GetSoundId(LegoEntity* p_entity, MxBool p_state) return 0; } - if (p_state) { - return info->m_mood + g_unk0x100f3740; + if (p_basedOnMood) { + return info->m_mood + g_buildingSoundIdMoodOffset; } if (info != NULL) { - return info->m_sound + g_unk0x100f373c; + return info->m_sound + g_buildingSoundIdOffset; } return 0; diff --git a/LEGO1/lego/legoomni/src/common/legocharactermanager.cpp b/LEGO1/lego/legoomni/src/common/legocharactermanager.cpp index 6510dcb3..180b8eec 100644 --- a/LEGO1/lego/legoomni/src/common/legocharactermanager.cpp +++ b/LEGO1/lego/legoomni/src/common/legocharactermanager.cpp @@ -39,10 +39,10 @@ MxU32 g_characterAnimationId = 10; char* LegoCharacterManager::g_customizeAnimFile = NULL; // GLOBAL: LEGO1 0x100fc4d8 -MxU32 g_soundIdOffset = 50; +MxU32 g_characterSoundIdOffset = 50; // GLOBAL: LEGO1 0x100fc4dc -MxU32 g_soundIdMoodOffset = 66; +MxU32 g_characterSoundIdMoodOffset = 66; // GLOBAL: LEGO1 0x100fc4e8 MxU32 g_headTextureCounter = 0; @@ -636,7 +636,7 @@ MxBool LegoCharacterManager::SetHeadTexture(LegoROI* p_roi, LegoTextureInfo* p_t LegoLOD* clone = lod->Clone(renderer); if (p_texture != NULL) { - clone->FUN_100aad70(p_texture); + clone->UpdateTextureInfo(p_texture); } dupLodList->PushBack(clone); @@ -933,16 +933,16 @@ MxU32 LegoCharacterManager::GetAnimationId(LegoROI* p_roi) // FUNCTION: LEGO1 0x10085140 // FUNCTION: BETA10 0x10076855 -MxU32 LegoCharacterManager::GetSoundId(LegoROI* p_roi, MxBool p_und) +MxU32 LegoCharacterManager::GetSoundId(LegoROI* p_roi, MxBool p_basedOnMood) { LegoActorInfo* info = GetActorInfo(p_roi); - if (p_und) { - return info->m_mood + g_soundIdMoodOffset; + if (p_basedOnMood) { + return info->m_mood + g_characterSoundIdMoodOffset; } if (info != NULL) { - return info->m_sound + g_soundIdOffset; + return info->m_sound + g_characterSoundIdOffset; } else { return 0; @@ -1092,6 +1092,7 @@ LegoROI* LegoCharacterManager::FUN_10085a80(const char* p_name, const char* p_lo } // FUNCTION: LEGO1 0x10085aa0 +// FUNCTION: BETA10 0x1007703d CustomizeAnimFileVariable::CustomizeAnimFileVariable(const char* p_key) { m_key = p_key; @@ -1099,6 +1100,7 @@ CustomizeAnimFileVariable::CustomizeAnimFileVariable(const char* p_key) } // FUNCTION: LEGO1 0x10085b50 +// FUNCTION: BETA10 0x100770c8 void CustomizeAnimFileVariable::SetValue(const char* p_value) { // STRING: LEGO1 0x100fc4f4 diff --git a/LEGO1/lego/legoomni/src/common/legogamestate.cpp b/LEGO1/lego/legoomni/src/common/legogamestate.cpp index 93665ee3..6df31604 100644 --- a/LEGO1/lego/legoomni/src/common/legogamestate.cpp +++ b/LEGO1/lego/legoomni/src/common/legogamestate.cpp @@ -866,7 +866,7 @@ void LegoGameState::SwitchArea(Area p_area) m_previousArea = m_currentArea; m_currentArea = p_area; - FUN_10015820(TRUE, LegoOmni::c_disableInput | LegoOmni::c_disable3d); + Disable(TRUE, LegoOmni::c_disableInput | LegoOmni::c_disable3d); BackgroundAudioManager()->Stop(); AnimationManager()->Suspend(); VideoManager()->SetUnk0x554(FALSE); @@ -967,7 +967,7 @@ void LegoGameState::SwitchArea(Area p_area) Act1State* state = (Act1State*) GameState()->GetState("Act1State"); LoadIsle(); - if (state->GetUnknown18() == 7) { + if (state->GetState() == Act1State::e_transitionToTowtrack) { VideoManager()->Get3DManager()->SetFrustrum(90, 0.1f, 250.0f); } else { @@ -1349,6 +1349,11 @@ void LegoBackgroundColor::SetLightColor() SetLightColor(convertedR, convertedG, convertedB); } +// FUNCTION: BETA10 0x10086a87 +LegoFullScreenMovie::LegoFullScreenMovie() +{ +} + // FUNCTION: LEGO1 0x1003c500 // FUNCTION: BETA10 0x10086af6 LegoFullScreenMovie::LegoFullScreenMovie(const char* p_key, const char* p_value) diff --git a/LEGO1/lego/legoomni/src/common/legoobjectfactory.cpp b/LEGO1/lego/legoomni/src/common/legoobjectfactory.cpp index 68a3b35a..b8514020 100644 --- a/LEGO1/lego/legoomni/src/common/legoobjectfactory.cpp +++ b/LEGO1/lego/legoomni/src/common/legoobjectfactory.cpp @@ -10,7 +10,7 @@ #include "legoentity.h" #include "legopathactor.h" // The below header inclusions should be sound. -#include "legoloopinganimpresenter.h" +#include "legoanimpresenter.h" #include "mxcompositemediapresenter.h" #include "legoactorpresenter.h" #include "legomodelpresenter.h" @@ -71,10 +71,7 @@ #include "legoentity.h" #include "legoentitypresenter.h" #include "legoflctexturepresenter.h" -#include "legohideanimpresenter.h" #include "legoloadcachesoundpresenter.h" -#include "legolocomotionanimpresenter.h" -#include "legoloopinganimpresenter.h" #include "legometerpresenter.h" #include "legomodelpresenter.h" #include "legopalettepresenter.h" diff --git a/LEGO1/lego/legoomni/src/common/legoplantmanager.cpp b/LEGO1/lego/legoomni/src/common/legoplantmanager.cpp index 5385a86a..a67f7e08 100644 --- a/LEGO1/lego/legoomni/src/common/legoplantmanager.cpp +++ b/LEGO1/lego/legoomni/src/common/legoplantmanager.cpp @@ -40,10 +40,10 @@ MxU8 g_counters[] = {1, 2, 2, 3}; MxU32 LegoPlantManager::g_maxSound = 8; // GLOBAL: LEGO1 0x100f3160 -MxU32 g_unk0x100f3160 = 56; +MxU32 g_plantSoundIdOffset = 56; // GLOBAL: LEGO1 0x100f3164 -MxU32 g_unk0x100f3164 = 66; +MxU32 g_plantSoundIdMoodOffset = 66; // GLOBAL: LEGO1 0x100f3168 MxS32 LegoPlantManager::g_maxMove[4] = {3, 3, 3, 3}; @@ -83,7 +83,7 @@ void LegoPlantManager::Init() } m_worldId = LegoOmni::e_undefined; - m_unk0x0c = 0; + m_boundariesDetermined = FALSE; m_numEntries = 0; } @@ -98,7 +98,7 @@ void LegoPlantManager::LoadWorldInfo(LegoOmni::World p_worldId) CreatePlant(i, world, p_worldId); } - m_unk0x0c = 0; + m_boundariesDetermined = FALSE; } // FUNCTION: LEGO1 0x100263a0 @@ -119,12 +119,12 @@ void LegoPlantManager::Reset(LegoOmni::World p_worldId) } m_worldId = LegoOmni::e_undefined; - m_unk0x0c = 0; + m_boundariesDetermined = FALSE; } // FUNCTION: LEGO1 0x10026410 // FUNCTION: BETA10 0x100c50e9 -MxResult LegoPlantManager::FUN_10026410() +MxResult LegoPlantManager::DetermineBoundaries() { // similar to LegoBuildingManager::FUN_10030630() @@ -192,7 +192,7 @@ MxResult LegoPlantManager::FUN_10026410() } } - m_unk0x0c = TRUE; + m_boundariesDetermined = TRUE; return SUCCESS; } @@ -200,8 +200,8 @@ MxResult LegoPlantManager::FUN_10026410() // FUNCTION: BETA10 0x100c55e0 LegoPlantInfo* LegoPlantManager::GetInfoArray(MxS32& p_length) { - if (!m_unk0x0c) { - FUN_10026410(); + if (!m_boundariesDetermined) { + DetermineBoundaries(); } p_length = sizeOfArray(g_plantInfo); @@ -514,16 +514,16 @@ MxU32 LegoPlantManager::GetAnimationId(LegoEntity* p_entity) // FUNCTION: LEGO1 0x10026ba0 // FUNCTION: BETA10 0x100c61ba -MxU32 LegoPlantManager::GetSoundId(LegoEntity* p_entity, MxBool p_state) +MxU32 LegoPlantManager::GetSoundId(LegoEntity* p_entity, MxBool p_basedOnMood) { LegoPlantInfo* info = GetInfo(p_entity); - if (p_state) { - return (info->m_mood & 1) + g_unk0x100f3164; + if (p_basedOnMood) { + return (info->m_mood & 1) + g_plantSoundIdMoodOffset; } if (info != NULL) { - return info->m_sound + g_unk0x100f3160; + return info->m_sound + g_plantSoundIdOffset; } return 0; diff --git a/LEGO1/lego/legoomni/src/common/legotextureinfo.cpp b/LEGO1/lego/legoomni/src/common/legotextureinfo.cpp index eb639d84..a0be25b7 100644 --- a/LEGO1/lego/legoomni/src/common/legotextureinfo.cpp +++ b/LEGO1/lego/legoomni/src/common/legotextureinfo.cpp @@ -1,5 +1,6 @@ #include "legotextureinfo.h" +#include "extensions/textureloader.h" #include "legovideomanager.h" #include "misc.h" #include "misc/legoimage.h" @@ -9,6 +10,8 @@ DECOMP_SIZE_ASSERT(LegoTextureInfo, 0x10) +using namespace Extensions; + // FUNCTION: LEGO1 0x10065bf0 LegoTextureInfo::LegoTextureInfo() { @@ -56,6 +59,10 @@ LegoTextureInfo* LegoTextureInfo::Create(const char* p_name, LegoTexture* p_text strcpy(textureInfo->m_name, p_name); } + if (Extension::Call(PatchTexture, textureInfo).value_or(false)) { + return textureInfo; + } + LPDIRECTDRAW pDirectDraw = VideoManager()->GetDirect3D()->DirectDraw(); LegoImage* image = p_texture->GetImage(); diff --git a/LEGO1/lego/legoomni/src/common/legoutils.cpp b/LEGO1/lego/legoomni/src/common/legoutils.cpp index 9d3f3c7d..fdc6755a 100644 --- a/LEGO1/lego/legoomni/src/common/legoutils.cpp +++ b/LEGO1/lego/legoomni/src/common/legoutils.cpp @@ -102,29 +102,29 @@ MxBool SpheresIntersect(const BoundingSphere& p_sphere1, const BoundingSphere& p // FUNCTION: LEGO1 0x1003ded0 // FUNCTION: BETA10 0x100d3802 -MxBool FUN_1003ded0(MxFloat p_param1[2], MxFloat p_param2[3], MxFloat p_param3[3]) +MxBool CalculateRayOriginDirection(MxFloat p_coordinates[2], MxFloat p_direction[3], MxFloat p_origin[3]) { - MxFloat local1c[4]; - MxFloat local10[3]; + MxFloat screenPoint[4]; + MxFloat farPoint[3]; Tgl::View* view = VideoManager()->Get3DManager()->GetLego3DView()->GetView(); - local1c[0] = p_param1[0]; - local1c[1] = p_param1[1]; - local1c[2] = 1.0f; - local1c[3] = 1.0f; + screenPoint[0] = p_coordinates[0]; + screenPoint[1] = p_coordinates[1]; + screenPoint[2] = 1.0f; + screenPoint[3] = 1.0f; - view->TransformScreenToWorld(local1c, p_param3); + view->TransformScreenToWorld(screenPoint, p_origin); - local1c[0] *= 2.0; - local1c[1] *= 2.0; - local1c[3] = 2.0; + screenPoint[0] *= 2.0; + screenPoint[1] *= 2.0; + screenPoint[3] = 2.0; - view->TransformScreenToWorld(local1c, local10); + view->TransformScreenToWorld(screenPoint, farPoint); - p_param2[0] = local10[0] - p_param3[0]; - p_param2[1] = local10[1] - p_param3[1]; - p_param2[2] = local10[2] - p_param3[2]; + p_direction[0] = farPoint[0] - p_origin[0]; + p_direction[1] = farPoint[1] - p_origin[1]; + p_direction[2] = farPoint[2] - p_origin[2]; return TRUE; } @@ -176,7 +176,7 @@ LegoTreeNode* GetTreeNode(LegoTreeNode* p_node, MxU32 p_index) // FUNCTION: LEGO1 0x1003e050 // FUNCTION: BETA10 0x100d3abc -void FUN_1003e050(LegoAnimPresenter* p_presenter) +void CalculateViewFromAnimation(LegoAnimPresenter* p_presenter) { MxMatrix viewMatrix; LegoTreeNode* rootNode = p_presenter->GetAnimation()->GetRoot(); @@ -184,7 +184,7 @@ void FUN_1003e050(LegoAnimPresenter* p_presenter) LegoAnimNodeData* targetData = NULL; MxS16 nodesCount = CountTotalTreeNodes(rootNode); - MxFloat cam; + MxFloat fov; for (MxS16 i = 0; i < nodesCount; i++) { if (camData && targetData) { break; @@ -194,7 +194,7 @@ void FUN_1003e050(LegoAnimPresenter* p_presenter) if (!SDL_strncasecmp(data->GetName(), "CAM", strlen("CAM"))) { camData = data; - cam = atof(&data->GetName()[strlen(data->GetName()) - 2]); + fov = atof(&data->GetName()[strlen(data->GetName()) - 2]); } else if (!SDL_strcasecmp(data->GetName(), "TARGET")) { targetData = data; @@ -223,8 +223,8 @@ void FUN_1003e050(LegoAnimPresenter* p_presenter) roi->WrappedSetLocal2WorldWithWorldDataUpdate(viewMatrix); view->Moved(*roi); - FUN_1003eda0(); - video->Get3DManager()->SetFrustrum(cam, 0.1, 250.0); + ResetViewVelocity(); + video->Get3DManager()->SetFrustrum(fov, 0.1, 250.0); } // FUNCTION: LEGO1 0x1003e300 @@ -477,7 +477,7 @@ void PlayCamAnim(LegoPathActor* p_actor, MxBool p_unused, MxU32 p_location, MxBo // FUNCTION: LEGO1 0x1003eda0 // FUNCTION: BETA10 0x100d4bf4 -void FUN_1003eda0() +void ResetViewVelocity() { Mx3DPointFloat vec; vec.Clear(); @@ -511,7 +511,7 @@ MxBool RemoveFromCurrentWorld(const MxAtomId& p_atomId, MxS32 p_id) } else { if (((MxPresenter*) object)->GetAction()) { - FUN_100b7220(((MxPresenter*) object)->GetAction(), MxDSAction::c_world, FALSE); + ApplyMask(((MxPresenter*) object)->GetAction(), MxDSAction::c_world, FALSE); } ((MxPresenter*) object)->EndAction(); @@ -540,7 +540,7 @@ MxBool RemoveFromWorld(MxAtomId& p_entityAtom, MxS32 p_entityId, MxAtomId& p_wor } else { if (((MxPresenter*) object)->GetAction()) { - FUN_100b7220(((MxPresenter*) object)->GetAction(), MxDSAction::c_world, FALSE); + ApplyMask(((MxPresenter*) object)->GetAction(), MxDSAction::c_world, FALSE); } ((MxPresenter*) object)->EndAction(); @@ -577,7 +577,7 @@ void SetAppCursor(Cursor p_cursor) } // FUNCTION: LEGO1 0x1003ef60 -MxBool FUN_1003ef60() +MxBool CanExit() { Act1State* act1State = (Act1State*) GameState()->GetState("Act1State"); @@ -591,9 +591,10 @@ MxBool FUN_1003ef60() GameState()->m_currentArea != LegoGameState::e_polidoor) { if (UserActor() == NULL || !UserActor()->IsA("TowTrack")) { if (UserActor() == NULL || !UserActor()->IsA("Ambulance")) { - MxU32 unk0x18 = act1State->GetUnknown18(); + MxU32 mission = act1State->GetState(); - if (unk0x18 != 10 && unk0x18 != 8 && unk0x18 != 3) { + if (mission != Act1State::e_ambulance && mission != Act1State::e_towtrack && + mission != Act1State::e_pizza) { return TRUE; } } @@ -708,19 +709,19 @@ void WriteDefaultTexture(LegoStorage* p_storage, const char* p_name) memset(&desc, 0, sizeof(desc)); desc.dwSize = sizeof(desc); - if (surface->Lock(NULL, &desc, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WRITEONLY, NULL) == DD_OK) { + if (surface->Lock(NULL, &desc, DDLOCK_SURFACEMEMORYPTR, NULL) == DD_OK) { LegoImage* image = new LegoImage(desc.dwWidth, desc.dwHeight); if (image != NULL) { if (desc.dwWidth == desc.lPitch) { - memcpy(desc.lpSurface, image->GetBits(), desc.dwWidth * desc.dwHeight); + memcpy(image->GetBits(), desc.lpSurface, desc.dwWidth * desc.dwHeight); } else { MxU8* surface = (MxU8*) desc.lpSurface; - const LegoU8* bits = image->GetBits(); + LegoU8* bits = image->GetBits(); for (MxS32 i = 0; i < desc.dwHeight; i++) { - memcpy(surface, bits, desc.dwWidth); + memcpy(bits, surface, desc.dwWidth); surface += desc.lPitch; bits += desc.dwWidth; } @@ -774,7 +775,7 @@ void WriteNamedTexture(LegoStorage* p_storage, LegoNamedTexture* p_namedTexture) } // FUNCTION: LEGO1 0x1003f930 -void FUN_1003f930(LegoNamedTexture* p_namedTexture) +void LoadFromNamedTexture(LegoNamedTexture* p_namedTexture) { LegoTextureInfo* textureInfo = TextureContainer()->Get(p_namedTexture->GetName()->GetData()); @@ -782,3 +783,11 @@ void FUN_1003f930(LegoNamedTexture* p_namedTexture) textureInfo->LoadBits(p_namedTexture->GetTexture()->GetImage()->GetBits()); } } + +void EmitGameEvent(GameEvent p_event) +{ + SDL_Event event; + event.user.type = g_legoSdlEvents.m_gameEvent; + event.user.code = p_event; + SDL_PushEvent(&event); +} diff --git a/LEGO1/lego/legoomni/src/common/legovariables.cpp b/LEGO1/lego/legoomni/src/common/legovariables.cpp index 8269dfde..5d2d6cdb 100644 --- a/LEGO1/lego/legoomni/src/common/legovariables.cpp +++ b/LEGO1/lego/legoomni/src/common/legovariables.cpp @@ -6,6 +6,7 @@ #include "legonavcontroller.h" #include "legovideomanager.h" #include "misc.h" +#include "mxdebug.h" #include "roi/legoroi.h" #include @@ -103,6 +104,10 @@ const char* g_nick = "Nick"; // STRING: LEGO1 0x100f39e0 const char* g_laura = "Laura"; +// GLOBAL: BETA10 0x101f6ce4 +// STRING: BETA10 0x101f6d54 +const char* g_varDEBUG = "DEBUG"; + // FUNCTION: LEGO1 0x10037d00 // FUNCTION: BETA10 0x100d5620 void VisibilityVariable::SetValue(const char* p_value) @@ -132,6 +137,7 @@ void VisibilityVariable::SetValue(const char* p_value) } // FUNCTION: LEGO1 0x10037d80 +// FUNCTION: BETA10 0x100d56ee void CameraLocationVariable::SetValue(const char* p_value) { char buffer[256]; @@ -139,22 +145,25 @@ void CameraLocationVariable::SetValue(const char* p_value) strcpy(buffer, p_value); - char* location = strtok(buffer, ","); - NavController()->UpdateLocation(location); + char* token = strtok(buffer, ","); + assert(token); + NavController()->UpdateLocation(token); - location = strtok(NULL, ","); - if (location) { - MxFloat pov = (MxFloat) atof(location); + token = strtok(NULL, ","); + if (token) { + MxFloat pov = (MxFloat) atof(token); VideoManager()->Get3DManager()->SetFrustrum(pov, 0.1f, 250.0f); } } // FUNCTION: LEGO1 0x10037e30 +// FUNCTION: BETA10 0x100d57e2 void CursorVariable::SetValue(const char* p_value) { } // FUNCTION: LEGO1 0x10037e40 +// FUNCTION: BETA10 0x100d57fa void WhoAmIVariable::SetValue(const char* p_value) { MxVariable::SetValue(p_value); @@ -175,3 +184,10 @@ void WhoAmIVariable::SetValue(const char* p_value) GameState()->SetActorId(LegoActor::c_laura); } } + +// FUNCTION: BETA10 0x100d58fa +void DebugVariable::SetValue(const char* p_value) +{ + MxVariable::SetValue(p_value); + MxTrace("%s\n", p_value); +} diff --git a/LEGO1/lego/legoomni/src/common/misc.cpp b/LEGO1/lego/legoomni/src/common/misc.cpp index 08072b7c..19ff0a21 100644 --- a/LEGO1/lego/legoomni/src/common/misc.cpp +++ b/LEGO1/lego/legoomni/src/common/misc.cpp @@ -140,10 +140,10 @@ ViewLODListManager* GetViewLODListManager() // FUNCTION: LEGO1 0x10015820 // FUNCTION: BETA10 0x100e4c92 -void FUN_10015820(MxBool p_disable, MxU16 p_flags) +void Disable(MxBool p_disable, MxU16 p_flags) { assert(LegoOmni::GetInstance()); - LegoOmni::GetInstance()->FUN_1005b4f0(p_disable, p_flags); + LegoOmni::GetInstance()->Disable(p_disable, p_flags); } // FUNCTION: LEGO1 0x10015840 @@ -172,9 +172,9 @@ void SetUserActor(LegoPathActor* p_userActor) // FUNCTION: LEGO1 0x10015890 // FUNCTION: BETA10 0x100e4d80 -MxResult StartActionIfUnknown0x13c(MxDSAction& p_dsAction) +MxResult StartActionIfInitialized(MxDSAction& p_dsAction) { - return LegoOmni::GetInstance()->StartActionIfUnknown0x13c(p_dsAction); + return LegoOmni::GetInstance()->StartActionIfInitialized(p_dsAction); } // FUNCTION: LEGO1 0x100158b0 diff --git a/LEGO1/lego/legoomni/src/common/mxcompositemediapresenter.cpp b/LEGO1/lego/legoomni/src/common/mxcompositemediapresenter.cpp index dadd8de7..7c6a788d 100644 --- a/LEGO1/lego/legoomni/src/common/mxcompositemediapresenter.cpp +++ b/LEGO1/lego/legoomni/src/common/mxcompositemediapresenter.cpp @@ -27,6 +27,7 @@ MxCompositeMediaPresenter::~MxCompositeMediaPresenter() } // FUNCTION: LEGO1 0x10074090 +// FUNCTION: BETA10 0x100e9d37 MxResult MxCompositeMediaPresenter::StartAction(MxStreamController* p_controller, MxDSAction* p_action) { AUTOLOCK(m_criticalSection); @@ -84,7 +85,7 @@ MxResult MxCompositeMediaPresenter::StartAction(MxStreamController* p_controller if (!m_compositePresenter) { SetTickleState(e_ready); MxLong time = Timer()->GetTime(); - m_action->SetUnknown90(time); + m_action->SetTimeStarted(time); } result = SUCCESS; @@ -134,7 +135,7 @@ void MxCompositeMediaPresenter::StartingTickle() if (!m_unk0x4c) { ProgressTickleState(e_streaming); MxLong time = Timer()->GetTime(); - m_action->SetUnknown90(time); + m_action->SetTimeStarted(time); } } } diff --git a/LEGO1/lego/legoomni/src/common/mxcontrolpresenter.cpp b/LEGO1/lego/legoomni/src/common/mxcontrolpresenter.cpp index 5c533adf..ae11da97 100644 --- a/LEGO1/lego/legoomni/src/common/mxcontrolpresenter.cpp +++ b/LEGO1/lego/legoomni/src/common/mxcontrolpresenter.cpp @@ -18,12 +18,12 @@ DECOMP_SIZE_ASSERT(MxControlPresenter, 0x5c) // FUNCTION: LEGO1 0x10043f50 MxControlPresenter::MxControlPresenter() { - m_unk0x4c = 0; - m_unk0x4e = -1; + m_style = e_none; + m_enabledChild = -1; m_unk0x50 = FALSE; - m_unk0x52 = 0; + m_columnsOrRows = 0; m_states = NULL; - m_unk0x54 = 0; + m_rowsOrColumns = 0; } // FUNCTION: LEGO1 0x10044110 @@ -37,7 +37,7 @@ MxControlPresenter::~MxControlPresenter() // FUNCTION: LEGO1 0x10044180 MxResult MxControlPresenter::AddToManager() { - m_unk0x4e = 0; + m_enabledChild = 0; return SUCCESS; } @@ -46,16 +46,16 @@ MxResult MxControlPresenter::StartAction(MxStreamController* p_controller, MxDSA { MxResult result = MxCompositePresenter::StartAction(p_controller, p_action); - FUN_100b7220(m_action, MxDSAction::c_world | MxDSAction::c_looping, TRUE); + ApplyMask(m_action, MxDSAction::c_world | MxDSAction::c_looping, TRUE); ParseExtra(); MxS16 i = 0; for (MxCompositePresenterList::iterator it = m_list.begin(); it != m_list.end(); it++) { - (*it)->Enable((m_unk0x4c != 3 || m_unk0x4e) && IsEnabled() ? m_unk0x4e == i : FALSE); + (*it)->Enable((m_style != e_map || m_enabledChild) && IsEnabled() ? m_enabledChild == i : FALSE); i++; } - if (m_unk0x4c == 3) { + if (m_style == e_map) { MxDSAction* action = (*m_list.begin())->GetAction(); action->SetFlags(action->GetFlags() | MxDSAction::c_bit11); } @@ -76,16 +76,13 @@ void MxControlPresenter::EndAction() // FUNCTION: LEGO1 0x10044270 // FUNCTION: BETA10 0x100eae68 -MxBool MxControlPresenter::FUN_10044270(MxS32 p_x, MxS32 p_y, MxPresenter* p_presenter) +MxBool MxControlPresenter::CheckButtonDown(MxS32 p_x, MxS32 p_y, MxPresenter* p_presenter) { assert(p_presenter); MxVideoPresenter* presenter = dynamic_cast(p_presenter); - if (!presenter) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Invalid presenter"); - return FALSE; - } + assert(presenter); - if (m_unk0x4c == 3) { + if (m_style == e_map) { MxStillPresenter* map = (MxStillPresenter*) m_list.front(); assert(map && map->IsA("MxStillPresenter")); @@ -100,23 +97,23 @@ MxBool MxControlPresenter::FUN_10044270(MxS32 p_x, MxS32 p_y, MxPresenter* p_pre ? NULL : map->GetBitmap()->GetStart(p_x - rect.GetLeft(), p_y - rect.GetTop()); - m_unk0x56 = 0; + m_stateOrCellIndex = 0; if (m_states) { for (MxS16 i = 1; i <= *m_states; i++) { // TODO: Can we match without the cast here? if (m_states[i] == (MxS16) *start) { - m_unk0x56 = i; + m_stateOrCellIndex = i; break; } } } else { if (*start != 0) { - m_unk0x56 = 1; + m_stateOrCellIndex = 1; } } - if (m_unk0x56) { + if (m_stateOrCellIndex) { return TRUE; } } @@ -125,21 +122,21 @@ MxBool MxControlPresenter::FUN_10044270(MxS32 p_x, MxS32 p_y, MxPresenter* p_pre } else { if (ContainsPresenter(m_list, presenter)) { - if (m_unk0x4c == 2) { + if (m_style == e_grid) { MxS32 width = presenter->GetWidth(); MxS32 height = presenter->GetHeight(); - if (m_unk0x52 == 2 && m_unk0x54 == 2) { + if (m_columnsOrRows == 2 && m_rowsOrColumns == 2) { if (p_x < presenter->GetX() + width / 2) { - m_unk0x56 = (p_y >= presenter->GetY() + height / 2) ? 3 : 1; + m_stateOrCellIndex = (p_y >= presenter->GetY() + height / 2) ? 3 : 1; } else { - m_unk0x56 = (p_y >= presenter->GetY() + height / 2) ? 4 : 2; + m_stateOrCellIndex = (p_y >= presenter->GetY() + height / 2) ? 4 : 2; } } } else { - m_unk0x56 = -1; + m_stateOrCellIndex = -1; } return TRUE; @@ -150,27 +147,27 @@ MxBool MxControlPresenter::FUN_10044270(MxS32 p_x, MxS32 p_y, MxPresenter* p_pre } // FUNCTION: LEGO1 0x10044480 -MxBool MxControlPresenter::FUN_10044480(LegoControlManagerNotificationParam* p_param, MxPresenter* p_presenter) +MxBool MxControlPresenter::Notify(LegoControlManagerNotificationParam* p_param, MxPresenter* p_presenter) { if (IsEnabled()) { switch (p_param->GetNotification()) { case c_notificationButtonUp: - if (m_unk0x4c == 0 || m_unk0x4c == 2 || m_unk0x4c == 3) { + if (m_style == e_none || m_style == e_grid || m_style == e_map) { p_param->SetClickedObjectId(m_action->GetObjectId()); p_param->SetClickedAtom(m_action->GetAtomId().GetInternal()); - VTable0x6c(0); + UpdateEnabledChild(0); p_param->SetNotification(c_notificationControl); - p_param->SetUnknown0x28(m_unk0x4e); + p_param->SetEnabledChild(m_enabledChild); return TRUE; } break; case c_notificationButtonDown: - if (FUN_10044270(p_param->GetX(), p_param->GetY(), p_presenter)) { + if (CheckButtonDown(p_param->GetX(), p_param->GetY(), p_presenter)) { p_param->SetClickedObjectId(m_action->GetObjectId()); p_param->SetClickedAtom(m_action->GetAtomId().GetInternal()); - VTable0x6c(m_unk0x56); + UpdateEnabledChild(m_stateOrCellIndex); p_param->SetNotification(c_notificationControl); - p_param->SetUnknown0x28(m_unk0x4e); + p_param->SetEnabledChild(m_enabledChild); return TRUE; } break; @@ -181,25 +178,25 @@ MxBool MxControlPresenter::FUN_10044480(LegoControlManagerNotificationParam* p_p } // FUNCTION: LEGO1 0x10044540 -void MxControlPresenter::VTable0x6c(MxS16 p_unk0x4e) +void MxControlPresenter::UpdateEnabledChild(MxS16 p_enabledChild) { - if (p_unk0x4e == -1) { - if ((MxS16) ((MxDSMultiAction*) m_action)->GetActionList()->GetNumElements() - m_unk0x4e == 1) { - m_unk0x4e = 0; + if (p_enabledChild == -1) { + if ((MxS16) ((MxDSMultiAction*) m_action)->GetActionList()->GetNumElements() - m_enabledChild == 1) { + m_enabledChild = 0; } else { - m_unk0x4e++; + m_enabledChild++; } } else { - m_unk0x4e = p_unk0x4e; + m_enabledChild = p_enabledChild; } - m_action->SetUnknown90(Timer()->GetTime()); + m_action->SetTimeStarted(Timer()->GetTime()); MxS16 i = 0; for (MxCompositePresenterList::iterator it = m_list.begin(); it != m_list.end(); it++) { - (*it)->Enable(((m_unk0x4c == 3 && m_unk0x4e == 0) || !IsEnabled()) ? FALSE : m_unk0x4e == i); + (*it)->Enable(((m_style == e_map && m_enabledChild == 0) || !IsEnabled()) ? FALSE : m_enabledChild == i); i++; } } @@ -230,20 +227,20 @@ void MxControlPresenter::ParseExtra() char* token = strtok(output, g_parseExtraTokens); if (!SDL_strcasecmp(token, g_strTOGGLE)) { - m_unk0x4c = 1; + m_style = e_toggle; } else if (!SDL_strcasecmp(token, g_strGRID)) { - m_unk0x4c = 2; + m_style = e_grid; token = strtok(NULL, g_parseExtraTokens); assert(token); - m_unk0x52 = atoi(token); + m_columnsOrRows = atoi(token); token = strtok(NULL, g_parseExtraTokens); assert(token); - m_unk0x54 = atoi(token); + m_rowsOrColumns = atoi(token); } else if (!SDL_strcasecmp(token, g_strMAP)) { - m_unk0x4c = 3; + m_style = e_map; token = strtok(NULL, g_parseExtraTokens); if (token) { @@ -260,7 +257,7 @@ void MxControlPresenter::ParseExtra() } } else { - m_unk0x4c = 0; + m_style = e_none; } } @@ -280,8 +277,8 @@ void MxControlPresenter::Enable(MxBool p_enable) MxS16 i = 0; for (MxCompositePresenterList::iterator it = m_list.begin(); it != m_list.end(); it++) { - if (i == m_unk0x4e) { - (*it)->Enable((m_unk0x4c != 3 || i != 0) ? p_enable : 0); + if (i == m_enabledChild) { + (*it)->Enable((m_style != e_map || i != 0) ? p_enable : 0); break; } @@ -289,7 +286,7 @@ void MxControlPresenter::Enable(MxBool p_enable) } if (!p_enable) { - m_unk0x4e = 0; + m_enabledChild = 0; } } } @@ -300,10 +297,10 @@ MxBool MxControlPresenter::HasTickleStatePassed(TickleState p_tickleState) MxCompositePresenterList::const_iterator it = m_list.begin(); #ifdef COMPAT_MODE - advance(it, m_unk0x4e); + advance(it, m_enabledChild); #else // Uses forward iterator logic instead of bidrectional for some reason. - _Advance(it, m_unk0x4e, forward_iterator_tag()); + _Advance(it, m_enabledChild, forward_iterator_tag()); #endif return (*it)->HasTickleStatePassed(p_tickleState); diff --git a/LEGO1/lego/legoomni/src/common/mxtransitionmanager.cpp b/LEGO1/lego/legoomni/src/common/mxtransitionmanager.cpp index b251c1c0..7431033e 100644 --- a/LEGO1/lego/legoomni/src/common/mxtransitionmanager.cpp +++ b/LEGO1/lego/legoomni/src/common/mxtransitionmanager.cpp @@ -16,6 +16,8 @@ DECOMP_SIZE_ASSERT(MxTransitionManager, 0x900) +MxTransitionManager::TransitionType g_transitionManagerConfig = MxTransitionManager::e_mosaic; + // GLOBAL: LEGO1 0x100f4378 RECT g_fullScreenRect = {0, 0, 640, 480}; @@ -105,7 +107,7 @@ MxResult MxTransitionManager::StartTransition( backgroundAudioManager->Stop(); } - m_mode = p_animationType; + m_mode = g_transitionManagerConfig; m_copyFlags.m_bit0 = p_doCopy; @@ -246,7 +248,7 @@ void MxTransitionManager::DissolveTransition() } else { MxU8* surf = (MxU8*) ddsd.lpSurface + ddsd.lPitch * row + xShift * 4; - *(MxU32*) surf = 0; + *(MxU32*) surf = 0xFF000000; } } } @@ -266,8 +268,15 @@ void MxTransitionManager::DissolveTransition() // FUNCTION: LEGO1 0x1004bed0 void MxTransitionManager::MosaicTransition() { + static LPDIRECTDRAWSURFACE g_transitionSurface = nullptr; + static MxU32 g_colors[64][48]; + if (m_animationTimer == 16) { m_animationTimer = 0; + if (g_transitionSurface) { + g_transitionSurface->Release(); + g_transitionSurface = nullptr; + } EndTransition(TRUE); return; } @@ -292,6 +301,84 @@ void MxTransitionManager::MosaicTransition() for (i = 0; i < 48; i++) { m_randomShift[i] = SDL_rand(64); } + + DDSURFACEDESC srcDesc = {}; + srcDesc.dwSize = sizeof(srcDesc); + HRESULT lockRes = m_ddSurface->Lock(NULL, &srcDesc, DDLOCK_WAIT | DDLOCK_READONLY, NULL); + if (lockRes == DDERR_SURFACELOST) { + m_ddSurface->Restore(); + lockRes = m_ddSurface->Lock(NULL, &srcDesc, DDLOCK_WAIT | DDLOCK_READONLY, NULL); + } + + if (lockRes != DD_OK) { + return; + } + + MxS32 bytesPerPixel = srcDesc.ddpfPixelFormat.dwRGBBitCount / 8; + + for (MxS32 col = 0; col < 64; col++) { + for (MxS32 row = 0; row < 48; row++) { + MxS32 xBlock = (m_randomShift[row] + col) % 64; + MxS32 y = row * 10; + MxS32 x = xBlock * 10; + + MxU8* pixelPtr = (MxU8*) srcDesc.lpSurface + y * srcDesc.lPitch + x * bytesPerPixel; + + MxU32 pixel; + switch (bytesPerPixel) { + case 1: + pixel = *pixelPtr; + break; + case 2: + pixel = *(MxU16*) pixelPtr; + break; + default: + pixel = *(MxU32*) pixelPtr; + break; + } + + g_colors[col][row] = pixel; + } + } + + m_ddSurface->Unlock(srcDesc.lpSurface); + + DDSURFACEDESC mainDesc = {}; + mainDesc.dwSize = sizeof(mainDesc); + if (m_ddSurface->GetSurfaceDesc(&mainDesc) != DD_OK) { + return; + } + + DDSURFACEDESC tempDesc = {}; + tempDesc.dwSize = sizeof(tempDesc); + tempDesc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | DDSD_CAPS; + tempDesc.dwWidth = 64; + tempDesc.dwHeight = 48; + tempDesc.ddpfPixelFormat = mainDesc.ddpfPixelFormat; + tempDesc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN; + + if (MVideoManager()->GetDirectDraw()->CreateSurface(&tempDesc, &g_transitionSurface, nullptr) != DD_OK) { + return; + } + + DWORD fillColor = 0x00000000; + switch (mainDesc.ddpfPixelFormat.dwRGBBitCount) { + case 8: + fillColor = 0x10; + break; + case 16: + fillColor = RGB555_CREATE(0x1f, 0, 0x1f); + break; + } + + DDBLTFX bltFx = {}; + bltFx.dwSize = sizeof(bltFx); + bltFx.dwFillColor = fillColor; + g_transitionSurface->Blt(NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &bltFx); + + DDCOLORKEY key = {}; + key.dwColorSpaceLowValue = key.dwColorSpaceHighValue = fillColor; + g_transitionSurface->SetColorKey(DDCKEY_SRCBLT, &key); } // Run one tick of the animation @@ -299,15 +386,18 @@ void MxTransitionManager::MosaicTransition() memset(&ddsd, 0, sizeof(ddsd)); ddsd.dwSize = sizeof(ddsd); - HRESULT res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL); + HRESULT res = g_transitionSurface->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL); if (res == DDERR_SURFACELOST) { - m_ddSurface->Restore(); - res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL); + g_transitionSurface->Restore(); + res = g_transitionSurface->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL); } if (res == DD_OK) { SubmitCopyRect(&ddsd); + // Combine xShift with this value to target the correct location in the buffer. + MxS32 bytesPerPixel = ddsd.ddpfPixelFormat.dwRGBBitCount / 8; + for (MxS32 col = 0; col < 64; col++) { // Select 4 columns on each tick if (m_animationTimer * 4 > m_columnOrder[col]) { @@ -319,69 +409,29 @@ void MxTransitionManager::MosaicTransition() } for (MxS32 row = 0; row < 48; row++) { - // To do the mosaic effect, we subdivide the 640x480 surface into - // 10x10 pixel blocks. At the chosen block, we sample the top-leftmost - // color and set the other 99 pixels to that value. + MxS32 x = (m_randomShift[row] + col) % 64; + MxU8* dest = (MxU8*) ddsd.lpSurface + row * ddsd.lPitch + x * bytesPerPixel; - // First, get the offset of the 10x10 block that we will sample for this row. - MxS32 xShift = 10 * ((m_randomShift[row] + col) % 64); - - // Combine xShift with this value to target the correct location in the buffer. - MxS32 bytesPerPixel = ddsd.ddpfPixelFormat.dwRGBBitCount / 8; - - // Seek to the sample position. - MxU8* source = (MxU8*) ddsd.lpSurface + 10 * row * ddsd.lPitch + bytesPerPixel * xShift; - - // Sample byte or word depending on display mode. - MxU32 sample; + MxU32 source = g_colors[col][row]; switch (bytesPerPixel) { case 1: - sample = *source; + *dest = (MxU8) source; break; case 2: - sample = *(MxU16*) source; + *((MxU16*) dest) = (MxU16) source; break; default: - sample = *(MxU32*) source; + *((MxU32*) dest) = source; break; } - - // For each of the 10 rows in the 10x10 square: - for (MxS32 k = 10 * row; k < 10 * row + 10; k++) { - void* pos = (MxU8*) ddsd.lpSurface + k * ddsd.lPitch + bytesPerPixel * xShift; - - switch (bytesPerPixel) { - case 1: { - // Optimization: If the pixel is only one byte, we can use memset - memset(pos, sample, 10); - break; - } - case 2: { - MxU16* p = (MxU16*) pos; - for (MxS32 tt = 0; tt < 10; tt++) { - p[tt] = (MxU16) sample; - } - break; - } - default: { - MxU32* p = (MxU32*) pos; - for (MxS32 tt = 0; tt < 10; tt++) { - p[tt] = (MxU32) sample; - } - break; - } - } - } } } SetupCopyRect(&ddsd); - m_ddSurface->Unlock(ddsd.lpSurface); + g_transitionSurface->Unlock(ddsd.lpSurface); - if (VideoManager()->GetVideoParam().Flags().GetFlipSurfaces()) { - LPDIRECTDRAWSURFACE surf = VideoManager()->GetDisplaySurface()->GetDirectDrawSurface1(); - surf->BltFast(0, 0, m_ddSurface, &g_fullScreenRect, DDBLTFAST_WAIT); - } + RECT srcRect = {0, 0, 64, 48}; + m_ddSurface->Blt(&g_fullScreenRect, g_transitionSurface, &srcRect, DDBLT_WAIT | DDBLT_KEYSRC, NULL); m_animationTimer++; } @@ -398,32 +448,18 @@ void MxTransitionManager::WipeDownTransition() return; } - DDSURFACEDESC ddsd; - memset(&ddsd, 0, sizeof(ddsd)); - ddsd.dwSize = sizeof(ddsd); + RECT fillRect = g_fullScreenRect; + // For each of the 240 animation ticks, blank out two scanlines + // starting at the top of the screen. + fillRect.bottom = 2 * (m_animationTimer + 1); - HRESULT res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL); - if (res == DDERR_SURFACELOST) { - m_ddSurface->Restore(); - res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL); - } + DDBLTFX bltFx = {}; + bltFx.dwSize = sizeof(bltFx); + bltFx.dwFillColor = 0xFF000000; - if (res == DD_OK) { - SubmitCopyRect(&ddsd); + m_ddSurface->Blt(&fillRect, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &bltFx); - // For each of the 240 animation ticks, blank out two scanlines - // starting at the top of the screen. - MxU8* line = (MxU8*) ddsd.lpSurface + 2 * ddsd.lPitch * m_animationTimer; - memset(line, 0, ddsd.lPitch); - - line += ddsd.lPitch; - memset(line, 0, ddsd.lPitch); - - SetupCopyRect(&ddsd); - m_ddSurface->Unlock(ddsd.lpSurface); - - m_animationTimer++; - } + m_animationTimer++; } // FUNCTION: LEGO1 0x1004c270 @@ -435,40 +471,28 @@ void MxTransitionManager::WindowsTransition() return; } - DDSURFACEDESC ddsd; - memset(&ddsd, 0, sizeof(ddsd)); - ddsd.dwSize = sizeof(ddsd); + DDBLTFX bltFx = {}; + bltFx.dwSize = sizeof(bltFx); + bltFx.dwFillColor = 0xFF000000; - HRESULT res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL); - if (res == DDERR_SURFACELOST) { - m_ddSurface->Restore(); - res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL); - } + int top = m_animationTimer; + int bottom = 480 - m_animationTimer - 1; + int left = m_animationTimer; + int right = 639 - m_animationTimer; - if (res == DD_OK) { - SubmitCopyRect(&ddsd); + RECT topRect = {0, top, 640, top + 1}; + m_ddSurface->Blt(&topRect, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &bltFx); - MxU8* line = (MxU8*) ddsd.lpSurface + m_animationTimer * ddsd.lPitch; + RECT bottomRect = {0, bottom, 640, bottom + 1}; + m_ddSurface->Blt(&bottomRect, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &bltFx); - MxS32 bytesPerPixel = ddsd.ddpfPixelFormat.dwRGBBitCount / 8; + RECT leftRect = {left, top + 1, left + 1, bottom}; + m_ddSurface->Blt(&leftRect, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &bltFx); - memset(line, 0, ddsd.lPitch); + RECT rightRect = {right, top + 1, right + 1, bottom}; + m_ddSurface->Blt(&rightRect, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &bltFx); - for (MxS32 i = m_animationTimer + 1; i < 480 - m_animationTimer; i++) { - line += ddsd.lPitch; - - memset(line + m_animationTimer * bytesPerPixel, 0, bytesPerPixel); - memset(line + 640 + (-1 - m_animationTimer) * bytesPerPixel, 0, bytesPerPixel); - } - - line += ddsd.lPitch; - memset(line, 0, ddsd.lPitch); - - SetupCopyRect(&ddsd); - m_ddSurface->Unlock(ddsd.lpSurface); - - m_animationTimer++; - } + m_animationTimer++; } // FUNCTION: LEGO1 0x1004c3e0 @@ -632,3 +656,8 @@ void MxTransitionManager::SetupCopyRect(LPDDSURFACEDESC p_ddsc) ); } } + +void MxTransitionManager::configureMxTransitionManager(TransitionType p_transitionManagerConfig) +{ + g_transitionManagerConfig = p_transitionManagerConfig; +} diff --git a/LEGO1/lego/legoomni/src/control/legocontrolmanager.cpp b/LEGO1/lego/legoomni/src/control/legocontrolmanager.cpp index 8dd094f9..7851a52a 100644 --- a/LEGO1/lego/legoomni/src/control/legocontrolmanager.cpp +++ b/LEGO1/lego/legoomni/src/control/legocontrolmanager.cpp @@ -17,10 +17,10 @@ DECOMP_SIZE_ASSERT(LegoEventNotificationParam, 0x20) LegoControlManager::LegoControlManager() { m_presenterList = NULL; - m_unk0x08 = 0; - m_unk0x0c = 0; - m_unk0x10 = FALSE; - m_unk0x14 = NULL; + m_buttonDownState = e_idle; + m_handleUpNextTickle = 0; + m_secondButtonDown = FALSE; + m_handledPresenter = NULL; TickleManager()->RegisterClient(this, 10); } @@ -31,11 +31,11 @@ LegoControlManager::~LegoControlManager() } // FUNCTION: LEGO1 0x10028df0 -void LegoControlManager::FUN_10028df0(MxPresenterList* p_presenterList) +void LegoControlManager::SetPresenterList(MxPresenterList* p_presenterList) { m_presenterList = p_presenterList; - g_unk0x100f31b0 = -1; - g_unk0x100f31b4 = NULL; + g_clickedObjectId = -1; + g_clickedAtom = NULL; } // FUNCTION: LEGO1 0x10028e10 @@ -56,10 +56,10 @@ void LegoControlManager::Unregister(MxCore* p_listener) } // FUNCTION: LEGO1 0x10029210 -MxBool LegoControlManager::FUN_10029210(LegoEventNotificationParam& p_param, MxPresenter* p_presenter) +MxBool LegoControlManager::HandleButtonDown(LegoEventNotificationParam& p_param, MxPresenter* p_presenter) { if (m_presenterList != NULL && m_presenterList->GetNumElements() != 0) { - m_unk0x14 = p_presenter; + m_handledPresenter = p_presenter; if (p_param.GetNotification() == c_notificationButtonUp || p_param.GetNotification() == c_notificationButtonDown) { @@ -71,28 +71,28 @@ MxBool LegoControlManager::FUN_10029210(LegoEventNotificationParam& p_param, MxP m_event.SetKey(p_param.GetKey()); if (p_param.GetNotification() == c_notificationButtonUp) { - if (m_unk0x10 == TRUE) { - m_unk0x10 = FALSE; + if (m_secondButtonDown == TRUE) { + m_secondButtonDown = FALSE; return TRUE; } - if (g_unk0x100f31b0 != -1 && g_unk0x100f31b4 != NULL) { - if (m_unk0x08 == 2) { - return FUN_10029750(); + if (g_clickedObjectId != -1 && g_clickedAtom != NULL) { + if (m_buttonDownState == e_tickled) { + return HandleButtonUp(); } else { - m_unk0x0c = 1; + m_handleUpNextTickle = 1; return TRUE; } } } else if (p_param.GetNotification() == c_notificationButtonDown) { - if (m_unk0x0c == 1) { - m_unk0x10 = TRUE; + if (m_handleUpNextTickle == 1) { + m_secondButtonDown = TRUE; return TRUE; } else { - return FUN_10029630(); + return HandleButtonDown(); } } } @@ -100,15 +100,15 @@ MxBool LegoControlManager::FUN_10029210(LegoEventNotificationParam& p_param, MxP return FALSE; } else { - g_unk0x100f31b0 = -1; - g_unk0x100f31b4 = NULL; + g_clickedObjectId = -1; + g_clickedAtom = NULL; return FALSE; } } // FUNCTION: LEGO1 0x100292e0 -void LegoControlManager::FUN_100292e0() +void LegoControlManager::Notify() { LegoNotifyListCursor cursor(&m_notifyList); MxCore* target; @@ -121,7 +121,7 @@ void LegoControlManager::FUN_100292e0() } // FUNCTION: LEGO1 0x100293c0 -void LegoControlManager::FUN_100293c0(MxU32 p_objectId, const char* p_atom, MxS16 p_unk0x4e) +void LegoControlManager::UpdateEnabledChild(MxU32 p_objectId, const char* p_atom, MxS16 p_enabledChild) { if (m_presenterList) { MxPresenterListCursor cursor(m_presenterList); @@ -131,11 +131,11 @@ void LegoControlManager::FUN_100293c0(MxU32 p_objectId, const char* p_atom, MxS1 MxDSAction* action = control->GetAction(); if (action->GetObjectId() == p_objectId && action->GetAtomId().GetInternal() == p_atom) { - ((MxControlPresenter*) control)->VTable0x6c(p_unk0x4e); + ((MxControlPresenter*) control)->UpdateEnabledChild(p_enabledChild); - if (((MxControlPresenter*) control)->GetUnknown0x4e() == 0) { - g_unk0x100f31b0 = -1; - g_unk0x100f31b4 = NULL; + if (((MxControlPresenter*) control)->GetEnabledChild() == 0) { + g_clickedObjectId = -1; + g_clickedAtom = NULL; break; } } @@ -145,7 +145,7 @@ void LegoControlManager::FUN_100293c0(MxU32 p_objectId, const char* p_atom, MxS1 // FUNCTION: LEGO1 0x100294e0 // FUNCTION: BETA10 0x1007c92f -MxControlPresenter* LegoControlManager::FUN_100294e0(MxS32 p_x, MxS32 p_y) +MxControlPresenter* LegoControlManager::GetControlAt(MxS32 p_x, MxS32 p_y) { if (m_presenterList) { MxPresenterListCursor cursor(m_presenterList); @@ -154,7 +154,7 @@ MxControlPresenter* LegoControlManager::FUN_100294e0(MxS32 p_x, MxS32 p_y) if (presenter) { while (cursor.Next(control)) { - if (((MxControlPresenter*) control)->FUN_10044270(p_x, p_y, presenter)) { + if (((MxControlPresenter*) control)->CheckButtonDown(p_x, p_y, presenter)) { return (MxControlPresenter*) control; } } @@ -167,29 +167,29 @@ MxControlPresenter* LegoControlManager::FUN_100294e0(MxS32 p_x, MxS32 p_y) // FUNCTION: LEGO1 0x10029600 MxResult LegoControlManager::Tickle() { - if (m_unk0x08 == 2 && m_unk0x0c == 1) { + if (m_buttonDownState == e_tickled && m_handleUpNextTickle == 1) { m_event.SetNotification(c_notificationButtonUp); - FUN_10029750(); + HandleButtonUp(); return 0; } - else if (m_unk0x08 == 1) { - m_unk0x08 = 2; + else if (m_buttonDownState == e_waitNextTickle) { + m_buttonDownState = e_tickled; } return 0; } // FUNCTION: LEGO1 0x10029630 -MxBool LegoControlManager::FUN_10029630() +MxBool LegoControlManager::HandleButtonDown() { MxPresenterListCursor cursor(m_presenterList); MxPresenter* presenter; while (cursor.Next(presenter)) { - if (((MxControlPresenter*) presenter)->FUN_10044480(&m_event, m_unk0x14)) { - g_unk0x100f31b0 = m_event.m_clickedObjectId; - g_unk0x100f31b4 = m_event.GetClickedAtom(); - FUN_100292e0(); - m_unk0x08 = 1; + if (((MxControlPresenter*) presenter)->Notify(&m_event, m_handledPresenter)) { + g_clickedObjectId = m_event.m_clickedObjectId; + g_clickedAtom = m_event.GetClickedAtom(); + Notify(); + m_buttonDownState = e_waitNextTickle; return TRUE; } } @@ -198,29 +198,29 @@ MxBool LegoControlManager::FUN_10029630() } // FUNCTION: LEGO1 0x10029750 -MxBool LegoControlManager::FUN_10029750() +MxBool LegoControlManager::HandleButtonUp() { MxPresenterListCursor cursor(m_presenterList); MxPresenter* presenter; while (cursor.Next(presenter)) { - if (presenter->GetAction() && presenter->GetAction()->GetObjectId() == g_unk0x100f31b0 && - presenter->GetAction()->GetAtomId().GetInternal() == g_unk0x100f31b4) { - if (((MxControlPresenter*) presenter)->FUN_10044480(&m_event, m_unk0x14)) { - FUN_100292e0(); + if (presenter->GetAction() && presenter->GetAction()->GetObjectId() == g_clickedObjectId && + presenter->GetAction()->GetAtomId().GetInternal() == g_clickedAtom) { + if (((MxControlPresenter*) presenter)->Notify(&m_event, m_handledPresenter)) { + Notify(); } - g_unk0x100f31b0 = -1; - g_unk0x100f31b4 = NULL; + g_clickedObjectId = -1; + g_clickedAtom = NULL; - m_unk0x08 = 0; - m_unk0x0c = 0; + m_buttonDownState = e_idle; + m_handleUpNextTickle = 0; return TRUE; } } - g_unk0x100f31b0 = -1; - g_unk0x100f31b4 = NULL; + g_clickedObjectId = -1; + g_clickedAtom = NULL; return FALSE; } diff --git a/LEGO1/lego/legoomni/src/entity/legoactor.cpp b/LEGO1/lego/legoomni/src/entity/legoactor.cpp index 34ba9fb8..477bf529 100644 --- a/LEGO1/lego/legoomni/src/entity/legoactor.cpp +++ b/LEGO1/lego/legoomni/src/entity/legoactor.cpp @@ -20,7 +20,7 @@ LegoActor::LegoActor() m_frequencyFactor = 0.0f; m_sound = NULL; m_unk0x70 = 0.0f; - m_unk0x10 = 0; + m_interaction = 0; m_actorId = 0; } diff --git a/LEGO1/lego/legoomni/src/entity/legocameracontroller.cpp b/LEGO1/lego/legoomni/src/entity/legocameracontroller.cpp index 563ba615..cac7d66a 100644 --- a/LEGO1/lego/legoomni/src/entity/legocameracontroller.cpp +++ b/LEGO1/lego/legoomni/src/entity/legocameracontroller.cpp @@ -41,6 +41,10 @@ MxResult LegoCameraController::Create() // FUNCTION: BETA10 0x10067852 MxLong LegoCameraController::Notify(MxParam& p_param) { + if (((LegoEventNotificationParam&) p_param).GetModifier() & LegoEventNotificationParam::c_motionHandled) { + return SUCCESS; + } + switch (((MxNotificationParam&) p_param).GetNotification()) { case c_notificationDragEnd: { if (((((LegoEventNotificationParam&) p_param).GetModifier()) & LegoEventNotificationParam::c_lButtonState) == @@ -120,28 +124,28 @@ void LegoCameraController::OnMouseMove(MxU8 p_modifier, MxPoint32 p_point) // FUNCTION: LEGO1 0x10012260 void LegoCameraController::SetWorldTransform(const Vector3& p_at, const Vector3& p_dir, const Vector3& p_up) { - CalcLocalTransform(p_at, p_dir, p_up, m_matrix1); - m_matrix2 = m_matrix1; + CalcLocalTransform(p_at, p_dir, p_up, m_currentTransform); + m_originalTransform = m_currentTransform; } // FUNCTION: LEGO1 0x10012290 // FUNCTION: BETA10 0x10068c34 -void LegoCameraController::FUN_10012290(float p_angle) +void LegoCameraController::RotateZ(float p_angle) { - m_matrix1 = m_matrix2; - m_matrix1.RotateZ(p_angle); + m_currentTransform = m_originalTransform; + m_currentTransform.RotateZ(p_angle); } // FUNCTION: LEGO1 0x10012320 // FUNCTION: BETA10 0x10068c73 -void LegoCameraController::FUN_10012320(float p_angle) +void LegoCameraController::RotateY(float p_angle) { - m_matrix1 = m_matrix2; - m_matrix1.RotateY(p_angle); + m_currentTransform = m_originalTransform; + m_currentTransform.RotateY(p_angle); } // FUNCTION: LEGO1 0x100123b0 -MxResult LegoCameraController::FUN_100123b0(Matrix4& p_matrix) +MxResult LegoCameraController::GetPointOfView(Matrix4& p_matrix) { if (m_lego3DView) { ViewROI* pov = m_lego3DView->GetPointOfView(); @@ -156,7 +160,7 @@ MxResult LegoCameraController::FUN_100123b0(Matrix4& p_matrix) // FUNCTION: LEGO1 0x100123e0 // FUNCTION: BETA10 0x10068cb2 -void LegoCameraController::FUN_100123e0(const Matrix4& p_transform, MxU32 p_und) +void LegoCameraController::TransformPointOfView(const Matrix4& p_transform, MxU32 p_multiply) { if (m_lego3DView != NULL) { ViewROI* pov = m_lego3DView->GetPointOfView(); @@ -164,14 +168,14 @@ void LegoCameraController::FUN_100123e0(const Matrix4& p_transform, MxU32 p_und) if (pov != NULL) { MxMatrix mat; - if (p_und) { - MXM4(mat, m_matrix1, p_transform); + if (p_multiply) { + MXM4(mat, m_currentTransform, p_transform); } else { mat = p_transform; } - ((TimeROI*) pov)->FUN_100a9b40(mat, Timer()->GetTime()); + ((TimeROI*) pov)->CalculateWorldVelocity(mat, Timer()->GetTime()); pov->WrappedSetLocal2WorldWithWorldDataUpdate(mat); m_lego3DView->Moved(*pov); diff --git a/LEGO1/lego/legoomni/src/entity/legoentity.cpp b/LEGO1/lego/legoomni/src/entity/legoentity.cpp index 148d4c16..927d8125 100644 --- a/LEGO1/lego/legoomni/src/entity/legoentity.cpp +++ b/LEGO1/lego/legoomni/src/entity/legoentity.cpp @@ -31,7 +31,7 @@ void LegoEntity::Init() m_roi = NULL; m_cameraFlag = FALSE; m_siFile = NULL; - m_unk0x10 = 0; + m_interaction = 0; m_flags = 0; m_actionType = Extra::ActionType::e_unknown; m_targetEntityId = -1; @@ -197,7 +197,7 @@ void LegoEntity::FUN_10010c30() LegoWorld* world = CurrentWorld(); if (m_cameraFlag && world && world->GetCameraController() && m_roi) { - world->GetCameraController()->FUN_100123e0(m_roi->GetLocal2World(), 1); + world->GetCameraController()->TransformPointOfView(m_roi->GetLocal2World(), 1); } } @@ -266,23 +266,23 @@ void LegoEntity::ParseAction(char* p_extra) // FUNCTION: LEGO1 0x10010f10 // FUNCTION: BETA10 0x1007ee87 -void LegoEntity::ClickSound(MxBool p_und) +void LegoEntity::ClickSound(MxBool p_basedOnMood) { - if (!GetUnknown0x10IsSet(c_altBit1)) { + if (!IsInteraction(c_disabled)) { MxU32 objectId = 0; const char* name = m_roi->GetName(); switch (m_type) { case e_actor: - objectId = CharacterManager()->GetSoundId(m_roi, p_und); + objectId = CharacterManager()->GetSoundId(m_roi, p_basedOnMood); break; case e_unk1: break; case e_plant: - objectId = PlantManager()->GetSoundId(this, p_und); + objectId = PlantManager()->GetSoundId(this, p_basedOnMood); break; case e_building: - objectId = BuildingManager()->GetSoundId(this, p_und); + objectId = BuildingManager()->GetSoundId(this, p_basedOnMood); break; } @@ -300,7 +300,7 @@ void LegoEntity::ClickSound(MxBool p_und) // FUNCTION: BETA10 0x1007f062 void LegoEntity::ClickAnimation() { - if (!GetUnknown0x10IsSet(c_altBit1)) { + if (!IsInteraction(c_disabled)) { MxU32 objectId = 0; MxDSAction action; const char* name = m_roi->GetName(); @@ -332,7 +332,7 @@ void LegoEntity::ClickAnimation() action.SetObjectId(objectId); action.AppendExtra(strlen(extra) + 1, extra); LegoOmni::GetInstance()->GetAnimationManager()->StartEntityAction(action, this); - m_unk0x10 |= c_altBit1; + m_interaction |= c_disabled; } } } diff --git a/LEGO1/lego/legoomni/src/entity/legonavcontroller.cpp b/LEGO1/lego/legoomni/src/entity/legonavcontroller.cpp index 407fa3cb..c1cfc87a 100644 --- a/LEGO1/lego/legoomni/src/entity/legonavcontroller.cpp +++ b/LEGO1/lego/legoomni/src/entity/legonavcontroller.cpp @@ -555,7 +555,7 @@ MxResult LegoNavController::ProcessJoystickInput(MxBool& p_und) LegoWorld* world = CurrentWorld(); if (world && world->GetCameraController()) { - world->GetCameraController()->FUN_10012320(DTOR(povPosition)); + world->GetCameraController()->RotateY(DTOR(povPosition)); p_und = TRUE; } } @@ -697,7 +697,7 @@ MxLong LegoNavController::Notify(MxParam& p_param) for (MxS32 i = 0; i < numPlants; i++) { LegoEntity* entity = plantMgr->CreatePlant(i, NULL, LegoOmni::e_act1); - if (entity != NULL && !entity->GetUnknown0x10IsSet(LegoEntity::c_altBit1)) { + if (entity != NULL && !entity->IsInteraction(LegoEntity::c_disabled)) { LegoROI* roi = entity->GetROI(); if (roi != NULL && roi->GetVisibility()) { @@ -902,7 +902,7 @@ MxLong LegoNavController::Notify(MxParam& p_param) break; case SDLK_A: if (g_animationCalcStep == 1) { - Lego()->m_unk0x13c = TRUE; + Lego()->m_initialized = TRUE; AnimationManager()->FUN_10060570(TRUE); g_animationCalcStep = 0; } diff --git a/LEGO1/lego/legoomni/src/entity/legopovcontroller.cpp b/LEGO1/lego/legoomni/src/entity/legopovcontroller.cpp index 7541e98b..fc823c60 100644 --- a/LEGO1/lego/legoomni/src/entity/legopovcontroller.cpp +++ b/LEGO1/lego/legoomni/src/entity/legopovcontroller.cpp @@ -153,7 +153,7 @@ MxResult LegoPointOfViewController::Tickle() MxMatrix mat; CalcLocalTransform(newPos, newDir, pov->GetWorldUp(), mat); - ((TimeROI*) pov)->FUN_100a9b40(mat, Timer()->GetTime()); + ((TimeROI*) pov)->CalculateWorldVelocity(mat, Timer()->GetTime()); pov->WrappedSetLocal2WorldWithWorldDataUpdate(mat); m_lego3DView->Moved(*pov); diff --git a/LEGO1/lego/legoomni/src/entity/legoworld.cpp b/LEGO1/lego/legoomni/src/entity/legoworld.cpp index 90f56d10..1ba828cb 100644 --- a/LEGO1/lego/legoomni/src/entity/legoworld.cpp +++ b/LEGO1/lego/legoomni/src/entity/legoworld.cpp @@ -9,7 +9,6 @@ #include "legocontrolmanager.h" #include "legogamestate.h" #include "legoinputmanager.h" -#include "legolocomotionanimpresenter.h" #include "legonavcontroller.h" #include "legoplantmanager.h" #include "legosoundmanager.h" @@ -83,7 +82,7 @@ MxResult LegoWorld::Create(MxDSAction& p_dsAction) } SetCurrentWorld(this); - ControlManager()->FUN_10028df0(&m_controlPresenters); + ControlManager()->SetPresenterList(&m_controlPresenters); } SetIsWorldActive(TRUE); @@ -98,7 +97,7 @@ void LegoWorld::Destroy(MxBool p_fromDestructor) m_destroyed = TRUE; if (CurrentWorld() == this) { - ControlManager()->FUN_10028df0(NULL); + ControlManager()->SetPresenterList(NULL); SetCurrentWorld(NULL); } @@ -122,12 +121,12 @@ void LegoWorld::Destroy(MxBool p_fromDestructor) animPresenter->DecrementUnknown0xd4(); if (animPresenter->GetUnknown0xd4() == 0) { - FUN_100b7220(action, MxDSAction::c_world, FALSE); + ApplyMask(action, MxDSAction::c_world, FALSE); presenter->EndAction(); } } else { - FUN_100b7220(action, MxDSAction::c_world, FALSE); + ApplyMask(action, MxDSAction::c_world, FALSE); presenter->EndAction(); } } @@ -143,7 +142,7 @@ void LegoWorld::Destroy(MxBool p_fromDestructor) MxDSAction* action = presenter->GetAction(); if (action) { - FUN_100b7220(action, MxDSAction::c_world, FALSE); + ApplyMask(action, MxDSAction::c_world, FALSE); presenter->EndAction(); } } @@ -159,7 +158,7 @@ void LegoWorld::Destroy(MxBool p_fromDestructor) MxDSAction* action = presenter->GetAction(); if (action) { - FUN_100b7220(action, MxDSAction::c_world, FALSE); + ApplyMask(action, MxDSAction::c_world, FALSE); presenter->EndAction(); } } @@ -288,6 +287,7 @@ MxResult LegoWorld::PlaceActor( } // FUNCTION: LEGO1 0x1001fa70 +// FUNCTION: BETA10 0x100da328 MxResult LegoWorld::PlaceActor(LegoPathActor* p_actor) { LegoPathControllerListCursor cursor(&m_pathControllerList); @@ -303,6 +303,7 @@ MxResult LegoWorld::PlaceActor(LegoPathActor* p_actor) } // FUNCTION: LEGO1 0x1001fb70 +// FUNCTION: BETA10 0x100da3f1 MxResult LegoWorld::PlaceActor( LegoPathActor* p_actor, LegoAnimPresenter* p_presenter, @@ -426,7 +427,7 @@ void LegoWorld::Add(MxCore* p_object) #ifndef BETA10 if (p_object->IsA("LegoAnimPresenter")) { if (!SDL_strcasecmp(((LegoAnimPresenter*) p_object)->GetAction()->GetObjectName(), "ConfigAnimation")) { - FUN_1003e050((LegoAnimPresenter*) p_object); + CalculateViewFromAnimation((LegoAnimPresenter*) p_object); ((LegoAnimPresenter*) p_object) ->GetAction() ->SetDuration(((LegoAnimPresenter*) p_object)->GetAnimation()->GetDuration()); @@ -724,7 +725,7 @@ void LegoWorld::Enable(MxBool p_enable) } SetCurrentWorld(this); - ControlManager()->FUN_10028df0(&m_controlPresenters); + ControlManager()->SetPresenterList(&m_controlPresenters); InputManager()->SetCamera(m_cameraController); if (m_cameraController) { @@ -781,7 +782,7 @@ void LegoWorld::Enable(MxBool p_enable) } if (CurrentWorld() && CurrentWorld() == this) { - ControlManager()->FUN_10028df0(NULL); + ControlManager()->SetPresenterList(NULL); Lego()->SetCurrentWorld(NULL); } diff --git a/LEGO1/lego/legoomni/src/entity/legoworldpresenter.cpp b/LEGO1/lego/legoomni/src/entity/legoworldpresenter.cpp index 00b877bd..abf6c32a 100644 --- a/LEGO1/lego/legoomni/src/entity/legoworldpresenter.cpp +++ b/LEGO1/lego/legoomni/src/entity/legoworldpresenter.cpp @@ -63,7 +63,7 @@ LegoWorldPresenter::~LegoWorldPresenter() } if (result == FALSE) { - FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + Disable(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); } if (m_entity) { @@ -260,8 +260,12 @@ MxResult LegoWorldPresenter::LoadWorld(char* p_worldName, LegoWorld* p_world) ModelDbPart* part; while (cursor.Next(part)) { - if (GetViewLODListManager()->Lookup(part->m_roiName.GetData()) == NULL && - LoadWorldPart(*part, wdbFile) != SUCCESS) { + ViewLODList* lodList = GetViewLODListManager()->Lookup(part->m_roiName.GetData()); + if (lodList) { + lodList->Release(); + } + + if (lodList == NULL && LoadWorldPart(*part, wdbFile) != SUCCESS) { return FAILURE; } } @@ -393,7 +397,7 @@ MxResult LegoWorldPresenter::LoadWorldModel(ModelDbModel& p_model, SDL_IOStream* } modelPresenter.SetAction(&action); - modelPresenter.FUN_1007ff70(chunk, createdEntity, p_model.m_visible, p_world); + modelPresenter.CreateROI(chunk, createdEntity, p_model.m_visible, p_world); delete[] buff; return SUCCESS; diff --git a/LEGO1/lego/legoomni/src/input/legoinputmanager.cpp b/LEGO1/lego/legoomni/src/input/legoinputmanager.cpp index 3e9622c2..61dfa9bc 100644 --- a/LEGO1/lego/legoomni/src/input/legoinputmanager.cpp +++ b/LEGO1/lego/legoomni/src/input/legoinputmanager.cpp @@ -11,16 +11,18 @@ #include "mxdebug.h" #include "roi/legoroi.h" +#include + DECOMP_SIZE_ASSERT(LegoInputManager, 0x338) DECOMP_SIZE_ASSERT(LegoNotifyList, 0x18) DECOMP_SIZE_ASSERT(LegoNotifyListCursor, 0x10) DECOMP_SIZE_ASSERT(LegoEventQueue, 0x18) // GLOBAL: LEGO1 0x100f31b0 -MxS32 g_unk0x100f31b0 = -1; +MxS32 g_clickedObjectId = -1; // GLOBAL: LEGO1 0x100f31b4 -const char* g_unk0x100f31b4 = NULL; +const char* g_clickedAtom = NULL; // GLOBAL: LEGO1 0x100f67b8 MxBool g_unk0x100f67b8 = TRUE; @@ -40,10 +42,6 @@ LegoInputManager::LegoInputManager() m_unk0x81 = FALSE; m_unk0x88 = FALSE; m_unk0x195 = 0; - m_joyids = NULL; - m_joystickIndex = -1; - m_joystick = NULL; - m_useJoystick = FALSE; m_unk0x335 = FALSE; m_unk0x336 = FALSE; m_unk0x74 = 0x19; @@ -71,8 +69,6 @@ MxResult LegoInputManager::Create(HWND p_hwnd) m_eventQueue = new LegoEventQueue; } - GetJoystick(); - if (!m_keyboardNotifyList || !m_eventQueue) { Destroy(); result = FAILURE; @@ -98,7 +94,23 @@ void LegoInputManager::Destroy() delete m_controlManager; } - SDL_free(m_joyids); + for (const auto& [id, joystick] : m_joysticks) { + if (joystick.second) { + SDL_CloseHaptic(joystick.second); + } + + SDL_CloseGamepad(joystick.first); + } + + for (const auto& [id, mouse] : m_mice) { + if (mouse.second) { + SDL_CloseHaptic(mouse.second); + } + } + + for (const auto& [id, haptic] : m_otherHaptics) { + SDL_CloseHaptic(haptic); + } } // FUNCTION: LEGO1 0x1005c0f0 @@ -145,97 +157,39 @@ MxResult LegoInputManager::GetNavigationKeyStates(MxU32& p_keyFlags) return SUCCESS; } -// FUNCTION: LEGO1 0x1005c240 -MxResult LegoInputManager::GetJoystick() -{ - if (m_joystick != NULL && SDL_JoystickConnected(m_joystick) == TRUE) { - return SUCCESS; - } - - MxS32 numJoysticks = 0; - if (m_joyids == NULL) { - m_joyids = SDL_GetJoysticks(&numJoysticks); - } - - if (m_useJoystick != FALSE && numJoysticks != 0) { - MxS32 joyid = m_joystickIndex; - if (joyid >= 0) { - m_joystick = SDL_OpenJoystick(m_joyids[joyid]); - if (m_joystick != NULL) { - return SUCCESS; - } - } - - for (joyid = 0; joyid < numJoysticks; joyid++) { - m_joystick = SDL_OpenJoystick(m_joyids[joyid]); - if (m_joystick != NULL) { - return SUCCESS; - } - } - } - - return FAILURE; -} - // FUNCTION: LEGO1 0x1005c320 MxResult LegoInputManager::GetJoystickState(MxU32* p_joystickX, MxU32* p_joystickY, MxU32* p_povPosition) { - if (m_useJoystick != FALSE) { - if (GetJoystick() == -1) { - if (m_joystick != NULL) { - // GetJoystick() failed but handle to joystick is still open, close it - SDL_CloseJoystick(m_joystick); - m_joystick = NULL; - } - - return FAILURE; - } - - MxS16 xPos = SDL_GetJoystickAxis(m_joystick, 0); - MxS16 yPos = SDL_GetJoystickAxis(m_joystick, 1); - MxU8 hatPos = SDL_GetJoystickHat(m_joystick, 0); - - // normalize values acquired from joystick axes - *p_joystickX = ((xPos + 32768) * 100) / 65535; - *p_joystickY = ((yPos + 32768) * 100) / 65535; - - switch (hatPos) { - case SDL_HAT_CENTERED: - *p_povPosition = (MxU32) -1; - break; - case SDL_HAT_UP: - *p_povPosition = (MxU32) 0; - break; - case SDL_HAT_RIGHT: - *p_povPosition = (MxU32) 9000 / 100; - break; - case SDL_HAT_DOWN: - *p_povPosition = (MxU32) 18000 / 100; - break; - case SDL_HAT_LEFT: - *p_povPosition = (MxU32) 27000 / 100; - break; - case SDL_HAT_RIGHTUP: - *p_povPosition = (MxU32) 4500 / 100; - break; - case SDL_HAT_RIGHTDOWN: - *p_povPosition = (MxU32) 13500 / 100; - break; - case SDL_HAT_LEFTUP: - *p_povPosition = (MxU32) 31500 / 100; - break; - case SDL_HAT_LEFTDOWN: - *p_povPosition = (MxU32) 22500 / 100; - break; - default: - *p_povPosition = (MxU32) -1; - break; - } - - return SUCCESS; + if (!std::holds_alternative(m_lastInputMethod) && + !(std::holds_alternative(m_lastInputMethod) && m_touchScheme == e_gamepad)) { + return FAILURE; } - return FAILURE; + MxS16 xPos, yPos = 0; + for (const auto& [id, joystick] : m_joysticks) { + xPos = SDL_GetGamepadAxis(joystick.first, SDL_GAMEPAD_AXIS_LEFTX); + yPos = SDL_GetGamepadAxis(joystick.first, SDL_GAMEPAD_AXIS_LEFTY); + if (xPos > -8000 && xPos < 8000) { + xPos = 0; + } + if (yPos > -8000 && yPos < 8000) { + yPos = 0; + } + + if (xPos || yPos) { + break; + } + } + + if (!xPos && !yPos) { + xPos = m_touchVirtualThumb.x; + yPos = m_touchVirtualThumb.y; + } + + *p_joystickX = ((xPos + 32768) * 100) / 65535; + *p_joystickY = ((yPos + 32768) * 100) / 65535; + *p_povPosition = -1; + return SUCCESS; } // FUNCTION: LEGO1 0x1005c470 @@ -377,23 +331,23 @@ MxBool LegoInputManager::ProcessOneEvent(LegoEventNotificationParam& p_param) if (presenter->GetDisplayZ() < 0) { processRoi = FALSE; - if (m_controlManager->FUN_10029210(p_param, presenter)) { + if (m_controlManager->HandleButtonDown(p_param, presenter)) { return TRUE; } } else { LegoROI* roi = PickROI(p_param.GetX(), p_param.GetY()); - if (roi == NULL && m_controlManager->FUN_10029210(p_param, presenter)) { + if (roi == NULL && m_controlManager->HandleButtonDown(p_param, presenter)) { return TRUE; } } } } else if (p_param.GetNotification() == c_notificationButtonUp) { - if (g_unk0x100f31b0 != -1 || m_controlManager->GetUnknown0x10() || - m_controlManager->GetUnknown0x0c() == 1) { - MxBool result = m_controlManager->FUN_10029210(p_param, NULL); + if (g_clickedObjectId != -1 || m_controlManager->IsSecondButtonDown() || + m_controlManager->HandleUpNextTickle() == 1) { + MxBool result = m_controlManager->HandleButtonDown(p_param, NULL); StopAutoDragTimer(); m_unk0x80 = FALSE; @@ -545,48 +499,306 @@ void LegoInputManager::StopAutoDragTimer() void LegoInputManager::EnableInputProcessing() { m_unk0x88 = FALSE; - g_unk0x100f31b0 = -1; - g_unk0x100f31b4 = NULL; + g_clickedObjectId = -1; + g_clickedAtom = NULL; } MxResult LegoInputManager::GetNavigationTouchStates(MxU32& p_keyStates) { - int count; - SDL_TouchID* touchDevices = SDL_GetTouchDevices(&count); - - if (touchDevices) { - auto applyFingerNavigation = [&p_keyStates](SDL_TouchID p_touchId) { - int count; - SDL_Finger** fingers = SDL_GetTouchFingers(p_touchId, &count); - - if (fingers) { - for (int i = 0; i < count; i++) { - if (fingers[i]->y > 3.0 / 4.0) { - if (fingers[i]->x < 1.0 / 3.0) { - p_keyStates |= c_left; - } - else if (fingers[i]->x > 2.0 / 3.0) { - p_keyStates |= c_right; - } - else { - p_keyStates |= c_down; - } - } - else { - p_keyStates |= c_up; - } - } - - SDL_free(fingers); - } - }; - - for (int i = 0; i < count; i++) { - applyFingerNavigation(touchDevices[i]); + if (m_touchScheme == e_arrowKeys) { + for (auto& [fingerID, touchFlags] : m_touchFlags) { + p_keyStates |= touchFlags; } - - SDL_free(touchDevices); } return SUCCESS; } + +void LegoInputManager::AddKeyboard(SDL_KeyboardID p_keyboardID) +{ + if (m_keyboards.count(p_keyboardID)) { + return; + } + + m_keyboards[p_keyboardID] = {nullptr, nullptr}; +} + +void LegoInputManager::RemoveKeyboard(SDL_KeyboardID p_keyboardID) +{ + if (!m_keyboards.count(p_keyboardID)) { + return; + } + + m_keyboards.erase(p_keyboardID); +} + +void LegoInputManager::AddMouse(SDL_MouseID p_mouseID) +{ + if (m_mice.count(p_mouseID)) { + return; + } + + // Currently no way to get an individual haptic device for a mouse. + SDL_Haptic* haptic = SDL_OpenHapticFromMouse(); + if (haptic) { + if (!SDL_InitHapticRumble(haptic)) { + SDL_CloseHaptic(haptic); + haptic = nullptr; + } + } + + m_mice[p_mouseID] = {nullptr, haptic}; +} + +void LegoInputManager::RemoveMouse(SDL_MouseID p_mouseID) +{ + if (!m_mice.count(p_mouseID)) { + return; + } + + if (m_mice[p_mouseID].second) { + SDL_CloseHaptic(m_mice[p_mouseID].second); + } + + m_mice.erase(p_mouseID); +} + +void LegoInputManager::AddJoystick(SDL_JoystickID p_joystickID) +{ + if (m_joysticks.count(p_joystickID)) { + return; + } + + SDL_Gamepad* joystick = SDL_OpenGamepad(p_joystickID); + if (joystick) { + SDL_Haptic* haptic = SDL_OpenHapticFromJoystick(SDL_GetGamepadJoystick(joystick)); + if (haptic) { + if (!SDL_InitHapticRumble(haptic)) { + SDL_CloseHaptic(haptic); + haptic = nullptr; + } + } + + m_joysticks[p_joystickID] = {joystick, haptic}; + } + else { + SDL_Log("Failed to open gamepad: %s", SDL_GetError()); + } +} + +void LegoInputManager::RemoveJoystick(SDL_JoystickID p_joystickID) +{ + if (!m_joysticks.count(p_joystickID)) { + return; + } + + if (m_joysticks[p_joystickID].second) { + SDL_CloseHaptic(m_joysticks[p_joystickID].second); + } + + SDL_CloseGamepad(m_joysticks[p_joystickID].first); + m_joysticks.erase(p_joystickID); +} + +MxBool LegoInputManager::HandleTouchEvent(SDL_Event* p_event, TouchScheme p_touchScheme) +{ + const SDL_TouchFingerEvent& event = p_event->tfinger; + m_touchScheme = p_touchScheme; + + switch (p_touchScheme) { + case e_mouse: + // Handled in LegoCameraController + return FALSE; + case e_arrowKeys: + switch (p_event->type) { + case SDL_EVENT_FINGER_UP: + case SDL_EVENT_FINGER_CANCELED: + m_touchFlags.erase(event.fingerID); + break; + case SDL_EVENT_FINGER_DOWN: + case SDL_EVENT_FINGER_MOTION: + m_touchFlags[event.fingerID] = 0; + + if (event.y > 3.0 / 4.0) { + if (event.x < 1.0 / 3.0) { + m_touchFlags[event.fingerID] |= c_left; + } + else if (event.x > 2.0 / 3.0) { + m_touchFlags[event.fingerID] |= c_right; + } + else { + m_touchFlags[event.fingerID] |= c_down; + } + } + else { + m_touchFlags[event.fingerID] |= c_up; + } + break; + } + break; + case e_gamepad: { + static SDL_FingerID g_finger = (SDL_FingerID) 0; + + switch (p_event->type) { + case SDL_EVENT_FINGER_DOWN: + if (!g_finger) { + g_finger = event.fingerID; + m_touchVirtualThumb = {0, 0}; + m_touchVirtualThumbOrigin = {event.x, event.y}; + } + break; + case SDL_EVENT_FINGER_UP: + case SDL_EVENT_FINGER_CANCELED: + if (event.fingerID == g_finger) { + g_finger = 0; + m_touchVirtualThumb = {0, 0}; + m_touchVirtualThumbOrigin = {0, 0}; + } + break; + case SDL_EVENT_FINGER_MOTION: + if (event.fingerID == g_finger) { + const float thumbstickRadius = 0.25f; + const float deltaX = + SDL_clamp(event.x - m_touchVirtualThumbOrigin.x, -thumbstickRadius, thumbstickRadius); + const float deltaY = + SDL_clamp(event.y - m_touchVirtualThumbOrigin.y, -thumbstickRadius, thumbstickRadius); + + m_touchVirtualThumb = { + (int) (deltaX / thumbstickRadius * 32767.0f), + (int) (deltaY / thumbstickRadius * 32767.0f), + }; + } + break; + } + break; + } + } + + return TRUE; +} + +MxBool LegoInputManager::HandleRumbleEvent( + float p_strength, + float p_lowFrequencyRumble, + float p_highFrequencyRumble, + MxU32 p_milliseconds +) +{ + static bool g_hapticsInitialized = false; + + if (!g_hapticsInitialized) { + InitializeHaptics(); + g_hapticsInitialized = true; + } + + SDL_Haptic* haptic = nullptr; + std::visit( + overloaded{ + [](SDL_KeyboardID_v p_id) {}, + [&haptic, this](SDL_MouseID_v p_id) { + if (m_mice.count((SDL_MouseID) p_id)) { + haptic = m_mice[(SDL_MouseID) p_id].second; + } + }, + [&haptic, this](SDL_JoystickID_v p_id) { + if (m_joysticks.count((SDL_JoystickID) p_id)) { + haptic = m_joysticks[(SDL_JoystickID) p_id].second; + } + }, + [&haptic, this](SDL_TouchID_v p_id) { + // We can't currently correlate Touch devices with Haptic devices + if (!m_otherHaptics.empty()) { + haptic = m_otherHaptics.begin()->second; + } + } + }, + m_lastInputMethod + ); + + if (haptic) { + return SDL_PlayHapticRumble(haptic, p_strength, p_milliseconds); + } + + // A joystick isn't necessarily a haptic device; try basic rumble instead + if (const SDL_JoystickID_v* joystick = std::get_if(&m_lastInputMethod)) { + if (m_joysticks.count((SDL_JoystickID) *joystick)) { + return SDL_RumbleGamepad( + m_joysticks[(SDL_JoystickID) *joystick].first, + SDL_clamp(p_lowFrequencyRumble, 0, 1) * USHRT_MAX, + SDL_clamp(p_highFrequencyRumble, 0, 1) * USHRT_MAX, + p_milliseconds + ); + } + } + + return FALSE; +} + +void LegoInputManager::InitializeHaptics() +{ + // We don't get added/removed events for haptic devices that are not joysticks or mice, + // so we initialize "otherHaptics" once at this point. + std::vector existingHaptics; + + for (const auto& [id, mouse] : m_mice) { + if (mouse.second) { + existingHaptics.push_back(SDL_GetHapticID(mouse.second)); + } + } + + for (const auto& [id, joystick] : m_joysticks) { + if (joystick.second) { + existingHaptics.push_back(SDL_GetHapticID(joystick.second)); + } + } + + int count; + SDL_HapticID* haptics = SDL_GetHaptics(&count); + if (haptics) { + for (int i = 0; i < count; i++) { + if (std::find(existingHaptics.begin(), existingHaptics.end(), haptics[i]) == existingHaptics.end()) { + SDL_Haptic* haptic = SDL_OpenHaptic(haptics[i]); + if (haptic) { + if (SDL_InitHapticRumble(haptic)) { + m_otherHaptics[haptics[i]] = haptic; + } + else { + SDL_CloseHaptic(haptic); + } + } + } + } + + SDL_free(haptics); + } +} + +void LegoInputManager::UpdateLastInputMethod(SDL_Event* p_event) +{ + switch (p_event->type) { + case SDL_EVENT_KEY_DOWN: + case SDL_EVENT_KEY_UP: + m_lastInputMethod = SDL_KeyboardID_v{p_event->key.which}; + break; + case SDL_EVENT_MOUSE_BUTTON_DOWN: + case SDL_EVENT_MOUSE_BUTTON_UP: + m_lastInputMethod = SDL_MouseID_v{p_event->button.which}; + break; + case SDL_EVENT_MOUSE_MOTION: + m_lastInputMethod = SDL_MouseID_v{p_event->motion.which}; + break; + case SDL_EVENT_GAMEPAD_BUTTON_DOWN: + case SDL_EVENT_GAMEPAD_BUTTON_UP: + m_lastInputMethod = SDL_JoystickID_v{p_event->gbutton.which}; + break; + case SDL_EVENT_GAMEPAD_AXIS_MOTION: + m_lastInputMethod = SDL_JoystickID_v{p_event->gaxis.which}; + break; + case SDL_EVENT_FINGER_MOTION: + case SDL_EVENT_FINGER_DOWN: + case SDL_EVENT_FINGER_UP: + case SDL_EVENT_FINGER_CANCELED: + m_lastInputMethod = SDL_TouchID_v{p_event->tfinger.touchID}; + break; + } +} diff --git a/LEGO1/lego/legoomni/src/main/legomain.cpp b/LEGO1/lego/legoomni/src/main/legomain.cpp index 3b99f0b5..e2105797 100644 --- a/LEGO1/lego/legoomni/src/main/legomain.cpp +++ b/LEGO1/lego/legoomni/src/main/legomain.cpp @@ -74,8 +74,9 @@ void LegoOmni::Init() m_animationManager = NULL; m_buildingManager = NULL; m_bkgAudioManager = NULL; - m_unk0x13c = TRUE; + m_initialized = TRUE; m_transitionManager = NULL; + m_version10 = FALSE; } // FUNCTION: LEGO1 0x10058c30 @@ -121,6 +122,8 @@ void LegoOmni::Destroy() m_textureContainer = NULL; } + LegoPartPresenter::Release(); + if (m_viewLODListManager) { delete m_viewLODListManager; m_viewLODListManager = NULL; @@ -542,26 +545,36 @@ LegoOmni::World LegoOmni::GetWorldId(const char* p_key) } // FUNCTION: LEGO1 0x1005b4f0 -void LegoOmni::FUN_1005b4f0(MxBool p_disable, MxU16 p_flags) +// FUNCTION: BETA10 0x1008eeec +void LegoOmni::Disable(MxBool p_disable, MxU16 p_flags) { - if (p_disable) { - if (p_flags & c_disableInput) { - m_inputManager->DisableInputProcessing(); - } +#ifdef BETA10 + if (this->m_paused != p_disable) { + // This is probably a different variable, but this code was mostly added for structural matching + m_paused = p_disable; +#endif - if (p_flags & c_disable3d) { - ((LegoVideoManager*) m_videoManager)->SetRender3D(FALSE); - } + if (p_disable) { + if (p_flags & c_disableInput) { + m_inputManager->DisableInputProcessing(); + } - if (p_flags & c_clearScreen) { - m_videoManager->GetDisplaySurface()->ClearScreen(); + if (p_flags & c_disable3d) { + ((LegoVideoManager*) m_videoManager)->SetRender3D(FALSE); + } + + if (p_flags & c_clearScreen) { + m_videoManager->GetDisplaySurface()->ClearScreen(); + } } + else { + m_inputManager->EnableInputProcessing(); + ((LegoVideoManager*) m_videoManager)->SetRender3D(TRUE); + ((LegoVideoManager*) m_videoManager)->UpdateView(0, 0, 0, 0); + } +#ifdef BETA10 } - else { - m_inputManager->EnableInputProcessing(); - ((LegoVideoManager*) m_videoManager)->SetRender3D(TRUE); - ((LegoVideoManager*) m_videoManager)->UpdateView(0, 0, 0, 0); - } +#endif } // FUNCTION: LEGO1 0x1005b560 diff --git a/LEGO1/lego/legoomni/src/paths/legoanimactor.cpp b/LEGO1/lego/legoomni/src/paths/legoanimactor.cpp index 182945d5..0a1e6d98 100644 --- a/LEGO1/lego/legoomni/src/paths/legoanimactor.cpp +++ b/LEGO1/lego/legoomni/src/paths/legoanimactor.cpp @@ -2,7 +2,7 @@ #include "anim/legoanim.h" #include "define.h" -#include "legolocomotionanimpresenter.h" +#include "legoanimpresenter.h" #include "legopathboundary.h" #include "legoworld.h" #include "misc.h" @@ -133,7 +133,7 @@ MxResult LegoAnimActor::FUN_1001c360(float p_und, Matrix4& p_transform) } for (MxS32 j = 0; j < n->GetNumChildren(); j++) { - LegoROI::FUN_100a8e80(n->GetChild(j), p_transform, p_und, roiMap); + LegoROI::ApplyAnimationTransformation(n->GetChild(j), p_transform, p_und, roiMap); } if (m_cameraFlag) { diff --git a/LEGO1/lego/legoomni/src/paths/legoextraactor.cpp b/LEGO1/lego/legoomni/src/paths/legoextraactor.cpp index 0a888b46..04c551d0 100644 --- a/LEGO1/lego/legoomni/src/paths/legoextraactor.cpp +++ b/LEGO1/lego/legoomni/src/paths/legoextraactor.cpp @@ -1,8 +1,8 @@ #include "legoextraactor.h" #include "anim/legoanim.h" +#include "legoanimpresenter.h" #include "legocachesoundmanager.h" -#include "legolocomotionanimpresenter.h" #include "legosoundmanager.h" #include "legoworld.h" #include "misc.h" @@ -235,6 +235,9 @@ MxResult LegoExtraActor::HitActor(LegoPathActor* p_actor, MxBool p_bool) assert(m_roi); assert(SoundManager()->GetCacheSoundManager()); SoundManager()->GetCacheSoundManager()->Play("crash5", m_roi->GetName(), FALSE); + if (p_actor->GetUserNavFlag()) { + EmitGameEvent(e_hitActor); + } m_scheduledTime = Timer()->GetTime() + m_disAnim->GetDuration(); m_prevWorldSpeed = GetWorldSpeed(); VTable0xc4(); @@ -248,6 +251,9 @@ MxResult LegoExtraActor::HitActor(LegoPathActor* p_actor, MxBool p_bool) LegoROI* roi = GetROI(); assert(roi); SoundManager()->GetCacheSoundManager()->Play("crash5", m_roi->GetName(), FALSE); + if (p_actor->GetUserNavFlag()) { + EmitGameEvent(e_hitActor); + } VTable0xc4(); SetActorState(c_two | c_noCollide); Mx3DPointFloat dir = p_actor->GetWorldDirection(); @@ -373,7 +379,7 @@ void LegoExtraActor::Animate(float p_time) MxS32 count = root->GetNumChildren(); for (MxS32 i = 0; i < count; i++) { - LegoROI::FUN_100a8e80(root->GetChild(i), matrix, duration2, laas->m_roiMap); + LegoROI::ApplyAnimationTransformation(root->GetChild(i), matrix, duration2, laas->m_roiMap); } } } diff --git a/LEGO1/lego/legoomni/src/paths/legopathactor.cpp b/LEGO1/lego/legoomni/src/paths/legopathactor.cpp index adf3390a..2e9ae767 100644 --- a/LEGO1/lego/legoomni/src/paths/legopathactor.cpp +++ b/LEGO1/lego/legoomni/src/paths/legopathactor.cpp @@ -37,7 +37,7 @@ const char* g_strHIT_WALL_SOUND = "HIT_WALL_SOUND"; // GLOBAL: LEGO1 0x100f3308 // GLOBAL: BETA10 0x101f1e1c -MxLong g_unk0x100f3308 = 0; +MxLong g_timeLastHitSoundPlayed = 0; // FUNCTION: LEGO1 0x1002d700 // FUNCTION: BETA10 0x100ae6e0 @@ -292,8 +292,8 @@ MxS32 LegoPathActor::VTable0x8c(float p_time, Matrix4& p_transform) if (m_boundary == oldBoundary) { MxLong time = Timer()->GetTime(); - if (time - g_unk0x100f3308 > 1000) { - g_unk0x100f3308 = time; + if (time - g_timeLastHitSoundPlayed > 1000) { + g_timeLastHitSoundPlayed = time; const char* var = VariableTable()->GetVariable(g_strHIT_WALL_SOUND); if (var && var[0] != 0) { @@ -440,7 +440,7 @@ void LegoPathActor::Animate(float p_time) LegoWorld* world = CurrentWorld(); if (world) { - world->GetCameraController()->FUN_10012290(DTOR(m_unk0x14c)); + world->GetCameraController()->RotateZ(DTOR(m_unk0x14c)); } } } diff --git a/LEGO1/lego/legoomni/src/paths/legopathboundary.cpp b/LEGO1/lego/legoomni/src/paths/legopathboundary.cpp index f4d09f9e..31600f3e 100644 --- a/LEGO1/lego/legoomni/src/paths/legopathboundary.cpp +++ b/LEGO1/lego/legoomni/src/paths/legopathboundary.cpp @@ -2,7 +2,7 @@ #include "decomp.h" #include "geom/legoorientededge.h" -#include "legolocomotionanimpresenter.h" +#include "legoanimpresenter.h" #include "legopathactor.h" #include "legopathstruct.h" diff --git a/LEGO1/lego/legoomni/src/paths/legopathstruct.cpp b/LEGO1/lego/legoomni/src/paths/legopathstruct.cpp index e269f727..276b66ab 100644 --- a/LEGO1/lego/legoomni/src/paths/legopathstruct.cpp +++ b/LEGO1/lego/legoomni/src/paths/legopathstruct.cpp @@ -3,7 +3,7 @@ #include "isle.h" #include "jukebox.h" #include "jukebox_actions.h" -#include "legohideanimpresenter.h" +#include "legoanimpresenter.h" #include "legopathactor.h" #include "legoutils.h" #include "misc.h" diff --git a/LEGO1/lego/legoomni/src/race/carrace.cpp b/LEGO1/lego/legoomni/src/race/carrace.cpp index 988584c5..33c740a1 100644 --- a/LEGO1/lego/legoomni/src/race/carrace.cpp +++ b/LEGO1/lego/legoomni/src/race/carrace.cpp @@ -5,8 +5,8 @@ #include "isle.h" #include "jukebox_actions.h" #include "legoanimationmanager.h" +#include "legoanimpresenter.h" #include "legocontrolmanager.h" -#include "legohideanimpresenter.h" #include "legomain.h" #include "legonavcontroller.h" #include "legopathstruct.h" @@ -97,7 +97,7 @@ MxResult CarRace::Create(MxDSAction& p_dsAction) m_raceState = raceState; - m_act1State->m_unk0x018 = 6; + m_act1State->m_state = Act1State::e_transitionToRacecar; m_unk0x144 = -1; m_unk0x148 = -1; m_unk0x14c = -1; @@ -126,7 +126,7 @@ void CarRace::ReadyWorld() BackgroundAudioManager()->PlayMusic(action, 5, MxPresenter::e_repeating); AnimationManager()->Resume(); - FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + Disable(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); m_unk0x144 = g_unk0x100d5d10[SDL_rand(8)]; @@ -181,7 +181,7 @@ MxLong CarRace::HandlePathStruct(LegoPathStructNotificationParam& p_param) { MxLong result = 0; - if (p_param.GetTrigger() == 68) { + if (p_param.GetTrigger() == LegoPathStruct::c_d) { MxEntity* sender = (MxEntity*) p_param.GetSender(); MxS32 paramData = p_param.GetData(); @@ -246,7 +246,7 @@ MxLong CarRace::HandlePathStruct(LegoPathStructNotificationParam& p_param) VariableTable()->SetVariable(g_strHIT_WALL_SOUND, ""); NavController()->SetDeadZone(NavController()->GetDefaultDeadZone()); NavController()->SetTrackDefault(1); - LegoRaceCar::FUN_10012de0(); + LegoRaceCar::InitYouCantStopSound(); m_raceState->m_unk0x28 = 2; RaceState::Entry* raceState = m_raceState->GetState(GameState()->GetActorId()); @@ -267,6 +267,8 @@ MxLong CarRace::HandlePathStruct(LegoPathStructNotificationParam& p_param) FALSE, TRUE ); + + EmitGameEvent(e_raceFinished); } result = 1; @@ -335,32 +337,30 @@ MxLong CarRace::HandlePathStruct(LegoPathStructNotificationParam& p_param) } // FUNCTION: LEGO1 0x10017650 -MxLong CarRace::HandleClick(LegoEventNotificationParam& p_param) +MxLong CarRace::HandleControl(LegoControlManagerNotificationParam& p_param) { - LegoControlManagerNotificationParam* param = (LegoControlManagerNotificationParam*) &p_param; - - if (param->m_unk0x28 == 1) { - switch (param->m_clickedObjectId) { + if (p_param.m_enabledChild == 1) { + switch (p_param.m_clickedObjectId) { case 3: InvokeAction(Extra::e_stop, *g_carraceScript, CarraceScript::c_irtx08ra_PlayWav, NULL); - m_act1State->m_unk0x018 = 0; + m_act1State->m_state = Act1State::e_none; VariableTable()->SetVariable(g_raceState, ""); VariableTable()->SetVariable(g_strHIT_WALL_SOUND, ""); NavController()->SetDeadZone(NavController()->GetDefaultDeadZone()); NavController()->SetTrackDefault(1); - LegoRaceCar::FUN_10012de0(); + LegoRaceCar::InitYouCantStopSound(); m_destLocation = LegoGameState::e_infomain; TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); GameState()->GetBackgroundColor()->SetValue("reset"); break; case 98: InvokeAction(Extra::e_stop, *g_carraceScript, CarraceScript::c_irtx08ra_PlayWav, NULL); - m_act1State->m_unk0x018 = 0; + m_act1State->m_state = Act1State::e_none; VariableTable()->SetVariable(g_raceState, ""); VariableTable()->SetVariable(g_strHIT_WALL_SOUND, ""); NavController()->SetDeadZone(NavController()->GetDefaultDeadZone()); NavController()->SetTrackDefault(1); - LegoRaceCar::FUN_10012de0(); + LegoRaceCar::InitYouCantStopSound(); m_destLocation = LegoGameState::e_carraceExterior; TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); GameState()->GetBackgroundColor()->SetValue("reset"); @@ -388,7 +388,7 @@ MxLong CarRace::HandleType0Notification(MxNotificationParam&) void CarRace::FUN_10017820(MxS32 p_param1, MxS16 p_param2) { MxS32 local4; - MxStillPresenter* presenter; + MxStillPresenter* presenter = NULL; MxS32 x, y; if (p_param1 == 11) { @@ -417,14 +417,14 @@ MxBool CarRace::Escape() AnimationManager()->FUN_10061010(FALSE); DeleteObjects(&m_atomId, 500, 999); - m_act1State->m_unk0x018 = 0; + m_act1State->m_state = Act1State::e_none; VariableTable()->SetVariable(g_strHIT_WALL_SOUND, ""); VariableTable()->SetVariable(g_raceState, ""); NavController()->SetDeadZone(NavController()->GetDefaultDeadZone()); NavController()->SetTrackDefault(1); - LegoRaceCar::FUN_10012de0(); + LegoRaceCar::InitYouCantStopSound(); GameState()->GetBackgroundColor()->SetValue("reset"); m_destLocation = LegoGameState::e_infomain; diff --git a/LEGO1/lego/legoomni/src/race/jetskirace.cpp b/LEGO1/lego/legoomni/src/race/jetskirace.cpp index 042090db..f906c0d9 100644 --- a/LEGO1/lego/legoomni/src/race/jetskirace.cpp +++ b/LEGO1/lego/legoomni/src/race/jetskirace.cpp @@ -6,8 +6,8 @@ #include "jetski_actions.h" #include "jukebox_actions.h" #include "legoanimationmanager.h" +#include "legoanimpresenter.h" #include "legocontrolmanager.h" -#include "legohideanimpresenter.h" #include "legomain.h" #include "legopathstruct.h" #include "legoracers.h" @@ -97,7 +97,7 @@ void JetskiRace::ReadyWorld() m_unk0x12c = (MxStillPresenter*) Find("MxPresenter", "JetskiLocator3"); m_unk0x12c->SetPosition(m_unk0x130.GetLeft(), m_unk0x130.GetTop()); - FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + Disable(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); VariableTable()->SetVariable("DISTANCE", "0.036"); @@ -122,25 +122,25 @@ MxLong JetskiRace::HandleEndAction(MxEndActionNotificationParam& p_param) } // FUNCTION: LEGO1 0x100165a0 -MxLong JetskiRace::HandleClick(LegoEventNotificationParam& p_param) +MxLong JetskiRace::HandleControl(LegoControlManagerNotificationParam& p_param) { MxLong result = 0; - if (((LegoControlManagerNotificationParam*) &p_param)->m_unk0x28 == 1) { - switch (((LegoControlManagerNotificationParam*) &p_param)->m_clickedObjectId) { + if (p_param.m_enabledChild == 1) { + switch (p_param.m_clickedObjectId) { case JetraceScript::c_JetskiArms_Ctl: - m_act1State->m_unk0x018 = 0; + m_act1State->m_state = Act1State::e_none; VariableTable()->SetVariable(g_raceState, ""); VariableTable()->SetVariable(g_strHIT_WALL_SOUND, ""); - LegoRaceCar::FUN_10012de0(); + LegoRaceCar::InitYouCantStopSound(); m_destLocation = LegoGameState::e_jetraceExterior; TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); break; case JetraceScript::c_JetskiInfo_Ctl: - m_act1State->m_unk0x018 = 0; + m_act1State->m_state = Act1State::e_none; VariableTable()->SetVariable(g_raceState, ""); VariableTable()->SetVariable(g_strHIT_WALL_SOUND, ""); - LegoRaceCar::FUN_10012de0(); + LegoRaceCar::InitYouCantStopSound(); m_destLocation = LegoGameState::e_infomain; result = 1; TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); @@ -160,7 +160,7 @@ MxLong JetskiRace::HandlePathStruct(LegoPathStructNotificationParam& p_param) MxLong result = 0; MxEntity* sender = (MxEntity*) p_param.GetSender(); - if (p_param.GetTrigger() == 68) { + if (p_param.GetTrigger() == LegoPathStruct::c_d) { MxS32 paramData = p_param.GetData(); switch (sender->GetEntityId()) { @@ -193,7 +193,7 @@ MxLong JetskiRace::HandlePathStruct(LegoPathStructNotificationParam& p_param) VariableTable()->SetVariable(g_raceState, ""); VariableTable()->SetVariable(g_strHIT_WALL_SOUND, ""); - LegoRaceCar::FUN_10012de0(); + LegoRaceCar::InitYouCantStopSound(); m_raceState->m_unk0x28 = 2; RaceState::Entry* raceStateEntry = m_raceState->GetState(GameState()->GetActorId()); @@ -206,6 +206,7 @@ MxLong JetskiRace::HandlePathStruct(LegoPathStructNotificationParam& p_param) m_destLocation = LegoGameState::e_jetrace2; TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); + EmitGameEvent(e_raceFinished); } result = 1; @@ -263,7 +264,7 @@ MxLong JetskiRace::HandlePathStruct(LegoPathStructNotificationParam& p_param) void JetskiRace::FUN_10016930(MxS32 p_param1, MxS16 p_param2) { MxS32 local4; - MxStillPresenter* presenter; + MxStillPresenter* presenter = NULL; MxS32 x, y; if (p_param1 == 11) { @@ -290,10 +291,10 @@ MxBool JetskiRace::Escape() { AnimationManager()->FUN_10061010(FALSE); DeleteObjects(&m_atomId, 500, 999); - m_act1State->m_unk0x018 = 0; + m_act1State->m_state = Act1State::e_none; VariableTable()->SetVariable(g_raceState, ""); VariableTable()->SetVariable(g_strHIT_WALL_SOUND, ""); m_destLocation = LegoGameState::e_infomain; - LegoRaceCar::FUN_10012de0(); + LegoRaceCar::InitYouCantStopSound(); return TRUE; } diff --git a/LEGO1/lego/legoomni/src/race/legorace.cpp b/LEGO1/lego/legoomni/src/race/legorace.cpp index a2c0555d..91374766 100644 --- a/LEGO1/lego/legoomni/src/race/legorace.cpp +++ b/LEGO1/lego/legoomni/src/race/legorace.cpp @@ -82,8 +82,8 @@ MxLong LegoRace::Notify(MxParam& p_param) case c_notificationEndAction: result = HandleEndAction((MxEndActionNotificationParam&) p_param); break; - case c_notificationClick: - result = HandleClick((LegoEventNotificationParam&) p_param); + case c_notificationControl: + result = HandleControl((LegoControlManagerNotificationParam&) p_param); break; case c_notificationPathStruct: result = HandlePathStruct((LegoPathStructNotificationParam&) p_param); diff --git a/LEGO1/lego/legoomni/src/race/legoraceactor.cpp b/LEGO1/lego/legoomni/src/race/legoraceactor.cpp index 965ba326..f005d996 100644 --- a/LEGO1/lego/legoomni/src/race/legoraceactor.cpp +++ b/LEGO1/lego/legoomni/src/race/legoraceactor.cpp @@ -31,8 +31,8 @@ MxS32 LegoRaceActor::VTable0x68(Vector3& p_v1, Vector3& p_v2, Vector3& p_v3) if (m_userNavFlag && result) { MxLong time = Timer()->GetTime(); - if (time - g_unk0x100f3308 > 1000) { - g_unk0x100f3308 = time; + if (time - g_timeLastHitSoundPlayed > 1000) { + g_timeLastHitSoundPlayed = time; const char* soundKey = VariableTable()->GetVariable(g_strHIT_ACTOR_SOUND); if (soundKey && *soundKey) { diff --git a/LEGO1/lego/legoomni/src/race/legoracemap.cpp b/LEGO1/lego/legoomni/src/race/legoracemap.cpp index bd0a04bd..9637114d 100644 --- a/LEGO1/lego/legoomni/src/race/legoracemap.cpp +++ b/LEGO1/lego/legoomni/src/race/legoracemap.cpp @@ -129,7 +129,7 @@ MxLong LegoRaceMap::Notify(MxParam& p_param) if (param.GetNotification() == c_notificationControl && m_Map_Ctl->GetAction()->GetObjectId() == ((LegoControlManagerNotificationParam&) p_param).m_clickedObjectId) { - if (((LegoControlManagerNotificationParam&) p_param).m_unk0x28 == 1) { + if (((LegoControlManagerNotificationParam&) p_param).m_enabledChild == 1) { m_unk0x08 = TRUE; FUN_1005d4b0(); m_stillPresenter->Enable(TRUE); diff --git a/LEGO1/lego/legoomni/src/race/legoracers.cpp b/LEGO1/lego/legoomni/src/race/legoracers.cpp index 0cffed0c..d6b25088 100644 --- a/LEGO1/lego/legoomni/src/race/legoracers.cpp +++ b/LEGO1/lego/legoomni/src/race/legoracers.cpp @@ -59,7 +59,7 @@ EdgeReference g_skBMap[] = { // GLOBAL: LEGO1 0x100f0a50 // GLOBAL: BETA10 0x101f5e60 -const SkeletonKickPhase g_skeletonKickPhases[] = { +SkeletonKickPhase g_skeletonKickPhases[] = { {&g_skBMap[0], 0.1, 0.2, LEGORACECAR_KICK2}, {&g_skBMap[1], 0.2, 0.3, LEGORACECAR_KICK2}, {&g_skBMap[2], 0.3, 0.4, LEGORACECAR_KICK2}, @@ -178,7 +178,7 @@ LegoRaceCar::LegoRaceCar() m_skelKick1Anim = 0; m_skelKick2Anim = 0; m_unk0x5c.Clear(); - m_unk0x58 = 0; + m_kickStart = 0; m_kick1B = 0; m_kick2B = 0; NotificationManager()->Register(this); @@ -201,10 +201,10 @@ MxLong LegoRaceCar::Notify(MxParam& p_param) // Initialized at LEGO1 0x10012db0 // GLOBAL: LEGO1 0x10102af0 // GLOBAL: BETA10 0x102114c0 -Mx3DPointFloat g_unk0x10102af0 = Mx3DPointFloat(0.0f, 2.0f, 0.0f); +Mx3DPointFloat g_hitOffset = Mx3DPointFloat(0.0f, 2.0f, 0.0f); // FUNCTION: LEGO1 0x10012de0 -void LegoRaceCar::FUN_10012de0() +void LegoRaceCar::InitYouCantStopSound() { // Init to TRUE so we don't play "you can't stop in the middle of the race!" before the player ever moves g_playedYouCantStopSound = TRUE; @@ -229,7 +229,7 @@ void LegoRaceCar::InitSoundIndices() void LegoRaceCar::SetWorldSpeed(MxFloat p_worldSpeed) { if (!m_userNavFlag) { - if (!LegoCarRaceActor::m_unk0x0c) { + if (!LegoCarRaceActor::m_animState) { m_maxLinearVel = p_worldSpeed; } LegoAnimActor::SetWorldSpeed(p_worldSpeed); @@ -244,7 +244,7 @@ void LegoRaceCar::SetWorldSpeed(MxFloat p_worldSpeed) void LegoRaceCar::SetMaxLinearVelocity(float p_maxLinearVelocity) { if (p_maxLinearVelocity < 0) { - LegoCarRaceActor::m_unk0x0c = 2; + LegoCarRaceActor::m_animState = 2; m_maxLinearVel = 0; SetWorldSpeed(0); } @@ -299,7 +299,7 @@ void LegoRaceCar::ParseAction(char* p_extra) // FUNCTION: LEGO1 0x10012ff0 // FUNCTION: BETA10 0x100cb60e -void LegoRaceCar::FUN_10012ff0(float p_param) +void LegoRaceCar::KickCamera(float p_param) { LegoAnimActorStruct* a; // called `a` in BETA10 float deltaTime; @@ -315,7 +315,7 @@ void LegoRaceCar::FUN_10012ff0(float p_param) assert(a && a->GetAnimTreePtr() && a->GetAnimTreePtr()->GetCamAnim()); if (a->GetAnimTreePtr()) { - deltaTime = p_param - m_unk0x58; + deltaTime = p_param - m_kickStart; if (a->GetDuration() <= deltaTime || deltaTime < 0.0) { if (m_userState == LEGORACECAR_KICK1) { @@ -340,10 +340,10 @@ void LegoRaceCar::FUN_10012ff0(float p_param) transformationMatrix.SetIdentity(); // Possible bug in the original code: The first argument is not initialized - a->GetAnimTreePtr()->GetCamAnim()->FUN_1009f490(deltaTime, transformationMatrix); + a->GetAnimTreePtr()->GetCamAnim()->CalculateCameraTransform(deltaTime, transformationMatrix); if (r->GetCameraController()) { - r->GetCameraController()->FUN_100123e0(transformationMatrix, 0); + r->GetCameraController()->TransformPointOfView(transformationMatrix, 0); } m_roi->SetLocal2World(transformationMatrix); @@ -390,8 +390,9 @@ MxU32 LegoRaceCar::HandleSkeletonKicks(float p_param1) return FALSE; } - m_unk0x58 = p_param1; + m_kickStart = p_param1; SoundManager()->GetCacheSoundManager()->Play(g_soundSkel3, NULL, FALSE); + EmitGameEvent(e_skeletonKick); return TRUE; } @@ -401,7 +402,7 @@ MxU32 LegoRaceCar::HandleSkeletonKicks(float p_param1) void LegoRaceCar::Animate(float p_time) { if (m_userNavFlag && (m_userState == LEGORACECAR_KICK1 || m_userState == LEGORACECAR_KICK2)) { - FUN_10012ff0(p_time); + KickCamera(p_time); return; } @@ -413,7 +414,7 @@ void LegoRaceCar::Animate(float p_time) } } - if (LegoCarRaceActor::m_unk0x0c == 1) { + if (LegoCarRaceActor::m_animState == 1) { FUN_1005d4b0(); if (!m_userNavFlag) { @@ -471,7 +472,7 @@ MxResult LegoRaceCar::HitActor(LegoPathActor* p_actor, MxBool p_bool) assert(roi); matr = roi->GetLocal2World(); - Vector3(matr[3]) += g_unk0x10102af0; + Vector3(matr[3]) += g_hitOffset; roi->SetLocal2World(matr); p_actor->SetActorState(c_two); @@ -516,7 +517,7 @@ MxResult LegoRaceCar::HitActor(LegoPathActor* p_actor, MxBool p_bool) if (soundKey) { SoundManager()->GetCacheSoundManager()->Play(soundKey, NULL, FALSE); - g_timeLastRaceCarSoundPlayed = g_unk0x100f3308 = time; + g_timeLastRaceCarSoundPlayed = g_timeLastHitSoundPlayed = time; } } @@ -528,6 +529,9 @@ MxResult LegoRaceCar::HitActor(LegoPathActor* p_actor, MxBool p_bool) } } } + else { + EmitGameEvent(e_hitActor); + } return SUCCESS; } @@ -582,7 +586,7 @@ void LegoJetski::InitSoundIndices() void LegoJetski::SetWorldSpeed(MxFloat p_worldSpeed) { if (!m_userNavFlag) { - if (!LegoCarRaceActor::m_unk0x0c) { + if (!LegoCarRaceActor::m_animState) { m_maxLinearVel = p_worldSpeed; } LegoAnimActor::SetWorldSpeed(p_worldSpeed); @@ -597,7 +601,7 @@ void LegoJetski::SetWorldSpeed(MxFloat p_worldSpeed) void LegoJetski::FUN_100136f0(float p_worldSpeed) { if (p_worldSpeed < 0) { - LegoCarRaceActor::m_unk0x0c = 2; + LegoCarRaceActor::m_animState = 2; m_maxLinearVel = 0; SetWorldSpeed(0); } @@ -612,7 +616,7 @@ void LegoJetski::Animate(float p_time) { LegoJetskiRaceActor::Animate(p_time); - if (LegoCarRaceActor::m_unk0x0c == 1) { + if (LegoCarRaceActor::m_animState == 1) { FUN_1005d4b0(); if (!m_userNavFlag) { @@ -685,7 +689,7 @@ MxResult LegoJetski::HitActor(LegoPathActor* p_actor, MxBool p_bool) LegoROI* roi = p_actor->GetROI(); matr = roi->GetLocal2World(); - Vector3(matr[3]) += g_unk0x10102af0; + Vector3(matr[3]) += g_hitOffset; roi->SetLocal2World(matr); p_actor->SetActorState(c_two); @@ -714,7 +718,7 @@ MxResult LegoJetski::HitActor(LegoPathActor* p_actor, MxBool p_bool) if (soundKey) { SoundManager()->GetCacheSoundManager()->Play(soundKey, NULL, FALSE); - g_timeLastJetskiSoundPlayed = g_unk0x100f3308 = time; + g_timeLastJetskiSoundPlayed = g_timeLastHitSoundPlayed = time; } } @@ -726,6 +730,9 @@ MxResult LegoJetski::HitActor(LegoPathActor* p_actor, MxBool p_bool) } } } + else { + EmitGameEvent(e_hitActor); + } return SUCCESS; } diff --git a/LEGO1/lego/legoomni/src/race/legoracespecial.cpp b/LEGO1/lego/legoomni/src/race/legoracespecial.cpp index 935c3406..7fe58c71 100644 --- a/LEGO1/lego/legoomni/src/race/legoracespecial.cpp +++ b/LEGO1/lego/legoomni/src/race/legoracespecial.cpp @@ -45,7 +45,7 @@ LegoCarRaceActor::LegoCarRaceActor() { m_unk0x08 = 1.0f; m_unk0x70 = 0.0f; - m_unk0x0c = 0; + m_animState = 0; m_maxLinearVel = 0.0f; m_frequencyFactor = 1.0f; m_unk0x1c = 0; @@ -224,18 +224,18 @@ void LegoCarRaceActor::SwitchBoundary(LegoPathBoundary*& p_boundary, LegoOriente // FUNCTION: BETA10 0x100cdbae void LegoCarRaceActor::Animate(float p_time) { - // m_unk0x0c is not an MxBool, there are places where it is set to 2 or higher - if (m_unk0x0c == 0) { + // m_animState is not an MxBool, there are places where it is set to 2 or higher + if (m_animState == 0) { const char* value = VariableTable()->GetVariable(g_raceState); if (SDL_strcasecmp(value, g_racing) == 0) { - m_unk0x0c = 1; + m_animState = 1; m_lastTime = p_time - 1.0f; m_unk0x1c = p_time; } } - if (m_unk0x0c == 1) { + if (m_animState == 1) { LegoAnimActor::Animate(p_time); } } @@ -399,10 +399,10 @@ MxS32 LegoJetskiRaceActor::VTable0x1c(LegoPathBoundary* p_boundary, LegoEdge* p_ // FUNCTION: LEGO1 0x10081550 void LegoJetskiRaceActor::Animate(float p_time) { - if (m_unk0x0c == 0) { + if (m_animState == 0) { const LegoChar* raceState = VariableTable()->GetVariable(g_raceState); if (!SDL_strcasecmp(raceState, g_racing)) { - m_unk0x0c = 1; + m_animState = 1; m_lastTime = p_time - 1.0f; m_unk0x1c = p_time; } @@ -411,7 +411,7 @@ void LegoJetskiRaceActor::Animate(float p_time) } } - if (m_unk0x0c == 1) { + if (m_animState == 1) { LegoAnimActor::Animate(p_time); } } diff --git a/LEGO1/lego/legoomni/src/video/legoanimpresenter.cpp b/LEGO1/lego/legoomni/src/video/legoanimpresenter.cpp index 28642bab..9e31e18b 100644 --- a/LEGO1/lego/legoomni/src/video/legoanimpresenter.cpp +++ b/LEGO1/lego/legoomni/src/video/legoanimpresenter.cpp @@ -3,6 +3,7 @@ #include "3dmanager/lego3dmanager.h" #include "anim/legoanim.h" #include "define.h" +#include "legoanimactor.h" #include "legoanimationmanager.h" #include "legoanimmmpresenter.h" #include "legocameracontroller.h" @@ -30,6 +31,10 @@ #include DECOMP_SIZE_ASSERT(LegoAnimPresenter, 0xbc) +DECOMP_SIZE_ASSERT(LegoLoopingAnimPresenter, 0xc0) +DECOMP_SIZE_ASSERT(LegoLocomotionAnimPresenter, 0xd8) +DECOMP_SIZE_ASSERT(LegoHideAnimPresenter, 0xc4) +DECOMP_SIZE_ASSERT(LegoHideAnimStruct, 0x08) // FUNCTION: LEGO1 0x10068420 // FUNCTION: BETA10 0x1004e5f0 @@ -706,11 +711,14 @@ MxResult LegoAnimPresenter::FUN_1006b140(LegoROI* p_roi) if (p_roi == NULL) { return FAILURE; } +#ifdef BETA10 + MxMatrix unused_matrix; +#endif Matrix4* mn = new MxMatrix(); assert(mn); - MxMatrix local58; + MxMatrix inverse; const Matrix4& local2world = p_roi->GetLocal2World(); MxMatrix* local5c; MxU32 i; @@ -721,7 +729,7 @@ MxResult LegoAnimPresenter::FUN_1006b140(LegoROI* p_roi) for (i = 1; i <= m_roiMapSize; i++) { if (m_roiMap[i] == p_roi) { - if (local5c[i].BETA_1005a590(local58) != SUCCESS) { + if (local5c[i].Invert(inverse) != SUCCESS) { goto done; } @@ -730,7 +738,7 @@ MxResult LegoAnimPresenter::FUN_1006b140(LegoROI* p_roi) } { - mn->Product(local58, local2world); + mn->Product(inverse, local2world); SetUnknown0xa0(mn); delete[] local5c; SetUnknown0x0cTo1(); @@ -793,7 +801,7 @@ void LegoAnimPresenter::StartingTickle() } FUN_10069b10(); - FUN_1006c8a0(TRUE); + SetDisabled(TRUE); if (m_unk0x78 == NULL) { if (fabs(m_action->GetDirection()[0]) >= 0.00000047683716F || @@ -818,7 +826,7 @@ void LegoAnimPresenter::StartingTickle() m_compositePresenter->VTable0x60(this); } else { - m_action->SetUnknown90(Timer()->GetTime()); + m_action->SetTimeStarted(Timer()->GetTime()); } ProgressTickleState(e_streaming); @@ -906,7 +914,7 @@ void LegoAnimPresenter::FUN_1006b900(LegoAnim* p_anim, MxLong p_time, Matrix4* p } } - LegoROI::FUN_100a8fd0(root, mat, p_time, m_roiMap); + LegoROI::ApplyTransform(root, mat, p_time, m_roiMap); } // FUNCTION: LEGO1 0x1006b9a0 @@ -933,14 +941,14 @@ void LegoAnimPresenter::FUN_1006b9a0(LegoAnim* p_anim, MxLong p_time, Matrix4* p if (p_anim->GetCamAnim() != NULL) { MxMatrix transform(mat); - p_anim->GetCamAnim()->FUN_1009f490(p_time, transform); + p_anim->GetCamAnim()->CalculateCameraTransform(p_time, transform); if (m_currentWorld != NULL && m_currentWorld->GetCameraController() != NULL) { - m_currentWorld->GetCameraController()->FUN_100123e0(transform, 0); + m_currentWorld->GetCameraController()->TransformPointOfView(transform, FALSE); } } - LegoROI::FUN_100a8e80(root, mat, p_time, m_roiMap); + LegoROI::ApplyAnimationTransformation(root, mat, p_time, m_roiMap); } // FUNCTION: LEGO1 0x1006bac0 @@ -1093,7 +1101,7 @@ void LegoAnimPresenter::EndAction() } } - FUN_1006c8a0(FALSE); + SetDisabled(FALSE); FUN_1006ab70(); VTable0x90(); @@ -1154,18 +1162,18 @@ void LegoAnimPresenter::VTable0x90() } // FUNCTION: LEGO1 0x1006c8a0 -void LegoAnimPresenter::FUN_1006c8a0(MxBool p_bool) +void LegoAnimPresenter::SetDisabled(MxBool p_disabled) { if (m_roiMapSize != 0 && m_roiMap != NULL) { for (MxU32 i = 1; i <= m_roiMapSize; i++) { LegoEntity* entity = m_roiMap[i]->GetEntity(); if (entity != NULL) { - if (p_bool) { - entity->SetUnknown0x10Flag(LegoEntity::c_altBit1); + if (p_disabled) { + entity->SetInteractionFlag(LegoEntity::c_disabled); } else { - entity->ClearUnknown0x10Flag(LegoEntity::c_altBit1); + entity->ClearInteractionFlag(LegoEntity::c_disabled); } } } @@ -1216,3 +1224,439 @@ MxResult LegoAnimPresenter::VTable0x98(LegoPathBoundary* p_boundary) return SUCCESS; } + +// FUNCTION: LEGO1 0x1006caa0 +// FUNCTION: BETA10 0x1005223d +void LegoLoopingAnimPresenter::StreamingTickle() +{ + if (m_subscriber->PeekData()) { + MxStreamChunk* chunk = m_subscriber->PopData(); + m_subscriber->FreeDataChunk(chunk); + } + + if (m_unk0x95) { + ProgressTickleState(e_done); + if (m_compositePresenter) { + if (m_compositePresenter->IsA("LegoAnimMMPresenter")) { + m_compositePresenter->VTable0x60(this); + } + } + } + else { + if (m_action->GetDuration() != -1) { + if (m_action->GetElapsedTime() > m_action->GetDuration() + m_action->GetStartTime()) { + m_unk0x95 = TRUE; + } + } + } +} + +// FUNCTION: LEGO1 0x1006cb40 +// FUNCTION: BETA10 0x1005239a +void LegoLoopingAnimPresenter::PutFrame() +{ + MxLong time; + + if (m_action->GetStartTime() <= m_action->GetElapsedTime()) { + time = (m_action->GetElapsedTime() - m_action->GetStartTime()) % m_anim->GetDuration(); + } + else { + time = 0; + } + + FUN_1006b9a0(m_anim, time, m_unk0x78); + + if (m_unk0x8c != NULL && m_currentWorld != NULL && m_currentWorld->GetCameraController() != NULL) { + for (MxS32 i = 0; i < m_unk0x94; i++) { + if (m_unk0x8c[i] != NULL) { + MxMatrix mat(m_unk0x8c[i]->GetLocal2World()); + + Vector3 pos(mat[0]); + Vector3 dir(mat[1]); + Vector3 up(mat[2]); + Vector3 und(mat[3]); + + float possqr = sqrt(pos.LenSquared()); + float dirsqr = sqrt(dir.LenSquared()); + float upsqr = sqrt(up.LenSquared()); + + up = und; + + up -= m_currentWorld->GetCameraController()->GetWorldLocation(); + dir /= dirsqr; + pos.EqualsCross(dir, up); + pos.Unitize(); + up.EqualsCross(pos, dir); + pos *= possqr; + dir *= dirsqr; + up *= upsqr; + + m_unk0x8c[i]->SetLocal2World(mat); + m_unk0x8c[i]->WrappedUpdateWorldData(); + } + } + } +} + +// FUNCTION: LEGO1 0x1006cdd0 +LegoLocomotionAnimPresenter::LegoLocomotionAnimPresenter() +{ + Init(); +} + +// FUNCTION: LEGO1 0x1006d050 +LegoLocomotionAnimPresenter::~LegoLocomotionAnimPresenter() +{ + Destroy(TRUE); +} + +// FUNCTION: LEGO1 0x1006d0b0 +void LegoLocomotionAnimPresenter::Init() +{ + m_unk0xc0 = 0; + m_unk0xc4 = NULL; + m_unk0xcc = -1; + m_unk0xd0 = -1; + m_roiMapList = NULL; + m_unk0xd4 = 0; +} + +// FUNCTION: LEGO1 0x1006d0e0 +void LegoLocomotionAnimPresenter::Destroy(MxBool p_fromDestructor) +{ + ENTER(m_criticalSection); + + if (m_unk0xc4) { + delete[] m_unk0xc4; + } + + if (m_roiMapList) { + delete m_roiMapList; + } + + m_roiMap = NULL; + Init(); + + m_criticalSection.Leave(); + + if (!p_fromDestructor) { + LegoLoopingAnimPresenter::Destroy(); + } +} + +// FUNCTION: LEGO1 0x1006d140 +MxResult LegoLocomotionAnimPresenter::CreateAnim(MxStreamChunk* p_chunk) +{ + MxResult result = LegoAnimPresenter::CreateAnim(p_chunk); + return result == SUCCESS ? SUCCESS : result; +} + +// FUNCTION: LEGO1 0x1006d160 +// FUNCTION: BETA10 0x100528c7 +MxResult LegoLocomotionAnimPresenter::AddToManager() +{ + m_roiMapList = new LegoROIMapList(); + + if (m_roiMapList == NULL) { + return FAILURE; + } + + return LegoAnimPresenter::AddToManager(); +} + +// FUNCTION: LEGO1 0x1006d5b0 +void LegoLocomotionAnimPresenter::Destroy() +{ + Destroy(FALSE); +} + +// FUNCTION: LEGO1 0x1006d5c0 +void LegoLocomotionAnimPresenter::PutFrame() +{ + // Empty +} + +// FUNCTION: LEGO1 0x1006d5d0 +void LegoLocomotionAnimPresenter::ReadyTickle() +{ + LegoLoopingAnimPresenter::ReadyTickle(); + + if (m_currentWorld != NULL && m_currentTickleState == e_starting) { + m_currentWorld->Add(this); + if (m_compositePresenter != NULL) { + SendToCompositePresenter(Lego()); + } + + m_unk0xd4++; + } +} + +// FUNCTION: LEGO1 0x1006d610 +// FUNCTION: BETA10 0x10052a34 +void LegoLocomotionAnimPresenter::StartingTickle() +{ + if (m_subscriber->PeekData()) { + MxStreamChunk* chunk = m_subscriber->PopData(); + m_subscriber->FreeDataChunk(chunk); + } + + if (m_roiMapList->GetNumElements() != 0) { + ProgressTickleState(e_streaming); + } +} + +// FUNCTION: LEGO1 0x1006d660 +void LegoLocomotionAnimPresenter::StreamingTickle() +{ + if (m_unk0xd4 == 0) { + EndAction(); + } +} + +// FUNCTION: LEGO1 0x1006d670 +void LegoLocomotionAnimPresenter::EndAction() +{ + if (m_action) { + MxVideoPresenter::EndAction(); + } +} + +// FUNCTION: LEGO1 0x1006d680 +// FUNCTION: BETA10 0x10052b3d +void LegoLocomotionAnimPresenter::FUN_1006d680(LegoAnimActor* p_actor, MxFloat p_value) +{ + // This asserts that LegoLocomotionAnimPresenter is contained in legoanimpresenter.cpp + AUTOLOCK(m_criticalSection); + + MxVariableTable* variableTable = VariableTable(); + + const char* key = ((LegoAnimNodeData*) m_anim->GetRoot()->GetData())->GetName(); + variableTable->SetVariable(key, p_actor->GetROI()->GetName()); + + FUN_100695c0(); + FUN_10069b10(); + + if (m_roiMap != NULL) { + m_roiMapList->Append(m_roiMap); + p_actor->FUN_1001c450(m_anim, p_value, m_roiMap, m_roiMapSize); + m_roiMap = NULL; + } + + variableTable->SetVariable(key, ""); + + if (m_sceneROIs != NULL) { + delete m_sceneROIs; + m_sceneROIs = NULL; + } +} + +// We do not have any hard evidence that `LegoHideAnimPresenter` is part of this file as well. +// However, since all of the other AnimPresenters are in the same file, it is reasonable to assume +// that the same holds here. + +// FUNCTION: LEGO1 0x1006d7e0 +LegoHideAnimPresenter::LegoHideAnimPresenter() +{ + Init(); +} + +// FUNCTION: LEGO1 0x1006d9f0 +LegoHideAnimPresenter::~LegoHideAnimPresenter() +{ + Destroy(TRUE); +} + +// FUNCTION: LEGO1 0x1006da50 +void LegoHideAnimPresenter::Init() +{ + m_boundaryMap = NULL; +} + +// FUNCTION: LEGO1 0x1006da60 +void LegoHideAnimPresenter::Destroy(MxBool p_fromDestructor) +{ + ENTER(m_criticalSection); + + if (m_boundaryMap) { + delete[] m_boundaryMap; + } + Init(); + + m_criticalSection.Leave(); + + // This appears to be a bug, since it results in an endless loop + if (!p_fromDestructor) { + LegoHideAnimPresenter::Destroy(); + } +} + +// FUNCTION: LEGO1 0x1006dab0 +MxResult LegoHideAnimPresenter::AddToManager() +{ + return LegoAnimPresenter::AddToManager(); +} + +// FUNCTION: LEGO1 0x1006dac0 +void LegoHideAnimPresenter::Destroy() +{ + Destroy(FALSE); +} + +// FUNCTION: LEGO1 0x1006dad0 +void LegoHideAnimPresenter::PutFrame() +{ +} + +// FUNCTION: LEGO1 0x1006dae0 +// FUNCTION: BETA10 0x100530f4 +void LegoHideAnimPresenter::ReadyTickle() +{ + LegoLoopingAnimPresenter::ReadyTickle(); + + if (m_currentWorld) { + if (m_currentTickleState == e_starting && m_compositePresenter != NULL) { + SendToCompositePresenter(Lego()); + } + + m_currentWorld->Add(this); + } +} + +// FUNCTION: LEGO1 0x1006db20 +// FUNCTION: BETA10 0x1005316b +void LegoHideAnimPresenter::StartingTickle() +{ + LegoLoopingAnimPresenter::StartingTickle(); + + if (m_currentTickleState == e_streaming) { + FUN_1006dc10(); + FUN_1006db40(0); + } +} + +// FUNCTION: LEGO1 0x1006db40 +// FUNCTION: BETA10 0x100531ab +void LegoHideAnimPresenter::FUN_1006db40(LegoTime p_time) +{ + FUN_1006db60(m_anim->GetRoot(), p_time); +} + +// FUNCTION: LEGO1 0x1006db60 +// FUNCTION: BETA10 0x100531de +void LegoHideAnimPresenter::FUN_1006db60(LegoTreeNode* p_node, LegoTime p_time) +{ + LegoAnimNodeData* data = (LegoAnimNodeData*) p_node->GetData(); + MxBool newB = FALSE; + MxBool previousB = FALSE; + + if (m_roiMap != NULL) { + LegoROI* roi = m_roiMap[data->GetROIIndex()]; + + if (roi != NULL) { + newB = data->GetVisibility(p_time); + previousB = roi->GetVisibility(); + roi->SetVisibility(newB); + } + } + + if (m_boundaryMap != NULL) { + LegoPathBoundary* boundary = m_boundaryMap[data->GetBoundaryIndex()]; + + if (boundary != NULL) { + newB = data->GetVisibility(p_time); + previousB = boundary->GetFlag0x10(); + boundary->SetFlag0x10(newB); + } + } + + for (MxS32 i = 0; i < p_node->GetNumChildren(); i++) { + FUN_1006db60(p_node->GetChild(i), p_time); + } +} + +// FUNCTION: LEGO1 0x1006dc10 +// FUNCTION: BETA10 0x100532fd +void LegoHideAnimPresenter::FUN_1006dc10() +{ + LegoHideAnimStructMap anims; + + FUN_1006e3f0(anims, m_anim->GetRoot()); + + if (m_boundaryMap != NULL) { + delete[] m_boundaryMap; + } + + m_boundaryMap = new LegoPathBoundary*[anims.size() + 1]; + m_boundaryMap[0] = NULL; + + for (LegoHideAnimStructMap::iterator it = anims.begin(); !(it == anims.end()); it++) { + m_boundaryMap[(*it).second.m_index] = (*it).second.m_boundary; + delete[] const_cast((*it).first); + } +} + +// FUNCTION: LEGO1 0x1006e3f0 +// FUNCTION: BETA10 0x1005345e +void LegoHideAnimPresenter::FUN_1006e3f0(LegoHideAnimStructMap& p_map, LegoTreeNode* p_node) +{ + LegoAnimNodeData* data = (LegoAnimNodeData*) p_node->GetData(); + const char* name = data->GetName(); + + if (name != NULL) { + LegoPathBoundary* boundary = m_currentWorld->FindPathBoundary(name); + + if (boundary != NULL) { + FUN_1006e470(p_map, data, name, boundary); + } + else { + data->SetBoundaryIndex(0); + } + } + + MxS32 count = p_node->GetNumChildren(); + for (MxS32 i = 0; i < count; i++) { + FUN_1006e3f0(p_map, p_node->GetChild(i)); + } +} + +// FUNCTION: LEGO1 0x1006e470 +// FUNCTION: BETA10 0x10053520 +void LegoHideAnimPresenter::FUN_1006e470( + LegoHideAnimStructMap& p_map, + LegoAnimNodeData* p_data, + const char* p_name, + LegoPathBoundary* p_boundary +) +{ + LegoHideAnimStructMap::iterator it; + + it = p_map.find(p_name); + if (it == p_map.end()) { + LegoHideAnimStruct animStruct; + animStruct.m_index = p_map.size() + 1; + animStruct.m_boundary = p_boundary; + + p_data->SetBoundaryIndex(animStruct.m_index); + + char* name = new char[strlen(p_name) + 1]; + strcpy(name, p_name); + + p_map[name] = animStruct; + } + else { + p_data->SetBoundaryIndex((*it).second.m_index); + } +} + +// FUNCTION: LEGO1 0x1006e9e0 +// FUNCTION: BETA10 0x100535ef +void LegoHideAnimPresenter::EndAction() +{ + if (m_action) { + MxVideoPresenter::EndAction(); + + if (m_currentWorld) { + m_currentWorld->Remove(this); + } + } +} diff --git a/LEGO1/lego/legoomni/src/video/legohideanimpresenter.cpp b/LEGO1/lego/legoomni/src/video/legohideanimpresenter.cpp deleted file mode 100644 index 89768b3e..00000000 --- a/LEGO1/lego/legoomni/src/video/legohideanimpresenter.cpp +++ /dev/null @@ -1,216 +0,0 @@ -#include "legohideanimpresenter.h" - -#include "anim/legoanim.h" -#include "legomain.h" -#include "legoworld.h" -#include "misc.h" - -DECOMP_SIZE_ASSERT(LegoHideAnimPresenter, 0xc4) -DECOMP_SIZE_ASSERT(LegoHideAnimStruct, 0x08) - -// FUNCTION: LEGO1 0x1006d7e0 -LegoHideAnimPresenter::LegoHideAnimPresenter() -{ - Init(); -} - -// FUNCTION: LEGO1 0x1006d9f0 -LegoHideAnimPresenter::~LegoHideAnimPresenter() -{ - Destroy(TRUE); -} - -// FUNCTION: LEGO1 0x1006da50 -void LegoHideAnimPresenter::Init() -{ - m_boundaryMap = NULL; -} - -// FUNCTION: LEGO1 0x1006da60 -void LegoHideAnimPresenter::Destroy(MxBool p_fromDestructor) -{ - m_criticalSection.Enter(); - - if (m_boundaryMap) { - delete[] m_boundaryMap; - } - Init(); - - m_criticalSection.Leave(); - - // This appears to be a bug, since it results in an endless loop - if (!p_fromDestructor) { - LegoHideAnimPresenter::Destroy(); - } -} - -// FUNCTION: LEGO1 0x1006dab0 -MxResult LegoHideAnimPresenter::AddToManager() -{ - return LegoAnimPresenter::AddToManager(); -} - -// FUNCTION: LEGO1 0x1006dac0 -void LegoHideAnimPresenter::Destroy() -{ - Destroy(FALSE); -} - -// FUNCTION: LEGO1 0x1006dad0 -void LegoHideAnimPresenter::PutFrame() -{ -} - -// FUNCTION: LEGO1 0x1006dae0 -// FUNCTION: BETA10 0x100530f4 -void LegoHideAnimPresenter::ReadyTickle() -{ - LegoLoopingAnimPresenter::ReadyTickle(); - - if (m_currentWorld) { - if (m_currentTickleState == e_starting && m_compositePresenter != NULL) { - SendToCompositePresenter(Lego()); - } - - m_currentWorld->Add(this); - } -} - -// FUNCTION: LEGO1 0x1006db20 -// FUNCTION: BETA10 0x1005316b -void LegoHideAnimPresenter::StartingTickle() -{ - LegoLoopingAnimPresenter::StartingTickle(); - - if (m_currentTickleState == e_streaming) { - FUN_1006dc10(); - FUN_1006db40(0); - } -} - -// FUNCTION: LEGO1 0x1006db40 -// FUNCTION: BETA10 0x100531ab -void LegoHideAnimPresenter::FUN_1006db40(LegoTime p_time) -{ - FUN_1006db60(m_anim->GetRoot(), p_time); -} - -// FUNCTION: LEGO1 0x1006db60 -// FUNCTION: BETA10 0x100531de -void LegoHideAnimPresenter::FUN_1006db60(LegoTreeNode* p_node, LegoTime p_time) -{ - LegoAnimNodeData* data = (LegoAnimNodeData*) p_node->GetData(); - MxBool newB = FALSE; - MxBool previousB = FALSE; - - if (m_roiMap != NULL) { - LegoROI* roi = m_roiMap[data->GetROIIndex()]; - - if (roi != NULL) { - newB = data->GetVisibility(p_time); - previousB = roi->GetVisibility(); - roi->SetVisibility(newB); - } - } - - if (m_boundaryMap != NULL) { - LegoPathBoundary* boundary = m_boundaryMap[data->GetUnknown0x22()]; - - if (boundary != NULL) { - newB = data->GetVisibility(p_time); - previousB = boundary->GetFlag0x10(); - boundary->SetFlag0x10(newB); - } - } - - for (MxS32 i = 0; i < p_node->GetNumChildren(); i++) { - FUN_1006db60(p_node->GetChild(i), p_time); - } -} - -// FUNCTION: LEGO1 0x1006dc10 -// FUNCTION: BETA10 0x100532fd -void LegoHideAnimPresenter::FUN_1006dc10() -{ - LegoHideAnimStructMap anims; - - FUN_1006e3f0(anims, m_anim->GetRoot()); - - if (m_boundaryMap != NULL) { - delete[] m_boundaryMap; - } - - m_boundaryMap = new LegoPathBoundary*[anims.size() + 1]; - m_boundaryMap[0] = NULL; - - for (LegoHideAnimStructMap::iterator it = anims.begin(); !(it == anims.end()); it++) { - m_boundaryMap[(*it).second.m_index] = (*it).second.m_boundary; - delete[] const_cast((*it).first); - } -} - -// FUNCTION: LEGO1 0x1006e3f0 -// FUNCTION: BETA10 0x1005345e -void LegoHideAnimPresenter::FUN_1006e3f0(LegoHideAnimStructMap& p_map, LegoTreeNode* p_node) -{ - LegoAnimNodeData* data = (LegoAnimNodeData*) p_node->GetData(); - const char* name = data->GetName(); - - if (name != NULL) { - LegoPathBoundary* boundary = m_currentWorld->FindPathBoundary(name); - - if (boundary != NULL) { - FUN_1006e470(p_map, data, name, boundary); - } - else { - data->SetUnknown0x22(0); - } - } - - MxS32 count = p_node->GetNumChildren(); - for (MxS32 i = 0; i < count; i++) { - FUN_1006e3f0(p_map, p_node->GetChild(i)); - } -} - -// FUNCTION: LEGO1 0x1006e470 -// FUNCTION: BETA10 0x10053520 -void LegoHideAnimPresenter::FUN_1006e470( - LegoHideAnimStructMap& p_map, - LegoAnimNodeData* p_data, - const char* p_name, - LegoPathBoundary* p_boundary -) -{ - LegoHideAnimStructMap::iterator it; - - it = p_map.find(p_name); - if (it == p_map.end()) { - LegoHideAnimStruct animStruct; - animStruct.m_index = p_map.size() + 1; - animStruct.m_boundary = p_boundary; - - p_data->SetUnknown0x22(animStruct.m_index); - - char* name = new char[strlen(p_name) + 1]; - strcpy(name, p_name); - - p_map[name] = animStruct; - } - else { - p_data->SetUnknown0x22((*it).second.m_index); - } -} - -// FUNCTION: LEGO1 0x1006e9e0 -// FUNCTION: BETA10 0x100535ef -void LegoHideAnimPresenter::EndAction() -{ - if (m_action) { - MxVideoPresenter::EndAction(); - - if (m_currentWorld) { - m_currentWorld->Remove(this); - } - } -} diff --git a/LEGO1/lego/legoomni/src/video/legolocomotionanimpresenter.cpp b/LEGO1/lego/legoomni/src/video/legolocomotionanimpresenter.cpp deleted file mode 100644 index 90b98e91..00000000 --- a/LEGO1/lego/legoomni/src/video/legolocomotionanimpresenter.cpp +++ /dev/null @@ -1,164 +0,0 @@ -#include "legolocomotionanimpresenter.h" - -#include "anim/legoanim.h" -#include "legoanimactor.h" -#include "legomain.h" -#include "legoworld.h" -#include "misc.h" -#include "mxautolock.h" -#include "mxdssubscriber.h" -#include "mxmisc.h" -#include "mxvariabletable.h" - -DECOMP_SIZE_ASSERT(LegoLocomotionAnimPresenter, 0xd8) - -// FUNCTION: LEGO1 0x1006cdd0 -LegoLocomotionAnimPresenter::LegoLocomotionAnimPresenter() -{ - Init(); -} - -// FUNCTION: LEGO1 0x1006d050 -LegoLocomotionAnimPresenter::~LegoLocomotionAnimPresenter() -{ - Destroy(TRUE); -} - -// FUNCTION: LEGO1 0x1006d0b0 -void LegoLocomotionAnimPresenter::Init() -{ - m_unk0xc0 = 0; - m_unk0xc4 = NULL; - m_unk0xcc = -1; - m_unk0xd0 = -1; - m_roiMapList = NULL; - m_unk0xd4 = 0; -} - -// FUNCTION: LEGO1 0x1006d0e0 -void LegoLocomotionAnimPresenter::Destroy(MxBool p_fromDestructor) -{ - m_criticalSection.Enter(); - - if (m_unk0xc4) { - delete[] m_unk0xc4; - } - - if (m_roiMapList) { - delete m_roiMapList; - } - - m_roiMap = NULL; - Init(); - - m_criticalSection.Leave(); - - if (!p_fromDestructor) { - LegoLoopingAnimPresenter::Destroy(); - } -} - -// FUNCTION: LEGO1 0x1006d140 -MxResult LegoLocomotionAnimPresenter::CreateAnim(MxStreamChunk* p_chunk) -{ - MxResult result = LegoAnimPresenter::CreateAnim(p_chunk); - return result == SUCCESS ? SUCCESS : result; -} - -// FUNCTION: LEGO1 0x1006d160 -// FUNCTION: BETA10 0x100528c7 -MxResult LegoLocomotionAnimPresenter::AddToManager() -{ - m_roiMapList = new LegoROIMapList(); - - if (m_roiMapList == NULL) { - return FAILURE; - } - - return LegoAnimPresenter::AddToManager(); -} - -// FUNCTION: LEGO1 0x1006d5b0 -void LegoLocomotionAnimPresenter::Destroy() -{ - Destroy(FALSE); -} - -// FUNCTION: LEGO1 0x1006d5c0 -void LegoLocomotionAnimPresenter::PutFrame() -{ - // Empty -} - -// FUNCTION: LEGO1 0x1006d5d0 -void LegoLocomotionAnimPresenter::ReadyTickle() -{ - LegoLoopingAnimPresenter::ReadyTickle(); - - if (m_currentWorld != NULL && m_currentTickleState == e_starting) { - m_currentWorld->Add(this); - if (m_compositePresenter != NULL) { - SendToCompositePresenter(Lego()); - } - - m_unk0xd4++; - } -} - -// FUNCTION: LEGO1 0x1006d610 -// FUNCTION: BETA10 0x10052a34 -void LegoLocomotionAnimPresenter::StartingTickle() -{ - if (m_subscriber->PeekData()) { - MxStreamChunk* chunk = m_subscriber->PopData(); - m_subscriber->FreeDataChunk(chunk); - } - - if (m_roiMapList->GetNumElements() != 0) { - ProgressTickleState(e_streaming); - } -} - -// FUNCTION: LEGO1 0x1006d660 -void LegoLocomotionAnimPresenter::StreamingTickle() -{ - if (m_unk0xd4 == 0) { - EndAction(); - } -} - -// FUNCTION: LEGO1 0x1006d670 -void LegoLocomotionAnimPresenter::EndAction() -{ - if (m_action) { - MxVideoPresenter::EndAction(); - } -} - -// FUNCTION: LEGO1 0x1006d680 -// FUNCTION: BETA10 0x10052b3d -void LegoLocomotionAnimPresenter::FUN_1006d680(LegoAnimActor* p_actor, MxFloat p_value) -{ - AUTOLOCK(m_criticalSection); - - MxVariableTable* variableTable = VariableTable(); - - const char* key = ((LegoAnimNodeData*) m_anim->GetRoot()->GetData())->GetName(); - variableTable->SetVariable(key, p_actor->GetROI()->GetName()); - - FUN_100695c0(); - FUN_10069b10(); - - if (m_roiMap != NULL) { - m_roiMapList->Append(m_roiMap); - p_actor->FUN_1001c450(m_anim, p_value, m_roiMap, m_roiMapSize); - m_roiMap = NULL; - } - - variableTable->SetVariable(key, ""); - - if (m_sceneROIs != NULL) { - delete m_sceneROIs; - m_sceneROIs = NULL; - } -} diff --git a/LEGO1/lego/legoomni/src/video/legoloopinganimpresenter.cpp b/LEGO1/lego/legoomni/src/video/legoloopinganimpresenter.cpp deleted file mode 100644 index cf75ce47..00000000 --- a/LEGO1/lego/legoomni/src/video/legoloopinganimpresenter.cpp +++ /dev/null @@ -1,83 +0,0 @@ -#include "legoloopinganimpresenter.h" - -#include "anim/legoanim.h" -#include "legocameracontroller.h" -#include "legoworld.h" -#include "mxcompositepresenter.h" -#include "mxdsaction.h" -#include "mxdssubscriber.h" - -DECOMP_SIZE_ASSERT(LegoLoopingAnimPresenter, 0xc0) - -// FUNCTION: LEGO1 0x1006caa0 -// FUNCTION: BETA10 0x1005223d -void LegoLoopingAnimPresenter::StreamingTickle() -{ - if (m_subscriber->PeekData()) { - MxStreamChunk* chunk = m_subscriber->PopData(); - m_subscriber->FreeDataChunk(chunk); - } - - if (m_unk0x95) { - ProgressTickleState(e_done); - if (m_compositePresenter) { - if (m_compositePresenter->IsA("LegoAnimMMPresenter")) { - m_compositePresenter->VTable0x60(this); - } - } - } - else { - if (m_action->GetDuration() != -1) { - if (m_action->GetElapsedTime() > m_action->GetDuration() + m_action->GetStartTime()) { - m_unk0x95 = TRUE; - } - } - } -} - -// FUNCTION: LEGO1 0x1006cb40 -// FUNCTION: BETA10 0x1005239a -void LegoLoopingAnimPresenter::PutFrame() -{ - MxLong time; - - if (m_action->GetStartTime() <= m_action->GetElapsedTime()) { - time = (m_action->GetElapsedTime() - m_action->GetStartTime()) % m_anim->GetDuration(); - } - else { - time = 0; - } - - FUN_1006b9a0(m_anim, time, m_unk0x78); - - if (m_unk0x8c != NULL && m_currentWorld != NULL && m_currentWorld->GetCameraController() != NULL) { - for (MxS32 i = 0; i < m_unk0x94; i++) { - if (m_unk0x8c[i] != NULL) { - MxMatrix mat(m_unk0x8c[i]->GetLocal2World()); - - Vector3 pos(mat[0]); - Vector3 dir(mat[1]); - Vector3 up(mat[2]); - Vector3 und(mat[3]); - - float possqr = sqrt(pos.LenSquared()); - float dirsqr = sqrt(dir.LenSquared()); - float upsqr = sqrt(up.LenSquared()); - - up = und; - - up -= m_currentWorld->GetCameraController()->GetWorldLocation(); - dir /= dirsqr; - pos.EqualsCross(dir, up); - pos.Unitize(); - up.EqualsCross(pos, dir); - pos *= possqr; - dir *= dirsqr; - up *= upsqr; - - m_unk0x8c[i]->SetLocal2World(mat); - m_unk0x8c[i]->WrappedUpdateWorldData(); - } - } - } -} diff --git a/LEGO1/lego/legoomni/src/video/legomodelpresenter.cpp b/LEGO1/lego/legoomni/src/video/legomodelpresenter.cpp index 405154c1..25ec48a4 100644 --- a/LEGO1/lego/legoomni/src/video/legomodelpresenter.cpp +++ b/LEGO1/lego/legoomni/src/video/legomodelpresenter.cpp @@ -35,7 +35,7 @@ void LegoModelPresenter::configureLegoModelPresenter(MxS32 p_modelPresenterConfi // FUNCTION: LEGO1 0x1007f670 void LegoModelPresenter::Destroy(MxBool p_fromDestructor) { - m_criticalSection.Enter(); + ENTER(m_criticalSection); m_roi = NULL; m_addedToView = FALSE; m_criticalSection.Leave(); @@ -197,7 +197,7 @@ MxResult LegoModelPresenter::CreateROI(MxDSChunk* p_chunk) // FUNCTION: LEGO1 0x1007ff70 // FUNCTION: BETA10 0x10099061 -MxResult LegoModelPresenter::FUN_1007ff70( +MxResult LegoModelPresenter::CreateROI( MxDSChunk& p_chunk, LegoEntity* p_entity, MxBool p_roiVisible, diff --git a/LEGO1/lego/legoomni/src/video/legopalettepresenter.cpp b/LEGO1/lego/legoomni/src/video/legopalettepresenter.cpp index ea5c7326..e76b90d9 100644 --- a/LEGO1/lego/legoomni/src/video/legopalettepresenter.cpp +++ b/LEGO1/lego/legoomni/src/video/legopalettepresenter.cpp @@ -31,7 +31,7 @@ void LegoPalettePresenter::Init() // FUNCTION: LEGO1 0x1007a0e0 void LegoPalettePresenter::Destroy(MxBool p_fromDestructor) { - m_criticalSection.Enter(); + ENTER(m_criticalSection); if (m_palette) { delete m_palette; } diff --git a/LEGO1/lego/legoomni/src/video/legopartpresenter.cpp b/LEGO1/lego/legoomni/src/video/legopartpresenter.cpp index 23b8f44a..10b72caa 100644 --- a/LEGO1/lego/legoomni/src/video/legopartpresenter.cpp +++ b/LEGO1/lego/legoomni/src/video/legopartpresenter.cpp @@ -22,6 +22,8 @@ MxS32 g_partPresenterConfig1 = 1; // GLOBAL: LEGO1 0x100f7aa4 MxS32 g_partPresenterConfig2 = 100; +vector LegoPartPresenter::g_lodLists; + // FUNCTION: LEGO1 0x1007c990 void LegoPartPresenter::configureLegoPartPresenter(MxS32 p_partPresenterConfig1, MxS32 p_partPresenterConfig2) { @@ -39,7 +41,7 @@ MxResult LegoPartPresenter::AddToManager() // FUNCTION: LEGO1 0x1007c9d0 void LegoPartPresenter::Destroy(MxBool p_fromDestructor) { - m_criticalSection.Enter(); + ENTER(m_criticalSection); VideoManager()->UnregisterPresenter(*this); if (m_parts) { @@ -189,7 +191,7 @@ MxResult LegoPartPresenter::Read(MxDSChunk& p_chunk) } if (j == 0) { - if (surplusLODs != 0 && lod->GetUnknown0x08Test8()) { + if (surplusLODs != 0 && lod->IsExtraLOD()) { numLODs++; surplusLODs--; } @@ -261,6 +263,8 @@ void LegoPartPresenter::Store() lodCursor.Detach(); lodList->PushBack(lod); } + + g_lodLists.push_back(lodList); } else { lodList->Release(); diff --git a/LEGO1/lego/legoomni/src/video/legophonemepresenter.cpp b/LEGO1/lego/legoomni/src/video/legophonemepresenter.cpp index 353480fc..6ea4d36d 100644 --- a/LEGO1/lego/legoomni/src/video/legophonemepresenter.cpp +++ b/LEGO1/lego/legoomni/src/video/legophonemepresenter.cpp @@ -25,8 +25,8 @@ void LegoPhonemePresenter::Init() { m_rectCount = 0; m_textureInfo = NULL; - m_unk0x70 = FALSE; - m_unk0x84 = FALSE; + m_reusedPhoneme = FALSE; + m_isPartOfAnimMM = FALSE; } // FUNCTION: LEGO1 0x1004e3d0 @@ -49,7 +49,7 @@ void LegoPhonemePresenter::StartingTickle() if (m_compositePresenter != NULL && m_compositePresenter->IsA("LegoAnimMMPresenter")) { entityROI = FindROI(m_roiName.GetData()); - m_unk0x84 = TRUE; + m_isPartOfAnimMM = TRUE; } else { entityROI = CharacterManager()->GetActorROI(m_roiName.GetData(), TRUE); @@ -81,7 +81,7 @@ void LegoPhonemePresenter::StartingTickle() phoneme->SetCount(phoneme->GetCount() + 1); cursor.SetValue(phoneme); - m_unk0x70 = TRUE; + m_reusedPhoneme = TRUE; } } } @@ -139,7 +139,7 @@ void LegoPhonemePresenter::EndAction() if (phoneme->GetCount() == 1) { LegoROI* roi; - if (m_unk0x84) { + if (m_isPartOfAnimMM) { roi = FindROI(m_roiName.GetData()); } else { @@ -150,7 +150,7 @@ void LegoPhonemePresenter::EndAction() CharacterManager()->SetHeadTexture(roi, NULL); } - if (!m_unk0x84) { + if (!m_isPartOfAnimMM) { CharacterManager()->ReleaseActor(m_roiName.GetData()); } @@ -163,7 +163,7 @@ void LegoPhonemePresenter::EndAction() cursor.SetValue(phoneme); } - if (!m_unk0x84) { + if (!m_isPartOfAnimMM) { CharacterManager()->ReleaseActor(m_roiName.GetData()); } } diff --git a/LEGO1/lego/legoomni/src/video/legovideomanager.cpp b/LEGO1/lego/legoomni/src/video/legovideomanager.cpp index a0173224..53c79a5f 100644 --- a/LEGO1/lego/legoomni/src/video/legovideomanager.cpp +++ b/LEGO1/lego/legoomni/src/video/legovideomanager.cpp @@ -108,7 +108,7 @@ MxResult LegoVideoManager::Create(MxVideoParam& p_videoParam, MxU32 p_frequencyM goto done; } - if (deviceEnumerate.DoEnumerate() != SUCCESS) { + if (deviceEnumerate.DoEnumerate(hwnd) != SUCCESS) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "LegoDeviceEnumerate::DoEnumerate failed"); goto done; } @@ -272,14 +272,13 @@ void LegoVideoManager::MoveCursor(MxS32 p_cursorX, MxS32 p_cursorY) { m_cursorX = p_cursorX; m_cursorY = p_cursorY; - m_drawCursor = TRUE; - if (623 < p_cursorX) { - m_cursorX = 623; + if (640 < p_cursorX) { + m_cursorX = 640; } - if (463 < p_cursorY) { - m_cursorY = 463; + if (480 < p_cursorY) { + m_cursorY = 480; } } @@ -388,15 +387,7 @@ inline void LegoVideoManager::DrawCursor() LPDIRECTDRAWSURFACE ddSurface2 = m_displaySurface->GetDirectDrawSurface2(); if (!m_cursorSurface) { - m_cursorRect.top = 0; - m_cursorRect.left = 0; - m_cursorRect.bottom = 16; - m_cursorRect.right = 16; - m_cursorSurface = MxDisplaySurface::CreateCursorSurface(); - - if (!m_cursorSurface) { - m_drawCursor = FALSE; - } + return; } ddSurface2 @@ -554,14 +545,14 @@ void LegoVideoManager::EnableFullScreenMovie(MxBool p_enable, MxBool p_scale) m_palette = m_videoParam.GetPalette()->Clone(); OverrideSkyColor(FALSE); - m_displaySurface->GetVideoParam().Flags().SetF1bit3(p_scale); + m_displaySurface->GetVideoParam().Flags().SetDoubleScaling(p_scale); m_render3d = FALSE; m_fullScreenMovie = TRUE; } else { m_displaySurface->ClearScreen(); - m_displaySurface->GetVideoParam().Flags().SetF1bit3(FALSE); + m_displaySurface->GetVideoParam().Flags().SetDoubleScaling(FALSE); // restore previous pallete RealizePalette(m_palette); @@ -586,23 +577,23 @@ void LegoVideoManager::EnableFullScreenMovie(MxBool p_enable, MxBool p_scale) } if (p_enable) { - m_displaySurface->GetVideoParam().Flags().SetF1bit3(p_scale); + m_displaySurface->GetVideoParam().Flags().SetDoubleScaling(p_scale); } else { - m_displaySurface->GetVideoParam().Flags().SetF1bit3(FALSE); + m_displaySurface->GetVideoParam().Flags().SetDoubleScaling(FALSE); } } // FUNCTION: LEGO1 0x1007c440 void LegoVideoManager::SetSkyColor(float p_red, float p_green, float p_blue) { - PALETTEENTRY colorStrucure; + PALETTEENTRY colorStructure; - colorStrucure.peRed = (p_red * 255.0f); - colorStrucure.peGreen = (p_green * 255.0f); - colorStrucure.peBlue = (p_blue * 255.0f); - colorStrucure.peFlags = D3DPAL_RESERVED | PC_NOCOLLAPSE; - m_videoParam.GetPalette()->SetSkyColor(&colorStrucure); + colorStructure.peRed = (p_red * 255.0f); + colorStructure.peGreen = (p_green * 255.0f); + colorStructure.peBlue = (p_blue * 255.0f); + colorStructure.peFlags = D3DPAL_RESERVED | PC_NOCOLLAPSE; + m_videoParam.GetPalette()->SetSkyColor(&colorStructure); m_videoParam.GetPalette()->SetOverrideSkyColor(TRUE); m_3dManager->GetLego3DView()->GetView()->SetBackgroundColor(p_red, p_green, p_blue); } @@ -836,3 +827,30 @@ void LegoVideoManager::DrawTextToSurface32( ++p_text; } } + +void LegoVideoManager::SetCursorBitmap(const CursorBitmap* p_cursorBitmap) +{ + if (p_cursorBitmap == NULL) { + m_drawCursor = FALSE; + return; + } + + if (m_cursorSurface != NULL) { + m_cursorSurface->Release(); + m_cursorSurface = NULL; + } + + m_cursorRect.top = 0; + m_cursorRect.left = 0; + m_cursorRect.bottom = p_cursorBitmap->height; + m_cursorRect.right = p_cursorBitmap->width; + + m_cursorSurface = MxDisplaySurface::CreateCursorSurface(p_cursorBitmap); + + if (m_cursorSurface == NULL) { + m_drawCursor = FALSE; + return; + } + + m_drawCursor = TRUE; +} diff --git a/LEGO1/lego/legoomni/src/worlds/act3.cpp b/LEGO1/lego/legoomni/src/worlds/act3.cpp index 0166c9d7..8e839e3c 100644 --- a/LEGO1/lego/legoomni/src/worlds/act3.cpp +++ b/LEGO1/lego/legoomni/src/worlds/act3.cpp @@ -32,7 +32,7 @@ DECOMP_SIZE_ASSERT(Act3ListElement, 0x0c) DECOMP_SIZE_ASSERT(Act3List, 0x10) // GLOBAL: LEGO1 0x100d94f8 -Act3Script::Script g_unk0x100d94f8[] = { +Act3Script::Script g_pizzaHitSounds[] = { Act3Script::c_sns02xni_PlayWav, Act3Script::c_sns03xni_PlayWav, Act3Script::c_sns04xni_PlayWav, @@ -52,7 +52,7 @@ Act3Script::Script g_unk0x100d94f8[] = { }; // GLOBAL: LEGO1 0x100d9538 -Act3Script::Script g_unk0x100d9538[] = { +Act3Script::Script g_pizzaMissSounds[] = { Act3Script::c_sns19xni_PlayWav, Act3Script::c_sns20xni_PlayWav, Act3Script::c_sns22xni_PlayWav, @@ -62,7 +62,7 @@ Act3Script::Script g_unk0x100d9538[] = { }; // GLOBAL: LEGO1 0x100d9550 -Act3Script::Script g_unk0x100d9550[] = { +Act3Script::Script g_copDonutSounds[] = { Act3Script::c_sns25xni_PlayWav, Act3Script::c_sns26xni_PlayWav, Act3Script::c_sns27xni_PlayWav, @@ -74,7 +74,7 @@ Act3Script::Script g_unk0x100d9550[] = { }; // GLOBAL: LEGO1 0x100d9570 -Act3Script::Script g_unk0x100d9570[] = { +Act3Script::Script g_donutMissSounds[] = { Act3Script::c_sns30xni_PlayWav, Act3Script::c_sns31xni_PlayWav, Act3Script::c_sns32xni_PlayWav, @@ -84,7 +84,7 @@ Act3Script::Script g_unk0x100d9570[] = { }; // GLOBAL: LEGO1 0x100d9588 -Act3Script::Script g_unk0x100d9588[] = { +Act3Script::Script g_islanderSounds[] = { Act3Script::c_sns43xma_PlayWav, Act3Script::c_sns46xin_PlayWav, Act3Script::c_sns60xna_PlayWav, Act3Script::c_sns52xro_PlayWav, Act3Script::c_sns58xna_PlayWav, Act3Script::c_sns68xbu_PlayWav, Act3Script::c_sns59xna_PlayWav, Act3Script::c_sns51xin_PlayWav, Act3Script::c_sns61xva_PlayWav, @@ -95,7 +95,7 @@ Act3Script::Script g_unk0x100d9588[] = { }; // GLOBAL: LEGO1 0x100d95d8 -Act3Script::Script g_unk0x100d95d8[] = { +Act3Script::Script g_bricksterDonutSounds[] = { Act3Script::c_tns080br_PlayWav, Act3Script::c_tnsx07br_PlayWav, Act3Script::c_snsxx2br_PlayWav, @@ -110,16 +110,16 @@ Act3Script::Script g_unk0x100d95e8[] = {Act3Script::c_tlp053in_RunAnim, Act3Script::c_tlp064la_RunAnim, Act3Script::c_tlp068in_RunAnim}; // FUNCTION: LEGO1 0x10071d40 -void Act3List::Insert(MxS32 p_objectId, MxS32 p_option) +void Act3List::Insert(MxS32 p_objectId, InsertMode p_option) { if (m_unk0x0c) { return; } switch (p_option) { - case 1: + case InsertMode::e_replaceAction: if (!empty()) { - FUN_10071fa0(); + DeleteActionWrapper(); push_back(Act3ListElement(p_objectId, p_option, FALSE)); } else { @@ -127,7 +127,7 @@ void Act3List::Insert(MxS32 p_objectId, MxS32 p_option) push_back(Act3ListElement(p_objectId, p_option, TRUE)); } break; - case 2: + case InsertMode::e_queueAction: if (empty()) { push_back(Act3ListElement(p_objectId, p_option, TRUE)); InvokeAction(Extra::e_start, *g_act3Script, p_objectId, NULL); @@ -136,7 +136,7 @@ void Act3List::Insert(MxS32 p_objectId, MxS32 p_option) push_back(Act3ListElement(p_objectId, p_option, FALSE)); } break; - case 3: + case InsertMode::e_onlyIfEmpty: if (empty()) { push_back(Act3ListElement(p_objectId, p_option, TRUE)); InvokeAction(Extra::e_start, *g_act3Script, p_objectId, NULL); @@ -146,7 +146,7 @@ void Act3List::Insert(MxS32 p_objectId, MxS32 p_option) } // FUNCTION: LEGO1 0x10071fa0 -void Act3List::FUN_10071fa0() +void Act3List::DeleteActionWrapper() { DeleteAction(); } @@ -162,7 +162,7 @@ void Act3List::Clear() } for (Act3List::iterator it = begin(); it != end();) { - if ((*it).m_unk0x08) { + if ((*it).m_hasStarted) { MxDSAction ds; ds.SetAtomId(*g_act3Script); ds.SetObjectId((*it).m_objectId); @@ -173,50 +173,64 @@ void Act3List::Clear() } } +// Removes the element with the given objectId from the list, or the first if `p_objectId` is zero. // FUNCTION: LEGO1 0x100720d0 -void Act3List::FUN_100720d0(MxU32 p_objectId) +void Act3List::RemoveByObjectIdOrFirst(MxU32 p_objectId) { - if (m_unk0x0c == 0) { - MxU32 removed = FALSE; + if (m_unk0x0c) { + return; + } - if (!empty()) { - if (p_objectId != 0) { - for (Act3List::iterator it = begin(); it != end(); it++) { - if ((*it).m_unk0x08 && (*it).m_objectId == p_objectId) { - erase(it); - removed = TRUE; - break; - } - } - } - else { - pop_front(); + MxU32 removed = FALSE; + Act3List::iterator it; + // This iterator appears to be unnecessary - maybe left in by accident, or it was used for assertions. + // Removing it decreases the match percentage. + Act3List::iterator unusedIterator; + + if (empty()) { + return; + } + + if (!p_objectId) { + pop_front(); + removed = TRUE; + } + else { + for (it = begin(); it != end(); it++) { + // Removing this variable decreases the match, but replacing `*it` by `unused` below also does. + Act3ListElement& unused = *it; + + if ((*it).m_hasStarted && (*it).m_objectId == p_objectId) { + erase(it); removed = TRUE; + break; } + } + } - if (removed && size() > 0) { - // TODO: Match - Act3List::iterator it = begin(); - Act3ListElement& item = *(it++); + if (removed && size() > 0) { + it = begin(); + unusedIterator = it; + Act3ListElement& firstItem = front(); + it++; - for (; it != end(); it++) { - if ((*it).m_unk0x04 == 1) { - for (Act3List::iterator it2 = begin(); it2 != it;) { - if ((*it2).m_unk0x08) { - FUN_10071fa0(); - return; - } - - it2 = erase(it2); - } + while (it != end()) { + if ((*it).m_unk0x04 == 1) { + for (Act3List::iterator it2 = begin(); it2 != it; erase(it2++)) { + if ((*it2).m_hasStarted) { + DeleteActionWrapper(); + return; } } - - if (!item.m_unk0x08) { - item.m_unk0x08 = TRUE; - InvokeAction(Extra::e_start, *g_act3Script, item.m_objectId, NULL); - } } + + it++; + unusedIterator++; + } + + if (!firstItem.m_hasStarted) { + firstItem.m_hasStarted = TRUE; + InvokeAction(Extra::e_start, *g_act3Script, firstItem.m_objectId, NULL); } } } @@ -404,65 +418,65 @@ MxResult Act3::ShootDonut(LegoPathController* p_controller, Vector3& p_location, // FUNCTION: LEGO1 0x10072ad0 // FUNCTION: BETA10 0x10015eec -void Act3::FUN_10072ad0(undefined4 p_param1) +void Act3::TriggerHitSound(undefined4 p_param1) { float time = Timer()->GetTime(); Act3Script::Script objectId; switch (p_param1) { case 1: { - if (m_unk0x4218 >= sizeOfArray(g_unk0x100d94f8)) { - m_unk0x4218 = 0; + if (m_pizzaHitSound >= sizeOfArray(g_pizzaHitSounds)) { + m_pizzaHitSound = 0; } - objectId = g_unk0x100d94f8[m_unk0x4218++]; + objectId = g_pizzaHitSounds[m_pizzaHitSound++]; break; } case 2: { - if (m_unk0x4219 >= sizeOfArray(g_unk0x100d9538) - 1) { - m_unk0x4219 = 0; + if (m_pizzaMissSound >= sizeOfArray(g_pizzaMissSounds) - 1) { + m_pizzaMissSound = 0; } - objectId = g_unk0x100d9538[m_unk0x4219++]; + objectId = g_pizzaMissSounds[m_pizzaMissSound++]; break; } case 3: { - if (m_unk0x421a >= sizeOfArray(g_unk0x100d9550)) { - m_unk0x421a = 0; + if (m_copDonutSound >= sizeOfArray(g_copDonutSounds)) { + m_copDonutSound = 0; } - objectId = g_unk0x100d9550[m_unk0x421a++]; + objectId = g_copDonutSounds[m_copDonutSound++]; break; } case 4: { - if (m_unk0x421b >= sizeOfArray(g_unk0x100d9570)) { - m_unk0x421b = 0; + if (m_donutMissSound >= sizeOfArray(g_donutMissSounds)) { + m_donutMissSound = 0; } - objectId = g_unk0x100d9570[m_unk0x421b++]; + objectId = g_donutMissSounds[m_donutMissSound++]; break; } case 5: { - if (m_unk0x421c >= sizeOfArray(g_unk0x100d9588)) { - m_unk0x421c = 0; + if (m_islanderSound >= sizeOfArray(g_islanderSounds)) { + m_islanderSound = 0; } - objectId = g_unk0x100d9588[m_unk0x421c++]; + objectId = g_islanderSounds[m_islanderSound++]; break; } case 6: { - if (m_unk0x421d >= sizeOfArray(g_unk0x100d95d8)) { - m_unk0x421d = 0; + if (m_bricksterDonutSound >= sizeOfArray(g_bricksterDonutSounds)) { + m_bricksterDonutSound = 0; } - m_unk0x4220.Insert(g_unk0x100d95d8[m_unk0x421d++], 1); + m_unk0x4220.Insert(g_bricksterDonutSounds[m_bricksterDonutSound++], Act3List::e_replaceAction); return; } default: return; } - m_unk0x4220.Insert(objectId, 3); + m_unk0x4220.Insert(objectId, Act3List::e_onlyIfEmpty); } // FUNCTION: LEGO1 0x10072c30 @@ -553,7 +567,7 @@ MxLong Act3::Notify(MxParam& p_param) if (param.GetAction() != NULL && param.GetAction()->GetAtomId() == *g_act3Script) { if (param.GetAction()->GetObjectId() == Act3Script::c_HelicopterDashboard) { MxDSAction action; - FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + Disable(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); SetAppCursor(e_cursorArrow); VideoManager()->Get3DManager()->SetFrustrum(45.0f, 0.1f, 125.0f); @@ -576,13 +590,12 @@ MxLong Act3::Notify(MxParam& p_param) m_cop2->VTable0xa8(); m_brickster->VTable0xa8(); - - m_unk0x4218 = 0; - m_unk0x4219 = 0; - m_unk0x421a = 0; - m_unk0x421b = 0; - m_unk0x421c = 0; - m_unk0x421d = 0; + m_pizzaHitSound = 0; + m_pizzaMissSound = 0; + m_copDonutSound = 0; + m_donutMissSound = 0; + m_islanderSound = 0; + m_bricksterDonutSound = 0; MxS32 length; LegoBuildingInfo* info = BuildingManager()->GetInfoArray(length); @@ -614,7 +627,7 @@ MxLong Act3::Notify(MxParam& p_param) } while (length < (MxS32) sizeOfArray(m_helicopterDots)); } else { - m_unk0x4220.FUN_100720d0(param.GetAction()->GetObjectId()); + m_unk0x4220.RemoveByObjectIdOrFirst(param.GetAction()->GetObjectId()); } } break; @@ -634,9 +647,9 @@ MxLong Act3::Notify(MxParam& p_param) case c_notificationEndAnim: if (m_state->m_unk0x08 == 1) { assert(m_copter && m_brickster && m_cop1 && m_cop2); - m_unk0x4220.FUN_100720d0(0); + m_unk0x4220.RemoveByObjectIdOrFirst(0); m_state->m_unk0x08 = 0; - FUN_10015820(TRUE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + Disable(TRUE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); m_copter->HandleClick(); m_copter->m_state->m_unk0x08 = 1; m_copter->HandleEndAnim((LegoEndAnimNotificationParam&) param); @@ -687,7 +700,7 @@ MxResult Act3::Tickle() if (m_unk0x426c != (Act3Script::Script) 0) { if (AnimationManager()->FUN_10064ee0(m_unk0x426c)) { - FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + Disable(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); TickleManager()->UnregisterClient(this); m_unk0x426c = (Act3Script::Script) 0; } @@ -702,7 +715,7 @@ MxResult Act3::FUN_10073360(Act3Ammo& p_ammo, const Vector3& p_param2) { assert(m_brickster); m_brickster->FUN_100417a0(p_ammo, p_param2); - FUN_10072ad0(1); + TriggerHitSound(1); return SUCCESS; } @@ -719,7 +732,7 @@ MxResult Act3::FUN_10073390(Act3Ammo& p_ammo, const Vector3& p_param2) m_cop2->FUN_10040350(p_ammo, p_param2); } - FUN_10072ad0(3); + TriggerHitSound(3); g_unk0x100f7814++; return SUCCESS; } @@ -780,6 +793,8 @@ void Act3::GoodEnding(const Matrix4& p_destination) m_copter->m_unk0x1a8, m_copter->m_unk0x1f4 ); + + EmitGameEvent(e_goodEnding); } // FUNCTION: LEGO1 0x10073500 @@ -859,6 +874,8 @@ void Act3::BadEnding(const Matrix4& p_destination) m_copter->m_unk0x1a8, m_copter->m_unk0x1f4 ); + + EmitGameEvent(e_badEnding); } // FUNCTION: LEGO1 0x10073a60 @@ -882,7 +899,7 @@ void Act3::Enable(MxBool p_enable) GameState()->StopArea(LegoGameState::e_infomain); } - FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + Disable(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); PlayMusic(JukeboxScript::c_Act3Music); GameState()->m_isDirty = TRUE; diff --git a/LEGO1/lego/legoomni/src/worlds/elevatorbottom.cpp b/LEGO1/lego/legoomni/src/worlds/elevatorbottom.cpp index 7affe1c8..6e1d484d 100644 --- a/LEGO1/lego/legoomni/src/worlds/elevatorbottom.cpp +++ b/LEGO1/lego/legoomni/src/worlds/elevatorbottom.cpp @@ -79,7 +79,7 @@ void ElevatorBottom::ReadyWorld() { LegoWorld::ReadyWorld(); PlayMusic(JukeboxScript::c_InformationCenter_Music); - FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + Disable(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); } // FUNCTION: LEGO1 0x100181d0 @@ -87,7 +87,7 @@ MxLong ElevatorBottom::HandleControl(LegoControlManagerNotificationParam& p_para { MxLong result = 0; - if (p_param.m_unk0x28 == 1) { + if (p_param.m_enabledChild == 1) { switch (p_param.m_clickedObjectId) { case ElevbottScript::c_LeftArrow_Ctl: m_destLocation = LegoGameState::e_infodoor; diff --git a/LEGO1/lego/legoomni/src/worlds/gasstation.cpp b/LEGO1/lego/legoomni/src/worlds/gasstation.cpp index 155a839b..d83c172d 100644 --- a/LEGO1/lego/legoomni/src/worlds/gasstation.cpp +++ b/LEGO1/lego/legoomni/src/worlds/gasstation.cpp @@ -267,7 +267,7 @@ void GasStation::ReadyWorld() break; } - FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + Disable(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); } // FUNCTION: LEGO1 0x10005590 @@ -330,7 +330,7 @@ MxLong GasStation::HandleEndAction(MxEndActionNotificationParam& p_param) break; case GasStationState::e_afterAcceptingQuest: m_state->m_state = GasStationState::e_beforeExitingForQuest; - ((Act1State*) GameState()->GetState("Act1State"))->m_unk0x018 = 7; + ((Act1State*) GameState()->GetState("Act1State"))->m_state = Act1State::e_transitionToTowtrack; m_destLocation = LegoGameState::e_garageExited; m_radio.Stop(); BackgroundAudioManager()->Stop(); @@ -389,7 +389,7 @@ MxLong GasStation::HandleButtonDown(LegoControlManagerNotificationParam& p_param // FUNCTION: BETA10 0x10029445 MxLong GasStation::HandleControl(LegoControlManagerNotificationParam& p_param) { - if (p_param.m_unk0x28 == 1) { + if (p_param.m_enabledChild == 1) { MxDSAction action; switch (p_param.m_clickedObjectId) { diff --git a/LEGO1/lego/legoomni/src/worlds/hospital.cpp b/LEGO1/lego/legoomni/src/worlds/hospital.cpp index 66d22168..cd75e1a1 100644 --- a/LEGO1/lego/legoomni/src/worlds/hospital.cpp +++ b/LEGO1/lego/legoomni/src/worlds/hospital.cpp @@ -48,7 +48,7 @@ Hospital::Hospital() m_flashingLeds = 0; m_copLedAnimTimer = 0; m_pizzaLedAnimTimer = 0; - m_unk0x128 = 0; + m_exited = FALSE; NotificationManager()->Register(this); } @@ -216,7 +216,7 @@ void Hospital::ReadyWorld() m_setWithCurrentAction = 1; } - FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + Disable(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); } // FUNCTION: LEGO1 0x10074dd0 @@ -367,10 +367,10 @@ MxLong Hospital::HandleEndAction(MxEndActionNotificationParam& p_param) case HospitalState::e_afterAcceptingQuest: m_hospitalState->m_state = HospitalState::e_beforeEnteringAmbulance; act1State = (Act1State*) GameState()->GetState("Act1State"); - act1State->SetUnknown18(9); + act1State->SetState(Act1State::e_transitionToAmbulance); case HospitalState::e_exitToFront: - if (m_unk0x128 == 0) { - m_unk0x128 = 1; + if (m_exited == FALSE) { + m_exited = TRUE; m_destLocation = LegoGameState::e_hospitalExited; DeleteObjects(&m_atomId, HospitalScript::c_hho002cl_RunAnim, HospitalScript::c_hho006cl_RunAnim); @@ -378,8 +378,8 @@ MxLong Hospital::HandleEndAction(MxEndActionNotificationParam& p_param) } break; case HospitalState::e_exitToInfocenter: - if (m_unk0x128 == 0) { - m_unk0x128 = 1; + if (m_exited == FALSE) { + m_exited = TRUE; m_destLocation = LegoGameState::e_infomain; DeleteObjects(&m_atomId, HospitalScript::c_hho002cl_RunAnim, HospitalScript::c_hho006cl_RunAnim); @@ -412,8 +412,8 @@ MxLong Hospital::HandleButtonDown(LegoControlManagerNotificationParam& p_param) m_interactionMode = 3; if (m_hospitalState->m_state == HospitalState::e_explainQuestShort) { - if (m_unk0x128 == 0) { - m_unk0x128 = 1; + if (m_exited == FALSE) { + m_exited = TRUE; TickleManager()->UnregisterClient(this); @@ -421,7 +421,7 @@ MxLong Hospital::HandleButtonDown(LegoControlManagerNotificationParam& p_param) Act1State* act1State = (Act1State*) GameState()->GetState("Act1State"); assert(act1State); - act1State->m_unk0x018 = 9; + act1State->m_state = Act1State::e_transitionToAmbulance; m_destLocation = LegoGameState::e_hospitalExited; DeleteObjects( @@ -555,7 +555,7 @@ MxLong Hospital::HandleButtonDown(LegoControlManagerNotificationParam& p_param) // FUNCTION: LEGO1 0x10075f90 MxBool Hospital::HandleControl(LegoControlManagerNotificationParam& p_param) { - if (p_param.m_unk0x28 == 1) { + if (p_param.m_enabledChild == 1) { switch (p_param.m_clickedObjectId) { case HospitalScript::c_Info_Ctl: BackgroundAudioManager()->RaiseVolume(); @@ -568,8 +568,8 @@ MxBool Hospital::HandleControl(LegoControlManagerNotificationParam& p_param) m_currentAction = HospitalScript::c_hho016cl_RunAnim; m_setWithCurrentAction = 1; } - else if (m_unk0x128 == 0) { - m_unk0x128 = 1; + else if (m_exited == FALSE) { + m_exited = TRUE; m_hospitalState->m_state = HospitalState::e_exitImmediately; m_destLocation = LegoGameState::e_infomain; @@ -589,8 +589,8 @@ MxBool Hospital::HandleControl(LegoControlManagerNotificationParam& p_param) m_currentAction = HospitalScript::c_hho016cl_RunAnim; m_setWithCurrentAction = 1; } - else if (m_unk0x128 == 0) { - m_unk0x128 = 1; + else if (m_exited == FALSE) { + m_exited = TRUE; m_hospitalState->m_state = HospitalState::e_exitImmediately; m_destLocation = LegoGameState::e_hospitalExited; diff --git a/LEGO1/lego/legoomni/src/worlds/infocenter.cpp b/LEGO1/lego/legoomni/src/worlds/infocenter.cpp index f9bfb4eb..141b8f85 100644 --- a/LEGO1/lego/legoomni/src/worlds/infocenter.cpp +++ b/LEGO1/lego/legoomni/src/worlds/infocenter.cpp @@ -138,14 +138,14 @@ Infocenter::Infocenter() memset(&m_glowInfo, 0, sizeof(m_glowInfo)); - m_unk0x1c8 = -1; + m_enabledGlowControl = -1; SetAppCursor(e_cursorBusy); NotificationManager()->Register(this); m_infoManDialogueTimer = 0; m_bookAnimationTimer = 0; - m_unk0x1d4 = 0; - m_unk0x1d6 = 0; + m_playingMovieCounter = 0; + m_bigInfoBlinkTimer = 0; } // FUNCTION: LEGO1 0x1006ec80 @@ -300,35 +300,38 @@ MxLong Infocenter::HandleEndAction(MxEndActionNotificationParam& p_param) action->GetObjectId() == InfomainScript::c_Pepper_All_Movie || action->GetObjectId() == InfomainScript::c_Nick_All_Movie || action->GetObjectId() == InfomainScript::c_Laura_All_Movie)) { - if (m_unk0x1d4) { - m_unk0x1d4--; + if (m_playingMovieCounter) { + m_playingMovieCounter--; } - if (!m_unk0x1d4) { + if (!m_playingMovieCounter) { PlayMusic(JukeboxScript::c_InformationCenter_Music); - GameState()->SetActor(m_selectedCharacter); - switch (m_selectedCharacter) { - case e_pepper: - PlayAction(InfomainScript::c_avo901in_RunAnim); - break; - case e_mama: - PlayAction(InfomainScript::c_avo902in_RunAnim); - break; - case e_papa: - PlayAction(InfomainScript::c_avo903in_RunAnim); - break; - case e_nick: - PlayAction(InfomainScript::c_avo904in_RunAnim); - break; - case e_laura: - PlayAction(InfomainScript::c_avo905in_RunAnim); - break; - default: - break; + if (!Lego()->IsVersion10()) { + GameState()->SetActor(m_selectedCharacter); + + switch (m_selectedCharacter) { + case e_pepper: + PlayAction(InfomainScript::c_avo901in_RunAnim); + break; + case e_mama: + PlayAction(InfomainScript::c_avo902in_RunAnim); + break; + case e_papa: + PlayAction(InfomainScript::c_avo903in_RunAnim); + break; + case e_nick: + PlayAction(InfomainScript::c_avo904in_RunAnim); + break; + case e_laura: + PlayAction(InfomainScript::c_avo905in_RunAnim); + break; + default: + break; + } + + UpdateFrameHot(TRUE); } - - UpdateFrameHot(TRUE); } } @@ -338,9 +341,9 @@ MxLong Infocenter::HandleEndAction(MxEndActionNotificationParam& p_param) return result; } - if (action->GetObjectId() == InfomainScript::c_iicx26in_RunAnim) { - ControlManager()->FUN_100293c0(InfomainScript::c_BigInfo_Ctl, action->GetAtomId().GetInternal(), 0); - m_unk0x1d6 = 0; + if (action->GetObjectId() == InfomainScript::c_iicx26in_RunAnim - Lego()->IsVersion10()) { + ControlManager()->UpdateEnabledChild(InfomainScript::c_BigInfo_Ctl, action->GetAtomId().GetInternal(), 0); + m_bigInfoBlinkTimer = 0; } switch (m_infocenterState->m_unk0x74) { @@ -445,8 +448,8 @@ void Infocenter::ReadyWorld() { m_infoManDialogueTimer = 0; m_bookAnimationTimer = 0; - m_unk0x1d4 = 0; - m_unk0x1d6 = 0; + m_playingMovieCounter = 0; + m_bigInfoBlinkTimer = 0; MxStillPresenter* bg = (MxStillPresenter*) Find("MxStillPresenter", "Background_Bitmap"); MxStillPresenter* bgRed = (MxStillPresenter*) Find("MxStillPresenter", "BackgroundRed_Bitmap"); @@ -469,7 +472,7 @@ void Infocenter::ReadyWorld() PlayAction(InfomainScript::c_iicx18in_RunAnim); PlayMusic(JukeboxScript::c_InformationCenter_Music); - FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + Disable(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); return; case 5: default: { @@ -478,11 +481,11 @@ void Infocenter::ReadyWorld() InfomainScript::Script script = m_infocenterState->GetNextReturnDialogue(); PlayAction(script); - if (script == InfomainScript::c_iicx26in_RunAnim) { - m_unk0x1d6 = 1; + if (script == InfomainScript::c_iicx26in_RunAnim - Lego()->IsVersion10()) { // want to get back? Click on I! + m_bigInfoBlinkTimer = 1; } - FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + Disable(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); if (!m_infocenterState->HasRegistered()) { m_bookAnimationTimer = 1; @@ -493,7 +496,7 @@ void Infocenter::ReadyWorld() case 8: PlayMusic(JukeboxScript::c_InformationCenter_Music); PlayAction(InfomainScript::c_iic043in_RunAnim); - FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + Disable(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); return; case 0xf: m_infocenterState->m_unk0x74 = 2; @@ -503,7 +506,7 @@ void Infocenter::ReadyWorld() PlayAction(InfomainScript::c_iicx17in_RunAnim); PlayMusic(JukeboxScript::c_InformationCenter_Music); - FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + Disable(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); return; } break; @@ -512,7 +515,7 @@ void Infocenter::ReadyWorld() PlayMusic(JukeboxScript::c_InformationCenter_Music); bgRed->Enable(TRUE); PlayAction(InfomainScript::c_iic043in_RunAnim); - FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + Disable(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); return; } @@ -542,7 +545,7 @@ void Infocenter::ReadyWorld() PlayAction(script); InputManager()->DisableInputProcessing(); - FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + Disable(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); return; } @@ -557,7 +560,7 @@ void Infocenter::ReadyWorld() PlayMusic(JukeboxScript::c_InformationCenter_Music); bgRed->Enable(TRUE); PlayAction(InfomainScript::c_iic043in_RunAnim); - FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + Disable(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); return; } @@ -594,7 +597,7 @@ void Infocenter::ReadyWorld() PlayAction(script); InputManager()->DisableInputProcessing(); - FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + Disable(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); return; } @@ -607,7 +610,7 @@ void Infocenter::ReadyWorld() } m_infocenterState->m_unk0x74 = 11; - FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + Disable(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); } // FUNCTION: LEGO1 0x1006f9a0 @@ -635,37 +638,37 @@ void Infocenter::InitializeBitmaps() m_glowInfo[0].m_destCtl = (MxStillPresenter*) Find("MxStillPresenter", "Info_A_Bitmap"); assert(m_glowInfo[0].m_destCtl); m_glowInfo[0].m_area = MxRect(391, 182, 427, 230); - m_glowInfo[0].m_unk0x04 = 3; + m_glowInfo[0].m_target = InfocenterMapEntry::e_infocenter; m_glowInfo[1].m_destCtl = (MxStillPresenter*) Find("MxStillPresenter", "Boat_A_Bitmap"); assert(m_glowInfo[1].m_destCtl); m_glowInfo[1].m_area = MxRect(304, 225, 350, 268); - m_glowInfo[1].m_unk0x04 = 10; + m_glowInfo[1].m_target = InfocenterMapEntry::e_jetrace; m_glowInfo[2].m_destCtl = (MxStillPresenter*) Find("MxStillPresenter", "Race_A_Bitmap"); assert(m_glowInfo[1].m_destCtl); // DECOMP: intentional typo m_glowInfo[2].m_area = MxRect(301, 133, 347, 181); - m_glowInfo[2].m_unk0x04 = 11; + m_glowInfo[2].m_target = InfocenterMapEntry::e_carrace; m_glowInfo[3].m_destCtl = (MxStillPresenter*) Find("MxStillPresenter", "Pizza_A_Bitmap"); assert(m_glowInfo[3].m_destCtl); m_glowInfo[3].m_area = MxRect(289, 182, 335, 225); - m_glowInfo[3].m_unk0x04 = 12; + m_glowInfo[3].m_target = InfocenterMapEntry::e_pizzeria; m_glowInfo[4].m_destCtl = (MxStillPresenter*) Find("MxStillPresenter", "Gas_A_Bitmap"); assert(m_glowInfo[4].m_destCtl); m_glowInfo[4].m_area = MxRect(350, 161, 391, 209); - m_glowInfo[4].m_unk0x04 = 13; + m_glowInfo[4].m_target = InfocenterMapEntry::e_garage; m_glowInfo[5].m_destCtl = (MxStillPresenter*) Find("MxStillPresenter", "Med_A_Bitmap"); assert(m_glowInfo[5].m_destCtl); m_glowInfo[5].m_area = MxRect(392, 130, 438, 176); - m_glowInfo[5].m_unk0x04 = 14; + m_glowInfo[5].m_target = InfocenterMapEntry::e_hospital; m_glowInfo[6].m_destCtl = (MxStillPresenter*) Find("MxStillPresenter", "Cop_A_Bitmap"); assert(m_glowInfo[6].m_destCtl); m_glowInfo[6].m_area = MxRect(396, 229, 442, 272); - m_glowInfo[6].m_unk0x04 = 15; + m_glowInfo[6].m_target = InfocenterMapEntry::e_police; m_frame = (MxStillPresenter*) Find("MxStillPresenter", "FrameHot_Bitmap"); assert(m_frame); @@ -691,7 +694,7 @@ MxU8 Infocenter::HandleMouseMove(MxS32 p_x, MxS32 p_y) m_dragPresenter->SetPosition(p_x, p_y); } - FUN_10070d10(p_x, p_y); + UpdateEnabledGlowControl(p_x, p_y); return 1; } @@ -751,7 +754,7 @@ MxLong Infocenter::HandleKeyPress(SDL_Keycode p_key) MxU8 Infocenter::HandleButtonUp(MxS32 p_x, MxS32 p_y) { if (m_dragPresenter) { - MxControlPresenter* control = InputManager()->GetControlManager()->FUN_100294e0(p_x - 1, p_y - 1); + MxControlPresenter* control = InputManager()->GetControlManager()->GetControlAt(p_x - 1, p_y - 1); switch (m_dragPresenter->GetAction()->GetObjectId()) { case InfomainScript::c_PepperHot_Bitmap: @@ -780,7 +783,7 @@ MxU8 Infocenter::HandleButtonUp(MxS32 p_x, MxS32 p_y) m_radio.Stop(); BackgroundAudioManager()->Stop(); PlayAction(InfomainScript::c_Pepper_All_Movie); - m_unk0x1d4++; + m_playingMovieCounter++; } break; case InfomainScript::c_Mama_Ctl: @@ -788,7 +791,7 @@ MxU8 Infocenter::HandleButtonUp(MxS32 p_x, MxS32 p_y) m_radio.Stop(); BackgroundAudioManager()->Stop(); PlayAction(InfomainScript::c_Mama_All_Movie); - m_unk0x1d4++; + m_playingMovieCounter++; } break; case InfomainScript::c_Papa_Ctl: @@ -796,7 +799,7 @@ MxU8 Infocenter::HandleButtonUp(MxS32 p_x, MxS32 p_y) m_radio.Stop(); BackgroundAudioManager()->Stop(); PlayAction(InfomainScript::c_Papa_All_Movie); - m_unk0x1d4++; + m_playingMovieCounter++; } break; case InfomainScript::c_Nick_Ctl: @@ -804,7 +807,7 @@ MxU8 Infocenter::HandleButtonUp(MxS32 p_x, MxS32 p_y) m_radio.Stop(); BackgroundAudioManager()->Stop(); PlayAction(InfomainScript::c_Nick_All_Movie); - m_unk0x1d4++; + m_playingMovieCounter++; } break; case InfomainScript::c_Laura_Ctl: @@ -812,17 +815,17 @@ MxU8 Infocenter::HandleButtonUp(MxS32 p_x, MxS32 p_y) m_radio.Stop(); BackgroundAudioManager()->Stop(); PlayAction(InfomainScript::c_Laura_All_Movie); - m_unk0x1d4++; + m_playingMovieCounter++; } break; } } else { - if (m_unk0x1c8 != -1) { + if (m_enabledGlowControl != -1) { m_infoManDialogueTimer = 0; - switch (m_glowInfo[m_unk0x1c8].m_unk0x04) { - case 3: + switch (m_glowInfo[m_enabledGlowControl].m_target) { + case InfocenterMapEntry::e_infocenter: GameState()->SetActor(m_selectedCharacter); switch (m_selectedCharacter) { @@ -843,37 +846,37 @@ MxU8 Infocenter::HandleButtonUp(MxS32 p_x, MxS32 p_y) break; } break; - case 10: + case InfocenterMapEntry::e_jetrace: if (m_selectedCharacter) { m_destLocation = LegoGameState::e_jetraceExterior; m_infocenterState->m_unk0x74 = 5; } break; - case 11: + case InfocenterMapEntry::e_carrace: if (m_selectedCharacter) { m_destLocation = LegoGameState::e_carraceExterior; m_infocenterState->m_unk0x74 = 5; } break; - case 12: + case InfocenterMapEntry::e_pizzeria: if (m_selectedCharacter) { m_destLocation = LegoGameState::e_pizzeriaExterior; m_infocenterState->m_unk0x74 = 5; } break; - case 13: + case InfocenterMapEntry::e_garage: if (m_selectedCharacter) { m_destLocation = LegoGameState::e_garageExterior; m_infocenterState->m_unk0x74 = 5; } break; - case 14: + case InfocenterMapEntry::e_hospital: if (m_selectedCharacter) { m_destLocation = LegoGameState::e_hospitalExterior; m_infocenterState->m_unk0x74 = 5; } break; - case 15: + case InfocenterMapEntry::e_police: if (m_selectedCharacter) { m_destLocation = LegoGameState::e_policeExterior; m_infocenterState->m_unk0x74 = 5; @@ -935,7 +938,7 @@ MxU8 Infocenter::HandleButtonUp(MxS32 p_x, MxS32 p_y) } UpdateFrameHot(TRUE); - FUN_10070d10(0, 0); + UpdateEnabledGlowControl(0, 0); } return FALSE; @@ -945,7 +948,7 @@ MxU8 Infocenter::HandleButtonUp(MxS32 p_x, MxS32 p_y) // FUNCTION: BETA10 0x1002ffd4 MxU8 Infocenter::HandleControl(LegoControlManagerNotificationParam& p_param) { - if (p_param.m_unk0x28 == 1) { + if (p_param.m_enabledChild == 1) { m_infoManDialogueTimer = 0; InfomainScript::Script actionToPlay = InfomainScript::c_noneInfomain; @@ -1186,13 +1189,13 @@ MxLong Infocenter::HandleNotification0(MxNotificationParam& p_param) m_currentInfomainScript == InfomainScript::c_Pepper_All_Movie || m_currentInfomainScript == InfomainScript::c_Nick_All_Movie || m_currentInfomainScript == InfomainScript::c_Laura_All_Movie || - m_currentInfomainScript == InfomainScript::c_iic007ra_PlayWav || - m_currentInfomainScript == InfomainScript::c_ijs002ra_PlayWav || - m_currentInfomainScript == InfomainScript::c_irt001ra_PlayWav || - m_currentInfomainScript == InfomainScript::c_ipz006ra_PlayWav || - m_currentInfomainScript == InfomainScript::c_igs004ra_PlayWav || - m_currentInfomainScript == InfomainScript::c_iho003ra_PlayWav || - m_currentInfomainScript == InfomainScript::c_ips005ra_PlayWav) { + m_currentInfomainScript == InfomainScript::c_iic007ra_PlayWav - Lego()->IsVersion10() || + m_currentInfomainScript == InfomainScript::c_ijs002ra_PlayWav - Lego()->IsVersion10() || + m_currentInfomainScript == InfomainScript::c_irt001ra_PlayWav - Lego()->IsVersion10() || + m_currentInfomainScript == InfomainScript::c_ipz006ra_PlayWav - Lego()->IsVersion10() || + m_currentInfomainScript == InfomainScript::c_igs004ra_PlayWav - Lego()->IsVersion10() || + m_currentInfomainScript == InfomainScript::c_iho003ra_PlayWav - Lego()->IsVersion10() || + m_currentInfomainScript == InfomainScript::c_ips005ra_PlayWav - Lego()->IsVersion10()) { StopCurrentAction(); } } @@ -1236,21 +1239,21 @@ MxResult Infocenter::Tickle() m_bookAnimationTimer = 1; } - if (m_unk0x1d6 != 0) { - m_unk0x1d6 += 100; + if (m_bigInfoBlinkTimer != 0) { + m_bigInfoBlinkTimer += 100; - if (m_unk0x1d6 > 3400 && m_unk0x1d6 < 3650) { - ControlManager()->FUN_100293c0(InfomainScript::c_BigInfo_Ctl, m_atomId.GetInternal(), 1); + if (m_bigInfoBlinkTimer > 3400 && m_bigInfoBlinkTimer < 3650) { + ControlManager()->UpdateEnabledChild(InfomainScript::c_BigInfo_Ctl, m_atomId.GetInternal(), 1); } - else if (m_unk0x1d6 > 3650 && m_unk0x1d6 < 3900) { - ControlManager()->FUN_100293c0(InfomainScript::c_BigInfo_Ctl, m_atomId.GetInternal(), 0); + else if (m_bigInfoBlinkTimer > 3650 && m_bigInfoBlinkTimer < 3900) { + ControlManager()->UpdateEnabledChild(InfomainScript::c_BigInfo_Ctl, m_atomId.GetInternal(), 0); } - else if (m_unk0x1d6 > 3900 && m_unk0x1d6 < 4150) { - ControlManager()->FUN_100293c0(InfomainScript::c_BigInfo_Ctl, m_atomId.GetInternal(), 1); + else if (m_bigInfoBlinkTimer > 3900 && m_bigInfoBlinkTimer < 4150) { + ControlManager()->UpdateEnabledChild(InfomainScript::c_BigInfo_Ctl, m_atomId.GetInternal(), 1); } - else if (m_unk0x1d6 > 4400) { - ControlManager()->FUN_100293c0(InfomainScript::c_BigInfo_Ctl, m_atomId.GetInternal(), 0); - m_unk0x1d6 = 0; + else if (m_bigInfoBlinkTimer > 4400) { + ControlManager()->UpdateEnabledChild(InfomainScript::c_BigInfo_Ctl, m_atomId.GetInternal(), 0); + m_bigInfoBlinkTimer = 0; } } @@ -1288,7 +1291,7 @@ void Infocenter::StopCutscene() VideoManager()->EnableFullScreenMovie(FALSE); InputManager()->SetUnknown335(FALSE); SetAppCursor(e_cursorArrow); - FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + Disable(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); } // FUNCTION: LEGO1 0x10070d00 @@ -1299,7 +1302,7 @@ MxBool Infocenter::VTable0x5c() // FUNCTION: LEGO1 0x10070d10 // FUNCTION: BETA10 0x100307d4 -void Infocenter::FUN_10070d10(MxS32 p_x, MxS32 p_y) +void Infocenter::UpdateEnabledGlowControl(MxS32 p_x, MxS32 p_y) { MxS16 i; for (i = 0; i < (MxS32) (sizeof(m_glowInfo) / sizeof(m_glowInfo[0])); i++) { @@ -1317,12 +1320,12 @@ void Infocenter::FUN_10070d10(MxS32 p_x, MxS32 p_y) i = -1; } - if (i != m_unk0x1c8) { - if (m_unk0x1c8 != -1) { - m_glowInfo[m_unk0x1c8].m_destCtl->Enable(FALSE); + if (i != m_enabledGlowControl) { + if (m_enabledGlowControl != -1) { + m_glowInfo[m_enabledGlowControl].m_destCtl->Enable(FALSE); } - m_unk0x1c8 = i; + m_enabledGlowControl = i; if (i != -1) { m_glowInfo[i].m_destCtl->Enable(TRUE); } @@ -1454,7 +1457,7 @@ void Infocenter::StartCredits() MxDSAction* action = presenter->GetAction(); if (action) { - FUN_100b7220(action, MxDSAction::c_world, FALSE); + ApplyMask(action, MxDSAction::c_world, FALSE); presenter->EndAction(); } } @@ -1470,7 +1473,7 @@ void Infocenter::StartCredits() MxDSAction* action = presenter->GetAction(); if (action) { - FUN_100b7220(action, MxDSAction::c_world, FALSE); + ApplyMask(action, MxDSAction::c_world, FALSE); presenter->EndAction(); } } @@ -1506,6 +1509,17 @@ void Infocenter::StopCredits() // FUNCTION: BETA10 0x1002ee8c void Infocenter::PlayAction(InfomainScript::Script p_script) { + if (Lego()->IsVersion10()) { + if (p_script == InfomainScript::c_iicx18in_RunAnim) { + // Alternative dialogue after signing in (1.0 version) + p_script = InfomainScript::c_iic016in_RunAnim; + } + else if (p_script > InfomainScript::c_iicx18in_RunAnim) { + // Shift all other actions by 1 + p_script = (InfomainScript::Script)((int) p_script - 1); + } + } + MxDSAction action; action.SetObjectId(p_script); action.SetAtomId(*g_infomainScript); diff --git a/LEGO1/lego/legoomni/src/worlds/infocenterdoor.cpp b/LEGO1/lego/legoomni/src/worlds/infocenterdoor.cpp index c546744a..8dc21750 100644 --- a/LEGO1/lego/legoomni/src/worlds/infocenterdoor.cpp +++ b/LEGO1/lego/legoomni/src/worlds/infocenterdoor.cpp @@ -88,7 +88,7 @@ void InfocenterDoor::ReadyWorld() { LegoWorld::ReadyWorld(); PlayMusic(JukeboxScript::c_InformationCenter_Music); - FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + Disable(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); } // FUNCTION: LEGO1 0x10037a90 @@ -96,7 +96,7 @@ MxLong InfocenterDoor::HandleControl(LegoControlManagerNotificationParam& p_para { MxLong result = 0; - if (p_param.m_unk0x28 == 1) { + if (p_param.m_enabledChild == 1) { DeleteObjects(&m_atomId, InfodoorScript::c_iic037in_PlayWav, 510); switch (p_param.m_clickedObjectId) { diff --git a/LEGO1/lego/legoomni/src/worlds/isle.cpp b/LEGO1/lego/legoomni/src/worlds/isle.cpp index 4d2c5b29..718a8f2f 100644 --- a/LEGO1/lego/legoomni/src/worlds/isle.cpp +++ b/LEGO1/lego/legoomni/src/worlds/isle.cpp @@ -142,11 +142,11 @@ MxLong Isle::Notify(MxParam& p_param) break; case c_notificationButtonUp: case c_notificationButtonDown: - switch (m_act1state->m_unk0x018) { - case 3: + switch (m_act1state->m_state) { + case Act1State::e_pizza: result = m_pizza->Notify(p_param); break; - case 10: + case Act1State::e_ambulance: result = m_ambulance->Notify(p_param); break; } @@ -155,14 +155,14 @@ MxLong Isle::Notify(MxParam& p_param) result = HandleControl((LegoControlManagerNotificationParam&) p_param); break; case c_notificationEndAnim: - switch (m_act1state->m_unk0x018) { - case 4: + switch (m_act1state->m_state) { + case Act1State::e_helicopter: result = UserActor()->Notify(p_param); break; - case 8: + case Act1State::e_towtrack: result = m_towtrack->Notify(p_param); break; - case 10: + case Act1State::e_ambulance: result = m_ambulance->Notify(p_param); break; } @@ -187,18 +187,18 @@ MxLong Isle::HandleEndAction(MxEndActionNotificationParam& p_param) { MxLong result; - switch (m_act1state->m_unk0x018) { - case 2: + switch (m_act1state->m_state) { + case Act1State::e_elevator: HandleElevatorEndAction(); result = 1; break; - case 3: + case Act1State::e_pizza: result = m_pizza->Notify(p_param); break; - case 8: + case Act1State::e_towtrack: result = m_towtrack->Notify(p_param); break; - case 10: + case Act1State::e_ambulance: result = m_ambulance->Notify(p_param); break; default: @@ -241,12 +241,12 @@ void Isle::HandleElevatorEndAction() case Act1State::c_floor1: m_destLocation = LegoGameState::e_infomain; TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); - m_act1state->m_unk0x018 = 0; + m_act1state->m_state = Act1State::e_none; break; case Act1State::c_floor2: if (m_act1state->m_unk0x01e) { m_act1state->m_unk0x01e = FALSE; - m_act1state->m_unk0x018 = 0; + m_act1state->m_state = Act1State::e_none; InputManager()->EnableInputProcessing(); } else { @@ -258,7 +258,7 @@ void Isle::HandleElevatorEndAction() case Act1State::c_floor3: m_destLocation = LegoGameState::e_elevopen; TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); - m_act1state->m_unk0x018 = 0; + m_act1state->m_state = Act1State::e_none; break; } } @@ -270,26 +270,26 @@ void Isle::ReadyWorld() if (m_act1state->GetUnknown21()) { GameState()->SwitchArea(LegoGameState::e_infomain); - m_act1state->SetUnknown18(0); + m_act1state->SetState(Act1State::e_none); m_act1state->SetUnknown21(0); } else if (GameState()->GetLoadedAct() != LegoGameState::e_act1) { EnableAnimations(TRUE); FUN_10032620(); m_act1state->PlaceActors(); - FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + Disable(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); } } // FUNCTION: LEGO1 0x10031030 MxLong Isle::HandleControl(LegoControlManagerNotificationParam& p_param) { - if (p_param.m_unk0x28 == 1) { + if (p_param.m_enabledChild == 1) { MxDSAction action; switch (p_param.m_clickedObjectId) { case IsleScript::c_ElevRide_Info_Ctl: - m_act1state->m_unk0x018 = 2; + m_act1state->m_state = Act1State::e_elevator; switch (m_act1state->m_elevFloor) { case Act1State::c_floor1: @@ -309,7 +309,7 @@ MxLong Isle::HandleControl(LegoControlManagerNotificationParam& p_param) m_act1state->m_elevFloor = Act1State::c_floor1; break; case IsleScript::c_ElevRide_Two_Ctl: - m_act1state->m_unk0x018 = 2; + m_act1state->m_state = Act1State::e_elevator; switch (m_act1state->m_elevFloor) { case Act1State::c_floor1: @@ -329,7 +329,7 @@ MxLong Isle::HandleControl(LegoControlManagerNotificationParam& p_param) m_act1state->m_elevFloor = Act1State::c_floor2; break; case IsleScript::c_ElevRide_Three_Ctl: - m_act1state->m_unk0x018 = 2; + m_act1state->m_state = Act1State::e_elevator; switch (m_act1state->m_elevFloor) { case Act1State::c_floor1: @@ -478,14 +478,14 @@ MxLong Isle::HandlePathStruct(LegoPathStructNotificationParam& p_param) } } - switch (m_act1state->m_unk0x018) { - case 3: + switch (m_act1state->m_state) { + case Act1State::e_pizza: result = m_pizza->Notify(p_param); break; - case 8: + case Act1State::e_towtrack: result = m_towtrack->Notify(p_param); break; - case 10: + case Act1State::e_ambulance: result = m_ambulance->Notify(p_param); break; } @@ -502,7 +502,7 @@ MxLong Isle::HandlePathStruct(LegoPathStructNotificationParam& p_param) result = 1; break; case 0x131: - if (m_act1state->m_unk0x018 != 10) { + if (m_act1state->m_state != Act1State::e_ambulance) { AnimationManager()->FUN_10064740(NULL); } result = 1; @@ -558,7 +558,7 @@ void Isle::Enable(MxBool p_enable) EnableAnimations(TRUE); - if (m_act1state->m_unk0x018 == 0) { + if (m_act1state->m_state == Act1State::e_none) { MxS32 locations[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; for (MxU32 i = 0; i < 5; i++) { @@ -577,7 +577,7 @@ void Isle::Enable(MxBool p_enable) if (UserActor() != NULL && UserActor()->IsA("Jetski")) { IslePathActor* actor = (IslePathActor*) UserActor(); actor->SpawnPlayer( - LegoGameState::e_unk45, + LegoGameState::e_jetskiSpawn, FALSE, IslePathActor::c_spawnBit1 | IslePathActor::c_playMusic | IslePathActor::c_spawnBit3 ); @@ -595,7 +595,7 @@ void Isle::Enable(MxBool p_enable) break; case LegoGameState::e_jetrace2: if (((JetskiRaceState*) GameState()->GetState("JetskiRaceState"))->m_unk0x28 == 2) { - m_act1state->m_unk0x018 = 5; + m_act1state->m_state = Act1State::e_transitionToJetski; } PlaceActor(UserActor()); @@ -704,10 +704,10 @@ void Isle::Enable(MxBool p_enable) break; } - switch (m_act1state->m_unk0x018) { - case 0: - case 1: - m_act1state->m_unk0x018 = 0; + switch (m_act1state->m_state) { + case Act1State::e_none: + case Act1State::e_initial: + m_act1state->m_state = Act1State::e_none; if (GameState()->m_currentArea == LegoGameState::e_pizzeriaExterior) { AnimationManager()->FUN_10064740(NULL); @@ -728,7 +728,7 @@ void Isle::Enable(MxBool p_enable) } } break; - case 5: { + case Act1State::e_transitionToJetski: { ((IslePathActor*) UserActor()) ->SpawnPlayer( LegoGameState::e_jetrace2, @@ -756,12 +756,12 @@ void Isle::Enable(MxBool p_enable) ->FUN_10060dc0(script, NULL, TRUE, LegoAnimationManager::e_unk1, NULL, FALSE, FALSE, TRUE, FALSE); } - m_act1state->m_unk0x018 = 0; + m_act1state->m_state = Act1State::e_none; EnableAnimations(FALSE); AnimationManager()->FUN_10064670(NULL); break; } - case 6: { + case Act1State::e_transitionToRacecar: { GameState()->m_currentArea = LegoGameState::e_carraceExterior; ((IslePathActor*) UserActor()) ->SpawnPlayer( @@ -790,30 +790,30 @@ void Isle::Enable(MxBool p_enable) ->FUN_10060dc0(script, NULL, TRUE, LegoAnimationManager::e_unk1, NULL, FALSE, FALSE, TRUE, FALSE); } - m_act1state->m_unk0x018 = 0; + m_act1state->m_state = Act1State::e_none; EnableAnimations(TRUE); break; } - case 7: - m_act1state->m_unk0x018 = 8; + case Act1State::e_transitionToTowtrack: + m_act1state->m_state = Act1State::e_towtrack; AnimationManager()->FUN_1005f6d0(FALSE); AnimationManager()->EnableCamAnims(FALSE); g_isleFlags &= ~c_playMusic; - m_towtrack->FUN_1004dab0(); + m_towtrack->Init(); break; - case 9: - m_act1state->m_unk0x018 = 10; + case Act1State::e_transitionToAmbulance: + m_act1state->m_state = Act1State::e_ambulance; AnimationManager()->FUN_1005f6d0(FALSE); AnimationManager()->EnableCamAnims(FALSE); g_isleFlags &= ~c_playMusic; - m_ambulance->FUN_10036e60(); + m_ambulance->Init(); break; case 11: - m_act1state->m_unk0x018 = 0; + m_act1state->m_state = Act1State::e_none; ((IslePathActor*) UserActor()) ->SpawnPlayer( LegoGameState::e_jukeboxExterior, @@ -828,18 +828,18 @@ void Isle::Enable(MxBool p_enable) SetAppCursor(e_cursorArrow); - if (m_act1state->m_unk0x018 != 8 && - (m_act1state->m_unk0x018 != 0 || GameState()->m_currentArea != LegoGameState::e_elevride) && - (m_act1state->m_unk0x018 != 0 || GameState()->m_currentArea != LegoGameState::e_polidoor) && - (m_act1state->m_unk0x018 != 0 || GameState()->m_currentArea != LegoGameState::e_garadoor) && - (m_act1state->m_unk0x018 != 0 || GameState()->m_currentArea != LegoGameState::e_bike) && - (m_act1state->m_unk0x018 != 0 || GameState()->m_currentArea != LegoGameState::e_dunecar) && - (m_act1state->m_unk0x018 != 0 || GameState()->m_currentArea != LegoGameState::e_motocycle) && - (m_act1state->m_unk0x018 != 0 || GameState()->m_currentArea != LegoGameState::e_copter) && - (m_act1state->m_unk0x018 != 0 || GameState()->m_currentArea != LegoGameState::e_jetski) && - (m_act1state->m_unk0x018 != 0 || GameState()->m_currentArea != LegoGameState::e_skateboard) && - (m_act1state->m_unk0x018 != 0 || GameState()->m_currentArea != LegoGameState::e_jetrace2)) { - FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + if (m_act1state->m_state != Act1State::e_towtrack && + (m_act1state->m_state != Act1State::e_none || GameState()->m_currentArea != LegoGameState::e_elevride) && + (m_act1state->m_state != Act1State::e_none || GameState()->m_currentArea != LegoGameState::e_polidoor) && + (m_act1state->m_state != Act1State::e_none || GameState()->m_currentArea != LegoGameState::e_garadoor) && + (m_act1state->m_state != Act1State::e_none || GameState()->m_currentArea != LegoGameState::e_bike) && + (m_act1state->m_state != Act1State::e_none || GameState()->m_currentArea != LegoGameState::e_dunecar) && + (m_act1state->m_state != Act1State::e_none || GameState()->m_currentArea != LegoGameState::e_motocycle) && + (m_act1state->m_state != Act1State::e_none || GameState()->m_currentArea != LegoGameState::e_copter) && + (m_act1state->m_state != Act1State::e_none || GameState()->m_currentArea != LegoGameState::e_jetski) && + (m_act1state->m_state != Act1State::e_none || GameState()->m_currentArea != LegoGameState::e_skateboard) && + (m_act1state->m_state != Act1State::e_none || GameState()->m_currentArea != LegoGameState::e_jetrace2)) { + Disable(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); } SetROIVisible("stretch", FALSE); @@ -897,7 +897,7 @@ MxLong Isle::HandleTransitionEnd() DeleteObjects(&m_atomId, IsleScript::c_Avo900Ps_PlayWav, IsleScript::c_Avo907Ps_PlayWav); if (m_destLocation != LegoGameState::e_skateboard) { - m_act1state->m_unk0x018 = 0; + m_act1state->m_state = Act1State::e_none; } switch (m_destLocation) { @@ -961,7 +961,7 @@ MxLong Isle::HandleTransitionEnd() m_destLocation = LegoGameState::e_undefined; VariableTable()->SetVariable("VISIBILITY", "Show Gas"); AnimationManager()->Resume(); - FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + Disable(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); SetAppCursor(e_cursorArrow); SetIsWorldActive(TRUE); break; @@ -971,7 +971,7 @@ MxLong Isle::HandleTransitionEnd() m_destLocation = LegoGameState::e_undefined; VariableTable()->SetVariable("VISIBILITY", "Show Policsta"); AnimationManager()->Resume(); - FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + Disable(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); SetAppCursor(e_cursorArrow); SetIsWorldActive(TRUE); break; @@ -1023,7 +1023,7 @@ MxLong Isle::HandleTransitionEnd() break; case LegoGameState::e_ambulance: m_act1state->m_unk0x01f = TRUE; - m_act1state->m_unk0x018 = 10; + m_act1state->m_state = Act1State::e_ambulance; FUN_10032d30(IsleScript::c_AmbulanceFuelMeter, JukeboxScript::c_MusicTheme1, NULL, TRUE); if (!m_act1state->m_unk0x01f) { @@ -1032,7 +1032,7 @@ MxLong Isle::HandleTransitionEnd() break; case LegoGameState::e_towtrack: m_act1state->m_unk0x01f = TRUE; - m_act1state->m_unk0x018 = 8; + m_act1state->m_state = Act1State::e_towtrack; FUN_10032d30(IsleScript::c_TowFuelMeter, JukeboxScript::c_MusicTheme1, NULL, TRUE); if (!m_act1state->m_unk0x01f) { @@ -1082,7 +1082,7 @@ void Isle::FUN_10032d30( VariableTable()->SetVariable(g_varCAMERALOCATION, p_cameraLocation); } - FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + Disable(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); SetAppCursor(e_cursorArrow); m_destLocation = LegoGameState::e_undefined; m_act1state->m_unk0x01f = FALSE; @@ -1167,7 +1167,7 @@ void Isle::CreateState() m_act1state = (Act1State*) GameState()->GetState("Act1State"); if (!m_act1state) { m_act1state = (Act1State*) GameState()->CreateState("Act1State"); - m_act1state->m_unk0x018 = 0; + m_act1state->m_state = Act1State::e_none; } m_radio.CreateState(); @@ -1193,23 +1193,23 @@ MxBool Isle::Escape() m_radio.Stop(); BackgroundAudioManager()->Stop(); - switch (m_act1state->m_unk0x018) { - case 3: + switch (m_act1state->m_state) { + case Act1State::e_pizza: if (UserActor() != NULL) { m_pizza->StopActions(); m_pizza->FUN_100382b0(); } break; - case 8: + case Act1State::e_towtrack: if (UserActor() != NULL && !UserActor()->IsA("TowTrack")) { m_towtrack->StopActions(); - m_towtrack->FUN_1004dbe0(); + m_towtrack->Reset(); } break; - case 10: + case Act1State::e_ambulance: if (UserActor() != NULL && !UserActor()->IsA("Ambulance")) { m_ambulance->StopActions(); - m_ambulance->FUN_10037250(); + m_ambulance->Reset(); } break; } @@ -1239,7 +1239,7 @@ MxBool Isle::Escape() VariableTable()->SetVariable("VISIBILITY", "Show Gas"); } - m_act1state->m_unk0x018 = 0; + m_act1state->m_state = Act1State::e_none; m_destLocation = LegoGameState::e_infomain; return TRUE; } @@ -1247,21 +1247,21 @@ MxBool Isle::Escape() // FUNCTION: LEGO1 0x10033350 void Isle::FUN_10033350() { - if (m_act1state->m_unk0x018 == 10) { + if (m_act1state->m_state == Act1State::e_ambulance) { if (UserActor() != NULL && !UserActor()->IsA("Ambulance")) { m_ambulance->StopActions(); - m_ambulance->FUN_10037250(); + m_ambulance->Reset(); } } - if (m_act1state->m_unk0x018 == 8) { + if (m_act1state->m_state == Act1State::e_towtrack) { if (UserActor() != NULL && !UserActor()->IsA("TowTrack")) { m_towtrack->StopActions(); - m_towtrack->FUN_1004dbe0(); + m_towtrack->Reset(); } } - if (m_act1state->m_unk0x018 == 3) { + if (m_act1state->m_state == Act1State::e_pizza) { if (UserActor() != NULL) { m_pizza->StopActions(); m_pizza->FUN_100382b0(); @@ -1293,7 +1293,7 @@ void Isle::FUN_10033350() Act1State::Act1State() { m_elevFloor = Act1State::c_floor1; - m_unk0x018 = 1; + m_state = Act1State::e_initial; m_unk0x01e = FALSE; m_cptClickDialogue = Playlist((MxU32*) g_cptClickDialogue, sizeOfArray(g_cptClickDialogue), Playlist::e_loop); m_unk0x01f = FALSE; @@ -1633,7 +1633,7 @@ void Act1State::PlaceActors() if (m_helicopter != NULL) { if (!m_helicopterPlane.IsPresent()) { - m_helicopter->SpawnPlayer(LegoGameState::e_unk40, FALSE, 0); + m_helicopter->SpawnPlayer(LegoGameState::e_helicopterSpawn, FALSE, 0); } else { isle->PlaceActor(m_helicopter, m_helicopterPlane.GetName(), 0, 0.5f, 1, 0.5f); @@ -1653,19 +1653,19 @@ void Act1State::PlaceActors() m_helicopter = NULL; if (m_helicopterWindshield != NULL) { - FUN_1003f930(m_helicopterWindshield); + LoadFromNamedTexture(m_helicopterWindshield); delete m_helicopterWindshield; m_helicopterWindshield = NULL; } if (m_helicopterJetLeft != NULL) { - FUN_1003f930(m_helicopterJetLeft); + LoadFromNamedTexture(m_helicopterJetLeft); delete m_helicopterJetLeft; m_helicopterJetLeft = NULL; } if (m_helicopterJetRight != NULL) { - FUN_1003f930(m_helicopterJetRight); + LoadFromNamedTexture(m_helicopterJetRight); delete m_helicopterJetRight; m_helicopterJetRight = NULL; } @@ -1673,7 +1673,7 @@ void Act1State::PlaceActors() if (m_jetski != NULL) { if (!m_jetskiPlane.IsPresent()) { - m_jetski->SpawnPlayer(LegoGameState::e_unk45, FALSE, 0); + m_jetski->SpawnPlayer(LegoGameState::e_jetskiSpawn, FALSE, 0); } else { isle->PlaceActor(m_jetski, m_jetskiPlane.GetName(), 0, 0.5f, 1, 0.5f); @@ -1689,13 +1689,13 @@ void Act1State::PlaceActors() m_jetski = NULL; if (m_jetskiFront != NULL) { - FUN_1003f930(m_jetskiFront); + LoadFromNamedTexture(m_jetskiFront); delete m_jetskiFront; m_jetskiFront = NULL; } if (m_jetskiWindshield != NULL) { - FUN_1003f930(m_jetskiWindshield); + LoadFromNamedTexture(m_jetskiWindshield); delete m_jetskiWindshield; m_jetskiWindshield = NULL; } @@ -1703,7 +1703,7 @@ void Act1State::PlaceActors() if (m_dunebuggy != NULL) { if (!m_dunebuggyPlane.IsPresent()) { - m_dunebuggy->SpawnPlayer(LegoGameState::e_unk43, FALSE, 0); + m_dunebuggy->SpawnPlayer(LegoGameState::e_dunebuggySpawn, FALSE, 0); } else { isle->PlaceActor(m_dunebuggy, m_dunebuggyPlane.GetName(), 0, 0.5f, 1, 0.5f); @@ -1723,7 +1723,7 @@ void Act1State::PlaceActors() m_dunebuggy = NULL; if (m_dunebuggyFront != NULL) { - FUN_1003f930(m_dunebuggyFront); + LoadFromNamedTexture(m_dunebuggyFront); delete m_dunebuggyFront; m_dunebuggyFront = NULL; } @@ -1731,7 +1731,7 @@ void Act1State::PlaceActors() if (m_racecar != NULL) { if (!m_racecarPlane.IsPresent()) { - m_racecar->SpawnPlayer(LegoGameState::e_unk44, FALSE, 0); + m_racecar->SpawnPlayer(LegoGameState::e_racecarSpawn, FALSE, 0); } else { isle->PlaceActor(m_racecar, m_racecarPlane.GetName(), 0, 0.5f, 1, 0.5f); @@ -1751,19 +1751,19 @@ void Act1State::PlaceActors() m_racecar = NULL; if (m_racecarFront != NULL) { - FUN_1003f930(m_racecarFront); + LoadFromNamedTexture(m_racecarFront); delete m_racecarFront; m_racecarFront = NULL; } if (m_racecarBack != NULL) { - FUN_1003f930(m_racecarBack); + LoadFromNamedTexture(m_racecarBack); delete m_racecarBack; m_racecarBack = NULL; } if (m_racecarTail != NULL) { - FUN_1003f930(m_racecarTail); + LoadFromNamedTexture(m_racecarTail); delete m_racecarTail; m_racecarTail = NULL; } diff --git a/LEGO1/lego/legoomni/src/worlds/jukebox.cpp b/LEGO1/lego/legoomni/src/worlds/jukebox.cpp index a92f493d..aa8858cf 100644 --- a/LEGO1/lego/legoomni/src/worlds/jukebox.cpp +++ b/LEGO1/lego/legoomni/src/worlds/jukebox.cpp @@ -123,7 +123,7 @@ MxBool JukeBox::HandleControl(LegoControlManagerNotificationParam& p_param) { MxStillPresenter* presenter; - if (p_param.m_unk0x28 == 1) { + if (p_param.m_enabledChild == 1) { switch (p_param.m_clickedObjectId) { case JukeboxwScript::c_Dback_Ctl: switch (m_state->m_music) { @@ -211,7 +211,7 @@ MxBool JukeBox::HandleControl(LegoControlManagerNotificationParam& p_param) break; case JukeboxwScript::c_Note_Ctl: Act1State* act1State = (Act1State*) GameState()->GetState("Act1State"); - act1State->m_unk0x018 = 11; + act1State->m_state = Act1State::e_jukebox; m_destLocation = LegoGameState::Area::e_jukeboxExterior; TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, 0, FALSE); break; @@ -247,7 +247,7 @@ MxResult JukeBox::Tickle() if (m_unk0x100 == 1) { m_unk0x100 = 0; - FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + Disable(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); } return SUCCESS; diff --git a/LEGO1/lego/legoomni/src/worlds/legoact2.cpp b/LEGO1/lego/legoomni/src/worlds/legoact2.cpp index 094bdac9..c04bbdbc 100644 --- a/LEGO1/lego/legoomni/src/worlds/legoact2.cpp +++ b/LEGO1/lego/legoomni/src/worlds/legoact2.cpp @@ -7,10 +7,10 @@ #include "islepathactor.h" #include "jukebox_actions.h" #include "legoanimationmanager.h" +#include "legoanimpresenter.h" #include "legocachesoundmanager.h" #include "legogamestate.h" #include "legoinputmanager.h" -#include "legolocomotionanimpresenter.h" #include "legomain.h" #include "legopathstruct.h" #include "legosoundmanager.h" @@ -192,7 +192,7 @@ MxResult LegoAct2::Tickle() case 2: if (g_unk0x100f4474) { if (AnimationManager()->FUN_10064ee0(g_unk0x100f4474)) { - FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + Disable(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); g_unk0x100f4474 = (Act2mainScript::Script) 0; } } @@ -200,7 +200,7 @@ MxResult LegoAct2::Tickle() m_unk0x10d0 += 50; break; case 3: - FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + Disable(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); m_unk0x10d0 = 0; m_unk0x10c4 = 4; FUN_10052560(Act2mainScript::c_tja009ni_RunAnim, TRUE, TRUE, NULL, NULL, NULL); @@ -540,7 +540,7 @@ void LegoAct2::Enable(MxBool p_enable) GameState()->StopArea(LegoGameState::e_infomain); } - FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + Disable(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); if (m_unk0x10c4 != 6 && m_unk0x10c4 != 12) { PlayMusic(m_music); @@ -939,6 +939,7 @@ MxResult LegoAct2::BadEnding() MxTrace("Bad End of Act2\n"); m_unk0x10c4 = 14; + EmitGameEvent(e_badEnding); return SUCCESS; } @@ -1116,7 +1117,7 @@ MxResult LegoAct2::FUN_10052560( action.SetDirection(*p_direction); } - StartActionIfUnknown0x13c(action); + StartActionIfInitialized(action); } else { MxMatrix matrix; diff --git a/LEGO1/lego/legoomni/src/worlds/police.cpp b/LEGO1/lego/legoomni/src/worlds/police.cpp index 64992771..e609b319 100644 --- a/LEGO1/lego/legoomni/src/worlds/police.cpp +++ b/LEGO1/lego/legoomni/src/worlds/police.cpp @@ -95,13 +95,13 @@ void Police::ReadyWorld() { LegoWorld::ReadyWorld(); PlayMusic(JukeboxScript::c_PoliceStation_Music); - FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + Disable(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); } // FUNCTION: LEGO1 0x1005e550 MxLong Police::HandleControl(LegoControlManagerNotificationParam& p_param) { - if (p_param.m_unk0x28 == 1) { + if (p_param.m_enabledChild == 1) { switch (p_param.m_clickedObjectId) { case PoliceScript::c_LeftArrow_Ctl: case PoliceScript::c_RightArrow_Ctl: diff --git a/LEGO1/lego/legoomni/src/worlds/registrationbook.cpp b/LEGO1/lego/legoomni/src/worlds/registrationbook.cpp index adaf45d4..ddd3b7cf 100644 --- a/LEGO1/lego/legoomni/src/worlds/registrationbook.cpp +++ b/LEGO1/lego/legoomni/src/worlds/registrationbook.cpp @@ -241,7 +241,7 @@ MxLong RegistrationBook::HandleKeyPress(SDL_Keycode p_key) // FUNCTION: LEGO1 0x100774a0 MxLong RegistrationBook::HandleControl(LegoControlManagerNotificationParam& p_param) { - MxS16 buttonId = p_param.m_unk0x28; + MxS16 buttonId = p_param.m_enabledChild; const InternationalCharacter* intChar = NULL; for (int i = 0; i < sizeOfArray(m_intAlphabet); i++) { @@ -671,14 +671,14 @@ MxLong RegistrationBook::HandlePathStruct(LegoPathStructNotificationParam& p_par MxBool RegistrationBook::CreateSurface() { MxCompositePresenterList* presenters = m_checkmark[0]->GetList(); - MxStillPresenter *presenter, *uninitialized; + MxStillPresenter* presenter; if (presenters) { if (presenters->begin() != presenters->end()) { presenter = (MxStillPresenter*) presenters->front(); } else { - presenter = uninitialized; // intentionally uninitialized variable + presenter = NULL; } if (presenter) { diff --git a/LEGO1/lego/legoomni/src/worlds/score.cpp b/LEGO1/lego/legoomni/src/worlds/score.cpp index 69b4305a..067f43e4 100644 --- a/LEGO1/lego/legoomni/src/worlds/score.cpp +++ b/LEGO1/lego/legoomni/src/worlds/score.cpp @@ -159,13 +159,13 @@ void Score::ReadyWorld() PlayMusic(JukeboxScript::c_InformationCenter_Music); } - FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + Disable(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); } // FUNCTION: LEGO1 0x100016d0 MxLong Score::FUN_100016d0(LegoControlManagerNotificationParam& p_param) { - MxS16 unk0x28 = p_param.m_unk0x28; + MxS16 unk0x28 = p_param.m_enabledChild; if (unk0x28 == 1 || p_param.m_clickedObjectId == InfoscorScript::c_LegoBox_Ctl) { switch (p_param.m_clickedObjectId) { diff --git a/LEGO1/lego/sources/anim/legoanim.cpp b/LEGO1/lego/sources/anim/legoanim.cpp index 8ec3ee2d..e0fb90b6 100644 --- a/LEGO1/lego/sources/anim/legoanim.cpp +++ b/LEGO1/lego/sources/anim/legoanim.cpp @@ -10,20 +10,20 @@ DECOMP_SIZE_ASSERT(LegoTranslationKey, 0x14) DECOMP_SIZE_ASSERT(LegoRotationKey, 0x18) DECOMP_SIZE_ASSERT(LegoScaleKey, 0x14) DECOMP_SIZE_ASSERT(LegoMorphKey, 0x0c) -DECOMP_SIZE_ASSERT(LegoUnknownKey, 0x0c) +DECOMP_SIZE_ASSERT(LegoRotationZKey, 0x0c) DECOMP_SIZE_ASSERT(LegoAnimNodeData, 0x34) DECOMP_SIZE_ASSERT(LegoAnimActorEntry, 0x08) DECOMP_SIZE_ASSERT(LegoAnimScene, 0x24) DECOMP_SIZE_ASSERT(LegoAnim, 0x18) // FUNCTION: LEGO1 0x1009f000 -LegoUnknownKey::LegoUnknownKey() +LegoRotationZKey::LegoRotationZKey() { m_z = 0.0f; } // FUNCTION: LEGO1 0x1009f020 -LegoResult LegoUnknownKey::Read(LegoStorage* p_storage) +LegoResult LegoRotationZKey::Read(LegoStorage* p_storage) { LegoResult result; @@ -40,7 +40,7 @@ LegoResult LegoUnknownKey::Read(LegoStorage* p_storage) // FUNCTION: LEGO1 0x1009f060 // FUNCTION: BETA10 0x1018133f -LegoResult LegoUnknownKey::Write(LegoStorage* p_storage) +LegoResult LegoRotationZKey::Write(LegoStorage* p_storage) { LegoResult result; @@ -58,33 +58,33 @@ LegoResult LegoUnknownKey::Write(LegoStorage* p_storage) // FUNCTION: LEGO1 0x1009f0a0 LegoAnimScene::LegoAnimScene() { - m_unk0x00 = 0; - m_unk0x04 = NULL; - m_unk0x08 = 0; - m_unk0x0c = NULL; - m_unk0x10 = 0; - m_unk0x14 = NULL; - m_unk0x18 = 0; - m_unk0x1c = 0; - m_unk0x20 = 0; + m_translationKeysCount = 0; + m_translationKeys = NULL; + m_targetKeysCount = 0; + m_targetKeys = NULL; + m_rotationKeysCount = 0; + m_rotationKeys = NULL; + m_targetIndex = 0; + m_translationIndex = 0; + m_rotationIndex = 0; } // FUNCTION: LEGO1 0x1009f0d0 LegoAnimScene::~LegoAnimScene() { - if (m_unk0x04 != NULL) { - delete[] m_unk0x04; - m_unk0x04 = NULL; + if (m_translationKeys != NULL) { + delete[] m_translationKeys; + m_translationKeys = NULL; } - if (m_unk0x0c != NULL) { - delete[] m_unk0x0c; - m_unk0x0c = NULL; + if (m_targetKeys != NULL) { + delete[] m_targetKeys; + m_targetKeys = NULL; } - if (m_unk0x14 != NULL) { - delete[] m_unk0x14; - m_unk0x14 = NULL; + if (m_rotationKeys != NULL) { + delete[] m_rotationKeys; + m_rotationKeys = NULL; } } @@ -95,34 +95,34 @@ LegoResult LegoAnimScene::Write(LegoStorage* p_storage) LegoResult result; LegoS32 i; - if ((result = p_storage->Write(&m_unk0x00, sizeof(LegoU16))) != SUCCESS) { + if ((result = p_storage->Write(&m_translationKeysCount, sizeof(LegoU16))) != SUCCESS) { return result; } - if (m_unk0x00 != 0) { - for (i = 0; i < m_unk0x00; i++) { - if ((result = m_unk0x04[i].Write(p_storage)) != SUCCESS) { + if (m_translationKeysCount != 0) { + for (i = 0; i < m_translationKeysCount; i++) { + if ((result = m_translationKeys[i].Write(p_storage)) != SUCCESS) { return result; } } } - if ((result = p_storage->Write(&m_unk0x08, sizeof(LegoU16))) != SUCCESS) { + if ((result = p_storage->Write(&m_targetKeysCount, sizeof(LegoU16))) != SUCCESS) { return result; } - if (m_unk0x08 != 0) { - for (i = 0; i < m_unk0x08; i++) { - if ((result = m_unk0x0c[i].Write(p_storage)) != SUCCESS) { + if (m_targetKeysCount != 0) { + for (i = 0; i < m_targetKeysCount; i++) { + if ((result = m_targetKeys[i].Write(p_storage)) != SUCCESS) { return result; } } } - if ((result = p_storage->Write(&m_unk0x10, sizeof(LegoU16))) != SUCCESS) { + if ((result = p_storage->Write(&m_rotationKeysCount, sizeof(LegoU16))) != SUCCESS) { return result; } - if (m_unk0x10 != 0) { - for (i = 0; i < m_unk0x10; i++) { - if ((result = m_unk0x14[i].Write(p_storage)) != SUCCESS) { + if (m_rotationKeysCount != 0) { + for (i = 0; i < m_rotationKeysCount; i++) { + if ((result = m_rotationKeys[i].Write(p_storage)) != SUCCESS) { return result; } } @@ -137,37 +137,37 @@ LegoResult LegoAnimScene::Read(LegoStorage* p_storage) LegoResult result; LegoS32 i; - if ((result = p_storage->Read(&m_unk0x00, sizeof(LegoU16))) != SUCCESS) { + if ((result = p_storage->Read(&m_translationKeysCount, sizeof(LegoU16))) != SUCCESS) { return result; } - if (m_unk0x00 != 0) { - m_unk0x04 = new LegoTranslationKey[m_unk0x00]; - for (i = 0; i < m_unk0x00; i++) { - if ((result = m_unk0x04[i].Read(p_storage)) != SUCCESS) { + if (m_translationKeysCount != 0) { + m_translationKeys = new LegoTranslationKey[m_translationKeysCount]; + for (i = 0; i < m_translationKeysCount; i++) { + if ((result = m_translationKeys[i].Read(p_storage)) != SUCCESS) { goto done; } } } - if ((result = p_storage->Read(&m_unk0x08, sizeof(LegoU16))) != SUCCESS) { + if ((result = p_storage->Read(&m_targetKeysCount, sizeof(LegoU16))) != SUCCESS) { return result; } - if (m_unk0x08 != 0) { - m_unk0x0c = new LegoTranslationKey[m_unk0x08]; - for (i = 0; i < m_unk0x08; i++) { - if ((result = m_unk0x0c[i].Read(p_storage)) != SUCCESS) { + if (m_targetKeysCount != 0) { + m_targetKeys = new LegoTranslationKey[m_targetKeysCount]; + for (i = 0; i < m_targetKeysCount; i++) { + if ((result = m_targetKeys[i].Read(p_storage)) != SUCCESS) { goto done; } } } - if ((result = p_storage->Read(&m_unk0x10, sizeof(LegoU16))) != SUCCESS) { + if ((result = p_storage->Read(&m_rotationKeysCount, sizeof(LegoU16))) != SUCCESS) { return result; } - if (m_unk0x10 != 0) { - m_unk0x14 = new LegoUnknownKey[m_unk0x10]; - for (i = 0; i < m_unk0x10; i++) { - if ((result = m_unk0x14[i].Read(p_storage)) != SUCCESS) { + if (m_rotationKeysCount != 0) { + m_rotationKeys = new LegoRotationZKey[m_rotationKeysCount]; + for (i = 0; i < m_rotationKeysCount; i++) { + if ((result = m_rotationKeys[i].Read(p_storage)) != SUCCESS) { goto done; } } @@ -176,22 +176,22 @@ LegoResult LegoAnimScene::Read(LegoStorage* p_storage) return SUCCESS; done: - if (m_unk0x04 != NULL) { - delete[] m_unk0x04; - m_unk0x00 = 0; - m_unk0x04 = NULL; + if (m_translationKeys != NULL) { + delete[] m_translationKeys; + m_translationKeysCount = 0; + m_translationKeys = NULL; } - if (m_unk0x0c != NULL) { - delete[] m_unk0x0c; - m_unk0x08 = 0; - m_unk0x0c = NULL; + if (m_targetKeys != NULL) { + delete[] m_targetKeys; + m_targetKeysCount = 0; + m_targetKeys = NULL; } - if (m_unk0x14 != NULL) { - delete[] m_unk0x14; - m_unk0x10 = 0; - m_unk0x14 = NULL; + if (m_rotationKeys != NULL) { + delete[] m_rotationKeys; + m_rotationKeysCount = 0; + m_rotationKeys = NULL; } return result; @@ -199,82 +199,95 @@ LegoResult LegoAnimScene::Read(LegoStorage* p_storage) // FUNCTION: LEGO1 0x1009f490 // FUNCTION: BETA10 0x10181a83 -LegoResult LegoAnimScene::FUN_1009f490(LegoFloat p_time, Matrix4& p_matrix) +LegoResult LegoAnimScene::CalculateCameraTransform(LegoFloat p_time, Matrix4& p_matrix) { - MxMatrix localb0; - MxMatrix local4c; + MxMatrix tempMatrix; + MxMatrix original; - Vector3 local5c(localb0[0]); - Vector3 local68(localb0[1]); - Vector3 local54(localb0[2]); - Vector3 localb8(localb0[3]); + Vector3 column0(tempMatrix[0]); + Vector3 column1(tempMatrix[1]); + Vector3 column2(tempMatrix[2]); + Vector3 column3(tempMatrix[3]); - Mx3DPointFloat localcc; + Mx3DPointFloat tempTranslation; - localb0.SetIdentity(); + tempMatrix.SetIdentity(); - LegoU32 local60; - if (m_unk0x08 != 0) { - local60 = GetUnknown0x18(); - LegoAnimNodeData::GetTranslation(m_unk0x08, m_unk0x0c, p_time, localb0, local60); - SetUnknown0x18(local60); - localcc = localb8; - localb8.Clear(); + LegoU32 translationIndex; + if (m_targetKeysCount != 0) { + translationIndex = GetTargetIndex(); + LegoAnimNodeData::GetTranslation(m_targetKeysCount, m_targetKeys, p_time, tempMatrix, translationIndex); + SetTargetIndex(translationIndex); + tempTranslation = column3; + column3.Clear(); } - if (m_unk0x00 != 0) { - local60 = GetUnknown0x1c(); - LegoAnimNodeData::GetTranslation(m_unk0x00, m_unk0x04, p_time, localb0, local60); - SetUnknown0x1c(local60); + if (m_translationKeysCount != 0) { + translationIndex = GetTranslationIndex(); + LegoAnimNodeData::GetTranslation( + m_translationKeysCount, + m_translationKeys, + p_time, + tempMatrix, + translationIndex + ); + SetTranslationIndex(translationIndex); } - local54 = localcc; - local54 -= localb8; + column2 = tempTranslation; + column2 -= column3; - if (local54.Unitize() == 0) { - local5c.EqualsCross(local68, local54); + if (column2.Unitize() == 0) { + column0.EqualsCross(column1, column2); - if (local5c.Unitize() == 0) { - local68.EqualsCross(local54, local5c); + if (column0.Unitize() == 0) { + column1.EqualsCross(column2, column0); - localcc = p_matrix[3]; - localcc += localb0[3]; + tempTranslation = p_matrix[3]; + tempTranslation += tempMatrix[3]; - p_matrix[3][0] = p_matrix[3][1] = p_matrix[3][2] = localb0[3][0] = localb0[3][1] = localb0[3][2] = 0; + p_matrix[3][0] = p_matrix[3][1] = p_matrix[3][2] = tempMatrix[3][0] = tempMatrix[3][1] = tempMatrix[3][2] = + 0; - if (m_unk0x10 != 0) { - LegoU32 locald0 = -1; - LegoU32 locald8; - locald0 = GetUnknown0x20(); + if (m_rotationKeysCount != 0) { + LegoU32 old_index = -1; + LegoU32 i; + old_index = GetRotationIndex(); - LegoU32 localdc = - LegoAnimNodeData::FindKeys(p_time, m_unk0x10, m_unk0x14, sizeof(*m_unk0x14), locald8, locald0); + LegoU32 count = LegoAnimNodeData::FindKeys( + p_time, + m_rotationKeysCount, + m_rotationKeys, + sizeof(*m_rotationKeys), + i, + old_index + ); - SetUnknown0x20(locald0); + SetRotationIndex(old_index); - switch (localdc) { + switch (count) { case 1: - p_matrix.RotateZ(m_unk0x14[locald8].GetZ()); + p_matrix.RotateZ(m_rotationKeys[i].GetZ()); break; case 2: // Seems to be unused LegoFloat z = LegoAnimNodeData::Interpolate( p_time, - m_unk0x14[locald8], - m_unk0x14[locald8].GetZ(), - m_unk0x14[locald8 + 1], - m_unk0x14[locald8 + 1].GetZ() + m_rotationKeys[i], + m_rotationKeys[i].GetZ(), + m_rotationKeys[i + 1], + m_rotationKeys[i + 1].GetZ() ); - p_matrix.RotateZ(m_unk0x14[locald8].GetZ()); + p_matrix.RotateZ(m_rotationKeys[i].GetZ()); break; } } - local4c = p_matrix; - p_matrix.Product(local4c.GetData(), localb0.GetData()); - p_matrix[3][0] = localcc[0]; - p_matrix[3][1] = localcc[1]; - p_matrix[3][2] = localcc[2]; + original = p_matrix; + p_matrix.Product(original.GetData(), tempMatrix.GetData()); + p_matrix[3][0] = tempTranslation[0]; + p_matrix[3][1] = tempTranslation[1]; + p_matrix[3][2] = tempTranslation[2]; } } @@ -524,7 +537,7 @@ LegoAnimNodeData::LegoAnimNodeData() m_translationKeys = NULL; m_roiIndex = 0; m_rotationKeys = NULL; - m_unk0x22 = 0; + m_boundaryIndex = 0; m_scaleKeys = NULL; m_morphKeys = NULL; m_translationIndex = 0; diff --git a/LEGO1/lego/sources/anim/legoanim.h b/LEGO1/lego/sources/anim/legoanim.h index 372128b5..1c297c4d 100644 --- a/LEGO1/lego/sources/anim/legoanim.h +++ b/LEGO1/lego/sources/anim/legoanim.h @@ -137,9 +137,9 @@ class LegoMorphKey : public LegoAnimKey { }; // SIZE 0x0c -class LegoUnknownKey : public LegoAnimKey { +class LegoRotationZKey : public LegoAnimKey { public: - LegoUnknownKey(); + LegoRotationZKey(); LegoResult Read(LegoStorage* p_storage); LegoResult Write(LegoStorage* p_storage); @@ -190,7 +190,7 @@ class LegoAnimNodeData : public LegoTreeNodeData { LegoU16 GetROIIndex() { return m_roiIndex; } // FUNCTION: BETA10 0x1005d5c0 - LegoU16 GetUnknown0x22() { return m_unk0x22; } + LegoU16 GetBoundaryIndex() { return m_boundaryIndex; } // FUNCTION: BETA10 0x10073b80 LegoRotationKey* GetRotationKey(MxS32 index) { return &m_rotationKeys[index]; } @@ -217,7 +217,7 @@ class LegoAnimNodeData : public LegoTreeNodeData { void SetROIIndex(LegoU16 p_roiIndex) { m_roiIndex = p_roiIndex; } // FUNCTION: BETA10 0x1005f2e0 - void SetUnknown0x22(LegoU16 p_unk0x22) { m_unk0x22 = p_unk0x22; } + void SetBoundaryIndex(LegoU16 p_boundaryIndex) { m_boundaryIndex = p_boundaryIndex; } LegoResult CreateLocalTransform(LegoTime p_time, Matrix4& p_matrix) { @@ -280,7 +280,7 @@ class LegoAnimNodeData : public LegoTreeNodeData { LegoScaleKey* m_scaleKeys; // 0x18 LegoMorphKey* m_morphKeys; // 0x1c LegoU16 m_roiIndex; // 0x20 - LegoU16 m_unk0x22; // 0x22 + LegoU16 m_boundaryIndex; // 0x22 LegoU32 m_translationIndex; // 0x24 LegoU32 m_rotationIndex; // 0x28 LegoU32 m_scaleIndex; // 0x2c @@ -309,26 +309,26 @@ class LegoAnimScene { ~LegoAnimScene(); LegoResult Read(LegoStorage* p_storage); LegoResult Write(LegoStorage* p_storage); - LegoResult FUN_1009f490(LegoFloat p_time, Matrix4& p_matrix); + LegoResult CalculateCameraTransform(LegoFloat p_time, Matrix4& p_matrix); - LegoU32 GetUnknown0x18() { return m_unk0x18; } - LegoU32 GetUnknown0x1c() { return m_unk0x1c; } - LegoU32 GetUnknown0x20() { return m_unk0x20; } + LegoU32 GetTargetIndex() { return m_targetIndex; } + LegoU32 GetTranslationIndex() { return m_translationIndex; } + LegoU32 GetRotationIndex() { return m_rotationIndex; } - void SetUnknown0x18(LegoU32 p_unk0x18) { m_unk0x18 = p_unk0x18; } - void SetUnknown0x1c(LegoU32 p_unk0x1c) { m_unk0x1c = p_unk0x1c; } - void SetUnknown0x20(LegoU32 p_unk0x20) { m_unk0x20 = p_unk0x20; } + void SetTargetIndex(LegoU32 p_targetIndex) { m_targetIndex = p_targetIndex; } + void SetTranslationIndex(LegoU32 p_translationIndex) { m_translationIndex = p_translationIndex; } + void SetRotationIndex(LegoU32 p_rotationIndex) { m_rotationIndex = p_rotationIndex; } private: - LegoU16 m_unk0x00; // 0x00 - LegoTranslationKey* m_unk0x04; // 0x04 - LegoU16 m_unk0x08; // 0x08 - LegoTranslationKey* m_unk0x0c; // 0x0c - LegoU16 m_unk0x10; // 0x10 - LegoUnknownKey* m_unk0x14; // 0x14 - LegoU32 m_unk0x18; // 0x18 - LegoU32 m_unk0x1c; // 0x1c - LegoU32 m_unk0x20; // 0x20 + LegoU16 m_translationKeysCount; // 0x00 + LegoTranslationKey* m_translationKeys; // 0x04 + LegoU16 m_targetKeysCount; // 0x08 + LegoTranslationKey* m_targetKeys; // 0x0c + LegoU16 m_rotationKeysCount; // 0x10 + LegoRotationZKey* m_rotationKeys; // 0x14 + LegoU32 m_targetIndex; // 0x18 + LegoU32 m_translationIndex; // 0x1c + LegoU32 m_rotationIndex; // 0x20 }; // VTABLE: LEGO1 0x100db8d8 diff --git a/LEGO1/lego/sources/misc/legocontainer.cpp b/LEGO1/lego/sources/misc/legocontainer.cpp index 98836d6a..693f9b27 100644 --- a/LEGO1/lego/sources/misc/legocontainer.cpp +++ b/LEGO1/lego/sources/misc/legocontainer.cpp @@ -22,10 +22,9 @@ LegoTextureInfo* LegoTextureContainer::GetCached(LegoTextureInfo* p_textureInfo) memset(&desc, 0, sizeof(desc)); desc.dwSize = sizeof(desc); - if (p_textureInfo->m_surface->Lock(NULL, &desc, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WRITEONLY, NULL) == DD_OK) { + if (p_textureInfo->m_surface->GetSurfaceDesc(&desc) == DD_OK) { width = desc.dwWidth; height = desc.dwHeight; - p_textureInfo->m_surface->Unlock(desc.lpSurface); } for (LegoCachedTextureList::iterator it = m_cached.begin(); it != m_cached.end(); it++) { @@ -35,15 +34,8 @@ LegoTextureInfo* LegoTextureContainer::GetCached(LegoTextureInfo* p_textureInfo) memset(&newDesc, 0, sizeof(newDesc)); newDesc.dwSize = sizeof(newDesc); - if (surface->Lock(NULL, &newDesc, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WRITEONLY, NULL) == DD_OK) { - BOOL und = FALSE; + if (surface->GetSurfaceDesc(&newDesc) == DD_OK) { if (newDesc.dwWidth == width && newDesc.dwHeight == height) { - und = TRUE; - } - - surface->Unlock(newDesc.lpSurface); - - if (und) { (*it).second = TRUE; (*it).first->m_texture->AddRef(); return (*it).first; diff --git a/LEGO1/lego/sources/misc/legoimage.h b/LEGO1/lego/sources/misc/legoimage.h index ee1dc55d..d0269b82 100644 --- a/LEGO1/lego/sources/misc/legoimage.h +++ b/LEGO1/lego/sources/misc/legoimage.h @@ -46,7 +46,7 @@ class LegoImage { { m_palette->colors[p_i] = p_paletteEntry.GetColor(); } - const LegoU8* GetBits() const { return (LegoU8*) m_surface->pixels; } + LegoU8* GetBits() const { return (LegoU8*) m_surface->pixels; } LegoResult Read(LegoStorage* p_storage, LegoU32 p_square); LegoResult Write(LegoStorage* p_storage); diff --git a/LEGO1/lego/sources/misc/legoutil.h b/LEGO1/lego/sources/misc/legoutil.h index 871a9b72..78f52d0f 100644 --- a/LEGO1/lego/sources/misc/legoutil.h +++ b/LEGO1/lego/sources/misc/legoutil.h @@ -59,4 +59,12 @@ inline T RToD(T p_r) return p_r * 180.0F / 3.1416F; } +template +struct overloaded : Ts... { + using Ts::operator()...; +}; + +template +overloaded(Ts...) -> overloaded; + #endif // __LEGOUTIL_H diff --git a/LEGO1/lego/sources/roi/legolod.cpp b/LEGO1/lego/sources/roi/legolod.cpp index 2e0df088..866c9ef4 100644 --- a/LEGO1/lego/sources/roi/legolod.cpp +++ b/LEGO1/lego/sources/roi/legolod.cpp @@ -71,11 +71,11 @@ LegoResult LegoLOD::Read(Tgl::Renderer* p_renderer, LegoTextureContainer* p_text LegoU32 i, indexBackwards, indexForwards, tempNumVertsAndNormals; unsigned char paletteEntries[256]; - if (p_storage->Read(&m_unk0x08, sizeof(undefined4)) != SUCCESS) { + if (p_storage->Read(&m_flags, sizeof(LegoU32)) != SUCCESS) { goto done; } - if (GetUnknown0x08Test4()) { + if (SkipReadingData()) { return SUCCESS; } @@ -86,11 +86,11 @@ LegoResult LegoLOD::Read(Tgl::Renderer* p_renderer, LegoTextureContainer* p_text } if (m_numMeshes == 0) { - ClearFlag(c_bit4); + ClearFlag(c_hasMesh); return SUCCESS; } - SetFlag(c_bit4); + SetFlag(c_hasMesh); m_melems = new Mesh[m_numMeshes]; memset(m_melems, 0, sizeof(*m_melems) * m_numMeshes); @@ -317,7 +317,7 @@ LegoLOD* LegoLOD::Clone(Tgl::Renderer* p_renderer) dupLod->m_melems[i].m_textured = m_melems[i].m_textured; } - dupLod->m_unk0x08 = m_unk0x08; + dupLod->m_flags = m_flags; dupLod->m_numMeshes = m_numMeshes; dupLod->m_numVertices = m_numVertices; dupLod->m_numPolys = m_numPolys; @@ -353,7 +353,7 @@ LegoResult LegoLOD::SetTextureInfo(LegoTextureInfo* p_textureInfo) } // FUNCTION: LEGO1 0x100aad70 -LegoResult LegoLOD::FUN_100aad70(LegoTextureInfo* p_textureInfo) +LegoResult LegoLOD::UpdateTextureInfo(LegoTextureInfo* p_textureInfo) { for (LegoU32 i = m_meshOffset; i < m_numMeshes; i++) { if (m_melems[i].m_textured) { diff --git a/LEGO1/lego/sources/roi/legolod.h b/LEGO1/lego/sources/roi/legolod.h index 114e377b..e787d377 100644 --- a/LEGO1/lego/sources/roi/legolod.h +++ b/LEGO1/lego/sources/roi/legolod.h @@ -31,7 +31,7 @@ class LegoLOD : public ViewLOD { LegoLOD* Clone(Tgl::Renderer* p_renderer); LegoResult SetColor(LegoFloat p_red, LegoFloat p_green, LegoFloat p_blue, LegoFloat p_alpha); LegoResult SetTextureInfo(LegoTextureInfo* p_textureInfo); - LegoResult FUN_100aad70(LegoTextureInfo* p_textureInfo); + LegoResult UpdateTextureInfo(LegoTextureInfo* p_textureInfo); void ClearMeshOffset(); LegoResult GetTextureInfo(LegoTextureInfo*& p_textureInfo); diff --git a/LEGO1/lego/sources/roi/legoroi.cpp b/LEGO1/lego/sources/roi/legoroi.cpp index 81d8c3d0..260e51e5 100644 --- a/LEGO1/lego/sources/roi/legoroi.cpp +++ b/LEGO1/lego/sources/roi/legoroi.cpp @@ -44,13 +44,13 @@ ROIColorAlias g_roiColorAliases[22] = { int g_roiConfig = 100; // GLOBAL: LEGO1 0x10101370 -const char* g_unk0x10101370[] = {"bike", "moto", NULL}; +const char* g_sharedModelsHigh[] = {"bike", "moto", NULL}; // GLOBAL: LEGO1 0x10101380 -const char* g_unk0x10101380[] = {"bike", "moto", "haus", NULL}; +const char* g_sharedModelsLow[] = {"bike", "moto", "haus", NULL}; // GLOBAL: LEGO1 0x10101390 -const char* g_unk0x10101390[] = {"rcuser", "jsuser", "dunebugy", "chtrblad", "chtrbody", "chtrshld", NULL}; +const char* g_alwaysLoadNames[] = {"rcuser", "jsuser", "dunebugy", "chtrblad", "chtrbody", "chtrshld", NULL}; // GLOBAL: LEGO1 0x101013ac ColorOverride g_colorOverride = NULL; @@ -115,7 +115,7 @@ LegoROI::~LegoROI() // FUNCTION: LEGO1 0x100a84a0 // FUNCTION: BETA10 0x10189b99 LegoResult LegoROI::Read( - OrientableROI* p_unk0xd4, + OrientableROI* p_parentROI, Tgl::Renderer* p_renderer, ViewLODListManager* p_viewLODListManager, LegoTextureContainer* p_textureContainer, @@ -135,7 +135,7 @@ LegoResult LegoROI::Read( LegoSphere sphere; LegoBox box; - m_parentROI = p_unk0xd4; + m_parentROI = p_parentROI; if (p_storage->Read(&length, sizeof(LegoU32)) != SUCCESS) { goto done; @@ -178,11 +178,11 @@ LegoResult LegoROI::Read( textureName = NULL; } - if (p_storage->Read(&m_unk0x100, sizeof(undefined)) != SUCCESS) { + if (p_storage->Read(&m_sharedLodList, sizeof(LegoBool)) != SUCCESS) { goto done; } - if (m_unk0x100) { + if (m_sharedLodList) { for (roiLength = strlen(m_name); roiLength; roiLength--) { if (m_name[roiLength - 1] < '0' || m_name[roiLength - 1] > '9') { break; @@ -225,30 +225,30 @@ LegoResult LegoROI::Read( } if (g_roiConfig <= 2) { - for (i = 0; g_unk0x10101380[i] != NULL; i++) { - if (!SDL_strncasecmp(m_name, g_unk0x10101380[i], 4)) { - roiName = g_unk0x10101380[i]; + for (i = 0; g_sharedModelsLow[i] != NULL; i++) { + if (!SDL_strncasecmp(m_name, g_sharedModelsLow[i], 4)) { + roiName = g_sharedModelsLow[i]; break; } } } else { - for (i = 0; g_unk0x10101370[i] != NULL; i++) { - if (!SDL_strncasecmp(m_name, g_unk0x10101370[i], 4)) { - roiName = g_unk0x10101370[i]; + for (i = 0; g_sharedModelsHigh[i] != NULL; i++) { + if (!SDL_strncasecmp(m_name, g_sharedModelsHigh[i], 4)) { + roiName = g_sharedModelsHigh[i]; break; } } } if ((lodList = p_viewLODListManager->Lookup(roiName))) { - for (j = 0; g_unk0x10101390[j] != NULL; j++) { - if (!SDL_strcasecmp(g_unk0x10101390[j], roiName)) { + for (j = 0; g_alwaysLoadNames[j] != NULL; j++) { + if (!SDL_strcasecmp(g_alwaysLoadNames[j], roiName)) { break; } } - if (g_unk0x10101390[j] != NULL) { + if (g_alwaysLoadNames[j] != NULL) { while (lodList->Size()) { delete const_cast(lodList->PopBack()); } @@ -260,7 +260,7 @@ LegoResult LegoROI::Read( } if (j == 0) { - if (surplusLODs != 0 && lod->GetUnknown0x08Test8()) { + if (surplusLODs != 0 && lod->IsExtraLOD()) { numLODs++; } } @@ -277,7 +277,7 @@ LegoResult LegoROI::Read( } if (i == 0) { - if (surplusLODs != 0 && lod->GetUnknown0x08Test8()) { + if (surplusLODs != 0 && lod->IsExtraLOD()) { numLODs++; } } @@ -390,7 +390,7 @@ LegoROI* LegoROI::FindChildROI(const LegoChar* p_name, LegoROI* p_roi) // FUNCTION: LEGO1 0x100a8da0 // FUNCTION: BETA10 0x1018a9fb -LegoResult LegoROI::ApplyAnimationTransformation( +LegoResult LegoROI::ApplyChildAnimationTransformation( LegoTreeNode* p_node, const Matrix4& p_matrix, LegoTime p_time, @@ -411,11 +411,11 @@ LegoResult LegoROI::ApplyAnimationTransformation( roi->m_local2world.Product(mat, p_matrix); roi->UpdateWorldData(); - LegoBool und = data->GetVisibility(p_time); - roi->SetVisibility(und); + LegoBool visibility = data->GetVisibility(p_time); + roi->SetVisibility(visibility); for (LegoU32 i = 0; i < p_node->GetNumChildren(); i++) { - ApplyAnimationTransformation(p_node->GetChild(i), roi->m_local2world, p_time, roi); + ApplyChildAnimationTransformation(p_node->GetChild(i), roi->m_local2world, p_time, roi); } } else { @@ -427,7 +427,7 @@ LegoResult LegoROI::ApplyAnimationTransformation( // FUNCTION: LEGO1 0x100a8e80 // FUNCTION: BETA10 0x1018ab3a -void LegoROI::FUN_100a8e80(LegoTreeNode* p_node, Matrix4& p_matrix, LegoTime p_time, LegoROI** p_roiMap) +void LegoROI::ApplyAnimationTransformation(LegoTreeNode* p_node, Matrix4& p_matrix, LegoTime p_time, LegoROI** p_roiMap) { MxMatrix mat; @@ -439,11 +439,11 @@ void LegoROI::FUN_100a8e80(LegoTreeNode* p_node, Matrix4& p_matrix, LegoTime p_t roi->m_local2world.Product(mat, p_matrix); roi->UpdateWorldData(); - LegoBool und = data->GetVisibility(p_time); - roi->SetVisibility(und); + LegoBool visiblity = data->GetVisibility(p_time); + roi->SetVisibility(visiblity); for (LegoU32 i = 0; i < p_node->GetNumChildren(); i++) { - FUN_100a8e80(p_node->GetChild(i), roi->m_local2world, p_time, p_roiMap); + ApplyAnimationTransformation(p_node->GetChild(i), roi->m_local2world, p_time, p_roiMap); } } else { @@ -451,14 +451,14 @@ void LegoROI::FUN_100a8e80(LegoTreeNode* p_node, Matrix4& p_matrix, LegoTime p_t local2world.Product(mat, p_matrix); for (LegoU32 i = 0; i < p_node->GetNumChildren(); i++) { - FUN_100a8e80(p_node->GetChild(i), local2world, p_time, p_roiMap); + ApplyAnimationTransformation(p_node->GetChild(i), local2world, p_time, p_roiMap); } } } // FUNCTION: LEGO1 0x100a8fd0 // FUNCTION: BETA10 0x1018ac81 -void LegoROI::FUN_100a8fd0(LegoTreeNode* p_node, Matrix4& p_matrix, LegoTime p_time, LegoROI** p_roiMap) +void LegoROI::ApplyTransform(LegoTreeNode* p_node, Matrix4& p_matrix, LegoTime p_time, LegoROI** p_roiMap) { MxMatrix mat; @@ -470,7 +470,7 @@ void LegoROI::FUN_100a8fd0(LegoTreeNode* p_node, Matrix4& p_matrix, LegoTime p_t roi->m_local2world.Product(mat, p_matrix); for (LegoU32 i = 0; i < p_node->GetNumChildren(); i++) { - FUN_100a8fd0(p_node->GetChild(i), roi->m_local2world, p_time, p_roiMap); + ApplyTransform(p_node->GetChild(i), roi->m_local2world, p_time, p_roiMap); } } else { @@ -478,7 +478,7 @@ void LegoROI::FUN_100a8fd0(LegoTreeNode* p_node, Matrix4& p_matrix, LegoTime p_t local2world.Product(mat, p_matrix); for (LegoU32 i = 0; i < p_node->GetNumChildren(); i++) { - FUN_100a8fd0(p_node->GetChild(i), local2world, p_time, p_roiMap); + ApplyTransform(p_node->GetChild(i), local2world, p_time, p_roiMap); } } } @@ -493,7 +493,7 @@ LegoResult LegoROI::SetFrame(LegoAnim* p_anim, LegoTime p_time) mat = m_local2world; mat.SetIdentity(); // this clears the matrix, assignment above is redundant - return ApplyAnimationTransformation(root, mat, p_time, this); + return ApplyChildAnimationTransformation(root, mat, p_time, this); } // FUNCTION: LEGO1 0x100a9170 @@ -756,7 +756,7 @@ TimeROI::TimeROI(Tgl::Renderer* p_renderer, ViewLODList* p_lodList, LegoTime p_t // FUNCTION: LEGO1 0x100a9b40 // FUNCTION: BETA10 0x1018bbf0 -void TimeROI::FUN_100a9b40(Matrix4& p_matrix, LegoTime p_time) +void TimeROI::CalculateWorldVelocity(Matrix4& p_matrix, LegoTime p_time) { LegoTime time = p_time - m_time; diff --git a/LEGO1/lego/sources/roi/legoroi.h b/LEGO1/lego/sources/roi/legoroi.h index bef2c580..00452334 100644 --- a/LEGO1/lego/sources/roi/legoroi.h +++ b/LEGO1/lego/sources/roi/legoroi.h @@ -27,21 +27,26 @@ class LegoROI : public ViewROI { ~LegoROI() override; LegoResult Read( - OrientableROI* p_unk0xd4, + OrientableROI* p_parentROI, Tgl::Renderer* p_renderer, ViewLODListManager* p_viewLODListManager, LegoTextureContainer* p_textureContainer, LegoStorage* p_storage ); LegoROI* FindChildROI(const LegoChar* p_name, LegoROI* p_roi); - LegoResult ApplyAnimationTransformation( + LegoResult ApplyChildAnimationTransformation( LegoTreeNode* p_node, const Matrix4& p_matrix, LegoTime p_time, LegoROI* p_roi ); - static void FUN_100a8e80(LegoTreeNode* p_node, Matrix4& p_matrix, LegoTime p_time, LegoROI** p_roiMap); - static void FUN_100a8fd0(LegoTreeNode* p_node, Matrix4& p_matrix, LegoTime p_time, LegoROI** p_roiMap); + static void ApplyAnimationTransformation( + LegoTreeNode* p_node, + Matrix4& p_matrix, + LegoTime p_time, + LegoROI** p_roiMap + ); + static void ApplyTransform(LegoTreeNode* p_node, Matrix4& p_matrix, LegoTime p_time, LegoROI** p_roiMap); LegoResult SetFrame(LegoAnim* p_anim, LegoTime p_time); LegoResult SetLodColor(LegoFloat p_red, LegoFloat p_green, LegoFloat p_blue, LegoFloat p_alpha); LegoResult SetTextureInfo(LegoTextureInfo* p_textureInfo); @@ -92,10 +97,10 @@ class LegoROI : public ViewROI { // LegoROI::`scalar deleting destructor' private: - LegoChar* m_name; // 0xe4 - BoundingSphere m_sphere; // 0xe8 - undefined m_unk0x100; // 0x100 - LegoEntity* m_entity; // 0x104 + LegoChar* m_name; // 0xe4 + BoundingSphere m_sphere; // 0xe8 + LegoBool m_sharedLodList; // 0x100 + LegoEntity* m_entity; // 0x104 friend class DebugViewer; }; @@ -107,7 +112,7 @@ class TimeROI : public LegoROI { public: TimeROI(Tgl::Renderer* p_renderer, ViewLODList* p_lodList, LegoTime p_time); - void FUN_100a9b40(Matrix4& p_matrix, LegoTime p_time); + void CalculateWorldVelocity(Matrix4& p_matrix, LegoTime p_time); // SYNTHETIC: LEGO1 0x100a9ad0 // SYNTHETIC: BETA10 0x1018c540 diff --git a/LEGO1/lego1_pch.h b/LEGO1/lego1_pch.h index 624a4be3..40c5db6c 100644 --- a/LEGO1/lego1_pch.h +++ b/LEGO1/lego1_pch.h @@ -87,13 +87,10 @@ #include "lego/legoomni/include/legoextraactor.h" #include "lego/legoomni/include/legoflctexturepresenter.h" #include "lego/legoomni/include/legogamestate.h" -#include "lego/legoomni/include/legohideanimpresenter.h" #include "lego/legoomni/include/legoinputmanager.h" #include "lego/legoomni/include/legoloadcachesoundpresenter.h" #include "lego/legoomni/include/legolocations.h" -#include "lego/legoomni/include/legolocomotionanimpresenter.h" #include "lego/legoomni/include/legolodlist.h" -#include "lego/legoomni/include/legoloopinganimpresenter.h" #include "lego/legoomni/include/legomain.h" #include "lego/legoomni/include/legometerpresenter.h" #include "lego/legoomni/include/legomodelpresenter.h" @@ -239,7 +236,6 @@ #include "omni/include/mxlist.h" #include "omni/include/mxloopingflcpresenter.h" #include "omni/include/mxloopingsmkpresenter.h" -#include "omni/include/mxmediamanager.h" #include "omni/include/mxmediapresenter.h" #include "omni/include/mxmemorypool.h" #include "omni/include/mxmisc.h" @@ -252,6 +248,7 @@ #include "omni/include/mxomnicreateparam.h" #include "omni/include/mxpalette.h" #include "omni/include/mxparam.h" +#include "omni/include/mxpresentationmanager.h" #include "omni/include/mxpresenter.h" #include "omni/include/mxpresenterlist.h" #include "omni/include/mxqueue.h" diff --git a/LEGO1/mxdirectx/legodxinfo.cpp b/LEGO1/mxdirectx/legodxinfo.cpp index 3cc66b56..ff404b90 100644 --- a/LEGO1/mxdirectx/legodxinfo.cpp +++ b/LEGO1/mxdirectx/legodxinfo.cpp @@ -56,7 +56,7 @@ int LegoDeviceEnumerate::ProcessDeviceBytes(int p_deviceNum, GUID& p_guid) GUID4 deviceGuid; memcpy(&deviceGuid, &p_guid, sizeof(GUID4)); - for (list::iterator it = m_list.begin(); it != m_list.end(); it++, i++) { + for (list::iterator it = m_ddInfo.begin(); it != m_ddInfo.end(); it++, i++) { if (p_deviceNum >= 0 && p_deviceNum < i) { return -1; } @@ -91,7 +91,7 @@ int LegoDeviceEnumerate::GetDevice(int p_deviceNum, MxDriver*& p_driver, Direct3 int i = 0; - for (list::iterator it = m_list.begin(); it != m_list.end(); it++) { + for (list::iterator it = m_ddInfo.begin(); it != m_ddInfo.end(); it++) { p_driver = &*it; for (list::iterator it2 = p_driver->m_devices.begin(); it2 != p_driver->m_devices.end(); @@ -115,7 +115,7 @@ int LegoDeviceEnumerate::FormatDeviceName(char* p_buffer, const MxDriver* p_ddIn int number = 0; assert(p_ddInfo && p_d3dInfo); - for (list::const_iterator it = m_list.begin(); it != m_list.end(); it++, number++) { + for (list::const_iterator it = m_ddInfo.begin(); it != m_ddInfo.end(); it++, number++) { if (&(*it) == p_ddInfo) { GUID4 guid; memcpy(&guid, p_d3dInfo->m_guid, sizeof(GUID4)); @@ -138,7 +138,7 @@ int LegoDeviceEnumerate::BETA_1011cc65(int p_idx, char* p_buffer) int i = 0; int j = 0; - for (list::iterator it = m_list.begin(); it != m_list.end(); it++, i++) { + for (list::iterator it = m_ddInfo.begin(); it != m_ddInfo.end(); it++, i++) { MxDriver& driver = *it; for (list::iterator it2 = driver.m_devices.begin(); it2 != driver.m_devices.end(); it2++) { @@ -165,14 +165,14 @@ int LegoDeviceEnumerate::GetBestDevice() return -1; } - if (m_list.size() == 0) { + if (m_ddInfo.size() == 0) { return -1; } int j = 0; int k = -1; - for (list::iterator it = m_list.begin(); it != m_list.end(); it++) { + for (list::iterator it = m_ddInfo.begin(); it != m_ddInfo.end(); it++) { MxDriver& driver = *it; for (list::iterator it2 = driver.m_devices.begin(); it2 != driver.m_devices.end(); it2++) { @@ -199,7 +199,7 @@ int LegoDeviceEnumerate::FUN_1009d210() return -1; } - for (list::iterator it = m_list.begin(); it != m_list.end();) { + for (list::iterator it = m_ddInfo.begin(); it != m_ddInfo.end();) { MxDriver& driver = *it; for (list::iterator it2 = driver.m_devices.begin(); it2 != driver.m_devices.end();) { @@ -212,14 +212,14 @@ int LegoDeviceEnumerate::FUN_1009d210() } if (!driver.m_devices.size()) { - m_list.erase(it++); + m_ddInfo.erase(it++); } else { it++; } } - if (!m_list.size()) { + if (!m_ddInfo.size()) { return -1; } @@ -231,7 +231,7 @@ int LegoDeviceEnumerate::FUN_1009d210() // FUNCTION: BETA10 0x1011d235 unsigned char LegoDeviceEnumerate::FUN_1009d3d0(Direct3DDeviceInfo& p_device) { - if (m_list.size() <= 0) { + if (m_ddInfo.size() <= 0) { return FALSE; } @@ -246,7 +246,7 @@ unsigned char LegoDeviceEnumerate::FUN_1009d3d0(Direct3DDeviceInfo& p_device) } } - MxDriver& front = m_list.front(); + MxDriver& front = m_ddInfo.front(); for (list::iterator it = front.m_devices.begin(); it != front.m_devices.end(); it++) { if ((&*it) == &p_device) { return TRUE; diff --git a/LEGO1/mxdirectx/mxdirect3d.cpp b/LEGO1/mxdirectx/mxdirect3d.cpp index d6043a2c..84ff77d3 100644 --- a/LEGO1/mxdirectx/mxdirect3d.cpp +++ b/LEGO1/mxdirectx/mxdirect3d.cpp @@ -1,7 +1,12 @@ +#ifndef MINIWIN +#include +#endif + #include "mxdirect3d.h" #include // for SDL_Log #include +#include DECOMP_SIZE_ASSERT(MxDirect3D, 0x894) @@ -44,6 +49,7 @@ BOOL MxDirect3D::Create( ) { BOOL success = FALSE; + IDirect3DMiniwin* miniwind3d = nullptr; assert(m_currentDeviceInfo); if (!MxDirectDraw::Create( @@ -64,6 +70,21 @@ BOOL MxDirect3D::Create( goto done; } + if (m_pDirect3d->QueryInterface(IID_IDirect3DMiniwin, (void**) &miniwind3d) == DD_OK) { + MxVideoParam* videoParam = (MxVideoParam*) SDL_GetPointerProperty( + SDL_GetWindowProperties(reinterpret_cast(hWnd)), + ISLE_PROP_WINDOW_CREATE_VIDEO_PARAM, + nullptr + ); +#ifndef MXDIRECTX_FOR_CONFIG + assert(videoParam); +#endif + if (videoParam) { + miniwind3d->RequestMSAA(videoParam->GetMSAASamples()); + miniwind3d->RequestAnisotropic(videoParam->GetAnisotropic()); + } + } + if (!D3DSetMode()) { goto done; } @@ -170,39 +191,16 @@ BOOL MxDirect3D::D3DSetMode() LPDIRECTDRAWSURFACE frontBuffer = FrontBuffer(); LPDIRECTDRAWSURFACE backBuffer = BackBuffer(); - DDSURFACEDESC desc; - memset(&desc, 0, sizeof(desc)); - desc.dwSize = sizeof(desc); + DDBLTFX ddBltFx = {}; + ddBltFx.dwSize = sizeof(DDBLTFX); + ddBltFx.dwFillColor = 0xFF000000; - if (backBuffer->Lock(NULL, &desc, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL) == DD_OK) { - unsigned char* surface = (unsigned char*) desc.lpSurface; - - for (int i = 0; i < mode.height; i++) { - memset(surface, 0, desc.lPitch); - surface += desc.lPitch; - } - - backBuffer->Unlock(desc.lpSurface); - } - else { - SDL_Log("MxDirect3D::D3DSetMode() back lock failed\n"); + if (backBuffer->Blt(NULL, NULL, NULL, DDBLT_WAIT | DDBLT_COLORFILL, &ddBltFx) != DD_OK) { + SDL_Log("MxDirect3D::D3DSetMode() color fill failed\n"); } if (IsFullScreen()) { - memset(&desc, 0, sizeof(desc)); - desc.dwSize = sizeof(desc); - - if (frontBuffer->Lock(NULL, &desc, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL) == DD_OK) { - unsigned char* surface = (unsigned char*) desc.lpSurface; - - for (int i = 0; i < mode.height; i++) { - memset(surface, 0, desc.lPitch); - surface += desc.lPitch; - } - - frontBuffer->Unlock(desc.lpSurface); - } - else { + if (frontBuffer->Blt(NULL, NULL, NULL, DDBLT_WAIT | DDBLT_COLORFILL, &ddBltFx) != DD_OK) { SDL_Log("MxDirect3D::D3DSetMode() front lock failed\n"); } } @@ -257,7 +255,7 @@ BOOL MxDirect3D::SetDevice(MxDeviceEnumerate& p_deviceEnumerate, MxDriver* p_dri assert(d); int i = 0; - for (list::iterator it = p_deviceEnumerate.m_list.begin(); it != p_deviceEnumerate.m_list.end(); + for (list::iterator it = p_deviceEnumerate.m_ddInfo.begin(); it != p_deviceEnumerate.m_ddInfo.end(); it++, i++) { MxDriver& driver = *it; diff --git a/LEGO1/mxdirectx/mxdirectdraw.cpp b/LEGO1/mxdirectx/mxdirectdraw.cpp index 104b6836..7ccb78c2 100644 --- a/LEGO1/mxdirectx/mxdirectdraw.cpp +++ b/LEGO1/mxdirectx/mxdirectdraw.cpp @@ -32,8 +32,6 @@ MxDirectDraw::MxDirectDraw() m_pPalette = NULL; m_pDirectDraw = NULL; m_bIsOnPrimaryDevice = TRUE; - m_pText1Surface = NULL; - m_pText2Surface = NULL; m_hWndMain = NULL; m_bIgnoreWMSIZE = FALSE; m_bPrimaryPalettized = FALSE; @@ -236,8 +234,6 @@ void MxDirectDraw::DestroyButNotDirectDraw() RELEASE(m_pPalette); RELEASE(m_pClipper); - RELEASE(m_pText1Surface); - RELEASE(m_pText2Surface); RELEASE(m_pZBuffer); RELEASE(m_pBackBuffer); RELEASE(m_pFrontBuffer); @@ -409,13 +405,6 @@ BOOL MxDirectDraw::DDSetMode(int width, int height, int bpp) } } - // create debug text only in windowed mode? - if (!m_bFullScreen) { - if (!CreateTextSurfaces()) { - return FALSE; - } - } - return TRUE; } @@ -530,168 +519,29 @@ BOOL MxDirectDraw::DDCreateSurfaces() void MxDirectDraw::ClearBackBuffers() { HRESULT result; - byte* line; - DDSURFACEDESC ddsd; + DDBLTFX ddbltfx = {}; + ddbltfx.dwSize = sizeof(DDBLTFX); + ddbltfx.dwFillColor = 0xFF000000; int count = m_bFlipSurfaces ? 2 : 1; - int value = 0; for (int i = 0; i < count; i++) { - memset(&ddsd, 0, sizeof(ddsd)); - ddsd.dwSize = sizeof(ddsd); - - result = m_pBackBuffer->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL); + result = m_pBackBuffer->Blt(NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &ddbltfx); if (result == DDERR_SURFACELOST) { m_pBackBuffer->Restore(); - result = m_pBackBuffer->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL); + result = m_pBackBuffer->Blt(NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &ddbltfx); } if (result != DD_OK) { - // lock failed + // blt failed return; } - // clear backBuffer - line = (byte*) ddsd.lpSurface; - for (int j = ddsd.dwHeight; j--;) { - memset(line, value, ddsd.dwWidth); - line += ddsd.lPitch; - } - - m_pBackBuffer->Unlock(ddsd.lpSurface); - if (m_bFlipSurfaces) { m_pFrontBuffer->Flip(NULL, DDFLIP_WAIT); } } } -// FUNCTION: LEGO1 0x1009e110 -// FUNCTION: BETA10 0x101219de -BOOL MxDirectDraw::TextToTextSurface(const char* text, IDirectDrawSurface* pSurface, SIZE& textSizeOnSurface) -{ - HRESULT result; - HDC hdc; - RECT rc; - size_t textLength; - - if (!pSurface) { - return FALSE; - } - - result = pSurface->GetDC(&hdc); - if (result != DD_OK) { - Error("GetDC for text surface failed", result); - return FALSE; - } - - textLength = strlen(text); - - SelectObject(hdc, m_hFont); - SetTextColor(hdc, RGB(255, 255, 0)); - SetBkColor(hdc, RGB(0, 0, 0)); - SetBkMode(hdc, OPAQUE); - GetTextExtentPoint32(hdc, text, textLength, &textSizeOnSurface); - SetRect(&rc, 0, 0, textSizeOnSurface.cx, textSizeOnSurface.cy); - ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rc, text, textLength, NULL); - pSurface->ReleaseDC(hdc); - - return TRUE; -} - -// FUNCTION: LEGO1 0x1009e210 -// FUNCTION: BETA10 0x10121aea -BOOL MxDirectDraw::TextToTextSurface1(const char* text) -{ - return TextToTextSurface(text, m_pText1Surface, m_text1SizeOnSurface); -} - -// FUNCTION: LEGO1 0x1009e230 -// FUNCTION: BETA10 0x10121b1e -BOOL MxDirectDraw::TextToTextSurface2(const char* text) -{ - return TextToTextSurface(text, m_pText2Surface, m_text2SizeOnSurface); -} - -// FUNCTION: LEGO1 0x1009e250 -// FUNCTION: BETA10 0x10121b52 -BOOL MxDirectDraw::CreateTextSurfaces() -{ - HRESULT result; - DDCOLORKEY ddck; - DDSURFACEDESC ddsd; - HDC hdc; - char dummyinfo[] = "000x000x00 (RAMP) 0000"; - char dummyfps[] = "000.00 fps (000.00 fps (000.00 fps) 00000 tps)"; - - if (m_hFont != NULL) { - DeleteObject(m_hFont); - } - m_hFont = CreateFont( - m_currentMode.width <= 600 ? 12 : 24, - 0, - 0, - 0, - FW_NORMAL, - FALSE, - FALSE, - FALSE, - ANSI_CHARSET, - OUT_DEFAULT_PRECIS, - CLIP_DEFAULT_PRECIS, - DEFAULT_QUALITY, - VARIABLE_PITCH, - "Arial" - ); - - hdc = GetDC(NULL); - SelectObject(hdc, m_hFont); - GetTextExtentPoint(hdc, dummyfps, strlen(dummyfps), &m_text1SizeOnSurface); - GetTextExtentPoint(hdc, dummyinfo, strlen(dummyinfo), &m_text2SizeOnSurface); - ReleaseDC(NULL, hdc); - - memset(&ddsd, 0, sizeof(ddsd)); - ddsd.dwSize = sizeof(ddsd); - ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH; - ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN; - if (m_bOnlySystemMemory) { - ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY; - } - ddsd.dwHeight = m_text1SizeOnSurface.cy; - ddsd.dwWidth = m_text1SizeOnSurface.cx; - result = CreateDDSurface(&ddsd, &m_pText1Surface, NULL); - if (result != DD_OK) { - Error("CreateSurface for text surface 1 failed", result); - return FALSE; - } - memset(&ddck, 0, sizeof(ddck)); - m_pText1Surface->SetColorKey(DDCKEY_SRCBLT, &ddck); - if (!TextToTextSurface1(dummyfps)) { - return FALSE; - } - - memset(&ddsd, 0, sizeof(ddsd)); - ddsd.dwSize = sizeof(ddsd); - ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH; - ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN; - if (m_bOnlySystemMemory) { - ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY; - } - ddsd.dwHeight = m_text2SizeOnSurface.cy; - ddsd.dwWidth = m_text2SizeOnSurface.cx; - result = CreateDDSurface(&ddsd, &m_pText2Surface, NULL); - if (result != DD_OK) { - Error("CreateSurface for text surface 2 failed", result); - return FALSE; - } - memset(&ddck, 0, sizeof(ddck)); - m_pText2Surface->SetColorKey(DDCKEY_SRCBLT, &ddck); - if (!TextToTextSurface2(dummyinfo)) { - return FALSE; - } - - return TRUE; -} - // FUNCTION: LEGO1 0x1009e4d0 // FUNCTION: BETA10 0x10121e87 BOOL MxDirectDraw::RestoreSurfaces() @@ -728,26 +578,6 @@ BOOL MxDirectDraw::RestoreSurfaces() } } - if (m_pText1Surface != NULL) { - if (m_pText1Surface->IsLost() == DDERR_SURFACELOST) { - result = m_pText1Surface->Restore(); - if (result != DD_OK) { - Error("Restore of text surface 1 failed", result); - return FALSE; - } - } - } - - if (m_pText2Surface != NULL) { - if (m_pText2Surface->IsLost() == DDERR_SURFACELOST) { - result = m_pText2Surface->Restore(); - if (result != DD_OK) { - Error("Restore of text surface 2 failed", result); - return FALSE; - } - } - } - return TRUE; } diff --git a/LEGO1/mxdirectx/mxdirectdraw.h b/LEGO1/mxdirectx/mxdirectdraw.h index 574f8e54..554de189 100644 --- a/LEGO1/mxdirectx/mxdirectdraw.h +++ b/LEGO1/mxdirectx/mxdirectdraw.h @@ -58,9 +58,6 @@ class MxDirectDraw { int Pause(BOOL); BOOL RestoreSurfaces(); - BOOL TextToTextSurface1(const char* text); - BOOL TextToTextSurface2(const char* lpString); - virtual const char* ErrorToString(HRESULT p_error); // vtable+0x10 int FlipToGDISurface(); @@ -77,9 +74,6 @@ class MxDirectDraw { BOOL GetDDSurfaceDesc(LPDDSURFACEDESC lpDDSurfDesc, LPDIRECTDRAWSURFACE lpDDSurf); BOOL CreateZBuffer(DDSCapsFlags memorytype, DWORD depth); - BOOL CreateTextSurfaces(); - BOOL TextToTextSurface(const char* text, IDirectDrawSurface* pSurface, SIZE& textSizeOnSurface); - void Error(const char* p_message, int p_error); BOOL RecreateDirectDraw(GUID** a2); @@ -97,8 +91,6 @@ class MxDirectDraw { IDirectDrawSurface* m_pFrontBuffer; // 0x10 IDirectDrawSurface* m_pBackBuffer; // 0x14 IDirectDrawSurface* m_pZBuffer; // 0x18 - IDirectDrawSurface* m_pText1Surface; // 0x1c - IDirectDrawSurface* m_pText2Surface; // 0x20 IDirectDrawClipper* m_pClipper; // 0x24 IDirectDrawPalette* m_pPalette; // 0x28 PALETTEENTRY m_paletteEntries[256]; // 0x2c diff --git a/LEGO1/mxdirectx/mxdirectxinfo.cpp b/LEGO1/mxdirectx/mxdirectxinfo.cpp index c5100031..765d32f7 100644 --- a/LEGO1/mxdirectx/mxdirectxinfo.cpp +++ b/LEGO1/mxdirectx/mxdirectxinfo.cpp @@ -1,7 +1,10 @@ #include "mxdirectxinfo.h" +#include "omni/include/mxvideoparam.h" + #include #include +#include #include // for vsprintf DECOMP_SIZE_ASSERT(MxAssignedDevice, 0xe4) @@ -30,13 +33,12 @@ MxAssignedDevice::~MxAssignedDevice() } // FUNCTION: BETA10 0x1011d7f0 -MxDriver::MxDriver(LPGUID p_guid) +MxDriver::MxDriver() { m_guid = NULL; m_driverDesc = NULL; m_driverName = NULL; memset(&m_ddCaps, 0, sizeof(m_ddCaps)); - // TODO: ret vs ret 4 } // FUNCTION: CONFIG 0x00401180 @@ -99,6 +101,12 @@ void MxDriver::Init(LPGUID p_guid, LPCSTR p_driverDesc, LPCSTR p_driverName) } } +// FUNCTION: BETA10 0x1011dba4 +Direct3DDeviceInfo::Direct3DDeviceInfo() +{ + memset(this, 0, sizeof(*this)); +} + // FUNCTION: CONFIG 0x401420 // FUNCTION: LEGO1 0x1009bd20 // FUNCTION: BETA10 0x1011dbd0 @@ -198,7 +206,7 @@ MxDeviceEnumerate::~MxDeviceEnumerate() BOOL MxDeviceEnumerate::EnumDirectDrawCallback(LPGUID p_guid, LPSTR p_driverDesc, LPSTR p_driverName) { MxDriver driver(p_guid, p_driverDesc, p_driverName); - m_list.push_back(driver); + m_ddInfo.push_back(driver); // Must be zeroed because held resources are copied by pointer only // and should not be freed at the end of this function @@ -209,40 +217,64 @@ BOOL MxDeviceEnumerate::EnumDirectDrawCallback(LPGUID p_guid, LPSTR p_driverDesc LPDIRECT3D2 lpDirect3d2 = NULL; LPDIRECTDRAW lpDD = NULL; - MxDriver& newDevice = m_list.back(); + MxDriver& newDevice = m_ddInfo.back(); HRESULT result = DirectDrawCreate(newDevice.m_guid, &lpDD, NULL); + IDirect3DMiniwin* miniwind3d = nullptr; if (result != DD_OK) { BuildErrorString("DirectDraw Create failed: %s\n", EnumerateErrorToString(result)); + goto done; } - else { - newDevice.m_ddCaps.dwSize = sizeof(newDevice.m_ddCaps); - result = lpDD->GetCaps(&newDevice.m_ddCaps, NULL); - if (result != DD_OK) { - BuildErrorString("GetCaps failed: %s\n", EnumerateErrorToString(result)); - } - else { - result = lpDD->QueryInterface(IID_IDirect3D2, (LPVOID*) &lpDirect3d2); - - if (result != DD_OK) { - BuildErrorString("D3D creation failed: %s\n", EnumerateErrorToString(result)); - } - else { - result = lpDirect3d2->EnumDevices(DevicesEnumerateCallback, this); - - if (result != DD_OK) { - BuildErrorString("D3D enum devices failed: %s\n", EnumerateErrorToString(result)); - } - else { - if (!newDevice.m_devices.size()) { - m_list.pop_back(); - } - } - } + result = lpDD->QueryInterface(IID_IDirect3DMiniwin, (void**) &miniwind3d); + if (result == DD_OK) { + MxVideoParam* videoParam = (MxVideoParam*) SDL_GetPointerProperty( + SDL_GetWindowProperties(reinterpret_cast(m_hWnd)), + ISLE_PROP_WINDOW_CREATE_VIDEO_PARAM, + nullptr + ); +#ifndef MXDIRECTX_FOR_CONFIG + assert(videoParam); +#endif + if (videoParam) { + miniwind3d->RequestMSAA(videoParam->GetMSAASamples()); + miniwind3d->RequestAnisotropic(videoParam->GetAnisotropic()); } } + result = lpDD->SetCooperativeLevel(m_hWnd, DDSCL_NORMAL); + if (result != DD_OK) { + BuildErrorString("SetCooperativeLevel failed: %s\n", EnumerateErrorToString(result)); + goto done; + } + + newDevice.m_ddCaps.dwSize = sizeof(newDevice.m_ddCaps); + result = lpDD->GetCaps(&newDevice.m_ddCaps, NULL); + + if (result != DD_OK) { + BuildErrorString("GetCaps failed: %s\n", EnumerateErrorToString(result)); + goto done; + } + + result = lpDD->QueryInterface(IID_IDirect3D2, (LPVOID*) &lpDirect3d2); + + if (result != DD_OK) { + BuildErrorString("D3D creation failed: %s\n", EnumerateErrorToString(result)); + goto done; + } + + result = lpDirect3d2->EnumDevices(DevicesEnumerateCallback, this); + + if (result != DD_OK) { + BuildErrorString("D3D enum devices failed: %s\n", EnumerateErrorToString(result)); + goto done; + } + + if (!newDevice.m_devices.size()) { + m_ddInfo.pop_back(); + } + +done: if (lpDirect3d2) { lpDirect3d2->Release(); } @@ -275,15 +307,14 @@ HRESULT CALLBACK MxDeviceEnumerate::DevicesEnumerateCallback( LPSTR p_deviceName, LPD3DDEVICEDESC p_HWDesc, LPD3DDEVICEDESC p_HELDesc, - LPVOID p_context + LPVOID p_d ) { - if (p_context == NULL) { + if (p_d == NULL) { assert(0); } - return ((MxDeviceEnumerate*) p_context) - ->EnumDevicesCallback(p_guid, p_deviceDesc, p_deviceName, p_HWDesc, p_HELDesc); + return ((MxDeviceEnumerate*) p_d)->EnumDevicesCallback(p_guid, p_deviceDesc, p_deviceName, p_HWDesc, p_HELDesc); } // FUNCTION: CONFIG 0x00401cd0 @@ -298,7 +329,7 @@ HRESULT MxDeviceEnumerate::EnumDevicesCallback( ) { Direct3DDeviceInfo device(p_guid, p_deviceDesc, p_deviceName, p_HWDesc, p_HELDesc); - m_list.back().m_devices.push_back(device); + m_ddInfo.back().m_devices.push_back(device); memset(&device, 0, sizeof(device)); return DDENUMRET_OK; } @@ -306,12 +337,14 @@ HRESULT MxDeviceEnumerate::EnumDevicesCallback( // FUNCTION: CONFIG 0x00401dc0 // FUNCTION: LEGO1 0x1009c6c0 // FUNCTION: BETA10 0x1011e3fa -int MxDeviceEnumerate::DoEnumerate() +int MxDeviceEnumerate::DoEnumerate(HWND hWnd) { if (IsInitialized()) { return -1; } + m_hWnd = hWnd; + HRESULT ret = DirectDrawEnumerate(DirectDrawEnumerateCallback, this); if (ret != DD_OK) { BuildErrorString("DirectDrawEnumerate returned error %s\n", EnumerateErrorToString(ret)); @@ -326,13 +359,10 @@ int MxDeviceEnumerate::DoEnumerate() // FUNCTION: LEGO1 0x1009c710 // FUNCTION: BETA10 0x1011e476 BOOL CALLBACK -MxDeviceEnumerate::DirectDrawEnumerateCallback(LPGUID p_guid, LPSTR p_driverDesc, LPSTR p_driverName, LPVOID p_context) +MxDeviceEnumerate::DirectDrawEnumerateCallback(LPGUID p_guid, LPSTR p_driverDesc, LPSTR p_driverName, LPVOID p_d) { - if (p_context == NULL) { - assert(0); - } - - return ((MxDeviceEnumerate*) p_context)->EnumDirectDrawCallback(p_guid, p_driverDesc, p_driverName); + assert(p_d); + return ((MxDeviceEnumerate*) p_d)->EnumDirectDrawCallback(p_guid, p_driverDesc, p_driverName); } // FUNCTION: CONFIG 0x00401e30 @@ -343,79 +373,123 @@ const char* MxDeviceEnumerate::EnumerateErrorToString(HRESULT p_error) switch (p_error) { case DD_OK: return "No error."; - case DDERR_GENERIC: - return "Generic failure."; - case DDERR_UNSUPPORTED: - return "Action not supported."; - case DDERR_INVALIDPARAMS: - return "One or more of the parameters passed to the function are incorrect."; - case DDERR_OUTOFMEMORY: - return "DirectDraw does not have enough memory to perform the operation."; - case DDERR_CANNOTATTACHSURFACE: - return "This surface can not be attached to the requested surface."; case DDERR_ALREADYINITIALIZED: return "This object is already initialized."; - case DDERR_CURRENTLYNOTAVAIL: - return "Support is currently not available."; + case DDERR_BLTFASTCANTCLIP: + return "Return if a clipper object is attached to the source surface passed into a BltFast call."; + case DDERR_CANNOTATTACHSURFACE: + return "This surface can not be attached to the requested surface."; case DDERR_CANNOTDETACHSURFACE: return "This surface can not be detached from the requested surface."; - case DDERR_HEIGHTALIGN: - return "Height of rectangle provided is not a multiple of reqd alignment."; + case DDERR_CANTCREATEDC: + return "Windows can not create any more DCs."; + case DDERR_CANTDUPLICATE: + return "Can't duplicate primary & 3D surfaces, or surfaces that are implicitly created."; + case DDERR_CLIPPERISUSINGHWND: + return "An attempt was made to set a cliplist for a clipper object that is already monitoring an hwnd."; + case DDERR_COLORKEYNOTSET: + return "No src color key specified for this operation."; + case DDERR_CURRENTLYNOTAVAIL: + return "Support is currently not available."; + case DDERR_DIRECTDRAWALREADYCREATED: + return "A DirectDraw object representing this driver has already been created for this process."; case DDERR_EXCEPTION: return "An exception was encountered while performing the requested operation."; - case DDERR_INVALIDCAPS: - return "One or more of the caps bits passed to the callback are incorrect."; + case DDERR_EXCLUSIVEMODEALREADYSET: + return "An attempt was made to set the cooperative level when it was already set to exclusive."; + case DDERR_GENERIC: + return "Generic failure."; + case DDERR_HEIGHTALIGN: + return "Height of rectangle provided is not a multiple of reqd alignment."; + case DDERR_HWNDALREADYSET: + return "The CooperativeLevel HWND has already been set. It can not be reset while the process has surfaces or " + "palettes created."; + case DDERR_HWNDSUBCLASSED: + return "HWND used by DirectDraw CooperativeLevel has been subclassed, this prevents DirectDraw from restoring " + "state."; + case DDERR_IMPLICITLYCREATED: + return "This surface can not be restored because it is an implicitly created surface."; case DDERR_INCOMPATIBLEPRIMARY: return "Unable to match primary surface creation request with existing primary surface."; - case DDERR_INVALIDMODE: - return "DirectDraw does not support the requested mode."; + case DDERR_INVALIDCAPS: + return "One or more of the caps bits passed to the callback are incorrect."; case DDERR_INVALIDCLIPLIST: return "DirectDraw does not support the provided cliplist."; - case DDERR_INVALIDPIXELFORMAT: - return "The pixel format was invalid as specified."; + case DDERR_INVALIDDIRECTDRAWGUID: + return "The GUID passed to DirectDrawCreate is not a valid DirectDraw driver identifier."; + case DDERR_INVALIDMODE: + return "DirectDraw does not support the requested mode."; case DDERR_INVALIDOBJECT: return "DirectDraw received a pointer that was an invalid DIRECTDRAW object."; - case DDERR_LOCKEDSURFACES: - return "Operation could not be carried out because one or more surfaces are locked."; + case DDERR_INVALIDPARAMS: + return "One or more of the parameters passed to the function are incorrect."; + case DDERR_INVALIDPIXELFORMAT: + return "The pixel format was invalid as specified."; + case DDERR_INVALIDPOSITION: + return "Returned when the position of the overlay on the destination is no longer legal for that " + "destination."; case DDERR_INVALIDRECT: return "Rectangle provided was invalid."; + case DDERR_LOCKEDSURFACES: + return "Operation could not be carried out because one or more surfaces are locked."; + case DDERR_NO3D: + return "There is no 3D present."; case DDERR_NOALPHAHW: return "Operation could not be carried out because there is no alpha accleration hardware present or " "available."; - case DDERR_NO3D: - return "There is no 3D present."; - case DDERR_NOCOLORCONVHW: - return "Operation could not be carried out because there is no color conversion hardware present or available."; + case DDERR_NOBLTHW: + return "No blitter hardware present."; case DDERR_NOCLIPLIST: return "No cliplist available."; + case DDERR_NOCLIPPERATTACHED: + return "No clipper object attached to surface object."; + case DDERR_NOCOLORCONVHW: + return "Operation could not be carried out because there is no color conversion hardware present or " + "available."; case DDERR_NOCOLORKEY: return "Surface doesn't currently have a color key"; + case DDERR_NOCOLORKEYHW: + return "Operation could not be carried out because there is no hardware support of the destination color " + "key."; case DDERR_NOCOOPERATIVELEVELSET: return "Create function called without DirectDraw object method SetCooperativeLevel being called."; + case DDERR_NODC: + return "No DC was ever created for this surface."; + case DDERR_NODDROPSHW: + return "No DirectDraw ROP hardware."; + case DDERR_NODIRECTDRAWHW: + return "A hardware-only DirectDraw object creation was attempted but the driver did not support any " + "hardware."; + case DDERR_NOEMULATION: + return "Software emulation not available."; case DDERR_NOEXCLUSIVEMODE: return "Operation requires the application to have exclusive mode but the application does not have exclusive " "mode."; - case DDERR_NOCOLORKEYHW: - return "Operation could not be carried out because there is no hardware support of the destination color key."; - case DDERR_NOGDI: - return "There is no GDI present."; case DDERR_NOFLIPHW: return "Flipping visible surfaces is not supported."; - case DDERR_NOTFOUND: - return "Requested item was not found."; + case DDERR_NOGDI: + return "There is no GDI present."; + case DDERR_NOHWND: + return "Clipper notification requires an HWND or no HWND has previously been set as the CooperativeLevel " + "HWND."; case DDERR_NOMIRRORHW: return "Operation could not be carried out because there is no hardware present or available."; + case DDERR_NOOVERLAYDEST: + return "Returned when GetOverlayPosition is called on an overlay that UpdateOverlay has never been called on " + "to establish a destination."; + case DDERR_NOOVERLAYHW: + return "Operation could not be carried out because there is no overlay hardware present or available."; + case DDERR_NOPALETTEATTACHED: + return "No palette object attached to this surface."; + case DDERR_NOPALETTEHW: + return "No hardware support for 16 or 256 color palettes."; case DDERR_NORASTEROPHW: return "Operation could not be carried out because there is no appropriate raster op hardware present or " "available."; - case DDERR_NOOVERLAYHW: - return "Operation could not be carried out because there is no overlay hardware present or available."; - case DDERR_NOSTRETCHHW: - return "Operation could not be carried out because there is no hardware support for stretching."; case DDERR_NOROTATIONHW: return "Operation could not be carried out because there is no rotation hardware present or available."; - case DDERR_NOTEXTUREHW: - return "Operation could not be carried out because there is no texture mapping hardware present or available."; + case DDERR_NOSTRETCHHW: + return "Operation could not be carried out because there is no hardware support for stretching."; case DDERR_NOT4BITCOLOR: return "DirectDrawSurface is not in 4 bit color palette and the requested operation requires 4 bit color " "palette."; @@ -424,118 +498,80 @@ const char* MxDeviceEnumerate::EnumerateErrorToString(HRESULT p_error) "index palette."; case DDERR_NOT8BITCOLOR: return "DirectDrawSurface is not in 8 bit color mode and the requested operation requires 8 bit color."; - case DDERR_NOZBUFFERHW: - return "Operation could not be carried out because there is no hardware support for zbuffer blitting."; + case DDERR_NOTAOVERLAYSURFACE: + return "Returned when an overlay member is called for a non-overlay surface."; + case DDERR_NOTEXTUREHW: + return "Operation could not be carried out because there is no texture mapping hardware present or " + "available."; + case DDERR_NOTFLIPPABLE: + return "An attempt has been made to flip a surface that is not flippable."; + case DDERR_NOTFOUND: + return "Requested item was not found."; + case DDERR_NOTLOCKED: + return "Surface was not locked. An attempt to unlock a surface that was not locked at all, or by this " + "process, has been attempted."; + case DDERR_NOTPALETTIZED: + return "The surface being used is not a palette-based surface."; case DDERR_NOVSYNCHW: return "Operation could not be carried out because there is no hardware support for vertical blank " "synchronized operations."; - case DDERR_OUTOFCAPS: - return "The hardware needed for the requested operation has already been allocated."; + case DDERR_NOZBUFFERHW: + return "Operation could not be carried out because there is no hardware support for zbuffer blitting."; case DDERR_NOZOVERLAYHW: return "Overlay surfaces could not be z layered based on their BltOrder because the hardware does not support " "z layering of overlays."; - case DDERR_COLORKEYNOTSET: - return "No src color key specified for this operation."; + case DDERR_OUTOFCAPS: + return "The hardware needed for the requested operation has already been allocated."; + case DDERR_OUTOFMEMORY: + return "DirectDraw does not have enough memory to perform the operation."; case DDERR_OUTOFVIDEOMEMORY: return "DirectDraw does not have enough memory to perform the operation."; case DDERR_OVERLAYCANTCLIP: return "The hardware does not support clipped overlays."; case DDERR_OVERLAYCOLORKEYONLYONEACTIVE: return "Can only have ony color key active at one time for overlays."; + case DDERR_OVERLAYNOTVISIBLE: + return "Returned when GetOverlayPosition is called on a hidden overlay."; case DDERR_PALETTEBUSY: return "Access to this palette is being refused because the palette is already locked by another thread."; - case DDERR_SURFACEALREADYDEPENDENT: - return "This surface is already a dependency of the surface it is being made a dependency of."; + case DDERR_PRIMARYSURFACEALREADYEXISTS: + return "This process already has created a primary surface."; + case DDERR_REGIONTOOSMALL: + return "Region passed to Clipper::GetClipList is too small."; case DDERR_SURFACEALREADYATTACHED: return "This surface is already attached to the surface it is being attached to."; - case DDERR_SURFACEISOBSCURED: - return "Access to surface refused because the surface is obscured."; + case DDERR_SURFACEALREADYDEPENDENT: + return "This surface is already a dependency of the surface it is being made a dependency of."; case DDERR_SURFACEBUSY: return "Access to this surface is being refused because the surface is already locked by another thread."; - case DDERR_SURFACENOTATTACHED: - return "The requested surface is not attached."; + case DDERR_SURFACEISOBSCURED: + return "Access to surface refused because the surface is obscured."; case DDERR_SURFACELOST: return "Access to this surface is being refused because the surface memory is gone. The DirectDrawSurface " "object representing this surface should have Restore called on it."; - case DDERR_TOOBIGSIZE: - return "Size requested by DirectDraw is too large, but the individual height and width are OK."; + case DDERR_SURFACENOTATTACHED: + return "The requested surface is not attached."; case DDERR_TOOBIGHEIGHT: return "Height requested by DirectDraw is too large."; - case DDERR_UNSUPPORTEDFORMAT: - return "FOURCC format requested is unsupported by DirectDraw."; + case DDERR_TOOBIGSIZE: + return "Size requested by DirectDraw is too large, but the individual height and width are OK."; case DDERR_TOOBIGWIDTH: return "Width requested by DirectDraw is too large."; - case DDERR_VERTICALBLANKINPROGRESS: - return "Vertical blank is in progress."; + case DDERR_UNSUPPORTED: + return "Action not supported."; + case DDERR_UNSUPPORTEDFORMAT: + return "FOURCC format requested is unsupported by DirectDraw."; case DDERR_UNSUPPORTEDMASK: return "Bitmask in the pixel format requested is unsupported by DirectDraw."; - case DDERR_XALIGN: - return "Rectangle provided was not horizontally aligned on required boundary."; + case DDERR_VERTICALBLANKINPROGRESS: + return "Vertical blank is in progress."; case DDERR_WASSTILLDRAWING: return "Informs DirectDraw that the previous Blt which is transfering information to or from this Surface is " "incomplete."; - case DDERR_INVALIDDIRECTDRAWGUID: - return "The GUID passed to DirectDrawCreate is not a valid DirectDraw driver identifier."; - case DDERR_DIRECTDRAWALREADYCREATED: - return "A DirectDraw object representing this driver has already been created for this process."; - case DDERR_NODIRECTDRAWHW: - return "A hardware-only DirectDraw object creation was attempted but the driver did not support any hardware."; - case DDERR_PRIMARYSURFACEALREADYEXISTS: - return "This process already has created a primary surface."; - case DDERR_NOEMULATION: - return "Software emulation not available."; - case DDERR_REGIONTOOSMALL: - return "Region passed to Clipper::GetClipList is too small."; - case DDERR_CLIPPERISUSINGHWND: - return "An attempt was made to set a cliplist for a clipper object that is already monitoring an hwnd."; - case DDERR_NOCLIPPERATTACHED: - return "No clipper object attached to surface object."; - case DDERR_NOHWND: - return "Clipper notification requires an HWND or no HWND has previously been set as the CooperativeLevel HWND."; - case DDERR_HWNDSUBCLASSED: - return "HWND used by DirectDraw CooperativeLevel has been subclassed, this prevents DirectDraw from restoring " - "state."; - case DDERR_HWNDALREADYSET: - return "The CooperativeLevel HWND has already been set. It can not be reset while the process has surfaces or " - "palettes created."; - case DDERR_NOPALETTEATTACHED: - return "No palette object attached to this surface."; - case DDERR_NOPALETTEHW: - return "No hardware support for 16 or 256 color palettes."; - case DDERR_BLTFASTCANTCLIP: - return "Return if a clipper object is attached to the source surface passed into a BltFast call."; - case DDERR_NOBLTHW: - return "No blitter hardware present."; - case DDERR_NODDROPSHW: - return "No DirectDraw ROP hardware."; - case DDERR_OVERLAYNOTVISIBLE: - return "Returned when GetOverlayPosition is called on a hidden overlay."; - case DDERR_NOOVERLAYDEST: - return "Returned when GetOverlayPosition is called on an overlay that UpdateOverlay has never been called on " - "to establish a destination."; - case DDERR_INVALIDPOSITION: - return "Returned when the position of the overlay on the destination is no longer legal for that destination."; - case DDERR_NOTAOVERLAYSURFACE: - return "Returned when an overlay member is called for a non-overlay surface."; - case DDERR_EXCLUSIVEMODEALREADYSET: - return "An attempt was made to set the cooperative level when it was already set to exclusive."; - case DDERR_NOTFLIPPABLE: - return "An attempt has been made to flip a surface that is not flippable."; - case DDERR_CANTDUPLICATE: - return "Can't duplicate primary & 3D surfaces, or surfaces that are implicitly created."; - case DDERR_NOTLOCKED: - return "Surface was not locked. An attempt to unlock a surface that was not locked at all, or by this " - "process, has been attempted."; - case DDERR_CANTCREATEDC: - return "Windows can not create any more DCs."; - case DDERR_NODC: - return "No DC was ever created for this surface."; case DDERR_WRONGMODE: return "This surface can not be restored because it was created in a different mode."; - case DDERR_IMPLICITLYCREATED: - return "This surface can not be restored because it is an implicitly created surface."; - case DDERR_NOTPALETTIZED: - return "The surface being used is not a palette-based surface."; + case DDERR_XALIGN: + return "Rectangle provided was not horizontally aligned on required boundary."; default: return "Unrecognized error value."; } diff --git a/LEGO1/mxdirectx/mxdirectxinfo.h b/LEGO1/mxdirectx/mxdirectxinfo.h index a4ebef91..e3491891 100644 --- a/LEGO1/mxdirectx/mxdirectxinfo.h +++ b/LEGO1/mxdirectx/mxdirectxinfo.h @@ -66,7 +66,7 @@ class MxAssignedDevice { // SIZE 0x1a4 struct Direct3DDeviceInfo { - Direct3DDeviceInfo() {} + Direct3DDeviceInfo(); ~Direct3DDeviceInfo(); Direct3DDeviceInfo( LPGUID p_guid, @@ -115,9 +115,8 @@ struct MxDisplayMode { // SIZE 0x190 struct MxDriver { - MxDriver() {} + MxDriver(); ~MxDriver(); - MxDriver(LPGUID p_guid); MxDriver(LPGUID p_guid, LPCSTR p_driverDesc, LPCSTR p_driverName); void Init(LPGUID p_guid, LPCSTR p_driverDesc, LPCSTR p_driverName); @@ -194,7 +193,7 @@ class MxDeviceEnumerate { MxDeviceEnumerate(); ~MxDeviceEnumerate(); - virtual int DoEnumerate(); // vtable+0x00 + virtual int DoEnumerate(HWND hWnd); // vtable+0x00 BOOL EnumDirectDrawCallback(LPGUID p_guid, LPSTR p_driverDesc, LPSTR p_driverName); HRESULT EnumDevicesCallback( @@ -206,20 +205,19 @@ class MxDeviceEnumerate { ); const char* EnumerateErrorToString(HRESULT p_error); static void BuildErrorString(const char*, ...); - static BOOL CALLBACK - DirectDrawEnumerateCallback(LPGUID p_guid, LPSTR p_driverDesc, LPSTR p_driverName, LPVOID p_context); + static BOOL CALLBACK DirectDrawEnumerateCallback(LPGUID p_guid, LPSTR p_driverDesc, LPSTR p_driverName, LPVOID p_d); static HRESULT CALLBACK DevicesEnumerateCallback( LPGUID p_guid, LPSTR p_deviceDesc, LPSTR p_deviceName, LPD3DDEVICEDESC p_HWDesc, LPD3DDEVICEDESC p_HELDesc, - LPVOID p_context + LPVOID p_d ); friend class MxDirect3D; - - const list& GetDriverList() const { return m_list; } + friend class CConfigApp; + friend class CMainDialog; // SIZE 0x10 struct GUID4 { @@ -240,8 +238,9 @@ class MxDeviceEnumerate { unsigned char IsInitialized() const { return m_initialized; } protected: - list m_list; // 0x04 + list m_ddInfo; // 0x04 unsigned char m_initialized; // 0x10 + HWND m_hWnd; }; // TEMPLATE: BETA10 0x1011c1b0 diff --git a/LEGO1/omni/include/mxaudiomanager.h b/LEGO1/omni/include/mxaudiomanager.h index f962a16d..bab1f553 100644 --- a/LEGO1/omni/include/mxaudiomanager.h +++ b/LEGO1/omni/include/mxaudiomanager.h @@ -2,11 +2,12 @@ #define MXAUDIOMANAGER_H #include "decomp.h" -#include "mxmediamanager.h" +#include "mxpresentationmanager.h" // VTABLE: LEGO1 0x100dc6e0 +// VTABLE: BETA10 0x101c2348 // SIZE 0x30 -class MxAudioManager : public MxMediaManager { +class MxAudioManager : public MxPresentationManager { public: MxAudioManager(); ~MxAudioManager() override; @@ -15,11 +16,13 @@ class MxAudioManager : public MxMediaManager { void Destroy() override; // vtable+18 // FUNCTION: LEGO1 0x10029910 + // FUNCTION: BETA10 0x100d0630 virtual MxS32 GetVolume() { return m_volume; } // vtable+28 virtual void SetVolume(MxS32 p_volume); // vtable+2c // SYNTHETIC: LEGO1 0x100b8d70 + // SYNTHETIC: BETA10 0x10145110 // MxAudioManager::`scalar deleting destructor' private: diff --git a/LEGO1/omni/include/mxautolock.h b/LEGO1/omni/include/mxautolock.h index 8a2b3c35..6a26ba47 100644 --- a/LEGO1/omni/include/mxautolock.h +++ b/LEGO1/omni/include/mxautolock.h @@ -3,15 +3,27 @@ class MxCriticalSection; +#ifdef BETA10 +#define AUTOLOCK(CS) MxAutoLock lock(&CS, __FILE__, __LINE__) +#else #define AUTOLOCK(CS) MxAutoLock lock(&CS) +#endif class MxAutoLock { public: +#ifdef BETA10 + MxAutoLock(MxCriticalSection* p_criticalSection, const char* filename, int line); +#else MxAutoLock(MxCriticalSection* p_criticalSection); +#endif ~MxAutoLock(); private: MxCriticalSection* m_criticalSection; // 0x00 + +#ifdef BETA10 + unsigned long m_currentThreadId; // 0x04 +#endif }; #endif // MXAUTOLOCK_H diff --git a/LEGO1/omni/include/mxcriticalsection.h b/LEGO1/omni/include/mxcriticalsection.h index 9a5c85b6..81767fd9 100644 --- a/LEGO1/omni/include/mxcriticalsection.h +++ b/LEGO1/omni/include/mxcriticalsection.h @@ -11,7 +11,11 @@ class MxCriticalSection { static void SetDoMutex(); +#ifdef BETA10 + void Enter(unsigned long p_threadId, const char* filename, int line); +#else void Enter(); +#endif void Leave(); private: @@ -22,4 +26,11 @@ class MxCriticalSection { SDL_Mutex* m_mutex; }; +#ifdef BETA10 +// TODO: Not quite correct yet, the second argument becomes a relocated value +#define ENTER(criticalSection) criticalSection.Enter(-1, NULL, 0) +#else +#define ENTER(criticalSection) criticalSection.Enter() +#endif + #endif // MXCRITICALSECTION_H diff --git a/LEGO1/omni/include/mxdisplaysurface.h b/LEGO1/omni/include/mxdisplaysurface.h index 8d31ff4f..aa30b543 100644 --- a/LEGO1/omni/include/mxdisplaysurface.h +++ b/LEGO1/omni/include/mxdisplaysurface.h @@ -1,6 +1,7 @@ #ifndef MXDISPLAYSURFACE_H #define MXDISPLAYSURFACE_H +#include "cursor.h" #include "decomp.h" #include "mxcore.h" #include "mxvideoparam.h" @@ -11,6 +12,9 @@ #include #endif +#define RGB555_CREATE(R, G, B) (((R) << 10) | (G) << 5 | (B) << 0) +#define RGB8888_CREATE(R, G, B, A) (((A) << 24) | ((R) << 16) | ((G) << 8) | (B)) + class MxBitmap; class MxPalette; @@ -70,14 +74,6 @@ class MxDisplaySurface : public MxCore { MxS32 p_height, MxBool p_RLE ); // vtable+0x30 - virtual void VTable0x34( - MxU8* p_pixels, - MxS32 p_bpp, - MxS32 p_width, - MxS32 p_height, - MxS32 p_x, - MxS32 p_y - ); // vtable+0x34 virtual void Display( MxS32 p_left, MxS32 p_top, @@ -96,7 +92,7 @@ class MxDisplaySurface : public MxCore { ); // vtable+0x44 void ClearScreen(); - static LPDIRECTDRAWSURFACE CreateCursorSurface(); + static LPDIRECTDRAWSURFACE CreateCursorSurface(const CursorBitmap* p_cursorBitmap); static LPDIRECTDRAWSURFACE CopySurface(LPDIRECTDRAWSURFACE p_src); LPDIRECTDRAWSURFACE GetDirectDrawSurface1() { return m_ddSurface1; } diff --git a/LEGO1/omni/include/mxdsaction.h b/LEGO1/omni/include/mxdsaction.h index f82c2237..8dbccf46 100644 --- a/LEGO1/omni/include/mxdsaction.h +++ b/LEGO1/omni/include/mxdsaction.h @@ -56,8 +56,8 @@ class MxDSAction : public MxDSObject { virtual MxDSAction* Clone(); // vtable+0x2c virtual void MergeFrom(MxDSAction& p_dsAction); // vtable+0x30 virtual MxBool HasId(MxU32 p_objectId); // vtable+0x34 - virtual void SetUnknown90(MxLong p_unk0x90); // vtable+0x38 - virtual MxLong GetUnknown90(); // vtable+0x3c + virtual void SetTimeStarted(MxLong p_timeStarted); // vtable+0x38 + virtual MxLong GetTimeStarted(); // vtable+0x3c virtual MxLong GetElapsedTime(); // vtable+0x40 void AppendExtra(MxU16 p_extraLength, const char* p_extraData); @@ -131,7 +131,7 @@ class MxDSAction : public MxDSObject { MxCore* m_notificationObject; // 0x84 undefined4 m_unk0x88; // 0x88 MxCore* m_origin; // 0x8c - MxLong m_unk0x90; // 0x90 + MxLong m_timeStarted; // 0x90 }; #endif // MXDSACTION_H diff --git a/LEGO1/omni/include/mxdsmultiaction.h b/LEGO1/omni/include/mxdsmultiaction.h index 90cc5192..77ae8d67 100644 --- a/LEGO1/omni/include/mxdsmultiaction.h +++ b/LEGO1/omni/include/mxdsmultiaction.h @@ -38,7 +38,7 @@ class MxDSMultiAction : public MxDSAction { MxDSAction* Clone() override; // vtable+0x2c void MergeFrom(MxDSAction& p_dsAction) override; // vtable+0x30 MxBool HasId(MxU32 p_objectId) override; // vtable+0x34 - void SetUnknown90(MxLong p_unk0x90) override; // vtable+0x38 + void SetTimeStarted(MxLong p_timeStarted) override; // vtable+0x38 // FUNCTION: BETA10 0x1004e180 MxDSActionList* GetActionList() const { return m_actionList; } diff --git a/LEGO1/omni/include/mxeventmanager.h b/LEGO1/omni/include/mxeventmanager.h index b23a2ad0..f17f886d 100644 --- a/LEGO1/omni/include/mxeventmanager.h +++ b/LEGO1/omni/include/mxeventmanager.h @@ -2,11 +2,11 @@ #define MXEVENTMANAGER_H #include "decomp.h" -#include "mxmediamanager.h" +#include "mxpresentationmanager.h" // VTABLE: LEGO1 0x100dc900 // SIZE 0x2c -class MxEventManager : public MxMediaManager { +class MxEventManager : public MxPresentationManager { public: MxEventManager(); ~MxEventManager() override; diff --git a/LEGO1/omni/include/mxlist.h b/LEGO1/omni/include/mxlist.h index 6d46cb2a..3fe72d0f 100644 --- a/LEGO1/omni/include/mxlist.h +++ b/LEGO1/omni/include/mxlist.h @@ -254,11 +254,11 @@ inline MxBool MxListCursor::Next() template inline MxBool MxListCursor::Next(T& p_obj) { - if (!m_match) { - m_match = m_list->m_first; + if (m_match) { + m_match = m_match->GetNext(); } else { - m_match = m_match->GetNext(); + m_match = m_list->m_first; } if (m_match) { diff --git a/LEGO1/omni/include/mxmediamanager.h b/LEGO1/omni/include/mxpresentationmanager.h similarity index 71% rename from LEGO1/omni/include/mxmediamanager.h rename to LEGO1/omni/include/mxpresentationmanager.h index 38f611eb..f0740e6e 100644 --- a/LEGO1/omni/include/mxmediamanager.h +++ b/LEGO1/omni/include/mxpresentationmanager.h @@ -1,5 +1,5 @@ -#ifndef MXMEDIAMANGER_H -#define MXMEDIAMANGER_H +#ifndef MXPRESENTATIONMANAGER_H +#define MXPRESENTATIONMANAGER_H #include "mxcore.h" #include "mxcriticalsection.h" @@ -9,11 +9,12 @@ class MxThread; // VTABLE: LEGO1 0x100dc6b0 +// VTABLE: BETA10 0x101c2318 // SIZE 0x2c -class MxMediaManager : public MxCore { +class MxPresentationManager : public MxCore { public: - MxMediaManager(); - ~MxMediaManager() override; + MxPresentationManager(); + ~MxPresentationManager() override; MxResult Tickle() override; // vtable+08 virtual MxResult Create(); // vtable+14 @@ -25,7 +26,8 @@ class MxMediaManager : public MxCore { MxResult Init(); // SYNTHETIC: LEGO1 0x100b8540 - // MxMediaManager::`scalar deleting destructor' + // SYNTHETIC: BETA10 0x10144db0 + // MxPresentationManager::`scalar deleting destructor' protected: MxPresenterList* m_presenters; // 0x08 @@ -33,4 +35,4 @@ class MxMediaManager : public MxCore { MxCriticalSection m_criticalSection; // 0x10 }; -#endif // MXMEDIAMANGER_H +#endif // MXPRESENTATIONMANAGER_H diff --git a/LEGO1/omni/include/mxpresenterlist.h b/LEGO1/omni/include/mxpresenterlist.h index 0e8bd316..7d3000cc 100644 --- a/LEGO1/omni/include/mxpresenterlist.h +++ b/LEGO1/omni/include/mxpresenterlist.h @@ -5,12 +5,15 @@ #include "mxpresenter.h" // VTABLE: LEGO1 0x100d62f0 +// VTABLE: BETA10 0x101bf070 // class MxPtrList // VTABLE: LEGO1 0x100d6308 +// VTABLE: BETA10 0x101bf050 // SIZE 0x18 class MxPresenterList : public MxPtrList { public: + // FUNCTION: BETA10 0x100dc900 MxPresenterList(MxBool p_ownership = FALSE) : MxPtrList(p_ownership) {} // FUNCTION: LEGO1 0x1001cd00 @@ -35,6 +38,13 @@ class MxPresenterListCursor : public MxPtrListCursor { public: // FUNCTION: BETA10 0x1007d130 MxPresenterListCursor(MxPresenterList* p_list) : MxPtrListCursor(p_list) {} + + // SYNTHETIC: LEGO1 0x1001eed0 + // MxPresenterListCursor::`scalar deleting destructor' + + // SYNTHETIC: LEGO1 0x1001f0c0 + // SYNTHETIC: BETA10 0x1007d510 + // MxPresenterListCursor::~MxPresenterListCursor }; // VTABLE: LEGO1 0x100d6350 @@ -58,7 +68,11 @@ class MxPresenterListCursor : public MxPtrListCursor { // TEMPLATE: LEGO1 0x1001ce20 // MxList::~MxList +// TEMPLATE: BETA10 0x100dc9f0 +// MxPtrList::MxPtrList + // TEMPLATE: LEGO1 0x1001cf20 +// TEMPLATE: BETA10 0x100dce70 // MxPtrList::~MxPtrList // SYNTHETIC: LEGO1 0x1001cf70 @@ -73,10 +87,8 @@ class MxPresenterListCursor : public MxPtrListCursor { // SYNTHETIC: LEGO1 0x1001d100 // MxPresenterList::~MxPresenterList -// SYNTHETIC: LEGO1 0x1001eed0 -// MxPresenterListCursor::`scalar deleting destructor' - // TEMPLATE: LEGO1 0x1001ef40 +// TEMPLATE: BETA10 0x1007d370 // MxPtrListCursor::~MxPtrListCursor // SYNTHETIC: LEGO1 0x1001ef90 @@ -86,11 +98,9 @@ class MxPresenterListCursor : public MxPtrListCursor { // MxPtrListCursor::`scalar deleting destructor' // TEMPLATE: LEGO1 0x1001f070 +// TEMPLATE: BETA10 0x1007d490 // MxListCursor::~MxListCursor -// FUNCTION: LEGO1 0x1001f0c0 -// MxPresenterListCursor::~MxPresenterListCursor - // TEMPLATE: LEGO1 0x10020760 // MxListCursor::MxListCursor @@ -106,6 +116,18 @@ class MxPresenterListCursor : public MxPtrListCursor { // TEMPLATE: BETA10 0x1007d270 // MxListCursor::MxListCursor +// TEMPLATE: BETA10 0x1007dc60 +// MxListCursor::Next + +// TEMPLATE: BETA10 0x100d8f20 +// MxListCursor::Reset + +// TEMPLATE: BETA10 0x1007e070 +// MxListEntry::GetNext + +// TEMPLATE: BETA10 0x1007e0a0 +// MxListEntry::GetValue + // TEMPLATE: BETA10 0x100d9420 // ?Prev@?$MxListCursor@PAVMxPresenter@@@@QAEEAAPAVMxPresenter@@@Z diff --git a/LEGO1/omni/include/mxsemaphore.h b/LEGO1/omni/include/mxsemaphore.h index 1d43009a..fd8b60b0 100644 --- a/LEGO1/omni/include/mxsemaphore.h +++ b/LEGO1/omni/include/mxsemaphore.h @@ -6,17 +6,20 @@ #include // VTABLE: LEGO1 0x100dccf0 +// VTABLE: BETA10 0x101c28ac // SIZE 0x08 class MxSemaphore { public: MxSemaphore(); // FUNCTION: LEGO1 0x100c87e0 + // FUNCTION: BETA10 0x101592a9 ~MxSemaphore() { SDL_DestroySemaphore(m_semaphore); } virtual MxResult Init(MxU32 p_initialCount, MxU32 p_maxCount); - void Wait(); + void Acquire(); + void TryAcquire(); void Release(); private: diff --git a/LEGO1/omni/include/mxsoundmanager.h b/LEGO1/omni/include/mxsoundmanager.h index 062d3839..569a7ff1 100644 --- a/LEGO1/omni/include/mxsoundmanager.h +++ b/LEGO1/omni/include/mxsoundmanager.h @@ -26,7 +26,11 @@ class MxSoundManager : public MxAudioManager { float GetAttenuation(MxU32 p_volume); - MxPresenter* FUN_100aebd0(const MxAtomId& p_atomId, MxU32 p_objectId); + MxPresenter* FindPresenter(const MxAtomId& p_atomId, MxU32 p_objectId); + + // SYNTHETIC: LEGO1 0x100ae7b0 + // SYNTHETIC: BETA10 0x10133460 + // MxSoundManager::`scalar deleting destructor' protected: void Init(); @@ -49,7 +53,4 @@ class MxSoundManager : public MxAudioManager { undefined m_unk0x38[4]; }; -// SYNTHETIC: LEGO1 0x100ae7b0 -// MxSoundManager::`scalar deleting destructor' - #endif // MXSOUNDMANAGER_H diff --git a/LEGO1/omni/include/mxstring.h b/LEGO1/omni/include/mxstring.h index eaa58181..b4b25262 100644 --- a/LEGO1/omni/include/mxstring.h +++ b/LEGO1/omni/include/mxstring.h @@ -20,10 +20,10 @@ class MxString : public MxCore { void ToLowerCase(); void MapPathToFilesystem() { MapPathToFilesystem(m_data); } - MxString& operator=(const MxString& p_str); - const MxString& operator=(const char* p_str); - MxString operator+(const MxString& p_str) const; - MxString operator+(const char* p_str) const; + LEGO1_EXPORT MxString& operator=(const MxString& p_str); + LEGO1_EXPORT const MxString& operator=(const char* p_str); + LEGO1_EXPORT MxString operator+(const MxString& p_str) const; + LEGO1_EXPORT MxString operator+(const char* p_str) const; LEGO1_EXPORT MxString& operator+=(const char* p_str); static void CharSwap(char* p_a, char* p_b); diff --git a/LEGO1/omni/include/mxthread.h b/LEGO1/omni/include/mxthread.h index 8afa4454..0772dc65 100644 --- a/LEGO1/omni/include/mxthread.h +++ b/LEGO1/omni/include/mxthread.h @@ -10,6 +10,7 @@ class MxCore; // VTABLE: LEGO1 0x100dc860 +// VTABLE: BETA10 0x101c23e8 // SIZE 0x1c class MxThread { public: @@ -21,9 +22,16 @@ class MxThread { void Terminate(); void Sleep(MxS32 p_milliseconds); + void ResumeThread(); + void SuspendThread(); + bool TerminateThread(MxU32 p_exitCode); + MxS32 GetThreadPriority(MxU16& p_priority); + bool SetThreadPriority(MxU16 p_priority); + MxBool IsRunning() { return m_running; } // SYNTHETIC: LEGO1 0x100bf580 + // SYNTHETIC: BETA10 0x10147880 // MxThread::`scalar deleting destructor' protected: diff --git a/LEGO1/omni/include/mxutilities.h b/LEGO1/omni/include/mxutilities.h index c68d4201..7ea9fed5 100644 --- a/LEGO1/omni/include/mxutilities.h +++ b/LEGO1/omni/include/mxutilities.h @@ -10,6 +10,7 @@ struct LegoSdlEvents { Uint32 m_windowsMessage; Uint32 m_presenterProgress; + Uint32 m_gameEvent; }; LEGO1_EXPORT extern LegoSdlEvents g_legoSdlEvents; @@ -92,7 +93,7 @@ void MakeSourceName(char*, const char*); void OmniError(const char* p_message, MxS32 p_status); void SetOmniUserMessage(void (*p_omniUserMessage)(const char*, MxS32)); MxBool ContainsPresenter(MxCompositePresenterList& p_presenterList, MxPresenter* p_presenter); -void FUN_100b7220(MxDSAction* p_action, MxU32 p_newFlags, MxBool p_setFlags); +void ApplyMask(MxDSAction* p_action, MxU32 p_mask, MxBool p_setFlags); MxBool KeyValueStringParse(char*, const char*, const char*); // TEMPLATE: BETA10 0x1012dfd0 diff --git a/LEGO1/omni/include/mxvariable.h b/LEGO1/omni/include/mxvariable.h index 8949833f..9eda281f 100644 --- a/LEGO1/omni/include/mxvariable.h +++ b/LEGO1/omni/include/mxvariable.h @@ -9,6 +9,7 @@ // SIZE 0x24 class MxVariable { public: + // FUNCTION: BETA10 0x1007b750 MxVariable() {} // FUNCTION: BETA10 0x1012a840 @@ -41,12 +42,16 @@ class MxVariable { // FUNCTION: BETA10 0x1012a7f0 const MxString* GetKey() const { return &m_key; } + // SYNTHETIC: BETA10 0x1007b8c0 + // MxVariable::`scalar deleting destructor' + protected: MxString m_key; // 0x04 MxString m_value; // 0x14 }; // SYNTHETIC: LEGO1 0x1003bf40 +// SYNTHETIC: BETA10 0x1007b910 // MxVariable::~MxVariable #endif // MXVARIABLE_H diff --git a/LEGO1/omni/include/mxvideomanager.h b/LEGO1/omni/include/mxvideomanager.h index 5826cb64..08632f74 100644 --- a/LEGO1/omni/include/mxvideomanager.h +++ b/LEGO1/omni/include/mxvideomanager.h @@ -1,7 +1,7 @@ #ifndef MXVIDEOMANAGER_H #define MXVIDEOMANAGER_H -#include "mxmediamanager.h" +#include "mxpresentationmanager.h" #include "mxvideoparam.h" #ifdef MINIWIN @@ -15,8 +15,9 @@ class MxRect32; class MxRegion; // VTABLE: LEGO1 0x100dc810 +// VTABLE: BETA10 0x101c1bf8 // SIZE 0x64 -class MxVideoManager : public MxMediaManager { +class MxVideoManager : public MxPresentationManager { public: MxVideoManager(); ~MxVideoManager() override; @@ -45,10 +46,14 @@ class MxVideoManager : public MxMediaManager { MxVideoParam& GetVideoParam() { return this->m_videoParam; } LPDIRECTDRAW GetDirectDraw() { return this->m_pDirectDraw; } + + // FUNCTION: BETA10 0x1002e290 MxDisplaySurface* GetDisplaySurface() { return this->m_displaySurface; } + MxRegion* GetRegion() { return this->m_region; } // SYNTHETIC: LEGO1 0x100be280 + // SYNTHETIC: BETA10 0x1012de00 // MxVideoManager::`scalar deleting destructor' protected: diff --git a/LEGO1/omni/include/mxvideoparam.h b/LEGO1/omni/include/mxvideoparam.h index ccc073ab..cd425ba9 100644 --- a/LEGO1/omni/include/mxvideoparam.h +++ b/LEGO1/omni/include/mxvideoparam.h @@ -15,6 +15,8 @@ class MxPalette; +#define ISLE_PROP_WINDOW_CREATE_VIDEO_PARAM "ISLE.window.create.videoParam" + // SIZE 0x24 class MxVideoParam { public: @@ -51,6 +53,12 @@ class MxVideoParam { // FUNCTION: BETA10 0x10141fe0 void SetBackBuffers(MxU32 p_backBuffers) { m_backBuffers = p_backBuffers; } + void SetMSAASamples(MxU32 p_msaaSamples) { m_msaaSamples = p_msaaSamples; } + MxU32 GetMSAASamples() { return m_msaaSamples; } + + void SetAnisotropic(MxFloat p_anisotropic) { m_anisotropic = p_anisotropic; } + MxFloat GetAnisotropic() { return m_anisotropic; } + private: MxRect32 m_rect; // 0x00 MxPalette* m_palette; // 0x10 @@ -58,6 +66,8 @@ class MxVideoParam { MxVideoParamFlags m_flags; // 0x18 int m_unk0x1c; // 0x1c char* m_deviceId; // 0x20 + MxU32 m_msaaSamples; + MxFloat m_anisotropic; }; #endif // MXVIDEOPARAM_H diff --git a/LEGO1/omni/include/mxvideoparamflags.h b/LEGO1/omni/include/mxvideoparamflags.h index 4fef2145..6158c4d7 100644 --- a/LEGO1/omni/include/mxvideoparamflags.h +++ b/LEGO1/omni/include/mxvideoparamflags.h @@ -24,7 +24,7 @@ class MxVideoParamFlags { void SetBackBuffers(MxBool p_e) { m_flags1.m_bit2 = p_e; } // FUNCTION: BETA10 0x100d9250 - void SetF1bit3(MxBool p_e) { m_flags1.m_bit3 = p_e; } + void SetDoubleScaling(MxBool p_e) { m_flags1.m_bit3 = p_e; } // inlined in ISLE void Set16Bit(MxBool p_e) { m_flags1.m_bit5 = p_e; } @@ -39,7 +39,7 @@ class MxVideoParamFlags { void SetLacksLightSupport(MxBool p_e) { m_flags2.m_bit0 = p_e; } // inlined in ISLE - void SetF2bit1(MxBool p_e) { m_flags2.m_bit1 = p_e; } + void SetEnabled(MxBool p_e) { m_flags2.m_bit1 = p_e; } // FUNCTION: BETA10 0x1009e770 MxBool GetFullScreen() { return m_flags1.m_bit0; } @@ -51,7 +51,7 @@ class MxVideoParamFlags { MxBool GetBackBuffers() { return m_flags1.m_bit2; } // FUNCTION: BETA10 0x10142010 - MxBool GetF1bit3() { return m_flags1.m_bit3; } + MxBool GetDoubleScaling() { return m_flags1.m_bit3; } // FUNCTION: BETA10 0x100d8150 MxBool Get16Bit() { return m_flags1.m_bit5; } @@ -63,7 +63,7 @@ class MxVideoParamFlags { MxBool GetLacksLightSupport() { return m_flags2.m_bit0; } // FUNCTION: BETA10 0x10142050 - MxBool GetF2bit1() { return m_flags2.m_bit1; } + MxBool GetEnabled() { return m_flags2.m_bit1; } private: FlagBitfield m_flags1; diff --git a/LEGO1/omni/src/action/mxdsaction.cpp b/LEGO1/omni/src/action/mxdsaction.cpp index cd422d0d..aa92b9af 100644 --- a/LEGO1/omni/src/action/mxdsaction.cpp +++ b/LEGO1/omni/src/action/mxdsaction.cpp @@ -31,7 +31,7 @@ MxDSAction::MxDSAction() m_notificationObject = NULL; m_unk0x88 = 0; m_origin = NULL; - m_unk0x90 = INT_MIN; + m_timeStarted = INT_MIN; } // FUNCTION: LEGO1 0x100ad940 @@ -57,16 +57,16 @@ MxBool MxDSAction::HasId(MxU32 p_objectId) // FUNCTION: LEGO1 0x100ada40 // FUNCTION: BETA10 0x1012bdf0 -void MxDSAction::SetUnknown90(MxLong p_unk0x90) +void MxDSAction::SetTimeStarted(MxLong p_timeStarted) { - m_unk0x90 = p_unk0x90; + m_timeStarted = p_timeStarted; } // FUNCTION: LEGO1 0x100ada50 // FUNCTION: BETA10 0x1012be20 -MxLong MxDSAction::GetUnknown90() +MxLong MxDSAction::GetTimeStarted() { - return m_unk0x90; + return m_timeStarted; } // FUNCTION: LEGO1 0x100ada80 @@ -92,7 +92,7 @@ void MxDSAction::CopyFrom(MxDSAction& p_dsAction) m_notificationObject = p_dsAction.m_notificationObject; m_unk0x88 = p_dsAction.m_unk0x88; m_origin = p_dsAction.m_origin; - m_unk0x90 = p_dsAction.m_unk0x90; + m_timeStarted = p_dsAction.m_timeStarted; } // FUNCTION: BETA10 0x1012b2b3 @@ -158,7 +158,7 @@ MxDSAction* MxDSAction::Clone() // FUNCTION: BETA10 0x1012b4ca MxLong MxDSAction::GetElapsedTime() { - return Timer()->GetTime() - m_unk0x90; + return Timer()->GetTime() - m_timeStarted; } // FUNCTION: LEGO1 0x100add00 diff --git a/LEGO1/omni/src/action/mxdsmultiaction.cpp b/LEGO1/omni/src/action/mxdsmultiaction.cpp index 452bbee5..fdd493cb 100644 --- a/LEGO1/omni/src/action/mxdsmultiaction.cpp +++ b/LEGO1/omni/src/action/mxdsmultiaction.cpp @@ -59,14 +59,14 @@ MxDSMultiAction& MxDSMultiAction::operator=(MxDSMultiAction& p_dsMultiAction) // FUNCTION: LEGO1 0x100ca290 // FUNCTION: BETA10 0x10159728 -void MxDSMultiAction::SetUnknown90(MxLong p_unk0x90) +void MxDSMultiAction::SetTimeStarted(MxLong p_timeStarted) { - m_unk0x90 = p_unk0x90; + m_timeStarted = p_timeStarted; MxDSActionListCursor cursor(m_actionList); MxDSAction* action; while (cursor.Next(action)) { - action->SetUnknown90(p_unk0x90); + action->SetTimeStarted(p_timeStarted); } } diff --git a/LEGO1/omni/src/audio/mxaudiomanager.cpp b/LEGO1/omni/src/audio/mxaudiomanager.cpp index 81b8922e..3cef829a 100644 --- a/LEGO1/omni/src/audio/mxaudiomanager.cpp +++ b/LEGO1/omni/src/audio/mxaudiomanager.cpp @@ -3,47 +3,84 @@ DECOMP_SIZE_ASSERT(MxAudioManager, 0x30); // GLOBAL: LEGO1 0x10102108 +// GLOBAL: BETA10 0x10203a60 MxS32 MxAudioManager::g_count = 0; // FUNCTION: LEGO1 0x100b8d00 +// FUNCTION: BETA10 0x10144e90 MxAudioManager::MxAudioManager() { Init(); } // FUNCTION: LEGO1 0x100b8d90 +// STUB: BETA10 0x10144f07 MxAudioManager::~MxAudioManager() { Destroy(TRUE); } // FUNCTION: LEGO1 0x100b8df0 +// FUNCTION: BETA10 0x10144f79 void MxAudioManager::Init() { m_volume = 100; } // FUNCTION: LEGO1 0x100b8e00 +// FUNCTION: BETA10 0x10144f9c void MxAudioManager::Destroy(MxBool p_fromDestructor) { - m_criticalSection.Enter(); + ENTER(m_criticalSection); g_count--; Init(); m_criticalSection.Leave(); if (!p_fromDestructor) { - MxMediaManager::Destroy(); + MxPresentationManager::Destroy(); } } +#ifdef BETA10 +// FUNCTION: BETA10 0x10144ffe +MxResult MxAudioManager::Create() +{ + MxResult result = FAILURE; + MxBool success = FALSE; + + if (MxPresentationManager::Create() != SUCCESS) { + goto exit; + } + + ENTER(m_criticalSection); + success = TRUE; + + if (!g_count++) { + // This is correct. It was likely refactored later. + } + +exit: + result = SUCCESS; + + if (result) { + Destroy(); + } + + if (success) { + m_criticalSection.Leave(); + } + + return result; +} +#else // FUNCTION: LEGO1 0x100b8e40 MxResult MxAudioManager::Create() { MxResult result = FAILURE; MxBool success = FALSE; - if (MxMediaManager::Create() == SUCCESS) { - m_criticalSection.Enter(); + if (MxPresentationManager::Create() == SUCCESS) { + ENTER(m_criticalSection); success = TRUE; result = SUCCESS; g_count++; @@ -59,17 +96,20 @@ MxResult MxAudioManager::Create() return result; } +#endif // FUNCTION: LEGO1 0x100b8e90 +// FUNCTION: BETA10 0x101450a7 void MxAudioManager::Destroy() { Destroy(FALSE); } // FUNCTION: LEGO1 0x100b8ea0 +// FUNCTION: BETA10 0x101450c7 void MxAudioManager::SetVolume(MxS32 p_volume) { - m_criticalSection.Enter(); + ENTER(m_criticalSection); m_volume = p_volume; m_criticalSection.Leave(); } diff --git a/LEGO1/omni/src/audio/mxsoundmanager.cpp b/LEGO1/omni/src/audio/mxsoundmanager.cpp index f865ebf0..dab79698 100644 --- a/LEGO1/omni/src/audio/mxsoundmanager.cpp +++ b/LEGO1/omni/src/audio/mxsoundmanager.cpp @@ -25,18 +25,21 @@ MxS32 g_volumeAttenuation[100] = {-6643, -5643, -5058, -4643, -4321, -4058, -383 -43, -29, -14, 0}; // FUNCTION: LEGO1 0x100ae740 +// FUNCTION: BETA10 0x10132c70 MxSoundManager::MxSoundManager() { Init(); } // FUNCTION: LEGO1 0x100ae7d0 +// FUNCTION: BETA10 0x10132ce7 MxSoundManager::~MxSoundManager() { Destroy(TRUE); } // FUNCTION: LEGO1 0x100ae830 +// FUNCTION: BETA10 0x10132d59 void MxSoundManager::Init() { SDL_zero(m_engine); @@ -44,6 +47,7 @@ void MxSoundManager::Init() } // FUNCTION: LEGO1 0x100ae840 +// FUNCTION: BETA10 0x10132d89 void MxSoundManager::Destroy(MxBool p_fromDestructor) { if (m_thread) { @@ -54,7 +58,7 @@ void MxSoundManager::Destroy(MxBool p_fromDestructor) TickleManager()->UnregisterClient(this); } - m_criticalSection.Enter(); + ENTER(m_criticalSection); if (m_stream) { SDL_DestroyAudioStream(m_stream); @@ -82,7 +86,7 @@ MxResult MxSoundManager::Create(MxU32 p_frequencyMS, MxBool p_createThread) goto done; } - m_criticalSection.Enter(); + ENTER(m_criticalSection); locked = TRUE; engineConfig = ma_engine_config_init(); @@ -157,17 +161,19 @@ void MxSoundManager::AudioStreamCallback( } // FUNCTION: LEGO1 0x100aeab0 +// FUNCTION: BETA10 0x101331e3 void MxSoundManager::Destroy() { Destroy(FALSE); } // FUNCTION: LEGO1 0x100aeac0 +// FUNCTION: BETA10 0x10133203 void MxSoundManager::SetVolume(MxS32 p_volume) { MxAudioManager::SetVolume(p_volume); - m_criticalSection.Enter(); + ENTER(m_criticalSection); MxPresenter* presenter; MxPresenterListCursor cursor(m_presenters); @@ -180,7 +186,8 @@ void MxSoundManager::SetVolume(MxS32 p_volume) } // FUNCTION: LEGO1 0x100aebd0 -MxPresenter* MxSoundManager::FUN_100aebd0(const MxAtomId& p_atomId, MxU32 p_objectId) +// FUNCTION: BETA10 0x101332cf +MxPresenter* MxSoundManager::FindPresenter(const MxAtomId& p_atomId, MxU32 p_objectId) { AUTOLOCK(m_criticalSection); @@ -188,8 +195,7 @@ MxPresenter* MxSoundManager::FUN_100aebd0(const MxAtomId& p_atomId, MxU32 p_obje MxPresenterListCursor cursor(m_presenters); while (cursor.Next(presenter)) { - if (presenter->GetAction()->GetAtomId().GetInternal() == p_atomId.GetInternal() && - presenter->GetAction()->GetObjectId() == p_objectId) { + if (presenter->GetAction()->GetAtomId() == p_atomId && presenter->GetAction()->GetObjectId() == p_objectId) { return presenter; } } diff --git a/LEGO1/omni/src/audio/mxsoundpresenter.cpp b/LEGO1/omni/src/audio/mxsoundpresenter.cpp index 9d784532..3fa2cfaa 100644 --- a/LEGO1/omni/src/audio/mxsoundpresenter.cpp +++ b/LEGO1/omni/src/audio/mxsoundpresenter.cpp @@ -13,7 +13,7 @@ void MxSoundPresenter::Destroy(MxBool p_fromDestructor) MSoundManager()->UnregisterPresenter(*this); } - m_criticalSection.Enter(); + ENTER(m_criticalSection); MxMediaPresenter::Init(); m_criticalSection.Leave(); diff --git a/LEGO1/omni/src/audio/mxwavepresenter.cpp b/LEGO1/omni/src/audio/mxwavepresenter.cpp index 600d9b37..8601f44b 100644 --- a/LEGO1/omni/src/audio/mxwavepresenter.cpp +++ b/LEGO1/omni/src/audio/mxwavepresenter.cpp @@ -289,7 +289,7 @@ void MxWavePresenter::EndAction() // FUNCTION: LEGO1 0x100b2300 void MxWavePresenter::SetVolume(MxS32 p_volume) { - m_criticalSection.Enter(); + ENTER(m_criticalSection); m_volume = p_volume; if (m_sound) { diff --git a/LEGO1/omni/src/common/mxcompositepresenter.cpp b/LEGO1/omni/src/common/mxcompositepresenter.cpp index 4e83d86c..b3d56875 100644 --- a/LEGO1/omni/src/common/mxcompositepresenter.cpp +++ b/LEGO1/omni/src/common/mxcompositepresenter.cpp @@ -25,7 +25,7 @@ MxCompositePresenter::~MxCompositePresenter() } // FUNCTION: LEGO1 0x100b6410 -// FUNCTION: BETA10 0x100e9d37 +// FUNCTION: BETA10 0x10137344 MxResult MxCompositePresenter::StartAction(MxStreamController* p_controller, MxDSAction* p_action) { AUTOLOCK(m_criticalSection); diff --git a/LEGO1/omni/src/common/mxmediapresenter.cpp b/LEGO1/omni/src/common/mxmediapresenter.cpp index 0a1b96d9..11621f71 100644 --- a/LEGO1/omni/src/common/mxmediapresenter.cpp +++ b/LEGO1/omni/src/common/mxmediapresenter.cpp @@ -131,6 +131,7 @@ MxResult MxMediaPresenter::StartAction(MxStreamController* p_controller, MxDSAct } // FUNCTION: LEGO1 0x100b5bc0 +// STUB: BETA10 0x1013623c void MxMediaPresenter::EndAction() { AUTOLOCK(m_criticalSection); @@ -252,7 +253,7 @@ void MxMediaPresenter::Enable(MxBool p_enable) if (p_enable) { MxLong time = Timer()->GetTime(); - m_action->SetUnknown90(time); + m_action->SetTimeStarted(time); SetTickleState(e_repeating); } else { diff --git a/LEGO1/omni/src/common/mxmediamanager.cpp b/LEGO1/omni/src/common/mxpresentationmanager.cpp similarity index 62% rename from LEGO1/omni/src/common/mxmediamanager.cpp rename to LEGO1/omni/src/common/mxpresentationmanager.cpp index cc1611ae..6ef8448e 100644 --- a/LEGO1/omni/src/common/mxmediamanager.cpp +++ b/LEGO1/omni/src/common/mxpresentationmanager.cpp @@ -1,4 +1,4 @@ -#include "mxmediamanager.h" +#include "mxpresentationmanager.h" #include "decomp.h" #include "mxautolock.h" @@ -6,24 +6,27 @@ #include "mxpresenter.h" #include "mxticklemanager.h" -DECOMP_SIZE_ASSERT(MxMediaManager, 0x2c); +DECOMP_SIZE_ASSERT(MxPresentationManager, 0x2c); DECOMP_SIZE_ASSERT(MxPresenterList, 0x18); DECOMP_SIZE_ASSERT(MxPresenterListCursor, 0x10); // FUNCTION: LEGO1 0x100b84c0 -MxMediaManager::MxMediaManager() +// FUNCTION: BETA10 0x10144680 +MxPresentationManager::MxPresentationManager() { Init(); } // FUNCTION: LEGO1 0x100b8560 -MxMediaManager::~MxMediaManager() +// FUNCTION: BETA10 0x10144712 +MxPresentationManager::~MxPresentationManager() { Destroy(); } // FUNCTION: LEGO1 0x100b85d0 -MxResult MxMediaManager::Init() +// FUNCTION: BETA10 0x1014479b +MxResult MxPresentationManager::Init() { this->m_presenters = NULL; this->m_thread = NULL; @@ -31,8 +34,10 @@ MxResult MxMediaManager::Init() } // FUNCTION: LEGO1 0x100b85e0 -MxResult MxMediaManager::Create() +// FUNCTION: BETA10 0x101447c5 +MxResult MxPresentationManager::Create() { + // This validates the name of the source code file (and hence also the name of the class) AUTOLOCK(m_criticalSection); this->m_presenters = new MxPresenterList; @@ -46,7 +51,8 @@ MxResult MxMediaManager::Create() } // FUNCTION: LEGO1 0x100b8710 -void MxMediaManager::Destroy() +// FUNCTION: BETA10 0x101448e4 +void MxPresentationManager::Destroy() { AUTOLOCK(m_criticalSection); @@ -58,7 +64,8 @@ void MxMediaManager::Destroy() } // FUNCTION: LEGO1 0x100b8790 -MxResult MxMediaManager::Tickle() +// FUNCTION: BETA10 0x10144993 +MxResult MxPresentationManager::Tickle() { AUTOLOCK(m_criticalSection); MxPresenter* presenter; @@ -78,7 +85,8 @@ MxResult MxMediaManager::Tickle() } // FUNCTION: LEGO1 0x100b88c0 -void MxMediaManager::RegisterPresenter(MxPresenter& p_presenter) +// FUNCTION: BETA10 0x10144a8b +void MxPresentationManager::RegisterPresenter(MxPresenter& p_presenter) { AUTOLOCK(m_criticalSection); @@ -86,7 +94,8 @@ void MxMediaManager::RegisterPresenter(MxPresenter& p_presenter) } // FUNCTION: LEGO1 0x100b8980 -void MxMediaManager::UnregisterPresenter(MxPresenter& p_presenter) +// FUNCTION: BETA10 0x10144b0c +void MxPresentationManager::UnregisterPresenter(MxPresenter& p_presenter) { AUTOLOCK(m_criticalSection); MxPresenterListCursor cursor(this->m_presenters); @@ -97,7 +106,8 @@ void MxMediaManager::UnregisterPresenter(MxPresenter& p_presenter) } // FUNCTION: LEGO1 0x100b8ac0 -void MxMediaManager::StopPresenters() +// FUNCTION: BETA10 0x10144bc3 +void MxPresentationManager::StopPresenters() { AUTOLOCK(m_criticalSection); MxPresenter* presenter; diff --git a/LEGO1/omni/src/common/mxutilities.cpp b/LEGO1/omni/src/common/mxutilities.cpp index c17e41e5..5d7528fa 100644 --- a/LEGO1/omni/src/common/mxutilities.cpp +++ b/LEGO1/omni/src/common/mxutilities.cpp @@ -153,16 +153,16 @@ void SetOmniUserMessage(void (*p_omniUserMessage)(const char*, MxS32)) // FUNCTION: LEGO1 0x100b7220 // FUNCTION: BETA10 0x10136f37 -void FUN_100b7220(MxDSAction* p_action, MxU32 p_newFlags, MxBool p_setFlags) +void ApplyMask(MxDSAction* p_action, MxU32 p_mask, MxBool p_setFlags) { MxU32 oldFlags = p_action->GetFlags(); MxU32 newFlags; if (p_setFlags) { - newFlags = oldFlags | p_newFlags; + newFlags = oldFlags | p_mask; } else { - newFlags = oldFlags & ~p_newFlags; + newFlags = oldFlags & ~p_mask; } p_action->SetFlags(newFlags); @@ -172,7 +172,7 @@ void FUN_100b7220(MxDSAction* p_action, MxU32 p_newFlags, MxBool p_setFlags) MxDSAction* action; while (cursor.Next(action)) { - FUN_100b7220(action, p_newFlags, p_setFlags); + ApplyMask(action, p_mask, p_setFlags); } } } diff --git a/LEGO1/omni/src/event/mxeventmanager.cpp b/LEGO1/omni/src/event/mxeventmanager.cpp index 29b8aba0..91a22abb 100644 --- a/LEGO1/omni/src/event/mxeventmanager.cpp +++ b/LEGO1/omni/src/event/mxeventmanager.cpp @@ -35,7 +35,7 @@ void MxEventManager::Destroy(MxBool p_fromDestructor) } if (!p_fromDestructor) { - MxMediaManager::Destroy(); + MxPresentationManager::Destroy(); } } @@ -45,10 +45,10 @@ MxResult MxEventManager::Create(MxU32 p_frequencyMS, MxBool p_createThread) MxResult status = FAILURE; MxBool locked = FALSE; - MxResult result = MxMediaManager::Create(); + MxResult result = MxPresentationManager::Create(); if (result == SUCCESS) { if (p_createThread) { - this->m_criticalSection.Enter(); + ENTER(this->m_criticalSection); locked = TRUE; this->m_thread = new MxTickleThread(this, p_frequencyMS); diff --git a/LEGO1/omni/src/event/mxeventpresenter.cpp b/LEGO1/omni/src/event/mxeventpresenter.cpp index f819b68c..8134465e 100644 --- a/LEGO1/omni/src/event/mxeventpresenter.cpp +++ b/LEGO1/omni/src/event/mxeventpresenter.cpp @@ -50,7 +50,7 @@ void MxEventPresenter::Destroy() EventManager()->UnregisterPresenter(*this); } - m_criticalSection.Enter(); + ENTER(m_criticalSection); if (m_data) { delete[] m_data; diff --git a/LEGO1/omni/src/main/mxomni.cpp b/LEGO1/omni/src/main/mxomni.cpp index d7b76847..c314c7a8 100644 --- a/LEGO1/omni/src/main/mxomni.cpp +++ b/LEGO1/omni/src/main/mxomni.cpp @@ -163,9 +163,10 @@ MxResult MxOmni::Create(MxOmniCreateParam& p_param) } { - Uint32 event = SDL_RegisterEvents(2); + Uint32 event = SDL_RegisterEvents(3); g_legoSdlEvents.m_windowsMessage = event + 0; g_legoSdlEvents.m_presenterProgress = event + 1; + g_legoSdlEvents.m_gameEvent = event + 2; } result = SUCCESS; diff --git a/LEGO1/omni/src/stream/mxdiskstreamprovider.cpp b/LEGO1/omni/src/stream/mxdiskstreamprovider.cpp index 3cf753d6..49980ee1 100644 --- a/LEGO1/omni/src/stream/mxdiskstreamprovider.cpp +++ b/LEGO1/omni/src/stream/mxdiskstreamprovider.cpp @@ -161,10 +161,11 @@ void MxDiskStreamProvider::VTable0x20(MxDSAction* p_action) } // FUNCTION: LEGO1 0x100d1750 +// FUNCTION: BETA10 0x101632b8 MxResult MxDiskStreamProvider::WaitForWorkToComplete() { while (m_remainingWork) { - m_busySemaphore.Wait(); + m_busySemaphore.Acquire(); if (m_unk0x35) { PerformWork(); } diff --git a/LEGO1/omni/src/stream/mxdsbuffer.cpp b/LEGO1/omni/src/stream/mxdsbuffer.cpp index 9cfe3b24..3634b6c7 100644 --- a/LEGO1/omni/src/stream/mxdsbuffer.cpp +++ b/LEGO1/omni/src/stream/mxdsbuffer.cpp @@ -210,7 +210,7 @@ MxResult MxDSBuffer::StartPresenterFromAction( p_objectheader->SetUnknown28(p_action1->GetUnknown28()); p_objectheader->SetNotificationObject(p_action1->GetNotificationObject()); p_objectheader->SetOrigin(p_action1->GetOrigin()); - p_objectheader->SetUnknown90(p_action1->GetUnknown90()); + p_objectheader->SetTimeStarted(p_action1->GetTimeStarted()); p_objectheader->MergeFrom(*p_action1); m_unk0x30->SetInternalAction(p_objectheader->Clone()); diff --git a/LEGO1/omni/src/stream/mxramstreamprovider.cpp b/LEGO1/omni/src/stream/mxramstreamprovider.cpp index 71fa256c..966bec95 100644 --- a/LEGO1/omni/src/stream/mxramstreamprovider.cpp +++ b/LEGO1/omni/src/stream/mxramstreamprovider.cpp @@ -108,7 +108,7 @@ MxU32 ReadData(MxU8* p_buffer, MxU32 p_size) { MxU32 id; MxU8* data = p_buffer; - MxU8* data2; + MxU8* data2 = NULL; while (data < p_buffer + p_size) { if (data + sizeof(MxU32) <= p_buffer + p_size && UnalignedRead(data) == FOURCC('M', 'x', 'O', 'b')) { diff --git a/LEGO1/omni/src/stream/mxstreamcontroller.cpp b/LEGO1/omni/src/stream/mxstreamcontroller.cpp index dadd03ca..8c3cf079 100644 --- a/LEGO1/omni/src/stream/mxstreamcontroller.cpp +++ b/LEGO1/omni/src/stream/mxstreamcontroller.cpp @@ -202,7 +202,7 @@ MxResult MxStreamController::FUN_100c1a00(MxDSAction* p_action, MxU32 p_offset) streamingAction->SetObjectId(p_action->GetObjectId()); MxLong time = Timer()->GetTime(); - streamingAction->SetUnknown90(time); + streamingAction->SetTimeStarted(time); m_unk0x3c.PushBack(streamingAction); return SUCCESS; diff --git a/LEGO1/omni/src/system/mxautolock.cpp b/LEGO1/omni/src/system/mxautolock.cpp index 4508663e..227085dd 100644 --- a/LEGO1/omni/src/system/mxautolock.cpp +++ b/LEGO1/omni/src/system/mxautolock.cpp @@ -2,8 +2,19 @@ #include "mxcriticalsection.h" -// FUNCTION: LEGO1 0x100b8ed0 +#ifdef BETA10 // FUNCTION: BETA10 0x101386f0 +MxAutoLock::MxAutoLock(MxCriticalSection* p_criticalSection, const char* filename, int line) +{ + m_criticalSection = p_criticalSection; + m_currentThreadId = GetCurrentThreadId(); + + if (m_criticalSection != NULL) { + m_criticalSection->Enter(m_currentThreadId, filename, line); + } +} +#else +// FUNCTION: LEGO1 0x100b8ed0 MxAutoLock::MxAutoLock(MxCriticalSection* p_criticalSection) { m_criticalSection = p_criticalSection; @@ -12,6 +23,7 @@ MxAutoLock::MxAutoLock(MxCriticalSection* p_criticalSection) m_criticalSection->Enter(); } } +#endif // FUNCTION: LEGO1 0x100b8ef0 // FUNCTION: BETA10 0x10138744 diff --git a/LEGO1/omni/src/system/mxcriticalsection.cpp b/LEGO1/omni/src/system/mxcriticalsection.cpp index 7b982bd6..e940c847 100644 --- a/LEGO1/omni/src/system/mxcriticalsection.cpp +++ b/LEGO1/omni/src/system/mxcriticalsection.cpp @@ -22,14 +22,43 @@ MxCriticalSection::~MxCriticalSection() } } -// FUNCTION: LEGO1 0x100b6d80 +#ifdef BETA10 // FUNCTION: BETA10 0x1013c725 +void MxCriticalSection::Enter(unsigned long p_threadId, const char* filename, int line) +{ + DWORD result; + FILE* file; + + if (m_mutex != NULL) { + result = WaitForSingleObject(m_mutex, 5000); + if (result == WAIT_FAILED) { + file = fopen("C:\\DEADLOCK.TXT", "a"); + if (file != NULL) { + fprintf(file, "mutex timeout occurred!\n"); + fprintf(file, "file: %s, line: %d\n", filename, line); + fclose(file); + } + + abort(); + } + } + else { + EnterCriticalSection(&m_criticalSection); + } + + // There is way more structure in here, and the MxCriticalSection class is much larger in BETA10. + // The LEGO1 compilation is very unlikely to profit from a further decompilation here. +} +#else +// FUNCTION: LEGO1 0x100b6d80 void MxCriticalSection::Enter() { SDL_LockMutex(m_mutex); } +#endif // FUNCTION: LEGO1 0x100b6de0 +// FUNCTION: BETA10 0x1013c7ef void MxCriticalSection::Leave() { SDL_UnlockMutex(m_mutex); diff --git a/LEGO1/omni/src/system/mxsemaphore.cpp b/LEGO1/omni/src/system/mxsemaphore.cpp index a4db127b..2cd2016e 100644 --- a/LEGO1/omni/src/system/mxsemaphore.cpp +++ b/LEGO1/omni/src/system/mxsemaphore.cpp @@ -6,32 +6,46 @@ DECOMP_SIZE_ASSERT(MxSemaphore, 0x08) // FUNCTION: LEGO1 0x100c87d0 +// FUNCTION: BETA10 0x10159260 MxSemaphore::MxSemaphore() { m_semaphore = NULL; } // FUNCTION: LEGO1 0x100c8800 +// FUNCTION: BETA10 0x101592d5 MxResult MxSemaphore::Init(MxU32 p_initialCount, MxU32 p_maxCount) { // [library:synchronization] No support for max count, but shouldn't be necessary MxResult result = FAILURE; - if ((m_semaphore = SDL_CreateSemaphore(p_initialCount))) { - result = SUCCESS; + m_semaphore = SDL_CreateSemaphore(p_initialCount); + if (!m_semaphore) { + goto done; } + result = SUCCESS; + +done: return result; } // FUNCTION: LEGO1 0x100c8830 -void MxSemaphore::Wait() +// FUNCTION: BETA10 0x10159332 +void MxSemaphore::Acquire() { // [library:synchronization] Removed timeout since only INFINITE is ever requested SDL_WaitSemaphore(m_semaphore); } +// FUNCTION: BETA10 0x10159385 +void MxSemaphore::TryAcquire() +{ + // unused +} + // FUNCTION: LEGO1 0x100c8850 +// FUNCTION: BETA10 0x101593aa void MxSemaphore::Release() { // [library:synchronization] Removed release count since only 1 is ever requested diff --git a/LEGO1/omni/src/system/mxthread.cpp b/LEGO1/omni/src/system/mxthread.cpp index 96e64992..307db15a 100644 --- a/LEGO1/omni/src/system/mxthread.cpp +++ b/LEGO1/omni/src/system/mxthread.cpp @@ -7,6 +7,7 @@ DECOMP_SIZE_ASSERT(MxThread, 0x1c) // FUNCTION: LEGO1 0x100bf510 +// FUNCTION: BETA10 0x10147540 MxThread::MxThread() { m_thread = NULL; @@ -14,6 +15,7 @@ MxThread::MxThread() } // FUNCTION: LEGO1 0x100bf5a0 +// FUNCTION: BETA10 0x101475d0 MxThread::~MxThread() { if (m_thread) { @@ -22,46 +24,91 @@ MxThread::~MxThread() } // FUNCTION: LEGO1 0x100bf610 +// FUNCTION: BETA10 0x10147655 MxResult MxThread::Start(MxS32 p_stackSize, MxS32 p_flag) { MxResult result = FAILURE; - if (m_semaphore.Init(0, 1) == SUCCESS) { + if (m_semaphore.Init(0, 1) != SUCCESS) { + goto done; + } + + { const SDL_PropertiesID props = SDL_CreateProperties(); SDL_SetPointerProperty(props, SDL_PROP_THREAD_CREATE_ENTRY_FUNCTION_POINTER, (void*) MxThread::ThreadProc); SDL_SetPointerProperty(props, SDL_PROP_THREAD_CREATE_USERDATA_POINTER, this); SDL_SetNumberProperty(props, SDL_PROP_THREAD_CREATE_STACKSIZE_NUMBER, p_stackSize * 4); - if ((m_thread = SDL_CreateThreadWithProperties(props))) { - result = SUCCESS; + if (!(m_thread = SDL_CreateThreadWithProperties(props))) { + goto done; } SDL_DestroyProperties(props); } + result = SUCCESS; + +done: return result; } // FUNCTION: LEGO1 0x100bf660 +// FUNCTION: BETA10 0x101476ee void MxThread::Sleep(MxS32 p_milliseconds) { SDL_Delay(p_milliseconds); } +// FUNCTION: BETA10 0x10147710 +void MxThread::ResumeThread() +{ + // unused +} + +// FUNCTION: BETA10 0x10147733 +void MxThread::SuspendThread() +{ + // unused +} + +// FUNCTION: BETA10 0x10147756 +bool MxThread::TerminateThread(MxU32 p_exitCode) +{ + // unused + return false; +} + +// FUNCTION: BETA10 0x10147793 +MxS32 MxThread::GetThreadPriority(MxU16& p_priority) +{ + // unused + return -1; +} + +// FUNCTION: BETA10 0x101477c8 +bool MxThread::SetThreadPriority(MxU16 p_priority) +{ + // unused + return false; +} + // FUNCTION: LEGO1 0x100bf670 +// FUNCTION: BETA10 0x1014780a void MxThread::Terminate() { m_running = FALSE; - m_semaphore.Wait(); + m_semaphore.Acquire(); } // FUNCTION: LEGO1 0x100bf680 +// FUNCTION: BETA10 0x1014783b int MxThread::ThreadProc(void* p_thread) { return static_cast(p_thread)->Run(); } // FUNCTION: LEGO1 0x100bf690 +// FUNCTION: BETA10 0x10147855 MxResult MxThread::Run() { m_semaphore.Release(); diff --git a/LEGO1/omni/src/video/mxdisplaysurface.cpp b/LEGO1/omni/src/video/mxdisplaysurface.cpp index 6c93a0e7..51a2f36b 100644 --- a/LEGO1/omni/src/video/mxdisplaysurface.cpp +++ b/LEGO1/omni/src/video/mxdisplaysurface.cpp @@ -18,9 +18,6 @@ DECOMP_SIZE_ASSERT(MxDisplaySurface, 0xac); -#define RGB555_CREATE(R, G, B) (((R) << 10) | (G) << 5 | (B) << 0) -#define RGB8888_CREATE(R, G, B, A) (((A) << 24) | ((R) << 16) | ((G) << 8) | (B)) - // GLOBAL: LEGO1 0x1010215c MxU32 g_unk0x1010215c = 0; @@ -49,23 +46,23 @@ void MxDisplaySurface::Init() } // FUNCTION: LEGO1 0x100ba640 +// FUNCTION: BETA10 0x1013f506 void MxDisplaySurface::ClearScreen() { + MxS32 i; MxS32 backBuffers; DDSURFACEDESC desc; - if (!m_videoParam.Flags().GetFlipSurfaces()) { - backBuffers = 1; + if (m_videoParam.Flags().GetFlipSurfaces()) { + backBuffers = m_videoParam.GetBackBuffers() + 1; } else { - backBuffers = m_videoParam.GetBackBuffers() + 1; + backBuffers = 2; } MxS32 width = m_videoParam.GetRect().GetWidth(); MxS32 height = m_videoParam.GetRect().GetHeight(); - RECT rc = {0, 0, width, height}; - memset(&desc, 0, sizeof(desc)); desc.dwSize = sizeof(desc); if (m_ddSurface2->GetSurfaceDesc(&desc) != DD_OK) { @@ -74,17 +71,28 @@ void MxDisplaySurface::ClearScreen() DDBLTFX ddBltFx = {}; ddBltFx.dwSize = sizeof(DDBLTFX); - ddBltFx.dwFillColor = 0; + ddBltFx.dwFillColor = 0xFF000000; for (MxS32 i = 0; i < backBuffers; i++) { - if (m_ddSurface2->Blt(&rc, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &ddBltFx) == DDERR_SURFACELOST) { + if (m_ddSurface2->Blt(NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &ddBltFx) == DDERR_SURFACELOST) { m_ddSurface2->Restore(); - m_ddSurface2->Blt(&rc, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &ddBltFx); + m_ddSurface2->Blt(NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &ddBltFx); } if (m_videoParam.Flags().GetFlipSurfaces()) { m_ddSurface1->Flip(NULL, DDFLIP_WAIT); } + else { + DDBLTFX data; + memset(&data, 0, sizeof(data)); + data.dwSize = sizeof(data); + data.dwDDFX = DDBLTFX_NOTEARING; + + if (m_ddSurface1->Blt(NULL, m_ddSurface2, NULL, DDBLT_NONE, &data) == DDERR_SURFACELOST) { + m_ddSurface1->Restore(); + m_ddSurface1->Blt(NULL, m_ddSurface2, NULL, DDBLT_NONE, &data); + } + } } } @@ -401,86 +409,88 @@ void MxDisplaySurface::VTable0x28( DDSURFACEDESC ddsd; memset(&ddsd, 0, sizeof(ddsd)); ddsd.dwSize = sizeof(ddsd); + ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | DDSD_CAPS; + ddsd.dwWidth = p_width; + ddsd.dwHeight = p_height; + ddsd.ddpfPixelFormat = m_surfaceDesc.ddpfPixelFormat; + ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN; - HRESULT hr = m_ddSurface2->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL); + LPDIRECTDRAWSURFACE tempSurface = nullptr; + LPDIRECTDRAW draw = MVideoManager()->GetDirectDraw(); + HRESULT hr = draw->CreateSurface(&ddsd, &tempSurface, nullptr); + if (hr != DD_OK || !tempSurface) { + return; + } + + 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); + + hr = tempSurface->Lock(NULL, &tempDesc, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL); if (hr == DDERR_SURFACELOST) { - m_ddSurface2->Restore(); - hr = m_ddSurface2->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL); + tempSurface->Restore(); + hr = tempSurface->Lock(NULL, &tempDesc, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL); } if (hr != DD_OK) { + tempSurface->Release(); return; } MxU8* data = p_bitmap->GetStart(p_left, p_top); MxS32 bytesPerPixel = m_surfaceDesc.ddpfPixelFormat.dwRGBBitCount / 8; - if (m_videoParam.Flags().GetF1bit3()) { - p_bottom *= 2; - p_right *= 2; + MxU8* surface = (MxU8*) tempDesc.lpSurface; - MxU8* surface = (MxU8*) ddsd.lpSurface + (bytesPerPixel * p_right) + (p_bottom * ddsd.lPitch); - MxLong stride = -p_width + GetAdjustedStride(p_bitmap); - MxS32 copyWidth = p_width * bytesPerPixel * 2; - MxLong length = -(copyWidth) + ddsd.lPitch; + MxLong stride = (bytesPerPixel == 1) ? GetAdjustedStride(p_bitmap) : -p_width + GetAdjustedStride(p_bitmap); + MxLong length = tempDesc.lPitch - (p_width * bytesPerPixel); - while (p_height--) { - MxU8* surfaceBefore = surface; - - for (MxS32 i = 0; i < p_width; i++) { - if (bytesPerPixel == 1) { - surface[0] = surface[1] = *data; - } - else if (bytesPerPixel == 2) { - ((MxU16*) surface)[0] = ((MxU16*) surface)[1] = m_16bitPal[*data]; - } - else { - ((MxU32*) surface)[0] = ((MxU32*) surface)[1] = m_32bitPal[*data]; - } - surface += bytesPerPixel * 2; - data++; - } - - if (stride || length != ddsd.lPitch - copyWidth) { - data += stride; - surface += length; - } - - memcpy(surface, surfaceBefore, copyWidth); - surface += ddsd.lPitch; + for (MxS32 i = 0; i < p_height; i++) { + if (bytesPerPixel == 1) { + memcpy(surface, data, p_width); + surface += length + p_width; } + else if (bytesPerPixel == 2) { + for (MxS32 j = 0; j < p_width; j++) { + *(MxU16*) surface = m_16bitPal[*data++]; + surface += bytesPerPixel; + } + + surface += length; + } + else { + for (MxS32 j = 0; j < p_width; j++) { + *(MxU32*) surface = m_32bitPal[*data++]; + surface += bytesPerPixel; + } + surface += length; + } + + data += stride; + } + + tempSurface->Unlock(NULL); + + 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); } else { - MxU8* surface = (MxU8*) ddsd.lpSurface + (bytesPerPixel * p_right) + (p_bottom * ddsd.lPitch); - MxLong stride = (bytesPerPixel == 1) ? GetAdjustedStride(p_bitmap) : -p_width + GetAdjustedStride(p_bitmap); - MxLong length = ddsd.lPitch - (p_width * bytesPerPixel); - - for (MxS32 i = 0; i < p_height; i++) { - if (bytesPerPixel == 1) { - memcpy(surface, data, p_width); - surface += length + p_width; - } - else if (bytesPerPixel == 2) { - for (MxS32 j = 0; j < p_width; j++) { - *(MxU16*) surface = m_16bitPal[*data++]; - surface += bytesPerPixel; - } - - surface += length; - } - else { - for (MxS32 j = 0; j < p_width; j++) { - *(MxU32*) surface = m_32bitPal[*data++]; - surface += bytesPerPixel; - } - surface += length; - } - - data += stride; - } + m_ddSurface2->BltFast(p_right, p_bottom, tempSurface, NULL, DDBLTFAST_WAIT | DDBLTFAST_SRCCOLORKEY); } - m_ddSurface2->Unlock(ddsd.lpSurface); + tempSurface->Release(); } // FUNCTION: LEGO1 0x100bb1d0 @@ -513,29 +523,43 @@ void MxDisplaySurface::VTable0x30( DDSURFACEDESC ddsd; memset(&ddsd, 0, sizeof(ddsd)); ddsd.dwSize = sizeof(ddsd); + ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | DDSD_CAPS; + ddsd.dwWidth = p_width; + ddsd.dwHeight = p_height; + ddsd.ddpfPixelFormat = m_surfaceDesc.ddpfPixelFormat; + ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN; - HRESULT hr = m_ddSurface2->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL); - if (hr == DDERR_SURFACELOST) { - m_ddSurface2->Restore(); - hr = m_ddSurface2->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL); + LPDIRECTDRAW draw = MVideoManager()->GetDirectDraw(); + LPDIRECTDRAWSURFACE tempSurface = nullptr; + if (draw->CreateSurface(&ddsd, &tempSurface, nullptr) != DD_OK || !tempSurface) { + return; } - if (hr != DD_OK) { + DDCOLORKEY colorKey; + colorKey.dwColorSpaceLowValue = colorKey.dwColorSpaceHighValue = 0; + tempSurface->SetColorKey(DDCKEY_SRCBLT, &colorKey); + + DDSURFACEDESC tempDesc; + memset(&tempDesc, 0, sizeof(tempDesc)); + tempDesc.dwSize = sizeof(tempDesc); + + if (tempSurface->Lock(NULL, &tempDesc, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL) != DD_OK) { + tempSurface->Release(); return; } MxU8* data = p_bitmap->GetStart(p_left, p_top); MxS32 bytesPerPixel = m_surfaceDesc.ddpfPixelFormat.dwRGBBitCount / 8; - MxU8* surface = (MxU8*) ddsd.lpSurface + (bytesPerPixel * p_right) + (p_bottom * ddsd.lPitch); + MxU8* surface = (MxU8*) tempDesc.lpSurface; if (p_RLE) { MxS32 size = p_bitmap->GetBmiHeader()->biSizeImage; - DrawTransparentRLE(data, surface, size, p_width, p_height, ddsd.lPitch, bytesPerPixel * 8); + DrawTransparentRLE(data, surface, size, p_width, p_height, tempDesc.lPitch, bytesPerPixel * 8); } else { MxLong stride = -p_width + GetAdjustedStride(p_bitmap); - MxLong length = -bytesPerPixel * p_width + ddsd.lPitch; + MxLong length = -bytesPerPixel * p_width + tempDesc.lPitch; for (MxS32 i = 0; i < p_height; i++) { for (MxS32 j = 0; j < p_width; j++) { @@ -560,7 +584,11 @@ void MxDisplaySurface::VTable0x30( } } - m_ddSurface2->Unlock(ddsd.lpSurface); + tempSurface->Unlock(NULL); + + m_ddSurface2->BltFast(p_right, p_bottom, tempSurface, NULL, DDBLTFAST_WAIT | DDBLTFAST_SRCCOLORKEY); + + tempSurface->Release(); } // FUNCTION: LEGO1 0x100bb500 @@ -718,84 +746,19 @@ void MxDisplaySurface::DrawTransparentRLE( } } -// FUNCTION: LEGO1 0x100bb850 -// FUNCTION: BETA10 0x10141191 -void MxDisplaySurface::VTable0x34(MxU8* p_pixels, MxS32 p_bpp, MxS32 p_width, MxS32 p_height, MxS32 p_x, MxS32 p_y) -{ - DDSURFACEDESC surfaceDesc; - memset(&surfaceDesc, 0, sizeof(surfaceDesc)); - surfaceDesc.dwSize = sizeof(surfaceDesc); - - HRESULT result = m_ddSurface2->Lock(NULL, &surfaceDesc, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL); - - if (result == DDERR_SURFACELOST) { - m_ddSurface2->Restore(); - result = m_ddSurface2->Lock(NULL, &surfaceDesc, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL); - } - - if (result == DD_OK) { - MxU8* pixels = p_pixels; - MxS32 bytesPerPixel = m_surfaceDesc.ddpfPixelFormat.dwRGBBitCount / 8; - if (p_bpp != 8 && bytesPerPixel != p_bpp) { - MxTrace("Source format to display format NOT_IMPLEMENTED"); - assert(0); - return; - } - - MxU8* dst = (MxU8*) surfaceDesc.lpSurface + p_y * surfaceDesc.lPitch + bytesPerPixel * p_x; - MxLong stride = p_width * bytesPerPixel; - MxLong length = -bytesPerPixel * p_width + surfaceDesc.lPitch; - - if (bytesPerPixel == p_bpp) { - while (p_height--) { - memcpy(dst, pixels, p_width * bytesPerPixel); - pixels += stride; - dst += length; - } - } - else { - for (MxS32 i = 0; i < p_height; i++) { - for (MxS32 j = 0; j < p_width; j++) { - if (bytesPerPixel == 2) { - *(MxU16*) dst = m_16bitPal[*pixels++]; - } - else { - *(MxU32*) dst = m_32bitPal[*pixels++]; - } - dst += bytesPerPixel; - } - pixels += stride; - dst += length; - } - } - - m_ddSurface2->Unlock(surfaceDesc.lpSurface); - } -} - // FUNCTION: LEGO1 0x100bba50 void MxDisplaySurface::Display(MxS32 p_left, MxS32 p_top, MxS32 p_left2, MxS32 p_top2, MxS32 p_width, MxS32 p_height) { - if (m_videoParam.Flags().GetF2bit1()) { + if (m_videoParam.Flags().GetEnabled()) { if (m_videoParam.Flags().GetFlipSurfaces()) { if (g_unk0x1010215c < 2) { g_unk0x1010215c++; - DDSURFACEDESC ddsd; - memset(&ddsd, 0, sizeof(ddsd)); - ddsd.dwSize = sizeof(ddsd); - if (m_ddSurface2->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL) == DD_OK) { - MxU8* surface = (MxU8*) ddsd.lpSurface; - MxS32 height = m_videoParam.GetRect().GetHeight(); + DDBLTFX ddbltfx = {}; + ddbltfx.dwSize = sizeof(ddbltfx); + ddbltfx.dwFillColor = 0xFF000000; - for (MxU32 i = 0; i < ddsd.dwHeight; i++) { - memset(surface, 0, ddsd.lPitch); - surface += ddsd.lPitch; - } - - m_ddSurface2->Unlock(ddsd.lpSurface); - } - else { + if (m_ddSurface2->Blt(NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &ddbltfx) != DD_OK) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "MxDisplaySurface::Display error\n"); } } @@ -814,7 +777,7 @@ void MxDisplaySurface::Display(MxS32 p_left, MxS32 p_top, MxS32 p_left2, MxS32 p DDBLTFX data; memset(&data, 0, sizeof(data)); data.dwSize = sizeof(data); - data.dwDDFX = 8; + data.dwDDFX = DDBLTFX_NOTEARING; if (m_ddSurface1->Blt((LPRECT) &b, m_ddSurface2, (LPRECT) &a, DDBLT_NONE, &data) == DDERR_SURFACELOST) { m_ddSurface1->Restore(); @@ -866,6 +829,7 @@ LPDIRECTDRAWSURFACE MxDisplaySurface::VTable0x44( ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT; ddsd.dwWidth = p_bitmap->GetBmiWidth(); ddsd.dwHeight = p_bitmap->GetBmiHeightAbs(); + ddsd.ddpfPixelFormat = m_surfaceDesc.ddpfPixelFormat; ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN; *p_ret = 0; ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY; @@ -926,7 +890,7 @@ LPDIRECTDRAWSURFACE MxDisplaySurface::VTable0x44( transparentColor = RGB555_CREATE(0x1f, 0, 0x1f); break; default: - transparentColor = RGB8888_CREATE(0xff, 0, 0xff, 0); + transparentColor = RGB8888_CREATE(0, 0, 0, 0); break; } @@ -971,25 +935,11 @@ LPDIRECTDRAWSURFACE MxDisplaySurface::VTable0x44( surfacePtr += adjustedPitch; } - if (p_transparent && surface) { - DDCOLORKEY key; - key.dwColorSpaceLowValue = key.dwColorSpaceHighValue = transparentColor; - surface->SetColorKey(DDCKEY_SRCBLT, &key); - } - surface->Unlock(ddsd.lpSurface); - if (p_transparent && surface) { + if (p_transparent && surface && bytesPerPixel != 4) { DDCOLORKEY key; - if (bytesPerPixel == 1) { - key.dwColorSpaceLowValue = key.dwColorSpaceHighValue = 0; - } - else if (bytesPerPixel == 2) { - key.dwColorSpaceLowValue = key.dwColorSpaceHighValue = RGB555_CREATE(0x1f, 0, 0x1f); - } - else { - key.dwColorSpaceLowValue = key.dwColorSpaceHighValue = RGB8888_CREATE(0xff, 0, 0xff, 0); - } + key.dwColorSpaceLowValue = key.dwColorSpaceHighValue = transparentColor; surface->SetColorKey(DDCKEY_SRCBLT, &key); } } @@ -1031,86 +981,6 @@ LPDIRECTDRAWSURFACE MxDisplaySurface::CopySurface(LPDIRECTDRAWSURFACE p_src) return newSurface; } -// FUNCTION: LEGO1 0x100bc070 -LPDIRECTDRAWSURFACE MxDisplaySurface::CreateCursorSurface() -{ - LPDIRECTDRAWSURFACE newSurface = NULL; - IDirectDraw* draw = MVideoManager()->GetDirectDraw(); - MVideoManager(); - - DDSURFACEDESC ddsd; - memset(&ddsd, 0, sizeof(ddsd)); - ddsd.dwSize = sizeof(ddsd); - - if (draw->GetDisplayMode(&ddsd) != DD_OK) { - return NULL; - } - - if (ddsd.ddpfPixelFormat.dwRGBBitCount != 16) { - return NULL; - } - - ddsd.dwWidth = 16; - ddsd.dwHeight = 16; - ddsd.dwFlags = DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS; - ddsd.ddsCaps.dwCaps = DDSCAPS_VIDEOMEMORY | DDSCAPS_OFFSCREENPLAIN; - - if (draw->CreateSurface(&ddsd, &newSurface, NULL) != DD_OK) { - ddsd.ddsCaps.dwCaps &= ~DDSCAPS_VIDEOMEMORY; - ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY; - - if (draw->CreateSurface(&ddsd, &newSurface, NULL) != DD_OK) { - goto done; - } - } - - memset(&ddsd, 0, sizeof(ddsd)); - ddsd.dwSize = sizeof(ddsd); - - if (newSurface->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL) != DD_OK) { - goto done; - } - else { - MxU16* surface = (MxU16*) ddsd.lpSurface; - MxLong pitch = ddsd.lPitch; - - // draw a simple cursor to the surface - for (MxS32 x = 0; x < 16; x++) { - MxU16* surface2 = surface; - for (MxS32 y = 0; y < 16; y++) { - if ((y > 10 || x) && (x > 10 || y) && x + y != 10) { - if (x + y > 10) { - *surface2 = RGB555_CREATE(0x1f, 0, 0x1f); - } - else { - *surface2 = -1; - } - } - else { - *surface2 = 0; - } - surface2++; - } - surface = (MxU16*) ((MxU8*) surface + pitch); - } - - newSurface->Unlock(ddsd.lpSurface); - DDCOLORKEY colorkey; - colorkey.dwColorSpaceHighValue = RGB555_CREATE(0x1f, 0, 0x1f); - colorkey.dwColorSpaceLowValue = RGB555_CREATE(0x1f, 0, 0x1f); - newSurface->SetColorKey(DDCKEY_SRCBLT, &colorkey); - - return newSurface; - } - -done: - if (newSurface) { - newSurface->Release(); - } - - return NULL; -} - // FUNCTION: LEGO1 0x100bc200 void MxDisplaySurface::VTable0x24( LPDDSURFACEDESC p_desc, @@ -1142,7 +1012,7 @@ void MxDisplaySurface::VTable0x24( MxU8* data = p_bitmap->GetStart(p_left, p_top); - if (m_videoParam.Flags().GetF1bit3()) { + if (m_videoParam.Flags().GetDoubleScaling()) { p_bottom *= 2; p_right *= 2; @@ -1312,3 +1182,138 @@ LPDIRECTDRAWSURFACE MxDisplaySurface::FUN_100bc8b0(MxS32 p_width, MxS32 p_height return surface; } + +LPDIRECTDRAWSURFACE MxDisplaySurface::CreateCursorSurface(const CursorBitmap* p_cursorBitmap) +{ + LPDIRECTDRAWSURFACE newSurface = NULL; + IDirectDraw* draw = MVideoManager()->GetDirectDraw(); + MVideoManager(); + + DDSURFACEDESC ddsd; + memset(&ddsd, 0, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + + if (draw->GetDisplayMode(&ddsd) != DD_OK) { + return NULL; + } + + MxS32 bytesPerPixel = ddsd.ddpfPixelFormat.dwRGBBitCount / 8; + MxBool isAlphaAvailable = ((ddsd.ddpfPixelFormat.dwFlags & DDPF_ALPHAPIXELS) == DDPF_ALPHAPIXELS) && + (ddsd.ddpfPixelFormat.dwRGBAlphaBitMask != 0); + + ddsd.dwWidth = p_cursorBitmap->width; + ddsd.dwHeight = p_cursorBitmap->height; + ddsd.dwFlags = DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS; + ddsd.ddsCaps.dwCaps = DDSCAPS_VIDEOMEMORY | DDSCAPS_OFFSCREENPLAIN; + + if (draw->CreateSurface(&ddsd, &newSurface, NULL) != DD_OK) { + ddsd.ddsCaps.dwCaps &= ~DDSCAPS_VIDEOMEMORY; + ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY; + + if (draw->CreateSurface(&ddsd, &newSurface, NULL) != DD_OK) { + goto done; + } + } + + memset(&ddsd, 0, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + + if (newSurface->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL) != DD_OK) { + goto done; + } + else { + for (int y = 0; y < p_cursorBitmap->height; y++) { + for (int x = 0; x < p_cursorBitmap->width; x++) { + MxS32 bitIndex = y * p_cursorBitmap->width + x; + MxS32 byteIndex = bitIndex / 8; + MxS32 bitOffset = 7 - (bitIndex % 8); + + MxBool isOpaque = (p_cursorBitmap->mask[byteIndex] >> bitOffset) & 1; + MxBool isBlack = (p_cursorBitmap->data[byteIndex] >> bitOffset) & 1; + + switch (bytesPerPixel) { + case 1: { + MxU8* surface = (MxU8*) ddsd.lpSurface; + + MxU8 pixel; + if (!isOpaque) { + pixel = 0x10; + } + else { + pixel = isBlack ? 0 : 0xff; + } + } + case 2: { + MxU16* surface = (MxU16*) ddsd.lpSurface; + + MxU16 pixel; + if (!isOpaque) { + pixel = RGB555_CREATE(0x1f, 0, 0x1f); + } + else { + pixel = isBlack ? RGB555_CREATE(0, 0, 0) : RGB555_CREATE(0x1f, 0x1f, 0x1f); + } + + surface[x + y * p_cursorBitmap->width] = pixel; + break; + } + default: { + MxU32* surface = (MxU32*) ddsd.lpSurface; + + MxS32 pixel; + if (!isOpaque) { + if (isAlphaAvailable) { + pixel = RGB8888_CREATE(0, 0, 0, 0); + } + else { + pixel = RGB8888_CREATE(0xff, 0, 0xff, 0); + } // Transparent pixel + } + else { + pixel = isBlack ? RGB8888_CREATE(0, 0, 0, 0xff) : RGB8888_CREATE(0xff, 0xff, 0xff, 0xff); + } + + surface[x + y * p_cursorBitmap->width] = pixel; + break; + } + } + } + } + + newSurface->Unlock(ddsd.lpSurface); + switch (bytesPerPixel) { + case 1: { + DDCOLORKEY colorkey; + colorkey.dwColorSpaceHighValue = 0x10; + colorkey.dwColorSpaceLowValue = 0x10; + newSurface->SetColorKey(DDCKEY_SRCBLT, &colorkey); + break; + } + case 2: { + DDCOLORKEY colorkey; + colorkey.dwColorSpaceHighValue = RGB555_CREATE(0x1f, 0, 0x1f); + colorkey.dwColorSpaceLowValue = RGB555_CREATE(0x1f, 0, 0x1f); + newSurface->SetColorKey(DDCKEY_SRCBLT, &colorkey); + break; + } + default: { + if (!isAlphaAvailable) { + DDCOLORKEY colorkey; + colorkey.dwColorSpaceHighValue = RGB8888_CREATE(0xff, 0, 0xff, 0); + colorkey.dwColorSpaceLowValue = RGB8888_CREATE(0xff, 0, 0xff, 0); + newSurface->SetColorKey(DDCKEY_SRCBLT, &colorkey); + } + break; + } + } + + return newSurface; + } + +done: + if (newSurface) { + newSurface->Release(); + } + + return NULL; +} diff --git a/LEGO1/omni/src/video/mxloopingflcpresenter.cpp b/LEGO1/omni/src/video/mxloopingflcpresenter.cpp index a828296c..fb0e3134 100644 --- a/LEGO1/omni/src/video/mxloopingflcpresenter.cpp +++ b/LEGO1/omni/src/video/mxloopingflcpresenter.cpp @@ -29,7 +29,7 @@ void MxLoopingFlcPresenter::Init() // FUNCTION: LEGO1 0x100b4430 void MxLoopingFlcPresenter::Destroy(MxBool p_fromDestructor) { - m_criticalSection.Enter(); + ENTER(m_criticalSection); Init(); m_criticalSection.Leave(); @@ -117,7 +117,7 @@ MxResult MxLoopingFlcPresenter::AddToManager() MxBool locked = FALSE; if (MxFlcPresenter::AddToManager() == SUCCESS) { - m_criticalSection.Enter(); + ENTER(m_criticalSection); locked = TRUE; result = SUCCESS; } diff --git a/LEGO1/omni/src/video/mxloopingsmkpresenter.cpp b/LEGO1/omni/src/video/mxloopingsmkpresenter.cpp index e99533bd..b3705685 100644 --- a/LEGO1/omni/src/video/mxloopingsmkpresenter.cpp +++ b/LEGO1/omni/src/video/mxloopingsmkpresenter.cpp @@ -29,7 +29,7 @@ void MxLoopingSmkPresenter::Init() // FUNCTION: LEGO1 0x100b49d0 void MxLoopingSmkPresenter::Destroy(MxBool p_fromDestructor) { - m_criticalSection.Enter(); + ENTER(m_criticalSection); Init(); m_criticalSection.Leave(); diff --git a/LEGO1/omni/src/video/mxsmkpresenter.cpp b/LEGO1/omni/src/video/mxsmkpresenter.cpp index b530b2e2..2eadc6bf 100644 --- a/LEGO1/omni/src/video/mxsmkpresenter.cpp +++ b/LEGO1/omni/src/video/mxsmkpresenter.cpp @@ -34,7 +34,7 @@ void MxSmkPresenter::Init() // FUNCTION: LEGO1 0x100b3900 void MxSmkPresenter::Destroy(MxBool p_fromDestructor) { - m_criticalSection.Enter(); + ENTER(m_criticalSection); MxSmk::Destroy(&m_mxSmk); Init(); diff --git a/LEGO1/omni/src/video/mxstillpresenter.cpp b/LEGO1/omni/src/video/mxstillpresenter.cpp index 7ff98788..2bcaea47 100644 --- a/LEGO1/omni/src/video/mxstillpresenter.cpp +++ b/LEGO1/omni/src/video/mxstillpresenter.cpp @@ -19,7 +19,7 @@ DECOMP_SIZE_ASSERT(MxStillPresenter, 0x6c); // FUNCTION: LEGO1 0x100b9c70 void MxStillPresenter::Destroy(MxBool p_fromDestructor) { - m_criticalSection.Enter(); + ENTER(m_criticalSection); if (m_bitmapInfo) { delete[] ((MxU8*) m_bitmapInfo); diff --git a/LEGO1/omni/src/video/mxvideomanager.cpp b/LEGO1/omni/src/video/mxvideomanager.cpp index 8c75dc6a..e56cb48e 100644 --- a/LEGO1/omni/src/video/mxvideomanager.cpp +++ b/LEGO1/omni/src/video/mxvideomanager.cpp @@ -21,17 +21,20 @@ MxVideoManager::MxVideoManager() } // FUNCTION: LEGO1 0x100be270 +// FUNCTION: BETA10 0x1012dde0 void MxVideoManager::UpdateView(MxU32 p_x, MxU32 p_y, MxU32 p_width, MxU32 p_height) { } // FUNCTION: LEGO1 0x100be2a0 +// FUNCTION: BETA10 0x1012cad8 MxVideoManager::~MxVideoManager() { Destroy(TRUE); } // FUNCTION: LEGO1 0x100be320 +// FUNCTION: BETA10 0x1012cb66 MxResult MxVideoManager::Init() { m_pDirectDraw = NULL; @@ -44,6 +47,7 @@ MxResult MxVideoManager::Init() } // FUNCTION: LEGO1 0x100be340 +// FUNCTION: BETA10 0x1012cbca void MxVideoManager::Destroy(MxBool p_fromDestructor) { if (m_thread) { @@ -54,7 +58,7 @@ void MxVideoManager::Destroy(MxBool p_fromDestructor) TickleManager()->UnregisterClient(this); } - m_criticalSection.Enter(); + ENTER(m_criticalSection); if (m_displaySurface) { delete m_displaySurface; @@ -81,7 +85,7 @@ void MxVideoManager::Destroy(MxBool p_fromDestructor) m_criticalSection.Leave(); if (!p_fromDestructor) { - MxMediaManager::Destroy(); + MxPresentationManager::Destroy(); } } @@ -134,6 +138,7 @@ void MxVideoManager::SortPresenterList() } // FUNCTION: LEGO1 0x100be600 +// STUB: BETA10 0x1012cfbc MxResult MxVideoManager::VTable0x28( MxVideoParam& p_videoParam, LPDIRECTDRAW p_pDirectDraw, @@ -150,11 +155,11 @@ MxResult MxVideoManager::VTable0x28( m_unk0x60 = FALSE; - if (MxMediaManager::Create() != SUCCESS) { + if (MxPresentationManager::Create() != SUCCESS) { goto done; } - m_criticalSection.Enter(); + ENTER(m_criticalSection); locked = TRUE; m_videoParam = p_videoParam; @@ -216,6 +221,7 @@ MxResult MxVideoManager::VTable0x28( } // FUNCTION: LEGO1 0x100be820 +// STUB: BETA10 0x1012d3f1 MxResult MxVideoManager::Create(MxVideoParam& p_videoParam, MxU32 p_frequencyMS, MxBool p_createThread) { MxBool locked = FALSE; @@ -224,12 +230,12 @@ MxResult MxVideoManager::Create(MxVideoParam& p_videoParam, MxU32 p_frequencyMS, m_unk0x60 = TRUE; - if (MxMediaManager::Create() != SUCCESS) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "MxMediaManager::Create failed"); + if (MxPresentationManager::Create() != SUCCESS) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "MxPresentationManager::Create failed"); goto done; } - m_criticalSection.Enter(); + ENTER(m_criticalSection); locked = TRUE; m_videoParam = p_videoParam; @@ -308,6 +314,7 @@ MxResult MxVideoManager::Create(MxVideoParam& p_videoParam, MxU32 p_frequencyMS, } // FUNCTION: LEGO1 0x100bea50 +// FUNCTION: BETA10 0x1012d85f void MxVideoManager::Destroy() { Destroy(FALSE); @@ -316,7 +323,7 @@ void MxVideoManager::Destroy() // FUNCTION: LEGO1 0x100bea60 void MxVideoManager::InvalidateRect(MxRect32& p_rect) { - m_criticalSection.Enter(); + ENTER(m_criticalSection); if (m_region) { m_region->AddRect(p_rect); @@ -326,6 +333,7 @@ void MxVideoManager::InvalidateRect(MxRect32& p_rect) } // FUNCTION: LEGO1 0x100bea90 +// FUNCTION: BETA10 0x1012d8e3 MxResult MxVideoManager::Tickle() { AUTOLOCK(m_criticalSection); @@ -356,7 +364,7 @@ MxResult MxVideoManager::RealizePalette(MxPalette* p_palette) { PALETTEENTRY paletteEntries[256]; - m_criticalSection.Enter(); + ENTER(m_criticalSection); if (p_palette && m_videoParam.GetPalette()) { p_palette->GetEntries(paletteEntries); diff --git a/LEGO1/omni/src/video/mxvideoparam.cpp b/LEGO1/omni/src/video/mxvideoparam.cpp index 9a095c4e..45a9a688 100644 --- a/LEGO1/omni/src/video/mxvideoparam.cpp +++ b/LEGO1/omni/src/video/mxvideoparam.cpp @@ -28,6 +28,8 @@ MxVideoParam::MxVideoParam(MxRect32& p_rect, MxPalette* p_palette, MxULong p_bac m_flags = p_flags; m_unk0x1c = 0; m_deviceId = NULL; + m_msaaSamples = 0; + m_anisotropic = 0.0f; } // FUNCTION: LEGO1 0x100becf0 @@ -41,6 +43,8 @@ MxVideoParam::MxVideoParam(MxVideoParam& p_videoParam) m_unk0x1c = p_videoParam.m_unk0x1c; m_deviceId = NULL; SetDeviceName(p_videoParam.m_deviceId); + m_msaaSamples = p_videoParam.m_msaaSamples; + m_anisotropic = p_videoParam.m_anisotropic; } // FUNCTION: LEGO1 0x100bed50 @@ -82,6 +86,8 @@ MxVideoParam& MxVideoParam::operator=(const MxVideoParam& p_videoParam) m_flags = p_videoParam.m_flags; m_unk0x1c = p_videoParam.m_unk0x1c; SetDeviceName(p_videoParam.m_deviceId); + m_msaaSamples = p_videoParam.m_msaaSamples; + m_anisotropic = p_videoParam.m_anisotropic; return *this; } diff --git a/LEGO1/omni/src/video/mxvideopresenter.cpp b/LEGO1/omni/src/video/mxvideopresenter.cpp index 84b1c663..e5ed4564 100644 --- a/LEGO1/omni/src/video/mxvideopresenter.cpp +++ b/LEGO1/omni/src/video/mxvideopresenter.cpp @@ -275,61 +275,37 @@ void MxVideoPresenter::PutFrame() } } else { - MxRegionCursor cursor(region); - MxRect32* regionRect; + RECT src, dest; - while ((regionRect = cursor.Next(rect))) { - if (regionRect->GetWidth() >= 1 && regionRect->GetHeight() >= 1) { - RECT src, dest; + if (m_unk0x58) { + src.left = 0; + src.top = 0; + src.right = GetWidth(); + src.bottom = GetHeight(); - if (m_unk0x58) { - src.left = regionRect->GetLeft() - GetX(); - src.top = regionRect->GetTop() - GetY(); - src.right = src.left + regionRect->GetWidth(); - src.bottom = src.top + regionRect->GetHeight(); + dest.left = GetX(); + dest.top = GetY(); + dest.right = dest.left + GetWidth(); + dest.bottom = dest.top + GetHeight(); + } - dest.left = regionRect->GetLeft(); - dest.top = regionRect->GetTop(); - dest.right = dest.left + regionRect->GetWidth(); - dest.bottom = dest.top + regionRect->GetHeight(); - } - - if (m_action->GetFlags() & MxDSAction::c_bit4) { - if (m_unk0x58) { - if (PrepareRects(src, dest) >= 0) { - ddSurface->Blt(&dest, m_unk0x58, &src, DDBLT_KEYSRC, NULL); - } - } - else { - displaySurface->VTable0x30( - m_frameBitmap, - regionRect->GetLeft() - GetX(), - regionRect->GetTop() - GetY(), - regionRect->GetLeft(), - regionRect->GetTop(), - regionRect->GetWidth(), - regionRect->GetHeight(), - FALSE - ); - } - } - else if (m_unk0x58) { - if (PrepareRects(src, dest) >= 0) { - ddSurface->Blt(&dest, m_unk0x58, &src, DDBLT_NONE, NULL); - } - } - else { - displaySurface->VTable0x28( - m_frameBitmap, - regionRect->GetLeft() - GetX(), - regionRect->GetTop() - GetY(), - regionRect->GetLeft(), - regionRect->GetTop(), - regionRect->GetWidth(), - regionRect->GetHeight() - ); + if (m_action->GetFlags() & MxDSAction::c_bit4) { + if (m_unk0x58) { + if (PrepareRects(src, dest) >= 0) { + ddSurface->Blt(&dest, m_unk0x58, &src, DDBLT_KEYSRC, NULL); } } + else { + displaySurface->VTable0x30(m_frameBitmap, 0, 0, GetX(), GetY(), GetWidth(), GetHeight(), FALSE); + } + } + else if (m_unk0x58) { + if (PrepareRects(src, dest) >= 0) { + ddSurface->Blt(&dest, m_unk0x58, &src, DDBLT_NONE, NULL); + } + } + else { + displaySurface->VTable0x28(m_frameBitmap, 0, 0, GetX(), GetY(), GetWidth(), GetHeight()); } } } diff --git a/LEGO1/realtime/matrix.h b/LEGO1/realtime/matrix.h index ceadf97f..1b8d1fdb 100644 --- a/LEGO1/realtime/matrix.h +++ b/LEGO1/realtime/matrix.h @@ -47,7 +47,7 @@ class Matrix4 { inline void RotateX(const float& p_angle); inline void RotateY(const float& p_angle); inline void RotateZ(const float& p_angle); - inline int BETA_1005a590(Matrix4& p_mat); + inline int Invert(Matrix4& p_mat); inline void Swap(int p_d1, int p_d2); // FUNCTION: BETA10 0x1001c670 diff --git a/LEGO1/realtime/matrix4d.inl.h b/LEGO1/realtime/matrix4d.inl.h index b8bba5a3..c1643f76 100644 --- a/LEGO1/realtime/matrix4d.inl.h +++ b/LEGO1/realtime/matrix4d.inl.h @@ -288,75 +288,83 @@ void Matrix4::RotateZ(const float& p_angle) } // FUNCTION: BETA10 0x1005a590 -int Matrix4::BETA_1005a590(Matrix4& p_mat) +int Matrix4::Invert(Matrix4& p_mat) { - float local5c[4][4]; - Matrix4 localc(local5c); - localc = *this; + // Inlined at LEGO1 0x1006b2d3 + + float copyData[4][4]; + Matrix4 copy(copyData); + copy = *this; p_mat.SetIdentity(); for (int i = 0; i < 4; i++) { - int local1c = i; - int local10; + int pivotColumn = i; + int column; - for (local10 = i + 1; local10 < 4; local10++) { - if (fabs(localc[local1c][i]) < fabs(localc[local10][i])) { - local1c = local10; + for (column = i + 1; column < 4; column++) { + if (fabs(copy[pivotColumn][i]) < fabs(copy[column][i])) { + pivotColumn = column; } } - if (local1c != i) { - localc.Swap(local1c, i); - p_mat.Swap(local1c, i); + if (pivotColumn != i) { + copy.Swap(pivotColumn, i); + p_mat.Swap(pivotColumn, i); } - if (localc[i][i] < 0.001f && localc[i][i] > -0.001f) { + if (copy[i][i] < 0.001f && copy[i][i] > -0.001f) { + // FAILURE from mxtypes.h return -1; } - float local60 = localc[i][i]; - int local18; + float pivotValue = copy[i][i]; + int k; - for (local18 = 0; local18 < 4; local18++) { - p_mat[i][local18] /= local60; + for (k = 0; k < 4; k++) { + p_mat[i][k] /= pivotValue; } - for (local18 = 0; local18 < 4; local18++) { - localc[i][local18] /= local60; + for (k = 0; k < 4; k++) { + copy[i][k] /= pivotValue; } - for (local10 = 0; local10 < 4; local10++) { - if (i != local10) { - float afStack70[4]; + for (column = 0; column < 4; column++) { + if (i != column) { + float tempColumn[4]; - for (local18 = 0; local18 < 4; local18++) { - afStack70[local18] = p_mat[i][local18] * localc[local10][i]; + for (k = 0; k < 4; k++) { + tempColumn[k] = p_mat[i][k] * copy[column][i]; } - for (local18 = 0; local18 < 4; local18++) { - p_mat[local10][local18] -= afStack70[local18]; + for (k = 0; k < 4; k++) { + p_mat[column][k] -= tempColumn[k]; } - for (local18 = 0; local18 < 4; local18++) { - afStack70[local18] = localc[i][local18] * localc[local10][i]; + for (k = 0; k < 4; k++) { + tempColumn[k] = copy[i][k] * copy[column][i]; } - for (local18 = 0; local18 < 4; local18++) { - localc[local10][local18] -= afStack70[local18]; + for (k = 0; k < 4; k++) { + copy[column][k] -= tempColumn[k]; } } } } + // SUCCESS from mxtypes.h return 0; } // FUNCTION: LEGO1 0x1006b500 +// FUNCTION: BETA10 0x1005aa20 void Matrix4::Swap(int p_d1, int p_d2) { - for (int i = 0; i < 4; i++) { - float e = m_data[p_d1][i]; + // This function is affected by entropy even in debug builds + int i; + float e; + for (i = 0; i < 4; i++) { + e = m_data[p_d1][i]; m_data[p_d1][i] = m_data[p_d2][i]; m_data[p_d2][i] = e; } diff --git a/LEGO1/realtime/orientableroi.cpp b/LEGO1/realtime/orientableroi.cpp index 92c9ac9e..3c45e90f 100644 --- a/LEGO1/realtime/orientableroi.cpp +++ b/LEGO1/realtime/orientableroi.cpp @@ -153,6 +153,7 @@ void OrientableROI::UpdateWorldDataWithTransformAndChildren(const Matrix4& p_tra } // FUNCTION: LEGO1 0x100a5a30 +// FUNCTION: BETA10 0x10167d31 void OrientableROI::SetWorldVelocity(const Vector3& p_world_velocity) { m_world_velocity = p_world_velocity; diff --git a/LEGO1/viewmanager/viewlod.h b/LEGO1/viewmanager/viewlod.h index 7bf68b52..b7104526 100644 --- a/LEGO1/viewmanager/viewlod.h +++ b/LEGO1/viewmanager/viewlod.h @@ -14,10 +14,10 @@ class ViewLOD : public LODObject { public: enum { - c_bit4 = 0x10 + c_hasMesh = 0x10 }; - ViewLOD(Tgl::Renderer* pRenderer) : m_meshBuilder(NULL), m_unk0x08(3) {} + ViewLOD(Tgl::Renderer* pRenderer) : m_meshBuilder(NULL), m_flags(3) {} ~ViewLOD() override; // FUNCTION: LEGO1 0x100a6f30 @@ -28,19 +28,19 @@ class ViewLOD : public LODObject { Tgl::MeshBuilder* GetMeshBuilder() { return m_meshBuilder; } const Tgl::MeshBuilder* GetMeshBuilder() const { return m_meshBuilder; } - undefined4 GetUnknown0x08() { return m_unk0x08; } - unsigned char GetUnknown0x08Test4() { return m_unk0x08 & 0xffffff04; } - unsigned char GetUnknown0x08Test8() { return m_unk0x08 & 0xffffff08; } + unsigned int GetFlags() { return m_flags; } + unsigned char SkipReadingData() { return m_flags & 0xffffff04; } + unsigned char IsExtraLOD() { return m_flags & 0xffffff08; } - void SetFlag(unsigned char p_flag) { m_unk0x08 |= p_flag; } - void ClearFlag(unsigned char p_flag) { m_unk0x08 &= ~p_flag; } + void SetFlag(unsigned char p_flag) { m_flags |= p_flag; } + void ClearFlag(unsigned char p_flag) { m_flags &= ~p_flag; } // SYNTHETIC: LEGO1 0x100a6f60 // ViewLOD::`scalar deleting destructor' protected: Tgl::MeshBuilder* m_meshBuilder; // 0x04 - undefined4 m_unk0x08; // 0x08 + unsigned int m_flags; // 0x08 }; #endif // VIEWLOD_H diff --git a/LEGO1/viewmanager/viewmanager.cpp b/LEGO1/viewmanager/viewmanager.cpp index 9ec2da58..a6f4aaba 100644 --- a/LEGO1/viewmanager/viewmanager.cpp +++ b/LEGO1/viewmanager/viewmanager.cpp @@ -165,7 +165,7 @@ void ViewManager::UpdateROIDetailBasedOnLOD(ViewROI* p_roi, int p_lodLevel) if (lodLevel < 0) { lod = (ViewLOD*) p_roi->GetLOD(p_lodLevel); - if (lod->GetUnknown0x08() & ViewLOD::c_bit4) { + if (lod->GetFlags() & ViewLOD::c_hasMesh) { scene->Add(group); SetAppData(p_roi, reinterpret_cast(p_roi)); } @@ -184,7 +184,7 @@ void ViewManager::UpdateROIDetailBasedOnLOD(ViewROI* p_roi, int p_lodLevel) lod = (ViewLOD*) p_roi->GetLOD(p_lodLevel); } - if (lod->GetUnknown0x08() & ViewLOD::c_bit4) { + if (lod->GetFlags() & ViewLOD::c_hasMesh) { meshBuilder = lod->GetMeshBuilder(); if (meshBuilder != NULL) { @@ -235,7 +235,7 @@ inline void ViewManager::ManageVisibilityAndDetailRecursively(ViewROI* p_from, i if (p_from->GetWorldBoundingSphere().Radius() > 0.001F) { float projectedSize = ProjectedSize(p_from->GetWorldBoundingSphere()); - if (projectedSize < seconds_allowed * g_viewDistance) { + if (RealtimeView::GetUserMaxLOD() <= 5.0f && projectedSize < seconds_allowed * g_viewDistance) { if (p_from->GetLodLevel() != ViewROI::c_lodLevelInvisible) { ManageVisibilityAndDetailRecursively(p_from, ViewROI::c_lodLevelInvisible); } @@ -361,7 +361,7 @@ inline int ViewManager::CalculateLODLevel(float p_maximumScale, float p_initialS assert(from); if (GetFirstLODIndex(from) != 0) { - if (p_maximumScale < g_minLODThreshold) { + if (RealtimeView::GetUserMaxLOD() <= 5.0f && p_maximumScale < g_minLODThreshold) { return 0; } else { @@ -389,7 +389,7 @@ inline int ViewManager::GetFirstLODIndex(ViewROI* p_roi) const LODListBase* lods = p_roi->GetLODs(); if (lods != NULL && lods->Size() > 0) { - if (((ViewLOD*) p_roi->GetLOD(0))->GetUnknown0x08Test8()) { + if (((ViewLOD*) p_roi->GetLOD(0))->IsExtraLOD()) { return 1; } else { @@ -404,7 +404,7 @@ inline int ViewManager::GetFirstLODIndex(ViewROI* p_roi) const LODListBase* lods = ((ViewROI*) *it)->GetLODs(); if (lods != NULL && lods->Size() > 0) { - if (((ViewLOD*) ((ViewROI*) *it)->GetLOD(0))->GetUnknown0x08Test8()) { + if (((ViewLOD*) ((ViewROI*) *it)->GetLOD(0))->IsExtraLOD()) { return 1; } else { diff --git a/README.md b/README.md index 33dbd232..95237c85 100644 --- a/README.md +++ b/README.md @@ -4,22 +4,31 @@ This initiative is a portable version of LEGO Island (Version 1.1, English) based on the [decompilation project](https://github.com/isledecomp/isle). Our primary goal is to transform the codebase to achieve platform independence, thereby enhancing compatibility across various systems while preserving the original game's experience as faithfully as possible. -Please note: this project is dedicated to achieving platform independence without altering the core gameplay, adding new features, enhancing visual quality, or rewriting code for improvement's sake. While those are worthwhile objectives, they are not within the scope of this project. +Please note: this project is primarily dedicated to achieving platform independence without altering the core gameplay or rewriting code for improvement's sake. While those are worthwhile objectives, they are not within the scope of this project. `isle-portable` offers support for light modding using [`extensions`](/extensions). ## Status -### Supported platforms - | Platform | Status | | - | - | | Windows | [![CI](https://github.com/isledecomp/isle-portable/actions/workflows/ci.yml/badge.svg)](https://github.com/isledecomp/isle-portable/actions/workflows/ci.yml) | | Linux | [![CI](https://github.com/isledecomp/isle-portable/actions/workflows/ci.yml/badge.svg)](https://github.com/isledecomp/isle-portable/actions/workflows/ci.yml) | | macOS | [![CI](https://github.com/isledecomp/isle-portable/actions/workflows/ci.yml/badge.svg)](https://github.com/isledecomp/isle-portable/actions/workflows/ci.yml) | | [Web](https://isle.pizza) | [![CI](https://github.com/isledecomp/isle-portable/actions/workflows/ci.yml/badge.svg)](https://github.com/isledecomp/isle-portable/actions/workflows/ci.yml) | +| Nintendo 3DS | [![CI](https://github.com/isledecomp/isle-portable/actions/workflows/ci.yml/badge.svg)](https://github.com/isledecomp/isle-portable/actions/workflows/ci.yml) | +| Xbox One | [![CI](https://github.com/isledecomp/isle-portable/actions/workflows/ci.yml/badge.svg)](https://github.com/isledecomp/isle-portable/actions/workflows/ci.yml) | +| iOS | [![CI](https://github.com/isledecomp/isle-portable/actions/workflows/ci.yml/badge.svg)](https://github.com/isledecomp/isle-portable/actions/workflows/ci.yml) | We are actively working to support more platforms. If you have experience with a particular platform, we encourage you to contribute to `isle-portable`. You can find a [list of ongoing efforts](https://github.com/isledecomp/isle-portable/wiki/Work%E2%80%90in%E2%80%90progress-ports) in our Wiki. -### Library substitutions +## Usage + +**An existing copy of LEGO Island is required to use this project.** + +As it stands, builds provided in the [Releases tab](https://github.com/isledecomp/isle-portable/releases/tag/continuous) are mainly for developers; as such, they may not work properly for all end-users. Work is currently ongoing to create workable release builds ready for gameplay and general use by end-users. If you are technically inclined, you may find it easiest to compile the project yourself to get it running at this current point in time. + +[Installation instructions](https://github.com/isledecomp/isle-portable/wiki/Installation) for some ports can be found in our Wiki. + +## Library substitutions To achieve our goal of platform independence, we need to replace any Windows-only libraries with platform-independent alternatives. This ensures that our codebase remains versatile and compatible across various systems. The following table serves as an overview of major libraries / subsystems and their chosen replacements. For any significant changes or additions, it's recommended to discuss them with the team on the Matrix chat first to ensure consistency and alignment with our project's objectives. @@ -42,12 +51,6 @@ To achieve our goal of platform independence, we need to replace any Windows-onl This project uses the [CMake](https://cmake.org/) build system, which allows for a high degree of versatility regarding compilers and development environments. Please refer to the [GitHub action](/.github/workflows//ci.yml) for guidance. -## Usage - -**An existing copy of LEGO Island is required to use this project.** - -As it stands, the builds provided in the Releases tab are for developers; as such, they may not work properly for end-users. Work is currently ongoing to create workable release builds ready for gameplay and general use by end-users. If you are technically inclined, you may find it easiest to compile the project yourself to get it running at this current point in time. - ## Contributing If you're interested in helping or contributing to this project, check out the [CONTRIBUTING](/CONTRIBUTING.md) page. diff --git a/docker/emscripten/Dockerfile b/docker/emscripten/Dockerfile new file mode 100644 index 00000000..40c17cce --- /dev/null +++ b/docker/emscripten/Dockerfile @@ -0,0 +1,45 @@ +FROM emscripten/emsdk:4.0.10 AS builder + +ARG CMAKE_VERSION=3.29.3 + +WORKDIR /src + +USER root + +RUN apt-get update && apt-get install -y git wget && rm -rf /var/lib/apt/lists/* +RUN wget https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/cmake-${CMAKE_VERSION}-Linux-x86_64.sh -O /tmp/cmake.sh && \ + chmod +x /tmp/cmake.sh && \ + /tmp/cmake.sh --skip-license --prefix=/usr/local && \ + rm /tmp/cmake.sh + +RUN chown -R emscripten:emscripten /src + +USER emscripten + +COPY ISLE/emscripten/emscripten.patch /tmp/ +RUN cd /emsdk/upstream/emscripten && \ + git apply --check /tmp/emscripten.patch && \ + git apply /tmp/emscripten.patch + +COPY --chown=emscripten:emscripten 3rdparty/ ./3rdparty/ +COPY --chown=emscripten:emscripten LEGO1/ ./LEGO1/ +COPY --chown=emscripten:emscripten ISLE/ ./ISLE/ +COPY --chown=emscripten:emscripten miniwin/ ./miniwin/ +COPY --chown=emscripten:emscripten util/ ./util/ +COPY --chown=emscripten:emscripten CMake/ ./CMake/ +COPY --chown=emscripten:emscripten packaging/ ./packaging/ +COPY --chown=emscripten:emscripten extensions/ ./extensions/ +COPY --chown=emscripten:emscripten CMakeLists.txt . + +RUN emcmake cmake -S . -B build -DISLE_BUILD_CONFIG=OFF -DISLE_DEBUG=OFF -DCMAKE_BUILD_TYPE=Release -DISLE_EMSCRIPTEN_HOST=/assets && \ + emmake cmake --build build -j 32 + +RUN echo "Fetching isle.pizza frontend..."; \ + git clone --depth 1 https://github.com/isledecomp/isle.pizza /tmp/isle.pizza; + +FROM openresty/openresty:alpine + +COPY docker/emscripten/nginx.conf /usr/local/openresty/nginx/conf/nginx.conf +COPY --from=builder /tmp/isle.pizza /usr/local/openresty/nginx/html +COPY --from=builder /src/build/isle.* /usr/local/openresty/nginx/html +EXPOSE 6931 diff --git a/docker/emscripten/nginx.conf b/docker/emscripten/nginx.conf new file mode 100644 index 00000000..cbd53d25 --- /dev/null +++ b/docker/emscripten/nginx.conf @@ -0,0 +1,82 @@ +events { + worker_connections 1024; +} + +http { + init_by_lua_block { + function find_entry_in_dir(parent_dir, name_to_find) + local safe_parent_dir = string.gsub(parent_dir, "'", "'\\''") + local lower_name_to_find = string.lower(name_to_find) + local pipe = io.popen("ls -A '" .. safe_parent_dir .. "' 2>/dev/null") + if not pipe then return nil end + + for entry in pipe:lines() do + if string.lower(entry) == lower_name_to_find then + pipe:close() + return entry + end + end + pipe:close() + return nil + end + + function find_recursive_path(path_to_check) + local current_resolved_path = "/" + + for component in string.gmatch(path_to_check, "([^/]+)") do + local found_entry = find_entry_in_dir(current_resolved_path, component) + if not found_entry then + return nil + end + + if current_resolved_path == "/" then + current_resolved_path = current_resolved_path .. found_entry + else + current_resolved_path = current_resolved_path .. "/" .. found_entry + end + end + return current_resolved_path + end + } + + include /usr/local/openresty/nginx/conf/mime.types; + + server { + listen 6931; + server_name localhost; + + add_header 'Cross-Origin-Embedder-Policy' 'require-corp'; + add_header 'Cross-Origin-Opener-Policy' 'same-origin'; + add_header 'Cross-Origin-Resource-Policy' 'cross-origin'; + + location / { + root /usr/local/openresty/nginx/html; + index index.html isle.html; + try_files $uri $uri/ =404; + } + + location /assets/ { + content_by_lua_block { + local request_uri = ngx.var.uri + local resolved_path = find_recursive_path(request_uri) + + if not resolved_path then + local fallback_uri = ngx.re.sub(request_uri, [[^/assets/]], "/assets/DATA/disk/", "i") + resolved_path = find_recursive_path(fallback_uri) + end + + if resolved_path then + ngx.exec("/internal" .. resolved_path) + else + ngx.exit(ngx.HTTP_NOT_FOUND) + end + } + } + + location /internal/assets/ { + internal; + root /; + rewrite ^/internal(.*)$ $1 break; + } + } +} diff --git a/docker/emscripten/ssl_example/Caddyfile b/docker/emscripten/ssl_example/Caddyfile new file mode 100644 index 00000000..a5fc9766 --- /dev/null +++ b/docker/emscripten/ssl_example/Caddyfile @@ -0,0 +1,3 @@ +https://localhost:6932 { + reverse_proxy app:6931 +} diff --git a/docker/emscripten/ssl_example/docker-compose.yml b/docker/emscripten/ssl_example/docker-compose.yml new file mode 100644 index 00000000..84e88ea9 --- /dev/null +++ b/docker/emscripten/ssl_example/docker-compose.yml @@ -0,0 +1,18 @@ +services: + app: + image: ghcr.io/isledecomp/isle-portable-emscripten:master + ports: + - "6931:6931" + volumes: + - ${ASSETS_PATH}:/assets + + caddy: + image: caddy:latest + ports: + - "6932:6932" + volumes: + - ./Caddyfile:/etc/caddy/Caddyfile + - caddy_data:/data + +volumes: + caddy_data: \ No newline at end of file diff --git a/extensions/include/extensions/extensions.h b/extensions/include/extensions/extensions.h new file mode 100644 index 00000000..6c6f4f99 --- /dev/null +++ b/extensions/include/extensions/extensions.h @@ -0,0 +1,29 @@ +#pragma once + +#include "lego1_export.h" + +#include +#include +#include +#include + +namespace Extensions +{ +constexpr const char* availableExtensions[] = {"extensions:texture loader"}; + +LEGO1_EXPORT void Enable(const char* p_key, std::map p_options); + +template +struct Extension { + template + static auto Call(Function&& function, Args&&... args) -> std::optional> + { +#ifdef EXTENSIONS + if (T::enabled) { + return std::invoke(std::forward(function), std::forward(args)...); + } +#endif + return std::nullopt; + } +}; +}; // namespace Extensions diff --git a/extensions/include/extensions/textureloader.h b/extensions/include/extensions/textureloader.h new file mode 100644 index 00000000..a318c9b8 --- /dev/null +++ b/extensions/include/extensions/textureloader.h @@ -0,0 +1,34 @@ +#pragma once + +#include "extensions/extensions.h" +#include "legotextureinfo.h" + +#include +#include +#include + +namespace Extensions +{ +class TextureLoader { +public: + static void Initialize(); + static bool PatchTexture(LegoTextureInfo* p_textureInfo); + + static std::map options; + static std::vector excludedFiles; + static bool enabled; + + static constexpr std::array, 1> defaults = { + {{"texture loader:texture path", "/textures"}} + }; + +private: + static SDL_Surface* FindTexture(const char* p_name); +}; + +#ifdef EXTENSIONS +constexpr auto PatchTexture = &TextureLoader::PatchTexture; +#else +constexpr decltype(&TextureLoader::PatchTexture) PatchTexture = nullptr; +#endif +}; // namespace Extensions diff --git a/extensions/src/extensions.cpp b/extensions/src/extensions.cpp new file mode 100644 index 00000000..779c0547 --- /dev/null +++ b/extensions/src/extensions.cpp @@ -0,0 +1,21 @@ +#include "extensions/extensions.h" + +#include "extensions/textureloader.h" + +#include + +void Extensions::Enable(const char* p_key, std::map p_options) +{ + for (const char* key : availableExtensions) { + if (!SDL_strcasecmp(p_key, key)) { + if (!SDL_strcasecmp(p_key, "extensions:texture loader")) { + TextureLoader::options = std::move(p_options); + TextureLoader::enabled = true; + TextureLoader::Initialize(); + } + + SDL_Log("Enabled extension: %s", p_key); + break; + } + } +} diff --git a/extensions/src/textureloader.cpp b/extensions/src/textureloader.cpp new file mode 100644 index 00000000..3fbf0f7d --- /dev/null +++ b/extensions/src/textureloader.cpp @@ -0,0 +1,117 @@ +#include "extensions/textureloader.h" + +using namespace Extensions; + +std::map TextureLoader::options; +std::vector TextureLoader::excludedFiles; +bool TextureLoader::enabled = false; + +void TextureLoader::Initialize() +{ + for (const auto& option : defaults) { + if (!options.count(option.first.data())) { + options[option.first.data()] = option.second; + } + } +} + +bool TextureLoader::PatchTexture(LegoTextureInfo* p_textureInfo) +{ + SDL_Surface* surface = FindTexture(p_textureInfo->m_name); + if (!surface) { + return false; + } + + const SDL_PixelFormatDetails* details = SDL_GetPixelFormatDetails(surface->format); + + DDSURFACEDESC desc; + memset(&desc, 0, sizeof(desc)); + desc.dwSize = sizeof(desc); + desc.dwFlags = DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS; + desc.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_SYSTEMMEMORY; + desc.ddpfPixelFormat.dwSize = sizeof(desc.ddpfPixelFormat); + desc.dwWidth = surface->w; + desc.dwHeight = surface->h; + desc.ddpfPixelFormat.dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS; + desc.ddpfPixelFormat.dwRGBBitCount = details->bits_per_pixel; + desc.ddpfPixelFormat.dwRBitMask = details->Rmask; + desc.ddpfPixelFormat.dwGBitMask = details->Gmask; + desc.ddpfPixelFormat.dwBBitMask = details->Bmask; + desc.ddpfPixelFormat.dwRGBAlphaBitMask = details->Amask; + + LPDIRECTDRAW pDirectDraw = VideoManager()->GetDirect3D()->DirectDraw(); + if (pDirectDraw->CreateSurface(&desc, &p_textureInfo->m_surface, NULL) != DD_OK) { + SDL_DestroySurface(surface); + return false; + } + + memset(&desc, 0, sizeof(desc)); + desc.dwSize = sizeof(desc); + + if (p_textureInfo->m_surface->Lock(NULL, &desc, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WRITEONLY, NULL) != DD_OK) { + SDL_DestroySurface(surface); + return false; + } + + MxU8* dst = (MxU8*) desc.lpSurface; + Uint8* srcPixels = (Uint8*) surface->pixels; + + if (details->bits_per_pixel == 8) { + SDL_Palette* sdlPalette = SDL_GetSurfacePalette(surface); + if (!sdlPalette) { + SDL_DestroySurface(surface); + return false; + } + + PALETTEENTRY entries[256]; + for (int i = 0; i < sdlPalette->ncolors; ++i) { + entries[i].peRed = sdlPalette->colors[i].r; + entries[i].peGreen = sdlPalette->colors[i].g; + entries[i].peBlue = sdlPalette->colors[i].b; + entries[i].peFlags = PC_NONE; + } + + LPDIRECTDRAWPALETTE ddPalette = nullptr; + if (pDirectDraw->CreatePalette(DDPCAPS_8BIT | DDPCAPS_ALLOW256, entries, &ddPalette, NULL) != DD_OK) { + SDL_DestroySurface(surface); + return false; + } + + p_textureInfo->m_surface->SetPalette(ddPalette); + ddPalette->Release(); + } + + memcpy(dst, srcPixels, surface->pitch * surface->h); + p_textureInfo->m_surface->Unlock(desc.lpSurface); + p_textureInfo->m_palette = NULL; + + if (((TglImpl::RendererImpl*) VideoManager()->GetRenderer()) + ->CreateTextureFromSurface(p_textureInfo->m_surface, &p_textureInfo->m_texture) != D3DRM_OK) { + SDL_DestroySurface(surface); + return false; + } + + p_textureInfo->m_texture->SetAppData((LPD3DRM_APPDATA) p_textureInfo); + SDL_DestroySurface(surface); + return true; +} + +SDL_Surface* TextureLoader::FindTexture(const char* p_name) +{ + if (std::find(excludedFiles.begin(), excludedFiles.end(), p_name) != excludedFiles.end()) { + return nullptr; + } + + SDL_Surface* surface; + const char* texturePath = options["texture loader:texture path"].c_str(); + MxString path = MxString(MxOmni::GetHD()) + texturePath + "/" + p_name + ".bmp"; + + path.MapPathToFilesystem(); + if (!(surface = SDL_LoadBMP(path.GetData()))) { + path = MxString(MxOmni::GetCD()) + texturePath + "/" + p_name + ".bmp"; + path.MapPathToFilesystem(); + surface = SDL_LoadBMP(path.GetData()); + } + + return surface; +} diff --git a/miniwin/CMakeLists.txt b/miniwin/CMakeLists.txt index a1939441..615832cf 100644 --- a/miniwin/CMakeLists.txt +++ b/miniwin/CMakeLists.txt @@ -19,45 +19,87 @@ add_library(miniwin STATIC EXCLUDE_FROM_ALL src/d3drm/d3drmmesh.cpp src/d3drm/d3drmtexture.cpp src/d3drm/d3drmviewport.cpp + src/d3drm/d3drmrenderer.cpp src/internal/meshutils.cpp - - # D3DRM backends - src/d3drm/backends/sdl3gpu/renderer.cpp - src/d3drm/backends/sdl3gpu/shaders/generated/ShaderIndex.cpp - src/d3drm/backends/software/renderer.cpp ) target_compile_definitions(miniwin PRIVATE $<$:DEBUG> ) -find_package(OpenGL) -find_package(GLEW) -if(OpenGL_FOUND AND GLEW_FOUND) - message(STATUS "Found OpenGL and GLEW: enabling OpenGL 1.x renderer") - target_sources(miniwin PRIVATE src/d3drm/backends/opengl1/renderer.cpp) - target_compile_definitions(miniwin PRIVATE USE_OPENGL1) - target_link_libraries(miniwin PRIVATE OpenGL::GL GLEW::GLEW) -else() - message(STATUS "🧩 OpenGL 1.x support not enabled — needs OpenGL and GLEW") +list(APPEND GRAPHICS_BACKENDS USE_SOFTWARE_RENDER) +list(APPEND GRAPHICS_BACKENDS USE_SDL_GPU) + +if(NOT WINDOWS_STORE) + find_package(OpenGL) + if(OpenGL_FOUND) + message(STATUS "Found OpenGL: enabling OpenGL 1.x renderer") + target_sources(miniwin PRIVATE + src/d3drm/backends/opengl1/actual.cpp + src/d3drm/backends/opengl1/renderer.cpp + ) + list(APPEND GRAPHICS_BACKENDS USE_OPENGL1) + target_link_libraries(miniwin PRIVATE OpenGL::GL) + else() + message(STATUS "🧩 OpenGL 1.x support not enabled — needs OpenGL") + endif() + + find_library(OPENGL_ES3_LIBRARY NAMES GLESv2) + if(EMSCRIPTEN OR OPENGL_ES3_LIBRARY) + message(STATUS "Found OpenGL: enabling OpenGL ES 3.x renderer") + target_sources(miniwin PRIVATE src/d3drm/backends/opengles3/renderer.cpp) + list(APPEND GRAPHICS_BACKENDS USE_OPENGLES3) + if(OPENGL_ES3_LIBRARY) + target_link_libraries(miniwin PRIVATE ${OPENGL_ES3_LIBRARY}) + endif() + else() + message(STATUS "🧩 OpenGL ES 3.x support not enabled") + endif() endif() -find_library(OPENGL_ES2_LIBRARY NAMES GLESv2) -if(OPENGL_ES2_LIBRARY) - message(STATUS "Found OpenGL: enabling OpenGL ES 2.x renderer") - target_sources(miniwin PRIVATE src/d3drm/backends/opengles2/renderer.cpp) - target_compile_definitions(miniwin PRIVATE USE_OPENGLES2) - target_link_libraries(miniwin PRIVATE OpenGL::GL) -else() - message(STATUS "🧩 OpenGL ES 2.x support not enabled") + +if(NINTENDO_3DS) + if(ISLE_DEBUG) + find_library(CITRO3D_LIBRARY NAMES citro3dd) + else() + find_library(CITRO3D_LIBRARY NAMES citro3d) + endif() + if(CITRO3D_LIBRARY) + message(STATUS "Found citro3d: enabling Citro3D renderer") + target_sources(miniwin PRIVATE src/d3drm/backends/citro3d/renderer.cpp) + ctr_add_shader_library(vshader src/d3drm/backends/citro3d/vshader.v.pica) + dkp_add_embedded_binary_library(3ds_shaders vshader) + target_link_libraries(miniwin PRIVATE ${CITRO3D_LIBRARY} 3ds_shaders) + list(APPEND GRAPHICS_BACKENDS USE_CITRO3D) + else() + message(STATUS "🧩 Citro3D support not enabled") + endif() endif() -if(WIN32) +if(WIN32 AND NOT WINDOWS_STORE) target_sources(miniwin PRIVATE src/d3drm/backends/directx9/actual.cpp src/d3drm/backends/directx9/renderer.cpp ) target_link_libraries(miniwin PRIVATE d3d9) + list(APPEND GRAPHICS_BACKENDS USE_DIRECTX9) +endif() + +if(WINDOWS_STORE) + add_compile_definitions(WINDOWS_STORE) +endif() + +if(USE_SDL_GPU IN_LIST GRAPHICS_BACKENDS) + target_sources(miniwin PRIVATE + src/d3drm/backends/sdl3gpu/renderer.cpp + src/d3drm/backends/sdl3gpu/shaders/generated/ShaderIndex.cpp + ) +endif() + +if(USE_SOFTWARE_RENDER IN_LIST GRAPHICS_BACKENDS) + target_sources(miniwin PRIVATE + src/d3drm/backends/software/renderer.cpp + ) endif() target_compile_definitions(miniwin PUBLIC MINIWIN) @@ -71,6 +113,9 @@ target_link_libraries(miniwin PUBLIC miniwin-headers) target_link_libraries(miniwin PRIVATE SDL3::SDL3) +target_compile_definitions(miniwin PUBLIC ${GRAPHICS_BACKENDS}) + + # Shader stuff set(shader_src_dir "${CMAKE_CURRENT_SOURCE_DIR}/src/d3drm/backends/sdl3gpu/shaders/src") diff --git a/miniwin/include/miniwin/ddraw.h b/miniwin/include/miniwin/ddraw.h index 1e3fd17f..912a1b9f 100644 --- a/miniwin/include/miniwin/ddraw.h +++ b/miniwin/include/miniwin/ddraw.h @@ -143,9 +143,12 @@ enum class DDBltFlags : uint32_t { }; ENABLE_BITMASK_OPERATORS(DDBltFlags) +#define DDPF_ALPHAPIXELS DDPixelFormatFlags::ALPHAPIXELS #define DDPF_PALETTEINDEXED8 DDPixelFormatFlags::PALETTEINDEXED8 #define DDPF_RGB DDPixelFormatFlags::RGB +#define DDPF_ALPHAPIXELS DDPixelFormatFlags::ALPHAPIXELS enum class DDPixelFormatFlags : uint32_t { + ALPHAPIXELS = 1 << 0, // dwRGBAlphaBitMask is valid PALETTEINDEXED8 = 1 << 5, // The texture uses an 8 bit palette RGB = 1 << 6, // dwRGBBitCount, dwRBitMask, dwGBitMask, and dwBBitMask is valid }; @@ -162,9 +165,11 @@ ENABLE_BITMASK_OPERATORS(DDBltFastFlags) #define DDLOCK_SURFACEMEMORYPTR DDLockFlags::SURFACEMEMORYPTR #define DDLOCK_WAIT DDLockFlags::WAIT #define DDLOCK_WRITEONLY DDLockFlags::WRITEONLY +#define DDLOCK_READONLY DDLockFlags::READONLY enum class DDLockFlags : uint32_t { SURFACEMEMORYPTR = 0, WAIT = 1 << 0, + READONLY = 1 << 4, WRITEONLY = 1 << 5, }; ENABLE_BITMASK_OPERATORS(DDLockFlags) @@ -246,9 +251,13 @@ struct DDSCAPS { }; typedef struct DDSCAPS* LPDDSCAPS; +#define DDBLTFX_NOTEARING DDBLTFXFlags::NOTEARING +enum class DDBLTFXFlags : uint8_t { + NOTEARING = 1 << 3, +}; struct DDBLTFX { DWORD dwSize; - DWORD dwDDFX; + DDBLTFXFlags dwDDFX; DWORD dwROP; DWORD dwFillColor; }; diff --git a/miniwin/include/miniwin/miniwind3d.h b/miniwin/include/miniwin/miniwind3d.h new file mode 100644 index 00000000..aea2e25c --- /dev/null +++ b/miniwin/include/miniwin/miniwind3d.h @@ -0,0 +1,10 @@ +#pragma once + +DEFINE_GUID(IID_IDirect3DMiniwin, 0xf8a97f2d, 0x9b3a, 0x4f1c, 0x9e, 0x8d, 0x6a, 0x5b, 0x4c, 0x3d, 0x2e, 0x1f); + +struct IDirect3DMiniwin : virtual public IUnknown { + virtual HRESULT RequestMSAA(DWORD msaaSamples) = 0; + virtual DWORD GetMSAASamples() const = 0; + virtual HRESULT RequestAnisotropic(float anisotropic) = 0; + virtual float GetAnisotropic() const = 0; +}; diff --git a/miniwin/include/miniwin/miniwindevice.h b/miniwin/include/miniwin/miniwindevice.h index 00329393..de28e76a 100644 --- a/miniwin/include/miniwin/miniwindevice.h +++ b/miniwin/include/miniwin/miniwindevice.h @@ -6,4 +6,5 @@ DEFINE_GUID(IID_IDirect3DRMMiniwinDevice, 0x6eb09673, 0x8d30, 0x4d8a, 0x8d, 0x81 struct IDirect3DRMMiniwinDevice : virtual public IUnknown { virtual bool ConvertEventToRenderCoordinates(SDL_Event* event) = 0; + virtual bool ConvertRenderToWindowCoordinates(Sint32 inX, Sint32 inY, Sint32& outX, Sint32& outY) = 0; }; diff --git a/miniwin/include/miniwin/windows.h b/miniwin/include/miniwin/windows.h index 83726998..46bfd43c 100644 --- a/miniwin/include/miniwin/windows.h +++ b/miniwin/include/miniwin/windows.h @@ -169,37 +169,6 @@ int WINAPI GetDeviceCaps(HDC hdc, int index); BOOL RedrawWindow(void* hWnd, const void* lprcUpdate, void* hrgnUpdate, unsigned int flags); -int SetBkColor(void*, int); - -int SetBkMode(void*, int); - -int SetTextColor(HDC hdc, int color); - -BOOL GetTextExtentPoint(HDC hdc, LPCSTR lpString, int c, SIZE* psizl); - -int ExtTextOut(HDC, int, int, unsigned int, const RECT*, LPCSTR, unsigned int, void*); - -HFONT CreateFont( - int, - int, - int, - int, - int, - unsigned int, - unsigned int, - unsigned int, - unsigned int, - unsigned int, - unsigned int, - unsigned int, - unsigned int, - LPCSTR -); - -void* SelectObject(HDC, HFONT); - -int GetTextExtentPoint32(HDC hdc, LPCSTR str, int len, SIZE* out); - HMENU GetMenu(HWND hWnd); int DrawMenuBar(void* hWnd); diff --git a/miniwin/src/d3drm/backends/citro3d/renderer.cpp b/miniwin/src/d3drm/backends/citro3d/renderer.cpp new file mode 100644 index 00000000..a82f1238 --- /dev/null +++ b/miniwin/src/d3drm/backends/citro3d/renderer.cpp @@ -0,0 +1,687 @@ +#include "d3drmrenderer.h" +#include "d3drmrenderer_citro3d.h" +#include "d3drmtexture_impl.h" +#include "ddraw_impl.h" +#include "meshutils.h" +#include "miniwin.h" +#include "vshader_shbin.h" + +#include + +static bool g_rendering = false; + +static DVLB_s* vshader_dvlb; +static shaderProgram_s program; +static int uLoc_projection; +static int uLoc_modelView; +static int uLoc_meshColor; +static int uLoc_lightVec; +static int uLoc_lightClr; +static int uLoc_shininess; + +Citro3DRenderer::Citro3DRenderer(DWORD width, DWORD height) +{ + m_width = 320; + m_height = 240; + m_virtualWidth = width; + m_virtualHeight = height; + + gfxSetScreenFormat(GFX_BOTTOM, GSP_BGR8_OES); + consoleInit(GFX_TOP, nullptr); + C3D_Init(C3D_DEFAULT_CMDBUF_SIZE); + + m_renderTarget = C3D_RenderTargetCreate(m_height, m_width, GPU_RB_RGBA8, GPU_RB_DEPTH24_STENCIL8); + C3D_RenderTargetSetOutput( + m_renderTarget, + GFX_BOTTOM, + GFX_LEFT, + GX_TRANSFER_FLIP_VERT(0) | GX_TRANSFER_OUT_TILED(0) | GX_TRANSFER_RAW_COPY(0) | + GX_TRANSFER_IN_FORMAT(GX_TRANSFER_FMT_RGBA8) | GX_TRANSFER_OUT_FORMAT(GX_TRANSFER_FMT_RGB8) | + GX_TRANSFER_SCALING(GX_TRANSFER_SCALE_NO) + ); + + vshader_dvlb = DVLB_ParseFile((u32*) vshader_shbin, vshader_shbin_size); + shaderProgramInit(&program); + shaderProgramSetVsh(&program, &vshader_dvlb->DVLE[0]); + C3D_BindProgram(&program); + + C3D_CullFace(GPU_CULL_FRONT_CCW); + + uLoc_projection = shaderInstanceGetUniformLocation(program.vertexShader, "projection"); + uLoc_modelView = shaderInstanceGetUniformLocation(program.vertexShader, "modelView"); + uLoc_meshColor = shaderInstanceGetUniformLocation(program.vertexShader, "meshColor"); + uLoc_lightVec = shaderInstanceGetUniformLocation(program.vertexShader, "lightVec"); + uLoc_lightClr = shaderInstanceGetUniformLocation(program.vertexShader, "lightClr"); + uLoc_shininess = shaderInstanceGetUniformLocation(program.vertexShader, "shininess"); + + C3D_AttrInfo* attrInfo = C3D_GetAttrInfo(); + AttrInfo_Init(attrInfo); + AttrInfo_AddLoader(attrInfo, 0, GPU_FLOAT, 3); // v0=position + AttrInfo_AddLoader(attrInfo, 1, GPU_FLOAT, 3); // v2=normal + AttrInfo_AddLoader(attrInfo, 2, GPU_FLOAT, 2); // v1=texcoord +} + +Citro3DRenderer::~Citro3DRenderer() +{ + shaderProgramFree(&program); + DVLB_Free(vshader_dvlb); + C3D_Fini(); +} + +void Citro3DRenderer::PushLights(const SceneLight* lights, size_t count) +{ + m_lights.assign(lights, lights + count); +} + +void Citro3DRenderer::SetProjection(const D3DRMMATRIX4D& projection, D3DVALUE front, D3DVALUE back) +{ + memcpy(&m_projection, projection, sizeof(D3DRMMATRIX4D)); +} + +void Citro3DRenderer::SetFrustumPlanes(const Plane* frustumPlanes) +{ +} + +struct Citro3DCacheDestroyContext { + Citro3DRenderer* renderer; + Uint32 id; +}; + +void Citro3DRenderer::AddTextureDestroyCallback(Uint32 id, IDirect3DRMTexture* texture) +{ + auto* ctx = new Citro3DCacheDestroyContext{this, id}; + texture->AddDestroyCallback( + [](IDirect3DRMObject* obj, void* arg) { + auto* ctx = static_cast(arg); + auto& entry = ctx->renderer->m_textures[ctx->id]; + if (entry.texture) { + C3D_TexDelete(&entry.c3dTex); + entry.texture = nullptr; + } + delete ctx; + }, + ctx + ); +} + +static int NearestPowerOfTwoClamp(int val) +{ + static const int sizes[] = {8, 16, 32, 64, 128, 256, 512}; + for (int size : sizes) { + if (val <= size) { + return size; + } + } + return 512; +} + +static SDL_Surface* ConvertAndResizeSurface(SDL_Surface* original, bool isUI, float scaleX, float scaleY) +{ + if (!isUI) { + return SDL_ConvertSurface(original, SDL_PIXELFORMAT_RGBA8888); + } + + scaleX = std::min(scaleX, 1.0f); + scaleY = std::min(scaleY, 1.0f); + + int scaledW = static_cast(original->w * scaleX); + int scaledH = static_cast(original->h * scaleY); + + int paddedW = NearestPowerOfTwoClamp(scaledW); + int paddedH = NearestPowerOfTwoClamp(scaledH); + + SDL_Surface* padded = SDL_CreateSurface(paddedW, paddedH, SDL_PIXELFORMAT_RGBA8888); + if (!padded) { + return nullptr; + } + + if (scaleX == 1.0f && scaleY == 1.0f) { + SDL_BlitSurface(original, nullptr, padded, nullptr); + } + else { + SDL_ScaleMode scaleMode = (scaleX >= 1.0f && scaleY >= 1.0f) ? SDL_SCALEMODE_NEAREST : SDL_SCALEMODE_LINEAR; + SDL_Rect dstRect = {0, 0, scaledW, scaledH}; + SDL_BlitSurfaceScaled(original, nullptr, padded, &dstRect, scaleMode); + } + + return padded; +} + +static void EncodeTextureLayout(const u8* src, u8* dst, int width, int height) +{ + const int tileSize = 8; + const int bytesPerPixel = 4; + + int tilesPerRow = (width + tileSize - 1) / tileSize; + + static const uint8_t mortonLUT[64] = {0, 1, 4, 5, 16, 17, 20, 21, 2, 3, 6, 7, 18, 19, 22, 23, + 8, 9, 12, 13, 24, 25, 28, 29, 10, 11, 14, 15, 26, 27, 30, 31, + 32, 33, 36, 37, 48, 49, 52, 53, 34, 35, 38, 39, 50, 51, 54, 55, + 40, 41, 44, 45, 56, 57, 60, 61, 42, 43, 46, 47, 58, 59, 62, 63}; + + for (int tileY = 0; tileY < height; tileY += tileSize) { + for (int tileX = 0; tileX < width; tileX += tileSize) { + int tileIndex = (tileY / tileSize) * tilesPerRow + (tileX / tileSize); + tileIndex *= tileSize * tileSize; + + for (int y = 0; y < tileSize; ++y) { + for (int x = 0; x < tileSize; ++x) { + int srcX = tileX + x; + int srcY = tileY + y; + + if (srcX >= width || srcY >= height) { + continue; + } + + int morton = mortonLUT[y * tileSize + x]; + int dstIndex = (tileIndex + morton) * bytesPerPixel; + int srcIndex = ((height - 1 - srcY) * width + srcX); + + *(u32*) &dst[dstIndex] = ((u32*) src)[srcIndex]; + } + } + } + } +} + +static bool ConvertAndUploadTexture(C3D_Tex* tex, SDL_Surface* originalSurface, bool isUI, float scaleX, float scaleY) +{ + SDL_Surface* resized = ConvertAndResizeSurface(originalSurface, isUI, scaleX, scaleY); + if (!resized) { + return false; + } + + int width = resized->w; + int height = resized->h; + + C3D_TexInitParams params = {}; + params.width = width; + params.height = height; + params.format = GPU_RGBA8; + params.maxLevel = isUI ? 0 : 4; + params.type = GPU_TEX_2D; + if (!C3D_TexInitWithParams(tex, nullptr, params)) { + if (resized != originalSurface) { + SDL_DestroySurface(resized); + } + return false; + } + + uint8_t* tiledData = (uint8_t*) malloc(width * height * 4); + if (!tiledData) { + if (resized != originalSurface) { + SDL_DestroySurface(resized); + } + return false; + } + + EncodeTextureLayout((const u8*) resized->pixels, tiledData, width, height); + if (resized != originalSurface) { + SDL_DestroySurface(resized); + } + + C3D_TexUpload(tex, tiledData); + free(tiledData); + + if (isUI) { + C3D_TexSetFilter(tex, GPU_NEAREST, GPU_NEAREST); + C3D_TexSetWrap(tex, GPU_CLAMP_TO_EDGE, GPU_CLAMP_TO_EDGE); + } + else { + C3D_TexSetFilter(tex, GPU_LINEAR, GPU_LINEAR); + C3D_TexSetWrap(tex, GPU_REPEAT, GPU_REPEAT); + C3D_TexSetFilterMipmap(tex, GPU_LINEAR); + C3D_TexGenerateMipmap(tex, GPU_TEXFACE_2D); + } + + return true; +} + +Uint32 Citro3DRenderer::GetTextureId(IDirect3DRMTexture* iTexture, bool isUI, float scaleX, float scaleY) +{ + auto texture = static_cast(iTexture); + auto surface = static_cast(texture->m_surface); + SDL_Surface* originalSurface = surface->m_surface; + + int originalW = originalSurface->w; + int originalH = originalSurface->h; + + for (Uint32 i = 0; i < m_textures.size(); ++i) { + auto& tex = m_textures[i]; + if (tex.texture == texture) { + if (tex.version != texture->m_version) { + C3D_TexDelete(&tex.c3dTex); + if (!ConvertAndUploadTexture( + &tex.c3dTex, + originalSurface, + isUI, + scaleX * m_viewportTransform.scale, + scaleY * m_viewportTransform.scale + )) { + return NO_TEXTURE_ID; + } + + tex.version = texture->m_version; + tex.width = NearestPowerOfTwoClamp(originalW * m_viewportTransform.scale); + tex.height = NearestPowerOfTwoClamp(originalH * m_viewportTransform.scale); + } + return i; + } + } + + C3DTextureCacheEntry entry; + entry.texture = texture; + entry.version = texture->m_version; + entry.width = NearestPowerOfTwoClamp(originalW * m_viewportTransform.scale); + entry.height = NearestPowerOfTwoClamp(originalH * m_viewportTransform.scale); + + if (!ConvertAndUploadTexture( + &entry.c3dTex, + originalSurface, + isUI, + scaleX * m_viewportTransform.scale, + scaleY * m_viewportTransform.scale + )) { + return NO_TEXTURE_ID; + } + + for (Uint32 i = 0; i < m_textures.size(); ++i) { + if (!m_textures[i].texture) { + m_textures[i] = std::move(entry); + AddTextureDestroyCallback(i, texture); + return i; + } + } + + m_textures.push_back(std::move(entry)); + AddTextureDestroyCallback((Uint32) (m_textures.size() - 1), texture); + return (Uint32) (m_textures.size() - 1); +} + +C3DMeshCacheEntry C3DUploadMesh(const MeshGroup& meshGroup) +{ + C3DMeshCacheEntry cache{&meshGroup, meshGroup.version}; + + std::vector vertexBuffer; + std::vector indexBuffer; + + if (meshGroup.quality == D3DRMRENDER_FLAT || meshGroup.quality == D3DRMRENDER_UNLITFLAT) { + FlattenSurfaces( + meshGroup.vertices.data(), + meshGroup.vertices.size(), + meshGroup.indices.data(), + meshGroup.indices.size(), + meshGroup.texture != nullptr, + vertexBuffer, + indexBuffer + ); + } + else { + vertexBuffer.assign(meshGroup.vertices.begin(), meshGroup.vertices.end()); + indexBuffer.assign(meshGroup.indices.begin(), meshGroup.indices.end()); + } + + // Flatten vertices as IBO is buggy on 3DS hardware + std::vector vertexUploadBuffer; + vertexUploadBuffer.reserve(indexBuffer.size()); + + for (size_t i = 0; i < indexBuffer.size(); ++i) { + vertexUploadBuffer.emplace_back(vertexBuffer[indexBuffer[i]]); + } + + size_t vertexBufferSize = vertexUploadBuffer.size() * sizeof(D3DRMVERTEX); + cache.vbo = linearAlloc(vertexBufferSize); + memcpy(cache.vbo, vertexUploadBuffer.data(), vertexBufferSize); + cache.vertexCount = vertexUploadBuffer.size(); + + return cache; +} + +void Citro3DRenderer::AddMeshDestroyCallback(Uint32 id, IDirect3DRMMesh* mesh) +{ + auto* ctx = new Citro3DCacheDestroyContext{this, id}; + mesh->AddDestroyCallback( + [](IDirect3DRMObject* obj, void* arg) { + auto* ctx = static_cast(arg); + auto& cacheEntry = ctx->renderer->m_meshs[ctx->id]; + if (cacheEntry.meshGroup) { + cacheEntry.meshGroup = nullptr; + linearFree(cacheEntry.vbo); + cacheEntry.vertexCount = 0; + } + delete ctx; + }, + ctx + ); +} + +Uint32 Citro3DRenderer::GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* meshGroup) +{ + for (Uint32 i = 0; i < m_meshs.size(); ++i) { + auto& cache = m_meshs[i]; + if (cache.meshGroup == meshGroup) { + if (cache.version != meshGroup->version) { + cache = std::move(C3DUploadMesh(*meshGroup)); + } + return i; + } + } + + auto newCache = C3DUploadMesh(*meshGroup); + + for (Uint32 i = 0; i < m_meshs.size(); ++i) { + auto& cache = m_meshs[i]; + if (!cache.meshGroup) { + cache = std::move(newCache); + AddMeshDestroyCallback(i, mesh); + return i; + } + } + + m_meshs.push_back(std::move(newCache)); + AddMeshDestroyCallback((Uint32) (m_meshs.size() - 1), mesh); + return (Uint32) (m_meshs.size() - 1); +} + +void Citro3DRenderer::StartFrame() +{ + if (g_rendering) { + return; + } + C3D_FrameBegin(C3D_FRAME_SYNCDRAW); + C3D_FrameDrawOn(m_renderTarget); + g_rendering = true; +} + +void ConvertPerspective(const D3DRMMATRIX4D in, C3D_Mtx* out) +{ + float f_h = in[0][0]; + float f_v = in[1][1]; + + float aspect = f_v / f_h; + float fovY = 2.0f * atanf(1.0f / f_v); + + float nearZ = -in[3][2] / in[2][2]; + float farZ = nearZ * in[2][2] / (in[2][2] - 1.0f); + + Mtx_PerspTilt(out, fovY, aspect, nearZ, farZ, true); +} + +HRESULT Citro3DRenderer::BeginFrame() +{ + StartFrame(); + C3D_DepthTest(true, GPU_GREATER, GPU_WRITE_ALL); + + C3D_Mtx projection; + ConvertPerspective(m_projection, &projection); + C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, uLoc_projection, &projection); + + for (const auto& light : m_lights) { + FColor lightColor = light.color; + if (light.positional == 0.0f && light.directional == 0.0f) { + // Ambient light + C3D_FVUnifSet(GPU_VERTEX_SHADER, uLoc_lightClr + 2, lightColor.r, lightColor.g, lightColor.b, 1.0f); + } + else if (light.directional == 1.0f) { + C3D_FVUnifSet( + GPU_VERTEX_SHADER, + uLoc_lightVec + 1, + -light.direction.x, + -light.direction.y, + -light.direction.z, + 0.0f + ); + C3D_FVUnifSet(GPU_VERTEX_SHADER, uLoc_lightClr + 1, lightColor.r, lightColor.g, lightColor.b, 0.0f); + } + else if (light.positional == 1.0f) { + C3D_FVUnifSet( + GPU_VERTEX_SHADER, + uLoc_lightVec + 0, + light.position.x, + light.position.y, + light.position.z, + 0.0f + ); + C3D_FVUnifSet(GPU_VERTEX_SHADER, uLoc_lightClr + 0, lightColor.r, lightColor.g, lightColor.b, 0.0f); + } + } + + return S_OK; +} + +void Citro3DRenderer::EnableTransparency() +{ + C3D_DepthTest(true, GPU_GREATER, GPU_WRITE_COLOR); +} + +void ConvertMatrix(const D3DRMMATRIX4D in, C3D_Mtx* out) +{ + for (int i = 0; i < 4; i++) { + out->r[i].x = in[0][i]; + out->r[i].y = in[1][i]; + out->r[i].z = in[2][i]; + out->r[i].w = in[3][i]; + } +} + +void SetMaterialAppearance( + const FColor& color, + float shininess, + int uLoc_meshColor, + int uLoc_shininess, + C3D_Tex* textures +) +{ + C3D_FVUnifSet(GPU_VERTEX_SHADER, uLoc_meshColor, color.r, color.g, color.b, color.a); + C3D_FVUnifSet(GPU_VERTEX_SHADER, uLoc_shininess, shininess, 0.0f, 0.0f, 0.0f); + + C3D_TexEnv* env = C3D_GetTexEnv(0); + C3D_TexEnvInit(env); + + if (textures) { + C3D_TexBind(0, textures); + C3D_TexEnvSrc(env, C3D_Both, GPU_TEXTURE0, GPU_PRIMARY_COLOR, GPU_PRIMARY_COLOR); + C3D_TexEnvFunc(env, C3D_Both, GPU_MODULATE); + } + else { + C3D_TexBind(0, nullptr); + C3D_TexEnvSrc(env, C3D_Both, GPU_PRIMARY_COLOR, GPU_PRIMARY_COLOR, GPU_PRIMARY_COLOR); + C3D_TexEnvFunc(env, C3D_Both, GPU_REPLACE); + } +} + +void Citro3DRenderer::SubmitDraw( + DWORD meshId, + const D3DRMMATRIX4D& modelViewMatrix, + const D3DRMMATRIX4D& worldMatrix, + const D3DRMMATRIX4D& viewMatrix, + const Matrix3x3& normalMatrix, + const Appearance& appearance +) +{ + C3D_Mtx modelView; + ConvertMatrix(modelViewMatrix, &modelView); + C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, uLoc_modelView, &modelView); + + auto& mesh = m_meshs[meshId]; + + C3D_BufInfo* bufInfo = C3D_GetBufInfo(); + BufInfo_Init(bufInfo); + BufInfo_Add(bufInfo, mesh.vbo, sizeof(D3DRMVERTEX), 3, 0x210); + + SetMaterialAppearance( + {appearance.color.r / 255.0f, + appearance.color.g / 255.0f, + appearance.color.b / 255.0f, + appearance.color.a / 255.0f}, + appearance.shininess, + uLoc_meshColor, + uLoc_shininess, + appearance.textureId != NO_TEXTURE_ID ? &m_textures[appearance.textureId].c3dTex : nullptr + ); + + C3D_DrawArrays(GPU_TRIANGLES, 0, mesh.vertexCount); +} + +HRESULT Citro3DRenderer::FinalizeFrame() +{ + return S_OK; +} + +void Citro3DRenderer::Resize(int width, int height, const ViewportTransform& viewportTransform) +{ + m_width = width; + m_height = height; + m_viewportTransform = viewportTransform; +} + +void Citro3DRenderer::Clear(float r, float g, float b) +{ + StartFrame(); + u32 color = + (static_cast(r * 255) << 24) | (static_cast(g * 255) << 16) | (static_cast(b * 255) << 8) | 255; + C3D_RenderTargetClear(m_renderTarget, C3D_CLEAR_ALL, color, 0); +} + +void Citro3DRenderer::Flip() +{ + C3D_FrameEnd(0); + gfxFlushBuffers(); + gspWaitForVBlank(); + g_rendering = false; +} + +void Citro3DRenderer::Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, const SDL_Rect& dstRect, FColor color) +{ + C3D_AlphaBlend(GPU_BLEND_ADD, GPU_BLEND_ADD, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); + StartFrame(); + C3D_DepthTest(false, GPU_GREATER, GPU_WRITE_COLOR); + + float left = -m_viewportTransform.offsetX / m_viewportTransform.scale; + float right = (m_width - m_viewportTransform.offsetX) / m_viewportTransform.scale; + float top = -m_viewportTransform.offsetY / m_viewportTransform.scale; + float bottom = (m_height - m_viewportTransform.offsetY) / m_viewportTransform.scale; + + C3D_Mtx projection, modelView; + Mtx_OrthoTilt(&projection, left, right, bottom, top, 0.0f, 1.0f, true); + C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, uLoc_projection, &projection); + Mtx_Identity(&modelView); + C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, uLoc_modelView, &modelView); + + // Set light directions + C3D_FVUnifSet(GPU_VERTEX_SHADER, uLoc_lightVec + 0, 0.0f, 0.0f, 0.0f, 0.0f); + C3D_FVUnifSet(GPU_VERTEX_SHADER, uLoc_lightVec + 1, 0.0f, 0.0f, 0.0f, 0.0f); + + // Set light colors + C3D_FVUnifSet(GPU_VERTEX_SHADER, uLoc_lightClr + 0, 0.0f, 0.0f, 0.0f, 0.0f); + C3D_FVUnifSet(GPU_VERTEX_SHADER, uLoc_lightClr + 1, 0.0f, 0.0f, 0.0f, 0.0f); + C3D_FVUnifSet(GPU_VERTEX_SHADER, uLoc_lightClr + 2, 1.0f, 1.0f, 1.0f, 1.0f); // Ambient + + C3DTextureCacheEntry* texture = (textureId != NO_TEXTURE_ID) ? &m_textures[textureId] : nullptr; + + SetMaterialAppearance(color, 0.0f, uLoc_meshColor, uLoc_shininess, texture ? &texture->c3dTex : nullptr); + + float scale = m_viewportTransform.scale; + + float x1 = static_cast(dstRect.x); + float y1 = static_cast(dstRect.y); + float x2 = x1 + static_cast(dstRect.w); + float y2 = y1 + static_cast(dstRect.h); + + float u0 = 0.0f; + float u1 = 0.0f; + float v0 = 0.0f; + float v1 = 0.0f; + + if (texture) { + u0 = (srcRect.x * scale) / texture->width; + u1 = ((srcRect.x + srcRect.w) * scale) / texture->width; + v0 = (srcRect.y * scale) / texture->height; + v1 = ((srcRect.y + srcRect.h) * scale) / texture->height; + } + + C3D_ImmDrawBegin(GPU_TRIANGLES); + + // Triangle 1 + C3D_ImmSendAttrib(x1, y1, 0.5f, 0.0f); + C3D_ImmSendAttrib(0.0f, 0.0f, 1.0f, 0.0f); + C3D_ImmSendAttrib(u0, v0, 0.0f, 0.0f); + + C3D_ImmSendAttrib(x2, y1, 0.5f, 0.0f); + C3D_ImmSendAttrib(0.0f, 0.0f, 1.0f, 0.0f); + C3D_ImmSendAttrib(u1, v0, 0.0f, 0.0f); + + C3D_ImmSendAttrib(x2, y2, 0.5f, 0.0f); + C3D_ImmSendAttrib(0.0f, 0.0f, 1.0f, 0.0f); + C3D_ImmSendAttrib(u1, v1, 0.0f, 0.0f); + + // Triangle 2 + C3D_ImmSendAttrib(x2, y2, 0.5f, 0.0f); + C3D_ImmSendAttrib(0.0f, 0.0f, 1.0f, 0.0f); + C3D_ImmSendAttrib(u1, v1, 0.0f, 0.0f); + + C3D_ImmSendAttrib(x1, y2, 0.5f, 0.0f); + C3D_ImmSendAttrib(0.0f, 0.0f, 1.0f, 0.0f); + C3D_ImmSendAttrib(u0, v1, 0.0f, 0.0f); + + C3D_ImmSendAttrib(x1, y1, 0.5f, 0.0f); + C3D_ImmSendAttrib(0.0f, 0.0f, 1.0f, 0.0f); + C3D_ImmSendAttrib(u0, v0, 0.0f, 0.0f); + + C3D_ImmDrawEnd(); +} + +void Citro3DRenderer::SetDither(bool dither) +{ +} + +void Citro3DRenderer::Download(SDL_Surface* target) +{ + u16 width, height; + u8* fb = gfxGetFramebuffer(GFX_BOTTOM, GFX_LEFT, &width, &height); + if (!fb) { + SDL_Log("Failed to get framebuffer"); + return; + } + + SDL_Surface* srcSurface = SDL_CreateSurfaceFrom(width, height, SDL_PIXELFORMAT_BGR24, fb, width * 3); + if (!srcSurface) { + SDL_Log("SDL_CreateSurfaceFrom failed: %s", SDL_GetError()); + return; + } + + SDL_Surface* convertedSurface = SDL_ConvertSurface(srcSurface, target->format); + SDL_DestroySurface(srcSurface); + if (!convertedSurface) { + SDL_Log("SDL_ConvertSurface failed: %s", SDL_GetError()); + return; + } + + int rotatedWidth = height; + int rotatedHeight = width; + SDL_Surface* rotatedSurface = SDL_CreateSurface(rotatedWidth, rotatedHeight, target->format); + if (!rotatedSurface) { + SDL_Log("SDL_CreateSurface failed: %s", SDL_GetError()); + SDL_DestroySurface(convertedSurface); + return; + } + + Uint32* srcPixels = (Uint32*) convertedSurface->pixels; + Uint32* dstPixels = (Uint32*) rotatedSurface->pixels; + for (int y = 0; y < height; ++y) { + for (int x = 0; x < width; ++x) { + Uint32 pixel = srcPixels[y * width + x]; + int newX = y; + int newY = width - 1 - x; + dstPixels[newY * rotatedWidth + newX] = pixel; + } + } + + SDL_DestroySurface(convertedSurface); + + SDL_Rect srcRect = {0, 0, rotatedSurface->w, rotatedSurface->h}; + SDL_Rect dstRect = {0, 0, target->w, target->h}; + SDL_BlitSurfaceScaled(rotatedSurface, &srcRect, target, &dstRect, SDL_SCALEMODE_NEAREST); + + SDL_DestroySurface(rotatedSurface); +} diff --git a/miniwin/src/d3drm/backends/citro3d/vshader.v.pica b/miniwin/src/d3drm/backends/citro3d/vshader.v.pica new file mode 100644 index 00000000..cd7f91c4 --- /dev/null +++ b/miniwin/src/d3drm/backends/citro3d/vshader.v.pica @@ -0,0 +1,130 @@ +; Uniforms +.fvec projection[4], modelView[4], meshColor +.fvec lightVec[2], lightClr[3], shininess + +; Constants +.constf myconst(0.0, 1.0, -1.0, -0.5) + +; Outputs +.out outpos position +.out outtc0 texcoord0 +.out outclr color + +; Inputs +.alias inpos v0 +.alias innrm v1 +.alias intex v2 + +.proc main + ; Prepare constants in usable temp regs + mov r15.x, myconst.x ; 0.0 + mov r15.y, myconst.y ; 1.0 + mov r15.z, myconst.z ; -1.0 + + ; Force the w component of inpos to be 1.0 + mov r0.xyz, inpos + mov r0.w, r15.y + + ; r1 = modelView * inpos + dp4 r1.x, modelView[0], r0 + dp4 r1.y, modelView[1], r0 + dp4 r1.z, modelView[2], r0 + dp4 r1.w, modelView[3], r0 + + ; outpos = projection * r1 + dp4 outpos.x, projection[0], r1 + dp4 outpos.y, projection[1], r1 + dp4 outpos.z, projection[2], r1 + dp4 outpos.w, projection[3], r1 + + ; outtex = intex + mov outtc0, intex + mov outtc0.zw, myconst.xy + + ; Transform normal + mov r2.xyz, innrm + mov r2.w, r15.x + dp4 r3.x, modelView[0], r2 + dp4 r3.y, modelView[1], r2 + dp4 r3.z, modelView[2], r2 + mov r3.w, r15.x + dp3 r4.x, r3, r3 + rsq r4.x, r4.x + mul r3, r4.xxxx, r3 ; r3 = normalized normal + + ; Normalize lightVec[0] + mov r5, lightVec[0] + dp3 r6.x, r5, r5 + rsq r6.x, r6.x + mul r5, r6.xxxx, r5 + + ; dot(normal, lightVec[0]) + dp3 r6.x, r3, r5 + max r6.x, r6.x, r15.xxxx + + ; Normalize lightVec[1] + mov r7, lightVec[1] + dp3 r8.x, r7, r7 + rsq r8.x, r8.x + mul r7, r8.xxxx, r7 + + ; dot(normal, lightVec[1]) + dp3 r6.y, r3, r7 + max r6.y, r6.y, r15.xxxx + + ; Load lightClr + mov r8, lightClr[2] ; ambient + mov r9, lightClr[0] ; point + mov r10, lightClr[1] ; directional + + ; diffuse = ambient + (lightClr[0] * dot0) + (lightClr[1] * dot1) + mul r11, r9, r6.xxxx + add r8, r8, r11 + mul r11, r10, r6.yyyy + add r8, r8, r11 ; r8 = diffuse + + ; Check if shininess > 0 + mov r12, shininess + slt r13.x, r15.x, r12.x + + ; viewVec = normalize(-position.xyz) + mov r14.xyz, r1.xyz + mul r14.xyz, r14.xyz, r15.zzz + dp3 r4.x, r14, r14 + rsq r4.x, r4.x + mul r14, r4.xxxx, r14 + + ; H = normalize(view + lightVec[1]) + add r11, r14, r7 + dp3 r4.x, r11, r11 + rsq r4.x, r4.x + mul r11, r4.xxxx, r11 + + ; dot(normal, H) + dp3 r4.x, r3, r11 + max r4.x, r4.x, r15.x + + ; Approximate pow(dotNH, 10) by repeated multiplication + mul r5.x, r4.x, r4.x ; dotNH^2 + mul r5.x, r5.x, r5.x ; dotNH^4 + mul r5.x, r5.x, r5.x ; dotNH^8 + mul r4.x, r5.x, r4.x ; dotNH^9 + mul r4.x, r4.x, r4.x ; dotNH^10 + + ; Multiply by shininess > 0 flag + mul r4.x, r4.x, r13.x + + ; specular = lightClr[1] * spec + mul r5, r10, r4.xxxx + + ; final = diffuse * meshColor + specular * lightClr[1] + mov r9, meshColor + mul r6, r8, r9 ; diffuse * meshColor + add r7.xyz, r6.xyz, r5.xyz ; add specular (already multiplied by lightClr) + min r7.xyz, r7.xyz, r15.yyyy + + mov outclr.xyz, r7.xyz + mov outclr.w, meshColor.w + + end +.end diff --git a/miniwin/src/d3drm/backends/directx9/actual.cpp b/miniwin/src/d3drm/backends/directx9/actual.cpp index 33dc2864..4ccea210 100644 --- a/miniwin/src/d3drm/backends/directx9/actual.cpp +++ b/miniwin/src/d3drm/backends/directx9/actual.cpp @@ -297,44 +297,23 @@ D3DMATRIX ToD3DMATRIX(const Matrix4x4& in) return out; } -void Actual_SubmitDraw( - const D3D9MeshCacheEntry* mesh, - const Matrix4x4* modelViewMatrix, - const Matrix4x4* worldMatrix, - const Matrix4x4* viewMatrix, - const Matrix3x3* normalMatrix, - const Appearance* appearance, - IDirect3DTexture9* texture -) +void SetMaterialAndTexture(const FColor& color, float shininess, IDirect3DTexture9* texture) { - D3DMATRIX proj = ToD3DMATRIX(g_projection); - g_device->SetTransform(D3DTS_PROJECTION, &proj); - D3DMATRIX view = ToD3DMATRIX(*viewMatrix); - g_device->SetTransform(D3DTS_VIEW, &view); - D3DMATRIX world = ToD3DMATRIX(*worldMatrix); - g_device->SetTransform(D3DTS_WORLD, &world); - D3DMATERIAL9 mat = {}; - mat.Diffuse.r = appearance->color.r / 255.0f; - mat.Diffuse.g = appearance->color.g / 255.0f; - mat.Diffuse.b = appearance->color.b / 255.0f; - mat.Diffuse.a = appearance->color.a / 255.0f; + mat.Diffuse.r = color.r / 255.0f; + mat.Diffuse.g = color.g / 255.0f; + mat.Diffuse.b = color.b / 255.0f; + mat.Diffuse.a = color.a / 255.0f; mat.Ambient = mat.Diffuse; - if (appearance->shininess != 0) { + if (shininess != 0) { g_device->SetRenderState(D3DRS_SPECULARENABLE, TRUE); - mat.Specular.r = 1.0f; - mat.Specular.g = 1.0f; - mat.Specular.b = 1.0f; - mat.Specular.a = 1.0f; - mat.Power = appearance->shininess; + mat.Specular = {1.0f, 1.0f, 1.0f, 1.0f}; + mat.Power = shininess; } else { g_device->SetRenderState(D3DRS_SPECULARENABLE, FALSE); - mat.Specular.r = 0.0f; - mat.Specular.g = 0.0f; - mat.Specular.b = 0.0f; - mat.Specular.a = 0.0f; + mat.Specular = {0.0f, 0.0f, 0.0f, 0.0f}; mat.Power = 0.0f; } @@ -352,6 +331,33 @@ void Actual_SubmitDraw( else { g_device->SetTexture(0, nullptr); } +} + +void Actual_SubmitDraw( + const D3D9MeshCacheEntry* mesh, + const Matrix4x4* modelViewMatrix, + const Matrix4x4* worldMatrix, + const Matrix4x4* viewMatrix, + const Matrix3x3* normalMatrix, + const Appearance* appearance, + IDirect3DTexture9* texture +) +{ + D3DMATRIX proj = ToD3DMATRIX(g_projection); + g_device->SetTransform(D3DTS_PROJECTION, &proj); + D3DMATRIX view = ToD3DMATRIX(*viewMatrix); + g_device->SetTransform(D3DTS_VIEW, &view); + D3DMATRIX world = ToD3DMATRIX(*worldMatrix); + g_device->SetTransform(D3DTS_WORLD, &world); + + SetMaterialAndTexture( + {appearance->color.r / 255.0f, + appearance->color.g / 255.0f, + appearance->color.b / 255.0f, + appearance->color.a / 255.0f}, + appearance->shininess, + texture + ); g_device->SetRenderState(D3DRS_SHADEMODE, mesh->flat ? D3DSHADE_FLAT : D3DSHADE_GOURAUD); @@ -367,7 +373,7 @@ uint32_t Actual_Flip() return g_device->Present(nullptr, nullptr, nullptr, nullptr); } -void Actual_Draw2DImage(IDirect3DTexture9* texture, const SDL_Rect& srcRect, const SDL_Rect& dstRect) +void Actual_Draw2DImage(IDirect3DTexture9* texture, const SDL_Rect& srcRect, const SDL_Rect& dstRect, FColor color) { StartScene(); @@ -405,10 +411,7 @@ void Actual_Draw2DImage(IDirect3DTexture9* texture, const SDL_Rect& srcRect, con g_device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); g_device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); - g_device->SetTexture(0, texture); - g_device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE); - g_device->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); - g_device->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE); + SetMaterialAndTexture(color, 0, texture); D3DSURFACE_DESC texDesc; texture->GetLevelDesc(0, &texDesc); diff --git a/miniwin/src/d3drm/backends/directx9/actual.h b/miniwin/src/d3drm/backends/directx9/actual.h index e3369ec9..bf09cb00 100644 --- a/miniwin/src/d3drm/backends/directx9/actual.h +++ b/miniwin/src/d3drm/backends/directx9/actual.h @@ -78,5 +78,5 @@ void Actual_SubmitDraw( void Actual_Resize(int width, int height, const ViewportTransform& viewportTransform); void Actual_Clear(float r, float g, float b); uint32_t Actual_Flip(); -void Actual_Draw2DImage(IDirect3DTexture9* texture, const SDL_Rect& srcRect, const SDL_Rect& dstRect); +void Actual_Draw2DImage(IDirect3DTexture9* texture, const SDL_Rect& srcRect, const SDL_Rect& dstRect, FColor color); uint32_t Actual_Download(SDL_Surface* target); diff --git a/miniwin/src/d3drm/backends/directx9/renderer.cpp b/miniwin/src/d3drm/backends/directx9/renderer.cpp index 574939f5..e97dfa17 100644 --- a/miniwin/src/d3drm/backends/directx9/renderer.cpp +++ b/miniwin/src/d3drm/backends/directx9/renderer.cpp @@ -76,7 +76,7 @@ void DirectX9Renderer::AddTextureDestroyCallback(Uint32 id, IDirect3DRMTexture* ); } -Uint32 DirectX9Renderer::GetTextureId(IDirect3DRMTexture* iTexture) +Uint32 DirectX9Renderer::GetTextureId(IDirect3DRMTexture* iTexture, bool isUI, float scaleX, float scaleY) { auto texture = static_cast(iTexture); auto surface = static_cast(texture->m_surface); @@ -216,24 +216,6 @@ Uint32 DirectX9Renderer::GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* meshG return static_cast(m_meshs.size() - 1); } -void DirectX9Renderer::GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc) -{ - halDesc->dcmColorModel = D3DCOLORMODEL::RGB; - halDesc->dwFlags = D3DDD_DEVICEZBUFFERBITDEPTH; - halDesc->dwDeviceZBufferBitDepth = DDBD_24; - helDesc->dwDeviceRenderBitDepth = DDBD_32; - halDesc->dpcTriCaps.dwTextureCaps = D3DPTEXTURECAPS_PERSPECTIVE; - halDesc->dpcTriCaps.dwShadeCaps = D3DPSHADECAPS_ALPHAFLATBLEND; - halDesc->dpcTriCaps.dwTextureFilterCaps = D3DPTFILTERCAPS_LINEAR; - - memset(helDesc, 0, sizeof(D3DDEVICEDESC)); -} - -const char* DirectX9Renderer::GetName() -{ - return "DirectX 9 HAL"; -} - HRESULT DirectX9Renderer::BeginFrame() { return Actual_BeginFrame(); @@ -291,9 +273,13 @@ void DirectX9Renderer::Flip() Actual_Flip(); } -void DirectX9Renderer::Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, const SDL_Rect& dstRect) +void DirectX9Renderer::Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, const SDL_Rect& dstRect, FColor color) +{ + Actual_Draw2DImage(m_textures[textureId].dxTexture, srcRect, dstRect, color); +} + +void DirectX9Renderer::SetDither(bool dither) { - Actual_Draw2DImage(m_textures[textureId].dxTexture, srcRect, dstRect); } void DirectX9Renderer::Download(SDL_Surface* target) diff --git a/miniwin/src/d3drm/backends/opengl1/actual.cpp b/miniwin/src/d3drm/backends/opengl1/actual.cpp new file mode 100644 index 00000000..4b83daff --- /dev/null +++ b/miniwin/src/d3drm/backends/opengl1/actual.cpp @@ -0,0 +1,376 @@ +// This file cannot include any minwin headers. + +#include "actual.h" + +#include "structs.h" + +#include +#include +#include +#include +#include + +// GL extension API functions. +bool g_useVBOs; +PFNGLGENBUFFERSPROC mwglGenBuffers; +PFNGLBINDBUFFERPROC mwglBindBuffer; +PFNGLBUFFERDATAPROC mwglBufferData; +PFNGLDELETEBUFFERSPROC mwglDeleteBuffers; + +void GL11_InitState() +{ + glEnable(GL_CULL_FACE); + glCullFace(GL_BACK); + glFrontFace(GL_CW); +} + +void GL11_LoadExtensions() +{ + g_useVBOs = SDL_GL_ExtensionSupported("GL_ARB_vertex_buffer_object"); + + if (g_useVBOs) { + // Load the required GL function pointers. + mwglGenBuffers = (PFNGLGENBUFFERSPROC) SDL_GL_GetProcAddress("glGenBuffersARB"); + mwglBindBuffer = (PFNGLBINDBUFFERPROC) SDL_GL_GetProcAddress("glBindBufferARB"); + mwglBufferData = (PFNGLBUFFERDATAPROC) SDL_GL_GetProcAddress("glBufferDataARB"); + mwglDeleteBuffers = (PFNGLDELETEBUFFERSPROC) SDL_GL_GetProcAddress("glDeleteBuffersARB"); + } +} + +void GL11_DestroyTexture(GLuint texId) +{ + glDeleteTextures(1, &texId); +} + +int GL11_GetMaxTextureSize() +{ + GLint maxTextureSize = 0; + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize); + return maxTextureSize; +} + +GLuint GL11_UploadTextureData(void* pixels, int width, int height, bool isUI, float scaleX, float scaleY) +{ + GLuint texId; + glGenTextures(1, &texId); + glBindTexture(GL_TEXTURE_2D, texId); + if (isUI) { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + } + else { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + } + + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); + + return texId; +} + +void GL11_UploadMesh(GLMeshCacheEntry& cache, bool hasTexture) +{ + if (g_useVBOs) { + mwglGenBuffers(1, &cache.vboPositions); + mwglBindBuffer(GL_ARRAY_BUFFER_ARB, cache.vboPositions); + mwglBufferData( + GL_ARRAY_BUFFER_ARB, + cache.positions.size() * sizeof(GL11_BridgeVector), + cache.positions.data(), + GL_STATIC_DRAW_ARB + ); + + mwglGenBuffers(1, &cache.vboNormals); + mwglBindBuffer(GL_ARRAY_BUFFER_ARB, cache.vboNormals); + mwglBufferData( + GL_ARRAY_BUFFER_ARB, + cache.normals.size() * sizeof(GL11_BridgeVector), + cache.normals.data(), + GL_STATIC_DRAW_ARB + ); + + if (hasTexture) { + mwglGenBuffers(1, &cache.vboTexcoords); + mwglBindBuffer(GL_ARRAY_BUFFER_ARB, cache.vboTexcoords); + mwglBufferData( + GL_ARRAY_BUFFER_ARB, + cache.texcoords.size() * sizeof(GL11_BridgeTexCoord), + cache.texcoords.data(), + GL_STATIC_DRAW_ARB + ); + } + + mwglGenBuffers(1, &cache.ibo); + mwglBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, cache.ibo); + mwglBufferData( + GL_ELEMENT_ARRAY_BUFFER_ARB, + cache.indices.size() * sizeof(cache.indices[0]), + cache.indices.data(), + GL_STATIC_DRAW_ARB + ); + } +} + +void GL11_DestroyMesh(GLMeshCacheEntry& cache) +{ + if (g_useVBOs) { + mwglDeleteBuffers(1, &cache.vboPositions); + mwglDeleteBuffers(1, &cache.vboNormals); + mwglDeleteBuffers(1, &cache.vboTexcoords); + mwglDeleteBuffers(1, &cache.ibo); + } +} + +void GL11_BeginFrame(const Matrix4x4* projection) +{ + glDisable(GL_BLEND); + glEnable(GL_DEPTH_TEST); + glDepthMask(GL_TRUE); + glEnable(GL_LIGHTING); + glEnable(GL_COLOR_MATERIAL); + + // Disable all lights and reset global ambient + for (int i = 0; i < 8; ++i) { + glDisable(GL_LIGHT0 + i); + } + + glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE); + + // Projection and view + glMatrixMode(GL_PROJECTION); + glLoadMatrixf((const GLfloat*) projection); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); +} + +void GL11_UploadLight(int lightIdx, GL11_BridgeSceneLight* l) +{ + // Setup light + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + GLenum lightId = GL_LIGHT0 + lightIdx++; + const FColor& c = l->color; + GLfloat col[4] = {c.r, c.g, c.b, c.a}; + const GLfloat zeroAmbient[4] = {0.f, 0.f, 0.f, 1.f}; + + if (l->positional == 0.f && l->directional == 0.f) { + // Ambient light only + glLightfv(lightId, GL_AMBIENT, col); + const GLfloat black[4] = {0.f, 0.f, 0.f, 1.f}; + glLightfv(lightId, GL_DIFFUSE, black); + glLightfv(lightId, GL_SPECULAR, black); + const GLfloat dummyPos[4] = {0.f, 0.f, 1.f, 0.f}; + glLightfv(lightId, GL_POSITION, dummyPos); + } + else { + glLightfv(lightId, GL_AMBIENT, zeroAmbient); + glLightfv(lightId, GL_DIFFUSE, col); + if (l->directional == 1.0f) { + glLightfv(lightId, GL_SPECULAR, col); + } + else { + const GLfloat black[4] = {0.f, 0.f, 0.f, 1.f}; + glLightfv(lightId, GL_SPECULAR, black); + } + + GLfloat pos[4]; + if (l->directional == 1.f) { + pos[0] = -l->direction.x; + pos[1] = -l->direction.y; + pos[2] = -l->direction.z; + pos[3] = 0.f; + } + else { + pos[0] = l->position.x; + pos[1] = l->position.y; + pos[2] = l->position.z; + pos[3] = 1.f; + } + glLightfv(lightId, GL_POSITION, pos); + } + glEnable(lightId); +} + +void GL11_EnableTransparency() +{ + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glDepthMask(GL_FALSE); +} + +#define NO_TEXTURE_ID 0xffffffff + +void GL11_SubmitDraw( + GLMeshCacheEntry& mesh, + const Matrix4x4& modelViewMatrix, + const Appearance& appearance, + GLuint texId +) +{ + glLoadMatrixf(&modelViewMatrix[0][0]); + glEnable(GL_NORMALIZE); + + glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE); + glColor4ub(appearance.color.r, appearance.color.g, appearance.color.b, appearance.color.a); + + if (appearance.shininess != 0.0f) { + GLfloat whiteSpec[] = {1.f, 1.f, 1.f, 1.f}; + glMaterialfv(GL_FRONT, GL_SPECULAR, whiteSpec); + glMaterialf(GL_FRONT, GL_SHININESS, appearance.shininess); + } + else { + GLfloat noSpec[] = {0.0f, 0.0f, 0.0f, 0.0f}; + glMaterialfv(GL_FRONT, GL_SPECULAR, noSpec); + glMaterialf(GL_FRONT, GL_SHININESS, 0.0f); + } + + if (mesh.flat) { + glShadeModel(GL_FLAT); + } + else { + glShadeModel(GL_SMOOTH); + } + + // Bind texture if present + if (appearance.textureId != NO_TEXTURE_ID) { + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, texId); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + } + else { + glDisable(GL_TEXTURE_2D); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + } + + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_NORMAL_ARRAY); + + if (g_useVBOs) { + mwglBindBuffer(GL_ARRAY_BUFFER_ARB, mesh.vboPositions); + glVertexPointer(3, GL_FLOAT, 0, nullptr); + + mwglBindBuffer(GL_ARRAY_BUFFER_ARB, mesh.vboNormals); + glNormalPointer(GL_FLOAT, 0, nullptr); + + if (appearance.textureId != NO_TEXTURE_ID) { + mwglBindBuffer(GL_ARRAY_BUFFER_ARB, mesh.vboTexcoords); + glTexCoordPointer(2, GL_FLOAT, 0, nullptr); + } + + mwglBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, mesh.ibo); + glDrawElements(GL_TRIANGLES, static_cast(mesh.indices.size()), GL_UNSIGNED_SHORT, nullptr); + + mwglBindBuffer(GL_ARRAY_BUFFER_ARB, 0); + mwglBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); + } + else { + glVertexPointer(3, GL_FLOAT, 0, mesh.positions.data()); + glNormalPointer(GL_FLOAT, 0, mesh.normals.data()); + if (appearance.textureId != NO_TEXTURE_ID) { + glTexCoordPointer(2, GL_FLOAT, 0, mesh.texcoords.data()); + } + + glDrawElements(GL_TRIANGLES, static_cast(mesh.indices.size()), GL_UNSIGNED_SHORT, mesh.indices.data()); + } +} + +void GL11_Resize(int width, int height) +{ + glViewport(0, 0, width, height); +} + +void GL11_Clear(float r, float g, float b) +{ + glEnable(GL_DEPTH_TEST); + glDepthMask(GL_TRUE); + glClearColor(r, g, b, 1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); +} + +void GL11_Draw2DImage( + const GLTextureCacheEntry* cache, + const SDL_Rect& srcRect, + const SDL_Rect& dstRect, + const FColor& color, + float left, + float right, + float bottom, + float top +) +{ + glDisable(GL_DEPTH_TEST); + glDepthMask(GL_FALSE); + glShadeModel(GL_FLAT); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + + glOrtho(left, right, bottom, top, -1, 1); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + glDisable(GL_LIGHTING); + glColor4f(color.r, color.g, color.b, color.a); + + float u1 = 0; + float v1 = 0; + float u2 = 0; + float v2 = 0; + + if (cache) { + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, cache->glTextureId); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + u1 = srcRect.x / cache->width; + v1 = srcRect.y / cache->height; + u2 = (srcRect.x + srcRect.w) / cache->width; + v2 = (srcRect.y + srcRect.h) / cache->height; + } + else { + glDisable(GL_TEXTURE_2D); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + } + + float x1 = (float) dstRect.x; + float y1 = (float) dstRect.y; + float x2 = x1 + dstRect.w; + float y2 = y1 + dstRect.h; + + glBegin(GL_QUADS); + glTexCoord2f(u1, v1); + glVertex2f(x1, y1); + glTexCoord2f(u2, v1); + glVertex2f(x2, y1); + glTexCoord2f(u2, v2); + glVertex2f(x2, y2); + glTexCoord2f(u1, v2); + glVertex2f(x1, y2); + glEnd(); + + // Restore state + glMatrixMode(GL_MODELVIEW); + glMatrixMode(GL_PROJECTION); +} + +void GL11_Download(SDL_Surface* target) +{ + glFinish(); + glReadPixels(0, 0, target->w, target->h, GL_RGBA, GL_UNSIGNED_BYTE, target->pixels); +} + +void GL11_SetDither(bool dither) +{ + if (dither) { + glEnable(GL_DITHER); + } + else { + glDisable(GL_DITHER); + } +} diff --git a/miniwin/src/d3drm/backends/opengl1/actual.h b/miniwin/src/d3drm/backends/opengl1/actual.h new file mode 100644 index 00000000..232fc88d --- /dev/null +++ b/miniwin/src/d3drm/backends/opengl1/actual.h @@ -0,0 +1,93 @@ +#pragma once + +#include "structs.h" + +#include +#include +#include + +// We don't want to transitively include windows.h, but we need GLuint +typedef unsigned int GLuint; +struct IDirect3DRMTexture; +struct MeshGroup; + +typedef float Matrix4x4[4][4]; + +struct GL11_BridgeVector { + float x, y, z; +}; + +struct GL11_BridgeTexCoord { + float u, v; +}; + +struct GL11_BridgeSceneLight { + FColor color; + GL11_BridgeVector position; + float positional; + GL11_BridgeVector direction; + float directional; +}; + +struct GL11_BridgeSceneVertex { + GL11_BridgeVector position; + GL11_BridgeVector normal; + float tu, tv; +}; + +struct GLTextureCacheEntry { + IDirect3DRMTexture* texture; + Uint32 version; + GLuint glTextureId; + float width; + float height; +}; + +struct GLMeshCacheEntry { + const MeshGroup* meshGroup; + int version; + bool flat; + + // non-VBO cache + std::vector positions; + std::vector normals; + std::vector texcoords; + std::vector indices; + + // VBO cache + GLuint vboPositions; + GLuint vboNormals; + GLuint vboTexcoords; + GLuint ibo; +}; + +void GL11_InitState(); +void GL11_LoadExtensions(); +void GL11_DestroyTexture(GLuint texId); +int GL11_GetMaxTextureSize(); +GLuint GL11_UploadTextureData(void* pixels, int width, int height, bool isUI, float scaleX, float scaleY); +void GL11_UploadMesh(GLMeshCacheEntry& cache, bool hasTexture); +void GL11_DestroyMesh(GLMeshCacheEntry& cache); +void GL11_BeginFrame(const Matrix4x4* projection); +void GL11_UploadLight(int lightIdx, GL11_BridgeSceneLight* l); +void GL11_EnableTransparency(); +void GL11_SubmitDraw( + GLMeshCacheEntry& mesh, + const Matrix4x4& modelViewMatrix, + const Appearance& appearance, + GLuint texId +); +void GL11_Resize(int width, int height); +void GL11_Clear(float r, float g, float b); +void GL11_Draw2DImage( + const GLTextureCacheEntry* cache, + const SDL_Rect& srcRect, + const SDL_Rect& dstRect, + const FColor& color, + float left, + float right, + float bottom, + float top +); +void GL11_SetDither(bool dither); +void GL11_Download(SDL_Surface* target); diff --git a/miniwin/src/d3drm/backends/opengl1/renderer.cpp b/miniwin/src/d3drm/backends/opengl1/renderer.cpp index cc415de8..2d4c14c9 100644 --- a/miniwin/src/d3drm/backends/opengl1/renderer.cpp +++ b/miniwin/src/d3drm/backends/opengl1/renderer.cpp @@ -1,5 +1,4 @@ -#include -// must come after GLEW +#include "actual.h" #include "d3drmrenderer_opengl1.h" #include "ddraw_impl.h" #include "ddsurface_impl.h" @@ -11,58 +10,47 @@ #include #include -Direct3DRMRenderer* OpenGL1Renderer::Create(DWORD width, DWORD height) +static_assert(sizeof(Matrix4x4) == sizeof(D3DRMMATRIX4D), "Matrix4x4 is wrong size"); +static_assert(sizeof(GL11_BridgeVector) == sizeof(D3DVECTOR), "GL11_BridgeVector is wrong size"); +static_assert(sizeof(GL11_BridgeTexCoord) == sizeof(TexCoord), "GL11_BridgeTexCoord is wrong size"); +static_assert(sizeof(GL11_BridgeSceneLight) == sizeof(SceneLight), "GL11_BridgeSceneLight is wrong size"); +static_assert(sizeof(GL11_BridgeSceneVertex) == sizeof(D3DRMVERTEX), "GL11_BridgeSceneVertex is wrong size"); + +Direct3DRMRenderer* OpenGL1Renderer::Create(DWORD width, DWORD height, DWORD msaaSamples) { + // We have to reset the attributes here after having enumerated the + // OpenGL ES 2.0 renderer, or else SDL gets very confused by SDL_GL_DEPTH_SIZE + // call below when on an EGL-based backend, and crashes with EGL_BAD_MATCH. + SDL_GL_ResetAttributes(); + // But ResetAttributes resets it to 16. + SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 1); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1); - SDL_Window* window = DDWindow; - bool testWindow = false; - if (!window) { - window = SDL_CreateWindow("OpenGL 1.1 test", width, height, SDL_WINDOW_HIDDEN | SDL_WINDOW_OPENGL); - if (!window) { - SDL_Log("SDL_CreateWindow: %s", SDL_GetError()); - return nullptr; - } - testWindow = true; + if (msaaSamples > 1) { + SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1); + SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, msaaSamples); } - SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); + if (!DDWindow) { + SDL_Log("No window handler"); + return nullptr; + } - SDL_GLContext context = SDL_GL_CreateContext(window); + SDL_GLContext context = SDL_GL_CreateContext(DDWindow); if (!context) { SDL_Log("SDL_GL_CreateContext: %s", SDL_GetError()); - if (testWindow) { - SDL_DestroyWindow(window); - } return nullptr; } - if (!SDL_GL_MakeCurrent(window, context)) { + if (!SDL_GL_MakeCurrent(DDWindow, context)) { + SDL_GL_DestroyContext(context); SDL_Log("SDL_GL_MakeCurrent: %s", SDL_GetError()); - if (testWindow) { - SDL_DestroyWindow(window); - } return nullptr; } - GLenum err = glewInit(); - if (err != GLEW_OK) { - SDL_Log("glewInit: %s", glewGetErrorString(err)); - if (testWindow) { - SDL_DestroyWindow(window); - } - return nullptr; - } - - glEnable(GL_CULL_FACE); - glCullFace(GL_BACK); - glFrontFace(GL_CW); - - if (testWindow) { - SDL_DestroyWindow(window); - } + GL11_InitState(); return new OpenGL1Renderer(width, height, context); } @@ -74,12 +62,15 @@ OpenGL1Renderer::OpenGL1Renderer(DWORD width, DWORD height, SDL_GLContext contex m_virtualWidth = width; m_virtualHeight = height; m_renderedImage = SDL_CreateSurface(m_width, m_height, SDL_PIXELFORMAT_RGBA32); - m_useVBOs = GLEW_ARB_vertex_buffer_object; + GL11_LoadExtensions(); + m_useVBOs = SDL_GL_ExtensionSupported("GL_ARB_vertex_buffer_object"); + m_useNPOT = SDL_GL_ExtensionSupported("GL_OES_texture_npot"); } OpenGL1Renderer::~OpenGL1Renderer() { SDL_DestroySurface(m_renderedImage); + SDL_GL_DestroyContext(m_context); } void OpenGL1Renderer::PushLights(const SceneLight* lightsArray, size_t count) @@ -114,7 +105,7 @@ void OpenGL1Renderer::AddTextureDestroyCallback(Uint32 id, IDirect3DRMTexture* t auto* ctx = static_cast(arg); auto& cache = ctx->renderer->m_textures[ctx->textureId]; if (cache.glTextureId != 0) { - glDeleteTextures(1, &cache.glTextureId); + GL11_DestroyTexture(cache.glTextureId); cache.glTextureId = 0; cache.texture = nullptr; } @@ -124,8 +115,72 @@ void OpenGL1Renderer::AddTextureDestroyCallback(Uint32 id, IDirect3DRMTexture* t ); } -Uint32 OpenGL1Renderer::GetTextureId(IDirect3DRMTexture* iTexture) +static int NextPowerOfTwo(int v) { + int power = 1; + while (power < v) { + power <<= 1; + } + return power; +} + +static Uint32 UploadTextureData(SDL_Surface* src, bool useNPOT, bool isUI, float scaleX, float scaleY) +{ + SDL_Surface* working = src; + if (src->format != SDL_PIXELFORMAT_RGBA32) { + working = SDL_ConvertSurface(src, SDL_PIXELFORMAT_RGBA32); + if (!working) { + SDL_Log("SDL_ConvertSurface failed: %s", SDL_GetError()); + return NO_TEXTURE_ID; + } + } + + SDL_Surface* finalSurface = working; + + int newW = working->w; + int newH = working->h; + if (!useNPOT) { + newW = NextPowerOfTwo(newW); + newH = NextPowerOfTwo(newH); + } + int max = GL11_GetMaxTextureSize(); + if (newW > max) { + newW = max; + } + if (newH > max) { + newH = max; + } + + if (newW != working->w || newH != working->h) { + SDL_Surface* resized = SDL_CreateSurface(newW, newH, working->format); + if (!resized) { + SDL_Log("SDL_CreateSurface (resize) failed: %s", SDL_GetError()); + if (working != src) { + SDL_DestroySurface(working); + } + return NO_TEXTURE_ID; + } + + SDL_Rect srcRect = {0, 0, working->w, working->h}; + SDL_Rect dstRect = {0, 0, newW, newH}; + SDL_BlitSurfaceScaled(working, &srcRect, resized, &dstRect, SDL_SCALEMODE_NEAREST); + + if (working != src) { + SDL_DestroySurface(working); + } + finalSurface = resized; + } + + Uint32 texId = GL11_UploadTextureData(finalSurface->pixels, finalSurface->w, finalSurface->h, isUI, scaleX, scaleY); + if (finalSurface != src) { + SDL_DestroySurface(finalSurface); + } + return texId; +} + +Uint32 OpenGL1Renderer::GetTextureId(IDirect3DRMTexture* iTexture, bool isUI, float scaleX, float scaleY) +{ + SDL_GL_MakeCurrent(DDWindow, m_context); auto texture = static_cast(iTexture); auto surface = static_cast(texture->m_surface); @@ -133,33 +188,17 @@ Uint32 OpenGL1Renderer::GetTextureId(IDirect3DRMTexture* iTexture) auto& tex = m_textures[i]; if (tex.texture == texture) { if (tex.version != texture->m_version) { - glDeleteTextures(1, &tex.glTextureId); - glGenTextures(1, &tex.glTextureId); - glBindTexture(GL_TEXTURE_2D, tex.glTextureId); - - SDL_Surface* surf = SDL_ConvertSurface(surface->m_surface, SDL_PIXELFORMAT_RGBA32); - if (!surf) { - return NO_TEXTURE_ID; - } - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, surf->w, surf->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, surf->pixels); - SDL_DestroySurface(surf); - + GL11_DestroyTexture(tex.glTextureId); + tex.glTextureId = UploadTextureData(surface->m_surface, m_useNPOT, isUI, scaleX, scaleY); tex.version = texture->m_version; + tex.width = surface->m_surface->w; + tex.height = surface->m_surface->h; } return i; } } - GLuint texId; - glGenTextures(1, &texId); - glBindTexture(GL_TEXTURE_2D, texId); - - SDL_Surface* surf = SDL_ConvertSurface(surface->m_surface, SDL_PIXELFORMAT_RGBA32); - if (!surf) { - return NO_TEXTURE_ID; - } - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, surf->w, surf->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, surf->pixels); - SDL_DestroySurface(surf); + GLuint texId = UploadTextureData(surface->m_surface, m_useNPOT, isUI, scaleX, scaleY); for (Uint32 i = 0; i < m_textures.size(); ++i) { auto& tex = m_textures[i]; @@ -167,12 +206,20 @@ Uint32 OpenGL1Renderer::GetTextureId(IDirect3DRMTexture* iTexture) tex.texture = texture; tex.version = texture->m_version; tex.glTextureId = texId; + tex.width = surface->m_surface->w; + tex.height = surface->m_surface->h; AddTextureDestroyCallback(i, texture); return i; } } - m_textures.push_back({texture, texture->m_version, texId}); + m_textures.push_back( + {texture, + texture->m_version, + texId, + static_cast(surface->m_surface->w), + static_cast(surface->m_surface->h)} + ); AddTextureDestroyCallback((Uint32) (m_textures.size() - 1), texture); return (Uint32) (m_textures.size() - 1); } @@ -206,52 +253,19 @@ GLMeshCacheEntry GLUploadMesh(const MeshGroup& meshGroup, bool useVBOs) if (meshGroup.texture) { cache.texcoords.resize(vertices.size()); std::transform(vertices.begin(), vertices.end(), cache.texcoords.begin(), [](const D3DRMVERTEX& v) { - return v.texCoord; + return GL11_BridgeTexCoord{v.texCoord.u, v.texCoord.v}; }); } cache.positions.resize(vertices.size()); std::transform(vertices.begin(), vertices.end(), cache.positions.begin(), [](const D3DRMVERTEX& v) { - return v.position; + return GL11_BridgeVector{v.position.x, v.position.y, v.position.z}; }); cache.normals.resize(vertices.size()); std::transform(vertices.begin(), vertices.end(), cache.normals.begin(), [](const D3DRMVERTEX& v) { - return v.normal; + return GL11_BridgeVector{v.normal.x, v.normal.y, v.normal.z}; }); - if (useVBOs) { - glGenBuffers(1, &cache.vboPositions); - glBindBuffer(GL_ARRAY_BUFFER, cache.vboPositions); - glBufferData( - GL_ARRAY_BUFFER, - cache.positions.size() * sizeof(D3DVECTOR), - cache.positions.data(), - GL_STATIC_DRAW - ); - - glGenBuffers(1, &cache.vboNormals); - glBindBuffer(GL_ARRAY_BUFFER, cache.vboNormals); - glBufferData(GL_ARRAY_BUFFER, cache.normals.size() * sizeof(D3DVECTOR), cache.normals.data(), GL_STATIC_DRAW); - - if (meshGroup.texture) { - glGenBuffers(1, &cache.vboTexcoords); - glBindBuffer(GL_ARRAY_BUFFER, cache.vboTexcoords); - glBufferData( - GL_ARRAY_BUFFER, - cache.texcoords.size() * sizeof(TexCoord), - cache.texcoords.data(), - GL_STATIC_DRAW - ); - } - - glGenBuffers(1, &cache.ibo); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, cache.ibo); - glBufferData( - GL_ELEMENT_ARRAY_BUFFER, - cache.indices.size() * sizeof(cache.indices[0]), - cache.indices.data(), - GL_STATIC_DRAW - ); - } + GL11_UploadMesh(cache, meshGroup.texture != nullptr); return cache; } @@ -269,12 +283,7 @@ void OpenGL1Renderer::AddMeshDestroyCallback(Uint32 id, IDirect3DRMMesh* mesh) auto* ctx = static_cast(arg); auto& cache = ctx->renderer->m_meshs[ctx->id]; cache.meshGroup = nullptr; - if (ctx->renderer->m_useVBOs) { - glDeleteBuffers(1, &cache.vboPositions); - glDeleteBuffers(1, &cache.vboNormals); - glDeleteBuffers(1, &cache.vboTexcoords); - glDeleteBuffers(1, &cache.ibo); - } + GL11_DestroyMesh(cache); delete ctx; }, ctx @@ -309,110 +318,26 @@ Uint32 OpenGL1Renderer::GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* meshGr return (Uint32) (m_meshs.size() - 1); } -void OpenGL1Renderer::GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc) -{ - halDesc->dcmColorModel = D3DCOLORMODEL::RGB; - halDesc->dwFlags = D3DDD_DEVICEZBUFFERBITDEPTH; - halDesc->dwDeviceZBufferBitDepth = DDBD_24; - helDesc->dwDeviceRenderBitDepth = DDBD_32; - halDesc->dpcTriCaps.dwTextureCaps = D3DPTEXTURECAPS_PERSPECTIVE; - halDesc->dpcTriCaps.dwShadeCaps = D3DPSHADECAPS_ALPHAFLATBLEND; - halDesc->dpcTriCaps.dwTextureFilterCaps = D3DPTFILTERCAPS_LINEAR; - - memset(helDesc, 0, sizeof(D3DDEVICEDESC)); -} - -const char* OpenGL1Renderer::GetName() -{ - return "OpenGL 1.1 HAL"; -} - HRESULT OpenGL1Renderer::BeginFrame() { - m_dirty = true; - - glDisable(GL_BLEND); - glEnable(GL_DEPTH_TEST); - glDepthMask(GL_TRUE); - glEnable(GL_LIGHTING); - glEnable(GL_COLOR_MATERIAL); - glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE); - - // Disable all lights and reset global ambient - for (int i = 0; i < 8; ++i) { - glDisable(GL_LIGHT0 + i); - } - const GLfloat zeroAmbient[4] = {0.f, 0.f, 0.f, 1.f}; - glLightModelfv(GL_LIGHT_MODEL_AMBIENT, zeroAmbient); - glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE); - - // Setup lights - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadIdentity(); + SDL_GL_MakeCurrent(DDWindow, m_context); + GL11_BeginFrame((Matrix4x4*) &m_projection[0][0]); int lightIdx = 0; for (const auto& l : m_lights) { if (lightIdx > 7) { break; } - GLenum lightId = GL_LIGHT0 + lightIdx++; - const FColor& c = l.color; - GLfloat col[4] = {c.r, c.g, c.b, c.a}; + GL11_UploadLight(lightIdx, (GL11_BridgeSceneLight*) &l); - if (l.positional == 0.f && l.directional == 0.f) { - // Ambient light only - glLightfv(lightId, GL_AMBIENT, col); - const GLfloat black[4] = {0.f, 0.f, 0.f, 1.f}; - glLightfv(lightId, GL_DIFFUSE, black); - glLightfv(lightId, GL_SPECULAR, black); - const GLfloat dummyPos[4] = {0.f, 0.f, 1.f, 0.f}; - glLightfv(lightId, GL_POSITION, dummyPos); - } - else { - glLightfv(lightId, GL_AMBIENT, zeroAmbient); - glLightfv(lightId, GL_DIFFUSE, col); - if (l.directional == 1.0f) { - glLightfv(lightId, GL_SPECULAR, col); - } - else { - const GLfloat black[4] = {0.f, 0.f, 0.f, 1.f}; - glLightfv(lightId, GL_SPECULAR, black); - } - - GLfloat pos[4]; - if (l.directional == 1.f) { - pos[0] = -l.direction.x; - pos[1] = -l.direction.y; - pos[2] = -l.direction.z; - pos[3] = 0.f; - } - else { - pos[0] = l.position.x; - pos[1] = l.position.y; - pos[2] = l.position.z; - pos[3] = 1.f; - } - glLightfv(lightId, GL_POSITION, pos); - } - glEnable(lightId); + lightIdx++; } - glPopMatrix(); - - // Projection and view - glMatrixMode(GL_PROJECTION); - glLoadMatrixf(&m_projection[0][0]); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - return DD_OK; } void OpenGL1Renderer::EnableTransparency() { - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glDepthMask(GL_FALSE); + GL11_EnableTransparency(); } void OpenGL1Renderer::SubmitDraw( @@ -426,75 +351,14 @@ void OpenGL1Renderer::SubmitDraw( { auto& mesh = m_meshs[meshId]; - glLoadMatrixf(&modelViewMatrix[0][0]); - glEnable(GL_NORMALIZE); - - glColor4ub(appearance.color.r, appearance.color.g, appearance.color.b, appearance.color.a); - - if (appearance.shininess != 0.0f) { - GLfloat whiteSpec[] = {1.f, 1.f, 1.f, 1.f}; - glMaterialfv(GL_FRONT, GL_SPECULAR, whiteSpec); - glMaterialf(GL_FRONT, GL_SHININESS, appearance.shininess); - } - else { - GLfloat noSpec[] = {0.0f, 0.0f, 0.0f, 0.0f}; - glMaterialfv(GL_FRONT, GL_SPECULAR, noSpec); - glMaterialf(GL_FRONT, GL_SHININESS, 0.0f); - } - - if (mesh.flat) { - glShadeModel(GL_FLAT); - } - else { - glShadeModel(GL_SMOOTH); - } - // Bind texture if present if (appearance.textureId != NO_TEXTURE_ID) { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); auto& tex = m_textures[appearance.textureId]; - glEnable(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D, tex.glTextureId); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); + GL11_SubmitDraw(mesh, modelViewMatrix, appearance, tex.glTextureId); } else { - glDisable(GL_TEXTURE_2D); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); + GL11_SubmitDraw(mesh, modelViewMatrix, appearance, 0); } - - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_NORMAL_ARRAY); - - if (m_useVBOs) { - glBindBuffer(GL_ARRAY_BUFFER, mesh.vboPositions); - glVertexPointer(3, GL_FLOAT, 0, nullptr); - - glBindBuffer(GL_ARRAY_BUFFER, mesh.vboNormals); - glNormalPointer(GL_FLOAT, 0, nullptr); - - if (appearance.textureId != NO_TEXTURE_ID) { - glBindBuffer(GL_ARRAY_BUFFER, mesh.vboTexcoords); - glTexCoordPointer(2, GL_FLOAT, 0, nullptr); - } - - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh.ibo); - glDrawElements(GL_TRIANGLES, static_cast(mesh.indices.size()), GL_UNSIGNED_SHORT, nullptr); - - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - } - else { - glVertexPointer(3, GL_FLOAT, 0, mesh.positions.data()); - glNormalPointer(GL_FLOAT, 0, mesh.normals.data()); - if (appearance.textureId != NO_TEXTURE_ID) { - glTexCoordPointer(2, GL_FLOAT, 0, mesh.texcoords.data()); - } - - glDrawElements(GL_TRIANGLES, static_cast(mesh.indices.size()), GL_UNSIGNED_SHORT, mesh.indices.data()); - } - - glPopMatrix(); } HRESULT OpenGL1Renderer::FinalizeFrame() @@ -504,101 +368,57 @@ HRESULT OpenGL1Renderer::FinalizeFrame() void OpenGL1Renderer::Resize(int width, int height, const ViewportTransform& viewportTransform) { + SDL_GL_MakeCurrent(DDWindow, m_context); m_width = width; m_height = height; m_viewportTransform = viewportTransform; SDL_DestroySurface(m_renderedImage); m_renderedImage = SDL_CreateSurface(m_width, m_height, SDL_PIXELFORMAT_RGBA32); - glViewport(0, 0, m_width, m_height); + GL11_Resize(width, height); } void OpenGL1Renderer::Clear(float r, float g, float b) { + SDL_GL_MakeCurrent(DDWindow, m_context); m_dirty = true; - glEnable(GL_DEPTH_TEST); - glDepthMask(GL_TRUE); - glClearColor(r, g, b, 1.0f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + GL11_Clear(r, g, b); } void OpenGL1Renderer::Flip() { + SDL_GL_MakeCurrent(DDWindow, m_context); if (m_dirty) { SDL_GL_SwapWindow(DDWindow); m_dirty = false; } } -void OpenGL1Renderer::Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, const SDL_Rect& dstRect) +void OpenGL1Renderer::Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, const SDL_Rect& dstRect, FColor color) { + SDL_GL_MakeCurrent(DDWindow, m_context); m_dirty = true; - glDisable(GL_DEPTH_TEST); - glDepthMask(GL_FALSE); - - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); float left = -m_viewportTransform.offsetX / m_viewportTransform.scale; float right = (m_width - m_viewportTransform.offsetX) / m_viewportTransform.scale; float top = -m_viewportTransform.offsetY / m_viewportTransform.scale; float bottom = (m_height - m_viewportTransform.offsetY) / m_viewportTransform.scale; - glOrtho(left, right, bottom, top, -1, 1); - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadIdentity(); + const GLTextureCacheEntry* texture = nullptr; + if (textureId != NO_TEXTURE_ID) { + texture = &m_textures[textureId]; + } - glDisable(GL_LIGHTING); - glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + GL11_Draw2DImage(texture, srcRect, dstRect, color, left, right, bottom, top); +} - glEnable(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D, m_textures[textureId].glTextureId); - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - - GLint boundTexture = 0; - glGetIntegerv(GL_TEXTURE_BINDING_2D, &boundTexture); - - GLfloat texW, texH; - glGetTexLevelParameterfv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &texW); - glGetTexLevelParameterfv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &texH); - - float u1 = srcRect.x / texW; - float v1 = srcRect.y / texH; - float u2 = (srcRect.x + srcRect.w) / texW; - float v2 = (srcRect.y + srcRect.h) / texH; - - float x1 = (float) dstRect.x; - float y1 = (float) dstRect.y; - float x2 = x1 + dstRect.w; - float y2 = y1 + dstRect.h; - - glBegin(GL_QUADS); - glTexCoord2f(u1, v1); - glVertex2f(x1, y1); - glTexCoord2f(u2, v1); - glVertex2f(x2, y1); - glTexCoord2f(u2, v2); - glVertex2f(x2, y2); - glTexCoord2f(u1, v2); - glVertex2f(x1, y2); - glEnd(); - - // Restore state - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); - glMatrixMode(GL_PROJECTION); - glPopMatrix(); +void OpenGL1Renderer::SetDither(bool dither) +{ + GL11_SetDither(dither); } void OpenGL1Renderer::Download(SDL_Surface* target) { - glFinish(); - glReadPixels(0, 0, m_width, m_height, GL_RGBA, GL_UNSIGNED_BYTE, m_renderedImage->pixels); + GL11_Download(m_renderedImage); SDL_Rect srcRect = { static_cast(m_viewportTransform.offsetX), diff --git a/miniwin/src/d3drm/backends/opengles2/renderer.cpp b/miniwin/src/d3drm/backends/opengles2/renderer.cpp deleted file mode 100644 index 3dbabda2..00000000 --- a/miniwin/src/d3drm/backends/opengles2/renderer.cpp +++ /dev/null @@ -1,717 +0,0 @@ -#include "d3drmrenderer_opengles2.h" -#include "meshutils.h" - -#include -#include -#include -#include -#include - -static GLuint CompileShader(GLenum type, const char* source) -{ - GLuint shader = glCreateShader(type); - glShaderSource(shader, 1, &source, nullptr); - glCompileShader(shader); - GLint success; - glGetShaderiv(shader, GL_COMPILE_STATUS, &success); - if (!success) { - glDeleteShader(shader); - SDL_Log("CompileShader (%s)", SDL_GetError()); - return 0; - } - return shader; -} - -struct SceneLightGLES2 { - float color[4]; - float position[4]; - float direction[4]; -}; - -Direct3DRMRenderer* OpenGLES2Renderer::Create(DWORD width, DWORD height) -{ - SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); - - SDL_Window* window = DDWindow; - bool testWindow = false; - if (!window) { - window = SDL_CreateWindow("OpenGL ES 2.0 test", width, height, SDL_WINDOW_HIDDEN | SDL_WINDOW_OPENGL); - testWindow = true; - } - - SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); - - SDL_GLContext context = SDL_GL_CreateContext(window); - if (!context) { - if (testWindow) { - SDL_DestroyWindow(window); - } - return nullptr; - } - - if (!SDL_GL_MakeCurrent(window, context)) { - if (testWindow) { - SDL_DestroyWindow(window); - } - return nullptr; - } - - glDepthFunc(GL_LEQUAL); - glEnable(GL_CULL_FACE); - glCullFace(GL_BACK); - glFrontFace(GL_CW); - - const char* vertexShaderSource = R"( - attribute vec3 a_position; - attribute vec3 a_normal; - attribute vec2 a_texCoord; - - uniform mat4 u_modelViewMatrix; - uniform mat3 u_normalMatrix; - uniform mat4 u_projectionMatrix; - - varying vec3 v_viewPos; - varying vec3 v_normal; - varying vec2 v_texCoord; - - void main() { - vec4 viewPos = u_modelViewMatrix * vec4(a_position, 1.0); - gl_Position = u_projectionMatrix * viewPos; - v_viewPos = viewPos.xyz; - v_normal = normalize(u_normalMatrix * a_normal); - v_texCoord = a_texCoord; - } - )"; - - const char* fragmentShaderSource = R"( - precision mediump float; - - struct SceneLight { - vec4 color; - vec4 position; - vec4 direction; - }; - - uniform SceneLight u_lights[3]; - uniform int u_lightCount; - - varying vec3 v_viewPos; - varying vec3 v_normal; - varying vec2 v_texCoord; - - uniform float u_shininess; - uniform vec4 u_color; - uniform int u_useTexture; - uniform sampler2D u_texture; - - void main() { - vec3 diffuse = vec3(0.0); - vec3 specular = vec3(0.0); - - for (int i = 0; i < 3; ++i) { - if (i >= u_lightCount) break; - - vec3 lightColor = u_lights[i].color.rgb; - - if (u_lights[i].position.w == 0.0 && u_lights[i].direction.w == 0.0) { - diffuse += lightColor; - continue; - } - - vec3 lightVec; - if (u_lights[i].direction.w == 1.0) { - lightVec = -normalize(u_lights[i].direction.xyz); - } - else { - lightVec = u_lights[i].position.xyz - v_viewPos; - } - lightVec = normalize(lightVec); - - float dotNL = max(dot(v_normal, lightVec), 0.0); - if (dotNL > 0.0) { - // Diffuse contribution - diffuse += dotNL * lightColor; - - // Specular - if (u_shininess > 0.0 && u_lights[i].direction.w == 1.0) { - vec3 viewVec = normalize(-v_viewPos); // Assuming camera at origin - vec3 H = normalize(lightVec + viewVec); - float dotNH = max(dot(v_normal, H), 0.0); - float spec = pow(dotNH, u_shininess); - specular += spec * lightColor; - } - } - } - - vec4 finalColor = u_color; - finalColor.rgb = clamp(diffuse * u_color.rgb + specular, 0.0, 1.0); - if (u_useTexture != 0) { - vec4 texel = texture2D(u_texture, v_texCoord); - finalColor.rgb = clamp(texel.rgb * finalColor.rgb, 0.0, 1.0); - finalColor.a = texel.a; - } - - gl_FragColor = finalColor; - } - )"; - - GLuint vs = CompileShader(GL_VERTEX_SHADER, vertexShaderSource); - GLuint fs = CompileShader(GL_FRAGMENT_SHADER, fragmentShaderSource); - - GLuint shaderProgram = glCreateProgram(); - glAttachShader(shaderProgram, vs); - glAttachShader(shaderProgram, fs); - glBindAttribLocation(shaderProgram, 0, "a_position"); - glBindAttribLocation(shaderProgram, 1, "a_normal"); - glBindAttribLocation(shaderProgram, 2, "a_texCoord"); - glLinkProgram(shaderProgram); - glDeleteShader(vs); - glDeleteShader(fs); - - if (testWindow) { - SDL_DestroyWindow(window); - } - - return new OpenGLES2Renderer(width, height, context, shaderProgram); -} - -OpenGLES2Renderer::OpenGLES2Renderer(DWORD width, DWORD height, SDL_GLContext context, GLuint shaderProgram) - : m_context(context), m_shaderProgram(shaderProgram) -{ - m_width = width; - m_height = height; - m_virtualWidth = width; - m_virtualHeight = height; - m_renderedImage = SDL_CreateSurface(m_width, m_height, SDL_PIXELFORMAT_RGBA32); -} - -OpenGLES2Renderer::~OpenGLES2Renderer() -{ - SDL_DestroySurface(m_renderedImage); - glDeleteProgram(m_shaderProgram); -} - -void OpenGLES2Renderer::PushLights(const SceneLight* lightsArray, size_t count) -{ - if (count > 3) { - SDL_Log("Unsupported number of lights (%d)", static_cast(count)); - count = 3; - } - - m_lights.assign(lightsArray, lightsArray + count); -} - -void OpenGLES2Renderer::SetFrustumPlanes(const Plane* frustumPlanes) -{ -} - -void OpenGLES2Renderer::SetProjection(const D3DRMMATRIX4D& projection, D3DVALUE front, D3DVALUE back) -{ - memcpy(&m_projection, projection, sizeof(D3DRMMATRIX4D)); -} - -struct TextureDestroyContextGLS2 { - OpenGLES2Renderer* renderer; - Uint32 textureId; -}; - -void OpenGLES2Renderer::AddTextureDestroyCallback(Uint32 id, IDirect3DRMTexture* texture) -{ - auto* ctx = new TextureDestroyContextGLS2{this, id}; - texture->AddDestroyCallback( - [](IDirect3DRMObject* obj, void* arg) { - auto* ctx = static_cast(arg); - auto& cache = ctx->renderer->m_textures[ctx->textureId]; - if (cache.glTextureId != 0) { - glDeleteTextures(1, &cache.glTextureId); - cache.glTextureId = 0; - cache.texture = nullptr; - } - delete ctx; - }, - ctx - ); -} - -Uint32 OpenGLES2Renderer::GetTextureId(IDirect3DRMTexture* iTexture) -{ - auto texture = static_cast(iTexture); - auto surface = static_cast(texture->m_surface); - - for (Uint32 i = 0; i < m_textures.size(); ++i) { - auto& tex = m_textures[i]; - if (tex.texture == texture) { - if (tex.version != texture->m_version) { - glDeleteTextures(1, &tex.glTextureId); - glGenTextures(1, &tex.glTextureId); - glBindTexture(GL_TEXTURE_2D, tex.glTextureId); - - SDL_Surface* surf = SDL_ConvertSurface(surface->m_surface, SDL_PIXELFORMAT_RGBA32); - if (!surf) { - return NO_TEXTURE_ID; - } - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, surf->w, surf->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, surf->pixels); - SDL_DestroySurface(surf); - - tex.version = texture->m_version; - } - return i; - } - } - - GLuint texId; - glGenTextures(1, &texId); - glBindTexture(GL_TEXTURE_2D, texId); - - SDL_Surface* surf = SDL_ConvertSurface(surface->m_surface, SDL_PIXELFORMAT_RGBA32); - if (!surf) { - return NO_TEXTURE_ID; - } - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, surf->w, surf->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, surf->pixels); - - for (Uint32 i = 0; i < m_textures.size(); ++i) { - auto& tex = m_textures[i]; - if (!tex.texture) { - tex.texture = texture; - tex.version = texture->m_version; - tex.glTextureId = texId; - tex.width = surf->w; - tex.height = surf->h; - AddTextureDestroyCallback(i, texture); - return i; - } - } - - m_textures.push_back({texture, texture->m_version, texId, (uint16_t) surf->w, (uint16_t) surf->h}); - SDL_DestroySurface(surf); - AddTextureDestroyCallback((Uint32) (m_textures.size() - 1), texture); - return (Uint32) (m_textures.size() - 1); -} - -GLES2MeshCacheEntry GLES2UploadMesh(const MeshGroup& meshGroup) -{ - GLES2MeshCacheEntry cache{&meshGroup, meshGroup.version}; - - cache.flat = meshGroup.quality == D3DRMRENDER_FLAT || meshGroup.quality == D3DRMRENDER_UNLITFLAT; - - std::vector vertices; - if (cache.flat) { - FlattenSurfaces( - meshGroup.vertices.data(), - meshGroup.vertices.size(), - meshGroup.indices.data(), - meshGroup.indices.size(), - meshGroup.texture != nullptr, - vertices, - cache.indices - ); - } - else { - vertices = meshGroup.vertices; - cache.indices.resize(meshGroup.indices.size()); - std::transform(meshGroup.indices.begin(), meshGroup.indices.end(), cache.indices.begin(), [](DWORD index) { - return static_cast(index); - }); - } - - std::vector texcoords; - if (meshGroup.texture) { - texcoords.resize(vertices.size()); - std::transform(vertices.begin(), vertices.end(), texcoords.begin(), [](const D3DRMVERTEX& v) { - return v.texCoord; - }); - } - std::vector positions(vertices.size()); - std::transform(vertices.begin(), vertices.end(), positions.begin(), [](const D3DRMVERTEX& v) { - return v.position; - }); - std::vector normals(vertices.size()); - std::transform(vertices.begin(), vertices.end(), normals.begin(), [](const D3DRMVERTEX& v) { return v.normal; }); - - glGenBuffers(1, &cache.vboPositions); - glBindBuffer(GL_ARRAY_BUFFER, cache.vboPositions); - glBufferData(GL_ARRAY_BUFFER, positions.size() * sizeof(D3DVECTOR), positions.data(), GL_STATIC_DRAW); - - glGenBuffers(1, &cache.vboNormals); - glBindBuffer(GL_ARRAY_BUFFER, cache.vboNormals); - glBufferData(GL_ARRAY_BUFFER, normals.size() * sizeof(D3DVECTOR), normals.data(), GL_STATIC_DRAW); - - if (meshGroup.texture) { - glGenBuffers(1, &cache.vboTexcoords); - glBindBuffer(GL_ARRAY_BUFFER, cache.vboTexcoords); - glBufferData(GL_ARRAY_BUFFER, texcoords.size() * sizeof(TexCoord), texcoords.data(), GL_STATIC_DRAW); - } - - glGenBuffers(1, &cache.ibo); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, cache.ibo); - glBufferData( - GL_ELEMENT_ARRAY_BUFFER, - cache.indices.size() * sizeof(cache.indices[0]), - cache.indices.data(), - GL_STATIC_DRAW - ); - - return cache; -} - -struct GLES2MeshDestroyContext { - OpenGLES2Renderer* renderer; - Uint32 id; -}; - -void OpenGLES2Renderer::AddMeshDestroyCallback(Uint32 id, IDirect3DRMMesh* mesh) -{ - auto* ctx = new GLES2MeshDestroyContext{this, id}; - mesh->AddDestroyCallback( - [](IDirect3DRMObject*, void* arg) { - auto* ctx = static_cast(arg); - auto& cache = ctx->renderer->m_meshs[ctx->id]; - cache.meshGroup = nullptr; - glDeleteBuffers(1, &cache.vboPositions); - glDeleteBuffers(1, &cache.vboNormals); - glDeleteBuffers(1, &cache.vboTexcoords); - glDeleteBuffers(1, &cache.ibo); - delete ctx; - }, - ctx - ); -} - -Uint32 OpenGLES2Renderer::GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* meshGroup) -{ - for (Uint32 i = 0; i < m_meshs.size(); ++i) { - auto& cache = m_meshs[i]; - if (cache.meshGroup == meshGroup) { - if (cache.version != meshGroup->version) { - cache = std::move(GLES2UploadMesh(*meshGroup)); - } - return i; - } - } - - auto newCache = GLES2UploadMesh(*meshGroup); - - for (Uint32 i = 0; i < m_meshs.size(); ++i) { - auto& cache = m_meshs[i]; - if (!cache.meshGroup) { - cache = std::move(newCache); - AddMeshDestroyCallback(i, mesh); - return i; - } - } - - m_meshs.push_back(std::move(newCache)); - AddMeshDestroyCallback((Uint32) (m_meshs.size() - 1), mesh); - return (Uint32) (m_meshs.size() - 1); -} - -void OpenGLES2Renderer::GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc) -{ - halDesc->dcmColorModel = D3DCOLORMODEL::RGB; - halDesc->dwFlags = D3DDD_DEVICEZBUFFERBITDEPTH; - halDesc->dwDeviceZBufferBitDepth = DDBD_16; - const char* extensions = (const char*) glGetString(GL_EXTENSIONS); - if (extensions) { - if (strstr(extensions, "GL_OES_depth24")) { - halDesc->dwDeviceZBufferBitDepth |= DDBD_24; - } - if (strstr(extensions, "GL_OES_depth32")) { - halDesc->dwDeviceZBufferBitDepth |= DDBD_32; - } - } - helDesc->dwDeviceRenderBitDepth = DDBD_32; - halDesc->dpcTriCaps.dwTextureCaps = D3DPTEXTURECAPS_PERSPECTIVE; - halDesc->dpcTriCaps.dwShadeCaps = D3DPSHADECAPS_ALPHAFLATBLEND; - halDesc->dpcTriCaps.dwTextureFilterCaps = D3DPTFILTERCAPS_LINEAR; - - memset(helDesc, 0, sizeof(D3DDEVICEDESC)); -} - -const char* OpenGLES2Renderer::GetName() -{ - return "OpenGL ES 2.0 HAL"; -} - -HRESULT OpenGLES2Renderer::BeginFrame() -{ - m_dirty = true; - - glDisable(GL_BLEND); - glEnable(GL_DEPTH_TEST); - glDepthMask(GL_TRUE); - - glUseProgram(m_shaderProgram); - - SceneLightGLES2 lightData[3]; - int lightCount = std::min(static_cast(m_lights.size()), 3); - - for (int i = 0; i < lightCount; ++i) { - const auto& src = m_lights[i]; - lightData[i].color[0] = src.color.r; - lightData[i].color[1] = src.color.g; - lightData[i].color[2] = src.color.b; - lightData[i].color[3] = src.color.a; - - lightData[i].position[0] = src.position.x; - lightData[i].position[1] = src.position.y; - lightData[i].position[2] = src.position.z; - lightData[i].position[3] = src.positional; - - lightData[i].direction[0] = src.direction.x; - lightData[i].direction[1] = src.direction.y; - lightData[i].direction[2] = src.direction.z; - lightData[i].direction[3] = src.directional; - } - - for (int i = 0; i < lightCount; ++i) { - std::string base = "u_lights[" + std::to_string(i) + "]"; - glUniform4fv(glGetUniformLocation(m_shaderProgram, (base + ".color").c_str()), 1, lightData[i].color); - glUniform4fv(glGetUniformLocation(m_shaderProgram, (base + ".position").c_str()), 1, lightData[i].position); - glUniform4fv(glGetUniformLocation(m_shaderProgram, (base + ".direction").c_str()), 1, lightData[i].direction); - } - glUniform1i(glGetUniformLocation(m_shaderProgram, "u_lightCount"), lightCount); - return DD_OK; -} - -void OpenGLES2Renderer::EnableTransparency() -{ - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glDepthMask(GL_FALSE); -} - -void OpenGLES2Renderer::SubmitDraw( - DWORD meshId, - const D3DRMMATRIX4D& modelViewMatrix, - const D3DRMMATRIX4D& worldMatrix, - const D3DRMMATRIX4D& viewMatrix, - const Matrix3x3& normalMatrix, - const Appearance& appearance -) -{ - auto& mesh = m_meshs[meshId]; - - glUniformMatrix4fv(glGetUniformLocation(m_shaderProgram, "u_modelViewMatrix"), 1, GL_FALSE, &modelViewMatrix[0][0]); - glUniformMatrix3fv(glGetUniformLocation(m_shaderProgram, "u_normalMatrix"), 1, GL_FALSE, &normalMatrix[0][0]); - glUniformMatrix4fv(glGetUniformLocation(m_shaderProgram, "u_projectionMatrix"), 1, GL_FALSE, &m_projection[0][0]); - - glUniform4f( - glGetUniformLocation(m_shaderProgram, "u_color"), - appearance.color.r / 255.0f, - appearance.color.g / 255.0f, - appearance.color.b / 255.0f, - appearance.color.a / 255.0f - ); - - glUniform1f(glGetUniformLocation(m_shaderProgram, "u_shininess"), appearance.shininess); - - if (appearance.textureId != NO_TEXTURE_ID) { - glUniform1i(glGetUniformLocation(m_shaderProgram, "u_useTexture"), 1); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, m_textures[appearance.textureId].glTextureId); - glUniform1i(glGetUniformLocation(m_shaderProgram, "u_texture"), 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - } - else { - glUniform1i(glGetUniformLocation(m_shaderProgram, "u_useTexture"), 0); - } - - glBindBuffer(GL_ARRAY_BUFFER, mesh.vboPositions); - GLint posLoc = glGetAttribLocation(m_shaderProgram, "a_position"); - glEnableVertexAttribArray(posLoc); - glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, 0, nullptr); - - glBindBuffer(GL_ARRAY_BUFFER, mesh.vboNormals); - GLint normLoc = glGetAttribLocation(m_shaderProgram, "a_normal"); - glEnableVertexAttribArray(normLoc); - glVertexAttribPointer(normLoc, 3, GL_FLOAT, GL_FALSE, 0, nullptr); - - GLint texLoc = glGetAttribLocation(m_shaderProgram, "a_texCoord"); - if (appearance.textureId != NO_TEXTURE_ID) { - glBindBuffer(GL_ARRAY_BUFFER, mesh.vboTexcoords); - glEnableVertexAttribArray(texLoc); - glVertexAttribPointer(texLoc, 2, GL_FLOAT, GL_FALSE, 0, nullptr); - } - - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh.ibo); - glDrawElements(GL_TRIANGLES, static_cast(mesh.indices.size()), GL_UNSIGNED_SHORT, nullptr); - - glDisableVertexAttribArray(posLoc); - glDisableVertexAttribArray(normLoc); - glDisableVertexAttribArray(texLoc); -} - -HRESULT OpenGLES2Renderer::FinalizeFrame() -{ - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - glUseProgram(0); - - return DD_OK; -} - -void OpenGLES2Renderer::Resize(int width, int height, const ViewportTransform& viewportTransform) -{ - m_width = width; - m_height = height; - m_viewportTransform = viewportTransform; - SDL_DestroySurface(m_renderedImage); - m_renderedImage = SDL_CreateSurface(m_width, m_height, SDL_PIXELFORMAT_RGBA32); - glViewport(0, 0, m_width, m_height); -} - -void OpenGLES2Renderer::Clear(float r, float g, float b) -{ - m_dirty = true; - glEnable(GL_DEPTH_TEST); - glDepthMask(GL_TRUE); - glClearColor(r, g, b, 1.0f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); -} - -void OpenGLES2Renderer::Flip() -{ - if (m_dirty) { - SDL_GL_SwapWindow(DDWindow); - m_dirty = false; - } -} - -void CreateOrthoMatrix(float left, float right, float bottom, float top, D3DRMMATRIX4D& outMatrix) -{ - float near = -1.0f; - float far = 1.0f; - float rl = right - left; - float tb = top - bottom; - float fn = far - near; - - outMatrix[0][0] = 2.0f / rl; - outMatrix[0][1] = 0.0f; - outMatrix[0][2] = 0.0f; - outMatrix[0][3] = 0.0f; - - outMatrix[1][0] = 0.0f; - outMatrix[1][1] = 2.0f / tb; - outMatrix[1][2] = 0.0f; - outMatrix[1][3] = 0.0f; - - outMatrix[2][0] = 0.0f; - outMatrix[2][1] = 0.0f; - outMatrix[2][2] = -2.0f / fn; - outMatrix[2][3] = 0.0f; - - outMatrix[3][0] = -(right + left) / rl; - outMatrix[3][1] = -(top + bottom) / tb; - outMatrix[3][2] = -(far + near) / fn; - outMatrix[3][3] = 1.0f; -} - -void OpenGLES2Renderer::Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, const SDL_Rect& dstRect) -{ - m_dirty = true; - - glDisable(GL_DEPTH_TEST); - glDepthMask(GL_FALSE); - - glUseProgram(m_shaderProgram); - - float color[] = {1.0f, 1.0f, 1.0f, 1.0f}; - float blank[] = {0.0f, 0.0f, 0.0f, 0.0f}; - glUniform4fv(glGetUniformLocation(m_shaderProgram, "u_lights[0].color"), 1, color); - glUniform4fv(glGetUniformLocation(m_shaderProgram, "u_lights[0].position"), 1, blank); - glUniform4fv(glGetUniformLocation(m_shaderProgram, "u_lights[0].direction"), 1, blank); - glUniform1i(glGetUniformLocation(m_shaderProgram, "u_lightCount"), 1); - - glUniform4f(glGetUniformLocation(m_shaderProgram, "u_color"), 1.0f, 1.0f, 1.0f, 1.0f); - glUniform1f(glGetUniformLocation(m_shaderProgram, "u_shininess"), 0.0f); - - float left = -m_viewportTransform.offsetX / m_viewportTransform.scale; - float right = (m_width - m_viewportTransform.offsetX) / m_viewportTransform.scale; - float top = -m_viewportTransform.offsetY / m_viewportTransform.scale; - float bottom = (m_height - m_viewportTransform.offsetY) / m_viewportTransform.scale; - - D3DRMMATRIX4D projection; - CreateOrthoMatrix(left, right, bottom, top, projection); - - D3DRMMATRIX4D identity = {{1.f, 0.f, 0.f, 0.f}, {0.f, 1.f, 0.f, 0.f}, {0.f, 0.f, 1.f, 0.f}, {0.f, 0.f, 0.f, 1.f}}; - glUniformMatrix4fv(glGetUniformLocation(m_shaderProgram, "u_modelViewMatrix"), 1, GL_FALSE, &identity[0][0]); - glUniformMatrix3fv(glGetUniformLocation(m_shaderProgram, "u_normalMatrix"), 1, GL_FALSE, &identity[0][0]); - glUniformMatrix4fv(glGetUniformLocation(m_shaderProgram, "u_projectionMatrix"), 1, GL_FALSE, &projection[0][0]); - - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - glActiveTexture(GL_TEXTURE0); - glUniform1i(glGetUniformLocation(m_shaderProgram, "u_useTexture"), 1); - const GLES2TextureCacheEntry& texture = m_textures[textureId]; - glBindTexture(GL_TEXTURE_2D, texture.glTextureId); - glUniform1i(glGetUniformLocation(m_shaderProgram, "u_texture"), 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - float texW = texture.width; - float texH = texture.height; - - float u1 = srcRect.x / texW; - float v1 = srcRect.y / texH; - float u2 = (srcRect.x + srcRect.w) / texW; - float v2 = (srcRect.y + srcRect.h) / texH; - - float x1 = static_cast(dstRect.x); - float y1 = static_cast(dstRect.y); - float x2 = x1 + dstRect.w; - float y2 = y1 + dstRect.h; - - GLfloat vertices[] = {x1, y1, u1, v1, x2, y1, u2, v1, x1, y2, u1, v2, x2, y2, u2, v2}; - - GLint posLoc = glGetAttribLocation(m_shaderProgram, "a_position"); - GLint texLoc = glGetAttribLocation(m_shaderProgram, "a_texCoord"); - - glEnableVertexAttribArray(posLoc); - glEnableVertexAttribArray(texLoc); - - glVertexAttribPointer(posLoc, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), vertices); - glVertexAttribPointer(texLoc, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), vertices + 2); - - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - - glDisableVertexAttribArray(posLoc); - glDisableVertexAttribArray(texLoc); - - glBindTexture(GL_TEXTURE_2D, 0); - glUseProgram(0); -} - -void OpenGLES2Renderer::Download(SDL_Surface* target) -{ - glFinish(); - glReadPixels(0, 0, m_width, m_height, GL_RGBA, GL_UNSIGNED_BYTE, m_renderedImage->pixels); - - SDL_Rect srcRect = { - static_cast(m_viewportTransform.offsetX), - static_cast(m_viewportTransform.offsetY), - static_cast(target->w * m_viewportTransform.scale), - static_cast(target->h * m_viewportTransform.scale), - }; - - SDL_Surface* bufferClone = SDL_CreateSurface(target->w, target->h, SDL_PIXELFORMAT_RGBA32); - if (!bufferClone) { - SDL_Log("SDL_CreateSurface: %s", SDL_GetError()); - return; - } - - SDL_BlitSurfaceScaled(m_renderedImage, &srcRect, bufferClone, nullptr, SDL_SCALEMODE_NEAREST); - - // Flip image vertically into target - SDL_Rect rowSrc = {0, 0, bufferClone->w, 1}; - SDL_Rect rowDst = {0, 0, bufferClone->w, 1}; - for (int y = 0; y < bufferClone->h; ++y) { - rowSrc.y = y; - rowDst.y = bufferClone->h - 1 - y; - SDL_BlitSurface(bufferClone, &rowSrc, target, &rowDst); - } - - SDL_DestroySurface(bufferClone); -} diff --git a/miniwin/src/d3drm/backends/opengles3/renderer.cpp b/miniwin/src/d3drm/backends/opengles3/renderer.cpp new file mode 100644 index 00000000..98cf6db5 --- /dev/null +++ b/miniwin/src/d3drm/backends/opengles3/renderer.cpp @@ -0,0 +1,895 @@ +#include "d3drmrenderer_opengles3.h" +#include "meshutils.h" + +#include +#include +#include +#include +#include + +static GLuint CompileShader(GLenum type, const char* source) +{ + GLuint shader = glCreateShader(type); + glShaderSource(shader, 1, &source, nullptr); + glCompileShader(shader); + GLint success; + glGetShaderiv(shader, GL_COMPILE_STATUS, &success); + if (!success) { + GLint logLength = 0; + glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &logLength); + if (logLength > 0) { + std::vector log(logLength); + glGetShaderInfoLog(shader, logLength, nullptr, log.data()); + SDL_Log("Shader compile error: %s", log.data()); + } + else { + SDL_Log("CompileShader (%s)", SDL_GetError()); + } + glDeleteShader(shader); + return 0; + } + return shader; +} + +struct SceneLightGLES3 { + float color[4]; + float position[4]; + float direction[4]; +}; + +Direct3DRMRenderer* OpenGLES3Renderer::Create(DWORD width, DWORD height, DWORD msaaSamples, float anisotropic) +{ + // We have to reset the attributes here after having enumerated the + // OpenGL ES 2.0 renderer, or else SDL gets very confused by SDL_GL_DEPTH_SIZE + // call below when on an EGL-based backend, and crashes with EGL_BAD_MATCH. + SDL_GL_ResetAttributes(); + // But ResetAttributes resets it to 16. + SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); + + if (!DDWindow) { + SDL_Log("No window handler"); + return nullptr; + } + + SDL_GLContext context = SDL_GL_CreateContext(DDWindow); + if (!context) { + SDL_Log("SDL_GL_CreateContext: %s", SDL_GetError()); + return nullptr; + } + + if (!SDL_GL_MakeCurrent(DDWindow, context)) { + SDL_GL_DestroyContext(context); + return nullptr; + } + + glDepthFunc(GL_LEQUAL); + glEnable(GL_CULL_FACE); + glCullFace(GL_BACK); + glFrontFace(GL_CW); + + const char* vertexShaderSource = R"(#version 300 es + precision highp float; + + in vec3 a_position; + in vec3 a_normal; + in vec2 a_texCoord; + + uniform mat4 u_modelViewMatrix; + uniform mat3 u_normalMatrix; + uniform mat4 u_projectionMatrix; + + out vec3 v_viewPos; + out vec3 v_normal; + out vec2 v_texCoord; + + void main() { + vec4 viewPos = u_modelViewMatrix * vec4(a_position, 1.0); + gl_Position = u_projectionMatrix * viewPos; + v_viewPos = viewPos.xyz; + v_normal = normalize(u_normalMatrix * a_normal); + v_texCoord = a_texCoord; + } + )"; + + const char* fragmentShaderSource = R"(#version 300 es + precision mediump float; + + struct SceneLight { + vec4 color; + vec4 position; + vec4 direction; + }; + + uniform SceneLight u_lights[3]; + uniform int u_lightCount; + + in vec3 v_viewPos; + in vec3 v_normal; + in vec2 v_texCoord; + + uniform float u_shininess; + uniform vec4 u_color; + uniform bool u_useTexture; + uniform sampler2D u_texture; + + out vec4 fragColor; + + void main() { + vec3 diffuse = vec3(0.0); + vec3 specular = vec3(0.0); + + for (int i = 0; i < u_lightCount; ++i) { + vec3 lightColor = u_lights[i].color.rgb; + + if (u_lights[i].position.w == 0.0 && u_lights[i].direction.w == 0.0) { + diffuse += lightColor; + continue; + } + + vec3 lightVec; + if (u_lights[i].direction.w == 1.0) { + lightVec = -normalize(u_lights[i].direction.xyz); + } + else { + lightVec = u_lights[i].position.xyz - v_viewPos; + } + lightVec = normalize(lightVec); + + float dotNL = max(dot(v_normal, lightVec), 0.0); + if (dotNL > 0.0) { + // Diffuse contribution + diffuse += dotNL * lightColor; + + // Specular + if (u_shininess > 0.0 && u_lights[i].direction.w == 1.0) { + vec3 viewVec = normalize(-v_viewPos); + vec3 H = normalize(lightVec + viewVec); + float dotNH = max(dot(v_normal, H), 0.0); + float spec = pow(dotNH, u_shininess); + specular += spec * lightColor; + } + } + } + + vec4 finalColor = u_color; + finalColor.rgb = clamp(diffuse * u_color.rgb + specular, 0.0, 1.0); + if (u_useTexture) { + vec4 texel = texture(u_texture, v_texCoord); + finalColor.rgb = clamp(texel.rgb * finalColor.rgb, 0.0, 1.0); + finalColor.a = texel.a; + } + + fragColor = finalColor; + } + )"; + + GLuint vs = CompileShader(GL_VERTEX_SHADER, vertexShaderSource); + GLuint fs = CompileShader(GL_FRAGMENT_SHADER, fragmentShaderSource); + + GLuint shaderProgram = glCreateProgram(); + glAttachShader(shaderProgram, vs); + glAttachShader(shaderProgram, fs); + glBindAttribLocation(shaderProgram, 0, "a_position"); + glBindAttribLocation(shaderProgram, 1, "a_normal"); + glBindAttribLocation(shaderProgram, 2, "a_texCoord"); + glLinkProgram(shaderProgram); + glDeleteShader(vs); + glDeleteShader(fs); + + return new OpenGLES3Renderer(width, height, msaaSamples, anisotropic, context, shaderProgram); +} + +GLES3MeshCacheEntry OpenGLES3Renderer::GLES3UploadMesh(const MeshGroup& meshGroup, bool forceUV) +{ + GLES3MeshCacheEntry cache{&meshGroup, meshGroup.version}; + + cache.flat = meshGroup.quality == D3DRMRENDER_FLAT || meshGroup.quality == D3DRMRENDER_UNLITFLAT; + + std::vector vertices; + if (cache.flat) { + FlattenSurfaces( + meshGroup.vertices.data(), + meshGroup.vertices.size(), + meshGroup.indices.data(), + meshGroup.indices.size(), + meshGroup.texture != nullptr || forceUV, + vertices, + cache.indices + ); + } + else { + vertices = meshGroup.vertices; + cache.indices.resize(meshGroup.indices.size()); + std::transform(meshGroup.indices.begin(), meshGroup.indices.end(), cache.indices.begin(), [](DWORD index) { + return static_cast(index); + }); + } + + std::vector texcoords; + if (meshGroup.texture || forceUV) { + texcoords.resize(vertices.size()); + std::transform(vertices.begin(), vertices.end(), texcoords.begin(), [](const D3DRMVERTEX& v) { + return v.texCoord; + }); + } + std::vector positions(vertices.size()); + std::transform(vertices.begin(), vertices.end(), positions.begin(), [](const D3DRMVERTEX& v) { + return v.position; + }); + std::vector normals(vertices.size()); + std::transform(vertices.begin(), vertices.end(), normals.begin(), [](const D3DRMVERTEX& v) { return v.normal; }); + + glGenVertexArrays(1, &cache.vao); + glBindVertexArray(cache.vao); + + glGenBuffers(1, &cache.vboPositions); + glBindBuffer(GL_ARRAY_BUFFER, cache.vboPositions); + glBufferData(GL_ARRAY_BUFFER, positions.size() * sizeof(D3DVECTOR), positions.data(), GL_STATIC_DRAW); + glEnableVertexAttribArray(m_posLoc); + glVertexAttribPointer(m_posLoc, 3, GL_FLOAT, GL_FALSE, 0, nullptr); + + glGenBuffers(1, &cache.vboNormals); + glBindBuffer(GL_ARRAY_BUFFER, cache.vboNormals); + glBufferData(GL_ARRAY_BUFFER, normals.size() * sizeof(D3DVECTOR), normals.data(), GL_STATIC_DRAW); + glEnableVertexAttribArray(m_normLoc); + glVertexAttribPointer(m_normLoc, 3, GL_FLOAT, GL_FALSE, 0, nullptr); + + if (meshGroup.texture || forceUV) { + glGenBuffers(1, &cache.vboTexcoords); + glBindBuffer(GL_ARRAY_BUFFER, cache.vboTexcoords); + glBufferData(GL_ARRAY_BUFFER, texcoords.size() * sizeof(TexCoord), texcoords.data(), GL_STATIC_DRAW); + glEnableVertexAttribArray(m_texLoc); + glVertexAttribPointer(m_texLoc, 2, GL_FLOAT, GL_FALSE, 0, nullptr); + } + + glGenBuffers(1, &cache.ibo); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, cache.ibo); + glBufferData( + GL_ELEMENT_ARRAY_BUFFER, + cache.indices.size() * sizeof(cache.indices[0]), + cache.indices.data(), + GL_STATIC_DRAW + ); + + glBindVertexArray(0); + + return cache; +} + +bool OpenGLES3Renderer::UploadTexture(SDL_Surface* source, GLuint& outTexId, bool isUI) +{ + SDL_Surface* surf = source; + if (source->format != SDL_PIXELFORMAT_RGBA32) { + surf = SDL_ConvertSurface(source, SDL_PIXELFORMAT_RGBA32); + if (!surf) { + return false; + } + } + + glGenTextures(1, &outTexId); + glBindTexture(GL_TEXTURE_2D, outTexId); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, surf->w, surf->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, surf->pixels); + + if (isUI) { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + } + else { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + if (m_anisotropic > 1.0f) { + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, m_anisotropic); + } + glGenerateMipmap(GL_TEXTURE_2D); + } + + if (surf != source) { + SDL_DestroySurface(surf); + } + + return true; +} + +OpenGLES3Renderer::OpenGLES3Renderer( + DWORD width, + DWORD height, + DWORD msaaSamples, + float anisotropic, + SDL_GLContext context, + GLuint shaderProgram +) + : m_context(context), m_shaderProgram(shaderProgram), m_msaa(msaaSamples), m_anisotropic(anisotropic) +{ + glGenFramebuffers(1, &m_fbo); + glBindFramebuffer(GL_FRAMEBUFFER, m_fbo); + + GLint maxSamples; + glGetIntegerv(GL_MAX_SAMPLES, &maxSamples); + if (m_msaa > maxSamples) { + m_msaa = maxSamples; + } + SDL_Log( + "MSAA is %s. Requested samples: %d, active samples: %d, max samples: %d", + m_msaa > 1 ? "on" : "off", + msaaSamples, + m_msaa, + maxSamples + ); + + if (m_msaa > 1) { + glGenFramebuffers(1, &m_resolveFBO); + } + + bool anisoAvailable = SDL_GL_ExtensionSupported("GL_EXT_texture_filter_anisotropic"); + GLfloat maxAniso = 0.0f; + if (anisoAvailable) { + glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &maxAniso); + } + if (m_anisotropic > maxAniso) { + m_anisotropic = maxAniso; + } + SDL_Log( + "Anisotropic is %s. Requested: %f, active: %f, max aniso: %f", + m_anisotropic > 1.0f ? "on" : "off", + anisotropic, + m_anisotropic, + maxAniso + ); + + m_virtualWidth = width; + m_virtualHeight = height; + ViewportTransform viewportTransform = {1.0f, 0.0f, 0.0f}; + Resize(width, height, viewportTransform); + + SDL_Surface* dummySurface = SDL_CreateSurface(1, 1, SDL_PIXELFORMAT_RGBA32); + if (!dummySurface) { + SDL_Log("Failed to create surface: %s", SDL_GetError()); + return; + } + if (!SDL_LockSurface(dummySurface)) { + SDL_Log("Failed to lock surface: %s", SDL_GetError()); + SDL_DestroySurface(dummySurface); + return; + } + ((Uint32*) dummySurface->pixels)[0] = 0xFFFFFFFF; + SDL_UnlockSurface(dummySurface); + + UploadTexture(dummySurface, m_dummyTexture, false); + if (!m_dummyTexture) { + SDL_DestroySurface(dummySurface); + SDL_Log("Failed to create surface: %s", SDL_GetError()); + return; + } + SDL_DestroySurface(dummySurface); + + m_posLoc = glGetAttribLocation(m_shaderProgram, "a_position"); + m_normLoc = glGetAttribLocation(m_shaderProgram, "a_normal"); + m_texLoc = glGetAttribLocation(m_shaderProgram, "a_texCoord"); + m_colorLoc = glGetUniformLocation(m_shaderProgram, "u_color"); + m_shinLoc = glGetUniformLocation(m_shaderProgram, "u_shininess"); + m_lightCountLoc = glGetUniformLocation(m_shaderProgram, "u_lightCount"); + m_useTextureLoc = glGetUniformLocation(m_shaderProgram, "u_useTexture"); + m_textureLoc = glGetUniformLocation(m_shaderProgram, "u_texture"); + for (int i = 0; i < 3; ++i) { + std::string base = "u_lights[" + std::to_string(i) + "]"; + u_lightLocs[i][0] = glGetUniformLocation(m_shaderProgram, (base + ".color").c_str()); + u_lightLocs[i][1] = glGetUniformLocation(m_shaderProgram, (base + ".position").c_str()); + u_lightLocs[i][2] = glGetUniformLocation(m_shaderProgram, (base + ".direction").c_str()); + } + m_modelViewMatrixLoc = glGetUniformLocation(m_shaderProgram, "u_modelViewMatrix"); + m_normalMatrixLoc = glGetUniformLocation(m_shaderProgram, "u_normalMatrix"); + m_projectionMatrixLoc = glGetUniformLocation(m_shaderProgram, "u_projectionMatrix"); + + m_uiMesh.vertices = { + {{0.0f, 0.0f, 0.0f}, {0, 0, -1}, {0.0f, 0.0f}}, + {{1.0f, 0.0f, 0.0f}, {0, 0, -1}, {1.0f, 0.0f}}, + {{1.0f, 1.0f, 0.0f}, {0, 0, -1}, {1.0f, 1.0f}}, + {{0.0f, 1.0f, 0.0f}, {0, 0, -1}, {0.0f, 1.0f}} + }; + m_uiMesh.indices = {0, 1, 2, 0, 2, 3}; + m_uiMeshCache = GLES3UploadMesh(m_uiMesh, true); + + glUseProgram(m_shaderProgram); +} + +OpenGLES3Renderer::~OpenGLES3Renderer() +{ + SDL_DestroySurface(m_renderedImage); + glDeleteTextures(1, &m_dummyTexture); + glDeleteProgram(m_shaderProgram); + glDeleteRenderbuffers(1, &m_colorTarget); + glDeleteRenderbuffers(1, &m_depthTarget); + glDeleteFramebuffers(1, &m_fbo); + if (m_msaa > 1) { + glDeleteRenderbuffers(1, &m_resolveColor); + glDeleteFramebuffers(1, &m_resolveFBO); + } + + SDL_GL_DestroyContext(m_context); +} + +void OpenGLES3Renderer::PushLights(const SceneLight* lightsArray, size_t count) +{ + if (count > 3) { + SDL_Log("Unsupported number of lights (%d)", static_cast(count)); + count = 3; + } + + m_lights.assign(lightsArray, lightsArray + count); +} + +void OpenGLES3Renderer::SetFrustumPlanes(const Plane* frustumPlanes) +{ +} + +void OpenGLES3Renderer::SetProjection(const D3DRMMATRIX4D& projection, D3DVALUE front, D3DVALUE back) +{ + memcpy(&m_projection, projection, sizeof(D3DRMMATRIX4D)); +} + +struct TextureDestroyContextGLS2 { + OpenGLES3Renderer* renderer; + Uint32 textureId; +}; + +void OpenGLES3Renderer::AddTextureDestroyCallback(Uint32 id, IDirect3DRMTexture* texture) +{ + auto* ctx = new TextureDestroyContextGLS2{this, id}; + texture->AddDestroyCallback( + [](IDirect3DRMObject* obj, void* arg) { + auto* ctx = static_cast(arg); + auto& cache = ctx->renderer->m_textures[ctx->textureId]; + if (cache.glTextureId != 0) { + glDeleteTextures(1, &cache.glTextureId); + cache.glTextureId = 0; + cache.texture = nullptr; + } + delete ctx; + }, + ctx + ); +} + +Uint32 OpenGLES3Renderer::GetTextureId(IDirect3DRMTexture* iTexture, bool isUI, float scaleX, float scaleY) +{ + SDL_GL_MakeCurrent(DDWindow, m_context); + auto texture = static_cast(iTexture); + auto surface = static_cast(texture->m_surface); + + for (Uint32 i = 0; i < m_textures.size(); ++i) { + auto& tex = m_textures[i]; + if (tex.texture == texture) { + if (tex.version != texture->m_version) { + glDeleteTextures(1, &tex.glTextureId); + if (UploadTexture(surface->m_surface, tex.glTextureId, isUI)) { + tex.version = texture->m_version; + } + } + return i; + } + } + + GLuint texId; + if (!UploadTexture(surface->m_surface, texId, isUI)) { + return NO_TEXTURE_ID; + } + + for (Uint32 i = 0; i < m_textures.size(); ++i) { + auto& tex = m_textures[i]; + if (!tex.texture) { + tex.texture = texture; + tex.version = texture->m_version; + tex.glTextureId = texId; + tex.width = surface->m_surface->w; + tex.height = surface->m_surface->h; + AddTextureDestroyCallback(i, texture); + return i; + } + } + + m_textures.push_back( + {texture, texture->m_version, texId, (uint16_t) surface->m_surface->w, (uint16_t) surface->m_surface->h} + ); + AddTextureDestroyCallback((Uint32) (m_textures.size() - 1), texture); + return (Uint32) (m_textures.size() - 1); +} + +struct GLES3MeshDestroyContext { + OpenGLES3Renderer* renderer; + Uint32 id; +}; + +void OpenGLES3Renderer::AddMeshDestroyCallback(Uint32 id, IDirect3DRMMesh* mesh) +{ + auto* ctx = new GLES3MeshDestroyContext{this, id}; + mesh->AddDestroyCallback( + [](IDirect3DRMObject*, void* arg) { + auto* ctx = static_cast(arg); + auto& cache = ctx->renderer->m_meshs[ctx->id]; + cache.meshGroup = nullptr; + glDeleteBuffers(1, &cache.vboPositions); + glDeleteBuffers(1, &cache.vboNormals); + glDeleteBuffers(1, &cache.vboTexcoords); + glDeleteBuffers(1, &cache.ibo); + glDeleteVertexArrays(1, &cache.vao); + delete ctx; + }, + ctx + ); +} + +Uint32 OpenGLES3Renderer::GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* meshGroup) +{ + for (Uint32 i = 0; i < m_meshs.size(); ++i) { + auto& cache = m_meshs[i]; + if (cache.meshGroup == meshGroup) { + if (cache.version != meshGroup->version) { + cache = std::move(GLES3UploadMesh(*meshGroup)); + } + return i; + } + } + + auto newCache = GLES3UploadMesh(*meshGroup); + + for (Uint32 i = 0; i < m_meshs.size(); ++i) { + auto& cache = m_meshs[i]; + if (!cache.meshGroup) { + cache = std::move(newCache); + AddMeshDestroyCallback(i, mesh); + return i; + } + } + + m_meshs.push_back(std::move(newCache)); + AddMeshDestroyCallback((Uint32) (m_meshs.size() - 1), mesh); + return (Uint32) (m_meshs.size() - 1); +} + +HRESULT OpenGLES3Renderer::BeginFrame() +{ + SDL_GL_MakeCurrent(DDWindow, m_context); + m_dirty = true; + + glBindFramebuffer(GL_FRAMEBUFFER, m_fbo); + + glEnable(GL_CULL_FACE); + glDisable(GL_BLEND); + glEnable(GL_DEPTH_TEST); + glDepthMask(GL_TRUE); + + SceneLightGLES3 lightData[3]; + int lightCount = std::min(static_cast(m_lights.size()), 3); + + for (int i = 0; i < lightCount; ++i) { + const auto& src = m_lights[i]; + lightData[i].color[0] = src.color.r; + lightData[i].color[1] = src.color.g; + lightData[i].color[2] = src.color.b; + lightData[i].color[3] = src.color.a; + + lightData[i].position[0] = src.position.x; + lightData[i].position[1] = src.position.y; + lightData[i].position[2] = src.position.z; + lightData[i].position[3] = src.positional; + + lightData[i].direction[0] = src.direction.x; + lightData[i].direction[1] = src.direction.y; + lightData[i].direction[2] = src.direction.z; + lightData[i].direction[3] = src.directional; + } + + for (int i = 0; i < lightCount; ++i) { + glUniform4fv(u_lightLocs[i][0], 1, lightData[i].color); + glUniform4fv(u_lightLocs[i][1], 1, lightData[i].position); + glUniform4fv(u_lightLocs[i][2], 1, lightData[i].direction); + } + glUniform1i(m_lightCountLoc, lightCount); + return DD_OK; +} + +void OpenGLES3Renderer::EnableTransparency() +{ + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glDepthMask(GL_FALSE); +} + +void OpenGLES3Renderer::SubmitDraw( + DWORD meshId, + const D3DRMMATRIX4D& modelViewMatrix, + const D3DRMMATRIX4D& worldMatrix, + const D3DRMMATRIX4D& viewMatrix, + const Matrix3x3& normalMatrix, + const Appearance& appearance +) +{ + auto& mesh = m_meshs[meshId]; + + glUniformMatrix4fv(m_modelViewMatrixLoc, 1, GL_FALSE, &modelViewMatrix[0][0]); + glUniformMatrix3fv(m_normalMatrixLoc, 1, GL_FALSE, &normalMatrix[0][0]); + glUniformMatrix4fv(m_projectionMatrixLoc, 1, GL_FALSE, &m_projection[0][0]); + + glUniform4f( + m_colorLoc, + appearance.color.r / 255.0f, + appearance.color.g / 255.0f, + appearance.color.b / 255.0f, + appearance.color.a / 255.0f + ); + + glUniform1f(m_shinLoc, appearance.shininess); + + if (appearance.textureId != NO_TEXTURE_ID) { + glUniform1i(m_useTextureLoc, 1); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, m_textures[appearance.textureId].glTextureId); + glUniform1i(m_textureLoc, 0); + } + else { + glUniform1i(m_useTextureLoc, 0); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, m_dummyTexture); + glUniform1i(m_textureLoc, 0); + } + + glBindVertexArray(mesh.vao); + glDrawElements(GL_TRIANGLES, static_cast(mesh.indices.size()), GL_UNSIGNED_SHORT, nullptr); + glBindVertexArray(0); +} + +HRESULT OpenGLES3Renderer::FinalizeFrame() +{ + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + + return DD_OK; +} + +void OpenGLES3Renderer::Resize(int width, int height, const ViewportTransform& viewportTransform) +{ + SDL_GL_MakeCurrent(DDWindow, m_context); + m_width = width; + m_height = height; + m_viewportTransform = viewportTransform; + if (m_renderedImage) { + SDL_DestroySurface(m_renderedImage); + } + m_renderedImage = SDL_CreateSurface(m_width, m_height, SDL_PIXELFORMAT_RGBA32); + + if (m_colorTarget) { + glDeleteRenderbuffers(1, &m_colorTarget); + m_colorTarget = 0; + } + if (m_resolveColor) { + glDeleteRenderbuffers(1, &m_resolveColor); + m_resolveColor = 0; + } + if (m_depthTarget) { + glDeleteRenderbuffers(1, &m_depthTarget); + m_depthTarget = 0; + } + + glBindFramebuffer(GL_FRAMEBUFFER, m_fbo); + + // Create color texture + glGenRenderbuffers(1, &m_colorTarget); + glBindRenderbuffer(GL_RENDERBUFFER, m_colorTarget); + if (m_msaa > 1) { + glRenderbufferStorageMultisample(GL_RENDERBUFFER, m_msaa, GL_RGBA8, width, height); + } + else { + glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, width, height); + } + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_colorTarget); + + // Create depth renderbuffer + glGenRenderbuffers(1, &m_depthTarget); + glBindRenderbuffer(GL_RENDERBUFFER, m_depthTarget); + if (m_msaa > 1) { + glRenderbufferStorageMultisample(GL_RENDERBUFFER, m_msaa, GL_DEPTH_COMPONENT24, width, height); + } + else { + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, width, height); + } + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_depthTarget); + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + if (status != GL_FRAMEBUFFER_COMPLETE) { + SDL_Log("FBO incomplete: 0x%X", status); + } + + if (m_msaa > 1) { + glBindFramebuffer(GL_FRAMEBUFFER, m_resolveFBO); + glGenRenderbuffers(1, &m_resolveColor); + glBindRenderbuffer(GL_RENDERBUFFER, m_resolveColor); + glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, width, height); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_resolveColor); + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + if (status != GL_FRAMEBUFFER_COMPLETE) { + SDL_Log("Resolve FBO incomplete: 0x%X", status); + } + } + + glBindFramebuffer(GL_FRAMEBUFFER, m_fbo); + + glViewport(0, 0, m_width, m_height); +} + +void OpenGLES3Renderer::Clear(float r, float g, float b) +{ + SDL_GL_MakeCurrent(DDWindow, m_context); + m_dirty = true; + + glBindFramebuffer(GL_FRAMEBUFFER, m_fbo); + + glEnable(GL_DEPTH_TEST); + glDepthMask(GL_TRUE); + glClearColor(r, g, b, 1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); +} + +void OpenGLES3Renderer::Flip() +{ + SDL_GL_MakeCurrent(DDWindow, m_context); + if (!m_dirty) { + return; + } + + glBindFramebuffer(GL_READ_FRAMEBUFFER, m_fbo); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); + + // This is a workaround for what is (presumably) a driver bug in some WebGL environments (Android Chrome) + // During transitions, the screen would sometimes (randomly) briefly be cleared / flicker black when using + // glBlitFramebuffer. Any write to the back buffer before that fixes this issue. The following should have minimal + // performance impact. + glEnable(GL_SCISSOR_TEST); + glScissor(0, 0, 1, 1); + glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + glClear(GL_COLOR_BUFFER_BIT); + glDisable(GL_SCISSOR_TEST); + + glBlitFramebuffer(0, 0, m_width, m_height, 0, 0, m_width, m_height, GL_COLOR_BUFFER_BIT, GL_NEAREST); + + SDL_GL_SwapWindow(DDWindow); + m_dirty = false; +} + +void OpenGLES3Renderer::Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, const SDL_Rect& dstRect, FColor color) +{ + SDL_GL_MakeCurrent(DDWindow, m_context); + m_dirty = true; + + glBindFramebuffer(GL_FRAMEBUFFER, m_fbo); + + glDisable(GL_DEPTH_TEST); + glDepthMask(GL_FALSE); + + float ambient[] = {1.0f, 1.0f, 1.0f, 1.0f}; + float blank[] = {0.0f, 0.0f, 0.0f, 0.0f}; + glUniform4fv(u_lightLocs[0][0], 1, ambient); + glUniform4fv(u_lightLocs[0][1], 1, blank); + glUniform4fv(u_lightLocs[0][2], 1, blank); + glUniform1i(m_lightCountLoc, 1); + + glUniform4f(m_colorLoc, color.r, color.g, color.b, color.a); + glUniform1f(m_shinLoc, 0.0f); + + SDL_Rect expandedDstRect; + if (textureId != NO_TEXTURE_ID) { + const GLES3TextureCacheEntry& texture = m_textures[textureId]; + float scaleX = static_cast(dstRect.w) / srcRect.w; + float scaleY = static_cast(dstRect.h) / srcRect.h; + expandedDstRect = { + static_cast(std::round(dstRect.x - srcRect.x * scaleX)), + static_cast(std::round(dstRect.y - srcRect.y * scaleY)), + static_cast(std::round(texture.width * scaleX)), + static_cast(std::round(texture.height * scaleY)) + }; + + glUniform1i(m_useTextureLoc, 1); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, texture.glTextureId); + glUniform1i(m_textureLoc, 0); + } + else { + expandedDstRect = dstRect; + glUniform1i(m_useTextureLoc, 0); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, m_dummyTexture); + glUniform1i(m_textureLoc, 0); + } + + D3DRMMATRIX4D modelView, projection; + Create2DTransformMatrix( + expandedDstRect, + m_viewportTransform.scale, + m_viewportTransform.offsetX, + m_viewportTransform.offsetY, + modelView + ); + + glUniformMatrix4fv(m_modelViewMatrixLoc, 1, GL_FALSE, &modelView[0][0]); + Matrix3x3 identity = {{1.f, 0.f, 0.f}, {0.f, 1.f, 0.f}, {0.f, 0.f, 1.f}}; + glUniformMatrix3fv(m_normalMatrixLoc, 1, GL_FALSE, &identity[0][0]); + CreateOrthographicProjection((float) m_width, (float) m_height, projection); + glUniformMatrix4fv(m_projectionMatrixLoc, 1, GL_FALSE, &projection[0][0]); + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + glEnable(GL_SCISSOR_TEST); + glScissor( + static_cast(std::round(dstRect.x * m_viewportTransform.scale + m_viewportTransform.offsetX)), + m_height - static_cast( + std::round((dstRect.y + dstRect.h) * m_viewportTransform.scale + m_viewportTransform.offsetY) + ), + static_cast(std::round(dstRect.w * m_viewportTransform.scale)), + static_cast(std::round(dstRect.h * m_viewportTransform.scale)) + ); + + glBindVertexArray(m_uiMeshCache.vao); + glDrawElements(GL_TRIANGLES, static_cast(m_uiMeshCache.indices.size()), GL_UNSIGNED_SHORT, nullptr); + glBindVertexArray(0); + + glDisable(GL_SCISSOR_TEST); +} + +void OpenGLES3Renderer::Download(SDL_Surface* target) +{ + glFinish(); + + if (m_msaa > 1) { + glBindFramebuffer(GL_READ_FRAMEBUFFER, m_fbo); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_resolveFBO); + glBlitFramebuffer(0, 0, m_width, m_height, 0, 0, m_width, m_height, GL_COLOR_BUFFER_BIT, GL_NEAREST); + glBindFramebuffer(GL_FRAMEBUFFER, m_resolveFBO); + } + else { + glBindFramebuffer(GL_FRAMEBUFFER, m_fbo); + } + + glReadPixels(0, 0, m_width, m_height, GL_RGBA, GL_UNSIGNED_BYTE, m_renderedImage->pixels); + + SDL_Rect srcRect = { + static_cast(m_viewportTransform.offsetX), + static_cast(m_viewportTransform.offsetY), + static_cast(target->w * m_viewportTransform.scale), + static_cast(target->h * m_viewportTransform.scale), + }; + + SDL_Surface* bufferClone = SDL_CreateSurface(target->w, target->h, SDL_PIXELFORMAT_RGBA32); + if (!bufferClone) { + SDL_Log("SDL_CreateSurface: %s", SDL_GetError()); + return; + } + + SDL_BlitSurfaceScaled(m_renderedImage, &srcRect, bufferClone, nullptr, SDL_SCALEMODE_NEAREST); + + // Flip image vertically into target + SDL_Rect rowSrc = {0, 0, bufferClone->w, 1}; + SDL_Rect rowDst = {0, 0, bufferClone->w, 1}; + for (int y = 0; y < bufferClone->h; ++y) { + rowSrc.y = y; + rowDst.y = bufferClone->h - 1 - y; + SDL_BlitSurface(bufferClone, &rowSrc, target, &rowDst); + } + + SDL_DestroySurface(bufferClone); +} + +void OpenGLES3Renderer::SetDither(bool dither) +{ + if (dither) { + glEnable(GL_DITHER); + } + else { + glDisable(GL_DITHER); + } +} diff --git a/miniwin/src/d3drm/backends/sdl3gpu/renderer.cpp b/miniwin/src/d3drm/backends/sdl3gpu/renderer.cpp index 4ee5a35c..8039c147 100644 --- a/miniwin/src/d3drm/backends/sdl3gpu/renderer.cpp +++ b/miniwin/src/d3drm/backends/sdl3gpu/renderer.cpp @@ -190,7 +190,7 @@ static SDL_GPUGraphicsPipeline* InitializeGraphicsPipeline( Direct3DRMRenderer* Direct3DRMSDL3GPURenderer::Create(DWORD width, DWORD height) { ScopedDevice device{SDL_CreateGPUDevice( - SDL_GPU_SHADERFORMAT_SPIRV | SDL_GPU_SHADERFORMAT_DXIL | SDL_GPU_SHADERFORMAT_MSL, + SDL_GPU_SHADERFORMAT_SPIRV | SDL_GPU_SHADERFORMAT_DXBC | SDL_GPU_SHADERFORMAT_DXIL | SDL_GPU_SHADERFORMAT_MSL, #ifdef DEBUG true, #else @@ -203,49 +203,31 @@ Direct3DRMRenderer* Direct3DRMSDL3GPURenderer::Create(DWORD width, DWORD height) return nullptr; } - SDL_Window* window = DDWindow; - bool testWindow = false; - if (!window) { - window = SDL_CreateWindow("SDL_GPU test", width, height, SDL_WINDOW_HIDDEN); - if (!window) { - SDL_Log("SDL_CreateWindow: %s", SDL_GetError()); - return nullptr; - } - testWindow = true; - } - - if (!SDL_ClaimWindowForGPUDevice(device.ptr, window)) { - SDL_LogError(LOG_CATEGORY_MINIWIN, "SDL_ClaimWindowForGPUDevice: %s", SDL_GetError()); - if (testWindow) { - SDL_DestroyWindow(window); - } + if (!DDWindow) { + SDL_Log("No window handler"); return nullptr; } - ScopedPipeline opaquePipeline{device.ptr, InitializeGraphicsPipeline(device.ptr, window, true, true)}; + if (!SDL_ClaimWindowForGPUDevice(device.ptr, DDWindow)) { + SDL_LogError(LOG_CATEGORY_MINIWIN, "SDL_ClaimWindowForGPUDevice: %s", SDL_GetError()); + return nullptr; + } + + ScopedPipeline opaquePipeline{device.ptr, InitializeGraphicsPipeline(device.ptr, DDWindow, true, true)}; if (!opaquePipeline.ptr) { SDL_LogError(LOG_CATEGORY_MINIWIN, "InitializeGraphicsPipeline for opaquePipeline"); - if (testWindow) { - SDL_DestroyWindow(window); - } return nullptr; } - ScopedPipeline transparentPipeline{device.ptr, InitializeGraphicsPipeline(device.ptr, window, true, false)}; + ScopedPipeline transparentPipeline{device.ptr, InitializeGraphicsPipeline(device.ptr, DDWindow, true, false)}; if (!transparentPipeline.ptr) { SDL_LogError(LOG_CATEGORY_MINIWIN, "InitializeGraphicsPipeline for transparentPipeline"); - if (testWindow) { - SDL_DestroyWindow(window); - } return nullptr; } - ScopedPipeline uiPipeline{device.ptr, InitializeGraphicsPipeline(device.ptr, window, false, false)}; + ScopedPipeline uiPipeline{device.ptr, InitializeGraphicsPipeline(device.ptr, DDWindow, false, false)}; if (!uiPipeline.ptr) { SDL_LogError(LOG_CATEGORY_MINIWIN, "InitializeGraphicsPipeline for uiPipeline"); - if (testWindow) { - SDL_DestroyWindow(window); - } return nullptr; } @@ -257,9 +239,6 @@ Direct3DRMRenderer* Direct3DRMSDL3GPURenderer::Create(DWORD width, DWORD height) ScopedTransferBuffer uploadBuffer{device.ptr, SDL_CreateGPUTransferBuffer(device.ptr, &uploadBufferInfo)}; if (!uploadBuffer.ptr) { SDL_LogError(LOG_CATEGORY_MINIWIN, "SDL_CreateGPUTransferBuffer filed for upload buffer (%s)", SDL_GetError()); - if (testWindow) { - SDL_DestroyWindow(window); - } return nullptr; } @@ -273,9 +252,6 @@ Direct3DRMRenderer* Direct3DRMSDL3GPURenderer::Create(DWORD width, DWORD height) ScopedSampler sampler{device.ptr, SDL_CreateGPUSampler(device.ptr, &samplerInfo)}; if (!sampler.ptr) { SDL_LogError(LOG_CATEGORY_MINIWIN, "Failed to create sampler: %s", SDL_GetError()); - if (testWindow) { - SDL_DestroyWindow(window); - } return nullptr; } @@ -289,17 +265,9 @@ Direct3DRMRenderer* Direct3DRMSDL3GPURenderer::Create(DWORD width, DWORD height) ScopedSampler uiSampler{device.ptr, SDL_CreateGPUSampler(device.ptr, &uiSamplerInfo)}; if (!uiSampler.ptr) { SDL_LogError(LOG_CATEGORY_MINIWIN, "Failed to create sampler: %s", SDL_GetError()); - if (testWindow) { - SDL_DestroyWindow(window); - } return nullptr; } - if (testWindow) { - SDL_ReleaseWindowFromGPUDevice(device.ptr, window); - SDL_DestroyWindow(window); - } - auto renderer = new Direct3DRMSDL3GPURenderer( width, height, @@ -383,9 +351,7 @@ Direct3DRMSDL3GPURenderer::~Direct3DRMSDL3GPURenderer() { SDL_ReleaseGPUBuffer(m_device, m_uiMeshCache.vertexBuffer); SDL_ReleaseGPUBuffer(m_device, m_uiMeshCache.indexBuffer); - if (DDWindow) { - SDL_ReleaseWindowFromGPUDevice(m_device, DDWindow); - } + SDL_ReleaseWindowFromGPUDevice(m_device, DDWindow); if (m_downloadBuffer) { SDL_ReleaseGPUTransferBuffer(m_device, m_downloadBuffer); } @@ -533,7 +499,7 @@ SDL_GPUTexture* Direct3DRMSDL3GPURenderer::CreateTextureFromSurface(SDL_Surface* return texptr; } -Uint32 Direct3DRMSDL3GPURenderer::GetTextureId(IDirect3DRMTexture* iTexture) +Uint32 Direct3DRMSDL3GPURenderer::GetTextureId(IDirect3DRMTexture* iTexture, bool isUI, float scaleX, float scaleY) { auto texture = static_cast(iTexture); auto surface = static_cast(texture->m_surface); @@ -585,7 +551,7 @@ SDL3MeshCache Direct3DRMSDL3GPURenderer::UploadMesh(const MeshGroup& meshGroup) meshGroup.vertices.size(), meshGroup.indices.data(), meshGroup.indices.size(), - meshGroup.texture != nullptr, + true, finalVertices, newIndices ); @@ -712,24 +678,6 @@ Uint32 Direct3DRMSDL3GPURenderer::GetMeshId(IDirect3DRMMesh* mesh, const MeshGro return (Uint32) (m_meshs.size() - 1); } -void Direct3DRMSDL3GPURenderer::GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc) -{ - halDesc->dcmColorModel = D3DCOLORMODEL::RGB; - halDesc->dwFlags = D3DDD_DEVICEZBUFFERBITDEPTH; - halDesc->dwDeviceZBufferBitDepth = DDBD_32; // Todo add support for other depths - halDesc->dwDeviceRenderBitDepth = DDBD_32; - halDesc->dpcTriCaps.dwTextureCaps = D3DPTEXTURECAPS_PERSPECTIVE; - halDesc->dpcTriCaps.dwShadeCaps = D3DPSHADECAPS_ALPHAFLATBLEND; - halDesc->dpcTriCaps.dwTextureFilterCaps = D3DPTFILTERCAPS_LINEAR; - - memset(helDesc, 0, sizeof(D3DDEVICEDESC)); -} - -const char* Direct3DRMSDL3GPURenderer::GetName() -{ - return "SDL3 GPU HAL"; -} - void PackNormalMatrix(const Matrix3x3& normalMatrix3x3, D3DRMMATRIX4D& packedNormalMatrix4x4) { for (int row = 0; row < 3; ++row) { @@ -857,10 +805,6 @@ void Direct3DRMSDL3GPURenderer::Resize(int width, int height, const ViewportTran m_height = height; m_viewportTransform = viewportTransform; - if (!DDWindow) { - return; - } - if (m_transferTexture) { SDL_ReleaseGPUTexture(m_device, m_transferTexture); } @@ -940,55 +884,37 @@ void Direct3DRMSDL3GPURenderer::Flip() m_cmdbuf = nullptr; } -// TODO use SDL_SetGPUScissor(SDL_GPURenderPass *render_pass, const SDL_Rect *scissor) when srcRect isn't 100% of -// texture - -void Create2DTransformMatrix( +void Direct3DRMSDL3GPURenderer::Draw2DImage( + Uint32 textureId, + const SDL_Rect& srcRect, const SDL_Rect& dstRect, - float scale, - float offsetX, - float offsetY, - D3DRMMATRIX4D& outMatrix + FColor color ) -{ - float x = static_cast(dstRect.x) * scale + offsetX; - float y = static_cast(dstRect.y) * scale + offsetY; - float w = static_cast(dstRect.w) * scale; - float h = static_cast(dstRect.h) * scale; - - D3DVALUE tmp[4][4] = {{w, 0, 0, 0}, {0, h, 0, 0}, {0, 0, 1, 0}, {x, y, 0, 1}}; - memcpy(outMatrix, tmp, sizeof(tmp)); -} - -void CreateOrthographicProjection(float width, float height, D3DRMMATRIX4D& outProj) -{ - D3DVALUE tmp[4][4] = { - {2.0f / width, 0.0f, 0.0f, 0.0f}, - {0.0f, -2.0f / height, 0.0f, 0.0f}, - {0.0f, 0.0f, 1.0f, 0.0f}, - {-1.0f, 1.0f, 0.0f, 1.0f} - }; - memcpy(outProj, tmp, sizeof(tmp)); -} - -void Direct3DRMSDL3GPURenderer::Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, const SDL_Rect& dstRect) { if (!m_renderPass) { StartRenderPass(0, 0, 0, false); } SDL_BindGPUGraphicsPipeline(m_renderPass, m_uiPipeline); - const SDL3TextureCache& tex = m_textures[textureId]; - - auto surface = static_cast(tex.texture->m_surface); - float scaleX = static_cast(dstRect.w) / srcRect.w; - float scaleY = static_cast(dstRect.h) / srcRect.h; - SDL_Rect expandedDstRect = { - static_cast(std::round(dstRect.x - srcRect.x * scaleX)), - static_cast(std::round(dstRect.y - srcRect.y * scaleY)), - static_cast(std::round(static_cast(surface->m_surface->w) * scaleX)), - static_cast(std::round(static_cast(surface->m_surface->h) * scaleY)), - }; + SDL_GPUTexture* tex; + SDL_Rect expandedDstRect; + if (textureId == NO_TEXTURE_ID) { + expandedDstRect = dstRect; + tex = m_dummyTexture; + } + else { + SDL3TextureCache& cache = m_textures[textureId]; + tex = cache.gpuTexture; + auto surface = static_cast(cache.texture->m_surface); + float scaleX = static_cast(dstRect.w) / srcRect.w; + float scaleY = static_cast(dstRect.h) / srcRect.h; + expandedDstRect = { + static_cast(std::round(dstRect.x - srcRect.x * scaleX)), + static_cast(std::round(dstRect.y - srcRect.y * scaleY)), + static_cast(std::round(static_cast(surface->m_surface->w) * scaleX)), + static_cast(std::round(static_cast(surface->m_surface->h) * scaleY)), + }; + } Create2DTransformMatrix( expandedDstRect, @@ -1003,11 +929,14 @@ void Direct3DRMSDL3GPURenderer::Draw2DImage(Uint32 textureId, const SDL_Rect& sr SceneLight fullBright = {{1, 1, 1, 1}, {0, 0, 0}, 0, {0, 0, 0}, 0}; memcpy(&m_fragmentShadingData.lights, &fullBright, sizeof(SceneLight)); m_fragmentShadingData.lightCount = 1; - m_fragmentShadingData.color = {0xff, 0xff, 0xff, 0xff}; + m_fragmentShadingData.color.r = static_cast(color.r * 255); + m_fragmentShadingData.color.g = static_cast(color.g * 255); + m_fragmentShadingData.color.b = static_cast(color.b * 255); + m_fragmentShadingData.color.a = static_cast(color.a * 255); m_fragmentShadingData.shininess = 0.0f; m_fragmentShadingData.useTexture = 1; - SDL_GPUTextureSamplerBinding samplerBinding = {tex.gpuTexture, m_uiSampler}; + SDL_GPUTextureSamplerBinding samplerBinding = {tex, m_uiSampler}; SDL_BindGPUFragmentSamplers(m_renderPass, 0, &samplerBinding, 1); SDL_PushGPUVertexUniformData(m_cmdbuf, 0, &m_uniforms, sizeof(m_uniforms)); SDL_PushGPUFragmentUniformData(m_cmdbuf, 0, &m_fragmentShadingData, sizeof(m_fragmentShadingData)); @@ -1029,6 +958,10 @@ void Direct3DRMSDL3GPURenderer::Draw2DImage(Uint32 textureId, const SDL_Rect& sr SDL_SetGPUScissor(m_renderPass, &fullViewport); } +void Direct3DRMSDL3GPURenderer::SetDither(bool dither) +{ +} + void Direct3DRMSDL3GPURenderer::Download(SDL_Surface* target) { if (!m_cmdbuf) { @@ -1076,7 +1009,7 @@ void Direct3DRMSDL3GPURenderer::Download(SDL_Surface* target) } SDL_Surface* renderedImage = - SDL_CreateSurfaceFrom(width, height, SDL_PIXELFORMAT_ARGB8888, downloadedData, width * 4); + SDL_CreateSurfaceFrom(width, height, SDL_PIXELFORMAT_XRGB8888, downloadedData, width * 4); SDL_BlitSurfaceScaled(renderedImage, nullptr, target, nullptr, SDL_SCALEMODE_NEAREST); SDL_DestroySurface(renderedImage); diff --git a/miniwin/src/d3drm/backends/sdl3gpu/shaders/generated/PositionColor.vert.h b/miniwin/src/d3drm/backends/sdl3gpu/shaders/generated/PositionColor.vert.h index 46e7964d..08204e9e 100644 --- a/miniwin/src/d3drm/backends/sdl3gpu/shaders/generated/PositionColor.vert.h +++ b/miniwin/src/d3drm/backends/sdl3gpu/shaders/generated/PositionColor.vert.h @@ -8,7 +8,7 @@ #include -// DXIL only makes sense on Windows platforms +// DX only makes sense on Windows platforms #if defined(SDL_PLATFORM_WINDOWS) static const Uint8 PositionColor_vert_dxil[5132] = { 0x44, 0x58, 0x42, 0x43, 0x4a, 0x28, 0x54, 0x85, 0x4b, 0xb0, 0x04, 0x11, 0x56, 0x33, 0x94, 0x85, @@ -333,6 +333,104 @@ static const Uint8 PositionColor_vert_dxil[5132] = { 0x83, 0x3f, 0xcc, 0xc3, 0x37, 0x62, 0x90, 0x00, 0x20, 0x08, 0x06, 0x48, 0x49, 0xb8, 0x83, 0x3e, 0xf8, 0x03, 0x3d, 0x6c, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; +static const Uint8 PositionColor_vert_dxbc[1528] = { + 0x44, 0x58, 0x42, 0x43, 0x26, 0x81, 0xf8, 0x51, 0x4d, 0x47, 0xfd, 0xfd, 0xa8, 0xbd, 0xce, 0x70, + 0x72, 0xe8, 0x3f, 0x4e, 0x01, 0x00, 0x00, 0x00, 0xf8, 0x05, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x34, 0x00, 0x00, 0x00, 0xf4, 0x01, 0x00, 0x00, 0x58, 0x02, 0x00, 0x00, 0xe0, 0x02, 0x00, 0x00, + 0x5c, 0x05, 0x00, 0x00, 0x52, 0x44, 0x45, 0x46, 0xb8, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x74, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x05, 0xfe, 0xff, + 0x00, 0x01, 0x00, 0x00, 0x8f, 0x01, 0x00, 0x00, 0x52, 0x44, 0x31, 0x31, 0x3c, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x56, 0x69, 0x65, + 0x77, 0x70, 0x6f, 0x72, 0x74, 0x55, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x73, 0x00, 0xab, 0xab, + 0x5c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x8c, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x2c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x50, 0x01, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x2c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x71, 0x01, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0x40, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x2c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x56, 0x69, 0x65, 0x77, 0x70, 0x6f, 0x72, 0x74, 0x55, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x73, + 0x5f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x66, 0x6c, 0x6f, 0x61, + 0x74, 0x34, 0x78, 0x34, 0x00, 0xab, 0xab, 0xab, 0x03, 0x00, 0x03, 0x00, 0x04, 0x00, 0x04, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x56, 0x69, 0x65, 0x77, + 0x70, 0x6f, 0x72, 0x74, 0x55, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x73, 0x5f, 0x77, 0x6f, 0x72, + 0x6c, 0x64, 0x56, 0x69, 0x65, 0x77, 0x4d, 0x61, 0x74, 0x72, 0x69, 0x78, 0x00, 0x56, 0x69, 0x65, + 0x77, 0x70, 0x6f, 0x72, 0x74, 0x55, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x73, 0x5f, 0x6e, 0x6f, + 0x72, 0x6d, 0x61, 0x6c, 0x4d, 0x61, 0x74, 0x72, 0x69, 0x78, 0x00, 0x4d, 0x69, 0x63, 0x72, 0x6f, + 0x73, 0x6f, 0x66, 0x74, 0x20, 0x28, 0x52, 0x29, 0x20, 0x48, 0x4c, 0x53, 0x4c, 0x20, 0x53, 0x68, + 0x61, 0x64, 0x65, 0x72, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x72, 0x20, 0x31, 0x30, + 0x2e, 0x31, 0x00, 0xab, 0x49, 0x53, 0x47, 0x4e, 0x5c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x07, 0x07, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x54, 0x45, 0x58, 0x43, + 0x4f, 0x4f, 0x52, 0x44, 0x00, 0xab, 0xab, 0xab, 0x4f, 0x53, 0x47, 0x4e, 0x80, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x08, 0x00, 0x00, + 0x68, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x03, 0x0c, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x07, 0x08, 0x00, 0x00, + 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x54, 0x45, 0x58, 0x43, 0x4f, 0x4f, 0x52, 0x44, + 0x00, 0x53, 0x56, 0x5f, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0xab, 0xab, 0xab, + 0x53, 0x48, 0x45, 0x58, 0x74, 0x02, 0x00, 0x00, 0x50, 0x00, 0x01, 0x00, 0x9d, 0x00, 0x00, 0x00, + 0x6a, 0x08, 0x00, 0x01, 0x59, 0x00, 0x00, 0x04, 0x46, 0x8e, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0b, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x00, 0x03, 0x72, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x5f, 0x00, 0x00, 0x03, 0x72, 0x10, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x00, 0x03, + 0x32, 0x10, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x03, 0x72, 0x20, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x03, 0x32, 0x20, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x65, 0x00, 0x00, 0x03, 0x72, 0x20, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x04, + 0xf2, 0x20, 0x10, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x02, + 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x08, 0x12, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x46, 0x12, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x46, 0x82, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x08, 0x22, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x46, 0x12, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x46, 0x82, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x08, 0x42, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x46, 0x12, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x46, 0x82, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x07, 0x82, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x46, 0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x44, 0x00, 0x00, 0x05, 0x82, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x07, 0x72, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xf6, 0x0f, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x36, 0x00, 0x00, 0x05, 0x32, 0x20, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x46, 0x10, 0x10, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x08, 0x72, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x56, 0x15, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x82, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x0a, 0x72, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x46, 0x82, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x06, 0x10, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x46, 0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x0a, + 0x72, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x82, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0xa6, 0x1a, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x02, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x72, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x46, 0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x82, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x05, 0x72, 0x20, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x46, 0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x08, 0xf2, 0x00, 0x10, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x56, 0x05, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x8e, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x0a, 0xf2, 0x00, 0x10, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x46, 0x8e, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x0e, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x32, 0x00, 0x00, 0x0a, 0xf2, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x8e, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xa6, 0x0a, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x46, 0x0e, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0xf2, 0x20, 0x10, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x46, 0x0e, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x8e, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x01, 0x53, 0x54, 0x41, 0x54, + 0x94, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; #endif // MSL only makes sense on Apple platforms @@ -557,4 +655,4 @@ static const Uint8 PositionColor_vert_spirv[1924] = { 0x3d, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x08, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00, -}; +}; \ No newline at end of file diff --git a/miniwin/src/d3drm/backends/sdl3gpu/shaders/generated/ShaderIndex.cpp b/miniwin/src/d3drm/backends/sdl3gpu/shaders/generated/ShaderIndex.cpp index a092dd6d..fefcfa80 100644 --- a/miniwin/src/d3drm/backends/sdl3gpu/shaders/generated/ShaderIndex.cpp +++ b/miniwin/src/d3drm/backends/sdl3gpu/shaders/generated/ShaderIndex.cpp @@ -24,6 +24,20 @@ static const SDL_GPUShaderCreateInfo VertexShaderDXILCodes[] = { /* num_uniform_buffers */ 1, }, }; +static const SDL_GPUShaderCreateInfo VertexShaderDXBCCodes[] = { + // VertexShaderId::PositionColor + { + /* code_size */ sizeof(PositionColor_vert_dxbc), + /* code */ PositionColor_vert_dxbc, + /* entrypoint */ "main", + /* format */ SDL_GPU_SHADERFORMAT_DXBC, + /* stage */ SDL_GPU_SHADERSTAGE_VERTEX, + /* num_samplers */ 0, + /* num_storage_textures */ 0, + /* num_storage_buffers */ 0, + /* num_uniform_buffers */ 1, + }, +}; #endif #if defined(SDL_PLATFORM_APPLE) @@ -71,6 +85,20 @@ static const SDL_GPUShaderCreateInfo FragmentShaderDXILCodes[] = { /* num_uniform_buffers */ 1, }, }; +static const SDL_GPUShaderCreateInfo FragmentShaderDXBCCodes[] = { + // FragmentShaderId::SolidColor + { + /* code_size */ sizeof(SolidColor_frag_dxbc), + /* code */ SolidColor_frag_dxbc, + /* entrypoint */ "main", + /* format */ SDL_GPU_SHADERFORMAT_DXBC, + /* stage */ SDL_GPU_SHADERSTAGE_FRAGMENT, + /* num_samplers */ 1, + /* num_storage_textures */ 0, + /* num_storage_buffers */ 0, + /* num_uniform_buffers */ 1, + }, +}; #endif #if defined(SDL_PLATFORM_APPLE) @@ -109,6 +137,10 @@ const SDL_GPUShaderCreateInfo* GetVertexShaderCode(VertexShaderId id, SDL_GPUSha SDL_assert(id < SDL_arraysize(VertexShaderDXILCodes)); return &VertexShaderDXILCodes[id]; } + if (formats & SDL_GPU_SHADERFORMAT_DXBC) { + SDL_assert(id < SDL_arraysize(VertexShaderDXBCCodes)); + return &VertexShaderDXBCCodes[id]; + } #endif #if defined(SDL_PLATFORM_APPLE) if (formats & SDL_GPU_SHADERFORMAT_MSL) { @@ -130,6 +162,10 @@ const SDL_GPUShaderCreateInfo* GetFragmentShaderCode(FragmentShaderId id, SDL_GP SDL_assert(id < SDL_arraysize(FragmentShaderDXILCodes)); return &FragmentShaderDXILCodes[id]; } + if (formats & SDL_GPU_SHADERFORMAT_DXBC) { + SDL_assert(id < SDL_arraysize(FragmentShaderDXBCCodes)); + return &FragmentShaderDXBCCodes[id]; + } #endif #if defined(SDL_PLATFORM_APPLE) if (formats & SDL_GPU_SHADERFORMAT_MSL) { diff --git a/miniwin/src/d3drm/backends/sdl3gpu/shaders/generated/SolidColor.frag.h b/miniwin/src/d3drm/backends/sdl3gpu/shaders/generated/SolidColor.frag.h index ebdbe79d..beb316f4 100644 --- a/miniwin/src/d3drm/backends/sdl3gpu/shaders/generated/SolidColor.frag.h +++ b/miniwin/src/d3drm/backends/sdl3gpu/shaders/generated/SolidColor.frag.h @@ -8,7 +8,7 @@ #include -// DXIL only makes sense on Windows platforms +// DX only makes sense on Windows platforms #if defined(SDL_PLATFORM_WINDOWS) static const Uint8 SolidColor_frag_dxil[6648] = { 0x44, 0x58, 0x42, 0x43, 0xd8, 0xfe, 0x4c, 0xec, 0x17, 0x1b, 0x52, 0xee, 0xf7, 0xc8, 0x8d, 0xcf, @@ -428,6 +428,206 @@ static const Uint8 SolidColor_frag_dxil[6648] = { 0xc1, 0x88, 0x41, 0x02, 0x80, 0x20, 0x18, 0x20, 0xe9, 0xe1, 0x17, 0xe1, 0x01, 0x1e, 0xb5, 0x81, 0x16, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; +static const Uint8 SolidColor_frag_dxbc[3160] = { + 0x44, 0x58, 0x42, 0x43, 0xe8, 0x49, 0xcf, 0x45, 0xf9, 0x5a, 0x8f, 0xd1, 0xe0, 0x69, 0x77, 0x8f, + 0x38, 0xc7, 0x7b, 0xc1, 0x01, 0x00, 0x00, 0x00, 0x58, 0x0c, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x34, 0x00, 0x00, 0x00, 0xb8, 0x03, 0x00, 0x00, 0x40, 0x04, 0x00, 0x00, 0x94, 0x04, 0x00, 0x00, + 0xbc, 0x0b, 0x00, 0x00, 0x52, 0x44, 0x45, 0x46, 0x7c, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0xc8, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x05, 0xff, 0xff, + 0x00, 0x01, 0x00, 0x00, 0x53, 0x03, 0x00, 0x00, 0x52, 0x44, 0x31, 0x31, 0x3c, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0xac, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x53, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x72, 0x00, + 0x54, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x00, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x46, 0x72, 0x61, + 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x68, 0x61, 0x64, 0x69, 0x6e, 0x67, 0x44, 0x61, 0x74, 0x61, + 0x00, 0xab, 0xab, 0xab, 0xac, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, + 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x38, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x5c, 0x02, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x02, 0x00, 0x00, + 0x94, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xc8, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0xec, 0x02, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x10, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x34, 0x03, 0x00, 0x00, + 0x9c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x46, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x68, 0x61, 0x64, + 0x69, 0x6e, 0x67, 0x44, 0x61, 0x74, 0x61, 0x5f, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x73, 0x00, 0x53, + 0x63, 0x65, 0x6e, 0x65, 0x4c, 0x69, 0x67, 0x68, 0x74, 0x00, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x00, + 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x34, 0x00, 0xab, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x04, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd4, 0x01, 0x00, 0x00, 0x70, 0x6f, 0x73, 0x69, + 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0xab, + 0xce, 0x01, 0x00, 0x00, 0xdc, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, + 0xdc, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x09, 0x02, 0x00, 0x00, 0xdc, 0x01, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x03, 0x00, 0x03, 0x00, + 0x14, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xc3, 0x01, 0x00, 0x00, 0x46, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, + 0x53, 0x68, 0x61, 0x64, 0x69, 0x6e, 0x67, 0x44, 0x61, 0x74, 0x61, 0x5f, 0x6c, 0x69, 0x67, 0x68, + 0x74, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x00, 0x69, 0x6e, 0x74, 0x00, 0xab, 0x00, 0x00, 0x02, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7b, 0x02, 0x00, 0x00, + 0x46, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x68, 0x61, 0x64, 0x69, 0x6e, 0x67, 0x44, + 0x61, 0x74, 0x61, 0x5f, 0x53, 0x68, 0x69, 0x6e, 0x69, 0x6e, 0x65, 0x73, 0x73, 0x00, 0x66, 0x6c, + 0x6f, 0x61, 0x74, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xc2, 0x02, 0x00, 0x00, 0x46, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, + 0x53, 0x68, 0x61, 0x64, 0x69, 0x6e, 0x67, 0x44, 0x61, 0x74, 0x61, 0x5f, 0x43, 0x6f, 0x6c, 0x6f, + 0x72, 0x52, 0x61, 0x77, 0x00, 0x64, 0x77, 0x6f, 0x72, 0x64, 0x00, 0xab, 0x00, 0x00, 0x13, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x03, 0x00, 0x00, + 0x46, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x68, 0x61, 0x64, 0x69, 0x6e, 0x67, 0x44, + 0x61, 0x74, 0x61, 0x5f, 0x55, 0x73, 0x65, 0x54, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x00, 0x4d, + 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x20, 0x28, 0x52, 0x29, 0x20, 0x48, 0x4c, 0x53, + 0x4c, 0x20, 0x53, 0x68, 0x61, 0x64, 0x65, 0x72, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, + 0x72, 0x20, 0x31, 0x30, 0x2e, 0x31, 0x00, 0xab, 0x49, 0x53, 0x47, 0x4e, 0x80, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x00, 0x00, + 0x68, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x07, 0x07, 0x00, 0x00, + 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x0f, 0x08, 0x00, 0x00, 0x54, 0x45, 0x58, 0x43, 0x4f, 0x4f, 0x52, 0x44, + 0x00, 0x53, 0x56, 0x5f, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0xab, 0xab, 0xab, + 0x4f, 0x53, 0x47, 0x4e, 0x4c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x01, 0x0e, 0x00, 0x00, + 0x53, 0x56, 0x5f, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x00, 0x53, 0x56, 0x5f, 0x44, 0x65, 0x70, + 0x74, 0x68, 0x00, 0xab, 0x53, 0x48, 0x45, 0x58, 0x20, 0x07, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, + 0xc8, 0x01, 0x00, 0x00, 0x6a, 0x08, 0x00, 0x01, 0x59, 0x08, 0x00, 0x04, 0x46, 0x8e, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x5a, 0x00, 0x00, 0x03, 0x00, 0x60, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x58, 0x18, 0x00, 0x04, 0x00, 0x70, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x55, 0x55, 0x00, 0x00, 0x62, 0x10, 0x00, 0x03, 0x72, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x62, 0x10, 0x00, 0x03, 0x32, 0x10, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x62, 0x10, 0x00, 0x03, + 0x72, 0x10, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x64, 0x20, 0x00, 0x04, 0x82, 0x10, 0x10, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x03, 0xf2, 0x20, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x02, 0x01, 0xc0, 0x00, 0x00, 0x68, 0x00, 0x00, 0x02, + 0x04, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x09, 0x01, 0xc0, 0x00, 0x00, 0x02, 0x40, 0x00, 0x00, + 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x80, 0x3f, + 0x3a, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x08, 0x12, 0x00, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x80, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x09, 0x22, 0x00, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x46, 0x12, 0x10, 0x80, 0x41, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x46, 0x12, 0x10, 0x80, 0x41, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x05, + 0x22, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x36, 0x00, 0x00, 0x08, 0x72, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x40, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x36, 0x00, 0x00, 0x08, 0x72, 0x00, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x40, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x36, 0x00, 0x00, 0x05, 0x42, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x01, 0x21, 0x00, 0x00, 0x08, 0x82, 0x00, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x80, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x03, 0x00, 0x04, 0x03, 0x3a, 0x00, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x08, 0x00, 0xd0, 0x00, 0x00, 0x82, 0x00, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x0a, 0x82, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x80, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x04, 0x03, + 0x3a, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x0a, 0x82, 0x00, 0x10, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x80, 0x20, 0x06, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x12, 0x00, 0x00, 0x01, 0x36, 0x00, 0x00, 0x05, 0x82, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x01, 0x1f, 0x00, 0x04, 0x03, + 0x3a, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x72, 0x00, 0x10, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x46, 0x02, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x46, 0x82, 0x20, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x07, + 0x82, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x40, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x05, 0x72, 0x00, 0x10, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x46, 0x02, 0x10, 0x00, 0x03, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x05, + 0x42, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x01, 0x15, 0x00, 0x00, 0x01, 0x18, 0x00, 0x00, 0x0a, 0x82, 0x00, 0x10, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x3a, 0x80, 0x20, 0x06, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x1f, 0x00, 0x04, 0x03, 0x3a, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x09, + 0x72, 0x00, 0x10, 0x00, 0x03, 0x00, 0x00, 0x00, 0x46, 0x82, 0x20, 0x86, 0x41, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x12, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0b, 0x72, 0x00, 0x10, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x46, 0x12, 0x10, 0x80, 0x41, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x46, 0x82, 0x20, 0x06, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x15, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x07, 0x82, 0x00, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x46, 0x02, 0x10, 0x00, 0x03, 0x00, 0x00, 0x00, 0x46, 0x02, 0x10, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x44, 0x00, 0x00, 0x05, 0x82, 0x00, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x10, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x07, 0x72, 0x00, 0x10, 0x00, 0x03, 0x00, 0x00, 0x00, + 0xf6, 0x0f, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x46, 0x02, 0x10, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x07, 0x82, 0x00, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x46, 0x12, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x46, 0x02, 0x10, 0x00, 0x03, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x07, + 0x82, 0x00, 0x10, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3a, 0x00, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x04, 0x03, 0x3a, 0x00, 0x10, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x07, 0x82, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x0a, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x1f, 0x00, 0x04, 0x03, 0x3a, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x0a, + 0x72, 0x00, 0x10, 0x00, 0x03, 0x00, 0x00, 0x00, 0x46, 0x12, 0x10, 0x80, 0x41, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x56, 0x05, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x02, 0x10, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x07, 0x82, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x46, 0x02, 0x10, 0x00, 0x03, 0x00, 0x00, 0x00, 0x46, 0x02, 0x10, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x44, 0x00, 0x00, 0x05, 0x82, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x10, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x07, 0x72, 0x00, 0x10, 0x00, 0x03, 0x00, 0x00, 0x00, + 0xf6, 0x0f, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x46, 0x02, 0x10, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x07, 0x82, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x46, 0x12, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x46, 0x02, 0x10, 0x00, 0x03, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x07, + 0x82, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x05, 0x82, 0x00, 0x10, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x08, + 0x82, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x1a, 0x80, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x05, + 0x82, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x32, 0x00, 0x00, 0x0b, 0x72, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x46, 0x82, 0x20, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0x0f, 0x10, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x46, 0x02, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x01, + 0x32, 0x00, 0x00, 0x0b, 0x72, 0x00, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x46, 0x82, 0x20, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0x0f, 0x10, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x46, 0x02, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x01, + 0x1e, 0x00, 0x00, 0x07, 0x42, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x01, + 0x01, 0x00, 0x00, 0x08, 0x12, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, + 0xff, 0x00, 0x00, 0x00, 0x2a, 0x80, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x56, 0x00, 0x00, 0x05, 0x12, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x07, 0x12, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0a, 0x00, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x8a, 0x00, 0x00, 0x10, 0x92, 0x00, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x40, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x02, 0x40, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0xa6, 0x8a, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x56, 0x00, 0x00, 0x05, 0x92, 0x00, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x06, 0x0c, 0x10, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x07, 0x62, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x56, 0x06, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x06, 0x03, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x32, 0x20, 0x00, 0x0c, 0x72, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x02, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x40, 0x00, 0x00, 0x81, 0x80, 0x80, 0x3b, 0x81, 0x80, 0x80, 0x3b, + 0x81, 0x80, 0x80, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x46, 0x02, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x1f, 0x00, 0x04, 0x04, 0x3a, 0x80, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x45, 0x00, 0x00, 0x8b, 0xc2, 0x00, 0x00, 0x80, 0x43, 0x55, 0x15, 0x00, 0xf2, 0x00, 0x10, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x46, 0x10, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x46, 0x7e, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x20, 0x00, 0x07, + 0x72, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x46, 0x02, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x05, 0x82, 0x20, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x01, + 0x55, 0x00, 0x00, 0x08, 0x82, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x80, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x56, 0x00, 0x00, 0x05, 0x82, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x07, 0x82, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3a, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x81, 0x80, 0x80, 0x3b, + 0x36, 0x00, 0x00, 0x05, 0x72, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x02, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x01, 0x3e, 0x00, 0x00, 0x01, 0x53, 0x54, 0x41, 0x54, + 0x94, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; #endif // MSL only makes sense on Apple platforms @@ -938,4 +1138,4 @@ static const Uint8 SolidColor_frag_spirv[4616] = { 0xb0, 0x00, 0x00, 0x00, 0xaf, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x07, 0x00, 0x00, 0x00, 0xae, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x08, 0x00, 0x00, 0x00, 0xb0, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00, -}; +}; \ No newline at end of file diff --git a/miniwin/src/d3drm/backends/sdl3gpu/shaders/src/Common.hlsl b/miniwin/src/d3drm/backends/sdl3gpu/shaders/src/Common.hlsl index c4d9d361..6330aa9b 100644 --- a/miniwin/src/d3drm/backends/sdl3gpu/shaders/src/Common.hlsl +++ b/miniwin/src/d3drm/backends/sdl3gpu/shaders/src/Common.hlsl @@ -18,3 +18,9 @@ struct SceneLight { float4 position; float4 direction; }; + +#ifdef NO_REGISTER_SPACE + #define REGISTER_SPACE(REG, SPACE) register(REG) +#else + #define REGISTER_SPACE(REG, SPACE) register(REG, SPACE) +#endif \ No newline at end of file diff --git a/miniwin/src/d3drm/backends/sdl3gpu/shaders/src/PositionColor.vert.hlsl b/miniwin/src/d3drm/backends/sdl3gpu/shaders/src/PositionColor.vert.hlsl index cbf14c6b..598b8f09 100644 --- a/miniwin/src/d3drm/backends/sdl3gpu/shaders/src/PositionColor.vert.hlsl +++ b/miniwin/src/d3drm/backends/sdl3gpu/shaders/src/PositionColor.vert.hlsl @@ -1,6 +1,6 @@ #include "Common.hlsl" -cbuffer ViewportUniforms : register(b0, space1) +cbuffer ViewportUniforms : REGISTER_SPACE(b0, space1) { float4x4 projection; float4x4 worldViewMatrix; diff --git a/miniwin/src/d3drm/backends/sdl3gpu/shaders/src/SolidColor.frag.hlsl b/miniwin/src/d3drm/backends/sdl3gpu/shaders/src/SolidColor.frag.hlsl index 6a6608ba..8f9a269e 100644 --- a/miniwin/src/d3drm/backends/sdl3gpu/shaders/src/SolidColor.frag.hlsl +++ b/miniwin/src/d3drm/backends/sdl3gpu/shaders/src/SolidColor.frag.hlsl @@ -5,7 +5,7 @@ struct FS_Output { float Depth : SV_Depth; }; -cbuffer FragmentShadingData : register(b0, space3) +cbuffer FragmentShadingData : REGISTER_SPACE(b0, space3) { SceneLight lights[3]; int lightCount; @@ -24,8 +24,8 @@ float4 unpackColor(uint packed) return color; } -Texture2D Texture : register(t0, space2); -SamplerState Sampler : register(s0, space2); +Texture2D Texture : REGISTER_SPACE(t0, space2); +SamplerState Sampler : REGISTER_SPACE(s0, space2); FS_Output main(FS_Input input) { diff --git a/miniwin/src/d3drm/backends/software/renderer.cpp b/miniwin/src/d3drm/backends/software/renderer.cpp index 64adc93b..93a80a2e 100644 --- a/miniwin/src/d3drm/backends/software/renderer.cpp +++ b/miniwin/src/d3drm/backends/software/renderer.cpp @@ -80,7 +80,7 @@ void Direct3DRMSoftwareRenderer::ClearZBuffer() _mm_empty(); } #endif -#elif defined(__arm__) || defined(__aarch64__) +#elif (defined(__arm__) || defined(__aarch64__)) && !defined(__3DS__) if (SDL_HasNEON()) { float32x4_t inf4 = vdupq_n_f32(inf); for (; i + 4 <= size; i += 4) { @@ -554,7 +554,7 @@ void Direct3DRMSoftwareRenderer::AddTextureDestroyCallback(Uint32 id, IDirect3DR ); } -Uint32 Direct3DRMSoftwareRenderer::GetTextureId(IDirect3DRMTexture* iTexture) +Uint32 Direct3DRMSoftwareRenderer::GetTextureId(IDirect3DRMTexture* iTexture, bool isUI, float scaleX, float scaleY) { auto texture = static_cast(iTexture); auto surface = static_cast(texture->m_surface); @@ -664,24 +664,6 @@ Uint32 Direct3DRMSoftwareRenderer::GetMeshId(IDirect3DRMMesh* mesh, const MeshGr return (Uint32) (m_meshs.size() - 1); } -void Direct3DRMSoftwareRenderer::GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc) -{ - memset(halDesc, 0, sizeof(D3DDEVICEDESC)); - - helDesc->dcmColorModel = D3DCOLORMODEL::RGB; - helDesc->dwFlags = D3DDD_DEVICEZBUFFERBITDEPTH; - helDesc->dwDeviceZBufferBitDepth = DDBD_32; - helDesc->dwDeviceRenderBitDepth = DDBD_32; - helDesc->dpcTriCaps.dwTextureCaps = D3DPTEXTURECAPS_PERSPECTIVE; - helDesc->dpcTriCaps.dwShadeCaps = D3DPSHADECAPS_ALPHAFLATBLEND; - helDesc->dpcTriCaps.dwTextureFilterCaps = D3DPTFILTERCAPS_LINEAR; -} - -const char* Direct3DRMSoftwareRenderer::GetName() -{ - return "Miniwin Emulation"; -} - HRESULT Direct3DRMSoftwareRenderer::BeginFrame() { if (!m_renderedImage || !SDL_LockSurface(m_renderedImage)) { @@ -779,10 +761,9 @@ void Direct3DRMSoftwareRenderer::Resize(int width, int height, const ViewportTra void Direct3DRMSoftwareRenderer::Clear(float r, float g, float b) { - SDL_Rect rect = {0, 0, m_renderedImage->w, m_renderedImage->h}; const SDL_PixelFormatDetails* details = SDL_GetPixelFormatDetails(m_renderedImage->format); Uint32 color = SDL_MapRGB(details, m_palette, r * 255, g * 255, b * 255); - SDL_FillSurfaceRect(m_renderedImage, &rect, color); + SDL_FillSurfaceRect(m_renderedImage, nullptr, color); } void Direct3DRMSoftwareRenderer::Flip() @@ -792,20 +773,51 @@ void Direct3DRMSoftwareRenderer::Flip() SDL_RenderPresent(m_renderer); } -void Direct3DRMSoftwareRenderer::Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, const SDL_Rect& dstRect) +void Direct3DRMSoftwareRenderer::Draw2DImage( + Uint32 textureId, + const SDL_Rect& srcRect, + const SDL_Rect& dstRect, + FColor color +) { - SDL_Surface* surface = m_textures[textureId].cached; - SDL_UnlockSurface(surface); SDL_Rect centeredRect = { static_cast(dstRect.x * m_viewportTransform.scale + m_viewportTransform.offsetX), static_cast(dstRect.y * m_viewportTransform.scale + m_viewportTransform.offsetY), static_cast(dstRect.w * m_viewportTransform.scale), static_cast(dstRect.h * m_viewportTransform.scale), }; - SDL_BlitSurfaceScaled(surface, &srcRect, m_renderedImage, ¢eredRect, SDL_SCALEMODE_LINEAR); + + if (textureId == NO_TEXTURE_ID) { + Uint32 sdlColor = SDL_MapRGBA( + m_format, + m_palette, + static_cast(color.r * 255), + static_cast(color.g * 255), + static_cast(color.b * 255), + static_cast(color.a * 255) + ); + SDL_FillSurfaceRect(m_renderedImage, ¢eredRect, sdlColor); + return; + } + + bool isUpscaling = centeredRect.w > srcRect.w || centeredRect.h > srcRect.h; + + SDL_Surface* surface = m_textures[textureId].cached; + SDL_UnlockSurface(surface); + SDL_BlitSurfaceScaled( + surface, + &srcRect, + m_renderedImage, + ¢eredRect, + isUpscaling ? SDL_SCALEMODE_NEAREST : SDL_SCALEMODE_LINEAR + ); SDL_LockSurface(surface); } +void Direct3DRMSoftwareRenderer::SetDither(bool dither) +{ +} + void Direct3DRMSoftwareRenderer::Download(SDL_Surface* target) { SDL_Rect srcRect = { diff --git a/miniwin/src/d3drm/d3drm.cpp b/miniwin/src/d3drm/d3drm.cpp index e8df37b1..3b4d5c9d 100644 --- a/miniwin/src/d3drm/d3drm.cpp +++ b/miniwin/src/d3drm/d3drm.cpp @@ -7,17 +7,6 @@ #include "d3drmmesh_impl.h" #include "d3drmobject_impl.h" #include "d3drmrenderer.h" -#ifdef USE_OPENGL1 -#include "d3drmrenderer_opengl1.h" -#endif -#ifdef USE_OPENGLES2 -#include "d3drmrenderer_opengles2.h" -#endif -#ifdef _WIN32 -#include "d3drmrenderer_directx9.h" -#endif -#include "d3drmrenderer_sdl3gpu.h" -#include "d3drmrenderer_software.h" #include "d3drmtexture_impl.h" #include "d3drmviewport_impl.h" #include "ddraw_impl.h" @@ -143,28 +132,12 @@ HRESULT Direct3DRMImpl::CreateDeviceFromSurface( DDSDesc.dwSize = sizeof(DDSURFACEDESC); surface->GetSurfaceDesc(&DDSDesc); - if (SDL_memcmp(&guid, &SDL3_GPU_GUID, sizeof(GUID)) == 0) { - DDRenderer = Direct3DRMSDL3GPURenderer::Create(DDSDesc.dwWidth, DDSDesc.dwHeight); - } - else if (SDL_memcmp(&guid, &SOFTWARE_GUID, sizeof(GUID)) == 0) { - DDRenderer = new Direct3DRMSoftwareRenderer(DDSDesc.dwWidth, DDSDesc.dwHeight); - } -#ifdef USE_OPENGLES2 - else if (SDL_memcmp(&guid, &OpenGLES2_GUID, sizeof(GUID)) == 0) { - DDRenderer = OpenGLES2Renderer::Create(DDSDesc.dwWidth, DDSDesc.dwHeight); - } -#endif -#ifdef USE_OPENGL1 - else if (SDL_memcmp(&guid, &OpenGL1_GUID, sizeof(GUID)) == 0) { - DDRenderer = OpenGL1Renderer::Create(DDSDesc.dwWidth, DDSDesc.dwHeight); - } -#endif -#ifdef _WIN32 - else if (SDL_memcmp(&guid, &DirectX9_GUID, sizeof(GUID)) == 0) { - DDRenderer = DirectX9Renderer::Create(DDSDesc.dwWidth, DDSDesc.dwHeight); - } -#endif - else { + IDirect3DMiniwin* miniwind3d = nullptr; + dd->QueryInterface(IID_IDirect3DMiniwin, (void**) &miniwind3d); + SDL_assert(miniwind3d); + + DDRenderer = CreateDirect3DRMRenderer(miniwind3d, DDSDesc, guid); + if (!DDRenderer) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Device GUID not recognized"); return E_NOINTERFACE; } diff --git a/miniwin/src/d3drm/d3drmdevice.cpp b/miniwin/src/d3drm/d3drmdevice.cpp index f6b2f9f7..2b062d50 100644 --- a/miniwin/src/d3drm/d3drmdevice.cpp +++ b/miniwin/src/d3drm/d3drmdevice.cpp @@ -84,9 +84,7 @@ D3DRMRENDERQUALITY Direct3DRMDevice2Impl::GetQuality() HRESULT Direct3DRMDevice2Impl::SetDither(BOOL dither) { - if (dither) { - MINIWIN_NOT_IMPLEMENTED(); - } + m_renderer->SetDither(dither); return DD_OK; } @@ -118,7 +116,6 @@ D3DRMRENDERMODE Direct3DRMDevice2Impl::GetRenderMode() HRESULT Direct3DRMDevice2Impl::Update() { - MINIWIN_NOT_IMPLEMENTED(); return DD_OK; } @@ -153,10 +150,14 @@ ViewportTransform CalculateViewportTransform(int virtualW, int virtualH, int win void Direct3DRMDevice2Impl::Resize() { - int width, height; - SDL_GetWindowSizeInPixels(DDWindow, &width, &height); - m_viewportTransform = CalculateViewportTransform(m_virtualWidth, m_virtualHeight, width, height); - m_renderer->Resize(width, height, m_viewportTransform); + SDL_GetWindowSizeInPixels(DDWindow, &m_windowWidth, &m_windowHeight); +#ifdef __3DS__ + m_windowWidth = 320; // We are on the lower screen + m_windowHeight = 240; +#endif + m_viewportTransform = CalculateViewportTransform(m_virtualWidth, m_virtualHeight, m_windowWidth, m_windowHeight); + m_renderer->Resize(m_windowWidth, m_windowHeight, m_viewportTransform); + m_renderer->Clear(0, 0, 0); for (int i = 0; i < m_viewports->GetSize(); i++) { IDirect3DRMViewport* viewport; m_viewports->GetElement(i, &viewport); @@ -171,18 +172,36 @@ bool Direct3DRMDevice2Impl::ConvertEventToRenderCoordinates(SDL_Event* event) Resize(); break; } - case SDL_EVENT_MOUSE_MOTION: + case SDL_EVENT_MOUSE_MOTION: { + event->motion.x = (event->motion.x - m_viewportTransform.offsetX) / m_viewportTransform.scale; + event->motion.y = (event->motion.y - m_viewportTransform.offsetY) / m_viewportTransform.scale; + break; + } case SDL_EVENT_MOUSE_BUTTON_DOWN: case SDL_EVENT_MOUSE_BUTTON_UP: { - int rawX = event->motion.x; - int rawY = event->motion.y; - float x = (rawX - m_viewportTransform.offsetX) / m_viewportTransform.scale; - float y = (rawY - m_viewportTransform.offsetY) / m_viewportTransform.scale; - event->motion.x = static_cast(x); - event->motion.y = static_cast(y); + event->button.x = (event->button.x - m_viewportTransform.offsetX) / m_viewportTransform.scale; + event->button.y = (event->button.y - m_viewportTransform.offsetY) / m_viewportTransform.scale; break; - } break; + } + case SDL_EVENT_FINGER_MOTION: + case SDL_EVENT_FINGER_DOWN: + case SDL_EVENT_FINGER_UP: + case SDL_EVENT_FINGER_CANCELED: { + float x = (event->tfinger.x * m_windowWidth - m_viewportTransform.offsetX) / m_viewportTransform.scale; + float y = (event->tfinger.y * m_windowHeight - m_viewportTransform.offsetY) / m_viewportTransform.scale; + event->tfinger.x = x / m_virtualWidth; + event->tfinger.y = y / m_virtualHeight; + break; + } } return true; } + +bool Direct3DRMDevice2Impl::ConvertRenderToWindowCoordinates(Sint32 inX, Sint32 inY, Sint32& outX, Sint32& outY) +{ + outX = static_cast(inX * m_viewportTransform.scale + m_viewportTransform.offsetX); + outY = static_cast(inY * m_viewportTransform.scale + m_viewportTransform.offsetY); + + return true; +} diff --git a/miniwin/src/d3drm/d3drmrenderer.cpp b/miniwin/src/d3drm/d3drmrenderer.cpp new file mode 100644 index 00000000..8fe210b5 --- /dev/null +++ b/miniwin/src/d3drm/d3drmrenderer.cpp @@ -0,0 +1,85 @@ +#include "d3drmrenderer.h" +#ifdef USE_OPENGL1 +#include "d3drmrenderer_opengl1.h" +#endif +#ifdef USE_OPENGLES3 +#include "d3drmrenderer_opengles3.h" +#endif +#ifdef USE_CITRO3D +#include "d3drmrenderer_citro3d.h" +#endif +#ifdef USE_DIRECTX9 +#include "d3drmrenderer_directx9.h" +#endif +#ifdef USE_SDL_GPU +#include "d3drmrenderer_sdl3gpu.h" +#endif +#ifdef USE_SOFTWARE_RENDER +#include "d3drmrenderer_software.h" +#endif + +Direct3DRMRenderer* CreateDirect3DRMRenderer( + const IDirect3DMiniwin* d3d, + const DDSURFACEDESC& DDSDesc, + const GUID* guid +) +{ +#ifdef USE_SDL_GPU + if (SDL_memcmp(guid, &SDL3_GPU_GUID, sizeof(GUID)) == 0) { + return Direct3DRMSDL3GPURenderer::Create(DDSDesc.dwWidth, DDSDesc.dwHeight); + } +#endif +#ifdef USE_SOFTWARE_RENDER + if (SDL_memcmp(guid, &SOFTWARE_GUID, sizeof(GUID)) == 0) { + return new Direct3DRMSoftwareRenderer(DDSDesc.dwWidth, DDSDesc.dwHeight); + } +#endif +#ifdef USE_OPENGLES3 + if (SDL_memcmp(guid, &OpenGLES3_GUID, sizeof(GUID)) == 0) { + return OpenGLES3Renderer::Create( + DDSDesc.dwWidth, + DDSDesc.dwHeight, + d3d->GetMSAASamples(), + d3d->GetAnisotropic() + ); + } +#endif +#ifdef USE_OPENGL1 + if (SDL_memcmp(guid, &OpenGL1_GUID, sizeof(GUID)) == 0) { + return OpenGL1Renderer::Create(DDSDesc.dwWidth, DDSDesc.dwHeight, d3d->GetMSAASamples()); + } +#endif +#ifdef USE_CITRO3D + if (SDL_memcmp(guid, &Citro3D_GUID, sizeof(GUID)) == 0) { + return new Citro3DRenderer(DDSDesc.dwWidth, DDSDesc.dwHeight); + } +#endif +#ifdef USE_DIRECTX9 + if (SDL_memcmp(guid, &DirectX9_GUID, sizeof(GUID)) == 0) { + return DirectX9Renderer::Create(DDSDesc.dwWidth, DDSDesc.dwHeight); + } +#endif + return nullptr; +} + +void Direct3DRMRenderer_EnumDevices(const IDirect3DMiniwin* d3d, LPD3DENUMDEVICESCALLBACK cb, void* ctx) +{ +#ifdef USE_SDL_GPU + Direct3DRMSDL3GPU_EnumDevice(cb, ctx); +#endif +#ifdef USE_OPENGLES3 + OpenGLES3Renderer_EnumDevice(d3d, cb, ctx); +#endif +#ifdef USE_OPENGL1 + OpenGL1Renderer_EnumDevice(d3d, cb, ctx); +#endif +#ifdef USE_CITRO3D + Citro3DRenderer_EnumDevice(cb, ctx); +#endif +#ifdef USE_DIRECTX9 + DirectX9Renderer_EnumDevice(cb, ctx); +#endif +#ifdef USE_SOFTWARE_RENDER + Direct3DRMSoftware_EnumDevice(cb, ctx); +#endif +} diff --git a/miniwin/src/ddraw/ddraw.cpp b/miniwin/src/ddraw/ddraw.cpp index 2765a2a1..b28a105b 100644 --- a/miniwin/src/ddraw/ddraw.cpp +++ b/miniwin/src/ddraw/ddraw.cpp @@ -1,14 +1,5 @@ -#ifdef USE_OPENGL1 -#include "d3drmrenderer_opengl1.h" -#endif -#ifdef USE_OPENGLES2 -#include "d3drmrenderer_opengles2.h" -#endif -#ifdef _WIN32 -#include "d3drmrenderer_directx9.h" -#endif -#include "d3drmrenderer_sdl3gpu.h" -#include "d3drmrenderer_software.h" + +#include "d3drmrenderer.h" #include "ddpalette_impl.h" #include "ddraw_impl.h" #include "ddsurface_impl.h" @@ -18,6 +9,7 @@ #include #include +#include #include #include #include @@ -37,6 +29,11 @@ HRESULT DirectDrawImpl::QueryInterface(const GUID& riid, void** ppvObject) *ppvObject = static_cast(this); return S_OK; } + if (SDL_memcmp(&riid, &IID_IDirect3DMiniwin, sizeof(GUID)) == 0) { + this->IUnknown::AddRef(); + *ppvObject = static_cast(this); + return S_OK; + } MINIWIN_NOT_IMPLEMENTED(); return E_NOINTERFACE; } @@ -75,7 +72,7 @@ HRESULT DirectDrawImpl::CreateSurface( if ((lpDDSurfaceDesc->dwFlags & DDSD_ZBUFFERBITDEPTH) != DDSD_ZBUFFERBITDEPTH) { return DDERR_INVALIDPARAMS; } - SDL_Log("Todo: Set %dbit Z-Buffer", lpDDSurfaceDesc->dwZBufferBitDepth); + SDL_Log("Todo: Set %" PRIu32 "bit Z-Buffer", lpDDSurfaceDesc->dwZBufferBitDepth); *lplpDDSurface = static_cast(new DummySurfaceImpl); return DD_OK; } @@ -102,13 +99,17 @@ HRESULT DirectDrawImpl::CreateSurface( #endif if ((lpDDSurfaceDesc->dwFlags & DDSD_PIXELFORMAT) == DDSD_PIXELFORMAT) { if ((lpDDSurfaceDesc->ddpfPixelFormat.dwFlags & DDPF_RGB) == DDPF_RGB) { - switch (lpDDSurfaceDesc->ddpfPixelFormat.dwRGBBitCount) { - case 8: - format = SDL_PIXELFORMAT_INDEX8; - break; - case 16: - format = SDL_PIXELFORMAT_RGB565; - break; + int bpp = lpDDSurfaceDesc->ddpfPixelFormat.dwRGBBitCount; + Uint32 rMask = lpDDSurfaceDesc->ddpfPixelFormat.dwRBitMask; + Uint32 gMask = lpDDSurfaceDesc->ddpfPixelFormat.dwGBitMask; + Uint32 bMask = lpDDSurfaceDesc->ddpfPixelFormat.dwBBitMask; + Uint32 aMask = (lpDDSurfaceDesc->ddpfPixelFormat.dwFlags & DDPF_ALPHAPIXELS) == DDPF_ALPHAPIXELS + ? lpDDSurfaceDesc->ddpfPixelFormat.dwRGBAlphaBitMask + : 0; + + format = SDL_GetPixelFormatForMasks(bpp, rMask, gMask, bMask, aMask); + if (format == SDL_PIXELFORMAT_UNKNOWN) { + return DDERR_INVALIDPIXELFORMAT; } } } @@ -164,7 +165,7 @@ HRESULT DirectDrawImpl::EnumDisplayModes( ddsd.dwWidth = modes[i]->w; ddsd.dwHeight = modes[i]->h; ddsd.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT); - ddsd.ddpfPixelFormat.dwFlags = DDPF_RGB; + ddsd.ddpfPixelFormat.dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS; ddsd.ddpfPixelFormat.dwRGBBitCount = details->bits_per_pixel; if (details->bits_per_pixel == 8) { ddsd.ddpfPixelFormat.dwFlags |= DDPF_PALETTEINDEXED8; @@ -206,32 +207,25 @@ HRESULT DirectDrawImpl::GetCaps(LPDDCAPS lpDDDriverCaps, LPDDCAPS lpDDHELCaps) return S_OK; } -void EnumDevice(LPD3DENUMDEVICESCALLBACK cb, void* ctx, Direct3DRMRenderer* device, GUID deviceGuid) +void EnumDevice( + LPD3DENUMDEVICESCALLBACK cb, + void* ctx, + const char* name, + D3DDEVICEDESC* halDesc, + D3DDEVICEDESC* helDesc, + GUID deviceGuid +) { - D3DDEVICEDESC halDesc = {}; - D3DDEVICEDESC helDesc = {}; - device->GetDesc(&halDesc, &helDesc); - char* deviceNameDup = SDL_strdup(device->GetName()); + char* deviceNameDup = SDL_strdup(name); char* deviceDescDup = SDL_strdup("Miniwin driver"); - cb(&deviceGuid, deviceNameDup, deviceDescDup, &halDesc, &helDesc, ctx); + cb(&deviceGuid, deviceNameDup, deviceDescDup, halDesc, helDesc, ctx); SDL_free(deviceDescDup); SDL_free(deviceNameDup); } HRESULT DirectDrawImpl::EnumDevices(LPD3DENUMDEVICESCALLBACK cb, void* ctx) { - Direct3DRMSDL3GPU_EnumDevice(cb, ctx); -#ifdef USE_OPENGLES2 - OpenGLES2Renderer_EnumDevice(cb, ctx); -#endif -#ifdef USE_OPENGL1 - OpenGL1Renderer_EnumDevice(cb, ctx); -#endif -#ifdef _WIN32 - DirectX9Renderer_EnumDevice(cb, ctx); -#endif - Direct3DRMSoftware_EnumDevice(cb, ctx); - + Direct3DRMRenderer_EnumDevices(this, cb, ctx); return S_OK; } @@ -260,7 +254,7 @@ HRESULT DirectDrawImpl::GetDisplayMode(LPDDSURFACEDESC lpDDSurfaceDesc) lpDDSurfaceDesc->dwWidth = mode->w; lpDDSurfaceDesc->dwHeight = mode->h; lpDDSurfaceDesc->ddpfPixelFormat.dwRGBBitCount = details->bits_per_pixel; - lpDDSurfaceDesc->ddpfPixelFormat.dwFlags = DDPF_RGB; + lpDDSurfaceDesc->ddpfPixelFormat.dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS; if (details->bits_per_pixel == 8) { lpDDSurfaceDesc->ddpfPixelFormat.dwFlags |= DDPF_PALETTEINDEXED8; } @@ -300,11 +294,11 @@ HRESULT DirectDrawImpl::SetCooperativeLevel(HWND hWnd, DDSCLFlags dwFlags) return DDERR_INVALIDPARAMS; } - if (!SDL_SetWindowFullscreen(sdlWindow, fullscreen)) { #ifndef __EMSCRIPTEN__ + if (!SDL_SetWindowFullscreen(sdlWindow, fullscreen)) { return DDERR_GENERIC; -#endif } +#endif DDWindow = sdlWindow; } return DD_OK; @@ -328,28 +322,8 @@ HRESULT DirectDrawImpl::CreateDevice( DDSDesc.dwSize = sizeof(DDSURFACEDESC); pBackBuffer->GetSurfaceDesc(&DDSDesc); - if (SDL_memcmp(&guid, &SDL3_GPU_GUID, sizeof(GUID)) == 0) { - DDRenderer = Direct3DRMSDL3GPURenderer::Create(DDSDesc.dwWidth, DDSDesc.dwHeight); - } -#ifdef USE_OPENGLES2 - else if (SDL_memcmp(&guid, &OpenGLES2_GUID, sizeof(GUID)) == 0) { - DDRenderer = OpenGLES2Renderer::Create(DDSDesc.dwWidth, DDSDesc.dwHeight); - } -#endif -#ifdef USE_OPENGL1 - else if (SDL_memcmp(&guid, &OpenGL1_GUID, sizeof(GUID)) == 0) { - DDRenderer = OpenGL1Renderer::Create(DDSDesc.dwWidth, DDSDesc.dwHeight); - } -#endif -#ifdef _WIN32 - else if (SDL_memcmp(&guid, &DirectX9_GUID, sizeof(GUID)) == 0) { - DDRenderer = DirectX9Renderer::Create(DDSDesc.dwWidth, DDSDesc.dwHeight); - } -#endif - else if (SDL_memcmp(&guid, &SOFTWARE_GUID, sizeof(GUID)) == 0) { - DDRenderer = new Direct3DRMSoftwareRenderer(DDSDesc.dwWidth, DDSDesc.dwHeight); - } - else { + DDRenderer = CreateDirect3DRMRenderer(this, DDSDesc, &guid); + if (!DDRenderer) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Device GUID not recognized"); return E_NOINTERFACE; } diff --git a/miniwin/src/ddraw/ddsurface.cpp b/miniwin/src/ddraw/ddsurface.cpp index de250dea..9e710596 100644 --- a/miniwin/src/ddraw/ddsurface.cpp +++ b/miniwin/src/ddraw/ddsurface.cpp @@ -52,6 +52,24 @@ HRESULT DirectDrawSurfaceImpl::Blt( LPDDBLTFX lpDDBltFx ) { + 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; + + const SDL_PixelFormatDetails* details = SDL_GetPixelFormatDetails(m_surface->format); + Uint32 color = SDL_MapRGBA(details, nullptr, r, g, b, a); + if (lpDestRect) { + SDL_Rect dstRect = ConvertRect(lpDestRect); + SDL_FillSurfaceRect(m_surface, &dstRect, color); + } + else { + SDL_FillSurfaceRect(m_surface, nullptr, color); + } + return DD_OK; + } + auto other = static_cast(lpDDSrcSurface); SDL_Rect srcRect = lpSrcRect ? ConvertRect(lpSrcRect) : SDL_Rect{0, 0, other->m_surface->w, other->m_surface->h}; @@ -127,7 +145,7 @@ HRESULT DirectDrawSurfaceImpl::GetPalette(LPDIRECTDRAWPALETTE* lplpDDPalette) HRESULT DirectDrawSurfaceImpl::GetPixelFormat(LPDDPIXELFORMAT lpDDPixelFormat) { memset(lpDDPixelFormat, 0, sizeof(*lpDDPixelFormat)); - lpDDPixelFormat->dwFlags = DDPF_RGB; + lpDDPixelFormat->dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS; const SDL_PixelFormatDetails* details = SDL_GetPixelFormatDetails(m_surface->format); if (details->bits_per_pixel == 8) { lpDDPixelFormat->dwFlags |= DDPF_PALETTEINDEXED8; diff --git a/miniwin/src/ddraw/framebuffer.cpp b/miniwin/src/ddraw/framebuffer.cpp index eb21abef..d3d8a3b8 100644 --- a/miniwin/src/ddraw/framebuffer.cpp +++ b/miniwin/src/ddraw/framebuffer.cpp @@ -48,26 +48,44 @@ HRESULT FrameBufferImpl::Blt( if (!DDRenderer) { return DDERR_GENERIC; } + if (dynamic_cast(lpDDSrcSurface) == this) { return Flip(nullptr, DDFLIP_WAIT); } + if ((dwFlags & DDBLT_COLORFILL) == DDBLT_COLORFILL) { + Uint8 a = (lpDDBltFx->dwFillColor >> 24) & 0xFF; Uint8 r = (lpDDBltFx->dwFillColor >> 16) & 0xFF; Uint8 g = (lpDDBltFx->dwFillColor >> 8) & 0xFF; Uint8 b = lpDDBltFx->dwFillColor & 0xFF; - DDRenderer->Clear(r / 255.0f, g / 255.0f, b / 255.0f); + + float fa = a / 255.0f; + float fr = r / 255.0f; + float fg = g / 255.0f; + float fb = b / 255.0f; + + if (lpDestRect) { + SDL_Rect dstRect = ConvertRect(lpDestRect); + DDRenderer->Draw2DImage(NO_TEXTURE_ID, SDL_Rect{}, dstRect, {fr, fg, fb, fa}); + } + else { + DDRenderer->Clear(fr, fg, fb); + } return DD_OK; } + auto surface = static_cast(lpDDSrcSurface); if (!surface) { return DDERR_GENERIC; } - Uint32 textureId = DDRenderer->GetTextureId(surface->ToTexture()); SDL_Rect srcRect = lpSrcRect ? ConvertRect(lpSrcRect) : SDL_Rect{0, 0, surface->m_surface->w, surface->m_surface->h}; SDL_Rect dstRect = lpDestRect ? ConvertRect(lpDestRect) : SDL_Rect{0, 0, (int) m_virtualWidth, (int) m_virtualHeight}; - DDRenderer->Draw2DImage(textureId, srcRect, dstRect); + float scaleX = (float) dstRect.w / (float) srcRect.w; + float scaleY = (float) dstRect.h / (float) srcRect.h; + Uint32 textureId = DDRenderer->GetTextureId(surface->ToTexture(), true, scaleX, scaleY); + DDRenderer->Draw2DImage(textureId, srcRect, dstRect, {1.0f, 1.0f, 1.0f, 1.0f}); return DD_OK; } @@ -125,7 +143,7 @@ HRESULT FrameBufferImpl::GetPalette(LPDIRECTDRAWPALETTE* lplpDDPalette) HRESULT FrameBufferImpl::GetPixelFormat(LPDDPIXELFORMAT lpDDPixelFormat) { memset(lpDDPixelFormat, 0, sizeof(*lpDDPixelFormat)); - lpDDPixelFormat->dwFlags = DDPF_RGB; + lpDDPixelFormat->dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS; const SDL_PixelFormatDetails* details = SDL_GetPixelFormatDetails(m_transferBuffer->m_surface->format); if (details->bits_per_pixel == 8) { lpDDPixelFormat->dwFlags |= DDPF_PALETTEINDEXED8; @@ -153,12 +171,14 @@ HRESULT FrameBufferImpl::Lock(LPRECT lpDestRect, DDSURFACEDESC* lpDDSurfaceDesc, if (!DDRenderer) { return DDERR_GENERIC; } + + m_readOnlyLock = (dwFlags & DDLOCK_READONLY) == DDLOCK_READONLY; + if ((dwFlags & DDLOCK_WRITEONLY) == DDLOCK_WRITEONLY) { - SDL_Rect rect = {0, 0, m_transferBuffer->m_surface->w, m_transferBuffer->m_surface->h}; const SDL_PixelFormatDetails* details = SDL_GetPixelFormatDetails(m_transferBuffer->m_surface->format); SDL_Palette* palette = m_palette ? static_cast(m_palette)->m_palette : nullptr; Uint32 color = SDL_MapRGBA(details, palette, 0, 0, 0, 0); - SDL_FillSurfaceRect(m_transferBuffer->m_surface, &rect, color); + SDL_FillSurfaceRect(m_transferBuffer->m_surface, nullptr, color); } else { DDRenderer->Download(m_transferBuffer->m_surface); @@ -206,7 +226,9 @@ HRESULT FrameBufferImpl::SetPalette(LPDIRECTDRAWPALETTE lpDDPalette) HRESULT FrameBufferImpl::Unlock(LPVOID lpSurfaceData) { m_transferBuffer->Unlock(lpSurfaceData); - BltFast(0, 0, m_transferBuffer, nullptr, DDBLTFAST_WAIT); + if (!m_readOnlyLock) { + BltFast(0, 0, m_transferBuffer, nullptr, DDBLTFAST_WAIT); + } return DD_OK; } diff --git a/miniwin/src/internal/d3drmdevice_impl.h b/miniwin/src/internal/d3drmdevice_impl.h index daab564a..46dc5ed2 100644 --- a/miniwin/src/internal/d3drmdevice_impl.h +++ b/miniwin/src/internal/d3drmdevice_impl.h @@ -34,12 +34,15 @@ struct Direct3DRMDevice2Impl : public Direct3DRMObjectBaseImpl #include +#include #include -DEFINE_GUID(OpenGLES2_GUID, 0x682656F3, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04); +DEFINE_GUID(Citro3D_GUID, 0x682656F3, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3D, 0x53); -struct GLES2TextureCacheEntry { +struct C3DTextureCacheEntry { IDirect3DRMTexture* texture; Uint32 version; - GLuint glTextureId; + C3D_Tex c3dTex; uint16_t width; uint16_t height; }; -struct GLES2MeshCacheEntry { - const MeshGroup* meshGroup; - int version; - bool flat; - - std::vector indices; - GLuint vboPositions; - GLuint vboNormals; - GLuint vboTexcoords; - GLuint ibo; +struct C3DMeshCacheEntry { + const MeshGroup* meshGroup = nullptr; + int version = 0; + void* vbo = nullptr; + int vertexCount = 0; }; -class OpenGLES2Renderer : public Direct3DRMRenderer { +class Citro3DRenderer : public Direct3DRMRenderer { public: - static Direct3DRMRenderer* Create(DWORD width, DWORD height); - OpenGLES2Renderer(DWORD width, DWORD height, SDL_GLContext context, GLuint shaderProgram); - ~OpenGLES2Renderer() override; + Citro3DRenderer(DWORD width, DWORD height); + ~Citro3DRenderer() override; void PushLights(const SceneLight* lightsArray, size_t count) override; void SetProjection(const D3DRMMATRIX4D& projection, D3DVALUE front, D3DVALUE back) override; void SetFrustumPlanes(const Plane* frustumPlanes) override; - Uint32 GetTextureId(IDirect3DRMTexture* texture) override; + Uint32 GetTextureId(IDirect3DRMTexture* texture, bool isUI, float scaleX, float scaleY) override; Uint32 GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* meshGroup) override; - void GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc) override; - const char* GetName() override; HRESULT BeginFrame() override; void EnableTransparency() override; void SubmitDraw( @@ -57,29 +48,36 @@ class OpenGLES2Renderer : public Direct3DRMRenderer { void Resize(int width, int height, const ViewportTransform& viewportTransform) override; void Clear(float r, float g, float b) override; void Flip() override; - void Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, const SDL_Rect& dstRect) override; + void Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, const SDL_Rect& dstRect, FColor color) override; void Download(SDL_Surface* target) override; + void SetDither(bool dither) override; private: void AddTextureDestroyCallback(Uint32 id, IDirect3DRMTexture* texture); void AddMeshDestroyCallback(Uint32 id, IDirect3DRMMesh* mesh); + void StartFrame(); - std::vector m_textures; - std::vector m_meshs; D3DRMMATRIX4D m_projection; SDL_Surface* m_renderedImage; - bool m_dirty = false; - std::vector m_lights; - SDL_GLContext m_context; - GLuint m_shaderProgram; + C3D_RenderTarget* m_renderTarget; + std::vector m_textures; + std::vector m_meshs; ViewportTransform m_viewportTransform; + std::vector m_lights; }; -inline static void OpenGLES2Renderer_EnumDevice(LPD3DENUMDEVICESCALLBACK cb, void* ctx) +inline static void Citro3DRenderer_EnumDevice(LPD3DENUMDEVICESCALLBACK cb, void* ctx) { - Direct3DRMRenderer* device = OpenGLES2Renderer::Create(640, 480); - if (device) { - EnumDevice(cb, ctx, device, OpenGLES2_GUID); - delete device; - } + D3DDEVICEDESC halDesc = {}; + halDesc.dcmColorModel = D3DCOLOR_RGB; + halDesc.dwFlags = D3DDD_DEVICEZBUFFERBITDEPTH; + halDesc.dwDeviceZBufferBitDepth = DDBD_24; + halDesc.dwDeviceRenderBitDepth = DDBD_32; + halDesc.dpcTriCaps.dwTextureCaps = D3DPTEXTURECAPS_PERSPECTIVE; + halDesc.dpcTriCaps.dwShadeCaps = D3DPSHADECAPS_ALPHAFLATBLEND; + halDesc.dpcTriCaps.dwTextureFilterCaps = D3DPTFILTERCAPS_LINEAR; + + D3DDEVICEDESC helDesc = {}; + + EnumDevice(cb, ctx, "Citro3D", &halDesc, &helDesc, Citro3D_GUID); } diff --git a/miniwin/src/internal/d3drmrenderer_directx9.h b/miniwin/src/internal/d3drmrenderer_directx9.h index b7badb03..5e87aed3 100644 --- a/miniwin/src/internal/d3drmrenderer_directx9.h +++ b/miniwin/src/internal/d3drmrenderer_directx9.h @@ -18,10 +18,8 @@ class DirectX9Renderer : public Direct3DRMRenderer { void PushLights(const SceneLight* lightsArray, size_t count) override; void SetProjection(const D3DRMMATRIX4D& projection, D3DVALUE front, D3DVALUE back) override; void SetFrustumPlanes(const Plane* frustumPlanes) override; - Uint32 GetTextureId(IDirect3DRMTexture* texture) override; + Uint32 GetTextureId(IDirect3DRMTexture* texture, bool isUI, float scaleX, float scaleY) override; Uint32 GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* meshGroup) override; - void GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc) override; - const char* GetName() override; HRESULT BeginFrame() override; void EnableTransparency() override; void SubmitDraw( @@ -36,8 +34,9 @@ class DirectX9Renderer : public Direct3DRMRenderer { void Resize(int width, int height, const ViewportTransform& viewportTransform) override; void Clear(float r, float g, float b) override; void Flip() override; - void Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, const SDL_Rect& dstRect) override; + void Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, const SDL_Rect& dstRect, FColor color) override; void Download(SDL_Surface* target) override; + void SetDither(bool dither) override; private: void AddTextureDestroyCallback(Uint32 id, IDirect3DRMTexture* texture); @@ -52,8 +51,21 @@ class DirectX9Renderer : public Direct3DRMRenderer { inline static void DirectX9Renderer_EnumDevice(LPD3DENUMDEVICESCALLBACK cb, void* ctx) { Direct3DRMRenderer* device = DirectX9Renderer::Create(640, 480); - if (device) { - EnumDevice(cb, ctx, device, DirectX9_GUID); - delete device; + if (!device) { + return; } + delete device; + + D3DDEVICEDESC halDesc = {}; + halDesc.dcmColorModel = D3DCOLOR_RGB; + halDesc.dwFlags = D3DDD_DEVICEZBUFFERBITDEPTH; + halDesc.dwDeviceZBufferBitDepth = DDBD_24; + halDesc.dwDeviceRenderBitDepth = DDBD_32; + halDesc.dpcTriCaps.dwTextureCaps = D3DPTEXTURECAPS_PERSPECTIVE; + halDesc.dpcTriCaps.dwShadeCaps = D3DPSHADECAPS_ALPHAFLATBLEND; + halDesc.dpcTriCaps.dwTextureFilterCaps = D3DPTFILTERCAPS_LINEAR; + + D3DDEVICEDESC helDesc = {}; + + EnumDevice(cb, ctx, "DirectX 9 HAL", &halDesc, &helDesc, DirectX9_GUID); } diff --git a/miniwin/src/internal/d3drmrenderer_opengl1.h b/miniwin/src/internal/d3drmrenderer_opengl1.h index 71c0ea82..894fa10c 100644 --- a/miniwin/src/internal/d3drmrenderer_opengl1.h +++ b/miniwin/src/internal/d3drmrenderer_opengl1.h @@ -1,57 +1,25 @@ #pragma once - +#include "../d3drm/backends/opengl1/actual.h" #include "d3drmrenderer.h" #include "d3drmtexture_impl.h" #include "ddraw_impl.h" -#ifdef __APPLE__ -#include -#else -#include -#endif - #include #include DEFINE_GUID(OpenGL1_GUID, 0x682656F3, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03); -struct GLTextureCacheEntry { - IDirect3DRMTexture* texture; - Uint32 version; - GLuint glTextureId; -}; - -struct GLMeshCacheEntry { - const MeshGroup* meshGroup; - int version; - bool flat; - - // non-VBO cache - std::vector positions; - std::vector normals; - std::vector texcoords; - std::vector indices; - - // VBO cache - GLuint vboPositions; - GLuint vboNormals; - GLuint vboTexcoords; - GLuint ibo; -}; - class OpenGL1Renderer : public Direct3DRMRenderer { public: - static Direct3DRMRenderer* Create(DWORD width, DWORD height); + static Direct3DRMRenderer* Create(DWORD width, DWORD height, DWORD msaaSamples); OpenGL1Renderer(DWORD width, DWORD height, SDL_GLContext context); ~OpenGL1Renderer() override; void PushLights(const SceneLight* lightsArray, size_t count) override; void SetProjection(const D3DRMMATRIX4D& projection, D3DVALUE front, D3DVALUE back) override; void SetFrustumPlanes(const Plane* frustumPlanes) override; - Uint32 GetTextureId(IDirect3DRMTexture* texture) override; + Uint32 GetTextureId(IDirect3DRMTexture* texture, bool isUI, float scaleX, float scaleY) override; Uint32 GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* meshGroup) override; - void GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc) override; - const char* GetName() override; HRESULT BeginFrame() override; void EnableTransparency() override; void SubmitDraw( @@ -66,8 +34,9 @@ class OpenGL1Renderer : public Direct3DRMRenderer { void Resize(int width, int height, const ViewportTransform& viewportTransform) override; void Clear(float r, float g, float b) override; void Flip() override; - void Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, const SDL_Rect& dstRect) override; + void Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, const SDL_Rect& dstRect, FColor color) override; void Download(SDL_Surface* target) override; + void SetDither(bool dither) override; private: void AddTextureDestroyCallback(Uint32 id, IDirect3DRMTexture* texture); @@ -78,17 +47,31 @@ class OpenGL1Renderer : public Direct3DRMRenderer { D3DRMMATRIX4D m_projection; SDL_Surface* m_renderedImage; bool m_useVBOs; + bool m_useNPOT; bool m_dirty = false; std::vector m_lights; SDL_GLContext m_context; ViewportTransform m_viewportTransform; }; -inline static void OpenGL1Renderer_EnumDevice(LPD3DENUMDEVICESCALLBACK cb, void* ctx) +inline static void OpenGL1Renderer_EnumDevice(const IDirect3DMiniwin* d3d, LPD3DENUMDEVICESCALLBACK cb, void* ctx) { - Direct3DRMRenderer* device = OpenGL1Renderer::Create(640, 480); - if (device) { - EnumDevice(cb, ctx, device, OpenGL1_GUID); - delete device; + Direct3DRMRenderer* device = OpenGL1Renderer::Create(640, 480, d3d->GetMSAASamples()); + if (!device) { + return; } + delete device; + + D3DDEVICEDESC halDesc = {}; + halDesc.dcmColorModel = D3DCOLORMODEL::RGB; + halDesc.dwFlags = D3DDD_DEVICEZBUFFERBITDEPTH; + halDesc.dwDeviceZBufferBitDepth = DDBD_24; + halDesc.dwDeviceRenderBitDepth = DDBD_32; + halDesc.dpcTriCaps.dwTextureCaps = D3DPTEXTURECAPS_PERSPECTIVE; + halDesc.dpcTriCaps.dwShadeCaps = D3DPSHADECAPS_ALPHAFLATBLEND; + halDesc.dpcTriCaps.dwTextureFilterCaps = D3DPTFILTERCAPS_LINEAR; + + D3DDEVICEDESC helDesc = {}; + + EnumDevice(cb, ctx, "OpenGL 1.1 HAL", &halDesc, &helDesc, OpenGL1_GUID); } diff --git a/miniwin/src/internal/d3drmrenderer_opengles3.h b/miniwin/src/internal/d3drmrenderer_opengles3.h new file mode 100644 index 00000000..e3f3f59d --- /dev/null +++ b/miniwin/src/internal/d3drmrenderer_opengles3.h @@ -0,0 +1,130 @@ +#pragma once + +#include "d3drmrenderer.h" +#include "d3drmtexture_impl.h" +#include "ddraw_impl.h" + +#include +#include +#include + +DEFINE_GUID(OpenGLES3_GUID, 0x682656F3, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04); + +struct GLES3TextureCacheEntry { + IDirect3DRMTexture* texture; + Uint32 version; + GLuint glTextureId; + uint16_t width; + uint16_t height; +}; + +struct GLES3MeshCacheEntry { + const MeshGroup* meshGroup; + int version; + bool flat; + + std::vector indices; + GLuint vboPositions; + GLuint vboNormals; + GLuint vboTexcoords; + GLuint ibo; + GLuint vao; +}; + +class OpenGLES3Renderer : public Direct3DRMRenderer { +public: + static Direct3DRMRenderer* Create(DWORD width, DWORD height, DWORD msaaSamples, float anisotropic); + OpenGLES3Renderer( + DWORD width, + DWORD height, + DWORD msaaSamples, + float anisotropic, + SDL_GLContext context, + GLuint shaderProgram + ); + ~OpenGLES3Renderer() override; + + void PushLights(const SceneLight* lightsArray, size_t count) override; + void SetProjection(const D3DRMMATRIX4D& projection, D3DVALUE front, D3DVALUE back) override; + void SetFrustumPlanes(const Plane* frustumPlanes) override; + Uint32 GetTextureId(IDirect3DRMTexture* texture, bool isUI, float scaleX, float scaleY) override; + Uint32 GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* meshGroup) 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; + +private: + void AddTextureDestroyCallback(Uint32 id, IDirect3DRMTexture* texture); + void AddMeshDestroyCallback(Uint32 id, IDirect3DRMMesh* mesh); + GLES3MeshCacheEntry GLES3UploadMesh(const MeshGroup& meshGroup, bool forceUV = false); + bool UploadTexture(SDL_Surface* source, GLuint& outTexId, bool isUI); + + MeshGroup m_uiMesh; + GLES3MeshCacheEntry m_uiMeshCache; + std::vector m_textures; + std::vector m_meshs; + D3DRMMATRIX4D m_projection; + SDL_Surface* m_renderedImage = nullptr; + bool m_dirty = false; + std::vector m_lights; + SDL_GLContext m_context; + uint32_t m_msaa; + float m_anisotropic; + GLuint m_fbo; + GLuint m_resolveFBO; + GLuint m_colorTarget; + GLuint m_resolveColor = 0; + GLuint m_depthTarget; + GLuint m_shaderProgram; + GLuint m_dummyTexture; + GLint m_posLoc; + GLint m_normLoc; + GLint m_texLoc; + GLint m_colorLoc; + GLint m_shinLoc; + GLint m_lightCountLoc; + GLint m_useTextureLoc; + GLint m_textureLoc; + GLint u_lightLocs[3][3]; + GLint m_modelViewMatrixLoc; + GLint m_normalMatrixLoc; + GLint m_projectionMatrixLoc; + ViewportTransform m_viewportTransform; +}; + +inline static void OpenGLES3Renderer_EnumDevice(const IDirect3DMiniwin* d3d, LPD3DENUMDEVICESCALLBACK cb, void* ctx) +{ + Direct3DRMRenderer* device = OpenGLES3Renderer::Create(640, 480, d3d->GetMSAASamples(), d3d->GetAnisotropic()); + if (!device) { + return; + } + + delete device; + + D3DDEVICEDESC halDesc = {}; + halDesc.dcmColorModel = D3DCOLOR_RGB; + halDesc.dwFlags = D3DDD_DEVICEZBUFFERBITDEPTH; + halDesc.dwDeviceZBufferBitDepth = DDBD_24; + halDesc.dwDeviceRenderBitDepth = DDBD_32; + halDesc.dpcTriCaps.dwTextureCaps = D3DPTEXTURECAPS_PERSPECTIVE; + halDesc.dpcTriCaps.dwShadeCaps = D3DPSHADECAPS_ALPHAFLATBLEND; + halDesc.dpcTriCaps.dwTextureFilterCaps = D3DPTFILTERCAPS_LINEAR; + + D3DDEVICEDESC helDesc = {}; + + EnumDevice(cb, ctx, "OpenGL ES 3.0 HAL", &halDesc, &helDesc, OpenGLES3_GUID); +} diff --git a/miniwin/src/internal/d3drmrenderer_sdl3gpu.h b/miniwin/src/internal/d3drmrenderer_sdl3gpu.h index 25485b1f..1e528232 100644 --- a/miniwin/src/internal/d3drmrenderer_sdl3gpu.h +++ b/miniwin/src/internal/d3drmrenderer_sdl3gpu.h @@ -47,12 +47,10 @@ class Direct3DRMSDL3GPURenderer : public Direct3DRMRenderer { static Direct3DRMRenderer* Create(DWORD width, DWORD height); ~Direct3DRMSDL3GPURenderer() override; void PushLights(const SceneLight* vertices, size_t count) override; - Uint32 GetTextureId(IDirect3DRMTexture* texture) 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; - void GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc) override; - const char* GetName() override; HRESULT BeginFrame() override; void EnableTransparency() override; void SubmitDraw( @@ -67,8 +65,9 @@ class Direct3DRMSDL3GPURenderer : public Direct3DRMRenderer { void Resize(int width, int height, const ViewportTransform& viewportTransform) override; void Clear(float r, float g, float b) override; void Flip() override; - void Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, const SDL_Rect& dstRect) override; + void Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, const SDL_Rect& dstRect, FColor color) override; void Download(SDL_Surface* target) override; + void SetDither(bool dither) override; private: Direct3DRMSDL3GPURenderer( @@ -121,9 +120,30 @@ class Direct3DRMSDL3GPURenderer : public Direct3DRMRenderer { inline static void Direct3DRMSDL3GPU_EnumDevice(LPD3DENUMDEVICESCALLBACK cb, void* ctx) { - Direct3DRMRenderer* device = Direct3DRMSDL3GPURenderer::Create(640, 480); - if (device) { - EnumDevice(cb, ctx, device, SDL3_GPU_GUID); - delete device; +#ifdef __APPLE__ + SDL_GPUDevice* device = SDL_CreateGPUDevice(SDL_GPU_SHADERFORMAT_MSL, false, nullptr); + if (!device) { + return; } + SDL_DestroyGPUDevice(device); +#else + Direct3DRMRenderer* device = Direct3DRMSDL3GPURenderer::Create(640, 480); + if (!device) { + return; + } + delete device; +#endif + + D3DDEVICEDESC halDesc = {}; + halDesc.dcmColorModel = D3DCOLOR_RGB; + halDesc.dwFlags = D3DDD_DEVICEZBUFFERBITDEPTH; + halDesc.dwDeviceZBufferBitDepth = DDBD_32; + halDesc.dwDeviceRenderBitDepth = DDBD_32; + halDesc.dpcTriCaps.dwTextureCaps = D3DPTEXTURECAPS_PERSPECTIVE; + halDesc.dpcTriCaps.dwShadeCaps = D3DPSHADECAPS_ALPHAFLATBLEND; + halDesc.dpcTriCaps.dwTextureFilterCaps = D3DPTFILTERCAPS_LINEAR; + + D3DDEVICEDESC helDesc = {}; + + EnumDevice(cb, ctx, "SDL3 GPU HAL", &halDesc, &helDesc, SDL3_GPU_GUID); } diff --git a/miniwin/src/internal/d3drmrenderer_software.h b/miniwin/src/internal/d3drmrenderer_software.h index 444a80a3..0c422597 100644 --- a/miniwin/src/internal/d3drmrenderer_software.h +++ b/miniwin/src/internal/d3drmrenderer_software.h @@ -29,12 +29,10 @@ class Direct3DRMSoftwareRenderer : public Direct3DRMRenderer { Direct3DRMSoftwareRenderer(DWORD width, DWORD height); ~Direct3DRMSoftwareRenderer() override; void PushLights(const SceneLight* vertices, size_t count) override; - Uint32 GetTextureId(IDirect3DRMTexture* texture) 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; - void GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc) override; - const char* GetName() override; HRESULT BeginFrame() override; void EnableTransparency() override; void SubmitDraw( @@ -49,8 +47,9 @@ class Direct3DRMSoftwareRenderer : public Direct3DRMRenderer { void Resize(int width, int height, const ViewportTransform& viewportTransform) override; void Clear(float r, float g, float b) override; void Flip() override; - void Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, const SDL_Rect& dstRect) override; + void Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, const SDL_Rect& dstRect, FColor color) override; void Download(SDL_Surface* target) override; + void SetDither(bool dither) override; private: void ClearZBuffer(); @@ -87,8 +86,16 @@ class Direct3DRMSoftwareRenderer : public Direct3DRMRenderer { inline static void Direct3DRMSoftware_EnumDevice(LPD3DENUMDEVICESCALLBACK cb, void* ctx) { - Direct3DRMRenderer* device = nullptr; - device = new Direct3DRMSoftwareRenderer(640, 480); - EnumDevice(cb, ctx, device, SOFTWARE_GUID); - delete device; + D3DDEVICEDESC halDesc = {}; + + D3DDEVICEDESC helDesc = {}; + helDesc.dcmColorModel = D3DCOLOR_RGB; + helDesc.dwFlags = D3DDD_DEVICEZBUFFERBITDEPTH; + helDesc.dwDeviceZBufferBitDepth = DDBD_32; + helDesc.dwDeviceRenderBitDepth = DDBD_32; + helDesc.dpcTriCaps.dwTextureCaps = D3DPTEXTURECAPS_PERSPECTIVE; + helDesc.dpcTriCaps.dwShadeCaps = D3DPSHADECAPS_ALPHAFLATBLEND; + helDesc.dpcTriCaps.dwTextureFilterCaps = D3DPTFILTERCAPS_LINEAR; + + EnumDevice(cb, ctx, "Miniwin Emulation", &halDesc, &helDesc, SOFTWARE_GUID); } diff --git a/miniwin/src/internal/ddraw_impl.h b/miniwin/src/internal/ddraw_impl.h index f2604946..0da2d883 100644 --- a/miniwin/src/internal/ddraw_impl.h +++ b/miniwin/src/internal/ddraw_impl.h @@ -4,6 +4,7 @@ #include "framebuffer_impl.h" #include "miniwin/d3d.h" #include "miniwin/ddraw.h" +#include "miniwin/miniwind3d.h" #include @@ -15,7 +16,7 @@ inline static SDL_Rect ConvertRect(const RECT* r) return {r->left, r->top, r->right - r->left, r->bottom - r->top}; } -struct DirectDrawImpl : public IDirectDraw2, public IDirect3D2 { +struct DirectDrawImpl : public IDirectDraw2, public IDirect3D2, public IDirect3DMiniwin { // IUnknown interface HRESULT QueryInterface(const GUID& riid, void** ppvObject) override; // IDirectDraw interface @@ -45,15 +46,37 @@ struct DirectDrawImpl : public IDirectDraw2, public IDirect3D2 { HRESULT CreateDevice(const GUID& guid, IDirectDrawSurface* pBackBuffer, IDirect3DDevice2** ppDirect3DDevice) override; HRESULT EnumDevices(LPD3DENUMDEVICESCALLBACK cb, void* ctx) override; + // IDirect3DMiniwin interface + HRESULT RequestMSAA(DWORD msaaSamples) override + { + m_msaaSamples = msaaSamples; + return DD_OK; + } + DWORD GetMSAASamples() const override { return m_msaaSamples; } + HRESULT RequestAnisotropic(float anisotropic) override + { + m_anisotropic = anisotropic; + return DD_OK; + } + float GetAnisotropic() const override { return m_anisotropic; } private: FrameBufferImpl* m_frameBuffer; int m_virtualWidth = 0; int m_virtualHeight = 0; + DWORD m_msaaSamples = 0; + float m_anisotropic = 0.0f; }; HRESULT DirectDrawEnumerate(LPDDENUMCALLBACKA cb, void* context); HRESULT DirectDrawCreate(LPGUID lpGuid, LPDIRECTDRAW* lplpDD, IUnknown* pUnkOuter); -void EnumDevice(LPD3DENUMDEVICESCALLBACK cb, void* ctx, Direct3DRMRenderer* device, GUID deviceGuid); +void EnumDevice( + LPD3DENUMDEVICESCALLBACK cb, + void* ctx, + const char* name, + D3DDEVICEDESC* halDesc, + D3DDEVICEDESC* helDesc, + GUID deviceGuid +); diff --git a/miniwin/src/internal/framebuffer_impl.h b/miniwin/src/internal/framebuffer_impl.h index 5e40f7e8..47805e69 100644 --- a/miniwin/src/internal/framebuffer_impl.h +++ b/miniwin/src/internal/framebuffer_impl.h @@ -39,6 +39,7 @@ struct FrameBufferImpl : public IDirectDrawSurface3 { private: uint32_t m_virtualWidth; uint32_t m_virtualHeight; + bool m_readOnlyLock; DirectDrawSurfaceImpl* m_transferBuffer; IDirectDrawPalette* m_palette = nullptr; }; diff --git a/miniwin/src/internal/meshutils.cpp b/miniwin/src/internal/meshutils.cpp index 818ecd87..e0ce59e6 100644 --- a/miniwin/src/internal/meshutils.cpp +++ b/miniwin/src/internal/meshutils.cpp @@ -75,3 +75,31 @@ void FlattenSurfaces( } } } + +void Create2DTransformMatrix( + const SDL_Rect& dstRect, + float scale, + float offsetX, + float offsetY, + D3DRMMATRIX4D& outMatrix +) +{ + float x = static_cast(dstRect.x) * scale + offsetX; + float y = static_cast(dstRect.y) * scale + offsetY; + float w = static_cast(dstRect.w) * scale; + float h = static_cast(dstRect.h) * scale; + + D3DVALUE tmp[4][4] = {{w, 0, 0, 0}, {0, h, 0, 0}, {0, 0, 1, 0}, {x, y, 0, 1}}; + memcpy(outMatrix, tmp, sizeof(tmp)); +} + +void CreateOrthographicProjection(float width, float height, D3DRMMATRIX4D& outProj) +{ + D3DVALUE tmp[4][4] = { + {2.0f / width, 0.0f, 0.0f, 0.0f}, + {0.0f, -2.0f / height, 0.0f, 0.0f}, + {0.0f, 0.0f, 1.0f, 0.0f}, + {-1.0f, 1.0f, 0.0f, 1.0f} + }; + memcpy(outProj, tmp, sizeof(tmp)); +} diff --git a/miniwin/src/internal/meshutils.h b/miniwin/src/internal/meshutils.h index fb12a145..12c509ad 100644 --- a/miniwin/src/internal/meshutils.h +++ b/miniwin/src/internal/meshutils.h @@ -13,3 +13,13 @@ void FlattenSurfaces( std::vector& dedupedVertices, std::vector& newIndices ); + +void Create2DTransformMatrix( + const SDL_Rect& dstRect, + float scale, + float offsetX, + float offsetY, + D3DRMMATRIX4D& outMatrix +); + +void CreateOrthographicProjection(float width, float height, D3DRMMATRIX4D& outProj); diff --git a/miniwin/src/windows/windows.cpp b/miniwin/src/windows/windows.cpp index 5e174b8a..0e8b53ed 100644 --- a/miniwin/src/windows/windows.cpp +++ b/miniwin/src/windows/windows.cpp @@ -83,72 +83,6 @@ BOOL RedrawWindow(void* hWnd, const void* lprcUpdate, void* hrgnUpdate, unsigned return 1; } -int SetBkColor(void*, int) -{ - MINIWIN_NOT_IMPLEMENTED(); - return 0; -} - -int SetBkMode(void*, int) -{ - MINIWIN_NOT_IMPLEMENTED(); - return 0; -} - -int SetTextColor(HDC hdc, int color) -{ - MINIWIN_NOT_IMPLEMENTED(); - return color; -} - -BOOL GetTextExtentPoint(HDC hdc, LPCSTR lpString, int c, SIZE* psizl) -{ - MINIWIN_NOT_IMPLEMENTED(); - if (psizl) { - psizl->cx = 8 * c; - psizl->cy = 16; - } - return TRUE; -} - -int ExtTextOut(HDC, int, int, unsigned int, const RECT*, LPCSTR, unsigned int, void*) -{ - MINIWIN_NOT_IMPLEMENTED(); - return 1; -} - -HFONT CreateFont( - int, - int, - int, - int, - int, - unsigned int, - unsigned int, - unsigned int, - unsigned int, - unsigned int, - unsigned int, - unsigned int, - unsigned int, - LPCSTR -) -{ - MINIWIN_NOT_IMPLEMENTED(); - return nullptr; -} - -void* SelectObject(HDC, HFONT) -{ - MINIWIN_NOT_IMPLEMENTED(); - return nullptr; -} - -int GetTextExtentPoint32(HDC hdc, LPCSTR str, int len, SIZE* out) -{ - return GetTextExtentPoint(hdc, str, len, out); -} - HMENU GetMenu(HWND hWnd) { return NULL; diff --git a/packaging/3ds/banner.png b/packaging/3ds/banner.png new file mode 100644 index 00000000..550b53ea Binary files /dev/null and b/packaging/3ds/banner.png differ diff --git a/packaging/3ds/banner.wav b/packaging/3ds/banner.wav new file mode 100644 index 00000000..8eeb79ba Binary files /dev/null and b/packaging/3ds/banner.wav differ diff --git a/packaging/3ds/icon.png b/packaging/3ds/icon.png new file mode 100644 index 00000000..8fd9f2c4 Binary files /dev/null and b/packaging/3ds/icon.png differ diff --git a/packaging/3ds/logo.bcma.lz b/packaging/3ds/logo.bcma.lz new file mode 100644 index 00000000..dd9db8cd Binary files /dev/null and b/packaging/3ds/logo.bcma.lz differ diff --git a/packaging/3ds/template.rsf b/packaging/3ds/template.rsf new file mode 100644 index 00000000..bbde6448 --- /dev/null +++ b/packaging/3ds/template.rsf @@ -0,0 +1,283 @@ +BasicInfo: + Title : "Lego Island" + ProductCode : "CTR-P-ISLE" + Logo : Homebrew + +TitleInfo: + Category : Application + UniqueId : 0x76E7E + +Option: + UseOnSD : true # true if App is to be installed to SD + FreeProductCode : true # Removes limitations on ProductCode + MediaFootPadding : false # If true CCI files are created with padding + EnableCrypt : false # Enables encryption for NCCH and CIA + EnableCompress : true # Compresses where applicable (currently only exefs:/.code) + +AccessControlInfo: + CoreVersion : 2 + + # Exheader Format Version + DescVersion : 2 + + # Minimum Required Kernel Version (below is for 4.5.0) + ReleaseKernelMajor : "02" + ReleaseKernelMinor : "33" + + # ExtData + UseExtSaveData : false # enables ExtData + #ExtSaveDataId : 0x300 # only set this when the ID is different to the UniqueId + + # FS:USER Archive Access Permissions + # Uncomment as required + FileSystemAccess: + #- CategorySystemApplication + #- CategoryHardwareCheck + #- CategoryFileSystemTool + #- Debug + #- TwlCardBackup + #- TwlNandData + #- Boss + - DirectSdmc + - Core + #- CtrNandRo + #- CtrNandRw + #- CtrNandRoWrite + #- CategorySystemSettings + #- CardBoard + #- ExportImportIvs + - DirectSdmcWrite + #- SwitchCleanup + #- SaveDataMove + #- Shop + #- Shell + #- CategoryHomeMenu + #- SeedDB + IoAccessControl: + #- FsMountNand + #- FsMountNandRoWrite + #- FsMountTwln + #- FsMountWnand + #- FsMountCardSpi + #- UseSdif3 + #- CreateSeed + #- UseCardSpi + + # Process Settings + MemoryType : Application # Application/System/Base + SystemMode : 64MB # 64MB(Default)/96MB/80MB/72MB/32MB + IdealProcessor : 0 + AffinityMask : 1 + Priority : 16 + MaxCpu : 0x9E # Default + HandleTableSize : 0x200 + DisableDebug : false + EnableForceDebug : false + CanWriteSharedPage : true + CanUsePrivilegedPriority : false + CanUseNonAlphabetAndNumber : true + PermitMainFunctionArgument : true + CanShareDeviceMemory : true + RunnableOnSleep : false + SpecialMemoryArrange : true + + # New3DS Exclusive Process Settings + SystemModeExt : Legacy # Legacy(Default)/124MB/178MB Legacy:Use Old3DS SystemMode + CpuSpeed : 804MHz # 268MHz(Default)/804MHz + EnableL2Cache : true # false(default)/true + CanAccessCore2 : true + + # Virtual Address Mappings + IORegisterMapping: + - 1ff00000-1ff7ffff # DSP memory + MemoryMapping: + - 1f000000-1f5fffff:r # VRAM + + # Accessible SVCs, : + SystemCallAccess: + ControlMemory: 1 + QueryMemory: 2 + ExitProcess: 3 + GetProcessAffinityMask: 4 + SetProcessAffinityMask: 5 + GetProcessIdealProcessor: 6 + SetProcessIdealProcessor: 7 + CreateThread: 8 + ExitThread: 9 + SleepThread: 10 + GetThreadPriority: 11 + SetThreadPriority: 12 + GetThreadAffinityMask: 13 + SetThreadAffinityMask: 14 + GetThreadIdealProcessor: 15 + SetThreadIdealProcessor: 16 + GetCurrentProcessorNumber: 17 + Run: 18 + CreateMutex: 19 + ReleaseMutex: 20 + CreateSemaphore: 21 + ReleaseSemaphore: 22 + CreateEvent: 23 + SignalEvent: 24 + ClearEvent: 25 + CreateTimer: 26 + SetTimer: 27 + CancelTimer: 28 + ClearTimer: 29 + CreateMemoryBlock: 30 + MapMemoryBlock: 31 + UnmapMemoryBlock: 32 + CreateAddressArbiter: 33 + ArbitrateAddress: 34 + CloseHandle: 35 + WaitSynchronization1: 36 + WaitSynchronizationN: 37 + SignalAndWait: 38 + DuplicateHandle: 39 + GetSystemTick: 40 + GetHandleInfo: 41 + GetSystemInfo: 42 + GetProcessInfo: 43 + GetThreadInfo: 44 + ConnectToPort: 45 + SendSyncRequest1: 46 + SendSyncRequest2: 47 + SendSyncRequest3: 48 + SendSyncRequest4: 49 + SendSyncRequest: 50 + OpenProcess: 51 + OpenThread: 52 + GetProcessId: 53 + GetProcessIdOfThread: 54 + GetThreadId: 55 + GetResourceLimit: 56 + GetResourceLimitLimitValues: 57 + GetResourceLimitCurrentValues: 58 + GetThreadContext: 59 + Break: 60 + OutputDebugString: 61 + ControlPerformanceCounter: 62 + CreatePort: 71 + CreateSessionToPort: 72 + CreateSession: 73 + AcceptSession: 74 + ReplyAndReceive1: 75 + ReplyAndReceive2: 76 + ReplyAndReceive3: 77 + ReplyAndReceive4: 78 + ReplyAndReceive: 79 + BindInterrupt: 80 + UnbindInterrupt: 81 + InvalidateProcessDataCache: 82 + StoreProcessDataCache: 83 + FlushProcessDataCache: 84 + StartInterProcessDma: 85 + StopDma: 86 + GetDmaState: 87 + RestartDma: 88 + DebugActiveProcess: 96 + BreakDebugProcess: 97 + TerminateDebugProcess: 98 + GetProcessDebugEvent: 99 + ContinueDebugEvent: 100 + GetProcessList: 101 + GetThreadList: 102 + GetDebugThreadContext: 103 + SetDebugThreadContext: 104 + QueryDebugProcessMemory: 105 + ReadProcessMemory: 106 + WriteProcessMemory: 107 + SetHardwareBreakPoint: 108 + GetDebugThreadParam: 109 + ControlProcessMemory: 112 + MapProcessMemory: 113 + UnmapProcessMemory: 114 + CreateCodeSet: 115 + CreateProcess: 117 + TerminateProcess: 118 + SetProcessResourceLimits: 119 + CreateResourceLimit: 120 + SetResourceLimitValues: 121 + AddCodeSegment: 122 + Backdoor: 123 + KernelSetState: 124 + QueryProcessMemory: 125 + + # Service List + # Maximum 34 services (32 if firmware is prior to 9.6.0) + ServiceAccessControl: + - APT:U + - ac:u + - am:net + - boss:U + - cam:u + - cecd:u + - cfg:nor + - cfg:u + - csnd:SND + - dsp::DSP + - frd:u + - fs:USER + - gsp::Gpu + - gsp::Lcd + - hid:USER + #- http:C + - ir:rst + - ir:u + - ir:USER + #- mic:u + - mcu::HWC + - ndm:u + - news:s + - nwm::EXT + - nwm::UDS + - ptm:sysm + - ptm:u + - pxi:dev + - soc:U + - ssl:C + - y2r:u + + +SystemControlInfo: + SaveDataSize: 0KB # Change if the app uses savedata + RemasterVersion: $(APP_VERSION_MAJOR) + StackSize: 0x40000 + + # Modules that run services listed above should be included below + # Maximum 48 dependencies + # : + Dependency: + ac: 0x0004013000002402 + #act: 0x0004013000003802 + am: 0x0004013000001502 + boss: 0x0004013000003402 + camera: 0x0004013000001602 + cecd: 0x0004013000002602 + cfg: 0x0004013000001702 + codec: 0x0004013000001802 + csnd: 0x0004013000002702 + dlp: 0x0004013000002802 + dsp: 0x0004013000001a02 + friends: 0x0004013000003202 + gpio: 0x0004013000001b02 + gsp: 0x0004013000001c02 + hid: 0x0004013000001d02 + #http: 0x0004013000002902 + i2c: 0x0004013000001e02 + ir: 0x0004013000003302 + mcu: 0x0004013000001f02 + #mic: 0x0004013000002002 + ndm: 0x0004013000002b02 + news: 0x0004013000003502 + #nfc: 0x0004013000004002 + nim: 0x0004013000002c02 + nwm: 0x0004013000002d02 + pdn: 0x0004013000002102 + ps: 0x0004013000003102 + ptm: 0x0004013000002202 + #qtm: 0x0004013020004202 + ro: 0x0004013000003702 + socket: 0x0004013000002e02 + spi: 0x0004013000002302 + ssl: 0x0004013000002f02 diff --git a/packaging/CMakeLists.txt b/packaging/CMakeLists.txt new file mode 100644 index 00000000..6f5769e9 --- /dev/null +++ b/packaging/CMakeLists.txt @@ -0,0 +1,34 @@ +set(APP_ID "org.legoisland.Isle") +set(APP_NAME "Isle Portable") +set(APP_SUMMARY "Portable version of the LEGO Island Decompilation Project") +set(APP_SPDX "LGPL-3.0-or-later") + +string(TIMESTAMP BUILD_DATE UTC) + +file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/icons) +file(COPY_FILE icons/isle.svg ${CMAKE_BINARY_DIR}/icons/${APP_ID}.svg) + +# The following will need to be refined if we wish to post actual releases to a repo such as Flathub +if(DEFINED ENV{GITHUB_ACTIONS} AND ENV{GITHUB_ACTIONS} EQUAL TRUE) + # Use the sequential run# of the current pipeline when running in GH Actions + set(SEMANTIC_VERSION "${PROJECT_VERSION}~build$ENV{GITHUB_RUN_NUMBER}") +else() + # Don't worry about the build number for local builds + set(SEMANTIC_VERSION "${PROJECT_VERSION}") +endif() + +if(LINUX) + add_subdirectory(linux) +endif() + +if(WINDOWS_STORE) + add_subdirectory(UWP) +endif() + +if(APPLE AND NOT IOS) + add_subdirectory(macos) +endif() + +if(IOS) + add_subdirectory(ios) +endif() diff --git a/packaging/UWP/CMakeLists.txt b/packaging/UWP/CMakeLists.txt new file mode 100644 index 00000000..95018c49 --- /dev/null +++ b/packaging/UWP/CMakeLists.txt @@ -0,0 +1,20 @@ +file(GLOB_RECURSE GENERATED_ASSETS + "assets/*" +) +set(ASSET_FILES ${GENERATED_ASSETS}) +set_source_files_properties(${ASSET_FILES} PROPERTIES + VS_DEPLOYMENT_CONTENT 1 + VS_DEPLOYMENT_LOCATION "assets" +) + +set(MANIFEST_FILE Package.appxmanifest) +set_source_files_properties(${MANIFEST_FILE} PROPERTIES + VS_DEPLOYMENT_CONTENT 1 +) + +set(SIGNING_KEY_FILE IslePortable.pfx) +set_source_files_properties(${SIGNING_KEY_FILE} PROPERTIES + VS_DEPLOYMENT_CONTENT 1 +) + +target_sources(isle PRIVATE ${ASSET_FILES} ${MANIFEST_FILE} ${SIGNING_KEY_FILE}) diff --git a/packaging/UWP/IslePortable.pfx b/packaging/UWP/IslePortable.pfx new file mode 100644 index 00000000..3b85ffca Binary files /dev/null and b/packaging/UWP/IslePortable.pfx differ diff --git a/packaging/UWP/Package.appxmanifest b/packaging/UWP/Package.appxmanifest new file mode 100644 index 00000000..1c75a7cf --- /dev/null +++ b/packaging/UWP/Package.appxmanifest @@ -0,0 +1,47 @@ + + + + + + LEGO® Island + isledecomp/isle-portable + StoreLogo.png + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/packaging/UWP/assets/LargeTile.scale-100.png b/packaging/UWP/assets/LargeTile.scale-100.png new file mode 100644 index 00000000..94b280c2 Binary files /dev/null and b/packaging/UWP/assets/LargeTile.scale-100.png differ diff --git a/packaging/UWP/assets/LargeTile.scale-125.png b/packaging/UWP/assets/LargeTile.scale-125.png new file mode 100644 index 00000000..e8531486 Binary files /dev/null and b/packaging/UWP/assets/LargeTile.scale-125.png differ diff --git a/packaging/UWP/assets/LargeTile.scale-150.png b/packaging/UWP/assets/LargeTile.scale-150.png new file mode 100644 index 00000000..b73fc6b5 Binary files /dev/null and b/packaging/UWP/assets/LargeTile.scale-150.png differ diff --git a/packaging/UWP/assets/LargeTile.scale-200.png b/packaging/UWP/assets/LargeTile.scale-200.png new file mode 100644 index 00000000..02300849 Binary files /dev/null and b/packaging/UWP/assets/LargeTile.scale-200.png differ diff --git a/packaging/UWP/assets/LargeTile.scale-400.png b/packaging/UWP/assets/LargeTile.scale-400.png new file mode 100644 index 00000000..e4475176 Binary files /dev/null and b/packaging/UWP/assets/LargeTile.scale-400.png differ diff --git a/packaging/UWP/assets/SplashScreen.scale-100.png b/packaging/UWP/assets/SplashScreen.scale-100.png new file mode 100644 index 00000000..ba958235 Binary files /dev/null and b/packaging/UWP/assets/SplashScreen.scale-100.png differ diff --git a/packaging/UWP/assets/SplashScreen.scale-125.png b/packaging/UWP/assets/SplashScreen.scale-125.png new file mode 100644 index 00000000..f63eb9e8 Binary files /dev/null and b/packaging/UWP/assets/SplashScreen.scale-125.png differ diff --git a/packaging/UWP/assets/SplashScreen.scale-150.png b/packaging/UWP/assets/SplashScreen.scale-150.png new file mode 100644 index 00000000..55097645 Binary files /dev/null and b/packaging/UWP/assets/SplashScreen.scale-150.png differ diff --git a/packaging/UWP/assets/SplashScreen.scale-200.png b/packaging/UWP/assets/SplashScreen.scale-200.png new file mode 100644 index 00000000..24263c24 Binary files /dev/null and b/packaging/UWP/assets/SplashScreen.scale-200.png differ diff --git a/packaging/UWP/assets/SplashScreen.scale-400.png b/packaging/UWP/assets/SplashScreen.scale-400.png new file mode 100644 index 00000000..f622b917 Binary files /dev/null and b/packaging/UWP/assets/SplashScreen.scale-400.png differ diff --git a/packaging/UWP/assets/Square150x150Logo.scale-100.png b/packaging/UWP/assets/Square150x150Logo.scale-100.png new file mode 100644 index 00000000..2bce23c5 Binary files /dev/null and b/packaging/UWP/assets/Square150x150Logo.scale-100.png differ diff --git a/packaging/UWP/assets/Square150x150Logo.scale-125.png b/packaging/UWP/assets/Square150x150Logo.scale-125.png new file mode 100644 index 00000000..906a3f48 Binary files /dev/null and b/packaging/UWP/assets/Square150x150Logo.scale-125.png differ diff --git a/packaging/UWP/assets/Square150x150Logo.scale-150.png b/packaging/UWP/assets/Square150x150Logo.scale-150.png new file mode 100644 index 00000000..10cd54dc Binary files /dev/null and b/packaging/UWP/assets/Square150x150Logo.scale-150.png differ diff --git a/packaging/UWP/assets/Square150x150Logo.scale-200.png b/packaging/UWP/assets/Square150x150Logo.scale-200.png new file mode 100644 index 00000000..f214f06e Binary files /dev/null and b/packaging/UWP/assets/Square150x150Logo.scale-200.png differ diff --git a/packaging/UWP/assets/Square150x150Logo.scale-400.png b/packaging/UWP/assets/Square150x150Logo.scale-400.png new file mode 100644 index 00000000..7660b6a4 Binary files /dev/null and b/packaging/UWP/assets/Square150x150Logo.scale-400.png differ diff --git a/packaging/UWP/assets/Square44x44Logo.altform-lightunplated_targetsize-16.png b/packaging/UWP/assets/Square44x44Logo.altform-lightunplated_targetsize-16.png new file mode 100644 index 00000000..44ba1861 Binary files /dev/null and b/packaging/UWP/assets/Square44x44Logo.altform-lightunplated_targetsize-16.png differ diff --git a/packaging/UWP/assets/Square44x44Logo.altform-lightunplated_targetsize-24.png b/packaging/UWP/assets/Square44x44Logo.altform-lightunplated_targetsize-24.png new file mode 100644 index 00000000..c7d0d5c6 Binary files /dev/null and b/packaging/UWP/assets/Square44x44Logo.altform-lightunplated_targetsize-24.png differ diff --git a/packaging/UWP/assets/Square44x44Logo.altform-lightunplated_targetsize-256.png b/packaging/UWP/assets/Square44x44Logo.altform-lightunplated_targetsize-256.png new file mode 100644 index 00000000..05e20da7 Binary files /dev/null and b/packaging/UWP/assets/Square44x44Logo.altform-lightunplated_targetsize-256.png differ diff --git a/packaging/UWP/assets/Square44x44Logo.altform-lightunplated_targetsize-32.png b/packaging/UWP/assets/Square44x44Logo.altform-lightunplated_targetsize-32.png new file mode 100644 index 00000000..34f380b7 Binary files /dev/null and b/packaging/UWP/assets/Square44x44Logo.altform-lightunplated_targetsize-32.png differ diff --git a/packaging/UWP/assets/Square44x44Logo.altform-lightunplated_targetsize-48.png b/packaging/UWP/assets/Square44x44Logo.altform-lightunplated_targetsize-48.png new file mode 100644 index 00000000..4ca0928a Binary files /dev/null and b/packaging/UWP/assets/Square44x44Logo.altform-lightunplated_targetsize-48.png differ diff --git a/packaging/UWP/assets/Square44x44Logo.altform-unplated_targetsize-16.png b/packaging/UWP/assets/Square44x44Logo.altform-unplated_targetsize-16.png new file mode 100644 index 00000000..44ba1861 Binary files /dev/null and b/packaging/UWP/assets/Square44x44Logo.altform-unplated_targetsize-16.png differ diff --git a/packaging/UWP/assets/Square44x44Logo.altform-unplated_targetsize-24.png b/packaging/UWP/assets/Square44x44Logo.altform-unplated_targetsize-24.png new file mode 100644 index 00000000..c7d0d5c6 Binary files /dev/null and b/packaging/UWP/assets/Square44x44Logo.altform-unplated_targetsize-24.png differ diff --git a/packaging/UWP/assets/Square44x44Logo.altform-unplated_targetsize-256.png b/packaging/UWP/assets/Square44x44Logo.altform-unplated_targetsize-256.png new file mode 100644 index 00000000..05e20da7 Binary files /dev/null and b/packaging/UWP/assets/Square44x44Logo.altform-unplated_targetsize-256.png differ diff --git a/packaging/UWP/assets/Square44x44Logo.altform-unplated_targetsize-32.png b/packaging/UWP/assets/Square44x44Logo.altform-unplated_targetsize-32.png new file mode 100644 index 00000000..34f380b7 Binary files /dev/null and b/packaging/UWP/assets/Square44x44Logo.altform-unplated_targetsize-32.png differ diff --git a/packaging/UWP/assets/Square44x44Logo.altform-unplated_targetsize-48.png b/packaging/UWP/assets/Square44x44Logo.altform-unplated_targetsize-48.png new file mode 100644 index 00000000..4ca0928a Binary files /dev/null and b/packaging/UWP/assets/Square44x44Logo.altform-unplated_targetsize-48.png differ diff --git a/packaging/UWP/assets/Square44x44Logo.scale-100.png b/packaging/UWP/assets/Square44x44Logo.scale-100.png new file mode 100644 index 00000000..27cc2d3f Binary files /dev/null and b/packaging/UWP/assets/Square44x44Logo.scale-100.png differ diff --git a/packaging/UWP/assets/Square44x44Logo.scale-125.png b/packaging/UWP/assets/Square44x44Logo.scale-125.png new file mode 100644 index 00000000..2d569be1 Binary files /dev/null and b/packaging/UWP/assets/Square44x44Logo.scale-125.png differ diff --git a/packaging/UWP/assets/Square44x44Logo.scale-150.png b/packaging/UWP/assets/Square44x44Logo.scale-150.png new file mode 100644 index 00000000..8f5e6d9e Binary files /dev/null and b/packaging/UWP/assets/Square44x44Logo.scale-150.png differ diff --git a/packaging/UWP/assets/Square44x44Logo.scale-200.png b/packaging/UWP/assets/Square44x44Logo.scale-200.png new file mode 100644 index 00000000..5af98b83 Binary files /dev/null and b/packaging/UWP/assets/Square44x44Logo.scale-200.png differ diff --git a/packaging/UWP/assets/Square44x44Logo.scale-400.png b/packaging/UWP/assets/Square44x44Logo.scale-400.png new file mode 100644 index 00000000..5c7d9c85 Binary files /dev/null and b/packaging/UWP/assets/Square44x44Logo.scale-400.png differ diff --git a/packaging/UWP/assets/Square44x44Logo.targetsize-16.png b/packaging/UWP/assets/Square44x44Logo.targetsize-16.png new file mode 100644 index 00000000..36115ab1 Binary files /dev/null and b/packaging/UWP/assets/Square44x44Logo.targetsize-16.png differ diff --git a/packaging/UWP/assets/Square44x44Logo.targetsize-24.png b/packaging/UWP/assets/Square44x44Logo.targetsize-24.png new file mode 100644 index 00000000..24711949 Binary files /dev/null and b/packaging/UWP/assets/Square44x44Logo.targetsize-24.png differ diff --git a/packaging/UWP/assets/Square44x44Logo.targetsize-256.png b/packaging/UWP/assets/Square44x44Logo.targetsize-256.png new file mode 100644 index 00000000..e93cd58d Binary files /dev/null and b/packaging/UWP/assets/Square44x44Logo.targetsize-256.png differ diff --git a/packaging/UWP/assets/Square44x44Logo.targetsize-32.png b/packaging/UWP/assets/Square44x44Logo.targetsize-32.png new file mode 100644 index 00000000..ca116b92 Binary files /dev/null and b/packaging/UWP/assets/Square44x44Logo.targetsize-32.png differ diff --git a/packaging/UWP/assets/Square44x44Logo.targetsize-48.png b/packaging/UWP/assets/Square44x44Logo.targetsize-48.png new file mode 100644 index 00000000..1cc66b30 Binary files /dev/null and b/packaging/UWP/assets/Square44x44Logo.targetsize-48.png differ diff --git a/packaging/UWP/assets/Square71x71Logo.scale-100.png b/packaging/UWP/assets/Square71x71Logo.scale-100.png new file mode 100644 index 00000000..7eb2beda Binary files /dev/null and b/packaging/UWP/assets/Square71x71Logo.scale-100.png differ diff --git a/packaging/UWP/assets/Square71x71Logo.scale-125.png b/packaging/UWP/assets/Square71x71Logo.scale-125.png new file mode 100644 index 00000000..076c0703 Binary files /dev/null and b/packaging/UWP/assets/Square71x71Logo.scale-125.png differ diff --git a/packaging/UWP/assets/Square71x71Logo.scale-150.png b/packaging/UWP/assets/Square71x71Logo.scale-150.png new file mode 100644 index 00000000..578ec72d Binary files /dev/null and b/packaging/UWP/assets/Square71x71Logo.scale-150.png differ diff --git a/packaging/UWP/assets/Square71x71Logo.scale-200.png b/packaging/UWP/assets/Square71x71Logo.scale-200.png new file mode 100644 index 00000000..3805d16b Binary files /dev/null and b/packaging/UWP/assets/Square71x71Logo.scale-200.png differ diff --git a/packaging/UWP/assets/Square71x71Logo.scale-400.png b/packaging/UWP/assets/Square71x71Logo.scale-400.png new file mode 100644 index 00000000..020b9307 Binary files /dev/null and b/packaging/UWP/assets/Square71x71Logo.scale-400.png differ diff --git a/packaging/UWP/assets/StoreLogo.scale-100.png b/packaging/UWP/assets/StoreLogo.scale-100.png new file mode 100644 index 00000000..f05b2723 Binary files /dev/null and b/packaging/UWP/assets/StoreLogo.scale-100.png differ diff --git a/packaging/UWP/assets/StoreLogo.scale-125.png b/packaging/UWP/assets/StoreLogo.scale-125.png new file mode 100644 index 00000000..24dcfe05 Binary files /dev/null and b/packaging/UWP/assets/StoreLogo.scale-125.png differ diff --git a/packaging/UWP/assets/StoreLogo.scale-150.png b/packaging/UWP/assets/StoreLogo.scale-150.png new file mode 100644 index 00000000..db730a31 Binary files /dev/null and b/packaging/UWP/assets/StoreLogo.scale-150.png differ diff --git a/packaging/UWP/assets/StoreLogo.scale-200.png b/packaging/UWP/assets/StoreLogo.scale-200.png new file mode 100644 index 00000000..d9f30bf4 Binary files /dev/null and b/packaging/UWP/assets/StoreLogo.scale-200.png differ diff --git a/packaging/UWP/assets/StoreLogo.scale-400.png b/packaging/UWP/assets/StoreLogo.scale-400.png new file mode 100644 index 00000000..ff288809 Binary files /dev/null and b/packaging/UWP/assets/StoreLogo.scale-400.png differ diff --git a/packaging/UWP/assets/Wide310x150Logo.scale-100.png b/packaging/UWP/assets/Wide310x150Logo.scale-100.png new file mode 100644 index 00000000..82e3a2e6 Binary files /dev/null and b/packaging/UWP/assets/Wide310x150Logo.scale-100.png differ diff --git a/packaging/UWP/assets/Wide310x150Logo.scale-125.png b/packaging/UWP/assets/Wide310x150Logo.scale-125.png new file mode 100644 index 00000000..4a3315fc Binary files /dev/null and b/packaging/UWP/assets/Wide310x150Logo.scale-125.png differ diff --git a/packaging/UWP/assets/Wide310x150Logo.scale-150.png b/packaging/UWP/assets/Wide310x150Logo.scale-150.png new file mode 100644 index 00000000..d358c60d Binary files /dev/null and b/packaging/UWP/assets/Wide310x150Logo.scale-150.png differ diff --git a/packaging/UWP/assets/Wide310x150Logo.scale-200.png b/packaging/UWP/assets/Wide310x150Logo.scale-200.png new file mode 100644 index 00000000..ba958235 Binary files /dev/null and b/packaging/UWP/assets/Wide310x150Logo.scale-200.png differ diff --git a/packaging/UWP/assets/Wide310x150Logo.scale-400.png b/packaging/UWP/assets/Wide310x150Logo.scale-400.png new file mode 100644 index 00000000..24263c24 Binary files /dev/null and b/packaging/UWP/assets/Wide310x150Logo.scale-400.png differ diff --git a/packaging/icons/isle.svg b/packaging/icons/isle.svg new file mode 100644 index 00000000..d3f6dbf1 --- /dev/null +++ b/packaging/icons/isle.svg @@ -0,0 +1,161 @@ + + + +LEGO Island IconLEGO Island Icon2025-06-22 diff --git a/packaging/ios/CMakeLists.txt b/packaging/ios/CMakeLists.txt new file mode 100644 index 00000000..418ad518 --- /dev/null +++ b/packaging/ios/CMakeLists.txt @@ -0,0 +1,52 @@ +set(MACOSX_BUNDLE_GUI_IDENTIFIER ${APP_ID}) +set(MACOSX_BUNDLE_COPYRIGHT ${APP_SPDX}) +set(ISLE_TARGET_NAME isle) +set(MACOSX_ISLE_BUNDLE_NAME ${APP_NAME}) # Do note that it can be up to 15 characters long +set(MACOSX_ISLE_BUNDLE_DISPLAY_NAME ${APP_NAME}) +set(MACOSX_BUNDLE_INFO_STRING ${PROJECT_VERSION}) +set(MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}) +set(MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION}) +set(MACOSX_BUNDLE_LONG_VERSION_STRING "Version ${PROJECT_VERSION}") +set(MACOSX_BUNDLE_REQUIRED_PLATFORM IPhoneOS) + +if(ISLE_BUILD_APP) + configure_file( + "${CMAKE_CURRENT_SOURCE_DIR}/isle/Info.plist.in" + "${CMAKE_CURRENT_BINARY_DIR}/isle/Info.plist" + @ONLY + ) + set(RESOURCE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/isle/LaunchScreen.storyboard" "${CMAKE_CURRENT_SOURCE_DIR}/isle/Assets.xcassets") + target_sources(${ISLE_TARGET_NAME} PRIVATE ${RESOURCE_FILES}) + set_source_files_properties(${RESOURCE_FILES} + TARGET_DIRECTORY isle + PROPERTIES MACOSX_PACKAGE_LOCATION Resources) + set_target_properties(${ISLE_TARGET_NAME} PROPERTIES + MACOSX_BUNDLE TRUE + MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_BINARY_DIR}/isle/Info.plist" + XCODE_ATTRIBUTE_ASSETCATALOG_COMPILER_APPICON_NAME "AppIcon" + XCODE_ATTRIBUTE_TARGETED_DEVICE_FAMILY "1,2") + install(TARGETS ${ISLE_TARGET_NAME} DESTINATION ./) + install(CODE " + file(COPY + \"\$\" + \"\$\" + DESTINATION \"\$\{CMAKE_INSTALL_PREFIX\}/${ISLE_TARGET_NAME}.app/Frameworks\") + execute_process(COMMAND /usr/bin/install_name_tool + -add_rpath @executable_path/Frameworks + \"\$\{CMAKE_INSTALL_PREFIX\}/${ISLE_TARGET_NAME}.app/${ISLE_TARGET_NAME}\" + ) + file(MAKE_DIRECTORY + \"\$\{CMAKE_INSTALL_PREFIX\}/Payload\") + file(RENAME + \"\$\{CMAKE_INSTALL_PREFIX\}/${ISLE_TARGET_NAME}.app\" + \"\$\{CMAKE_INSTALL_PREFIX\}/Payload/${ISLE_TARGET_NAME}.app\") + ") +endif() + +install(CODE " + if(IS_DIRECTORY \"\$\{CMAKE_INSTALL_PREFIX\}/bin\" OR IS_DIRECTORY \"\$\{CMAKE_INSTALL_PREFIX\}/lib\" OR EXISTS \"\$\{CMAKE_INSTALL_PREFIX\}/AppIcon.icns\") + execute_process(COMMAND /bin/rm + -rf \"\$\{CMAKE_INSTALL_PREFIX\}/bin\" \"\$\{CMAKE_INSTALL_PREFIX\}/lib\" \"\$\{CMAKE_INSTALL_PREFIX\}/AppIcon.icns\" + ) + endif() +") diff --git a/packaging/ios/isle/Assets.xcassets/AppIcon.appiconset/AppIcon.png b/packaging/ios/isle/Assets.xcassets/AppIcon.appiconset/AppIcon.png new file mode 100644 index 00000000..f51e7069 Binary files /dev/null and b/packaging/ios/isle/Assets.xcassets/AppIcon.appiconset/AppIcon.png differ diff --git a/packaging/ios/isle/Assets.xcassets/AppIcon.appiconset/Contents.json b/packaging/ios/isle/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000..ce8e776e --- /dev/null +++ b/packaging/ios/isle/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,36 @@ +{ + "images" : [ + { + "filename" : "AppIcon.png", + "idiom" : "universal", + "platform" : "ios", + "size" : "1024x1024" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "idiom" : "universal", + "platform" : "ios", + "size" : "1024x1024" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "tinted" + } + ], + "idiom" : "universal", + "platform" : "ios", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/packaging/ios/isle/Assets.xcassets/Contents.json b/packaging/ios/isle/Assets.xcassets/Contents.json new file mode 100644 index 00000000..73c00596 --- /dev/null +++ b/packaging/ios/isle/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/packaging/ios/isle/Info.plist.in b/packaging/ios/isle/Info.plist.in new file mode 100644 index 00000000..714324a3 --- /dev/null +++ b/packaging/ios/isle/Info.plist.in @@ -0,0 +1,86 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${MACOSX_BUNDLE_EXECUTABLE_NAME} + CFBundleGetInfoString + @MACOSX_BUNDLE_INFO_STRING@ + CFBundleIdentifier + @MACOSX_BUNDLE_GUI_IDENTIFIER@ + CFBundleInfoDictionaryVersion + 6.0 + CFBundleLongVersionString + @MACOSX_BUNDLE_LONG_VERSION_STRING@ + CFBundleName + @MACOSX_ISLE_BUNDLE_NAME@ + CFBundleDisplayName + @MACOSX_ISLE_BUNDLE_DISPLAY_NAME@ + CFBundlePackageType + APPL + CFBundleShortVersionString + @MACOSX_BUNDLE_SHORT_VERSION_STRING@ + CFBundleSignature + ???? + CFBundleVersion + @MACOSX_BUNDLE_BUNDLE_VERSION@ + UILaunchStoryboardName + LaunchScreen + NSHighResolutionCapable + + CSResourcesFileMapped + + LSRequires@MACOSX_BUNDLE_REQUIRED_PLATFORM@ + + NSHumanReadableCopyright + @MACOSX_BUNDLE_COPYRIGHT@ + SDL_FILESYSTEM_BASE_DIR_TYPE + resource + NSSupportsAutomaticGraphicsSwitching + + UIApplicationSupportsIndirectInputEvents + + LSSupportsOpeningDocumentsInPlace + + UIFileSharingEnabled + + CADisableMinimumFrameDurationOnPhone + + UIDeviceFamily + + 1 + 2 + + UIRequiresFullScreen + + UIStatusBarHidden + + UISupportedInterfaceOrientations + + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + + CFBundleAllowMixedLocalizations + + LSApplicationCategoryType + public.app-category.games + DTPlatformName + iphoneos + UIFileSharingEnabled + + LSSupportsOpeningDocumentsInPlace + + + \ No newline at end of file diff --git a/packaging/ios/isle/LaunchScreen.storyboard b/packaging/ios/isle/LaunchScreen.storyboard new file mode 100644 index 00000000..ad167a8a --- /dev/null +++ b/packaging/ios/isle/LaunchScreen.storyboard @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packaging/linux/CMakeLists.txt b/packaging/linux/CMakeLists.txt new file mode 100644 index 00000000..2ece9db8 --- /dev/null +++ b/packaging/linux/CMakeLists.txt @@ -0,0 +1,7 @@ +# Injects the required variables into the Desktop and MetaInfo files +configure_file(isledecomp.desktop.in "${APP_ID}.desktop" @ONLY) +configure_file(isledecomp.metainfo.xml.in "${APP_ID}.metainfo.xml" @ONLY) + +install(FILES "../icons/isle.svg" RENAME "${APP_ID}.svg" DESTINATION "share/icons/hicolor/scalable/apps") +install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${APP_ID}.desktop" DESTINATION "share/applications") +install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${APP_ID}.metainfo.xml" DESTINATION "share/metainfo") diff --git a/packaging/linux/appimage/AppRun b/packaging/linux/appimage/AppRun new file mode 100755 index 00000000..0da15db1 --- /dev/null +++ b/packaging/linux/appimage/AppRun @@ -0,0 +1,25 @@ +#!/bin/sh + +HERE="$(dirname "$(readlink -f "${0}")")" + +MAIN=$(grep -r "^Exec=.*" "$HERE"/*.desktop | head -n 1 | cut -d "=" -f 2 | cut -d " " -f 1) + +# MAIN_BIN=$(find "$HERE/usr/bin" -name "$MAIN" | head -n 1) +MAIN_BIN="$HERE/usr/bin/isle-config" + +export PATH="${HERE}/usr/bin/":$PATH # Prefer bundled binaries + +export QT_QPA_PLATFORMTHEME=xdgdesktopportal # Use XDG filepicker for forward compatability +[ -z "$QT_PLUGIN_PATH" ] && export QT_PLUGIN_PATH=/usr/lib/qt6/plugins:/usr/lib64/qt6/plugins # Use system Qt theme, will fallback to the default one if unavailable + + +if [ ! -z $APPIMAGE ]; then + BINARY_NAME=$(basename "$ARGV0") + if [ -e "$HERE/usr/bin/$BINARY_NAME" ]; then + exec "$HERE/usr/bin/$BINARY_NAME" "$@" + else + exec "${MAIN_BIN}" "$@" + fi +else + exec "${MAIN_BIN}" "$@" +fi diff --git a/packaging/linux/appimage/Build b/packaging/linux/appimage/Build new file mode 100755 index 00000000..9cf0325c --- /dev/null +++ b/packaging/linux/appimage/Build @@ -0,0 +1,100 @@ +#!/usr/bin/env bash +set -e + +export LD_LIBRARY_PATH="build/source/lib:$LD_LIBRARY_PATH" +[ -z "$QMAKE" ] && export QMAKE=/usr/lib/qt6/bin/qmake + +# Sets a directory that has to have a following structure: +# build +# ├── bin +# │   ├── isle +# │   └── isle-config +# └── lib +# ├── liblego1.so +# ├── libSDL3.so -> libSDL3.so.0 # Not important if available on the system +# ├── libSDL3.so.0 -> libSDL3.so.0.3.0 # Not important if available on the system +# └── libSDL3.so.0.3.0 # Not important if available on the system +# Can also be defined using --build=path +BUILD_SOURCE=source + +# Sets where AppRun for AppImage is, can also be defined using --apprun=path +APPRUN_SOURCE=AppRun + +# Sets where desktop file for AppImage is, can also be defined using --desktop-file=path +DESKTOP_FILE_SOURCE=isledecomp.desktop + +# You know the drill +ICON_SOURCE=../../icons/isle.svg + +cd $(dirname $0) + +clean(){ + echo "Deleting build directory" + rm -rf build +} + +download(){ + if [ ! -e "$1" ]; then + curl -Lo "$1" "$2" + fi +} + +prepare(){ + mkdir -p build/tools + mkdir -p build/assets + + download build/tools/appimagetool.AppImage https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-$(uname -m).AppImage + chmod u+x build/tools/appimagetool.AppImage + + download build/tools/linuxdeploy.AppImage https://github.com/linuxdeploy/linuxdeploy/releases/latest/download/linuxdeploy-$(uname -m).AppImage + chmod u+x build/tools/linuxdeploy.AppImage + + download build/tools/linuxdeploy-plugin-qt.AppImage https://github.com/linuxdeploy/linuxdeploy-plugin-qt/releases/latest/download/linuxdeploy-plugin-qt-$(uname -m).AppImage + chmod u+x build/tools/linuxdeploy-plugin-qt.AppImage + + if [ ! -f "build/assets/isledecomp.desktop" ]; then + cp $DESKTOP_FILE_SOURCE build/assets/isledecomp.desktop + cp $APPRUN_SOURCE build/assets/AppRun + cp ../../icons/isle.svg build/assets/isle.svg + fi + + if [ ! -d "build/source" ]; then + cp -r $BUILD_SOURCE build/source + fi +} + +compile(){ + NO_STRIP=1 build/tools/linuxdeploy.AppImage \ + --plugin qt \ + -e build/source/bin/isle \ + -e build/source/bin/isle-config \ + -d build/assets/isledecomp.desktop \ + -i build/assets/isle.svg \ + --custom-apprun=AppRun \ + --appdir=build/AppDir +} + +package(){ + build/tools/appimagetool.AppImage build/AppDir build/"LEGO_Island-$(uname -m).AppImage" +} + +stop(){ # Can be used to do `Build clean stop` to just clean the directory + exit +} + +for arg in "$@"; do + case "$arg" in + --build=*) BUILD_SOURCE="${arg#--build=}";; + --apprun=*) APPRUN_SOURCE="${arg#--apprun=}";; + --desktop-file=*) DESKTOP_FILE_SOURCE="${arg#--desktop-file=}";; + --icon=*) ICON_SOURCE="${arg#--icon=}";; + *) "$arg" + esac +done + +prepare +compile +package +# Symlinks named as binaries in appimage can call these binaries specifically +# ln -s "LEGO_Island-$(uname -m).AppImage" isle-config +# ln -s "LEGO_Island-$(uname -m).AppImage" isle \ No newline at end of file diff --git a/packaging/linux/flatpak/org.legoisland.Isle.json b/packaging/linux/flatpak/org.legoisland.Isle.json new file mode 100644 index 00000000..229ba424 --- /dev/null +++ b/packaging/linux/flatpak/org.legoisland.Isle.json @@ -0,0 +1,85 @@ +{ + "id": "org.legoisland.Isle", + "runtime": "org.kde.Platform", + "sdk": "org.kde.Sdk", + "runtime-version": "6.8", + "command": "isle", + "finish-args": [ + "--share=ipc", + "--socket=wayland", + "--socket=fallback-x11", + "--socket=pulseaudio", + "--device=dri", + "--device=input", + "--filesystem=/run/media/:ro", + "--filesystem=/media/:ro", + "--filesystem=/mnt/:ro", + "--filesystem=home:ro" + ], + "modules": [ + { + "name": "isle", + "buildsystem": "cmake-ninja", + "config-opts": [ + "-DCMAKE_BUILD_TYPE=RelWithDebInfo", + "-DISLE_DEBUG=OFF" + ], + "sources": [ + { + "type": "dir", + "path": "../../../3rdparty", + "dest": "3rdparty/" + }, + { + "type": "dir", + "path": "../../../CMake", + "dest": "CMake/" + }, + { + "type": "dir", + "path": "../../../CONFIG", + "dest": "CONFIG/" + }, + { + "type": "dir", + "path": "../../../ISLE", + "dest": "ISLE/" + }, + { + "type": "dir", + "path": "../../../LEGO1", + "dest": "LEGO1/" + }, + { + "type": "dir", + "path": "../../../miniwin", + "dest": "miniwin/" + }, + { + "type": "dir", + "path": "../../../extensions", + "dest": "extensions/" + }, + { + "type": "dir", + "path": "../../../packaging", + "dest": "packaging/" + }, + { + "type": "dir", + "path": "../../../util", + "dest": "util/" + }, + { + "type": "file", + "path": "../../../CMakeLists.txt" + } + ], + "build-options": { + "build-args": [ + "--share=network" + ] + } + } + ] +} \ No newline at end of file diff --git a/packaging/linux/isledecomp.desktop.in b/packaging/linux/isledecomp.desktop.in new file mode 100644 index 00000000..3bb0a870 --- /dev/null +++ b/packaging/linux/isledecomp.desktop.in @@ -0,0 +1,39 @@ +[Desktop Entry] +Version=1.5 + +Name=@APP_NAME@ +Comment=@APP_SUMMARY@ + +Icon=@APP_ID@ +Type=Application +Categories=Game;KidsGame;AdventureGame;Qt + +Keywords=LEGO;lego;LEGO Island +Keywords[da]=LEGO;lego;Panik på LEGO Øen +Keywords[de]=LEGO;lego;Abenteuer auf der LEGO Insel +Keywords[es]=LEGO;lego;La Isla LEGO +Keywords[fr]=LEGO;lego;Aventures sur L'île LEGO +Keywords[it]=LEGO;lego;Isola LEGO +Keywords[ja]=LEGO;lego;レゴアイランドの大冒険 +Keywords[ko]=LEGO;lego;레고 아일랜드 +Keywords[pt]=LEGO;lego;A Ilha LEGO +Keywords[ru]=LEGO;lego;Остров LEGO +Keywords[uk_UA]=LEGO;lego;LEGO острів + +SingleMainWindow=true +StartupWMClass=isle + +TryExec=isle +Exec=isle + +Actions=play;configure + +[Desktop Action play] +Name=Play Game +Icon=currenttrack_play +Exec=isle + +[Desktop Action configure] +Name=Configure Settings +Icon=settings +Exec=isle-config diff --git a/packaging/linux/isledecomp.metainfo.xml.in b/packaging/linux/isledecomp.metainfo.xml.in new file mode 100644 index 00000000..b8faecc1 --- /dev/null +++ b/packaging/linux/isledecomp.metainfo.xml.in @@ -0,0 +1,91 @@ + + + + + @APP_ID@ + + @APP_NAME@ + @APP_SUMMARY@ + + @APP_ID@.desktop + + + #e3000b + + + + Isle Decomp Team + + + https://github.com/isledecomp/isle-portable + https://github.com/isledecomp/isle-portable/blob/master/CONTRIBUTING.md + https://github.com/isledecomp/isle-portable/tree/master + https://github.com/isledecomp/isle-portable/issues + + MIT + @APP_SPDX@ + + + 640 + offline-only + + + + 128 + + + + pointing + keyboard + gamepad + + + +

This initiative is a portable version of LEGO Island (Version 1.1, English) + based on the decompilation project. Our primary goal is to transform the codebase to achieve + platform independence, thereby enhancing compatibility across various systems while preserving + the original game's experience as faithfully as possible. +

+ +

+ Please note: this project is dedicated to achieving platform independence without altering the + core gameplay, adding new features, enhancing visual quality, or rewriting code for + improvement's sake. While those are worthwhile objectives, they are not within the scope + of this project. +

+ +
+ + + mild + mild + + + + Game + KidsGame + AdventureGame + Qt + + + + LEGO + lego + + LEGO Island + + Panik på LEGO Øen + Abenteuer auf der LEGO Insel + La Isla LEGO + Aventures sur L'île LEGO + Isola LEGO + レゴアイランドの大冒険 + 레고 아일랜드 + A Ilha LEGO + Остров LEGO + + + + + +
diff --git a/packaging/macos/CMakeLists.txt b/packaging/macos/CMakeLists.txt new file mode 100644 index 00000000..d6e93db8 --- /dev/null +++ b/packaging/macos/CMakeLists.txt @@ -0,0 +1,99 @@ +set(_icon_file AppIcon) +set(MACOSX_BUNDLE_GUI_IDENTIFIER ${APP_ID}) +set(MACOSX_BUNDLE_COPYRIGHT ${APP_SPDX}) +set(ISLE_TARGET_NAME isle) +set(MACOSX_ISLE_BUNDLE_NAME ${APP_NAME}) # Do note that it can be up to 15 characters long +set(MACOSX_ISLE_BUNDLE_DISPLAY_NAME ${APP_NAME}) +set(CONFIG_TARGET_NAME isle-config) +set(MACOSX_CONFIG_BUNDLE_NAME "Config Isle") # Do note that it can be up to 15 characters long +set(MACOSX_CONFIG_BUNDLE_DISPLAY_NAME "Configure ${APP_NAME}") +set(MACOSX_BUNDLE_INFO_STRING ${PROJECT_VERSION}) +set(MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}) +set(MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION}) +set(MACOSX_BUNDLE_LONG_VERSION_STRING "Version ${PROJECT_VERSION}") + +# TODO: darwin < 9 +set(MACOSX_BUNDLE_REQUIRED_PLATFORM Carbon) + +set(CPACK_DMG_VOLUME_NAME "Isle Portable") + +if(ISLE_BUILD_APP) + configure_file( + "${CMAKE_CURRENT_SOURCE_DIR}/isle/Info.plist.in" + "${CMAKE_CURRENT_BINARY_DIR}/isle/Info.plist" + @ONLY + ) + set(RESOURCE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/isle/${_icon_file}.icns") + target_sources(${ISLE_TARGET_NAME} PRIVATE ${RESOURCE_FILES}) + set_target_properties(${ISLE_TARGET_NAME} PROPERTIES + MACOSX_BUNDLE TRUE + MACOSX_BUNDLE_ICON_FILE "${_icon_file}.icns" + MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_BINARY_DIR}/isle/Info.plist" + RESOURCE ${RESOURCE_FILES}) + install(TARGETS ${ISLE_TARGET_NAME} DESTINATION ./) + install(CODE " + include(BundleUtilities) + fixup_bundle(${CMAKE_BINARY_DIR}/${ISLE_TARGET_NAME}.app \"\" \"\") + " + COMPONENT Runtime) + install(CODE " + execute_process(COMMAND /usr/bin/codesign + --force --deep --sign - --timestamp + \"\$\{CMAKE_INSTALL_PREFIX\}/${ISLE_TARGET_NAME}.app/Contents/MacOS/${ISLE_TARGET_NAME}\") + ") + install(CODE " + file(RENAME + \"\$\{CMAKE_INSTALL_PREFIX\}/${ISLE_TARGET_NAME}.app\" + \"\$\{CMAKE_INSTALL_PREFIX\}/${MACOSX_ISLE_BUNDLE_DISPLAY_NAME}.app\") + ") +endif() +if(ISLE_BUILD_CONFIG) + configure_file( + "${CMAKE_CURRENT_SOURCE_DIR}/config/Info.plist.in" + "${CMAKE_CURRENT_BINARY_DIR}/config/Info.plist" + @ONLY + ) + set(RESOURCE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/config/${_icon_file}.icns") + target_sources(${CONFIG_TARGET_NAME} PRIVATE ${RESOURCE_FILES}) + set_target_properties(${CONFIG_TARGET_NAME} PROPERTIES + MACOSX_BUNDLE TRUE + MACOSX_BUNDLE_ICON_FILE "${_icon_file}.icns" + MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_BINARY_DIR}/config/Info.plist" + RESOURCE ${RESOURCE_FILES}) + install(TARGETS ${CONFIG_TARGET_NAME} DESTINATION ./) + install(CODE " + include(BundleUtilities) + fixup_bundle(${CMAKE_BINARY_DIR}/${CONFIG_TARGET_NAME}.app \"\" \"\") + " + COMPONENT Runtime) + qt_generate_deploy_app_script( + TARGET ${CONFIG_TARGET_NAME} + OUTPUT_SCRIPT deploy_script + NO_COMPILER_RUNTIME + NO_TRANSLATIONS + ) + install(SCRIPT "${deploy_script}") + install(CODE " + execute_process(COMMAND /usr/bin/install_name_tool + -add_rpath \"@executable_path/../Frameworks\" + \"\$\{CMAKE_INSTALL_PREFIX\}/${CONFIG_TARGET_NAME}.app/Contents/MacOS/${CONFIG_TARGET_NAME}\") + ") + install(CODE " + execute_process(COMMAND /usr/bin/codesign + --force --deep --sign - --timestamp + \"\$\{CMAKE_INSTALL_PREFIX\}/${CONFIG_TARGET_NAME}.app/Contents/MacOS/${CONFIG_TARGET_NAME}\") + ") + install(CODE " + file(RENAME + \"\$\{CMAKE_INSTALL_PREFIX\}/${CONFIG_TARGET_NAME}.app\" + \"\$\{CMAKE_INSTALL_PREFIX\}/${MACOSX_CONFIG_BUNDLE_DISPLAY_NAME}.app\") + ") +endif() + +install(CODE " + if(IS_DIRECTORY \"\$\{CMAKE_INSTALL_PREFIX\}/bin\" OR IS_DIRECTORY \"\$\{CMAKE_INSTALL_PREFIX\}/lib\" OR EXISTS \"\$\{CMAKE_INSTALL_PREFIX\}/AppIcon.icns\") + execute_process(COMMAND /bin/rm + -rf \"\$\{CMAKE_INSTALL_PREFIX\}/bin\" \"\$\{CMAKE_INSTALL_PREFIX\}/lib\" \"\$\{CMAKE_INSTALL_PREFIX\}/AppIcon.icns\" + ) + endif() +") diff --git a/packaging/macos/config/AppIcon.icns b/packaging/macos/config/AppIcon.icns new file mode 100644 index 00000000..5b67c48a Binary files /dev/null and b/packaging/macos/config/AppIcon.icns differ diff --git a/packaging/macos/config/Info.plist.in b/packaging/macos/config/Info.plist.in new file mode 100644 index 00000000..d128adc0 --- /dev/null +++ b/packaging/macos/config/Info.plist.in @@ -0,0 +1,80 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${MACOSX_BUNDLE_EXECUTABLE_NAME} + CFBundleGetInfoString + @MACOSX_BUNDLE_INFO_STRING@ + CFBundleIconFile + @MACOSX_BUNDLE_ICON_FILE@ + CFBundleIdentifier + @MACOSX_BUNDLE_GUI_IDENTIFIER@ + CFBundleInfoDictionaryVersion + 6.0 + CFBundleLongVersionString + @MACOSX_BUNDLE_LONG_VERSION_STRING@ + CFBundleName + @MACOSX_CONFIG_BUNDLE_NAME@ + CFBundleDisplayName + @MACOSX_CONFIG_BUNDLE_DISPLAY_NAME@ + CFBundlePackageType + APPL + CFBundleShortVersionString + @MACOSX_BUNDLE_SHORT_VERSION_STRING@ + CFBundleSignature + ???? + CFBundleVersion + @MACOSX_BUNDLE_BUNDLE_VERSION@ + UILaunchStoryboardName + LaunchScreen + NSHighResolutionCapable + + CSResourcesFileMapped + + LSRequires@MACOSX_BUNDLE_REQUIRED_PLATFORM@ + + NSHumanReadableCopyright + @MACOSX_BUNDLE_COPYRIGHT@ + SDL_FILESYSTEM_BASE_DIR_TYPE + resource + NSSupportsAutomaticGraphicsSwitching + + UIApplicationSupportsIndirectInputEvents + + LSSupportsOpeningDocumentsInPlace + + UIFileSharingEnabled + + CADisableMinimumFrameDurationOnPhone + + UIDeviceFamily + + 1 + 2 + + UIRequiresFullScreen + + UIStatusBarHidden + + UISupportedInterfaceOrientations + + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + + CFBundleAllowMixedLocalizations + + + \ No newline at end of file diff --git a/packaging/macos/isle/AppIcon.icns b/packaging/macos/isle/AppIcon.icns new file mode 100644 index 00000000..61aa735e Binary files /dev/null and b/packaging/macos/isle/AppIcon.icns differ diff --git a/packaging/macos/isle/Info.plist.in b/packaging/macos/isle/Info.plist.in new file mode 100644 index 00000000..2ca3d26e --- /dev/null +++ b/packaging/macos/isle/Info.plist.in @@ -0,0 +1,82 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${MACOSX_BUNDLE_EXECUTABLE_NAME} + CFBundleGetInfoString + @MACOSX_BUNDLE_INFO_STRING@ + CFBundleIconFile + @MACOSX_BUNDLE_ICON_FILE@ + CFBundleIdentifier + @MACOSX_BUNDLE_GUI_IDENTIFIER@ + CFBundleInfoDictionaryVersion + 6.0 + CFBundleLongVersionString + @MACOSX_BUNDLE_LONG_VERSION_STRING@ + CFBundleName + @MACOSX_ISLE_BUNDLE_NAME@ + CFBundleDisplayName + @MACOSX_ISLE_BUNDLE_DISPLAY_NAME@ + CFBundlePackageType + APPL + CFBundleShortVersionString + @MACOSX_BUNDLE_SHORT_VERSION_STRING@ + CFBundleSignature + ???? + CFBundleVersion + @MACOSX_BUNDLE_BUNDLE_VERSION@ + UILaunchStoryboardName + LaunchScreen + NSHighResolutionCapable + + CSResourcesFileMapped + + LSRequires@MACOSX_BUNDLE_REQUIRED_PLATFORM@ + + NSHumanReadableCopyright + @MACOSX_BUNDLE_COPYRIGHT@ + SDL_FILESYSTEM_BASE_DIR_TYPE + resource + NSSupportsAutomaticGraphicsSwitching + + UIApplicationSupportsIndirectInputEvents + + LSSupportsOpeningDocumentsInPlace + + UIFileSharingEnabled + + CADisableMinimumFrameDurationOnPhone + + UIDeviceFamily + + 1 + 2 + + UIRequiresFullScreen + + UIStatusBarHidden + + UISupportedInterfaceOrientations + + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + + CFBundleAllowMixedLocalizations + + LSApplicationCategoryType + public.app-category.games + + \ No newline at end of file diff --git a/tools/curpng2h.py b/tools/curpng2h.py new file mode 100755 index 00000000..d55231b0 --- /dev/null +++ b/tools/curpng2h.py @@ -0,0 +1,75 @@ +#!/usr/bin/env python3 +import argparse +import itertools +from PIL import Image +from pathlib import Path + + +def encode_cursor(image_path: Path): + img = Image.open(image_path).convert("RGBA") + width, height = img.size + pixels = img.load() + + num_pixels = width * height + num_bytes = (num_pixels + 7) // 8 + + data = bytearray(num_bytes) + mask = bytearray(num_bytes) + + for y in range(height): + for x in range(width): + i = y * width + x + byte_index = i // 8 + bit_offset = 7 - (i % 8) + + r, g, b, a = pixels[x, y] + + if a >= 128: + mask[byte_index] |= 1 << bit_offset # opaque + lum = int(0.299 * r + 0.587 * g + 0.114 * b) + if lum < 128: + data[byte_index] |= 1 << bit_offset # black pixel + + return data, mask, width, height + + +def to_c_array(name, data): + lines = [] + for rowdata in itertools.batched(data, 12): + lines.append(", ".join(f"0x{byte:02X}" for byte in rowdata) + ",") + array_str = "\n ".join(lines) + return f"static const unsigned char {name}[] = {{\n {array_str}\n}};\n" + + +def main(): + parser = argparse.ArgumentParser(allow_abbrev=False) + parser.add_argument("inputs", nargs="+", help="PNG images", type=Path) + args = parser.parse_args() + + input_files: list[Path] = args.inputs + + for input_file in input_files: + data, mask, width, height = encode_cursor(input_file) + + input_file_name = input_file.stem + output_file = input_file.with_name(f"{input_file_name}_bmp.h") + + with output_file.open("w", newline="\n") as f: + f.write(f"#pragma once\n\n") + f.write(f"// Generated from {input_file}\n") + f.write(f"// Dimensions: {width}x{height}\n") + f.write("// This file is auto-generated, do not edit it.\n\n") + f.write(f'#include "cursor.h"\n\n') + f.write(to_c_array(f"{input_file_name}_data", data)) + f.write("\n") + f.write(to_c_array(f"{input_file_name}_mask", mask)) + f.write("\n") + f.write( + f"static const CursorBitmap {input_file_name}_cursor = {'{'} {width}, {height}, {input_file_name}_data, {input_file_name}_mask {'}'};\n" + ) + + print(f"Written {output_file} with cursor data.") + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/tools/ncc/skip.yml b/tools/ncc/skip.yml index 65de1ce7..322cded0 100644 --- a/tools/ncc/skip.yml +++ b/tools/ncc/skip.yml @@ -4,6 +4,7 @@ configureLegoModelPresenter(MxS32): 'DLL exported function' configureLegoPartPresenter(MxS32, MxS32): 'DLL exported function' configureLegoROI(int): 'DLL exported function' configureLegoWorldPresenter(MxS32): 'DLL exported function' +configureMxTransitionManager(TransitionType): 'DLL exported function' GetNoCD_SourceName(): 'DLL exported function' m_3dView: 'Allow this variable name' m_3dManager: 'Allow this variable name' @@ -73,3 +74,7 @@ cksize: "Re-defined Windows name" fccType: "Re-defined Windows name" dwDataOffset: "Re-defined Windows name" fccType: "Re-defined Windows name" +SDL_KeyboardID_v: "SDL-based name" +SDL_MouseID_v: "SDL-based name" +SDL_JoystickID_v: "SDL-based name" +SDL_TouchID_v: "SDL-based name" \ No newline at end of file