diff --git a/.github/workflows/build_3ds.yml b/.github/workflows/build_3ds.yml index 865be837e..f3ffd6305 100644 --- a/.github/workflows/build_3ds.yml +++ b/.github/workflows/build_3ds.yml @@ -1,5 +1,10 @@ name: Build latest (3DS) -on: [push] +# trigger via either push to selected branches or on manual run +on: + push: + branches: + - master + workflow_dispatch: concurrency: group: ${{ github.ref }}-3ds @@ -7,7 +12,6 @@ concurrency: jobs: build-3DS: - if: github.ref_name == github.event.repository.default_branch runs-on: ubuntu-latest container: image: devkitpro/devkitarm:latest diff --git a/.github/workflows/build_dreamcast.yml b/.github/workflows/build_dreamcast.yml index 8234a559a..f4f04875b 100644 --- a/.github/workflows/build_dreamcast.yml +++ b/.github/workflows/build_dreamcast.yml @@ -1,5 +1,10 @@ name: Build latest (Dreamcast) -on: [push] +# trigger via either push to selected branches or on manual run +on: + push: + branches: + - master + workflow_dispatch: concurrency: group: ${{ github.ref }}-dreamcast @@ -7,7 +12,6 @@ concurrency: jobs: build: - if: github.ref_name == github.event.repository.default_branch runs-on: ubuntu-latest container: image: kazade/dreamcast-sdk diff --git a/.github/workflows/build_freebsd.yml b/.github/workflows/build_freebsd.yml index 059587f7c..190939dee 100644 --- a/.github/workflows/build_freebsd.yml +++ b/.github/workflows/build_freebsd.yml @@ -1,5 +1,10 @@ name: Build latest (FreeBSD) -on: [push] +# trigger via either push to selected branches or on manual run +on: + push: + branches: + - master + workflow_dispatch: concurrency: group: ${{ github.ref }}-freebsd @@ -7,7 +12,6 @@ concurrency: jobs: build: - if: github.ref_name == github.event.repository.default_branch runs-on: ubuntu-latest container: image: empterdose/freebsd-cross-build:11.4 diff --git a/.github/workflows/build_haiku.yml b/.github/workflows/build_haiku.yml index de6789c11..55880b678 100644 --- a/.github/workflows/build_haiku.yml +++ b/.github/workflows/build_haiku.yml @@ -1,5 +1,10 @@ name: Build latest (Haiku) -on: [push] +# trigger via either push to selected branches or on manual run +on: + push: + branches: + - master + workflow_dispatch: concurrency: group: ${{ github.ref }}-haiku @@ -7,7 +12,6 @@ concurrency: jobs: build-haiku: - if: github.ref_name == github.event.repository.default_branch runs-on: ubuntu-latest container: image: haiku/cross-compiler:x86_64-r1beta4 diff --git a/.github/workflows/build_ios.yml b/.github/workflows/build_ios.yml index 45417daab..1fcc5aee1 100644 --- a/.github/workflows/build_ios.yml +++ b/.github/workflows/build_ios.yml @@ -1,5 +1,10 @@ name: Build latest (iOS) -on: [push] +# trigger via either push to selected branches or on manual run +on: + push: + branches: + - master + workflow_dispatch: concurrency: group: ${{ github.ref }}-ios @@ -7,7 +12,6 @@ concurrency: jobs: build: - if: github.ref_name == github.event.repository.default_branch runs-on: macOS-11 steps: - uses: actions/checkout@v3 diff --git a/.github/workflows/build_linux.yml b/.github/workflows/build_linux.yml index d81af37f5..729b0bc71 100644 --- a/.github/workflows/build_linux.yml +++ b/.github/workflows/build_linux.yml @@ -1,5 +1,11 @@ name: Build latest (Linux) -on: [push] +# trigger via either push to selected branches or on manual run +on: + push: + branches: + - master + - ModernLighting + workflow_dispatch: concurrency: group: ${{ github.ref }}-linux @@ -10,7 +16,6 @@ jobs: # =============== 32 BIT LINUX ============== # =========================================== build-32: - if: github.ref_name == github.event.repository.default_branch runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v4 @@ -64,7 +69,6 @@ jobs: # =============== 64 BIT LINUX ============== # =========================================== build-64: - if: github.ref_name == github.event.repository.default_branch runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/build_mac64.yml b/.github/workflows/build_mac64.yml index 510c10ae4..87925e9e4 100644 --- a/.github/workflows/build_mac64.yml +++ b/.github/workflows/build_mac64.yml @@ -1,5 +1,10 @@ name: Build latest (macOS 64 bit) -on: [push] +# trigger via either push to selected branches or on manual run +on: + push: + branches: + - master + workflow_dispatch: concurrency: group: ${{ github.ref }}-mac64 @@ -7,7 +12,6 @@ concurrency: jobs: build: - if: github.ref_name == github.event.repository.default_branch runs-on: macOS-latest steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/build_n64.yml b/.github/workflows/build_n64.yml index 3ba69268b..42d439d19 100644 --- a/.github/workflows/build_n64.yml +++ b/.github/workflows/build_n64.yml @@ -1,5 +1,10 @@ name: Build latest (N64) -on: [push] +# trigger via either push to selected branches or on manual run +on: + push: + branches: + - master + workflow_dispatch: concurrency: group: ${{ github.ref }}-n64 @@ -7,7 +12,6 @@ concurrency: jobs: build: - if: github.ref_name == github.event.repository.default_branch runs-on: ubuntu-latest container: image: ghcr.io/dragonminded/libdragon:latest diff --git a/.github/workflows/build_nds.yml b/.github/workflows/build_nds.yml index abb0ac7a1..96ec8f362 100644 --- a/.github/workflows/build_nds.yml +++ b/.github/workflows/build_nds.yml @@ -1,5 +1,10 @@ name: Build latest (NDS) -on: [push] +# trigger via either push to selected branches or on manual run +on: + push: + branches: + - master + workflow_dispatch: concurrency: group: ${{ github.ref }}-nds @@ -7,7 +12,6 @@ concurrency: jobs: build-DS: - if: github.ref_name == github.event.repository.default_branch runs-on: ubuntu-latest container: image: skylyrac/blocksds:dev-latest diff --git a/.github/workflows/build_netbsd.yml b/.github/workflows/build_netbsd.yml index 2f63c22ee..ac8cc46d5 100644 --- a/.github/workflows/build_netbsd.yml +++ b/.github/workflows/build_netbsd.yml @@ -1,5 +1,10 @@ name: Build latest (NetBSD) -on: [push] +# trigger via either push to selected branches or on manual run +on: + push: + branches: + - master + workflow_dispatch: concurrency: group: ${{ github.ref }}-netbsd @@ -7,7 +12,6 @@ concurrency: jobs: build: - if: github.ref_name == github.event.repository.default_branch runs-on: ubuntu-latest container: image: ghcr.io/cross-rs/x86_64-unknown-netbsd diff --git a/.github/workflows/build_ps2.yml b/.github/workflows/build_ps2.yml index 3fd5a69d0..1554825fb 100644 --- a/.github/workflows/build_ps2.yml +++ b/.github/workflows/build_ps2.yml @@ -1,5 +1,10 @@ name: Build latest (PS2) -on: [push] +# trigger via either push to selected branches or on manual run +on: + push: + branches: + - master + workflow_dispatch: concurrency: group: ${{ github.ref }}-ps2 @@ -7,7 +12,6 @@ concurrency: jobs: build: - if: github.ref_name == github.event.repository.default_branch runs-on: ubuntu-latest container: image: ghcr.io/ps2dev/ps2sdk:latest diff --git a/.github/workflows/build_ps3.yml b/.github/workflows/build_ps3.yml index b0f4ddb75..4587e92ba 100644 --- a/.github/workflows/build_ps3.yml +++ b/.github/workflows/build_ps3.yml @@ -1,5 +1,10 @@ name: Build latest (PS3) -on: [push] +# trigger via either push to selected branches or on manual run +on: + push: + branches: + - master + workflow_dispatch: concurrency: group: ${{ github.ref }}-ps3 @@ -7,7 +12,6 @@ concurrency: jobs: build-PS3: - if: github.ref_name == github.event.repository.default_branch runs-on: ubuntu-latest container: image: ghcr.io/classicube/minimal-psl1ght:latest diff --git a/.github/workflows/build_psp.yml b/.github/workflows/build_psp.yml index 639dac684..0f5e40cd4 100644 --- a/.github/workflows/build_psp.yml +++ b/.github/workflows/build_psp.yml @@ -1,5 +1,10 @@ name: Build latest (PSP) -on: [push] +# trigger via either push to selected branches or on manual run +on: + push: + branches: + - master + workflow_dispatch: concurrency: group: ${{ github.ref }}-psp @@ -7,7 +12,6 @@ concurrency: jobs: build-PSP: - if: github.ref_name == github.event.repository.default_branch runs-on: ubuntu-latest container: image: pspdev/pspdev:latest diff --git a/.github/workflows/build_rpi.yml b/.github/workflows/build_rpi.yml index c7da3f8e1..c8bc64b27 100644 --- a/.github/workflows/build_rpi.yml +++ b/.github/workflows/build_rpi.yml @@ -1,5 +1,10 @@ name: Build latest (RPI) -on: [push] +# trigger via either push to selected branches or on manual run +on: + push: + branches: + - master + workflow_dispatch: concurrency: group: ${{ github.ref }}-rpi @@ -10,7 +15,6 @@ jobs: # ================ 32 BIT RPI =============== # =========================================== build-RPI32: - if: github.ref_name == github.event.repository.default_branch runs-on: ubuntu-latest container: image: dockcross/linux-armv6-lts @@ -59,7 +63,6 @@ jobs: # ================ 64 BIT RPI =============== # =========================================== build-RPI64: - if: github.ref_name == github.event.repository.default_branch runs-on: ubuntu-latest container: image: dockcross/linux-arm64-lts diff --git a/.github/workflows/build_saturn.yml b/.github/workflows/build_saturn.yml index 59de7c6f3..b512200cb 100644 --- a/.github/workflows/build_saturn.yml +++ b/.github/workflows/build_saturn.yml @@ -1,5 +1,10 @@ name: Build latest (Saturn) -on: [push] +# trigger via either push to selected branches or on manual run +on: + push: + branches: + - master + workflow_dispatch: concurrency: group: ${{ github.ref }}-saturn @@ -7,7 +12,6 @@ concurrency: jobs: build: - if: github.ref_name == github.event.repository.default_branch runs-on: ubuntu-latest container: image: ijacquez/yaul @@ -35,4 +39,10 @@ jobs: if: ${{ always() && steps.compile.outcome == 'success' }} with: SOURCE_FILE: 'ClassiCube-saturn.iso' - DEST_NAME: 'ClassiCube-saturn.iso' \ No newline at end of file + DEST_NAME: 'ClassiCube-saturn.iso' + + - uses: ./.github/actions/upload_build + if: ${{ always() && steps.compile.outcome == 'success' }} + with: + SOURCE_FILE: 'ClassiCube-saturn.cue' + DEST_NAME: 'ClassiCube-saturn.cue' \ No newline at end of file diff --git a/.github/workflows/build_switch.yml b/.github/workflows/build_switch.yml index a85a66a47..fc726e9e3 100644 --- a/.github/workflows/build_switch.yml +++ b/.github/workflows/build_switch.yml @@ -1,5 +1,10 @@ name: Build latest (Switch) -on: [push] +# trigger via either push to selected branches or on manual run +on: + push: + branches: + - master + workflow_dispatch: concurrency: group: ${{ github.ref }}-switch @@ -7,7 +12,6 @@ concurrency: jobs: build-switch: - if: github.ref_name == github.event.repository.default_branch runs-on: ubuntu-latest container: image: devkitpro/devkita64:latest diff --git a/.github/workflows/build_vita.yml b/.github/workflows/build_vita.yml index 96195fed8..ed8851559 100644 --- a/.github/workflows/build_vita.yml +++ b/.github/workflows/build_vita.yml @@ -1,5 +1,10 @@ name: Build latest (Vita) -on: [push] +# trigger via either push to selected branches or on manual run +on: + push: + branches: + - master + workflow_dispatch: concurrency: group: ${{ github.ref }}-vita @@ -7,7 +12,6 @@ concurrency: jobs: build-Vita: - if: github.ref_name == github.event.repository.default_branch runs-on: ubuntu-latest container: image: vitasdk/vitasdk:latest diff --git a/.github/workflows/build_webclient.yml b/.github/workflows/build_webclient.yml new file mode 100644 index 000000000..1c4ccf5c6 --- /dev/null +++ b/.github/workflows/build_webclient.yml @@ -0,0 +1,44 @@ +name: Build latest (Webclient) +# trigger via either push to selected branches or on manual run +on: + push: + branches: + - master + workflow_dispatch: + +concurrency: + group: ${{ github.ref }}-webclient + cancel-in-progress: true + +jobs: + build: + runs-on: ubuntu-latest + container: + image: trzeci/emscripten-fastcomp:1.39.0 + steps: + - uses: actions/checkout@v4 + - name: Compiles webclient + id: compile + run: | + cd src + emcc *.c -o ClassiCube.js -s WASM=0 -s NO_EXIT_RUNTIME=1 -s LEGACY_VM_SUPPORT=1 -s ALLOW_MEMORY_GROWTH=1 -s ABORTING_MALLOC=0 -s ENVIRONMENT=web -s TOTAL_STACK=256Kb --js-library interop_web.js -Os -g2 -s SINGLE_FILE + sed -i 's#eventHandler.useCapture);#{ useCapture: eventHandler.useCapture, passive: false });#g' ClassiCube.js + + - uses: ./.github/actions/notify_failure + if: ${{ always() && steps.compile.outcome == 'failure' }} + with: + NOTIFY_MESSAGE: 'Failed to compile Webclient' + WEBHOOK_URL: '${{ secrets.WEBHOOK_URL }}' + + - uses: ./.github/actions/upload_build + if: ${{ always() && steps.compile.outcome == 'success' }} + with: + SOURCE_FILE: 'src/ClassiCube.js' + DEST_NAME: 'ClassiCube.js' + + + - uses: ./.github/actions/notify_success + if: ${{ always() && steps.compile.outcome == 'success' }} + with: + DESTINATION_URL: '${{ secrets.NOTIFY_URL }}' + WORKFLOW_NAME: 'webclient' \ No newline at end of file diff --git a/.github/workflows/build_wiigc.yml b/.github/workflows/build_wiigc.yml index 833e0f97c..d90d46e64 100644 --- a/.github/workflows/build_wiigc.yml +++ b/.github/workflows/build_wiigc.yml @@ -1,5 +1,10 @@ name: Build latest (Wii/GameCube) -on: [push] +# trigger via either push to selected branches or on manual run +on: + push: + branches: + - master + workflow_dispatch: concurrency: group: ${{ github.ref }}-wiigc @@ -7,7 +12,6 @@ concurrency: jobs: build: - if: github.ref_name == github.event.repository.default_branch runs-on: ubuntu-latest container: image: devkitpro/devkitppc:latest diff --git a/.github/workflows/build_wiiu.yml b/.github/workflows/build_wiiu.yml index e225d7a59..e19f6e8a0 100644 --- a/.github/workflows/build_wiiu.yml +++ b/.github/workflows/build_wiiu.yml @@ -1,5 +1,10 @@ name: Build latest (WiiU) -on: [push] +# trigger via either push to selected branches or on manual run +on: + push: + branches: + - master + workflow_dispatch: concurrency: group: ${{ github.ref }}-wiiu @@ -7,7 +12,6 @@ concurrency: jobs: build: - if: github.ref_name == github.event.repository.default_branch runs-on: ubuntu-latest container: image: devkitpro/devkitppc:latest diff --git a/.github/workflows/build_win-arm.yml b/.github/workflows/build_win-arm.yml new file mode 100644 index 000000000..9c3bf3d8f --- /dev/null +++ b/.github/workflows/build_win-arm.yml @@ -0,0 +1,79 @@ +name: Build latest (Windows ARM32/64) +# trigger via either push to selected branches or on manual run +on: + push: + branches: + - master + workflow_dispatch: + +concurrency: + group: ${{ github.ref }}-windows-arm + cancel-in-progress: true + +jobs: +#============================================ +# ============== ARM32 WINDOWS ============== +# =========================================== + build-32: + runs-on: ubuntu-latest + container: + image: dockcross/windows-armv7 + steps: + - uses: actions/checkout@v4 + - name: Compile ARM32 Windows builds + shell: bash + id: compile + env: + COMMON_FLAGS: "-O1 -s -fno-stack-protector -fno-math-errno -Qn" + WIN32_FLAGS: "-mwindows -nostartfiles -Wl,-emain_real -DCC_NOMAIN" + run: | + LATEST_FLAG=-DCC_COMMIT_SHA=\"${GITHUB_SHA::9}\" + + cd src + armv7-w64-mingw32-gcc *.c ${{ env.COMMON_FLAGS }} ${{ env.WIN32_FLAGS }} -o cc-arm32-d3d11.exe $LATEST_FLAG -DCC_BUILD_MANUAL -DCC_BUILD_WIN -DCC_BUILD_D3D11 -DCC_BUILD_WINGUI -DCC_BUILD_WGL -DCC_BUILD_WINMM -DCC_BUILD_HTTPCLIENT -DCC_BUILD_SCHANNEL -lwinmm -limagehlp + + + - uses: ./.github/actions/notify_failure + if: ${{ always() && steps.compile.outcome == 'failure' }} + with: + NOTIFY_MESSAGE: 'Failed to compile 32 bit Windows build' + WEBHOOK_URL: '${{ secrets.WEBHOOK_URL }}' + + - uses: ./.github/actions/upload_build + if: ${{ always() && steps.compile.outcome == 'success' }} + with: + SOURCE_FILE: 'src/cc-arm32-d3d11.exe' + DEST_NAME: 'ClassiCube-arm32-Direct3D11.exe' +#============================================ +# ============== ARM64 WINDOWS ============== +# =========================================== + build-64: + runs-on: ubuntu-latest + container: + image: dockcross/windows-arm64 + steps: + - uses: actions/checkout@v4 + - name: Compile ARM64 Windows builds + shell: bash + id: compile + env: + COMMON_FLAGS: "-O1 -s -fno-stack-protector -fno-math-errno -Qn" + WIN64_FLAGS: "-mwindows -nostartfiles -Wl,-emain_real -DCC_NOMAIN" + run: | + LATEST_FLAG=-DCC_COMMIT_SHA=\"${GITHUB_SHA::9}\" + + cd src + aarch64-w64-mingw32-gcc *.c ${{ env.COMMON_FLAGS }} ${{ env.WIN64_FLAGS }} -o cc-arm64-d3d11.exe $LATEST_FLAG -DCC_BUILD_MANUAL -DCC_BUILD_WIN -DCC_BUILD_D3D11 -DCC_BUILD_WINGUI -DCC_BUILD_WGL -DCC_BUILD_WINMM -DCC_BUILD_HTTPCLIENT -DCC_BUILD_SCHANNEL -lwinmm -limagehlp + + + - uses: ./.github/actions/notify_failure + if: ${{ always() && steps.compile.outcome == 'failure' }} + with: + NOTIFY_MESSAGE: 'Failed to compile 64 bit Windows build' + WEBHOOK_URL: '${{ secrets.WEBHOOK_URL }}' + + - uses: ./.github/actions/upload_build + if: ${{ always() && steps.compile.outcome == 'success' }} + with: + SOURCE_FILE: 'src/cc-arm64-d3d11.exe' + DEST_NAME: 'ClassiCube-arm64-Direct3D11.exe' \ No newline at end of file diff --git a/.github/workflows/build_windows.yml b/.github/workflows/build_windows.yml index cc14cfe70..905560275 100644 --- a/.github/workflows/build_windows.yml +++ b/.github/workflows/build_windows.yml @@ -1,5 +1,11 @@ name: Build latest (Windows) -on: [push] +# trigger via either push to selected branches or on manual run +on: + push: + branches: + - master + - ModernLighting + workflow_dispatch: concurrency: group: ${{ github.ref }}-windows @@ -10,7 +16,6 @@ jobs: # ============== 32 BIT WINDOWS ============= # =========================================== build-32: - if: github.ref_name == github.event.repository.default_branch runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -77,7 +82,6 @@ jobs: # ============== 64 BIT WINDOWS ============= # =========================================== build-64: - if: github.ref_name == github.event.repository.default_branch runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/build_xbox.yml b/.github/workflows/build_xbox.yml index 9c8b9ebee..5b016c496 100644 --- a/.github/workflows/build_xbox.yml +++ b/.github/workflows/build_xbox.yml @@ -1,5 +1,10 @@ name: Build latest (Xbox) -on: [push] +# trigger via either push to selected branches or on manual run +on: + push: + branches: + - master + workflow_dispatch: concurrency: group: ${{ github.ref }}-xbox @@ -7,7 +12,6 @@ concurrency: jobs: build-Xbox: - if: github.ref_name == github.event.repository.default_branch runs-on: ubuntu-latest container: image: ghcr.io/xboxdev/nxdk:git-e955705a diff --git a/.github/workflows/build_xbox360.yml b/.github/workflows/build_xbox360.yml index 8b07cbc7a..276dace35 100644 --- a/.github/workflows/build_xbox360.yml +++ b/.github/workflows/build_xbox360.yml @@ -1,13 +1,17 @@ name: Build latest (Xbox 360) -on: [push] +# trigger via either push to selected branches or on manual run +on: + push: + branches: + - master + workflow_dispatch: concurrency: group: ${{ github.ref }}-xbox360 cancel-in-progress: true jobs: - build-Xbox: - if: github.ref_name == github.event.repository.default_branch + build-360: runs-on: ubuntu-latest container: image: free60/libxenon diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index cbf07cf1a..62367b131 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -7,7 +7,6 @@ concurrency: jobs: build: - if: github.ref_name == github.event.repository.default_branch runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 diff --git a/.gitignore b/.gitignore index 38efbcdc3..550acea84 100644 --- a/.gitignore +++ b/.gitignore @@ -38,6 +38,12 @@ build-saturn/ cd/ # Microsoft console build results build-360/ +main.exe +main.lib +misc/xbox/ps_coloured.inl +misc/xbox/ps_textured.inl +misc/xbox/vs_coloured.inl +misc/xbox/vs_textured.inl # Sony console build results build-ps2/ build-ps3/ @@ -91,6 +97,8 @@ CMakeCache.txt #GCC object files *.o +# Build dependency files +*.d # Roslyn cache directories *.ide/ diff --git a/ios/CCIOS.xcodeproj/project.pbxproj b/ios/CCIOS.xcodeproj/project.pbxproj index ffa9fcf4a..aac987cc6 100644 --- a/ios/CCIOS.xcodeproj/project.pbxproj +++ b/ios/CCIOS.xcodeproj/project.pbxproj @@ -506,7 +506,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 6.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; @@ -559,7 +559,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 6.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; SDKROOT = iphoneos; @@ -573,7 +573,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_STYLE = Automatic; INFOPLIST_FILE = Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 6.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -590,7 +590,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_STYLE = Automatic; INFOPLIST_FILE = Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 6.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", diff --git a/license.txt b/license.txt index e37e196ad..1a3f45e26 100644 --- a/license.txt +++ b/license.txt @@ -1,4 +1,4 @@ -Copyright (c) 2014 - 2022, UnknownShadow200 +Copyright (c) 2014 - 2024, UnknownShadow200 All rights reserved. Redistribution and use in source and binary forms, with or without modification, diff --git a/misc/dreamcast/DrawColouredQuads.S b/misc/dreamcast/DrawColouredQuads.S new file mode 100644 index 000000000..a68f1127c --- /dev/null +++ b/misc/dreamcast/DrawColouredQuads.S @@ -0,0 +1,93 @@ +!r0 = clip flags +!r1 = GPU command +!r2 = temp +!r3 = prefetch address +!r4 = src pointer ARG +!r5 = dst pointer ARG +!r6 = quads count ARG +!r7 = ? + +!fr0 = temp +!fr1 = u (0.0) +!fr2 = v (0.0) +!fr3 = c +!fr4 = x +!fr5 = y +!fr6 = z +!fr7 = w +!fr8 = VIEWPORT_HWIDTH +!fr9 = VIEWPORT_HHEIGHT +!fr10 = VIEWPORT_X_PLUS_HWIDTH +!fr11 = VIEWPORT_Y_PLUS_HHEIGHT + +!fv4 = XYZW + +#include "ViewportTransform.S" +.global _DrawColouredQuads +.align 4 +.type _DrawColouredQuads,%function + +_DrawColouredQuads: +! Setup + fldi0 fr1 ! U = 0 + fldi0 fr2 ! V = 0 + mov r4,r3 ! r3 = src + add #-32, r5 ! r5 -= sizeof(VERTEX) + ViewportTransformSetup _VP_COL_HWIDTH + +.TRANSFORM_QUAD: + mov.l CMD_COL_VERT, r1 ! r1 = GPU VERT command + + LoadColouredVertex + ProcessVertex1 + + LoadColouredVertex + ProcessVertex2 + + LoadColouredVertex + ProcessVertex3 + + LoadColouredVertex + ProcessVertex4 CMD_COL_EOS + +! CLIPFLAGS TESTING + cmp/eq #0,r0 ! T = r0 == 0 (all points invisible) + bt/s .NO_POINTS_VISIBLE ! if T goto NO_POINTS_VISIBLE + nop + bra .SOME_POINTS_VISIBLE + nop + +.NO_POINTS_VISIBLE: + bra .LOOP_END ! jump to loop end after executing instruction in delay slot + add #-128, r5 ! r5 -= 4 * sizeof(VERTEX), move back to 1 vertex before start of quad + +.SOME_POINTS_VISIBLE: + +.LOOP_END: + dt r6 ! r6--; T = r6 == 0 + bf .TRANSFORM_QUAD ! if !T then goto TRANSFORM_QUAD + nop + + add #32, r5 ! r5 += sizeof(VERTEX) + rts ! return after executing instruction in delay slot + mov r5,r0 ! r0 = r5 + +.align 2 +CMD_COL_VERT: .long 0xe0000000 +CMD_COL_EOS: .long 0xf0000000 + +.global _VP_COL_HWIDTH +.type _VP_COL_HWIDTH,%object +_VP_COL_HWIDTH: .long 0 + +.global _VP_COL_HHEIGHT +.type _VP_COL_HHEIGHT,%object +_VP_COL_HHEIGHT: .long 0 + +.global _VP_COL_X_PLUS_HWIDTH +.type _VP_COL_X_PLUS_HWIDTH,%object +_VP_COL_X_PLUS_HWIDTH: .long 0 + +.global _VP_COL_Y_PLUS_HHEIGHT +.type _VP_COL_Y_PLUS_HHEIGHT,%object +_VP_COL_Y_PLUS_HHEIGHT: .long 0 \ No newline at end of file diff --git a/misc/dreamcast/DrawTexturedQuads.S b/misc/dreamcast/DrawTexturedQuads.S new file mode 100644 index 000000000..9ef80f9fe --- /dev/null +++ b/misc/dreamcast/DrawTexturedQuads.S @@ -0,0 +1,91 @@ +!r0 = clip flags +!r1 = GPU command +!r2 = temp +!r3 = prefetch address +!r4 = src pointer ARG +!r5 = dst pointer ARG +!r6 = quads count ARG +!r7 = ? + +!fr0 = temp +!fr1 = u +!fr2 = v +!fr3 = c +!fr4 = x +!fr5 = y +!fr6 = z +!fr7 = w +!fr8 = VIEWPORT_HWIDTH +!fr9 = VIEWPORT_HHEIGHT +!fr10 = VIEWPORT_X_PLUS_HWIDTH +!fr11 = VIEWPORT_Y_PLUS_HHEIGHT + +!fv4 = XYZW + +#include "ViewportTransform.S" +.global _DrawTexturedQuads +.align 4 +.type _DrawTexturedQuads,%function + +_DrawTexturedQuads: +! Setup + mov r4,r3 ! r3 = src + add #-32, r5 ! r5 -= sizeof(VERTEX) + ViewportTransformSetup _VP_TEX_HWIDTH + +.TRANSFORM_QUAD: + mov.l CMD_TEX_VERT, r1 ! r1 = GPU VERT command + + LoadTexturedVertex + ProcessVertex1 + + LoadTexturedVertex + ProcessVertex2 + + LoadTexturedVertex + ProcessVertex3 + + LoadTexturedVertex + ProcessVertex4 CMD_TEX_EOS + +! CLIPFLAGS TESTING + cmp/eq #0,r0 ! T = r0 == 0 (all points invisible) + bt/s .NO_POINTS_VISIBLE ! if T goto NO_POINTS_VISIBLE + nop + bra .SOME_POINTS_VISIBLE + nop + +.NO_POINTS_VISIBLE: + bra .LOOP_END ! jump to loop end after executing instruction in delay slot + add #-128, r5 ! r5 -= 4 * sizeof(VERTEX), move back to prior quad, so that this invisible quad gets overwritten in next iteration + +.SOME_POINTS_VISIBLE: + +.LOOP_END: + dt r6 ! r6--; T = r6 == 0 + bf .TRANSFORM_QUAD ! if !T then goto TRANSFORM_QUAD + nop + + add #32, r5 ! r5 += sizeof(VERTEX) + rts ! return after executing instruction in delay slot + mov r5,r0 ! r0 = r5 + +.align 2 +CMD_TEX_VERT: .long 0xe0000000 +CMD_TEX_EOS: .long 0xf0000000 + +.global _VP_TEX_HWIDTH +.type _VP_TEX_HWIDTH,%object +_VP_TEX_HWIDTH: .long 0 + +.global _VP_TEX_HHEIGHT +.type _VP_TEX_HHEIGHT,%object +_VP_TEX_HHEIGHT: .long 0 + +.global _VP_TEX_X_PLUS_HWIDTH +.type _VP_TEX_X_PLUS_HWIDTH,%object +_VP_TEX_X_PLUS_HWIDTH: .long 0 + +.global _VP_TEX_Y_PLUS_HHEIGHT +.type _VP_TEX_Y_PLUS_HHEIGHT,%object +_VP_TEX_Y_PLUS_HHEIGHT: .long 0 \ No newline at end of file diff --git a/misc/dreamcast/Makefile b/misc/dreamcast/Makefile index 54920960f..3d23e2600 100644 --- a/misc/dreamcast/Makefile +++ b/misc/dreamcast/Makefile @@ -1,8 +1,9 @@ BUILD_DIR := build-dc -SOURCE_DIRS := src third_party/bearssl/src +SOURCE_DIRS := src third_party/bearssl/src misc/dreamcast +S_FILES := $(foreach dir,$(SOURCE_DIRS),$(wildcard $(dir)/*.S)) C_FILES := $(foreach dir,$(SOURCE_DIRS),$(wildcard $(dir)/*.c)) -OBJS := $(addprefix $(BUILD_DIR)/, $(notdir $(C_FILES:%.c=%.o))) +OBJS := $(addprefix $(BUILD_DIR)/, $(notdir $(C_FILES:%.c=%.o) $(S_FILES:%.S=%.o))) CFLAGS :=-g -O1 -pipe -fno-math-errno -Ithird_party/bearssl/inc GLDC_LIB=third_party/gldc/libGLdc.a @@ -21,8 +22,9 @@ default: $(CC_TEXTURES) $(GLDC_LIB) $(BUILD_DIR) $(TARGET).cdi $(BUILD_DIR): mkdir -p $(BUILD_DIR) -$(GLDC_LIB): +$(GLDC_LIB): FORCE $(MAKE) -C third_party/gldc +FORCE: ; # TODO add textures to misc folder ? $(CC_TEXTURES): @@ -31,6 +33,9 @@ $(CC_TEXTURES): $(BUILD_DIR)/%.o: src/%.c kos-cc $(CFLAGS) -c $< -o $@ +$(BUILD_DIR)/%.o: misc/dreamcast/%.S + kos-cc -c $< -o $@ + $(BUILD_DIR)/%.o: third_party/bearssl/src/%.c kos-cc $(CFLAGS) -c $< -o $@ @@ -58,4 +63,4 @@ $(TARGET).iso: $(TARGET)-scr.bin # genisoimage -V ClassiCube -G IP.BIN -joliet -rock -l -o $(TARGET).iso ISO_FILES $(TARGET).cdi: $(TARGET).iso - cdi4dc $(TARGET).iso $(TARGET).cdi \ No newline at end of file + cdi4dc $(TARGET).iso $(TARGET).cdi diff --git a/misc/dreamcast/ViewportTransform.S b/misc/dreamcast/ViewportTransform.S new file mode 100644 index 000000000..fee37ce0c --- /dev/null +++ b/misc/dreamcast/ViewportTransform.S @@ -0,0 +1,161 @@ +! ========================================================= +! ========================= VERTEX LOADING ================ +! ========================================================= +.macro LoadColouredVertex +! PREPARE NEXT VERTEX + add #16, r3 ! r3 += VERTEX_STRIDE + pref @r3 ! PREFETCH r3 (next vertex) + add #64, r5 ! r5 += 2 * sizeof(VERTEX) +! LOAD XYZ + fmov @r4+, fr4 ! X = src->x + fmov @r4+, fr5 ! Y = src->y + fmov @r4+, fr6 ! Z = src->z + fldi1 fr7 ! W = 1.0 +! TRANSFORM VERTEX + ftrv xmtrx, fv4 ! TRANSFORM(XYZW) +! LOAD ATTRIBUTES + fmov @r4+,fr3 ! C = src->color +.endm + +.macro LoadTexturedVertex +! PREPARE NEXT VERTEX + add #24, r3 ! r3 += VERTEX_STRIDE + pref @r3 ! PREFETCH r3 (next vertex) + add #64, r5 ! r5 += 2 * sizeof(VERTEX) +! LOAD XYZ + fmov @r4+, fr4 ! X = src->x + fmov @r4+, fr5 ! Y = src->y + fmov @r4+, fr6 ! Z = src->z + fldi1 fr7 ! W = 1.0 +! TRANSFORM VERTEX + ftrv xmtrx, fv4 ! TRANSFORM(XYZW) +! LOAD ATTRIBUTES + fmov @r4+,fr3 ! C = src->color + fmov @r4+,fr1 ! U = src->u + fmov @r4+,fr2 ! V = src->v +.endm + +! ========================================================= +! ========================= VERTEX OUTPUT ================= +! ========================================================= +! To take advantage of SH4 dual instruction processing, interleave +! the clipflag calculation and vertex output instructions +.macro ProcessVertex1 + fmov.s fr7,@-r5 ! dst->w = W + fmov.s fr3,@-r5 ! dst->c = C + fneg fr7 ! W = -W + fmov.s fr2,@-r5 ! dst->v = V + fcmp/gt fr7,fr6 ! T = Z > W (i.e. Z > -W) + fmov.s fr1,@-r5 ! dst->u = U + movt r0 ! CLIPFLAGS = T + fmov.s fr6,@-r5 ! dst->z = Z + fmov.s fr5,@-r5 ! dst->y = Y + fmov.s fr4,@-r5 ! dst->x = X + mov.l r1,@-r5 ! dst->flags = CMD_VERT +.endm + +.macro ProcessVertex2 + fmov.s fr7,@-r5 ! dst->w = W + fmov.s fr3,@-r5 ! dst->c = C + fneg fr7 ! W = -W + fmov.s fr2,@-r5 ! dst->v = V + fcmp/gt fr7,fr6 ! T = Z > W (i.e. Z > -W) + fmov.s fr1,@-r5 ! dst->u = U + movt r2 ! tmp = T + fmov.s fr6,@-r5 ! dst->z = Z + add r2,r2 ! tmp = tmp + tmp + fmov.s fr5,@-r5 ! dst->y = Y + or r2,r0 ! CLIPFLAGS |= tmp (T << 1) + fmov.s fr4,@-r5 ! dst->x = X + mov.l r1,@-r5 ! dst->flags = CMD_VERT +.endm + +.macro ProcessVertex3 + fmov.s fr7,@-r5 ! dst->w = W + fmov.s fr3,@-r5 ! dst->c = C + fneg fr7 ! W = -W + fmov.s fr2,@-r5 ! dst->v = V + fcmp/gt fr7,fr6 ! T = Z > W (i.e. Z > -W) + fmov.s fr1,@-r5 ! dst->u = U + movt r2 ! tmp = T + fmov.s fr6,@-r5 ! dst->z = Z + fmov.s fr5,@-r5 ! dst->y = Y + shll2 r2 ! tmp = tmp << 2 + fmov.s fr4,@-r5 ! dst->x = X + or r2,r0 ! CLIPFLAGS |= tmp (T << 2) + mov.l r1,@-r5 ! dst->flags = CMD_VERT +.endm + +.macro ProcessVertex4 eos_addr + fmov.s fr7,@-r5 ! dst->w = W + fmov.s fr3,@-r5 ! dst->c = C + fneg fr7 ! W = -W + fmov.s fr2,@-r5 ! dst->v = V + fcmp/gt fr7,fr6 ! T = Z > W (i.e. Z > -W) + fmov.s fr1,@-r5 ! dst->u = U + movt r2 ! tmp = T + fmov.s fr6,@-r5 ! dst->z = Z + shll2 r2 ! tmp = tmp << 2 + fmov.s fr5,@-r5 ! dst->y = Y + add r2,r2 ! tmp = (tmp << 2) + (tmp << 2) + fmov.s fr4,@-r5 ! dst->x = X + mov.l \eos_addr, r1 ! r1 = GPU EOS command + or r2,r0 ! CLIPFLAGS |= tmp (T << 3) + or r0,r1 ! r1 |= CLIPFLAGS + mov.l r1,@-r5 ! dst->flags = GPU EOS | CLIPFLAGS +.endm + + +! ========================================================= +! ====================== VIEWPORT TRANSFORM =============== +! ========================================================= +!r2 = return addr +!r0 = temp +!r5 = dst pointer + +!fr0 = temp +!fr4 = temp +!fr5 = temp +!fr5 = temp +!fr8 = VIEWPORT_HWIDTH +!fr9 = VIEWPORT_HHEIGHT +!fr10 = VIEWPORT_X_PLUS_HWIDTH +!fr11 = VIEWPORT_Y_PLUS_HHEIGHT + +.macro ViewportTransformSetup viewport_addr + mova \viewport_addr, r0 + fmov.s @r0+,fr8 ! fr8 = VIEWPORT_HWIDTH + fmov.s @r0+,fr9 ! fr9 = VIEWPORT_HHEIGHT + fmov.s @r0+,fr10 ! fr10 = VIEWPORT_X_PLUS_HWIDTH + fmov.s @r0+,fr11 ! fr11 = VIEWPORT_Y_PLUS_HHEIGHT + nop ! align to even instructions +.endm + +.macro ViewportTransformVertex +! INVERSE W CALCULATION + add #28, r5 ! r5 = &vertex->w + fmov.s @r5,fr0 ! fr0 = vertex->w + fmul fr0,fr0 ! fr0 = fr0 * fr0 + add #-24, r5 ! r5 = &vertex->x + fsrra fr0 ! fr0 = 1 / sqrt(fr0) -> 1 / vertex->w + +! TRANSFORM X + fmov.s @r5,fr4 ! fr4 = vertex->x + fmov fr10,fr5 ! fr5 = VIEWPORT_X_PLUS_HWIDTH + fmul fr8,fr4 ! fr4 = VIEWPORT_HWIDTH * vertex->x + fmac fr0,fr4,fr5 ! fr5 = fr0 * fr4 + fr5 -- (X * F * hwidth) + x_plus_hwidth + fmov.s fr5,@r5 ! vertex->x = fr5 + add #4, r5 ! r5 = &vertex->y + +! TRANSFORM Y + fmov.s @r5,fr4 ! fr4 = vertex->y + fmov fr11,fr5 ! fr5 = VIEWPORT_Y_PLUS_HHEIGHT + fmul fr9,fr4 ! fr4 = VIEWPORT_HHEIGHT * vertex->y + fmac fr0,fr4,fr5 ! fr5 = fr0 * fr4 + fr5 -- (Y * F * hheight) + y_plus_hheight + fmov.s fr5,@r5 ! vertex->y = fr5 + add #4, r5 ! r5 = &vertex->z + +! ASSIGN Z + fmov.s fr0,@r5 ! vertex->z = fr0 + add #20, r5 ! r5 += 20 (points to start of next vertex) +.endm \ No newline at end of file diff --git a/misc/saturn/Makefile b/misc/saturn/Makefile index cd37ad8d1..9dcc22a36 100644 --- a/misc/saturn/Makefile +++ b/misc/saturn/Makefile @@ -16,10 +16,10 @@ SH_CFLAGS+= -Os -I. -DPLAT_SATURN SH_LDFLAGS+= IP_VERSION:= V1.000 -IP_RELEASE_DATE:= 20160101 +IP_RELEASE_DATE:= 20230101 IP_AREAS:= JTUBKAEL IP_PERIPHERALS:= JAMKST -IP_TITLE:= VDP1 drawing +IP_TITLE:= ClassiCube IP_MASTER_STACK_ADDR:= 0x06004000 IP_SLAVE_STACK_ADDR:= 0x06001E00 IP_1ST_READ_ADDR:= 0x06004000 diff --git a/misc/wiiu/Makefile b/misc/wiiu/Makefile index 9af30ecae..f1031f62a 100644 --- a/misc/wiiu/Makefile +++ b/misc/wiiu/Makefile @@ -78,14 +78,15 @@ export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ export DEPSDIR := $(CURDIR)/$(BUILD) CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) +CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) \ $(foreach dir,$(SHADERS),$(notdir $(wildcard $(dir)/*.gsh))) -export LD := $(CC) +export LD := $(CXX) export OFILES_BIN := $(addsuffix .o,$(BINFILES)) -export OFILES_SRC := $(CFILES:.c=.o) $(SFILES:.s=.o) +export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) export OFILES := $(OFILES_BIN) $(OFILES_SRC) export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES))) @@ -170,4 +171,4 @@ $(OFILES_SRC) : $(HFILES_BIN) #------------------------------------------------------------------------------- endif -#------------------------------------------------------------------------------- \ No newline at end of file +#------------------------------------------------------------------------------- diff --git a/src/Bitmap.c b/src/Bitmap.c index 6f84a9b25..af8c0d911 100644 --- a/src/Bitmap.c +++ b/src/Bitmap.c @@ -163,8 +163,8 @@ static void Png_Reconstruct(cc_uint8 type, cc_uint8 bytesPerPixel, cc_uint8* lin /* 7.2 Scanlines */ #define PNG_Do_Grayscale(dstI, src, scale) rgb = (src) * scale; Bitmap_Set(dst[dstI], rgb, rgb, rgb, 255); -#define PNG_Do_Grayscale_8() rgb = src[0]; Bitmap_Set(*dst, rgb, rgb, rgb, 255); dst--; src -= 2; -#define PNG_Do_Grayscale_A__8() rgb = src[0]; Bitmap_Set(*dst, rgb, rgb, rgb, src[1]); dst--; src -= 1; +#define PNG_Do_Grayscale_8() rgb = src[0]; Bitmap_Set(*dst, rgb, rgb, rgb, 255); dst--; src -= 1; +#define PNG_Do_Grayscale_A__8() rgb = src[0]; Bitmap_Set(*dst, rgb, rgb, rgb, src[1]); dst--; src -= 2; #define PNG_Do_RGB__8() Bitmap_Set(*dst, src[0], src[1], src[2], 255); dst--; src -= 3; #define PNG_Do_RGB_A__8() Bitmap_Set(*dst, src[0], src[1], src[2], src[3]); dst++; src += 4; #define PNG_Do_Palette__8() *dst-- = palette[*src--]; @@ -488,12 +488,14 @@ cc_result Png_Decode(struct Bitmap* bmp, struct Stream* stream) { /* immediately into the destination colour format */ if (colorspace == PNG_COLOR_RGB_A) { /* Prior line is no longer needed and can be overwritten now */ - rowExpander(bmp->width, palette, &prior[1], Bitmap_GetRow(bmp, rowY - 1)); - /* Current line is also no longer needed and can be overwritten now */ - if (rowY == bmp->height - 1) - rowExpander(bmp->width, palette, &scanline[1], Bitmap_GetRow(bmp, rowY)); + rowExpander(bmp->width, palette, &prior[1], Bitmap_GetRow(bmp, rowY - 1)); } } + + /* Current line is also no longer needed and can be overwritten now */ + if (colorspace == PNG_COLOR_RGB_A && rowY == bmp->height - 1) { + rowExpander(bmp->width, palette, &scanline[1], Bitmap_GetRow(bmp, rowY)); + } } /* Check if image fully decoded or not */ diff --git a/src/Builder.c b/src/Builder.c index 672b47d2a..e58bca5d2 100644 --- a/src/Builder.c +++ b/src/Builder.c @@ -360,9 +360,16 @@ static void OutputChunkPartsMeta(int x, int y, int z, struct ChunkInfo* info) { } void Builder_MakeChunk(struct ChunkInfo* info) { +#ifdef CC_BUILD_SATURN + /* The Saturn build only has 16 kb stack, not large enough */ + static BlockID chunk[EXTCHUNK_SIZE_3]; + static cc_uint8 counts[CHUNK_SIZE_3 * FACE_COUNT]; + static int bitFlags[1]; +#else BlockID chunk[EXTCHUNK_SIZE_3]; cc_uint8 counts[CHUNK_SIZE_3 * FACE_COUNT]; int bitFlags[EXTCHUNK_SIZE_3]; +#endif cc_bool allAir, allSolid, onBorder; int xMax, yMax, zMax, totalVerts; @@ -761,6 +768,7 @@ static void NormalBuilder_SetActive(void) { /*########################################################################################################################* *-------------------------------------------------Advanced mesh builder---------------------------------------------------* *#########################################################################################################################*/ +#ifdef CC_BUILD_ADVLIGHTING static Vec3 adv_minBB, adv_maxBB; static int adv_initBitFlags, adv_baseOffset; static int* adv_bitFlags; @@ -1259,6 +1267,9 @@ static void AdvBuilder_SetActive(void) { Builder_RenderBlock = Adv_RenderBlock; Builder_PrePrepareChunk = Adv_PrePrepareChunk; } +#else +static void AdvBuilder_SetActive(void) { NormalBuilder_SetActive(); } +#endif /*########################################################################################################################* diff --git a/src/Camera.c b/src/Camera.c index 2133ab942..2b4a8e698 100644 --- a/src/Camera.c +++ b/src/Camera.c @@ -154,8 +154,10 @@ static Vec2 FirstPersonCamera_GetOrientation(struct LocalPlayer* p) { return v; } -static Vec3 FirstPersonCamera_GetPosition(struct LocalPlayer* p, float t) { +static Vec3 FirstPersonCamera_GetPosition(float t) { + struct LocalPlayer* p = Entities.CurPlayer; struct Entity* e = &p->Base; + Vec3 camPos = Entity_GetEyePosition(e); float yaw = e->Yaw * MATH_DEG2RAD; PerspectiveCamera_CalcViewBobbing(p, t, 1); @@ -202,8 +204,10 @@ static float ThirdPersonCamera_GetZoom(struct LocalPlayer* p) { return dist; } -static Vec3 ThirdPersonCamera_GetPosition(struct LocalPlayer* p, float t) { +static Vec3 ThirdPersonCamera_GetPosition(float t) { + struct LocalPlayer* p = Entities.CurPlayer; struct Entity* e = &p->Base; + float dist = ThirdPersonCamera_GetZoom(p); Vec3 target, dir; Vec2 rot; diff --git a/src/Camera.h b/src/Camera.h index 8d8f513d9..04afda320 100644 --- a/src/Camera.h +++ b/src/Camera.h @@ -51,7 +51,7 @@ struct Camera { /* Returns the current orientation of the camera. */ Vec2 (*GetOrientation)(struct LocalPlayer* p); /* Returns the current interpolated position of the camera. */ - Vec3 (*GetPosition)(struct LocalPlayer* p, float t); + Vec3 (*GetPosition)(float t); /* Called to update the camera's state. */ /* Typically, this is used to adjust yaw/pitch based on accumulated mouse movement. */ diff --git a/src/Chat.h b/src/Chat.h index a97d46334..c4366bfef 100644 --- a/src/Chat.h +++ b/src/Chat.h @@ -67,8 +67,8 @@ typedef void (*FP_Chat_AddOf)(const cc_string* text, int msgType); /* Shorthand for Chat_AddOf(String_FromReadonly(raw), MSG_TYPE_NORMAL) */ void Chat_AddRaw(const char* raw); -void Chat_Add1(const char* format, const void* a1); -void Chat_Add2(const char* format, const void* a1, const void* a2); -void Chat_Add3(const char* format, const void* a1, const void* a2, const void* a3); -void Chat_Add4(const char* format, const void* a1, const void* a2, const void* a3, const void* a4); +CC_API void Chat_Add1(const char* format, const void* a1); +CC_API void Chat_Add2(const char* format, const void* a1, const void* a2); +CC_API void Chat_Add3(const char* format, const void* a1, const void* a2, const void* a3); +CC_API void Chat_Add4(const char* format, const void* a1, const void* a2, const void* a3, const void* a4); #endif diff --git a/src/ClassiCube.vcxproj b/src/ClassiCube.vcxproj index 8017c6dab..767c6dea8 100644 --- a/src/ClassiCube.vcxproj +++ b/src/ClassiCube.vcxproj @@ -561,7 +561,7 @@ - + diff --git a/src/ClassiCube.vcxproj.filters b/src/ClassiCube.vcxproj.filters index c694ffe91..5ba0c40e2 100644 --- a/src/ClassiCube.vcxproj.filters +++ b/src/ClassiCube.vcxproj.filters @@ -728,9 +728,6 @@ Source Files\Window - - Source Files\Window - Source Files\Platform @@ -752,6 +749,9 @@ Source Files\Graphics + + Source Files\Window + diff --git a/src/Commands.c b/src/Commands.c index 7276ba91a..b64e84fcc 100644 --- a/src/Commands.c +++ b/src/Commands.c @@ -267,6 +267,23 @@ static struct ChatCommand ClearDeniedCommand = { } }; +static void MotdCommand_Execute(const cc_string* args, int argsCount) { + if (Server.IsSinglePlayer) { + Chat_AddRaw("&eThis command can only be used in multiplayer."); + return; + } + Chat_Add1("&eName: &f%s", &Server.Name); + Chat_Add1("&eMOTD: &f%s", &Server.MOTD); +} + +static struct ChatCommand MotdCommand = { + "Motd", MotdCommand_Execute, + COMMAND_FLAG_UNSPLIT_ARGS, + { + "&a/client motd", + "&eDisplays the server's name and MOTD." + } +}; /*########################################################################################################################* *-------------------------------------------------------DrawOpCommand-----------------------------------------------------* @@ -709,6 +726,7 @@ static void OnInit(void) { Commands_Register(&ModelCommand); Commands_Register(&TeleportCommand); Commands_Register(&ClearDeniedCommand); + Commands_Register(&MotdCommand); Commands_Register(&BlockEditCommand); Commands_Register(&CuboidCommand); Commands_Register(&ReplaceCommand); diff --git a/src/Constants.h b/src/Constants.h index b5db72195..5a9686341 100644 --- a/src/Constants.h +++ b/src/Constants.h @@ -67,9 +67,8 @@ enum SKIN_TYPE { SKIN_64x32, SKIN_64x64, SKIN_64x64_SLIM, SKIN_INVALID = 0xF0 }; #define Int32_MinValue ((cc_int32)-2147483647L - (cc_int32)1L) #define Int32_MaxValue ((cc_int32)2147483647L) -/* Skins were moved to use Amazon S3, so link directly to avoid a pointless redirect */ #define SKINS_SERVER "http://cdn.classicube.net/skin" -#define UPDATES_SERVER "http://cs.classicube.net/client" +#define UPDATES_SERVER "http://cdn.classicube.net/client" #define SERVICES_SERVER "https://www.classicube.net/api" #define RESOURCE_SERVER "http://static.classicube.net" /* Webpage where users can register for a new account */ diff --git a/src/Core.h b/src/Core.h index 1915382f2..9843b4318 100644 --- a/src/Core.h +++ b/src/Core.h @@ -124,6 +124,7 @@ typedef cc_uint8 cc_bool; #define CC_BUILD_PLUGINS #define CC_BUILD_ANIMATIONS #define CC_BUILD_FILESYSTEM +#define CC_BUILD_ADVLIGHTING /*#define CC_BUILD_GL11*/ #ifndef CC_BUILD_MANUAL @@ -297,7 +298,6 @@ typedef cc_uint8 cc_bool; #elif defined __vita__ #define CC_BUILD_PSVITA #define CC_BUILD_CONSOLE - #define CC_BUILD_LOWMEM #define CC_BUILD_OPENAL #define CC_BUILD_HTTPCLIENT #define CC_BUILD_BEARSSL @@ -313,7 +313,6 @@ typedef cc_uint8 cc_bool; #elif defined PLAT_PS3 #define CC_BUILD_PS3 #define CC_BUILD_CONSOLE - #define CC_BUILD_LOWMEM #define CC_BUILD_OPENAL #define CC_BUILD_HTTPCLIENT #define CC_BUILD_BEARSSL @@ -347,6 +346,7 @@ typedef cc_uint8 cc_bool; #define CC_BUILD_TOUCH #undef CC_BUILD_RESOURCES #undef CC_BUILD_ANIMATIONS /* Very costly in FPU less system */ + #undef CC_BUILD_ADVLIGHTING #elif defined __WIIU__ #define CC_BUILD_WIIU #define CC_BUILD_CONSOLE @@ -354,6 +354,7 @@ typedef cc_uint8 cc_bool; #define CC_BUILD_OPENAL #define CC_BUILD_HTTPCLIENT #define CC_BUILD_BEARSSL + #define CC_BUILD_SPLITSCREEN #define CC_BUILD_TOUCH #elif defined __SWITCH__ #define CC_BUILD_SWITCH @@ -375,6 +376,7 @@ typedef cc_uint8 cc_bool; #undef CC_BUILD_RESOURCES #undef CC_BUILD_NETWORKING #undef CC_BUILD_ANIMATIONS /* Very costly in FPU less system */ + #undef CC_BUILD_ADVLIGHTING #undef CC_BUILD_FILESYSTEM #elif defined OS2 #define CC_BUILD_OS2 @@ -393,6 +395,7 @@ typedef cc_uint8 cc_bool; #undef CC_BUILD_RESOURCES #undef CC_BUILD_NETWORKING #undef CC_BUILD_ANIMATIONS /* Very costly in FPU less system */ + #undef CC_BUILD_ADVLIGHTING #undef CC_BUILD_FILESYSTEM #endif #endif diff --git a/src/Deflate.c b/src/Deflate.c index 747288616..c4171c1e2 100644 --- a/src/Deflate.c +++ b/src/Deflate.c @@ -243,7 +243,7 @@ static cc_result Huffman_Build(struct HuffmanTable* table, const cc_uint8* bitLe * - set fast value to specify a 'value' value, and to skip 'len' bits */ if (len <= INFLATE_FAST_BITS) { - cc_int16 packed = (cc_int16)((len << INFLATE_FAST_BITS) | value); + cc_int16 packed = (cc_int16)((len << INFLATE_FAST_LEN_SHIFT) | value); int codeword = table->firstCodewords[len] + (bl_offsets[len] - table->firstOffsets[len]); codeword <<= (INFLATE_FAST_BITS - len); @@ -273,9 +273,9 @@ static int Huffman_Decode(struct InflateState* state, struct HuffmanTable* table if (state->NumBits >= INFLATE_FAST_BITS) { packed = table->fast[Inflate_PeekBits(state, INFLATE_FAST_BITS)]; if (packed >= 0) { - bits = packed >> INFLATE_FAST_BITS; + bits = packed >> INFLATE_FAST_LEN_SHIFT; Inflate_ConsumeBits(state, bits); - return packed & 0x1FF; + return packed & INFLATE_FAST_VAL_MASK; } } diff --git a/src/Deflate.h b/src/Deflate.h index 7e363bdba..8ff3aa17b 100644 --- a/src/Deflate.h +++ b/src/Deflate.h @@ -27,7 +27,11 @@ cc_result ZLibHeader_Read(struct Stream* s, struct ZLibHeader* header); #define INFLATE_MAX_DISTS 32 #define INFLATE_MAX_LITS_DISTS (INFLATE_MAX_LITS + INFLATE_MAX_DISTS) #define INFLATE_MAX_BITS 16 + #define INFLATE_FAST_BITS 9 +#define INFLATE_FAST_LEN_SHIFT 9 +#define INFLATE_FAST_VAL_MASK 0x1FF + #define INFLATE_WINDOW_SIZE 0x8000UL #define INFLATE_WINDOW_MASK 0x7FFFUL diff --git a/src/Drawer2D.c b/src/Drawer2D.c index 80d36b966..589ca0b24 100644 --- a/src/Drawer2D.c +++ b/src/Drawer2D.c @@ -539,6 +539,12 @@ static void DrawBitmappedTextCore(struct Bitmap* bmp, struct DrawTextArgs* args, static void DrawBitmappedText(struct Bitmap* bmp, struct DrawTextArgs* args, int x, int y) { int offset = Drawer2D_ShadowOffset(args->font->size); + if (!fontBitmap.scan0) { + if (args->useShadow) FallbackFont_DrawText(args, bmp, x, y, true); + FallbackFont_DrawText(args, bmp, x, y, false); + return; + } + if (args->useShadow) { DrawBitmappedTextCore(bmp, args, x + offset, y + offset, true); } @@ -550,6 +556,8 @@ static int MeasureBitmappedWidth(const struct DrawTextArgs* args) { int xPadding, width; cc_string text; + if (!fontBitmap.scan0) return FallbackFont_TextWidth(args); + /* adjust coords to make drawn text match GDI fonts */ xPadding = Drawer2D_XPadding(point); width = 0; diff --git a/src/Entity.c b/src/Entity.c index 40ebb818e..165414f4a 100644 --- a/src/Entity.c +++ b/src/Entity.c @@ -622,6 +622,11 @@ void LocalPlayerInput_Add(struct LocalPlayerInput* source) { LinkedList_Append(source, sources_head, sources_tail); } +void LocalPlayerInput_Remove(struct LocalPlayerInput* source) { + struct LocalPlayerInput* cur; + LinkedList_Remove(source, cur, sources_head, sources_tail); +} + float LocalPlayer_JumpHeight(struct LocalPlayer* p) { return (float)PhysicsComp_CalcMaxHeight(p->Physics.JumpVel); } @@ -887,7 +892,9 @@ cc_bool LocalPlayer_HandleSetSpawn(struct LocalPlayer* p) { /* Spawn is normally centered to match vanilla Minecraft classic */ if (!p->Hacks.CanNoclip) { - p->Spawn = p->Base.Position; + /* Don't want to use Position because it is interpolated between prev and next. */ + /* This means it can be halfway between stepping up a stair and clip through the floor. */ + p->Spawn = p->Base.prev.pos; } else { p->Spawn.x = Math_Floor(p->Base.Position.x) + 0.5f; p->Spawn.y = p->Base.Position.y; @@ -968,7 +975,7 @@ void LocalPlayers_MoveToSpawn(struct LocationUpdate* update) { } /* TODO: This needs to be before new map... */ - Camera.CurrentPos = Camera.Active->GetPosition(Entities.CurPlayer, 0.0f); + Camera.CurrentPos = Camera.Active->GetPosition(0.0f); } void LocalPlayer_CalcDefaultSpawn(struct LocalPlayer* p, struct LocationUpdate* update) { @@ -1062,6 +1069,7 @@ static void Entities_Free(void) { { Entities_Remove((EntityID)i); } + sources_head = NULL; } struct IGameComponent Entities_Component = { diff --git a/src/Entity.h b/src/Entity.h index 295d168aa..9b6119d5d 100644 --- a/src/Entity.h +++ b/src/Entity.h @@ -231,6 +231,7 @@ struct LocalPlayerInput { struct LocalPlayerInput* next; }; void LocalPlayerInput_Add(struct LocalPlayerInput* source); +void LocalPlayerInput_Remove(struct LocalPlayerInput* source); /* Represents the user/player's own entity. */ struct LocalPlayer { diff --git a/src/EntityRenderers.c b/src/EntityRenderers.c index 92688694d..f673a8904 100644 --- a/src/EntityRenderers.c +++ b/src/EntityRenderers.c @@ -19,7 +19,7 @@ static cc_bool shadows_boundTex; static GfxResourceID shadows_VB; static GfxResourceID shadows_tex; static float shadow_radius, shadow_uvScale; -struct ShadowData { float y; BlockID Block; cc_uint8 A; }; +struct ShadowData { float y; BlockID block; cc_uint8 alpha; }; /* Circle shadows extend at most 4 blocks vertically */ #define SHADOW_MAX_RANGE 4 @@ -54,7 +54,7 @@ static void EntityShadow_DrawCoords(struct VertexTextured** vertices, struct Ent z2 = min(z2, cen.z + shadow_radius); v2 = v2 <= 1.0f ? v2 : 1.0f; v = *vertices; - col = PackedCol_Make(255, 255, 255, data->A); + col = PackedCol_Make(255, 255, 255, data->alpha); v->x = x1; v->y = data->y; v->z = z1; v->Col = col; v->U = u1; v->V = v1; v++; v->x = x2; v->y = data->y; v->z = z1; v->Col = col; v->U = u2; v->V = v1; v++; @@ -83,13 +83,13 @@ static void EntityShadow_DrawCircle(struct VertexTextured** vertices, struct Ent Vec3 min, max, nMin, nMax; int i; x = (float)Math_Floor(x); z = (float)Math_Floor(z); - min = Blocks.MinBB[data[0].Block]; max = Blocks.MaxBB[data[0].Block]; + min = Blocks.MinBB[data[0].block]; max = Blocks.MaxBB[data[0].block]; EntityShadow_DrawCoords(vertices, e, &data[0], x + min.x, z + min.z, x + max.x, z + max.z); for (i = 1; i < 4; i++) { - if (data[i].Block == BLOCK_AIR) return; - nMin = Blocks.MinBB[data[i].Block]; nMax = Blocks.MaxBB[data[i].Block]; + if (data[i].block == BLOCK_AIR) return; + nMin = Blocks.MinBB[data[i].block]; nMax = Blocks.MaxBB[data[i].block]; EntityShadow_DrawCoords(vertices, e, &data[i], x + min.x, z + nMin.z, x + max.x, z + min.z); EntityShadow_DrawCoords(vertices, e, &data[i], x + min.x, z + max.z, x + max.x, z + nMax.z); @@ -103,11 +103,12 @@ static void EntityShadow_DrawCircle(struct VertexTextured** vertices, struct Ent static void EntityShadow_CalcAlpha(float playerY, struct ShadowData* data) { float height = playerY - data->y; if (height <= 6.0f) { - data->A = (cc_uint8)(160 - 160 * height / 6.0f); - data->y += 1.0f / 64.0f; return; + data->alpha = (cc_uint8)(160 - 160 * height / 6.0f); + data->y += 1.0f / 64.0f; + return; } - data->A = 0; + data->alpha = 0; if (height <= 16.0f) data->y += 1.0f / 64.0f; else if (height <= 32.0f) data->y += 1.0f / 16.0f; else if (height <= 96.0f) data->y += 1.0f / 8.0f; @@ -144,7 +145,7 @@ static cc_bool EntityShadow_GetBlocks(struct Entity* e, int x, int y, int z, str topY = y + Blocks.MaxBB[block].y; if (topY >= posY + 0.01f) continue; - cur->Block = block; cur->y = topY; + cur->block = block; cur->y = topY; EntityShadow_CalcAlpha(posY, cur); i++; cur++; @@ -154,7 +155,7 @@ static cc_bool EntityShadow_GetBlocks(struct Entity* e, int x, int y, int z, str } if (i < 4) { - cur->Block = Env.EdgeBlock; cur->y = 0.0f; + cur->block = Env.EdgeBlock; cur->y = 0.0f; EntityShadow_CalcAlpha(posY, cur); i++; cur++; } @@ -188,16 +189,16 @@ static void EntityShadow_Draw(struct Entity* e) { x1 = Math_Floor(pos.x - shadow_radius); z1 = Math_Floor(pos.z - shadow_radius); x2 = Math_Floor(pos.x + shadow_radius); z2 = Math_Floor(pos.z + shadow_radius); - if (EntityShadow_GetBlocks(e, x1, y, z1, data) && data[0].A > 0) { + if (EntityShadow_GetBlocks(e, x1, y, z1, data) && data[0].alpha > 0) { EntityShadow_DrawCircle(&ptr, e, data, (float)x1, (float)z1); } - if (x1 != x2 && EntityShadow_GetBlocks(e, x2, y, z1, data) && data[0].A > 0) { + if (x1 != x2 && EntityShadow_GetBlocks(e, x2, y, z1, data) && data[0].alpha > 0) { EntityShadow_DrawCircle(&ptr, e, data, (float)x2, (float)z1); } - if (z1 != z2 && EntityShadow_GetBlocks(e, x1, y, z2, data) && data[0].A > 0) { + if (z1 != z2 && EntityShadow_GetBlocks(e, x1, y, z2, data) && data[0].alpha > 0) { EntityShadow_DrawCircle(&ptr, e, data, (float)x1, (float)z2); } - if (x1 != x2 && z1 != z2 && EntityShadow_GetBlocks(e, x2, y, z2, data) && data[0].A > 0) { + if (x1 != x2 && z1 != z2 && EntityShadow_GetBlocks(e, x2, y, z2, data) && data[0].alpha > 0) { EntityShadow_DrawCircle(&ptr, e, data, (float)x2, (float)z2); } } @@ -262,6 +263,7 @@ void EntityShadows_Render(void) { if (Entities.ShadowsMode == SHADOW_MODE_CIRCLE_ALL) { for (i = 0; i < ENTITIES_MAX_COUNT; i++) { + e = Entities.List[i]; if (!e || !e->ShouldRender || e == &Entities.CurPlayer->Base) continue; EntityShadow_Draw(e); } diff --git a/src/Errors.h b/src/Errors.h index 25abd7206..45072a4b0 100644 --- a/src/Errors.h +++ b/src/Errors.h @@ -132,7 +132,8 @@ enum CC_ERRORS { HTTP_ERR_RELATIVE = 0xCCDED069UL, /* Unsupported relative URL format */ HTTP_ERR_INVALID_BODY= 0xCCDED06AUL, /* HTTP message doesn't have Content-Length or use Chunked transfer encoding */ HTTP_ERR_CHUNK_SIZE = 0xCCDED06BUL, /* HTTP message chunk has negative size/length */ - HTTP_ERR_TRUNCATED = 0xCCDED06CUL, /* HTTP respone header was truncated due to being too long */ + HTTP_ERR_TRUNCATED = 0xCCDED06CUL, /* HTTP response header was truncated due to being too long */ + HTTP_ERR_NO_RESPONSE = 0xCCDED06DUL, /* First attempt to read response returned 0 bytes */ SSL_ERR_CONTEXT_DEAD = 0xCCDED070UL, /* Server shutdown the SSL context and it must be recreated */ PNG_ERR_16BITSAMPLES = 0xCCDED071UL, /* Image uses 16 bit samples, which is unimplemented */ diff --git a/src/ExtMath.c b/src/ExtMath.c index aa10e9791..a281baf6a 100644 --- a/src/ExtMath.c +++ b/src/ExtMath.c @@ -4,6 +4,8 @@ /* For abs(x) function */ #include +#define PI 3.141592653589793238462643383279502884197169399 + /* Sega saturn is missing these intrinsics */ #ifdef CC_BUILD_SATURN #include @@ -80,8 +82,8 @@ float Math_ClampAngle(float degrees) { } float Math_LerpAngle(float leftAngle, float rightAngle, float t) { - /* We have to cheat a bit for angles here */ - /* Consider 350* --> 0*, we only want to travel 10* */ + /* Need to potentially adjust a bit when interpolating some angles */ + /* Consider 350* --> 0*, we only want to interpolate across the 10* */ /* But without adjusting for this case, we would interpolate back the whole 350* degrees */ cc_bool invertLeft = leftAngle > 270.0f && rightAngle < 90.0f; cc_bool invertRight = rightAngle > 270.0f && leftAngle < 90.0f; @@ -147,8 +149,6 @@ float Random_Float(RNGState* seed) { /*########################################################################################################################* *--------------------------------------------------Transcendental functions-----------------------------------------------* *#########################################################################################################################*/ -static const double SQRT2 = 1.4142135623730950488016887242096980785696718753769; - #ifdef CC_BUILD_DREAMCAST #include @@ -156,12 +156,10 @@ static const double SQRT2 = 1.4142135623730950488016887242096980785696718753769; /* TODO: Properly investigate this issue */ /* double make_dreamcast_build_compile(void) { fabs(4); } */ -double Math_Sin(double x) { return sin(x); } -double Math_Cos(double x) { return cos(x); } +double Math_Sin(double x) { return sinf(x); } +double Math_Cos(double x) { return cosf(x); } double Math_Exp2(double x) { return exp2(x); } double Math_Log2(double x) { return log2(x); } - -double Math_Atan2(double x, double y) { return atan2(y, x); } #else /***** Caleb's Math functions *****/ @@ -187,7 +185,7 @@ double Math_Atan2(double x, double y) { return atan2(y, x); } /* from the mathematical functions anyways */ /* Global constants */ -#define PI 3.141592653589793238462643383279502884197169399 +static const double SQRT2 = 1.4142135623730950488016887242096980785696718753769; #define DIV_2_PI (1.0 / (2.0 * PI)) static const cc_uint64 _DBL_NAN = 0x7FF8000000000000ULL; @@ -296,149 +294,6 @@ double Math_Cos(double x) { return SinStage3(x_div_pi_shifted - Floord(x_div_pi_shifted)); } -/************** - * Math_Atan2 * - **************/ - -/* Calculates the 5th degree polynomial ARCTN 4903 listed in the book's - * appendix. - * - * Associated math function: arctan(x) - * Allowed input range: [0, tan(pi/32)] - * Precision: 16.52 - */ -static double AtanStage1(double x) { - const double A[] = { - .99999999999969557, - -.3333333333318, - .1999999997276, - -.14285702288, - .11108719478, - -.8870580341e-1, - }; - - double P = A[5]; - double x_2 = x * x; - int i; - - for (i = 4; i >= 0; i--) { - P *= x_2; - P += A[i]; - } - P *= x; - return P; -} - -/* This function finds out in which partition the non-negative real number x - * resides out of 8 partitions, which are precomputed. It then uses the - * following law: - * - * t = x_i^{-1} - (x_i^{-2} + 1)/(x_i^{-1} + x) - * arctan(x) = arctan(x_i) + arctan(t) - * - * where x_i = tan((2i - 2)*pi/32) and i is the partition number. The value of t - * is guaranteed to be between [-tan(pi/32), tan(pi/32)]. - * - * Associated math function: arctan(x) - * Allowed input range: [0, infinity] - */ -static double AtanStage2(double x) { - const double X_i[] = { - 0.0, - 0.0984914033571642477671304050090839155018329620361328125, - 0.3033466836073424044428747947677038609981536865234375, - 0.53451113595079158269385288804187439382076263427734375, - 0.82067879082866024287312711749109439551830291748046875, - 1.218503525587976366040265929768793284893035888671875, - 1.8708684117893887854933154812897555530071258544921875, - 3.29655820893832096629694206058047711849212646484375, - (float)(1e+300 * 1e+300) /* Infinity */ - }; - - const double div_x_i[] = { - 0, - 0, - 5.02733949212584807497705696732737123966217041015625, - 2.41421356237309492343001693370752036571502685546875, - 1.496605762665489169904731170390732586383819580078125, - 1.0000000000000002220446049250313080847263336181640625, - 0.66817863791929898997778991542872972786426544189453125, - 0.414213562373095089963470627481001429259777069091796875, - 0.1989123673796580893391450217677629552781581878662109375, - }; - - const double div_x_i_2_plus_1[] = { - 0, - 0, - 26.2741423690881816810360760428011417388916015625, - 6.8284271247461898468600338674150407314300537109375, - 3.23982880884355051165357508580200374126434326171875, - 2.000000000000000444089209850062616169452667236328125, - 1.446462692171689656817079594475217163562774658203125, - 1.1715728752538099310953612075536511838436126708984375, - 1.0395661298965801488947136022034101188182830810546875, - }; - - int L = 0; - int R = 8; - double t; - - while (R - L > 1) { - int m = (L + R) / 2; - if (X_i[m] <= x) - L = m; - else if (X_i[m] > x) - R = m; - } - - if (R <= 1) - return AtanStage1(x); - - t = div_x_i[R] - div_x_i_2_plus_1[R] / (div_x_i[R] + x); - if (t >= 0) - return (2 * R - 2) * PI / 32.0 + AtanStage1(t); - - return (2 * R - 2) * PI / 32.0 - AtanStage1(-t); -} - -/* Uses the property arctan(x) = -arctan(-x). - * - * Associated math function: arctan(x) - * Allowed input range: anything - */ -static double Atan(double x) { - if (x == DBL_NAN) - return DBL_NAN; - if (x == NEG_INF) - return -PI / 2.0; - if (x == POS_INF) - return PI / 2.0; - if (x >= 0) - return AtanStage2(x); - return -AtanStage2(-x); -} - -/* Implements the function atan2 using Atan. - * - * Associated math function: atan2(y, x) - * Allowed input range: anything - */ -double Math_Atan2(double x, double y) { - if (x > 0) - return Atan(y / x); - if (x < 0) { - if (y >= 0) - return Atan(y / x) + PI; - return Atan(y / x) - PI; - } - - /* x = 0 case */ - if (y > 0) return PI / 2.0; - if (y < 0) return -PI / 2.0; - - return DBL_NAN; -} - /************ * Math_Exp * ************/ @@ -576,7 +431,7 @@ double Math_Log2(double x) { if (x == POS_INF) return POS_INF; - if (x == NEG_INF || x == DBL_NAN || x <= 0.0) + if (x == DBL_NAN || x <= 0.0) return DBL_NAN; doi.d = x; @@ -588,5 +443,26 @@ double Math_Log2(double x) { return exponent + Log2Stage1(doi.d); } +#endif -#endif \ No newline at end of file +// Approximation of atan2f using the Remez algorithm +// https://math.stackexchange.com/a/1105038 +float Math_Atan2f(float x, float y) { + if (x == 0) { + if (y > 0) return PI / 2.0f; + if (y < 0) return -PI / 2.0f; + return 0; /* Should probably be NaN */ + } + + float ax = Math_AbsF(x); + float ay = Math_AbsF(y); + + float a = (ax < ay) ? (ax / ay) : (ay / ax); + float s = a * a; + float r = ((-0.0464964749f * s + 0.15931422f) * s - 0.327622764f) * s * a + a; + + if (ay > ax) r = 1.57079637f - r; + if (x < 0) r = 3.14159274f - r; + if (y < 0) r = -r; + return r; +} \ No newline at end of file diff --git a/src/ExtMath.h b/src/ExtMath.h index f02db6399..a4a689cc0 100644 --- a/src/ExtMath.h +++ b/src/ExtMath.h @@ -31,7 +31,9 @@ CC_API double Math_Sin(double x); CC_API double Math_Cos(double x); float Math_SinF(float x); float Math_CosF(float x); -double Math_Atan2(double x, double y); +/* Computes atan2(y, x), intended primarily for angle calculation*/ +/* Note that accuracy is only up to around 4 decimal places */ +float Math_Atan2f(float x, float y); /* Computes log2(x). Can also be used to approximate log_y(x). */ /* e.g. for log3(x), use: log2(x)/log2(3) */ diff --git a/src/Game.c b/src/Game.c index 3f7d161a8..1ee4a4cb5 100644 --- a/src/Game.c +++ b/src/Game.c @@ -640,7 +640,7 @@ static void DrawSplitscreen(float delta, float t, int i, int x, int y, int w, in Entities.CurPlayer = &LocalPlayer_Instances[i]; LocalPlayer_SetInterpPosition(Entities.CurPlayer, t); - Camera.CurrentPos = Camera.Active->GetPosition(Entities.CurPlayer, t); + Camera.CurrentPos = Camera.Active->GetPosition(t); Game_DrawFrame(delta, t); } @@ -684,7 +684,7 @@ static CC_INLINE void Game_RenderFrame(double delta) { t = (float)(entTask.accumulator / entTask.interval); LocalPlayer_SetInterpPosition(Entities.CurPlayer, t); - Camera.CurrentPos = Camera.Active->GetPosition(Entities.CurPlayer, t); + Camera.CurrentPos = Camera.Active->GetPosition(t); /* NOTE: EnvRenderer_UpdateFog also also sets clear color */ EnvRenderer_UpdateFog(); AudioBackend_Tick(); diff --git a/src/Graphics_3DS.c b/src/Graphics_3DS.c index 36c8d53ec..422666a8e 100644 --- a/src/Graphics_3DS.c +++ b/src/Graphics_3DS.c @@ -439,7 +439,7 @@ void Gfx_SetFaceCulling(cc_bool enabled) { void Gfx_SetAlphaArgBlend(cc_bool enabled) { } -void Gfx_SetAlphaBlending(cc_bool enabled) { +static void SetAlphaBlend(cc_bool enabled) { if (enabled) { C3D_AlphaBlend(GPU_BLEND_ADD, GPU_BLEND_ADD, GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA); } else { @@ -447,7 +447,7 @@ void Gfx_SetAlphaBlending(cc_bool enabled) { } } -void Gfx_SetAlphaTest(cc_bool enabled) { +static void SetAlphaTest(cc_bool enabled) { C3D_AlphaTest(enabled, GPU_GREATER, 0x7F); } @@ -806,7 +806,7 @@ void Gfx_CalcOrthoMatrix(struct Matrix* matrix, float width, float height, float matrix->row1.y = -2.0f / width; matrix->row4.y = 1.0f; - matrix->row3.z = 1.0f / (zNear - zFar); + matrix->row3.z = 1.0f / (zNear - zFar); matrix->row4.z = 0.5f * (zNear + zFar) / (zNear - zFar) - 0.5f; matrix->row4.w = 1.0f; } diff --git a/src/Graphics_D3D11.c b/src/Graphics_D3D11.c index 19f57f626..0017c0c55 100644 --- a/src/Graphics_D3D11.c +++ b/src/Graphics_D3D11.c @@ -691,7 +691,7 @@ void Gfx_SetFaceCulling(cc_bool enabled) { static ID3D11SamplerState* ps_samplers[2]; static ID3D11PixelShader* ps_shaders[12]; static ID3D11Buffer* ps_cBuffer; -static cc_bool ps_alphaTesting, ps_mipmaps; +static cc_bool ps_mipmaps; static float ps_fogEnd, ps_fogDensity; static PackedCol ps_fogColor; static int ps_fogMode; @@ -725,7 +725,7 @@ static void PS_CreateShaders(void) { static int PS_CalcShaderIndex(void) { int idx = gfx_format == VERTEX_FORMAT_COLOURED ? 0 : 1; - if (ps_alphaTesting) idx += 2; + if (gfx_alphaTest) idx += 2; if (gfx_fogEnabled) { // uncomment when it works @@ -822,8 +822,7 @@ static void PS_Free(void) { PS_FreeConstants(); } -void Gfx_SetAlphaTest(cc_bool enabled) { - ps_alphaTesting = enabled; +static void SetAlphaTest(cc_bool enabled) { PS_UpdateShader(); } // unnecessary? check if any performance is gained, probably irrelevant @@ -887,10 +886,10 @@ void Gfx_DisableMipmaps(void) { static ID3D11RenderTargetView* backbuffer; static ID3D11Texture2D* depthbuffer; static ID3D11DepthStencilView* depthbufferView; -static ID3D11BlendState* om_blendStates[4]; +static ID3D11BlendState* om_blendStates[16 * 2]; static ID3D11DepthStencilState* om_depthStates[4]; static float gfx_clearColor[4]; -static cc_bool gfx_alphaBlending, gfx_colorEnabled = true; +static cc_bool gfx_channels[4] = { true, true, true, true }; static cc_bool gfx_depthTest, gfx_depthWrite; static void OM_Clear(GfxBuffers buffers) { @@ -972,8 +971,14 @@ static void OM_CreateBlendStates(void) { for (int i = 0; i < Array_Elems(om_blendStates); i++) { - desc.RenderTarget[0].RenderTargetWriteMask = (i & 1) ? D3D11_COLOR_WRITE_ENABLE_ALL : 0; - desc.RenderTarget[0].BlendEnable = (i & 2) != 0; + int mask = 0; + if (i & 0x01) mask |= D3D11_COLOR_WRITE_ENABLE_RED; + if (i & 0x02) mask |= D3D11_COLOR_WRITE_ENABLE_GREEN; + if (i & 0x04) mask |= D3D11_COLOR_WRITE_ENABLE_BLUE; + if (i & 0x08) mask |= D3D11_COLOR_WRITE_ENABLE_ALPHA; + + desc.RenderTarget[0].RenderTargetWriteMask = mask; + desc.RenderTarget[0].BlendEnable = (i & 0x10) != 0; hr = ID3D11Device_CreateBlendState(device, &desc, &om_blendStates[i]); if (hr) Logger_Abort2(hr, "Failed to create blend state"); @@ -981,7 +986,8 @@ static void OM_CreateBlendStates(void) { } static void OM_UpdateBlendState(void) { - ID3D11BlendState* blendState = om_blendStates[gfx_colorEnabled | (gfx_alphaBlending << 1)]; + int idx = (gfx_channels[0]) | (gfx_channels[1] << 1) | (gfx_channels[2] << 2) | (gfx_channels[3] << 3) | (gfx_alphaBlend << 4); + ID3D11BlendState* blendState = om_blendStates[idx]; ID3D11DeviceContext_OMSetBlendState(context, blendState, NULL, 0xffffffff); } @@ -1030,15 +1036,16 @@ void Gfx_SetDepthWrite(cc_bool enabled) { OM_UpdateDepthState(); } -void Gfx_SetAlphaBlending(cc_bool enabled) { - gfx_alphaBlending = enabled; +static void SetAlphaBlend(cc_bool enabled) { OM_UpdateBlendState(); } static void SetColorWrite(cc_bool r, cc_bool g, cc_bool b, cc_bool a) { - gfx_colorEnabled = r; + gfx_channels[0] = r; + gfx_channels[1] = g; + gfx_channels[2] = b; + gfx_channels[3] = a; OM_UpdateBlendState(); - // TODO all channels } void Gfx_DepthOnlyRendering(cc_bool depthOnly) { diff --git a/src/Graphics_D3D9.c b/src/Graphics_D3D9.c index 8cf140ade..c64301a0f 100644 --- a/src/Graphics_D3D9.c +++ b/src/Graphics_D3D9.c @@ -394,7 +394,7 @@ void Gfx_DisableMipmaps(void) { *-----------------------------------------------------State management----------------------------------------------------* *#########################################################################################################################*/ static D3DFOGMODE gfx_fogMode = D3DFOG_NONE; -static cc_bool gfx_alphaTesting, gfx_alphaBlending; +static cc_bool gfx_alphaBlending; static cc_bool gfx_depthTesting, gfx_depthWriting; static PackedCol gfx_clearColor, gfx_fogColor; static float gfx_fogEnd = -1.0f, gfx_fogDensity = -1.0f; @@ -455,18 +455,12 @@ void Gfx_SetFogMode(FogFunc func) { IDirect3DDevice9_SetRenderState(device, D3DRS_FOGTABLEMODE, mode); } -void Gfx_SetAlphaTest(cc_bool enabled) { - if (gfx_alphaTesting == enabled) return; - gfx_alphaTesting = enabled; - +static void SetAlphaTest(cc_bool enabled) { if (Gfx.LostContext) return; IDirect3DDevice9_SetRenderState(device, D3DRS_ALPHATESTENABLE, enabled); } -void Gfx_SetAlphaBlending(cc_bool enabled) { - if (gfx_alphaBlending == enabled) return; - gfx_alphaBlending = enabled; - +static void SetAlphaBlend(cc_bool enabled) { if (Gfx.LostContext) return; IDirect3DDevice9_SetRenderState(device, D3DRS_ALPHABLENDENABLE, enabled); } @@ -529,7 +523,7 @@ void Gfx_DepthOnlyRendering(cc_bool depthOnly) { static void D3D9_RestoreRenderStates(void) { union IntAndFloat raw; - IDirect3DDevice9_SetRenderState(device, D3DRS_ALPHATESTENABLE, gfx_alphaTesting); + IDirect3DDevice9_SetRenderState(device, D3DRS_ALPHATESTENABLE, gfx_alphaTest); IDirect3DDevice9_SetRenderState(device, D3DRS_ALPHABLENDENABLE, gfx_alphaBlending); IDirect3DDevice9_SetRenderState(device, D3DRS_FOGENABLE, gfx_fogEnabled); diff --git a/src/Graphics_Dreamcast.c b/src/Graphics_Dreamcast.c index 29f9e3145..7408dad6d 100644 --- a/src/Graphics_Dreamcast.c +++ b/src/Graphics_Dreamcast.c @@ -5,6 +5,7 @@ #include "Logger.h" #include "Window.h" #include "../third_party/gldc/gldc.h" +#include "../third_party/gldc/src/draw.c" #include #include #include @@ -30,6 +31,7 @@ static void InitGLState(void) { void Gfx_Create(void) { if (!Gfx.Created) glKosInit(); + Gfx_SetViewport(0, 0, Game.Width, Game.Height); InitGLState(); @@ -59,7 +61,7 @@ void Gfx_Free(void) { *#########################################################################################################################*/ static PackedCol gfx_clearColor; void Gfx_SetFaceCulling(cc_bool enabled) { gl_Toggle(GL_CULL_FACE); } -void Gfx_SetAlphaBlending(cc_bool enabled) { gl_Toggle(GL_BLEND); } +static void SetAlphaBlend(cc_bool enabled) { gl_Toggle(GL_BLEND); } void Gfx_SetAlphaArgBlend(cc_bool enabled) { } void Gfx_ClearColor(PackedCol color) { @@ -79,7 +81,7 @@ static void SetColorWrite(cc_bool r, cc_bool g, cc_bool b, cc_bool a) { void Gfx_SetDepthWrite(cc_bool enabled) { glDepthMask(enabled); } void Gfx_SetDepthTest(cc_bool enabled) { gl_Toggle(GL_DEPTH_TEST); } -void Gfx_SetAlphaTest(cc_bool enabled) { gl_Toggle(GL_ALPHA_TEST); } +static void SetAlphaTest(cc_bool enabled) { gl_Toggle(GL_ALPHA_TEST); } void Gfx_DepthOnlyRendering(cc_bool depthOnly) { // don't need a fake second pass in this case @@ -352,7 +354,7 @@ static FogFunc gfx_fogMode = -1; void Gfx_SetFog(cc_bool enabled) { gfx_fogEnabled = enabled; - if (enabled) { glEnable(GL_FOG); } else { glDisable(GL_FOG); } + gl_Toggle(GL_FOG); } void Gfx_SetFogCol(PackedCol color) { @@ -371,7 +373,7 @@ static void UpdateFog(void) { if (gfx_fogMode == FOG_LINEAR) { pvr_fog_table_linear(0.0f, gfx_fogEnd); } else if (gfx_fogMode == FOG_EXP) { - pvr_fog_table_exp(gfx_fogDensity); + pvr_fog_table_exp(gfx_fogDensity); } else if (gfx_fogMode == FOG_EXP2) { pvr_fog_table_exp2(gfx_fogDensity); } @@ -465,15 +467,35 @@ cc_bool Gfx_WarnIfNecessary(void) { *----------------------------------------------------------Drawing--------------------------------------------------------* *#########################################################################################################################*/ #define VB_PTR gfx_vertices +static const void* VERTEX_PTR; +extern void apply_poly_header(PolyHeader* header, PolyList* activePolyList); -static void SetupVertices(int startVertex) { - if (gfx_format == VERTEX_FORMAT_TEXTURED) { - cc_uint32 offset = startVertex * SIZEOF_VERTEX_TEXTURED; - gldcVertexPointer(SIZEOF_VERTEX_TEXTURED, (void*)(VB_PTR + offset)); - } else { - cc_uint32 offset = startVertex * SIZEOF_VERTEX_COLOURED; - gldcVertexPointer(SIZEOF_VERTEX_COLOURED, (void*)(VB_PTR + offset)); +extern Vertex* DrawColouredQuads(const void* src, Vertex* dst, int numQuads); +extern Vertex* DrawTexturedQuads(const void* src, Vertex* dst, int numQuads); + +void DrawQuads(int count) { + if (!count) return; + PolyList* output = _glActivePolyList(); + AlignedVectorHeader* hdr = &output->vector.hdr; + + uint32_t header_required = (hdr->size == 0) || STATE_DIRTY; + // Reserve room for the vertices and header + Vertex* beg = aligned_vector_reserve(&output->vector, hdr->size + (header_required) + count); + + if (header_required) { + apply_poly_header((PolyHeader*)beg, output); + STATE_DIRTY = GL_FALSE; + beg++; + hdr->size += 1; } + Vertex* end; + + if (TEXTURES_ENABLED) { + end = DrawTexturedQuads(VERTEX_PTR, beg, count >> 2); + } else { + end = DrawColouredQuads(VERTEX_PTR, beg, count >> 2); + } + hdr->size += (end - beg); } void Gfx_SetVertexFormat(VertexFormat fmt) { @@ -489,29 +511,33 @@ void Gfx_SetVertexFormat(VertexFormat fmt) { } void Gfx_DrawVb_Lines(int verticesCount) { - SetupVertices(0); + //SetupVertices(0); //glDrawArrays(GL_LINES, 0, verticesCount); } void Gfx_DrawVb_IndexedTris_Range(int verticesCount, int startVertex) { - SetupVertices(startVertex); - glDrawArrays(GL_QUADS, 0, verticesCount); + if (gfx_format == VERTEX_FORMAT_TEXTURED) { + VERTEX_PTR = gfx_vertices + startVertex * SIZEOF_VERTEX_TEXTURED; + } else { + VERTEX_PTR = gfx_vertices + startVertex * SIZEOF_VERTEX_COLOURED; + } + + DrawQuads(verticesCount); } void Gfx_DrawVb_IndexedTris(int verticesCount) { - SetupVertices(0); - + VERTEX_PTR = gfx_vertices; + if (textureOffset) ShiftTextureCoords(verticesCount); - glDrawArrays(GL_QUADS, 0, verticesCount); + DrawQuads(verticesCount); if (textureOffset) UnshiftTextureCoords(verticesCount); } void Gfx_DrawIndexedTris_T2fC4b(int verticesCount, int startVertex) { if (renderingDisabled) return; - cc_uint32 offset = startVertex * SIZEOF_VERTEX_TEXTURED; - gldcVertexPointer(SIZEOF_VERTEX_TEXTURED, (void*)(VB_PTR + offset)); - glDrawArrays(GL_QUADS, 0, verticesCount); + VERTEX_PTR = gfx_vertices + startVertex * SIZEOF_VERTEX_TEXTURED; + DrawQuads(verticesCount); } @@ -550,6 +576,7 @@ void Gfx_ClearBuffers(GfxBuffers buffers) { } void Gfx_EndFrame(void) { + pvr_wait_ready(); glKosSwapBuffers(); if (gfx_minFrameMs) LimitFPS(); } @@ -558,6 +585,11 @@ void Gfx_OnWindowResize(void) { Gfx_SetViewport(0, 0, Game.Width, Game.Height); } +extern float VP_COL_HWIDTH, VP_TEX_HWIDTH; +extern float VP_COL_HHEIGHT, VP_TEX_HHEIGHT; +extern float VP_COL_X_PLUS_HWIDTH, VP_TEX_X_PLUS_HWIDTH; +extern float VP_COL_Y_PLUS_HHEIGHT, VP_TEX_Y_PLUS_HHEIGHT; + void Gfx_SetViewport(int x, int y, int w, int h) { if (x == 0 && y == 0 && w == Game.Width && h == Game.Height) { glDisable(GL_SCISSOR_TEST); @@ -567,5 +599,11 @@ void Gfx_SetViewport(int x, int y, int w, int h) { glViewport(x, y, w, h); glScissor (x, y, w, h); + + VP_COL_HWIDTH = VP_TEX_HWIDTH = w * 0.5f; + VP_COL_HHEIGHT = VP_TEX_HHEIGHT = h * -0.5f; + + VP_COL_X_PLUS_HWIDTH = VP_TEX_X_PLUS_HWIDTH = x + w * 0.5f; + VP_COL_Y_PLUS_HHEIGHT = VP_TEX_Y_PLUS_HHEIGHT = y + h * 0.5f; } #endif diff --git a/src/Graphics_GCWii.c b/src/Graphics_GCWii.c index 923b0cff3..cafd6e886 100644 --- a/src/Graphics_GCWii.c +++ b/src/Graphics_GCWii.c @@ -187,7 +187,7 @@ void Gfx_SetFaceCulling(cc_bool enabled) { GX_SetCullMode(enabled ? GX_CULL_FRONT : GX_CULL_NONE); } -void Gfx_SetAlphaBlending(cc_bool enabled) { +static void SetAlphaBlend(cc_bool enabled) { if (enabled) { GX_SetBlendMode(GX_BM_BLEND, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_CLEAR); } else { @@ -409,7 +409,7 @@ void Gfx_SetFogEnd(float value) { void Gfx_SetFogMode(FogFunc func) { } -void Gfx_SetAlphaTest(cc_bool enabled) { +static void SetAlphaTest(cc_bool enabled) { if (enabled) { GX_SetAlphaCompare(GX_GREATER, 127, GX_AOP_AND, GX_ALWAYS, 0); } else { @@ -560,7 +560,7 @@ static void Draw_ColouredTriangles(int verticesCount, int startVertex) { struct VertexColoured* v = (struct VertexColoured*)gfx_vertices + startVertex + i; GX_Position3f32(v->x, v->y, v->z); - GX_Color4u8(PackedCol_R(v->Col), PackedCol_G(v->Col), PackedCol_B(v->Col), PackedCol_A(v->Col)); + GX_Color1u32(v->Col); } GX_End(); } @@ -572,7 +572,7 @@ static void Draw_TexturedTriangles(int verticesCount, int startVertex) { struct VertexTextured* v = (struct VertexTextured*)gfx_vertices + startVertex + i; GX_Position3f32(v->x, v->y, v->z); - GX_Color4u8(PackedCol_R(v->Col), PackedCol_G(v->Col), PackedCol_B(v->Col), PackedCol_A(v->Col)); + GX_Color1u32(v->Col); GX_TexCoord2f32(v->U, v->V); } GX_End(); diff --git a/src/Graphics_GL1.c b/src/Graphics_GL1.c index ea26aa58a..97ade43cc 100644 --- a/src/Graphics_GL1.c +++ b/src/Graphics_GL1.c @@ -534,7 +534,7 @@ void Gfx_SetFogMode(FogFunc func) { gfx_fogMode = func; } -void Gfx_SetAlphaTest(cc_bool enabled) { +static void SetAlphaTest(cc_bool enabled) { if (enabled) { glEnable(GL_ALPHA_TEST); } else { glDisable(GL_ALPHA_TEST); } } diff --git a/src/Graphics_GL2.c b/src/Graphics_GL2.c index e1aa6c6dc..6edfc67d9 100644 --- a/src/Graphics_GL2.c +++ b/src/Graphics_GL2.c @@ -202,7 +202,7 @@ void Gfx_SetDynamicVbData(GfxResourceID vb, void* vertices, int vCount) { /* cached uniforms (cached for multiple programs */ static struct Matrix _view, _proj, _mvp; -static cc_bool gfx_alphaTest, gfx_texTransform; +static cc_bool gfx_texTransform; static float _texX, _texY; static PackedCol gfx_fogColor; static float gfx_fogEnd = -1.0f, gfx_fogDensity = -1.0f; @@ -500,7 +500,7 @@ void Gfx_SetFogMode(FogFunc func) { SwitchProgram(); } -void Gfx_SetAlphaTest(cc_bool enabled) { gfx_alphaTest = enabled; SwitchProgram(); } +static void SetAlphaTest(cc_bool enabled) { SwitchProgram(); } void Gfx_DepthOnlyRendering(cc_bool depthOnly) { cc_bool enabled = !depthOnly; diff --git a/src/Graphics_N64.c b/src/Graphics_N64.c index 1b26f0458..b895cb94b 100644 --- a/src/Graphics_N64.c +++ b/src/Graphics_N64.c @@ -237,7 +237,7 @@ void Gfx_DisableMipmaps(void) { } *-----------------------------------------------------State management----------------------------------------------------* *#########################################################################################################################*/ void Gfx_SetFaceCulling(cc_bool enabled) { gl_Toggle(GL_CULL_FACE); } -void Gfx_SetAlphaBlending(cc_bool enabled) { gl_Toggle(GL_BLEND); } +static void SetAlphaBlend(cc_bool enabled) { gl_Toggle(GL_BLEND); } void Gfx_SetAlphaArgBlend(cc_bool enabled) { } static void SetColorWrite(cc_bool r, cc_bool g, cc_bool b, cc_bool a) { @@ -377,7 +377,7 @@ void Gfx_SetFogEnd(float value) { void Gfx_SetFogMode(FogFunc func) { } -void Gfx_SetAlphaTest(cc_bool enabled) { +static void SetAlphaTest(cc_bool enabled) { if (enabled) { glEnable(GL_ALPHA_TEST); } else { glDisable(GL_ALPHA_TEST); } } diff --git a/src/Graphics_NDS.c b/src/Graphics_NDS.c index ba081eaa5..d01cb0929 100644 --- a/src/Graphics_NDS.c +++ b/src/Graphics_NDS.c @@ -176,7 +176,7 @@ void Gfx_SetFaceCulling(cc_bool enabled) { glPolyFmt(POLY_ALPHA(31) | (enabled ? POLY_CULL_BACK : POLY_CULL_NONE)); } -void Gfx_SetAlphaBlending(cc_bool enabled) { +static void SetAlphaBlend(cc_bool enabled) { /*if (enabled) { glEnable(GL_BLEND); } else { @@ -376,7 +376,7 @@ void Gfx_SetFogEnd(float value) { void Gfx_SetFogMode(FogFunc func) { } -void Gfx_SetAlphaTest(cc_bool enabled) { +static void SetAlphaTest(cc_bool enabled) { if (enabled) { //glEnable(GL_ALPHA_TEST); } else { diff --git a/src/Graphics_PS1.c b/src/Graphics_PS1.c index ce21f156d..14ffbfacc 100644 --- a/src/Graphics_PS1.c +++ b/src/Graphics_PS1.c @@ -36,6 +36,9 @@ static RenderBuffer buffers[2]; static cc_uint8* next_packet; static int active_buffer; static RenderBuffer* buffer; +static cc_bool rendering2D; +static void* lastPoly; +static cc_bool cullingEnabled; static void OnBufferUpdated(void) { buffer = &buffers[active_buffer]; @@ -100,7 +103,7 @@ void Gfx_FreeState(void) { void Gfx_Create(void) { Gfx.MaxTexWidth = 128; - Gfx.MaxTexHeight = 128; + Gfx.MaxTexHeight = 256; Gfx.Created = true; Gfx_RestoreState(); @@ -126,30 +129,41 @@ void Gfx_Free(void) { // VRAM can be divided into texture pages // 32 texture pages total - each page is 64 x 256 // 10 texture pages are occupied by the doublebuffered display -// 22 texture packs are usable, and are then divided into -// - 4 pages for 256 wide textures, 8 for 128 wide, 10 for 64 -#define TPAGE_START_HOR 5 -#define TPAGES_PER_HALF 16 - +// 22 texture pages are usable for textures +// These 22 pages are then divided into: +// - 5 for 128+ wide horizontal, 6 otherwise +// - 11 pages for vertical textures #define TPAGE_WIDTH 64 #define TPAGE_HEIGHT 256 -#define MAX_TEX_PAGES 22 -static cc_uint8 vram_used[(MAX_TEX_PAGES * TPAGE_HEIGHT) / 8]; +#define TPAGES_PER_HALF 16 +// Horizontally oriented textures (first group of 16) +#define TPAGE_START_HOR 5 +#define MAX_HOR_TEX_PAGES 11 +#define MAX_HOR_TEX_LINES (MAX_HOR_TEX_PAGES * TPAGE_HEIGHT) + +// Horizontally oriented textures (second group of 16) +#define TPAGE_START_VER (16 + 5) +#define MAX_VER_TEX_PAGES 11 +#define MAX_VER_TEX_LINES (MAX_VER_TEX_PAGES * TPAGE_WIDTH) + +static cc_uint8 vram_used[(MAX_HOR_TEX_LINES + MAX_VER_TEX_LINES) / 8]; #define VRAM_SetUsed(line) (vram_used[(line) / 8] |= (1 << ((line) % 8))) #define VRAM_UnUsed(line) (vram_used[(line) / 8] &= ~(1 << ((line) % 8))) #define VRAM_IsUsed(line) (vram_used[(line) / 8] & (1 << ((line) % 8))) -static void VRAM_GetBlockRange(int width, int* beg, int* end) { - if (width >= 256) { - *beg = 0; - *end = 4 * TPAGE_HEIGHT; +#define VRAM_BoundingAxis(width, height) height > width ? width : height + +static void VRAM_GetBlockRange(int width, int height, int* beg, int* end) { + if (height > width) { + *beg = MAX_HOR_TEX_LINES; + *end = MAX_HOR_TEX_LINES + MAX_VER_TEX_LINES; } else if (width >= 128) { - *beg = 4 * TPAGE_HEIGHT; - *end = 12 * TPAGE_HEIGHT; + *beg = 0; + *end = 5 * TPAGE_HEIGHT; } else { - *beg = 12 * TPAGE_HEIGHT; - *end = 22 * TPAGE_HEIGHT; + *beg = 5 * TPAGE_HEIGHT; + *end = MAX_HOR_TEX_LINES; } } @@ -163,7 +177,7 @@ static cc_bool VRAM_IsRangeFree(int beg, int end) { static int VRAM_FindFreeBlock(int width, int height) { int beg, end; - VRAM_GetBlockRange(width, &beg, &end); + VRAM_GetBlockRange(width, height, &beg, &end); // TODO kinda inefficient for (int i = beg; i < end - height; i++) @@ -175,13 +189,41 @@ static int VRAM_FindFreeBlock(int width, int height) { return -1; } +static void VRAM_AllocBlock(int line, int width, int height) { + int lines = VRAM_BoundingAxis(width, height); + for (int i = line; i < line + lines; i++) + { + VRAM_SetUsed(i); + } +} + +static void VRAM_FreeBlock(int line, int width, int height) { + int lines = VRAM_BoundingAxis(width, height); + for (int i = line; i < line + lines; i++) + { + VRAM_UnUsed(i); + } +} + +static int VRAM_CalcPage(int line) { + if (line < MAX_HOR_TEX_LINES) { + return TPAGE_START_HOR + (line / TPAGE_HEIGHT); + } else { + line -= MAX_HOR_TEX_LINES; + return TPAGE_START_VER + (line / TPAGE_WIDTH); + } +} + + #define TEXTURES_MAX_COUNT 64 typedef struct GPUTexture { cc_uint16 width, height; + cc_uint8 width_mask, height_mask; cc_uint16 line, tpage; + cc_uint8 xOffset, yOffset; } GPUTexture; static GPUTexture textures[TEXTURES_MAX_COUNT]; -static GPUTexture* active_tex; +static GPUTexture* curTex; #define BGRA8_to_PS1(src) \ ((src[2] & 0xF8) >> 3) | ((src[1] & 0xF8) << 2) | ((src[0] & 0xF8) << 7) | ((src[3] & 0x80) << 8) @@ -205,28 +247,30 @@ static void* AllocTextureAt(int i, struct Bitmap* bmp, int rowWidth) { int line = VRAM_FindFreeBlock(bmp->width, bmp->height); if (line == -1) { Mem_Free(tmp); return NULL; } - tex->width = bmp->width; - tex->height = bmp->height; + tex->width = bmp->width; tex->width_mask = bmp->width - 1; + tex->height = bmp->height; tex->height_mask = bmp->height - 1; tex->line = line; - int page = TPAGE_START_HOR + (line / TPAGE_HEIGHT); - // In bottom half of VRAM? Need to offset horizontally again - if (page >= TPAGES_PER_HALF) page += TPAGE_START_HOR; - - int pageX = (page % TPAGES_PER_HALF); - int pageY = (page / TPAGES_PER_HALF); - - for (int i = tex->line; i < tex->line + tex->height; i++) - { - VRAM_SetUsed(i); - } + int page = VRAM_CalcPage(line); + int pageX = (page % TPAGES_PER_HALF); + int pageY = (page / TPAGES_PER_HALF); tex->tpage = (2 << 7) | (pageY << 4) | pageX; + + VRAM_AllocBlock(line, bmp->width, bmp->height); + if (bmp->height > bmp->width) { + tex->xOffset = line % TPAGE_WIDTH; + tex->yOffset = 0; + } else { + tex->xOffset = 0; + tex->yOffset = line % TPAGE_HEIGHT; + } + Platform_Log3("%i x %i = %i", &bmp->width, &bmp->height, &line); Platform_Log3(" at %i (%i, %i)", &page, &pageX, &pageY); RECT rect; - rect.x = pageX * TPAGE_WIDTH; - rect.y = pageY * TPAGE_HEIGHT + (line % TPAGE_HEIGHT); + rect.x = pageX * TPAGE_WIDTH + tex->xOffset; + rect.y = pageY * TPAGE_HEIGHT + tex->yOffset; rect.w = bmp->width; rect.h = bmp->height; @@ -251,7 +295,7 @@ static GfxResourceID Gfx_AllocTexture(struct Bitmap* bmp, int rowWidth, cc_uint8 void Gfx_BindTexture(GfxResourceID texId) { if (!texId) texId = white_square; - active_tex = (GPUTexture*)texId; + curTex = (GPUTexture*)texId; } void Gfx_DeleteTexture(GfxResourceID* texId) { @@ -259,10 +303,7 @@ void Gfx_DeleteTexture(GfxResourceID* texId) { if (!data) return; GPUTexture* tex = (GPUTexture*)data; - for (int i = tex->line; i < tex->line + tex->height; i++) - { - VRAM_UnUsed(i); - } + VRAM_FreeBlock(tex->line, tex->width, tex->height); tex->width = 0; tex->height = 0; *texId = NULL; } @@ -285,13 +326,13 @@ void Gfx_SetFogEnd(float value) { } void Gfx_SetFogMode(FogFunc func) { } void Gfx_SetFaceCulling(cc_bool enabled) { - // TODO + cullingEnabled = enabled; } -void Gfx_SetAlphaTest(cc_bool enabled) { +static void SetAlphaTest(cc_bool enabled) { } -void Gfx_SetAlphaBlending(cc_bool enabled) { +static void SetAlphaBlend(cc_bool enabled) { } void Gfx_SetAlphaArgBlend(cc_bool enabled) { } @@ -530,8 +571,77 @@ static void Transform(Vec3* result, struct VertexTextured* a, const struct Matri } cc_bool VERTEX_LOGGING; -static void DrawColouredQuads(int verticesCount, int startVertex) { + +static void DrawColouredQuads2D(int verticesCount, int startVertex) { return; + for (int i = 0; i < verticesCount; i += 4) + { + struct VertexColoured* v = (struct VertexColoured*)gfx_vertices + startVertex + i; + + POLY_F4* poly = new_primitive(sizeof(POLY_F4)); + setPolyF4(poly); + + poly->x0 = v[1].x; poly->y0 = v[1].y; + poly->x1 = v[0].x; poly->y1 = v[0].y; + poly->x2 = v[2].x; poly->y2 = v[2].y; + poly->x3 = v[3].x; poly->y3 = v[3].y; + + poly->r0 = PackedCol_R(v->Col); + poly->g0 = PackedCol_G(v->Col); + poly->b0 = PackedCol_B(v->Col); + + if (lastPoly) { + setaddr(poly, getaddr(lastPoly)); setaddr(lastPoly, poly); + } else { + addPrim(&buffer->ot[0], poly); + } + lastPoly = poly; + } +} + +static void DrawTexturedQuads2D(int verticesCount, int startVertex) { + int uOffset = curTex->xOffset, vOffset = curTex->yOffset; + + for (int i = 0; i < verticesCount; i += 4) + { + struct VertexTextured* v = (struct VertexTextured*)gfx_vertices + startVertex + i; + + POLY_FT4* poly = new_primitive(sizeof(POLY_FT4)); + setPolyFT4(poly); + poly->tpage = curTex->tpage; + poly->clut = 0; + + // TODO & instead of % + poly->x0 = v[1].x; poly->y0 = v[1].y; + poly->x1 = v[0].x; poly->y1 = v[0].y; + poly->x2 = v[2].x; poly->y2 = v[2].y; + poly->x3 = v[3].x; poly->y3 = v[3].y; + + poly->u0 = ((int)(v[1].U * 0.99f * curTex->width) & curTex->width_mask) + uOffset; + poly->v0 = ((int)(v[1].V * curTex->height) & curTex->height_mask) + vOffset; + poly->u1 = ((int)(v[0].U * 0.99f * curTex->width) & curTex->width_mask) + uOffset; + poly->v1 = ((int)(v[0].V * curTex->height) & curTex->height_mask) + vOffset; + poly->u2 = ((int)(v[2].U * 0.99f * curTex->width) & curTex->width_mask) + uOffset; + poly->v2 = ((int)(v[2].V * curTex->height) & curTex->height_mask) + vOffset; + poly->u3 = ((int)(v[3].U * 0.99f * curTex->width) & curTex->width_mask) + uOffset; + poly->v3 = ((int)(v[3].V * curTex->height) & curTex->height_mask) + vOffset; + + // https://problemkaputt.de/psxspx-gpu-rendering-attributes.htm + // "For untextured graphics, 8bit RGB values of FFh are brightest. However, for texture blending, 8bit values of 80h are brightest" + poly->r0 = PackedCol_R(v->Col) >> 1; + poly->g0 = PackedCol_G(v->Col) >> 1; + poly->b0 = PackedCol_B(v->Col) >> 1; + + if (lastPoly) { + setaddr(poly, getaddr(lastPoly)); setaddr(lastPoly, poly); + } else { + addPrim(&buffer->ot[0], poly); + } + lastPoly = poly; + } +} + +static void DrawColouredQuads3D(int verticesCount, int startVertex) { for (int i = 0; i < verticesCount; i += 4) { struct VertexColoured* v = (struct VertexColoured*)gfx_vertices + startVertex + i; @@ -567,8 +677,8 @@ static void DrawColouredQuads(int verticesCount, int startVertex) { } } -static void DrawTexturedQuads(int verticesCount, int startVertex) { - int pageOffset = active_tex->line % TPAGE_HEIGHT; +static void DrawTexturedQuads3D(int verticesCount, int startVertex) { + int uOffset = curTex->xOffset, vOffset = curTex->yOffset; for (int i = 0; i < verticesCount; i += 4) { @@ -576,7 +686,7 @@ static void DrawTexturedQuads(int verticesCount, int startVertex) { POLY_FT4* poly = new_primitive(sizeof(POLY_FT4)); setPolyFT4(poly); - poly->tpage = active_tex->tpage; + poly->tpage = curTex->tpage; poly->clut = 0; Vec3 coords[4]; @@ -586,12 +696,28 @@ static void DrawTexturedQuads(int verticesCount, int startVertex) { Transform(&coords[3], &v[3], &mvp); // TODO & instead of % - poly->x0 = coords[1].x; poly->y0 = coords[1].y; poly->u0 = (int)(v[1].U * active_tex->width) % active_tex->width; poly->v0 = ((int)(v[1].V * active_tex->height) % active_tex->height) + pageOffset; - poly->x1 = coords[0].x; poly->y1 = coords[0].y; poly->u1 = (int)(v[0].U * active_tex->width) % active_tex->width; poly->v1 = ((int)(v[0].V * active_tex->height) % active_tex->height) + pageOffset; - poly->x2 = coords[2].x; poly->y2 = coords[2].y; poly->u2 = (int)(v[2].U * active_tex->width) % active_tex->width; poly->v2 = ((int)(v[2].V * active_tex->height) % active_tex->height) + pageOffset; - poly->x3 = coords[3].x; poly->y3 = coords[3].y; poly->u3 = (int)(v[3].U * active_tex->width) % active_tex->width; poly->v3 = ((int)(v[3].V * active_tex->height) % active_tex->height) + pageOffset; - - //int P = active_tex->height, page = poly->tpage & 0xFF, ll = active_tex->line % TPAGE_HEIGHT; + poly->x0 = coords[1].x; poly->y0 = coords[1].y; + poly->x1 = coords[0].x; poly->y1 = coords[0].y; + poly->x2 = coords[2].x; poly->y2 = coords[2].y; + poly->x3 = coords[3].x; poly->y3 = coords[3].y; + + if (cullingEnabled) { + // https://gamedev.stackexchange.com/questions/203694/how-to-make-backface-culling-work-correctly-in-both-orthographic-and-perspective + int signA = (poly->x0 - poly->x1) * (poly->y2 - poly->y1); + int signB = (poly->x2 - poly->x1) * (poly->y0 - poly->y1); + if (signA > signB) continue; + } + + poly->u0 = ((int)(v[1].U * curTex->width) & curTex->width_mask) + uOffset; + poly->v0 = ((int)(v[1].V * curTex->height) & curTex->height_mask) + vOffset; + poly->u1 = ((int)(v[0].U * curTex->width) & curTex->width_mask) + uOffset; + poly->v1 = ((int)(v[0].V * curTex->height) & curTex->height_mask) + vOffset; + poly->u2 = ((int)(v[2].U * curTex->width) & curTex->width_mask) + uOffset; + poly->v2 = ((int)(v[2].V * curTex->height) & curTex->height_mask) + vOffset; + poly->u3 = ((int)(v[3].U * curTex->width) & curTex->width_mask) + uOffset; + poly->v3 = ((int)(v[3].V * curTex->height) & curTex->height_mask) + vOffset; + + //int P = curTex->height, page = poly->tpage & 0xFF, ll = curTex->yOffset; //Platform_Log4("XYZ: %f3 x %i, %i, %i", &v[0].V, &P, &page, &ll); int p = (coords[0].z + coords[1].z + coords[2].z + coords[3].z) / 4; if (p < 0 || p >= OT_LENGTH) continue; @@ -600,9 +726,9 @@ static void DrawTexturedQuads(int verticesCount, int startVertex) { //if (VERTEX_LOGGING) Platform_Log3("IN: %i, %i, %i", &X, &Y, &Z); X = poly->x1; Y = poly->y1, Z = coords[0].z; - poly->r0 = PackedCol_R(v->Col); - poly->g0 = PackedCol_G(v->Col); - poly->b0 = PackedCol_B(v->Col); + poly->r0 = PackedCol_R(v->Col) >> 1; + poly->g0 = PackedCol_G(v->Col) >> 1; + poly->b0 = PackedCol_B(v->Col) >> 1; //if (VERTEX_LOGGING) Platform_Log4("OUT: %i, %i, %i (%i)", &X, &Y, &Z, &p); // TODO: 2D shouldn't use AddPrim, draws in the wrong way @@ -678,24 +804,29 @@ static void DrawTexturedQuads(int verticesCount, int startVertex) { } }*/ -void Gfx_DrawVb_IndexedTris_Range(int verticesCount, int startVertex) { - if (gfx_format == VERTEX_FORMAT_TEXTURED) { - DrawTexturedQuads(verticesCount, startVertex); +static void DrawQuads(int verticesCount, int startVertex) { + if (rendering2D && gfx_format == VERTEX_FORMAT_TEXTURED) { + DrawTexturedQuads2D(verticesCount, startVertex); + } else if (rendering2D) { + DrawColouredQuads2D(verticesCount, startVertex); + } else if (gfx_format == VERTEX_FORMAT_TEXTURED) { + DrawTexturedQuads3D(verticesCount, startVertex); } else { - DrawColouredQuads(verticesCount, startVertex); + DrawColouredQuads3D(verticesCount, startVertex); } } + +void Gfx_DrawVb_IndexedTris_Range(int verticesCount, int startVertex) { + DrawQuads(verticesCount, startVertex); +} + void Gfx_DrawVb_IndexedTris(int verticesCount) { - if (gfx_format == VERTEX_FORMAT_TEXTURED) { - DrawTexturedQuads(verticesCount, 0); - } else { - DrawColouredQuads(verticesCount, 0); - } + DrawQuads(verticesCount, 0); } void Gfx_DrawIndexedTris_T2fC4b(int verticesCount, int startVertex) { - DrawTexturedQuads(verticesCount, startVertex); + DrawTexturedQuads3D(verticesCount, startVertex); } @@ -711,6 +842,7 @@ cc_bool Gfx_WarnIfNecessary(void) { } void Gfx_BeginFrame(void) { + lastPoly = NULL; } void Gfx_EndFrame(void) { @@ -735,4 +867,14 @@ void Gfx_GetApiInfo(cc_string* info) { } cc_bool Gfx_TryRestoreContext(void) { return true; } + +void Gfx_Begin2D(int width, int height) { + rendering2D = true; + Gfx_SetAlphaBlending(true); +} + +void Gfx_End2D(void) { + rendering2D = false; + Gfx_SetAlphaBlending(false); +} #endif diff --git a/src/Graphics_PS2.c b/src/Graphics_PS2.c index 383bd8677..917d4641d 100644 --- a/src/Graphics_PS2.c +++ b/src/Graphics_PS2.c @@ -243,8 +243,6 @@ void Gfx_DisableMipmaps(void) { } *------------------------------------------------------State management---------------------------------------------------* *#########################################################################################################################*/ static int clearR, clearG, clearB; -static cc_bool gfx_alphaBlend; -static cc_bool gfx_alphaTest; static cc_bool gfx_depthTest; static cc_bool stateDirty; @@ -274,13 +272,11 @@ void Gfx_SetFaceCulling(cc_bool enabled) { // TODO } -void Gfx_SetAlphaTest(cc_bool enabled) { - gfx_alphaTest = enabled; - stateDirty = true; +static void SetAlphaTest(cc_bool enabled) { + stateDirty = true; } -void Gfx_SetAlphaBlending(cc_bool enabled) { - gfx_alphaBlend = enabled; +static void SetAlphaBlend(cc_bool enabled) { // TODO update primitive state } diff --git a/src/Graphics_PS3.c b/src/Graphics_PS3.c index 3283ba3dc..773bd73f0 100644 --- a/src/Graphics_PS3.c +++ b/src/Graphics_PS3.c @@ -286,7 +286,7 @@ void Gfx_SetFaceCulling(cc_bool enabled) { rsxSetCullFaceEnable(context, enabled); } -void Gfx_SetAlphaBlending(cc_bool enabled) { +static void SetAlphaBlend(cc_bool enabled) { rsxSetBlendEnable(context, enabled); } void Gfx_SetAlphaArgBlend(cc_bool enabled) { } @@ -316,7 +316,7 @@ void Gfx_SetDepthTest(cc_bool enabled) { UpdateDepthState(); } -void Gfx_SetAlphaTest(cc_bool enabled) { +static void SetAlphaTest(cc_bool enabled) { rsxSetAlphaTestEnable(context, enabled); } diff --git a/src/Graphics_PSP.c b/src/Graphics_PSP.c index 82b53a93e..6ed8efc8a 100644 --- a/src/Graphics_PSP.c +++ b/src/Graphics_PSP.c @@ -163,7 +163,7 @@ void Gfx_BindTexture(GfxResourceID texId) { *#########################################################################################################################*/ static PackedCol gfx_clearColor; void Gfx_SetFaceCulling(cc_bool enabled) { GU_Toggle(GU_CULL_FACE); } -void Gfx_SetAlphaBlending(cc_bool enabled) { GU_Toggle(GU_BLEND); } +static void SetAlphaBlend(cc_bool enabled) { GU_Toggle(GU_BLEND); } void Gfx_SetAlphaArgBlend(cc_bool enabled) { } void Gfx_ClearColor(PackedCol color) { @@ -377,7 +377,7 @@ void Gfx_SetFogMode(FogFunc func) { /* TODO: Implemen fake exp/exp2 fog */ } -void Gfx_SetAlphaTest(cc_bool enabled) { GU_Toggle(GU_ALPHA_TEST); } +static void SetAlphaTest(cc_bool enabled) { GU_Toggle(GU_ALPHA_TEST); } void Gfx_DepthOnlyRendering(cc_bool depthOnly) { cc_bool enabled = !depthOnly; diff --git a/src/Graphics_PSVita.c b/src/Graphics_PSVita.c index c96a799b6..1482e4328 100644 --- a/src/Graphics_PSVita.c +++ b/src/Graphics_PSVita.c @@ -8,7 +8,6 @@ // TODO track last frame used on static cc_bool gfx_depthOnly; -static cc_bool gfx_alphaTesting, gfx_alphaBlending; static int frontBufferIndex, backBufferIndex; // Inspired from // https://github.com/xerpi/gxmfun/blob/master/source/main.c @@ -242,11 +241,11 @@ static void FP_SwitchActive(void) { // [normal rendering, blend rendering, no rendering] if (gfx_depthOnly) { index += 2; - } else if (gfx_alphaBlending) { + } else if (gfx_alphaBlend) { index += 1; } - if (gfx_alphaTesting) index += 2 * 3; + if (gfx_alphaTest) index += 2 * 3; FragmentProgram* FP = &FP_list[index]; if (FP == FP_Active) return; @@ -964,13 +963,11 @@ void Gfx_SetFogMode(FogFunc func) { // TODO } -void Gfx_SetAlphaTest(cc_bool enabled) { - gfx_alphaTesting = enabled; +static void SetAlphaTest(cc_bool enabled) { FP_SwitchActive(); } -void Gfx_SetAlphaBlending(cc_bool enabled) { - gfx_alphaBlending = enabled; +static void SetAlphaBlend(cc_bool enabled) { FP_SwitchActive(); } diff --git a/src/Graphics_Saturn.c b/src/Graphics_Saturn.c index 0949fde19..96670d2b2 100644 --- a/src/Graphics_Saturn.c +++ b/src/Graphics_Saturn.c @@ -143,10 +143,10 @@ void Gfx_SetFaceCulling(cc_bool enabled) { // TODO } -void Gfx_SetAlphaTest(cc_bool enabled) { +static void SetAlphaTest(cc_bool enabled) { } -void Gfx_SetAlphaBlending(cc_bool enabled) { +static void SetAlphaBlend(cc_bool enabled) { } void Gfx_SetAlphaArgBlend(cc_bool enabled) { } diff --git a/src/Graphics_SoftGPU.c b/src/Graphics_SoftGPU.c index 5b19f26fe..00e569478 100644 --- a/src/Graphics_SoftGPU.c +++ b/src/Graphics_SoftGPU.c @@ -10,9 +10,6 @@ static struct Bitmap fb_bmp; static float vp_hwidth, vp_hheight; static int sc_maxX, sc_maxY; -static cc_bool alphaBlending; -static cc_bool alphaTest; - static PackedCol* colorBuffer; static PackedCol clearColor; static cc_bool colWrite = true; @@ -115,12 +112,12 @@ void Gfx_SetFaceCulling(cc_bool enabled) { faceCulling = enabled; } -void Gfx_SetAlphaTest(cc_bool enabled) { - alphaTest = enabled; +static void SetAlphaTest(cc_bool enabled) { + /* Uses value from Gfx_SetAlphaTest */ } -void Gfx_SetAlphaBlending(cc_bool enabled) { - alphaBlending = enabled; +static void SetAlphaBlend(cc_bool enabled) { + /* Uses value from Gfx_SetAlphaBlending */ } void Gfx_SetAlphaArgBlend(cc_bool enabled) { } @@ -358,7 +355,7 @@ static void DrawTriangle(Vector4 frag1, Vector4 frag2, Vector4 frag3, for (int x = minX; x <= maxX; x++) { float xx = x + 0.5f; - float ic0 = ((y2 - y3) * (xx - x3) + (x3 - x2) * (yy - y3)) * factor; + float ic0 = ((y2 - y3) * (xx - x3) + (x3 - x2) * (yy - y3)) * factor; if (ic0 < 0 || ic0 > 1) continue; float ic1 = ((y3 - y1) * (xx - x3) + (x1 - x3) * (yy - y3)) * factor; if (ic1 < 0 || ic1 > 1) continue; @@ -391,7 +388,7 @@ static void DrawTriangle(Vector4 frag1, Vector4 frag2, Vector4 frag3, int B = PackedCol_B(fragColor); int A = PackedCol_A(fragColor); - if (alphaBlending) { + if (gfx_alphaBlend) { PackedCol dst = colorBuffer[index]; int dstR = BitmapCol_R(dst); int dstG = BitmapCol_G(dst); @@ -401,7 +398,7 @@ static void DrawTriangle(Vector4 frag1, Vector4 frag2, Vector4 frag3, G = (G * A) / 255 + (dstG * (255 - A)) / 255; B = (B * A) / 255 + (dstB * (255 - A)) / 255; } - if (alphaTest && A < 0x80) continue; + if (gfx_alphaTest && A < 0x80) continue; if (depthWrite) depthBuffer[index] = z; colorBuffer[index] = BitmapCol_Make(R, G, B, 0xFF); diff --git a/src/Graphics_WiiU.c b/src/Graphics_WiiU.c index 899c0a3da..ea565fa6c 100644 --- a/src/Graphics_WiiU.c +++ b/src/Graphics_WiiU.c @@ -31,7 +31,6 @@ static GfxResourceID white_square; static WHBGfxShaderGroup* group; static void InitGfx(void) { - WHBGfxInit(); GX2InitSampler(&sampler, GX2_TEX_CLAMP_MODE_WRAP, GX2_TEX_XY_FILTER_MODE_POINT); WHBGfxLoadGFDShaderGroup(&colorShader, 0, coloured_gsh); @@ -86,7 +85,9 @@ static void Gfx_RestoreState(void) { static GX2Texture* pendingTex; static GfxResourceID Gfx_AllocTexture(struct Bitmap* bmp, int rowWidth, cc_uint8 flags, cc_bool mipmaps) { - GX2Texture* tex = Mem_AllocCleared(1, sizeof(GX2Texture), "GX2 texture"); + GX2Texture* tex = Mem_TryAllocCleared(1, sizeof(GX2Texture)); + if (!tex) return NULL; + // TODO handle out of memory better int width = bmp->width, height = bmp->height; tex->surface.width = width; @@ -99,8 +100,9 @@ static GfxResourceID Gfx_AllocTexture(struct Bitmap* bmp, int rowWidth, cc_uint8 tex->compMap = GX2_COMP_MAP(GX2_SQ_SEL_R, GX2_SQ_SEL_G, GX2_SQ_SEL_B, GX2_SQ_SEL_A); GX2CalcSurfaceSizeAndAlignment(&tex->surface); GX2InitTextureRegs(tex); + tex->surface.image = MEMAllocFromDefaultHeapEx(tex->surface.imageSize, tex->surface.alignment); - // TODO check result + if (!tex->surface.image) { Mem_Free(tex); return NULL; } CopyTextureData(tex->surface.image, tex->surface.pitch << 2, bmp, rowWidth << 2); GX2Invalidate(GX2_INVALIDATE_MODE_CPU_TEXTURE, tex->surface.image, tex->surface.imageSize); @@ -175,16 +177,16 @@ void Gfx_SetFogMode(FogFunc func) { // TODO } -void Gfx_SetAlphaTest(cc_bool enabled) { +static void SetAlphaTest(cc_bool enabled) { GX2SetAlphaTest(enabled, GX2_COMPARE_FUNC_GEQUAL, 0.5f); } -void Gfx_SetAlphaBlending(cc_bool enabled) { +static void SetAlphaBlend(cc_bool enabled) { GX2SetBlendControl(GX2_RENDER_TARGET_0, GX2_BLEND_MODE_SRC_ALPHA, GX2_BLEND_MODE_INV_SRC_ALPHA, GX2_BLEND_COMBINE_MODE_ADD, true, GX2_BLEND_MODE_SRC_ALPHA, GX2_BLEND_MODE_INV_SRC_ALPHA, GX2_BLEND_COMBINE_MODE_ADD); - GX2SetColorControl(GX2_LOGIC_OP_COPY, enabled, FALSE, TRUE); + GX2SetColorControl(GX2_LOGIC_OP_COPY, enabled, FALSE, TRUE); } void Gfx_SetAlphaArgBlend(cc_bool enabled) { @@ -431,12 +433,18 @@ void Gfx_ClearBuffers(GfxBuffers buffers) { } } +static int drc_ticks; void Gfx_EndFrame(void) { GX2ColorBuffer* buf; buf = WHBGfxGetTVColourBuffer(); GX2CopyColorBufferToScanBuffer(buf, GX2_SCAN_TARGET_TV); + + GX2ContextState* state = WHBGfxGetDRCContextState(); + GX2SetContextState(state); + drc_ticks = (drc_ticks + 1) % 200; buf = WHBGfxGetDRCColourBuffer(); + GX2ClearColor(buf, drc_ticks / 200.0f, drc_ticks / 200.0f, drc_ticks / 200.0f, 1.0f); GX2CopyColorBufferToScanBuffer(buf, GX2_SCAN_TARGET_DRC); GX2SwapScanBuffers(); @@ -459,7 +467,10 @@ void Gfx_OnWindowResize(void) { } -void Gfx_SetViewport(int x, int y, int w, int h) { } +void Gfx_SetViewport(int x, int y, int w, int h) { + GX2SetViewport(x, y, w, h, 0.0f, 1.0f); + GX2SetScissor( x, y, w, h); +} void Gfx_3DS_SetRenderScreen1(enum Screen3DS screen) { GX2ContextState* tv_state = WHBGfxGetTVContextState(); @@ -467,4 +478,4 @@ void Gfx_3DS_SetRenderScreen1(enum Screen3DS screen) { GX2SetContextState(screen == TOP_SCREEN ? tv_state : drc_state); } -#endif \ No newline at end of file +#endif diff --git a/src/Graphics_Xbox.c b/src/Graphics_Xbox.c index 5580892bd..6fcdedb51 100644 --- a/src/Graphics_Xbox.c +++ b/src/Graphics_Xbox.c @@ -299,13 +299,13 @@ void Gfx_SetFaceCulling(cc_bool enabled) { void Gfx_SetAlphaArgBlend(cc_bool enabled) { } -void Gfx_SetAlphaBlending(cc_bool enabled) { +static void SetAlphaBlend(cc_bool enabled) { uint32_t* p = pb_begin(); p = pb_push1(p, NV097_SET_BLEND_ENABLE, enabled); pb_end(p); } -void Gfx_SetAlphaTest(cc_bool enabled) { +static void SetAlphaTest(cc_bool enabled) { uint32_t* p = pb_begin(); p = pb_push1(p, NV097_SET_ALPHA_TEST_ENABLE, enabled); pb_end(p); @@ -396,7 +396,6 @@ void Gfx_EndFrame(void) { *----------------------------------------------------------Buffers--------------------------------------------------------* *#########################################################################################################################*/ static cc_uint8* gfx_vertices; -static cc_uint16* gfx_indices; static void* AllocBuffer(int count, int elemSize) { return MmAllocateContiguousMemoryEx(count * elemSize, 0, MAX_RAM_ADDR, 16, PAGE_WRITECOMBINE | PAGE_READWRITE); @@ -410,16 +409,12 @@ static void FreeBuffer(GfxResourceID* buffer) { GfxResourceID Gfx_CreateIb2(int count, Gfx_FillIBFunc fillFunc, void* obj) { - void* ib = AllocBuffer(count, sizeof(cc_uint16)); - if (!ib) Logger_Abort("Failed to allocate memory for index buffer"); - - fillFunc(ib, count, obj); - return ib; + return (void*)1; } -void Gfx_BindIb(GfxResourceID ib) { gfx_indices = ib; } +void Gfx_BindIb(GfxResourceID ib) { } -void Gfx_DeleteIb(GfxResourceID* ib) { FreeBuffer(ib); } +void Gfx_DeleteIb(GfxResourceID* ib) { } static GfxResourceID Gfx_AllocStaticVb(VertexFormat fmt, int count) { @@ -476,6 +471,18 @@ void Gfx_SetFog(cc_bool enabled) { } void Gfx_SetFogCol(PackedCol color) { + int R = PackedCol_R(color); + int G = PackedCol_G(color); + int B = PackedCol_B(color); + int A = PackedCol_A(color); + + uint32_t* p = pb_begin(); + p = pb_push1(p, NV097_SET_FOG_COLOR, + MASK(NV097_SET_FOG_COLOR_RED, R) | + MASK(NV097_SET_FOG_COLOR_GREEN, G) | + MASK(NV097_SET_FOG_COLOR_BLUE, B) | + MASK(NV097_SET_FOG_COLOR_ALPHA, A)); + pb_end(p); } void Gfx_SetFogDensity(float value) { @@ -536,8 +543,8 @@ void Gfx_CalcPerspectiveMatrix(struct Matrix* matrix, float fov, float aspect, f void Gfx_OnWindowResize(void) { } -static struct Vec4 vp_offset = { 320, -240, 8388608, 1 }; -static struct Vec4 vp_scale = { 320, 240, 8388608, 1 }; +static struct Vec4 vp_scale = { 320, -240, 8388608, 1 }; +static struct Vec4 vp_offset = { 320, 240, 8388608, 1 }; static struct Matrix _view, _proj, _mvp; static void UpdateVSConstants(void) { @@ -655,16 +662,16 @@ static void DrawArrays(int mode, int start, int count) { uint32_t *p = pb_begin(); p = pb_push1(p, NV097_SET_BEGIN_END, mode); - // NV097_DRAW_ARRAYS_COUNT is an 8 bit mask, so must be < 256 + // NV097_DRAW_ARRAYS_COUNT is an 8 bit mask, so must be <= 256 while (count > 0) { - int batch_count = min(count, 64); // TODO increase? + int batch_count = min(count, 256); p = pb_push1(p, 0x40000000 | NV097_DRAW_ARRAYS, MASK(NV097_DRAW_ARRAYS_COUNT, (batch_count-1)) | MASK(NV097_DRAW_ARRAYS_START_INDEX, start)); - start += batch_count; + start += batch_count; count -= batch_count; } @@ -676,9 +683,7 @@ void Gfx_DrawVb_Lines(int verticesCount) { DrawArrays(NV097_SET_BEGIN_END_OP_LINES, 0, verticesCount); } -#define MAX_BATCH 120 static void DrawIndexedVertices(int verticesCount, int startVertex) { - // TODO switch to indexed rendering DrawArrays(NV097_SET_BEGIN_END_OP_QUADS, startVertex, verticesCount); } diff --git a/src/Graphics_Xbox360.c b/src/Graphics_Xbox360.c index 745729c02..f657f16ca 100644 --- a/src/Graphics_Xbox360.c +++ b/src/Graphics_Xbox360.c @@ -82,7 +82,7 @@ static void Gfx_FreeState(void) { static void Gfx_RestoreState(void) { InitDefaultResources(); Gfx_SetFaceCulling(false); - Gfx_SetAlphaBlending(false); + SetAlphaBlend(false); Xe_SetAlphaFunc(xe, XE_CMP_GREATER); Xe_SetAlphaRef(xe, 0.5f); @@ -155,11 +155,11 @@ void Gfx_SetFogMode(FogFunc func) { // TODO } -void Gfx_SetAlphaTest(cc_bool enabled) { +static void SetAlphaTest(cc_bool enabled) { Xe_SetAlphaTestEnable(xe, enabled); } -void Gfx_SetAlphaBlending(cc_bool enabled) { +static void SetAlphaBlend(cc_bool enabled) { if (enabled) { Xe_SetBlendControl(xe, XE_BLEND_SRCALPHA, XE_BLENDOP_ADD, XE_BLEND_INVSRCALPHA, diff --git a/src/Gui.c b/src/Gui.c index 06ebef00a..e6f7bd728 100644 --- a/src/Gui.c +++ b/src/Gui.c @@ -249,7 +249,6 @@ void Gui_Remove(struct Screen* s) { void Gui_Add(struct Screen* s, int priority) { struct Screen* existing; - int i; Gui_RemoveCore(s); existing = Gui_GetScreen(priority); diff --git a/src/Gui.h b/src/Gui.h index c9d9cc7b7..cf2fcb330 100644 --- a/src/Gui.h +++ b/src/Gui.h @@ -45,7 +45,7 @@ CC_VAR extern struct _GuiData { float RawHotbarScale, RawChatScale, RawInventoryScale, RawCrosshairScale; GfxResourceID GuiTex, GuiClassicTex, IconsTex, TouchTex; int DefaultLines; - int __unused; + int _unused; float RawTouchScale; /* The highest priority screen that has grabbed input. */ struct Screen* InputGrab; diff --git a/src/HeldBlockRenderer.c b/src/HeldBlockRenderer.c index b0b603ac4..22707f47c 100644 --- a/src/HeldBlockRenderer.c +++ b/src/HeldBlockRenderer.c @@ -43,7 +43,6 @@ static void HeldBlockRenderer_RenderModel(void) { SetHeldModel(model); Vec3_Set(held_entity.ModelScale, 1.0f,1.0f,1.0f); - Gfx_SetAlphaTest(true); Model_RenderArm(model, &held_entity); Gfx_SetAlphaTest(false); } else { diff --git a/src/Http_Worker.c b/src/Http_Worker.c index b7c0a625d..7d60e90ee 100644 --- a/src/Http_Worker.c +++ b/src/Http_Worker.c @@ -41,6 +41,14 @@ static void Http_ParseCookie(struct HttpRequest* req, const cc_string* value) { EntryList_Set(req->cookies, &name, &data, '='); } +static void Http_ParseContentLength(struct HttpRequest* req, const cc_string* value) { + int contentLen = 0; + Convert_ParseInt(value, &contentLen); + + if (contentLen <= 0) return; + req->contentLength = contentLen; +} + /* Parses a HTTP header */ static void Http_ParseHeader(struct HttpRequest* req, const cc_string* line) { static const cc_string httpVersion = String_FromConst("HTTP"); @@ -58,11 +66,11 @@ static void Http_ParseHeader(struct HttpRequest* req, const cc_string* line) { if (String_CaselessEqualsConst(&name, "ETag")) { String_CopyToRawArray(req->etag, &value); } else if (String_CaselessEqualsConst(&name, "Content-Length")) { - Convert_ParseInt(&value, &req->contentLength); + Http_ParseContentLength(req, &value); } else if (String_CaselessEqualsConst(&name, "X-Dropbox-Content-Length")) { /* dropbox stopped returning Content-Length header since switching to chunked transfer */ /* https://www.dropboxforum.com/t5/Discuss-Dropbox-Developer-API/Dropbox-media-can-t-be-access-by-azure-blob/td-p/575458 */ - Convert_ParseInt(&value, &req->contentLength); + Http_ParseContentLength(req, &value); } else if (String_CaselessEqualsConst(&name, "Last-Modified")) { String_CopyToRawArray(req->lastModified, &value); } else if (req->cookies && String_CaselessEqualsConst(&name, "Set-Cookie")) { @@ -496,13 +504,15 @@ static cc_result HttpConnection_Open(struct HttpConnection* conn, const struct H static cc_result HttpConnection_Read(struct HttpConnection* conn, cc_uint8* data, cc_uint32 count, cc_uint32* read) { if (conn->sslCtx) return SSL_Read(conn->sslCtx, data, count, read); + return Socket_Read(conn->socket, data, count, read); } -static cc_result HttpConnection_Write(struct HttpConnection* conn, const cc_uint8* data, cc_uint32 count, cc_uint32* wrote) { +static cc_result HttpConnection_Write(struct HttpConnection* conn, const cc_uint8* data, cc_uint32 count) { if (conn->sslCtx) - return SSL_Write(conn->sslCtx, data, count, wrote); - return Socket_Write(conn->socket, data, count, wrote); + return SSL_WriteAll(conn->sslCtx, data, count); + + return Socket_WriteAll(conn->socket, data, count); } @@ -556,6 +566,7 @@ static cc_result ConnectionPool_Open(struct HttpConnection** conn, const struct *--------------------------------------------------------HttpClient-------------------------------------------------------* *#########################################################################################################################*/ enum HTTP_RESPONSE_STATE { + HTTP_RESPONSE_STATE_INITIAL, HTTP_RESPONSE_STATE_HEADER, HTTP_RESPONSE_STATE_DATA, HTTP_RESPONSE_STATE_CHUNK_HEADER, @@ -581,7 +592,7 @@ struct HttpClientState { }; static void HttpClientState_Reset(struct HttpClientState* state) { - state->state = HTTP_RESPONSE_STATE_HEADER; + state->state = HTTP_RESPONSE_STATE_INITIAL; state->chunked = 0; state->dataLeft = 0; state->autoClose = false; @@ -621,15 +632,13 @@ static void HttpClient_Serialise(struct HttpClientState* state) { static cc_result HttpClient_SendRequest(struct HttpClientState* state) { char inputBuffer[16384]; cc_string inputMsg; - cc_uint32 wrote; String_InitArray(inputMsg, inputBuffer); state->req->meta = &inputMsg; state->req->progress = HTTP_PROGRESS_FETCHING_DATA; HttpClient_Serialise(state); - /* TODO check that wrote is >= inputMsg.length */ - return HttpConnection_Write(state->conn, (cc_uint8*)inputBuffer, inputMsg.length, &wrote); + return HttpConnection_Write(state->conn, (cc_uint8*)inputBuffer, inputMsg.length); } @@ -705,6 +714,9 @@ static cc_result HttpClient_Process(struct HttpClientState* state, char* buffer, while (offset < total) { switch (state->state) { + case HTTP_RESPONSE_STATE_INITIAL: + state->state = HTTP_RESPONSE_STATE_HEADER; + break; case HTTP_RESPONSE_STATE_HEADER: { @@ -833,9 +845,12 @@ static cc_result HttpClient_ParseResponse(struct HttpClientState* state) { { dst = state->dataLeft > INPUT_BUFFER_LEN ? (req->data + req->size) : buffer; res = HttpConnection_Read(state->conn, dst, INPUT_BUFFER_LEN, &total); + if (res) return res; - if (res) return res; - if (total == 0) return ERR_END_OF_STREAM; + if (total == 0) { + Platform_Log1("Http read unexpectedly returned 0 in state %i", &state->state); + return state->state == HTTP_RESPONSE_STATE_INITIAL ? HTTP_ERR_NO_RESPONSE : ERR_END_OF_STREAM; + } if (dst != buffer) { /* When there is more than INPUT_BUFFER_LEN bytes of unread data/content, */ @@ -912,6 +927,11 @@ static cc_result HttpBackend_Do(struct HttpRequest* req, cc_string* urlStr) { res = HttpBackend_PerformRequest(&state); retried = true; } + if (res == HTTP_ERR_NO_RESPONSE && !retried) { + Platform_LogConst("Resetting connection due to empty response.."); + res = HttpBackend_PerformRequest(&state); + retried = true; + } if (res || !HttpClient_IsRedirect(req)) break; if (redirects >= 20) return HTTP_ERR_REDIRECTS; @@ -1278,7 +1298,7 @@ static void PerformRequest(struct HttpRequest* req, cc_string* url) { end = Stopwatch_Measure(); elapsed = Stopwatch_ElapsedMS(beg, end); - Platform_Log4("HTTP: result %i (http %i) in %i ms (%i bytes)", + Platform_Log4("HTTP: result %e (http %i) in %i ms (%i bytes)", &req->result, &req->statusCode, &elapsed, &req->size); Http_FinishRequest(req); diff --git a/src/Input.c b/src/Input.c index 8bc4c4aaa..c49bb8896 100644 --- a/src/Input.c +++ b/src/Input.c @@ -216,7 +216,8 @@ static const char* const storageNames[INPUT_COUNT] = { "Keypad5", "Keypad6", "Keypad7", "Keypad8", "Keypad9", "KeypadDivide", "KeypadMultiply", "KeypadSubtract", "KeypadAdd", "KeypadDecimal", "KeypadEnter", - "XButton1", "XButton2", "LeftMouse", "RightMouse", "MiddleMouse", + "XButton1", "XButton2", "XButton3", "XButton4", "XButton5", "XButton6", + "LeftMouse", "RightMouse", "MiddleMouse", Pad_Names }; @@ -239,7 +240,8 @@ const char* const Input_DisplayNames[INPUT_COUNT] = { "NUMPAD5", "NUMPAD6", "NUMPAD7", "NUMPAD8", "NUMPAD9", "DIVIDE", "MULTIPLY", "SUBTRACT", "ADD", "DECIMAL", "NUMPADENTER", - "XBUTTON1", "XBUTTON2", "LMOUSE", "RMOUSE", "MMOUSE", + "XBUTTON1", "XBUTTON2", "XBUTTON3", "XBUTTON4", "XBUTTON5", "XBUTTON6", + "LMOUSE", "RMOUSE", "MMOUSE", Pad_Names }; @@ -291,6 +293,15 @@ void Input_Clear(void) { ClearTouches(); } +int Input_CalcDelta(int key, int horDelta, int verDelta) { + if (Input_IsLeftButton(key) || key == CCKEY_KP4) return -horDelta; + if (Input_IsRightButton(key) || key == CCKEY_KP6) return +horDelta; + if (Input_IsUpButton(key) || key == CCKEY_KP8) return -verDelta; + if (Input_IsDownButton(key) || key == CCKEY_KP2) return +verDelta; + + return 0; +} + /*########################################################################################################################* *----------------------------------------------------------Mouse----------------------------------------------------------* @@ -418,38 +429,49 @@ static void KeyBind_Init(void) { *---------------------------------------------------------Gamepad---------------------------------------------------------* *#########################################################################################################################*/ #define GAMEPAD_BEG_BTN CCPAD_A +#define GAMEPAD_BTN_COUNT (INPUT_COUNT - GAMEPAD_BEG_BTN) + int Gamepad_AxisBehaviour[2] = { AXIS_BEHAVIOUR_MOVEMENT, AXIS_BEHAVIOUR_CAMERA }; int Gamepad_AxisSensitivity[2] = { AXIS_SENSI_NORMAL, AXIS_SENSI_NORMAL }; static const float axis_sensiFactor[] = { 0.25f, 0.5f, 1.0f, 2.0f, 4.0f }; struct GamepadState { float axisX[2], axisY[2]; - /*cc_bool pressed[INPUT_COUNT - GAMEPAD_BEG_BTN];*/ - float holdtime[INPUT_COUNT - GAMEPAD_BEG_BTN]; + cc_bool pressed[GAMEPAD_BTN_COUNT]; + float holdtime[GAMEPAD_BTN_COUNT]; }; static struct GamepadState gamepads[INPUT_MAX_GAMEPADS]; static void Gamepad_Update(struct GamepadState* pad, float delta) { int btn; - for (btn = GAMEPAD_BEG_BTN; btn < INPUT_COUNT; btn++) + for (btn = 0; btn < GAMEPAD_BTN_COUNT; btn++) { - if (!Input.Pressed[btn]) continue; - pad->holdtime[btn - GAMEPAD_BEG_BTN] += delta; - if (pad->holdtime[btn - GAMEPAD_BEG_BTN] < 1.0f) continue; + if (!pad->pressed[btn]) continue; + pad->holdtime[btn] += delta; + if (pad->holdtime[btn] < 1.0f) continue; /* Held for over a second, trigger a fake press */ - pad->holdtime[btn - GAMEPAD_BEG_BTN] = 0; - Input_SetPressed(btn); + pad->holdtime[btn] = 0; + Input_SetPressed(btn + GAMEPAD_BEG_BTN); } } void Gamepad_SetButton(int port, int btn, int pressed) { struct GamepadState* pad = &gamepads[port]; - /* Reset hold tracking time */ - if (pressed && !Input.Pressed[btn]) pad->holdtime[btn - GAMEPAD_BEG_BTN] = 0; + int i; + btn -= GAMEPAD_BEG_BTN; - Input_SetNonRepeatable(btn, pressed); + /* Reset hold tracking time */ + if (pressed && !pad->pressed[btn]) pad->holdtime[btn] = 0; + pad->pressed[btn] = pressed != 0;; + + /* Set pressed if button pressed on any gamepad, to avoid constant flip flopping */ + /* between pressed and non-pressed when multiple controllers are plugged in */ + for (i = 0; i < INPUT_MAX_GAMEPADS; i++) + pressed |= gamepads[i].pressed[btn]; + + Input_SetNonRepeatable(btn + GAMEPAD_BEG_BTN, pressed); } void Gamepad_SetAxis(int port, int axis, float x, float y, float delta) { @@ -480,7 +502,7 @@ static void PlayerInputPad(int port, int axis, struct LocalPlayer* p, float* xMo y = gamepads[port].axisY[axis]; if (x != 0 || y != 0) { - angle = Math_Atan2(x, y); + angle = Math_Atan2f(x, y); *xMoving = Math_CosF(angle); *zMoving = Math_SinF(angle); } diff --git a/src/Input.h b/src/Input.h index 642090569..d24f778a5 100644 --- a/src/Input.h +++ b/src/Input.h @@ -43,7 +43,8 @@ enum InputButtons { CCKEY_KP_PLUS, CCKEY_KP_DECIMAL, CCKEY_KP_ENTER, /* NOTE: RMOUSE must be before MMOUSE for PlayerClick compatibility */ - CCMOUSE_X1, CCMOUSE_X2, CCMOUSE_L, CCMOUSE_R, CCMOUSE_M, + CCMOUSE_X1, CCMOUSE_X2, CCMOUSE_X3, CCMOUSE_X4, CCMOUSE_X5, CCMOUSE_X6, + CCMOUSE_L, CCMOUSE_R, CCMOUSE_M, CCPAD_A, CCPAD_B, CCPAD_X, CCPAD_Y, CCPAD_L, CCPAD_R, CCPAD_Z, CCPAD_LEFT, CCPAD_RIGHT, CCPAD_UP, CCPAD_DOWN, @@ -106,6 +107,7 @@ void Input_Clear(void); #else #define Input_IsActionPressed() Input_IsCtrlPressed() #endif +int Input_CalcDelta(int btn, int horDelta, int verDelta); #ifdef CC_BUILD_TOUCH diff --git a/src/LBackend.c b/src/LBackend.c index a6032265f..f9683c6af 100644 --- a/src/LBackend.c +++ b/src/LBackend.c @@ -334,6 +334,7 @@ static void OnPointerDown(void* obj, int idx) { struct LScreen* s = Launcher_Active; struct LWidget* over; struct LWidget* prev; + if (Window_Main.SoftKeyboardFocus) return; if (!s) return; over = GetWidgetAt(s, idx); @@ -347,6 +348,7 @@ static void OnPointerUp(void* obj, int idx) { struct LScreen* s = Launcher_Active; struct LWidget* over; struct LWidget* prev; + if (Window_Main.SoftKeyboardFocus) return; if (!s) return; over = GetWidgetAt(s, idx); @@ -367,6 +369,7 @@ static void OnPointerMove(void* obj, int idx) { struct LWidget* over; struct LWidget* prev; cc_bool overSame; + if (Window_Main.SoftKeyboardFocus) return; if (!s) return; over = GetWidgetAt(s, idx); diff --git a/src/LScreens.c b/src/LScreens.c index 676ccb8ac..4d8df2bd6 100644 --- a/src/LScreens.c +++ b/src/LScreens.c @@ -380,14 +380,9 @@ static void ColoursScreen_MouseWheel(struct LScreen* s_, float delta) { } static void ColoursScreen_KeyDown(struct LScreen* s, int key, cc_bool was) { - if (Input_IsLeftButton(key)) { - ColoursScreen_AdjustSelected(s, -1); - } else if (Input_IsRightButton(key)) { - ColoursScreen_AdjustSelected(s, +1); - } else if (Input_IsUpButton(key)) { - ColoursScreen_AdjustSelected(s, +10); - } else if (Input_IsDownButton(key)) { - ColoursScreen_AdjustSelected(s, -10); + int delta = Input_CalcDelta(key, 1, 10); + if (delta) { + ColoursScreen_AdjustSelected(s, delta); } else { LScreen_KeyDown(s, key, was); } @@ -886,6 +881,12 @@ static void MainScreen_ApplyUpdateLabel(struct MainScreen* s) { } } +#ifdef CC_BUILD_CONSOLE +static void MainScreen_ExitApp(void* w) { + Window_Main.Exists = false; +} +#endif + static void MainScreen_Activated(struct LScreen* s_) { struct MainScreen* s = (struct MainScreen*)s_; @@ -909,8 +910,6 @@ static void MainScreen_Activated(struct LScreen* s_) { SwitchToSplitScreen, main_btnSplit); #endif - LLabel_Add(s, &s->lblUpdate, "&eChecking..", - Updater_Supported ? main_lblUpdate_N : main_lblUpdate_H); if (Process_OpenSupported) { LButton_Add(s, &s->btnRegister, 100, 35, "Register", MainScreen_Register, main_btnRegister); @@ -918,10 +917,19 @@ static void MainScreen_Activated(struct LScreen* s_) { LButton_Add(s, &s->btnOptions, 100, 35, "Options", SwitchToSettings, main_btnOptions); + +#ifdef CC_BUILD_CONSOLE + LLabel_Add(s, &s->lblUpdate, "&eChecking..", main_lblUpdate_N); + LButton_Add(s, &s->btnUpdates, 100, 35, "Exit", + MainScreen_ExitApp, main_btnUpdates); +#else + LLabel_Add(s, &s->lblUpdate, "&eChecking..", + Updater_Supported ? main_lblUpdate_N : main_lblUpdate_H); if (Updater_Supported) { LButton_Add(s, &s->btnUpdates, 100, 35, "Updates", SwitchToUpdates, main_btnUpdates); } +#endif s->btnResume.OnHover = MainScreen_ResumeHover; s->btnResume.OnUnhover = MainScreen_ResumeUnhover; diff --git a/src/Launcher.c b/src/Launcher.c index 6c4822bdf..4b1e7f4dc 100644 --- a/src/Launcher.c +++ b/src/Launcher.c @@ -65,8 +65,7 @@ void Launcher_DisplayHttpError(struct HttpRequest* req, const char* action, cc_s if (res) { /* Non HTTP error - this is not good */ Http_LogError(action, req); - String_Format2(dst, res >= 0x80000000 ? "&cError %h when %c" : "&cError %i when %c", - &res, action); + String_Format2(dst, "&cError %e when %c", &res, action); } else if (status != 200) { String_Format2(dst, "&c%i error when %c", &status, action); } else { @@ -272,8 +271,9 @@ void Launcher_Run(void) { #endif for (;;) { - Window_ProcessEvents(10 / 1000.0); - Window_ProcessGamepads(10 / 1000.0); + Window_ProcessEvents(10 / 1000.0f); + Window_ProcessGamepads(10 / 1000.0f); + Gamepad_Tick(10 / 1000.0f); if (!Window_Main.Exists || Launcher_ShouldExit) break; Launcher_Active->Tick(Launcher_Active); @@ -580,4 +580,4 @@ void Launcher_MakeTitleFont(struct FontDesc* font) { Font_Make(font, 32, FONT_FLAGS_NONE); Drawer2D.BitmappedText = false; } -#endif \ No newline at end of file +#endif diff --git a/src/Lighting.c b/src/Lighting.c index 8af48cbeb..80abe11ba 100644 --- a/src/Lighting.c +++ b/src/Lighting.c @@ -7,6 +7,7 @@ #include "Logger.h" #include "Event.h" #include "Game.h" +#include "Options.h" struct _Lighting Lighting; #define Lighting_Pack(x, z) ((x) + World.Width * (z)) @@ -66,6 +67,12 @@ static PackedCol ClassicLighting_Color(int x, int y, int z) { return y > ClassicLighting_GetLightHeight(x, z) ? Env.SunCol : Env.ShadowCol; } +static PackedCol SmoothLighting_Color(int x, int y, int z) { + if (!World_Contains(x, y, z)) return Env.SunCol; + if (Blocks.FullBright[World_GetBlock(x, y, z)]) return Env.SunCol; + return y > ClassicLighting_GetLightHeight(x, z) ? Env.SunCol : Env.ShadowCol; +} + static PackedCol ClassicLighting_Color_XSide(int x, int y, int z) { if (!World_Contains(x, y, z)) return Env.SunXSide; return y > ClassicLighting_GetLightHeight(x, z) ? Env.SunXSide : Env.ShadowXSide; @@ -375,10 +382,13 @@ static void ClassicLighting_AllocState(void) { } static void ClassicLighting_SetActive(void) { + cc_bool smoothLighting = false; + if (!Game_ClassicMode) smoothLighting = Options_GetBool(OPT_SMOOTH_LIGHTING, false); + Lighting.OnBlockChanged = ClassicLighting_OnBlockChanged; Lighting.Refresh = ClassicLighting_Refresh; Lighting.IsLit = ClassicLighting_IsLit; - Lighting.Color = ClassicLighting_Color; + Lighting.Color = smoothLighting ? SmoothLighting_Color : ClassicLighting_Color; Lighting.Color_XSide = ClassicLighting_Color_XSide; Lighting.IsLit_Fast = ClassicLighting_IsLit_Fast; @@ -398,6 +408,10 @@ static void ClassicLighting_SetActive(void) { *---------------------------------------------------Lighting component----------------------------------------------------* *#########################################################################################################################*/ +void Lighting_ApplyActive() { + ClassicLighting_SetActive(); +} + static void OnInit(void) { ClassicLighting_SetActive(); } static void OnReset(void) { Lighting.FreeState(); } static void OnNewMapLoaded(void) { Lighting.AllocState(); } diff --git a/src/Lighting.h b/src/Lighting.h index e8c30f7b2..d8dba2be3 100644 --- a/src/Lighting.h +++ b/src/Lighting.h @@ -49,4 +49,6 @@ CC_VAR extern struct _Lighting { PackedCol (*Color_XSide_Fast)(int x, int y, int z); PackedCol (*Color_ZSide_Fast)(int x, int y, int z); } Lighting; + +void Lighting_ApplyActive(void); #endif diff --git a/src/Logger.c b/src/Logger.c index f4732be8c..9b2d2aa21 100644 --- a/src/Logger.c +++ b/src/Logger.c @@ -126,14 +126,12 @@ static void AppendErrorDesc(cc_string* msg, cc_result res, Logger_DescribeError } void Logger_FormatWarn(cc_string* msg, cc_result res, const char* action, Logger_DescribeError describeErr) { - String_Format2(msg, res < 20000 ? "Error %i when %c" : "Error %h when %c", - &res, action); + String_Format2(msg, "Error %e when %c", &res, action); AppendErrorDesc(msg, res, describeErr); } void Logger_FormatWarn2(cc_string* msg, cc_result res, const char* action, const cc_string* path, Logger_DescribeError describeErr) { - String_Format3(msg, res < 20000 ? "Error %i when %c '%s'" : "Error %h when %c '%s'", - &res, action, path); + String_Format3(msg, "Error %e when %c '%s'", &res, action, path); AppendErrorDesc(msg, res, describeErr); } @@ -508,7 +506,7 @@ static void PrintRegisters(cc_string* str, void* ctx) { #define REG_GET_PC() &r->Pc Dump_ARM32() #elif defined _M_ARM64 - #define REG_GNUM(num) &r->x[num] + #define REG_GNUM(num) &r->X[num] #define REG_GET_FP() &r->Fp #define REG_GET_LR() &r->Lr #define REG_GET_SP() &r->Sp diff --git a/src/Menus.c b/src/Menus.c index f4875120e..768e90216 100644 --- a/src/Menus.c +++ b/src/Menus.c @@ -33,6 +33,7 @@ #include "Utils.h" #include "Errors.h" #include "SystemFonts.h" +#include "Lighting.h" /* Describes a menu option button */ struct MenuOptionDesc { @@ -514,7 +515,7 @@ static void PauseScreen_CheckHacksAllowed(void* screen) { struct PauseScreen* s = (struct PauseScreen*)screen; if (Gui.ClassicMenu) return; - Widget_SetDisabled(&s->btns[4], + Widget_SetDisabled(&s->btns[1], !Entities.CurPlayer->Hacks.CanAnyHacks); /* select texture pack */ s->dirty = true; } @@ -541,11 +542,11 @@ static void PauseScreen_Init(void* screen) { struct PauseScreen* s = (struct PauseScreen*)screen; static const struct SimpleButtonDesc descs[] = { { -160, -50, "Options...", Menu_SwitchOptions }, + { -160, 0, "Change texture pack...", Menu_SwitchTexPacks }, + { -160, 50, "Hotkeys...", Menu_SwitchHotkeys }, { 160, -50, "Generate new level...", Menu_SwitchGenLevel }, { 160, 0, "Load level...", Menu_SwitchLoadLevel }, - { 160, 50, "Save level...", Menu_SwitchSaveLevel }, - { -160, 0, "Change texture pack...", Menu_SwitchTexPacks }, - { -160, 50, "Hotkeys...", Menu_SwitchHotkeys } + { 160, 50, "Save level...", Menu_SwitchSaveLevel } }; s->widgets = pause_widgets; s->numWidgets = 0; @@ -559,8 +560,8 @@ static void PauseScreen_Init(void* screen) { s->maxVertices = Screen_CalcDefaultMaxVertices(s); if (Server.IsSinglePlayer) return; - s->btns[1].flags = WIDGET_FLAG_DISABLED; - s->btns[2].flags = WIDGET_FLAG_DISABLED; + s->btns[3].flags = WIDGET_FLAG_DISABLED; + s->btns[5].flags = WIDGET_FLAG_DISABLED; } static void PauseScreen_Free(void* screen) { @@ -1655,8 +1656,18 @@ static void FontListScreen_LoadEntries(struct ListScreen* s) { ListScreen_Select(s, SysFonts_UNSAFE_GetDefault()); } +static void FontListScreen_RegisterCallback(const cc_string* path) { + Chat_Add1("Loaded font from %s", path); +} + static void FontListScreen_UploadCallback(const cc_string* path) { - SysFonts_Register(path); + cc_result res = SysFonts_Register(path, FontListScreen_RegisterCallback); + + if (res) { + Logger_SimpleWarn2(res, "loading font from", path); + } else { + SysFonts_SaveCache(); + } } static void FontListScreen_ActionFunc(void* s, void* w) { @@ -2862,6 +2873,7 @@ static void GraphicsOptionsScreen_SetViewDist(const cc_string* v) { Game_UserSet static void GraphicsOptionsScreen_GetSmooth(cc_string* v) { Menu_GetBool(v, Builder_SmoothLighting); } static void GraphicsOptionsScreen_SetSmooth(const cc_string* v) { Builder_SmoothLighting = Menu_SetBool(v, OPT_SMOOTH_LIGHTING); + Lighting_ApplyActive(); Builder_ApplyActive(); MapRenderer_Refresh(); } diff --git a/src/Model.c b/src/Model.c index 967a82d58..59d13a37d 100644 --- a/src/Model.c +++ b/src/Model.c @@ -818,6 +818,7 @@ static void CustomModel_DrawArm(struct Entity* e) { struct CustomModel* cm = (struct CustomModel*)Models.Active; int i; if (!cm->numArmParts) return; + Gfx_SetAlphaTest(true); Models.uScale = 1.0f / cm->uScale; Models.vScale = 1.0f / cm->vScale; @@ -952,6 +953,7 @@ static void HumanModel_DrawCore(struct Entity* e, struct ModelSet* model, cc_boo static void HumanModel_DrawArmCore(struct Entity* e, struct ModelSet* model) { struct ModelLimbs* set; int type, num; + Gfx_SetAlphaTest(true); type = Models.skinType; set = &model->limbs[type & 0x3]; @@ -1854,6 +1856,7 @@ static void SkeletonModel_Draw(struct Entity* e) { } static void SkeletonModel_DrawArm(struct Entity* e) { + Gfx_SetAlphaTest(true); Model_LockVB(e, MODEL_BOX_VERTICES); Model_DrawArmPart(&skeleton_rightArm); diff --git a/src/Options.c b/src/Options.c index 1a8dd4257..cc7083870 100644 --- a/src/Options.c +++ b/src/Options.c @@ -201,7 +201,7 @@ void Options_SetSecure(const char* opt, const cc_string* src) { String_InitArray(enc, encData); res = Platform_Encrypt(src->buffer, src->length, &enc); - if (res) { Platform_Log2("Error %h encrypting option %c", &res, opt); return; } + if (res) { Platform_Log2("Error %e encrypting option %c", &res, opt); return; } /* base64 encode the data, as user might edit options.txt with a text editor */ if (enc.length > 1500) Logger_Abort("too large to base64"); @@ -223,5 +223,5 @@ void Options_GetSecure(const char* opt, cc_string* dst) { dataLen = Convert_FromBase64(raw.buffer, raw.length, data); res = Platform_Decrypt(data, dataLen, dst); - if (res) Platform_Log2("Error %h decrypting option %c", &res, opt); + if (res) Platform_Log2("Error %e decrypting option %c", &res, opt); } diff --git a/src/Platform.h b/src/Platform.h index 7c78eb0d6..19b2c1bc4 100644 --- a/src/Platform.h +++ b/src/Platform.h @@ -270,6 +270,8 @@ cc_result Socket_Read(cc_socket s, cc_uint8* data, cc_uint32 count, cc_uint32* m cc_result Socket_Write(cc_socket s, const cc_uint8* data, cc_uint32 count, cc_uint32* modified); /* Attempts to close the given socket */ void Socket_Close(cc_socket s); +/* Attempts to write all data to the given socket, returning ERR_END_OF_STREAM if it could not */ +cc_result Socket_WriteAll(cc_socket socket, const cc_uint8* data, cc_uint32 count); #ifdef CC_BUILD_MOBILE void Platform_ShareScreenshot(const cc_string* filename); diff --git a/src/Platform_N64.c b/src/Platform_N64.c index 99b78f424..81cf6b52a 100644 --- a/src/Platform_N64.c +++ b/src/Platform_N64.c @@ -260,9 +260,6 @@ void Platform_Init(void) { DisableFpuExceptions(); Platform_ReadonlyFilesystem = true; - // TODO: Redesign Drawer2D to better handle this - Options_SetBool(OPT_USE_CHAT_FONT, true); - dfs_init(DFS_DEFAULT_LOCATION); timer_init(); rtc_init(); diff --git a/src/Platform_NDS.c b/src/Platform_NDS.c index 5b3420350..b0194b3cd 100644 --- a/src/Platform_NDS.c +++ b/src/Platform_NDS.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -66,17 +67,18 @@ cc_uint64 Stopwatch_Measure(void) { static void LogNocash(const char* msg, int len) { // Can only be up to 120 bytes total char buffer[120]; - len = min(len, 119); + len = min(len, 118); Mem_Copy(buffer, msg, len); - buffer[len] = '\n'; - nocashWrite(buffer, len + 1); + buffer[len + 0] = '\n'; + buffer[len + 1] = '\0'; + nocashWrite(buffer, len + 2); } extern void consolePrintString(const char* ptr, int len); void Platform_Log(const char* msg, int len) { LogNocash(msg, len); - if (!keyboardOpen) consolePrintString(msg, len); + consolePrintString(msg, len); } TimeMS DateTime_CurrentUTC(void) { @@ -108,16 +110,17 @@ static bool fat_available; static void GetNativePath(char* str, const cc_string* path) { Mem_Copy(str, root_path.buffer, root_path.length); - str += root_path.length; + str += root_path.length; String_EncodeUtf8(str, path); - Platform_Log1("Open %c", str - root_path.length); } cc_result Directory_Create(const cc_string* path) { - if (!fat_available) return ENOSYS; - + if (!fat_available) return 0; + char str[NATIVE_STR_LEN]; GetNativePath(str, path); + Platform_Log1("mkdir %c", str); + return mkdir(str, 0) == -1 ? errno : 0; } @@ -127,6 +130,8 @@ int File_Exists(const cc_string* path) { char str[NATIVE_STR_LEN]; struct stat sb; GetNativePath(str, path); + Platform_Log1("Check %c", str); + return stat(str, &sb) == 0 && S_ISREG(sb.st_mode); } @@ -137,6 +142,8 @@ cc_result Directory_Enum(const cc_string* dirPath, void* obj, Directory_EnumCall static cc_result File_Do(cc_file* file, const cc_string* path, int mode) { char str[NATIVE_STR_LEN]; GetNativePath(str, path); + Platform_Log1("Open %c", str); + *file = open(str, mode, 0); return *file == -1 ? errno : 0; } @@ -186,24 +193,36 @@ cc_result File_Length(cc_file file, cc_uint32* len) { *len = st.st_size; return 0; } +static int LoadFatFilesystem(void* arg) { + fat_available = fatInitDefault(); + return 0; +} + static void InitFilesystem(void) { - // I don't know why I have to call this function, but if I don't, - // then when running in DSi mode AND an SD card is readable, - // fatInitDefault gets stuck somewhere (in disk_initialize it seems) - if (isDSiMode()) { - const DISC_INTERFACE* sd_io = get_io_dsisd(); - if (sd_io) sd_io->startup(); + cothread_t thread = cothread_create(LoadFatFilesystem, NULL, 0, 0); + // If running with DSi mode in melonDS and the internal SD card is enabled, then + // fatInitDefault gets stuck in sdmmc_ReadSectors - because the fifoWaitValue32Async will never return + // (You can tell when this happens - "MMC: unknown CMD 17 00000000" is logged to console) + // However, since it does yield to cothreads, workaround this by running fatInitDefault on another thread + // and then giving up if it takes too long.. not the most elegant solution, but it does work + if (thread == -1) { + LoadFatFilesystem(NULL); + } else { + for (int i = 0; i < 100; i++) + { + cothread_yield(); + if (cothread_has_joined(thread)) break; + + swiDelay(2000); + } } - fat_available = fatInitDefault(); - Platform_ReadonlyFilesystem = !fat_available; - if (!fat_available) return; - char* dir = fatGetDefaultCwd(); - if (dir && dir[0]) { + if (dir) { root_path.buffer = dir; root_path.length = String_Length(dir); } + Platform_ReadonlyFilesystem = !fat_available; } @@ -406,9 +425,6 @@ void Platform_Init(void) { InitNetworking(); cpuStartTiming(1); - // TODO: Redesign Drawer2D to better handle this - Options_Load(); - Options_SetBool(OPT_USE_CHAT_FONT, true); } void Platform_Free(void) { } diff --git a/src/Platform_PS1.c b/src/Platform_PS1.c index e076d2fff..f4ad6f5a4 100644 --- a/src/Platform_PS1.c +++ b/src/Platform_PS1.c @@ -227,8 +227,6 @@ cc_result Socket_CheckWritable(cc_socket s, cc_bool* writable) { void Platform_Init(void) { ResetGraph(0); Stopwatch_Init(); - - Options_SetBool(OPT_USE_CHAT_FONT, true); } void Platform_Free(void) { } diff --git a/src/Platform_Posix.c b/src/Platform_Posix.c index 83942ef16..5a95592ee 100644 --- a/src/Platform_Posix.c +++ b/src/Platform_Posix.c @@ -497,7 +497,7 @@ void Waitable_WaitFor(void* handle, cc_uint32 milliseconds) { *--------------------------------------------------------Font/Text--------------------------------------------------------* *#########################################################################################################################*/ static void FontDirCallback(const cc_string* path, void* obj) { - SysFonts_Register(path); + SysFonts_Register(path, NULL); } void Platform_LoadSysFonts(void) { diff --git a/src/Platform_Saturn.c b/src/Platform_Saturn.c index 82033c116..a39079407 100644 --- a/src/Platform_Saturn.c +++ b/src/Platform_Saturn.c @@ -213,8 +213,6 @@ cc_result Socket_CheckWritable(cc_socket s, cc_bool* writable) { *#########################################################################################################################*/ void Platform_Init(void) { Stopwatch_Init(); - - Options_SetBool(OPT_USE_CHAT_FONT, true); } void Platform_Free(void) { } diff --git a/src/Platform_Switch.c b/src/Platform_Switch.c index 80ef1174b..271e31f1c 100644 --- a/src/Platform_Switch.c +++ b/src/Platform_Switch.c @@ -500,9 +500,6 @@ static void CreateRootDirectory(void) { } void Platform_Init(void) { - // TODO: Redesign Drawer2D to better handle this - //Options_SetBool(OPT_USE_CHAT_FONT, true); - CreateRootDirectory(); socketInitializeDefault(); } diff --git a/src/Platform_Windows.c b/src/Platform_Windows.c index 00aa6e3b6..a0633559f 100644 --- a/src/Platform_Windows.c +++ b/src/Platform_Windows.c @@ -360,7 +360,7 @@ static void FontDirCallback(const cc_string* path, void* obj) { static const cc_string fonExt = String_FromConst(".fon"); /* Completely skip windows .FON files */ if (String_CaselessEnds(path, &fonExt)) return; - SysFonts_Register(path); + SysFonts_Register(path, NULL); } void Platform_LoadSysFonts(void) { @@ -839,7 +839,7 @@ cc_bool DynamicLib_DescribeError(cc_string* dst) { dynamicErr = 0; /* Reset error (match posix behaviour) */ Platform_DescribeError(res, dst); - String_Format1(dst, " (error %i)", &res); + String_Format1(dst, " (error %e)", &res); /* Plugin may have been compiled to load symbols from ClassiCube.exe, */ /* but the user might have renamed it to something else */ diff --git a/src/Platform_Xbox.c b/src/Platform_Xbox.c index cea3e781e..06b47689d 100644 --- a/src/Platform_Xbox.c +++ b/src/Platform_Xbox.c @@ -111,7 +111,7 @@ cc_result Directory_Create(const cc_string* path) { } int File_Exists(const cc_string* path) { - if (!hdd_mounted) return ERR_NOT_SUPPORTED; + if (!hdd_mounted) return 0; char str[NATIVE_STR_LEN]; DWORD attribs; @@ -164,7 +164,7 @@ cc_result Directory_Enum(const cc_string* dirPath, void* obj, Directory_EnumCall } while (FindNextFileA(find, &eA)); res = GetLastError(); /* return code from FindNextFile */ - FindClose(find); + NtClose(find); return res == ERROR_NO_MORE_FILES ? 0 : res; } @@ -203,7 +203,8 @@ cc_result File_Write(cc_file file, const void* data, cc_uint32 count, cc_uint32* } cc_result File_Close(cc_file file) { - return CloseHandle(file) ? 0 : GetLastError(); + NTSTATUS status = NtClose(file); + return NT_SUCCESS(status) ? 0 : status; } cc_result File_Seek(cc_file file, int offset, int seekType) { @@ -225,7 +226,15 @@ cc_result File_Length(cc_file file, cc_uint32* len) { /*########################################################################################################################* *--------------------------------------------------------Threading--------------------------------------------------------* -*#############################################################################################################p############*/ +*##########################################################################################################################*/ +static void WaitForSignal(HANDLE handle, LARGE_INTEGER* duration) { + for (;;) + { + NTSTATUS status = NtWaitForSingleObjectEx((HANDLE)handle, UserMode, FALSE, duration); + if (status != STATUS_ALERTED) break; + } +} + void Thread_Sleep(cc_uint32 milliseconds) { Sleep(milliseconds); } static DWORD WINAPI ExecThread(void* param) { Thread_StartFunc func = (Thread_StartFunc)param; @@ -243,13 +252,12 @@ void Thread_Run(void** handle, Thread_StartFunc func, int stackSize, const char* } void Thread_Detach(void* handle) { - if (!CloseHandle((HANDLE)handle)) { - Logger_Abort2(GetLastError(), "Freeing thread handle"); - } + NTSTATUS status = NtClose((HANDLE)handle); + if (!NT_SUCCESS(status)) Logger_Abort2(status, "Freeing thread handle"); } void Thread_Join(void* handle) { - WaitForSingleObject((HANDLE)handle, INFINITE); + WaitForSignal((HANDLE)handle, NULL); Thread_Detach(handle); } @@ -263,30 +271,41 @@ void Mutex_Free(void* handle) { RtlDeleteCriticalSection((CRITICAL_SECTION*)handle); Mem_Free(handle); } -void Mutex_Lock(void* handle) { RtlEnterCriticalSection((CRITICAL_SECTION*)handle); } -void Mutex_Unlock(void* handle) { RtlLeaveCriticalSection((CRITICAL_SECTION*)handle); } + +void Mutex_Lock(void* handle) { + RtlEnterCriticalSection((CRITICAL_SECTION*)handle); +} + +void Mutex_Unlock(void* handle) { + RtlLeaveCriticalSection((CRITICAL_SECTION*)handle); +} void* Waitable_Create(void) { - void* handle = CreateEventA(NULL, false, false, NULL); - if (!handle) { - Logger_Abort2(GetLastError(), "Creating waitable"); - } + HANDLE handle; + NTSTATUS status = NtCreateEvent(&handle, NULL, SynchronizationEvent, false); + + if (!NT_SUCCESS(status)) Logger_Abort2(status, "Creating waitable"); return handle; } void Waitable_Free(void* handle) { - if (!CloseHandle((HANDLE)handle)) { - Logger_Abort2(GetLastError(), "Freeing waitable"); - } + NTSTATUS status = NtClose((HANDLE)handle); + if (!NT_SUCCESS(status)) Logger_Abort2(status, "Freeing waitable"); +} + +void Waitable_Signal(void* handle) { + NtSetEvent((HANDLE)handle, NULL); } -void Waitable_Signal(void* handle) { NtSetEvent((HANDLE)handle, NULL); } void Waitable_Wait(void* handle) { - WaitForSingleObject((HANDLE)handle, INFINITE); + WaitForSignal((HANDLE)handle, NULL); } void Waitable_WaitFor(void* handle, cc_uint32 milliseconds) { - WaitForSingleObject((HANDLE)handle, milliseconds); + LARGE_INTEGER duration; + duration.QuadPart = ((LONGLONG)milliseconds) * -10000; // negative for relative timeout + + WaitForSignal((HANDLE)handle, &duration); } @@ -397,18 +416,20 @@ static void InitHDD(void) { } else { hdd_mounted = nxMountDrive('E', "\\Device\\Harddisk0\\Partition1\\"); } - - if (!hdd_mounted) { - Platform_LogConst("Failed to mount E:/ from Data partition"); - return; - } - Directory_Create(&String_Empty); // create root ClassiCube folder + + if (!hdd_mounted) { + Platform_LogConst("Failed to mount E:/ from Data partition"); + return; + } + Directory_Create(&String_Empty); // create root ClassiCube folder } void Platform_Init(void) { InitHDD(); Stopwatch_Init(); +#ifndef CC_BUILD_CXBX nxNetInit(NULL); +#endif } void Platform_Free(void) { diff --git a/src/Protocol.c b/src/Protocol.c index 0f4b00bc0..084325b49 100644 --- a/src/Protocol.c +++ b/src/Protocol.c @@ -358,7 +358,7 @@ static void DisconnectInvalidMap(cc_result res) { cc_string tmp; char tmpBuffer[STRING_SIZE]; String_InitArray(tmp, tmpBuffer); - String_Format1(&tmp, "Server sent corrupted map data (error %h)", &res); + String_Format1(&tmp, "Server sent corrupted map data (error %e)", &res); Game_Disconnect(&title, &tmp); return; } diff --git a/src/SSL.c b/src/SSL.c index 389117e96..cb6d641f0 100644 --- a/src/SSL.c +++ b/src/SSL.c @@ -105,21 +105,6 @@ static SECURITY_STATUS SSL_CreateHandle(struct SSLContext* ctx) { &cred, NULL, NULL, &ctx->handle, NULL); } -static cc_result SSL_SendRaw(cc_socket socket, const cc_uint8* data, cc_uint32 count) { - cc_uint32 sent; - cc_result res; - - while (count) - { - if ((res = Socket_Write(socket, data, count, &sent))) return res; - if (!sent) return ERR_END_OF_STREAM; - - data += sent; - count -= sent; - } - return 0; -} - static cc_result SSL_RecvRaw(struct SSLContext* ctx) { cc_uint32 read; cc_result res; @@ -160,7 +145,7 @@ static SECURITY_STATUS SSL_Connect(struct SSLContext* ctx, const char* hostname) /* Send initial handshake to the server (if there is one) */ if (out_buffers[0].pvBuffer) { - res = SSL_SendRaw(ctx->socket, out_buffers[0].pvBuffer, out_buffers[0].cbBuffer); + res = Socket_WriteAll(ctx->socket, out_buffers[0].pvBuffer, out_buffers[0].cbBuffer); FP_FreeContextBuffer(out_buffers[0].pvBuffer); } return res; @@ -221,7 +206,7 @@ static SECURITY_STATUS SSL_Negotiate(struct SSLContext* ctx) { /* Need to send data to the server */ if (sec == SEC_I_CONTINUE_NEEDED) { - res = SSL_SendRaw(ctx->socket, out_buffers[0].pvBuffer, out_buffers[0].cbBuffer); + res = Socket_WriteAll(ctx->socket, out_buffers[0].pvBuffer, out_buffers[0].cbBuffer); FP_FreeContextBuffer(out_buffers[0].pvBuffer); /* TODO always free? */ if (res) return res; @@ -392,13 +377,12 @@ static cc_result SSL_WriteChunk(struct SSLContext* s, const cc_uint8* data, cc_u /* NOTE: Okay to write in one go, since all three buffers will be contiguous */ /* (as TLS record header size will always be the same size) */ total = buffers[0].cbBuffer + buffers[1].cbBuffer + buffers[2].cbBuffer; - return SSL_SendRaw(s->socket, buffer, total); + return Socket_WriteAll(s->socket, buffer, total); } -cc_result SSL_Write(void* ctx, const cc_uint8* data, cc_uint32 count, cc_uint32* wrote) { +cc_result SSL_WriteAll(void* ctx, const cc_uint8* data, cc_uint32 count) { struct SSLContext* s = ctx; cc_result res; - *wrote = 0; /* TODO: Don't loop here? move to HTTPConnection instead?? */ while (count) @@ -406,7 +390,6 @@ cc_result SSL_Write(void* ctx, const cc_uint8* data, cc_uint32 count, cc_uint32* int len = min(count, s->sizes.cbMaximumMessage); if ((res = SSL_WriteChunk(s, data, len))) return res; - *wrote += len; data += len; count -= len; } @@ -558,7 +541,7 @@ cc_result SSL_Read(void* ctx_, cc_uint8* data, cc_uint32 count, cc_uint32* read) return 0; } -cc_result SSL_Write(void* ctx_, const cc_uint8* data, cc_uint32 count, cc_uint32* wrote) { +cc_result SSL_WriteAll(void* ctx_, const cc_uint8* data, cc_uint32 count) { SSLContext* ctx = (SSLContext*)ctx_; // TODO: just br_sslio_write ?? int res = br_sslio_write_all(&ctx->ioc, data, count); @@ -569,7 +552,6 @@ cc_result SSL_Write(void* ctx_, const cc_uint8* data, cc_uint32 count, cc_uint32 } br_sslio_flush(&ctx->ioc); - *wrote = res; return 0; } @@ -592,7 +574,7 @@ cc_result SSL_Read(void* ctx, cc_uint8* data, cc_uint32 count, cc_uint32* read) return ERR_NOT_SUPPORTED; } -cc_result SSL_Write(void* ctx, const cc_uint8* data, cc_uint32 count, cc_uint32* wrote) { +cc_result SSL_WriteAll(void* ctx, const cc_uint8* data, cc_uint32 count) { return ERR_NOT_SUPPORTED; } diff --git a/src/SSL.h b/src/SSL.h index d3805b618..3865d55d4 100644 --- a/src/SSL.h +++ b/src/SSL.h @@ -11,6 +11,6 @@ cc_bool SSLBackend_DescribeError(cc_result res, cc_string* dst); cc_result SSL_Init(cc_socket socket, const cc_string* host, void** ctx); cc_result SSL_Read(void* ctx, cc_uint8* data, cc_uint32 count, cc_uint32* read); -cc_result SSL_Write(void* ctx, const cc_uint8* data, cc_uint32 count, cc_uint32* wrote); +cc_result SSL_WriteAll(void* ctx, const cc_uint8* data, cc_uint32 count); cc_result SSL_Free(void* ctx); #endif diff --git a/src/Server.c b/src/Server.c index 697ed0e62..1a898ebb0 100644 --- a/src/Server.c +++ b/src/Server.c @@ -264,7 +264,7 @@ static void MPConnection_FailConnect(cc_result result) { String_InitArray(msg, msgBuffer); if (result) { - String_Format3(&msg, "Error connecting to %s:%i: %i" _NL, &Server.Address, &Server.Port, &result); + String_Format3(&msg, "Error connecting to %s:%i: %e" _NL, &Server.Address, &Server.Port, &result); Logger_Log(&msg); } MPConnection_Fail(&reason); @@ -355,7 +355,7 @@ static void MPConnection_Disconnect(void) { static void DisconnectReadFailed(cc_result res) { cc_string msg; char msgBuffer[STRING_SIZE * 2]; String_InitArray(msg, msgBuffer); - String_Format3(&msg, "Error reading from %s:%i: %i" _NL, &Server.Address, &Server.Port, &res); + String_Format3(&msg, "Error reading from %s:%i: %e" _NL, &Server.Address, &Server.Port, &res); Logger_Log(&msg); MPConnection_Disconnect(); @@ -432,7 +432,7 @@ static void MPConnection_Tick(struct ScheduledTask* task) { } if (net_writeFailure) { - Platform_Log1("Error from send: %i", &net_writeFailure); + Platform_Log1("Error from send: %e", &net_writeFailure); MPConnection_Disconnect(); return; } diff --git a/src/String.c b/src/String.c index e6aae78d8..4802502ce 100644 --- a/src/String.c +++ b/src/String.c @@ -441,33 +441,52 @@ void String_Format4(cc_string* str, const char* format, const void* a1, const vo switch (format[++i]) { case 'b': - String_AppendInt(str, *((cc_uint8*)arg)); break; + String_AppendInt(str, *((cc_uint8*)arg)); + break; case 'i': - String_AppendInt(str, *((int*)arg)); break; + String_AppendInt(str, *((int*)arg)); + break; case 'f': digits = format[++i] - '0'; - String_AppendFloat(str, *((float*)arg), digits); break; + String_AppendFloat(str, *((float*)arg), digits); + break; case 'p': digits = format[++i] - '0'; - String_AppendPaddedInt(str, *((int*)arg), digits); break; + String_AppendPaddedInt(str, *((int*)arg), digits); + break; case 't': - String_AppendBool(str, *((cc_bool*)arg)); break; + String_AppendBool(str, *((cc_bool*)arg)); + break; case 'c': - String_AppendConst(str, (char*)arg); break; + String_AppendConst(str, (char*)arg); + break; case 's': - String_AppendString(str, (cc_string*)arg); break; + String_AppendString(str, (cc_string*)arg); + break; case 'r': - String_Append(str, *((char*)arg)); break; + String_Append(str, *((char*)arg)); + break; case 'x': if (sizeof(cc_uintptr) == 4) { - String_Hex32(str, *((cc_uint32*)arg)); break; + String_Hex32(str, *((cc_uint32*)arg)); } else { - String_Hex64(str, *((cc_uint64*)arg)); break; + String_Hex64(str, *((cc_uint64*)arg)); } + break; case 'h': - String_Hex32(str, *((cc_uint32*)arg)); break; + String_Hex32(str, *((cc_uint32*)arg)); + break; + case 'e': + digits = *((int*)arg); + if (digits >= -0xFFFF && digits <= 0xFFFF) { + String_AppendInt(str, digits); + } else { + String_Hex32(str, (cc_uint32)digits); + } + break; case '%': - String_Append(str, '%'); break; + String_Append(str, '%'); + break; default: Logger_Abort("Invalid type for string format"); } diff --git a/src/SystemFonts.c b/src/SystemFonts.c index 50ed49716..8df4df3e2 100644 --- a/src/SystemFonts.c +++ b/src/SystemFonts.c @@ -31,6 +31,224 @@ struct IGameComponent SystemFonts_Component = { }; +/*########################################################################################################################* +*------------------------------------------------------Fallback font------------------------------------------------------* +*#########################################################################################################################*/ +#define FallbackFont_ValidChar(c) ((c) > 32 && (c) < 127) +#define FallbackFont_ToIndex(c) ((c) - 33) /* First valid char is ! */ +#define SPACE_WIDTH 2 +#define CELL_SIZE 8 + +#define FallbackFont_GetRows(c) (FallbackFont_ValidChar(c) ? font_bitmap[FallbackFont_ToIndex(c)] : missing_cell) +#define FallbackFont_GetScale(size) ((size) >> 3) + +static const cc_uint8 missing_cell[CELL_SIZE] = { + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF +}; + +/* 8x8 font bitmap, represented with 1 bit for each pixel */ +/* Source: Goodly's texture pack for ClassiCube */ +static const cc_uint8 font_bitmap[][CELL_SIZE] = { + { 0x01,0x01,0x01,0x01,0x01,0x00,0x01,0x00 }, /* ! */ + { 0x05,0x05,0x05,0x00,0x00,0x00,0x00,0x00 }, /* " */ + { 0x0A,0x0A,0x1F,0x0A,0x1F,0x0A,0x0A,0x00 }, /* # */ + { 0x04,0x1F,0x01,0x1F,0x10,0x1F,0x04,0x00 }, /* $ */ + { 0x00,0x21,0x11,0x08,0x04,0x22,0x21,0x00 }, /* % */ + { 0x0C,0x12,0x0C,0x2E,0x19,0x11,0x2E,0x00 }, /* & */ + { 0x01,0x01,0x01,0x00,0x00,0x00,0x00,0x00 }, /* ' */ + { 0x04,0x02,0x01,0x01,0x01,0x02,0x04,0x00 }, /* ( */ + { 0x01,0x02,0x04,0x04,0x04,0x02,0x01,0x00 }, /* ) */ + { 0x00,0x02,0x07,0x02,0x05,0x00,0x00,0x00 }, /* * */ + { 0x00,0x04,0x04,0x1F,0x04,0x04,0x00,0x00 }, /* + */ + { 0x00,0x00,0x00,0x00,0x00,0x02,0x02,0x01 }, /* , */ + { 0x00,0x00,0x00,0x1F,0x00,0x00,0x00,0x00 }, /* - */ + { 0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x00 }, /* . */ + { 0x08,0x08,0x04,0x04,0x02,0x02,0x01,0x00 }, /* / */ + { 0x06,0x09,0x0D,0x0B,0x09,0x09,0x06,0x00 }, /* 0 */ + { 0x02,0x03,0x02,0x02,0x02,0x02,0x07,0x00 }, /* 1 */ + { 0x06,0x09,0x08,0x04,0x02,0x09,0x0F,0x00 }, /* 2 */ + { 0x06,0x09,0x08,0x06,0x08,0x09,0x06,0x00 }, /* 3 */ + { 0x05,0x05,0x05,0x0F,0x04,0x04,0x04,0x00 }, /* 4 */ + { 0x0F,0x01,0x07,0x08,0x08,0x09,0x06,0x00 }, /* 5 */ + { 0x06,0x09,0x01,0x07,0x09,0x09,0x06,0x00 }, /* 6 */ + { 0x0F,0x08,0x08,0x04,0x04,0x02,0x02,0x00 }, /* 7 */ + { 0x06,0x09,0x09,0x06,0x09,0x09,0x06,0x00 }, /* 8 */ + { 0x06,0x09,0x09,0x0E,0x08,0x09,0x06,0x00 }, /* 9 */ + { 0x00,0x01,0x01,0x00,0x00,0x01,0x01,0x00 }, /* : */ + { 0x00,0x02,0x02,0x00,0x00,0x02,0x02,0x01 }, /* ; */ + { 0x00,0x04,0x02,0x01,0x02,0x04,0x00,0x00 }, /* < */ + { 0x00,0x00,0x1F,0x00,0x00,0x1F,0x00,0x00 }, /* = */ + { 0x00,0x01,0x02,0x04,0x02,0x01,0x00,0x00 }, /* > */ + { 0x07,0x09,0x08,0x04,0x02,0x00,0x02,0x00 }, /* ? */ + { 0x0E,0x11,0x1D,0x1D,0x1D,0x01,0x0E,0x00 }, /* @ */ + { 0x06,0x09,0x09,0x0F,0x09,0x09,0x09,0x00 }, /* A */ + { 0x07,0x09,0x09,0x07,0x09,0x09,0x07,0x00 }, /* B */ + { 0x06,0x09,0x01,0x01,0x01,0x09,0x06,0x00 }, /* C */ + { 0x07,0x09,0x09,0x09,0x09,0x09,0x07,0x00 }, /* D */ + { 0x0F,0x01,0x01,0x07,0x01,0x01,0x0F,0x00 }, /* E */ + { 0x0F,0x01,0x01,0x07,0x01,0x01,0x01,0x00 }, /* F */ + { 0x06,0x09,0x01,0x0D,0x09,0x09,0x06,0x00 }, /* G */ + { 0x09,0x09,0x09,0x0F,0x09,0x09,0x09,0x00 }, /* H */ + { 0x07,0x02,0x02,0x02,0x02,0x02,0x07,0x00 }, /* I */ + { 0x08,0x08,0x08,0x08,0x08,0x09,0x07,0x00 }, /* J */ + { 0x09,0x09,0x05,0x03,0x05,0x09,0x09,0x00 }, /* K */ + { 0x01,0x01,0x01,0x01,0x01,0x01,0x0F,0x00 }, /* L */ + { 0x11,0x1B,0x15,0x11,0x11,0x11,0x11,0x00 }, /* M */ + { 0x09,0x0B,0x0D,0x09,0x09,0x09,0x09,0x00 }, /* N */ + { 0x06,0x09,0x09,0x09,0x09,0x09,0x06,0x00 }, /* O */ + { 0x07,0x09,0x09,0x07,0x01,0x01,0x01,0x00 }, /* P */ + { 0x06,0x09,0x09,0x09,0x09,0x05,0x0E,0x00 }, /* Q */ + { 0x07,0x09,0x09,0x07,0x09,0x09,0x09,0x00 }, /* R */ + { 0x06,0x09,0x01,0x06,0x08,0x09,0x06,0x00 }, /* S */ + { 0x07,0x02,0x02,0x02,0x02,0x02,0x02,0x00 }, /* T */ + { 0x09,0x09,0x09,0x09,0x09,0x09,0x06,0x00 }, /* U */ + { 0x11,0x11,0x11,0x11,0x11,0x0A,0x04,0x00 }, /* V */ + { 0x11,0x11,0x11,0x11,0x15,0x1B,0x11,0x00 }, /* W */ + { 0x11,0x11,0x0A,0x04,0x0A,0x11,0x11,0x00 }, /* X */ + { 0x11,0x11,0x0A,0x04,0x04,0x04,0x04,0x00 }, /* Y */ + { 0x0F,0x08,0x04,0x02,0x01,0x01,0x0F,0x00 }, /* Z */ + { 0x07,0x01,0x01,0x01,0x01,0x01,0x07,0x00 }, /* [ */ + { 0x01,0x01,0x02,0x02,0x04,0x04,0x08,0x00 }, /* \ */ + { 0x07,0x04,0x04,0x04,0x04,0x04,0x07,0x00 }, /* ] */ + { 0x04,0x0A,0x11,0x00,0x00,0x00,0x00,0x00 }, /* ^ */ + { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1F }, /* _ */ + { 0x01,0x01,0x02,0x00,0x00,0x00,0x00,0x00 }, /* ` */ + { 0x00,0x00,0x0E,0x09,0x09,0x0D,0x0B,0x00 }, /* a */ + { 0x01,0x01,0x07,0x09,0x09,0x09,0x07,0x00 }, /* b */ + { 0x00,0x00,0x06,0x09,0x01,0x09,0x06,0x00 }, /* c */ + { 0x08,0x08,0x0E,0x09,0x09,0x09,0x0E,0x00 }, /* d */ + { 0x00,0x00,0x06,0x09,0x0F,0x01,0x0E,0x00 }, /* e */ + { 0x06,0x01,0x07,0x01,0x01,0x01,0x01,0x00 }, /* f */ + { 0x00,0x00,0x0E,0x09,0x09,0x0E,0x08,0x07 }, /* g */ + { 0x01,0x01,0x07,0x09,0x09,0x09,0x09,0x00 }, /* h */ + { 0x01,0x00,0x01,0x01,0x01,0x01,0x01,0x00 }, /* i */ + { 0x08,0x00,0x08,0x08,0x08,0x08,0x09,0x06 }, /* j */ + { 0x01,0x01,0x09,0x05,0x03,0x05,0x09,0x00 }, /* k */ + { 0x01,0x01,0x01,0x01,0x01,0x01,0x02,0x00 }, /* l */ + { 0x00,0x00,0x0B,0x15,0x15,0x11,0x11,0x00 }, /* m */ + { 0x00,0x00,0x07,0x09,0x09,0x09,0x09,0x00 }, /* n */ + { 0x00,0x00,0x06,0x09,0x09,0x09,0x06,0x00 }, /* o */ + { 0x00,0x00,0x07,0x09,0x09,0x07,0x01,0x01 }, /* p */ + { 0x00,0x00,0x0E,0x09,0x09,0x0E,0x08,0x08 }, /* q */ + { 0x00,0x00,0x05,0x03,0x01,0x01,0x01,0x00 }, /* r */ + { 0x00,0x00,0x0E,0x01,0x06,0x08,0x07,0x00 }, /* s */ + { 0x02,0x02,0x07,0x02,0x02,0x02,0x02,0x00 }, /* t */ + { 0x00,0x00,0x09,0x09,0x09,0x09,0x0E,0x00 }, /* u */ + { 0x00,0x00,0x09,0x09,0x09,0x05,0x03,0x00 }, /* v */ + { 0x00,0x00,0x11,0x11,0x15,0x15,0x1A,0x00 }, /* w */ + { 0x00,0x00,0x05,0x05,0x02,0x05,0x05,0x00 }, /* x */ + { 0x00,0x00,0x09,0x09,0x09,0x0E,0x08,0x07 }, /* y */ + { 0x00,0x00,0x0F,0x08,0x04,0x02,0x0F,0x00 }, /* z */ + { 0x04,0x02,0x02,0x01,0x02,0x02,0x04,0x00 }, /* { */ + { 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01 }, /* | */ + { 0x01,0x02,0x02,0x04,0x02,0x02,0x01,0x00 }, /* } */ + { 0x00,0x00,0x26,0x19,0x00,0x00,0x00,0x00 }, /* ~ */ +}; + +static int Fallback_CellWidth(const cc_uint8* rows) { + int y, width, widest = 0; + + for (y = 0; y < CELL_SIZE; y++) + { + widest = max(widest, rows[y]); + } + width = Math_ilog2(widest) + 1; + + return width + 1; /* add 1 for padding */ +} + +int FallbackFont_TextWidth(const struct DrawTextArgs* args) { + cc_string left = args->text, part; + int size = args->font->size; + int scale = FallbackFont_GetScale(size); + char colorCode = 'f'; + int i, width = 0; + + while (Drawer2D_UNSAFE_NextPart(&left, &part, &colorCode)) + { + for (i = 0; i < part.length; i++) + { + cc_uint8 c = part.buffer[i]; + if (c == ' ') { + width += SPACE_WIDTH * scale; + } else { + width += Fallback_CellWidth(FallbackFont_GetRows(c)) * scale; + } + } + } + + width = max(1, width); + if (args->useShadow) width += 1 * scale; + return width; +} + +static void Fallback_DrawCell(struct Bitmap* bmp, int x, int y, + int scale, const cc_uint8* rows, BitmapCol color) { + int dst_width = CELL_SIZE * scale; + int dst_height = CELL_SIZE * scale; + int xx, srcX, dstX; + int yy, srcY, dstY; + BitmapCol* dst_row; + cc_uint8 src_row; + + for (yy = 0; yy < dst_height; yy++) + { + srcY = yy / scale; + dstY = y + yy; + if (dstY < 0 || dstY >= bmp->height) continue; + + dst_row = Bitmap_GetRow(bmp, dstY); + src_row = rows[srcY]; + + for (xx = 0; xx < dst_width; xx++) + { + srcX = xx / scale; + dstX = x + xx; + if (dstX < 0 || dstX >= bmp->width) continue; + + if (src_row & (1 << srcX)) { + dst_row[dstX] = color; + } + } + } +} + +void FallbackFont_DrawText(struct DrawTextArgs* args, struct Bitmap* bmp, int x, int y, cc_bool shadow) { + cc_string left = args->text, part; + int size = args->font->size; + int scale = FallbackFont_GetScale(size); + char colorCode = 'f'; + const cc_uint8* rows; + BitmapCol color; + int i; + + if (shadow) { + x += 1 * scale; + y += 1 * scale; + } + + /* adjust coords to make drawn text match GDI fonts */ + y += (args->font->height - size) / 2; + + while (Drawer2D_UNSAFE_NextPart(&left, &part, &colorCode)) + { + color = Drawer2D_GetColor(colorCode); + if (shadow) color = GetShadowColor(color); + + for (i = 0; i < part.length; i++) + { + cc_uint8 c = part.buffer[i]; + if (c == ' ') { x += SPACE_WIDTH * scale; continue; } + + rows = FallbackFont_GetRows(c); + + Fallback_DrawCell(bmp, x, y, scale, rows, color); + x += Fallback_CellWidth(rows) * scale; + } + } +} + + /*########################################################################################################################* *--------------------------------------------------------Freetype---------------------------------------------------------* *#########################################################################################################################*/ @@ -80,11 +298,13 @@ static void SysFont_Done(struct SysFont* font) { if (!source->meta.file) return; source->Close(source); - for (i = 0; i < 256; i++) { + for (i = 0; i < 256; i++) + { if (!font->glyphs[i]) continue; FT_Done_Glyph((FT_Glyph)font->glyphs[i]); } - for (i = 0; i < 256; i++) { + for (i = 0; i < 256; i++) + { if (!font->shadow_glyphs[i]) continue; FT_Done_Glyph((FT_Glyph)font->shadow_glyphs[i]); } @@ -191,7 +411,7 @@ static void SysFonts_LoadPlatform(void) { InitFreeTypeLibrary(); Platform_LoadSysFonts(); - if (fonts_changed) EntryList_Save(&font_list, FONT_CACHE_FILE); + if (fonts_changed) SysFonts_SaveCache(); } static cc_bool loadedCachedFonts; @@ -202,6 +422,10 @@ static void SysFonts_LoadCached(void) { EntryList_UNSAFE_Load(&font_list, FONT_CACHE_FILE); } +void SysFonts_SaveCache(void) { + EntryList_Save(&font_list, FONT_CACHE_FILE); +} + /* Some language-specific fonts don't support English letters */ /* and show entirely as '[]' - better off ignoring such fonts */ @@ -240,7 +464,7 @@ static void SysFonts_Add(const cc_string* path, FT_Face face, int index, char ty fonts_changed = true; } -static int SysFonts_DoRegister(const cc_string* path, int faceIndex) { +static int SysFonts_DoRegister(const cc_string* path, int faceIndex, SysFont_RegisterCallback callback) { struct SysFont font; FT_Open_Args args; FT_Error err; @@ -263,11 +487,12 @@ static int SysFonts_DoRegister(const cc_string* path, int faceIndex) { SysFonts_Add(path, font.face, faceIndex, 'R', "Regular"); } + if (callback) callback(path); FT_Done_Face(font.face); return count; } -void SysFonts_Register(const cc_string* path) { +cc_result SysFonts_Register(const cc_string* path, SysFont_RegisterCallback callback) { cc_string entry, name, value; cc_string fontPath, index; int i, count; @@ -278,14 +503,15 @@ void SysFonts_Register(const cc_string* path) { String_UNSAFE_Separate(&entry, '=', &name, &value); String_UNSAFE_Separate(&value, ',', &fontPath, &index); - if (String_CaselessEquals(path, &fontPath)) return; + if (String_CaselessEquals(path, &fontPath)) return 0; } - count = SysFonts_DoRegister(path, 0); + count = SysFonts_DoRegister(path, 0, callback); /* there may be more than one font in a font file */ for (i = 1; i < count; i++) { - SysFonts_DoRegister(path, i); + SysFonts_DoRegister(path, i, callback); } + return 0; } @@ -413,7 +639,9 @@ void SysFont_MakeDefault(struct FontDesc* desc, int size, int flags) { return; } } - Logger_Abort2(res, "Failed to init default font"); + + Window_ShowDialog("Failed to init default font", "Falling back to built-in font"); + Font_MakeBitmapped(desc, size, flags); } void SysFont_Free(struct FontDesc* desc) { @@ -443,7 +671,7 @@ int SysFont_TextWidth(struct DrawTextArgs* args) { res = FT_Load_Char(face, uc, 0); if (res) { - Platform_Log2("Error %i measuring width of %r", &res, &c); + Platform_Log2("Error %e measuring width of %r", &res, &c); charWidth = 0; } else { charWidth = face->glyph->advance.x; @@ -554,7 +782,7 @@ void SysFont_DrawText(struct DrawTextArgs* args, struct Bitmap* bmp, int x, int res = FT_Load_Char(face, uc, FT_LOAD_RENDER); if (res) { - Platform_Log2("Error %i drawing %r", &res, &text.buffer[i]); + Platform_Log2("Error %e drawing %r", &res, &text.buffer[i]); continue; } @@ -631,7 +859,11 @@ void SysFont_Free(struct FontDesc* desc) { Mem_Free(desc->handle); } -void SysFonts_Register(const cc_string* path) { } +void SysFonts_SaveCache(void) { } +cc_result SysFonts_Register(const cc_string* path, SysFont_RegisterCallback callback) { + return ERR_NOT_SUPPORTED; +} + extern void interop_SetFont(const char* font, int size, int flags); extern double interop_TextWidth(const char* text, const int len); extern double interop_TextDraw(const char* text, const int len, struct Bitmap* bmp, int x, int y, cc_bool shadow, const char* hex); @@ -692,7 +924,10 @@ extern void interop_SysFontFree(void* handle); extern int interop_SysTextWidth(struct DrawTextArgs* args); extern void interop_SysTextDraw(struct DrawTextArgs* args, struct Bitmap* bmp, int x, int y, cc_bool shadow); -void SysFonts_Register(const cc_string* path) { } +void SysFonts_SaveCache(void) { } +cc_result SysFonts_Register(const cc_string* path, SysFont_RegisterCallback callback) { + return ERR_NOT_SUPPORTED; +} const cc_string* SysFonts_UNSAFE_GetDefault(void) { return &String_Empty; @@ -710,7 +945,7 @@ void SysFont_MakeDefault(struct FontDesc* desc, int size, int flags) { interop_SysMakeDefault(desc, size, flags); } -void Font_Free(struct FontDesc* desc) { +void SysFont_Free(struct FontDesc* desc) { interop_SysFontFree(desc->handle); } @@ -722,119 +957,10 @@ void SysFont_DrawText(struct DrawTextArgs* args, struct Bitmap* bmp, int x, int interop_SysTextDraw(args, bmp, x, y, shadow); } #else - -#define SysFont_ValidChar(c) ((c) > 32 && (c) < 127) -#define SysFont_ToIndex(c) ((c) - 33) /* First valid char is ! */ -#define SPACE_WIDTH 2 -#define CELL_SIZE 8 - -#define SysFont_GetRows(c) (SysFont_ValidChar(c) ? font_bitmap[SysFont_ToIndex(c)] : missing_cell) - -static cc_uint8 missing_cell[CELL_SIZE] = { - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF -}; - -/* 8x8 font bitmap, represented with 1 bit for each pixel */ -/* Source: Goodly's texture pack for ClassiCube */ -static cc_uint8 font_bitmap[][CELL_SIZE] = { - { 0x01,0x01,0x01,0x01,0x01,0x00,0x01,0x00 }, /* ! */ - { 0x05,0x05,0x05,0x00,0x00,0x00,0x00,0x00 }, /* " */ - { 0x0A,0x0A,0x1F,0x0A,0x1F,0x0A,0x0A,0x00 }, /* # */ - { 0x04,0x1F,0x01,0x1F,0x10,0x1F,0x04,0x00 }, /* $ */ - { 0x00,0x21,0x11,0x08,0x04,0x22,0x21,0x00 }, /* % */ - { 0x0C,0x12,0x0C,0x2E,0x19,0x11,0x2E,0x00 }, /* & */ - { 0x01,0x01,0x01,0x00,0x00,0x00,0x00,0x00 }, /* ' */ - { 0x04,0x02,0x01,0x01,0x01,0x02,0x04,0x00 }, /* ( */ - { 0x01,0x02,0x04,0x04,0x04,0x02,0x01,0x00 }, /* ) */ - { 0x00,0x02,0x07,0x02,0x05,0x00,0x00,0x00 }, /* * */ - { 0x00,0x04,0x04,0x1F,0x04,0x04,0x00,0x00 }, /* + */ - { 0x00,0x00,0x00,0x00,0x00,0x02,0x02,0x01 }, /* , */ - { 0x00,0x00,0x00,0x1F,0x00,0x00,0x00,0x00 }, /* - */ - { 0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x00 }, /* . */ - { 0x08,0x08,0x04,0x04,0x02,0x02,0x01,0x00 }, /* / */ - { 0x06,0x09,0x0D,0x0B,0x09,0x09,0x06,0x00 }, /* 0 */ - { 0x02,0x03,0x02,0x02,0x02,0x02,0x07,0x00 }, /* 1 */ - { 0x06,0x09,0x08,0x04,0x02,0x09,0x0F,0x00 }, /* 2 */ - { 0x06,0x09,0x08,0x06,0x08,0x09,0x06,0x00 }, /* 3 */ - { 0x05,0x05,0x05,0x0F,0x04,0x04,0x04,0x00 }, /* 4 */ - { 0x0F,0x01,0x07,0x08,0x08,0x09,0x06,0x00 }, /* 5 */ - { 0x06,0x09,0x01,0x07,0x09,0x09,0x06,0x00 }, /* 6 */ - { 0x0F,0x08,0x08,0x04,0x04,0x02,0x02,0x00 }, /* 7 */ - { 0x06,0x09,0x09,0x06,0x09,0x09,0x06,0x00 }, /* 8 */ - { 0x06,0x09,0x09,0x0E,0x08,0x09,0x06,0x00 }, /* 9 */ - { 0x00,0x01,0x01,0x00,0x00,0x01,0x01,0x00 }, /* : */ - { 0x00,0x02,0x02,0x00,0x00,0x02,0x02,0x01 }, /* ; */ - { 0x00,0x04,0x02,0x01,0x02,0x04,0x00,0x00 }, /* < */ - { 0x00,0x00,0x1F,0x00,0x00,0x1F,0x00,0x00 }, /* = */ - { 0x00,0x01,0x02,0x04,0x02,0x01,0x00,0x00 }, /* > */ - { 0x07,0x09,0x08,0x04,0x02,0x00,0x02,0x00 }, /* ? */ - { 0x0E,0x11,0x1D,0x1D,0x1D,0x01,0x0E,0x00 }, /* @ */ - { 0x06,0x09,0x09,0x0F,0x09,0x09,0x09,0x00 }, /* A */ - { 0x07,0x09,0x09,0x07,0x09,0x09,0x07,0x00 }, /* B */ - { 0x06,0x09,0x01,0x01,0x01,0x09,0x06,0x00 }, /* C */ - { 0x07,0x09,0x09,0x09,0x09,0x09,0x07,0x00 }, /* D */ - { 0x0F,0x01,0x01,0x07,0x01,0x01,0x0F,0x00 }, /* E */ - { 0x0F,0x01,0x01,0x07,0x01,0x01,0x01,0x00 }, /* F */ - { 0x06,0x09,0x01,0x0D,0x09,0x09,0x06,0x00 }, /* G */ - { 0x09,0x09,0x09,0x0F,0x09,0x09,0x09,0x00 }, /* H */ - { 0x07,0x02,0x02,0x02,0x02,0x02,0x07,0x00 }, /* I */ - { 0x08,0x08,0x08,0x08,0x08,0x09,0x07,0x00 }, /* J */ - { 0x09,0x09,0x05,0x03,0x05,0x09,0x09,0x00 }, /* K */ - { 0x01,0x01,0x01,0x01,0x01,0x01,0x0F,0x00 }, /* L */ - { 0x11,0x1B,0x15,0x11,0x11,0x11,0x11,0x00 }, /* M */ - { 0x09,0x0B,0x0D,0x09,0x09,0x09,0x09,0x00 }, /* N */ - { 0x06,0x09,0x09,0x09,0x09,0x09,0x06,0x00 }, /* O */ - { 0x07,0x09,0x09,0x07,0x01,0x01,0x01,0x00 }, /* P */ - { 0x06,0x09,0x09,0x09,0x09,0x05,0x0E,0x00 }, /* Q */ - { 0x07,0x09,0x09,0x07,0x09,0x09,0x09,0x00 }, /* R */ - { 0x06,0x09,0x01,0x06,0x08,0x09,0x06,0x00 }, /* S */ - { 0x07,0x02,0x02,0x02,0x02,0x02,0x02,0x00 }, /* T */ - { 0x09,0x09,0x09,0x09,0x09,0x09,0x06,0x00 }, /* U */ - { 0x11,0x11,0x11,0x11,0x11,0x0A,0x04,0x00 }, /* V */ - { 0x11,0x11,0x11,0x11,0x15,0x1B,0x11,0x00 }, /* W */ - { 0x11,0x11,0x0A,0x04,0x0A,0x11,0x11,0x00 }, /* X */ - { 0x11,0x11,0x0A,0x04,0x04,0x04,0x04,0x00 }, /* Y */ - { 0x0F,0x08,0x04,0x02,0x01,0x01,0x0F,0x00 }, /* Z */ - { 0x07,0x01,0x01,0x01,0x01,0x01,0x07,0x00 }, /* [ */ - { 0x01,0x01,0x02,0x02,0x04,0x04,0x08,0x00 }, /* \ */ - { 0x07,0x04,0x04,0x04,0x04,0x04,0x07,0x00 }, /* ] */ - { 0x04,0x0A,0x11,0x00,0x00,0x00,0x00,0x00 }, /* ^ */ - { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1F }, /* _ */ - { 0x01,0x01,0x02,0x00,0x00,0x00,0x00,0x00 }, /* ` */ - { 0x00,0x00,0x0E,0x09,0x09,0x0D,0x0B,0x00 }, /* a */ - { 0x01,0x01,0x07,0x09,0x09,0x09,0x07,0x00 }, /* b */ - { 0x00,0x00,0x06,0x09,0x01,0x09,0x06,0x00 }, /* c */ - { 0x08,0x08,0x0E,0x09,0x09,0x09,0x0E,0x00 }, /* d */ - { 0x00,0x00,0x06,0x09,0x0F,0x01,0x0E,0x00 }, /* e */ - { 0x06,0x01,0x07,0x01,0x01,0x01,0x01,0x00 }, /* f */ - { 0x00,0x00,0x0E,0x09,0x09,0x0E,0x08,0x07 }, /* g */ - { 0x01,0x01,0x07,0x09,0x09,0x09,0x09,0x00 }, /* h */ - { 0x01,0x00,0x01,0x01,0x01,0x01,0x01,0x00 }, /* i */ - { 0x08,0x00,0x08,0x08,0x08,0x08,0x09,0x06 }, /* j */ - { 0x01,0x01,0x09,0x05,0x03,0x05,0x09,0x00 }, /* k */ - { 0x01,0x01,0x01,0x01,0x01,0x01,0x02,0x00 }, /* l */ - { 0x00,0x00,0x0B,0x15,0x15,0x11,0x11,0x00 }, /* m */ - { 0x00,0x00,0x07,0x09,0x09,0x09,0x09,0x00 }, /* n */ - { 0x00,0x00,0x06,0x09,0x09,0x09,0x06,0x00 }, /* o */ - { 0x00,0x00,0x07,0x09,0x09,0x07,0x01,0x01 }, /* p */ - { 0x00,0x00,0x0E,0x09,0x09,0x0E,0x08,0x08 }, /* q */ - { 0x00,0x00,0x05,0x03,0x01,0x01,0x01,0x00 }, /* r */ - { 0x00,0x00,0x0E,0x01,0x06,0x08,0x07,0x00 }, /* s */ - { 0x02,0x02,0x07,0x02,0x02,0x02,0x02,0x00 }, /* t */ - { 0x00,0x00,0x09,0x09,0x09,0x09,0x0E,0x00 }, /* u */ - { 0x00,0x00,0x09,0x09,0x09,0x05,0x03,0x00 }, /* v */ - { 0x00,0x00,0x11,0x11,0x15,0x15,0x1A,0x00 }, /* w */ - { 0x00,0x00,0x05,0x05,0x02,0x05,0x05,0x00 }, /* x */ - { 0x00,0x00,0x09,0x09,0x09,0x0E,0x08,0x07 }, /* y */ - { 0x00,0x00,0x0F,0x08,0x04,0x02,0x0F,0x00 }, /* z */ - { 0x04,0x02,0x02,0x01,0x02,0x02,0x04,0x00 }, /* { */ - { 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01 }, /* | */ - { 0x01,0x02,0x02,0x04,0x02,0x02,0x01,0x00 }, /* } */ - { 0x00,0x00,0x26,0x19,0x00,0x00,0x00,0x00 }, /* ~ */ -}; - - -void SysFonts_Register(const cc_string* path) { } +void SysFonts_SaveCache(void) { } +cc_result SysFonts_Register(const cc_string* path, SysFont_RegisterCallback callback) { + return ERR_NOT_SUPPORTED; +} const cc_string* SysFonts_UNSAFE_GetDefault(void) { return &String_Empty; } @@ -849,7 +975,7 @@ cc_result SysFont_Make(struct FontDesc* desc, const cc_string* fontName, int siz desc->flags = flags; desc->height = Drawer2D_AdjHeight(size); - desc->handle = (void*)(size / 8); + desc->handle = (void*)1; return 0; } @@ -861,106 +987,11 @@ void SysFont_Free(struct FontDesc* desc) { desc->handle = NULL; } - -static int CellWidth(cc_uint8* rows) { - int y, width, widest = 0; - - for (y = 0; y < CELL_SIZE; y++) - { - widest = max(widest, rows[y]); - } - width = Math_ilog2(widest) + 1; - - return width + 1; /* add 1 for padding */ -} - int SysFont_TextWidth(struct DrawTextArgs* args) { - cc_string left = args->text, part; - int scale = (int)args->font->handle; - char colorCode = 'f'; - int i, width = 0; - - while (Drawer2D_UNSAFE_NextPart(&left, &part, &colorCode)) - { - for (i = 0; i < part.length; i++) - { - cc_uint8 c = part.buffer[i]; - if (c == ' ') { - width += SPACE_WIDTH * scale; - } else { - width += CellWidth(SysFont_GetRows(c)) * scale; - } - } - } - - width = max(1, width); - if (args->useShadow) width += 1 * scale; - return width; -} - -static void DrawCell(struct Bitmap* bmp, int x, int y, - int scale, cc_uint8 * rows, BitmapCol color) { - int dst_width = CELL_SIZE * scale; - int dst_height = CELL_SIZE * scale; - int xx, srcX, dstX; - int yy, srcY, dstY; - BitmapCol* dst_row; - cc_uint8 src_row; - - for (yy = 0; yy < dst_height; yy++) - { - srcY = yy / scale; - dstY = y + yy; - if (dstY < 0 || dstY >= bmp->height) continue; - - dst_row = Bitmap_GetRow(bmp, dstY); - src_row = rows[srcY]; - - for (xx = 0; xx < dst_width; xx++) - { - srcX = xx / scale; - dstX = x + xx; - if (dstX < 0 || dstX >= bmp->width) continue; - - if (src_row & (1 << srcX)) { - dst_row[dstX] = color; - } - } - } + return FallbackFont_TextWidth(args); } void SysFont_DrawText(struct DrawTextArgs* args, struct Bitmap* bmp, int x, int y, cc_bool shadow) { - cc_string left = args->text, part; - int scale = (int)args->font->handle; - int size = args->font->size; - char colorCode = 'f'; - cc_uint8* rows; - BitmapCol color; - int i; - - if (shadow) { - x += 1 * scale; - y += 1 * scale; - } - - /* adjust coords to make drawn text match GDI fonts */ - y += (args->font->height - size) / 2; - - while (Drawer2D_UNSAFE_NextPart(&left, &part, &colorCode)) - { - color = Drawer2D_GetColor(colorCode); - if (shadow) color = GetShadowColor(color); - - for (i = 0; i < part.length; i++) - { - cc_uint8 c = part.buffer[i]; - if (c == ' ') { x += SPACE_WIDTH * scale; continue; } - - rows = SysFont_GetRows(c); - - DrawCell(bmp, x, y, scale, rows, color); - x += CellWidth(rows) * scale; - } - } + FallbackFont_DrawText(args, bmp, x, y, shadow); } #endif diff --git a/src/SystemFonts.h b/src/SystemFonts.h index 66b44827d..3573f4d5f 100644 --- a/src/SystemFonts.h +++ b/src/SystemFonts.h @@ -11,6 +11,9 @@ struct IGameComponent; struct StringsBuffer; extern struct IGameComponent SystemFonts_Component; +int FallbackFont_TextWidth(const struct DrawTextArgs* args); +void FallbackFont_DrawText(struct DrawTextArgs* args, struct Bitmap* bmp, int x, int y, cc_bool shadow); + /* Allocates a new system font from the given arguments */ cc_result SysFont_Make(struct FontDesc* desc, const cc_string* fontName, int size, int flags); /* Frees an allocated system font */ @@ -26,11 +29,13 @@ int SysFont_TextWidth(struct DrawTextArgs* args); /* Draws the given text with the given system font onto the given bitmap */ void SysFont_DrawText(struct DrawTextArgs* args, struct Bitmap* bmp, int x, int y, cc_bool shadow); +typedef void (*SysFont_RegisterCallback)(const cc_string* path); /* Gets the name of the default system font used */ const cc_string* SysFonts_UNSAFE_GetDefault(void); /* Gets the list of all supported system font names on this platform */ CC_API void SysFonts_GetNames(struct StringsBuffer* buffer); /* Attempts to decode one or more fonts from the given file */ /* NOTE: If this file has been decoded before (fontscache.txt), does nothing */ -void SysFonts_Register(const cc_string* path); +cc_result SysFonts_Register(const cc_string* path, SysFont_RegisterCallback callback); +void SysFonts_SaveCache(void); #endif diff --git a/src/TouchUI.c b/src/TouchUI.c index 408a6195e..7f359f710 100644 --- a/src/TouchUI.c +++ b/src/TouchUI.c @@ -725,10 +725,8 @@ static void TouchScreen_LayoutOnscreen(struct TouchScreen* s, cc_uint8 alignment static void TouchScreen_Layout(void* screen) { struct TouchScreen* s = (struct TouchScreen*)screen; const struct TouchButtonDesc* desc; - int haligns = GetOnscreenHAligns(); float scale = Gui.RawTouchScale; - cc_uint8 halign; - int i, x, y, height; + int i, height; /* Need to align these relative to the hotbar */ height = HUDScreen_LayoutHotbar(); @@ -759,7 +757,6 @@ static void TouchScreen_GetMovement(struct LocalPlayer* p, float* xMoving, float ThumbstickWidget_GetMovement(&TouchScreen.thumbstick, xMoving, zMoving); } static struct LocalPlayerInput touchInput = { TouchScreen_GetMovement }; -static cc_bool touchHooked; static void TouchScreen_Init(void* screen) { struct TouchScreen* s = (struct TouchScreen*)screen; @@ -774,15 +771,14 @@ static void TouchScreen_Init(void* screen) { ButtonWidget_Init(&s->more, 40, TouchScreen_MoreClick); s->more.color = TOUCHSCREEN_BTN_COLOR; ThumbstickWidget_Init(&s->thumbstick); - - if (touchHooked) return; - touchHooked = true; + LocalPlayerInput_Add(&touchInput); } static void TouchScreen_Free(void* s) { Event_Unregister_(&UserEvents.HacksStateChanged, s, TouchScreen_HacksChanged); Event_Unregister_(&UserEvents.HackPermsChanged, s, TouchScreen_HacksChanged); + LocalPlayerInput_Remove(&touchInput); } static const struct ScreenVTABLE TouchScreen_VTABLE = { diff --git a/src/Vectors.c b/src/Vectors.c index 6ff297ab8..18c16b67f 100644 --- a/src/Vectors.c +++ b/src/Vectors.c @@ -210,36 +210,35 @@ cc_bool FrustumCulling_SphereInFrustum(float x, float y, float z, float radius) } void FrustumCulling_CalcFrustumEquations(struct Matrix* projection, struct Matrix* modelView) { - struct Matrix clipMatrix; - float* clip = (float*)&clipMatrix; - Matrix_Mul(&clipMatrix, modelView, projection); + struct Matrix clip; + Matrix_Mul(&clip, modelView, projection); - /* Extract the numbers for the RIGHT plane */ - frustum00 = clip[3] - clip[0]; - frustum01 = clip[7] - clip[4]; - frustum02 = clip[11] - clip[8]; - frustum03 = clip[15] - clip[12]; + /* Extract the RIGHT plane */ + frustum00 = clip.row1.w - clip.row1.x; + frustum01 = clip.row2.w - clip.row2.x; + frustum02 = clip.row3.w - clip.row3.x; + frustum03 = clip.row4.w - clip.row4.x; FrustumCulling_Normalise(&frustum00, &frustum01, &frustum02, &frustum03); - /* Extract the numbers for the LEFT plane */ - frustum10 = clip[3] + clip[0]; - frustum11 = clip[7] + clip[4]; - frustum12 = clip[11] + clip[8]; - frustum13 = clip[15] + clip[12]; + /* Extract the LEFT plane */ + frustum10 = clip.row1.w + clip.row1.x; + frustum11 = clip.row2.w + clip.row2.x; + frustum12 = clip.row3.w + clip.row3.x; + frustum13 = clip.row4.w + clip.row4.x; FrustumCulling_Normalise(&frustum10, &frustum11, &frustum12, &frustum13); /* Extract the BOTTOM plane */ - frustum20 = clip[3] + clip[1]; - frustum21 = clip[7] + clip[5]; - frustum22 = clip[11] + clip[9]; - frustum23 = clip[15] + clip[13]; + frustum20 = clip.row1.w + clip.row1.y; + frustum21 = clip.row2.w + clip.row2.y; + frustum22 = clip.row3.w + clip.row3.y; + frustum23 = clip.row4.w + clip.row4.y; FrustumCulling_Normalise(&frustum20, &frustum21, &frustum22, &frustum23); /* Extract the TOP plane */ - frustum30 = clip[3] - clip[1]; - frustum31 = clip[7] - clip[5]; - frustum32 = clip[11] - clip[9]; - frustum33 = clip[15] - clip[13]; + frustum30 = clip.row1.w - clip.row1.y; + frustum31 = clip.row2.w - clip.row2.y; + frustum32 = clip.row3.w - clip.row3.y; + frustum33 = clip.row4.w - clip.row4.y; FrustumCulling_Normalise(&frustum30, &frustum31, &frustum32, &frustum33); /* Extract the FAR plane (Different for each graphics backend) */ @@ -247,15 +246,15 @@ void FrustumCulling_CalcFrustumEquations(struct Matrix* projection, struct Matri /* OpenGL and Direct3D require slightly different behaviour for NEAR clipping planes */ /* https://www.gamedevs.org/uploads/fast-extraction-viewing-frustum-planes-from-world-view-projection-matrix.pdf */ /* (and because reverse Z is used, 'NEAR' plane is actually the 'FAR' clipping plane) */ - frustum40 = clip[2]; - frustum41 = clip[6]; - frustum42 = clip[10]; - frustum43 = clip[14]; + frustum40 = clip.row1.z; + frustum41 = clip.row2.z; + frustum42 = clip.row3.z; + frustum43 = clip.row4.z; #else - frustum40 = clip[3] - clip[2]; - frustum41 = clip[7] - clip[6]; - frustum42 = clip[11] - clip[10]; - frustum43 = clip[15] - clip[14]; + frustum40 = clip.row1.w - clip.row1.z; + frustum41 = clip.row2.w - clip.row2.z; + frustum42 = clip.row3.w - clip.row3.z; + frustum43 = clip.row4.w - clip.row4.z; #endif FrustumCulling_Normalise(&frustum40, &frustum41, &frustum42, &frustum43); } diff --git a/src/VirtualKeyboard.h b/src/VirtualKeyboard.h index aacebd5e0..cf041b5bf 100644 --- a/src/VirtualKeyboard.h +++ b/src/VirtualKeyboard.h @@ -154,6 +154,12 @@ static void VirtualKeyboard_AppendChar(char c) { if (kb_shift) { VirtualKeyboard_ToggleTable(); kb_shift = false; } } +static void VirtualKeyboard_Backspace(void) { + if (kb_str.length) kb_str.length--; + Event_RaiseString(&InputEvents.TextChanged, &kb_str); + KB_MarkDirty(); +} + static void VirtualKeyboard_ClickSelected(void) { int selected = VirtualKeyboard_GetSelected(); if (selected < 0) return; @@ -161,9 +167,7 @@ static void VirtualKeyboard_ClickSelected(void) { /* TODO kinda hacky, redo this */ switch (selected) { case KB_INDEX(KB_LAST_CELL, 0): - if (kb_str.length) kb_str.length--; - Event_RaiseString(&InputEvents.TextChanged, &kb_str); - KB_MarkDirty(); + VirtualKeyboard_Backspace(); break; case KB_INDEX(KB_LAST_CELL, 2): OnscreenKeyboard_Close(); @@ -192,18 +196,21 @@ static void VirtualKeyboard_ClickSelected(void) { } static void VirtualKeyboard_ProcessDown(void* obj, int key, cc_bool was) { - if (Input_IsLeftButton(key)) { - VirtualKeyboard_Scroll(-1); - } else if (Input_IsRightButton(key)) { - VirtualKeyboard_Scroll(+1); - } else if (Input_IsUpButton(key)) { - VirtualKeyboard_Scroll(-KB_CELLS_PER_ROW); - } else if (Input_IsDownButton(key)) { - VirtualKeyboard_Scroll(+KB_CELLS_PER_ROW); - } else if (Input_IsEnterButton(key) || key == CCPAD_A) { + int delta = Input_CalcDelta(key, 1, KB_CELLS_PER_ROW); + if (delta) { + VirtualKeyboard_Scroll(delta); + } else if (key == CCPAD_START || key == CCPAD_A) { VirtualKeyboard_ClickSelected(); - } else if (Input_IsEscapeButton(key) || key == CCPAD_B) { + } else if (key == CCPAD_SELECT || key == CCPAD_B) { VirtualKeyboard_Close(); + } else if (key == CCPAD_X) { + VirtualKeyboard_Backspace(); + } else if (key == CCPAD_Y) { + VirtualKeyboard_AppendChar(' '); + } else if (key == CCPAD_L) { + VirtualKeyboard_AppendChar('@'); + } else if (key == CCPAD_R) { + VirtualKeyboard_AppendChar('/'); } } @@ -327,7 +334,7 @@ static void VirtualKeyboard_Open(struct OpenKeyboardArgs* args, cc_bool launcher kb_shift = false; kb_str.length = 0; - if (args) String_AppendConst(&kb_str, args->placeholder); + String_AppendString(&kb_str, args->text); if (launcher) { KB_MarkDirty = VirtualKeyboard_MarkDirty2D; diff --git a/src/Widgets.c b/src/Widgets.c index 47eb3a5be..85e66bede 100644 --- a/src/Widgets.c +++ b/src/Widgets.c @@ -975,20 +975,15 @@ static int TableWidget_PointerMove(void* widget, int id, int x, int y) { static int TableWidget_KeyDown(void* widget, int key) { struct TableWidget* w = (struct TableWidget*)widget; + int delta; if (w->selectedIndex == -1) return false; - if (Input_IsLeftButton(key) || key == CCKEY_KP4) { - TableWidget_ScrollRelative(w, -1); - } else if (Input_IsRightButton(key) || key == CCKEY_KP6) { - TableWidget_ScrollRelative(w, 1); - } else if (Input_IsUpButton(key) || key == CCKEY_KP8) { - TableWidget_ScrollRelative(w, -w->blocksPerRow); - } else if (Input_IsDownButton(key) || key == CCKEY_KP2) { - TableWidget_ScrollRelative(w, w->blocksPerRow); - } else { - return false; + delta = Input_CalcDelta(key, 1, w->blocksPerRow); + if (delta) { + TableWidget_ScrollRelative(w, delta); + return true; } - return true; + return false; } static int TableWidget_PadAxis(void* widget, int axis, float x, float y) { @@ -2783,7 +2778,7 @@ static int ThumbstickWidget_CalcDirs(struct ThumbstickWidget* w) { dx = Pointers[i].x - (w->x + w->width / 2); dy = Pointers[i].y - (w->y + w->height / 2); - angle = Math_Atan2(dx, dy) * MATH_RAD2DEG; + angle = Math_Atan2f(dx, dy) * MATH_RAD2DEG; /* 4 quadrants diagonally, but slightly expanded for overlap*/ if (angle >= 30 && angle <= 150) dirs |= DIR_YMAX; diff --git a/src/Window_NDS.c b/src/Window_NDS.c index 0ea5a6379..87516b56e 100644 --- a/src/Window_NDS.c +++ b/src/Window_NDS.c @@ -15,6 +15,8 @@ #include #include #include +#include +#include /*########################################################################################################################* @@ -68,6 +70,8 @@ static void consoleNewLine(void) { } static void consolePrintChar(char c) { + if (c < ' ') return; // only ASCII supported + if (conCursorX >= CON_WIDTH) consoleNewLine(); @@ -110,7 +114,7 @@ static void consoleLoadFont(u16* fontBgGfx) { } static void consoleInit(void) { - int bgId = bgInitSub(0, BgType_Text4bpp, BgSize_T_256x256, 14, 0); + int bgId = bgInitSub(0, BgType_Text4bpp, BgSize_T_256x256, 22, 2); conFontBgMap = (u16*)bgGetMapPtr(bgId); consoleLoadFont((u16*)bgGetGfxPtr(bgId)); @@ -129,17 +133,6 @@ static u16* bg_ptr; struct _DisplayData DisplayInfo; struct _WindowData WindowInfo; -// Console and Keyboard combined need more than 32 kb of H VRAM bank -// The simple solution would be to allocate the C VRAM bank, but ClassiCube -// needs as much VRAM as it can get for textures -// So the solution is to share the H VRAM bank between console and keyboard -static void ResetHBank(void) { - // Map all VRAM banks to LCDC mode so that the CPU can access it - vramSetBankH(VRAM_H_LCD); - dmaFillWords(0, VRAM_H, 32 * 1024); - vramSetBankH(VRAM_H_SUB_BG); -} - void Window_Init(void) { DisplayInfo.Width = SCREEN_WIDTH; DisplayInfo.Height = SCREEN_HEIGHT; @@ -157,8 +150,16 @@ void Window_Init(void) { videoSetModeSub(MODE_0_2D); vramSetBankH(VRAM_H_SUB_BG); + vramSetBankI(VRAM_I_SUB_BG_0x06208000); setBrightness(2, 0); consoleInit(); + + cc_bool dsiMode = isDSiMode(); + Platform_Log1("Running in %c mode", dsiMode ? "DSi" : "DS"); + + char* dir = fatGetDefaultCwd(); + if (dir) Platform_Log1("CWD: %c", dir); + Mem_Free(dir); } void Window_Free(void) { } @@ -309,7 +310,6 @@ void OnscreenKeyboard_Open(struct OpenKeyboardArgs* args) { Keyboard* kbd = keyboardGetDefault(); videoBgDisableSub(0); // hide console - ResetHBank(); // reset shared VRAM keyboardInit(kbd, 3, BgType_Text4bpp, BgSize_T_256x512, 14, 0, false, true); keyboardShow(); @@ -330,9 +330,7 @@ void OnscreenKeyboard_Close(void) { if (!keyboardOpen) return; keyboardOpen = false; - ResetHBank(); // reset shared VRAM videoBgEnableSub(0); // show console - consoleInit(); } diff --git a/src/Window_PS2.c b/src/Window_PS2.c index 3e691ae09..74428180f 100644 --- a/src/Window_PS2.c +++ b/src/Window_PS2.c @@ -110,6 +110,8 @@ static void HandleButtons(int port, int buttons) { Gamepad_SetButton(port, CCPAD_START, buttons & PAD_START); Gamepad_SetButton(port, CCPAD_SELECT, buttons & PAD_SELECT); + Gamepad_SetButton(port, CCPAD_LSTICK, buttons & PAD_L3); + Gamepad_SetButton(port, CCPAD_RSTICK, buttons & PAD_L3); Gamepad_SetButton(port, CCPAD_LEFT, buttons & PAD_LEFT); Gamepad_SetButton(port, CCPAD_RIGHT, buttons & PAD_RIGHT); diff --git a/src/Window_PS3.c b/src/Window_PS3.c index ef06422a2..445e271bc 100644 --- a/src/Window_PS3.c +++ b/src/Window_PS3.c @@ -276,6 +276,8 @@ static void HandleButtons(int port, padData* data) { Gamepad_SetButton(port, CCPAD_START, data->BTN_START); Gamepad_SetButton(port, CCPAD_SELECT, data->BTN_SELECT); + Gamepad_SetButton(port, CCPAD_LSTICK, data->BTN_L3); + Gamepad_SetButton(port, CCPAD_RSTICK, data->BTN_R3); Gamepad_SetButton(port, CCPAD_LEFT, data->BTN_LEFT); Gamepad_SetButton(port, CCPAD_RIGHT, data->BTN_RIGHT); diff --git a/src/Window_PSVita.c b/src/Window_PSVita.c index 137d26bf0..2f9c7336a 100644 --- a/src/Window_PSVita.c +++ b/src/Window_PSVita.c @@ -227,7 +227,7 @@ static void DisplayDialog(const char* msg) { msgParam.buttonType = SCE_MSG_DIALOG_BUTTON_TYPE_OK; int ret = sceMsgDialogInit(¶m); - if (ret) { Platform_Log1("ERROR SHOWING DIALOG: %i", &ret); return; } + if (ret) { Platform_Log1("ERROR SHOWING DIALOG: %e", &ret); return; } void (*prevCallback)(void* fb); prevCallback = DQ_OnNextFrame; @@ -315,7 +315,7 @@ void OnscreenKeyboard_Open(struct OpenKeyboardArgs* args) { param.inputTextBuffer = imeBuffer; int ret = sceImeDialogInit(¶m); - if (ret) { Platform_Log1("ERROR SHOWING IME: %i", &ret); return; } + if (ret) { Platform_Log1("ERROR SHOWING IME: %e", &ret); return; } void (*prevCallback)(void* fb); prevCallback = DQ_OnNextFrame; diff --git a/src/Window_SDL.c b/src/Window_SDL.c index ad3ab1fa9..5eb653f47 100644 --- a/src/Window_SDL.c +++ b/src/Window_SDL.c @@ -7,11 +7,11 @@ #include "Bitmap.h" #include "Errors.h" #include -static SDL_Window* win_handle; -#ifndef CC_BUILD_OS2 -#error "Some features are missing from the SDL backend. If possible, it is recommended that you use a native windowing backend instead" -#else +static SDL_Window* win_handle; +#warning "Some features are missing from the SDL backend. If possible, it is recommended that you use a native windowing backend instead" + +#ifdef CC_BUILD_OS2 #define INCL_PM #include // Internal OS/2 driver data diff --git a/src/Window_Saturn.c b/src/Window_Saturn.c index df8677c91..da368981d 100644 --- a/src/Window_Saturn.c +++ b/src/Window_Saturn.c @@ -130,7 +130,7 @@ void Window_Create2D(int width, int height) { }; vdp2_scrn_bitmap_format_set(&format); - vdp2_scrn_priority_set(VDP2_SCRN_NBG0, 7); + vdp2_scrn_priority_set(VDP2_SCRN_NBG0, 5); vdp2_scrn_display_set(VDP2_SCRN_DISP_NBG0); const vdp2_vram_cycp_t vram_cycp = { diff --git a/src/Window_WiiU.c b/src/Window_WiiU.c deleted file mode 100644 index aae3888fd..000000000 --- a/src/Window_WiiU.c +++ /dev/null @@ -1,345 +0,0 @@ -#include "Core.h" -#if defined CC_BUILD_WIIU -#include "Window.h" -#include "Platform.h" -#include "Input.h" -#include "Event.h" -#include "String.h" -#include "Funcs.h" -#include "Bitmap.h" -#include "Errors.h" -#include "ExtMath.h" -#include "Graphics.h" -#include "Launcher.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static cc_bool launcherMode; -struct _DisplayData DisplayInfo; -struct _WindowData WindowInfo; -struct _WindowData Window_Alt; -cc_bool launcherTop; - -static void LoadTVDimensions(void) { - switch(GX2GetSystemTVScanMode()) - { - case GX2_TV_SCAN_MODE_480I: - case GX2_TV_SCAN_MODE_480P: - DisplayInfo.Width = 854; - DisplayInfo.Height = 480; - break; - case GX2_TV_SCAN_MODE_1080I: - case GX2_TV_SCAN_MODE_1080P: - DisplayInfo.Width = 1920; - DisplayInfo.Height = 1080; - break; - case GX2_TV_SCAN_MODE_720P: - default: - DisplayInfo.Width = 1280; - DisplayInfo.Height = 720; - break; - } -} - -static uint32_t OnAcquired(void* context) { - Window_Main.Inactive = false; - Event_RaiseVoid(&WindowEvents.InactiveChanged); - return 0; -} - -static uint32_t OnReleased(void* context) { - Window_Main.Inactive = true; - Event_RaiseVoid(&WindowEvents.InactiveChanged); - return 0; -} - -void Window_Init(void) { - LoadTVDimensions(); - DisplayInfo.ScaleX = 1; - DisplayInfo.ScaleY = 1; - - Window_Main.Width = DisplayInfo.Width; - Window_Main.Height = DisplayInfo.Height; - Window_Main.Focused = true; - Window_Main.Exists = true; - - Input.Sources = INPUT_SOURCE_GAMEPAD; - DisplayInfo.ContentOffsetX = 10; - DisplayInfo.ContentOffsetY = 10; - - Window_Main.SoftKeyboard = SOFT_KEYBOARD_RESIZE; - Input_SetTouchMode(true); - - Window_Alt.Width = 854; - Window_Alt.Height = 480; - - KPADInit(); - VPADInit(); - - ProcUIRegisterCallback(PROCUI_CALLBACK_ACQUIRE, OnAcquired, NULL, 100); - ProcUIRegisterCallback(PROCUI_CALLBACK_RELEASE, OnReleased, NULL, 100); -} - -void Window_Free(void) { } - -// OSScreen is always this buffer size, regardless of the current TV resolution -#define OSSCREEN_TV_WIDTH 1280 -#define OSSCREEN_TV_HEIGHT 720 -#define OSSCREEN_DRC_WIDTH 854 -#define OSSCREEN_DRC_HEIGHT 480 -static void LauncherInactiveChanged(void* obj); - -void Window_Create2D(int width, int height) { - Window_Main.Width = OSSCREEN_DRC_WIDTH; - Window_Main.Height = OSSCREEN_DRC_HEIGHT; - - launcherMode = true; - Event_Register_(&WindowEvents.InactiveChanged, LauncherInactiveChanged, NULL); -} - -void Window_Create3D(int width, int height) { - Window_Main.Width = DisplayInfo.Width; - Window_Main.Height = DisplayInfo.Height; - - launcherMode = false; - Event_Unregister_(&WindowEvents.InactiveChanged, LauncherInactiveChanged, NULL); -} - -void Window_RequestClose(void) { - Event_RaiseVoid(&WindowEvents.Closing); -} - - -/*########################################################################################################################* -*----------------------------------------------------Input processing-----------------------------------------------------* -*#########################################################################################################################*/ -void Window_ProcessEvents(float delta) { - if (!WHBProcIsRunning()) { - Window_Main.Exists = false; - Window_RequestClose(); - } -} - -void Window_UpdateRawMouse(void) { } - -void Cursor_SetPosition(int x, int y) { } -void Window_EnableRawMouse(void) { Input.RawMode = true; } -void Window_DisableRawMouse(void) { Input.RawMode = false; } - - -/*########################################################################################################################* -*-------------------------------------------------------Gamepads----------------------------------------------------------* -*#########################################################################################################################*/ -static void ProcessKPAD(float delta) { - KPADStatus kpad = { 0 }; - int res = KPADRead(0, &kpad, 1); - if (res != KPAD_ERROR_OK) return; - - switch (kpad.extensionType) - { - - } -} - - -#define AXIS_SCALE 4.0f -static void ProcessVpadStick(int port, int axis, float x, float y, float delta) { - // May not be exactly 0 on actual hardware - if (Math_AbsF(x) <= 0.1f) x = 0; - if (Math_AbsF(y) <= 0.1f) y = 0; - - Gamepad_SetAxis(port, axis, x * AXIS_SCALE, -y * AXIS_SCALE, delta); -} - -static void ProcessVpadButtons(int port, int mods) { - Gamepad_SetButton(port, CCPAD_L, mods & VPAD_BUTTON_L); - Gamepad_SetButton(port, CCPAD_R, mods & VPAD_BUTTON_R); - Gamepad_SetButton(port, CCPAD_ZL, mods & VPAD_BUTTON_ZL); - Gamepad_SetButton(port, CCPAD_ZR, mods & VPAD_BUTTON_ZR); - - Gamepad_SetButton(port, CCPAD_A, mods & VPAD_BUTTON_A); - Gamepad_SetButton(port, CCPAD_B, mods & VPAD_BUTTON_B); - Gamepad_SetButton(port, CCPAD_X, mods & VPAD_BUTTON_X); - Gamepad_SetButton(port, CCPAD_Y, mods & VPAD_BUTTON_Y); - - Gamepad_SetButton(port, CCPAD_START, mods & VPAD_BUTTON_PLUS); - Gamepad_SetButton(port, CCPAD_SELECT, mods & VPAD_BUTTON_MINUS); - - Gamepad_SetButton(port, CCPAD_LEFT, mods & VPAD_BUTTON_LEFT); - Gamepad_SetButton(port, CCPAD_RIGHT, mods & VPAD_BUTTON_RIGHT); - Gamepad_SetButton(port, CCPAD_UP, mods & VPAD_BUTTON_UP); - Gamepad_SetButton(port, CCPAD_DOWN, mods & VPAD_BUTTON_DOWN); - -} - -static void ProcessVpadTouch(VPADTouchData* data) { - static int was_touched; - - // TODO rescale to main screen size - if (data->touched) { - int x = data->x; - int y = data->y; - Platform_Log2("TOUCH: %i, %i", &x, &y); - - x = x * Window_Main.Width / 1280; - y = y * Window_Main.Height / 720; - - Input_AddTouch(0, x, y); - } else if (was_touched) { - Input_RemoveTouch(0, Pointers[0].x, Pointers[0].y); - } - was_touched = data->touched; -} - -static void ProcessVPAD(float delta) { - VPADStatus vpadStatus; - VPADReadError error = VPAD_READ_SUCCESS; - VPADRead(VPAD_CHAN_0, &vpadStatus, 1, &error); - if (error != VPAD_READ_SUCCESS) return; - - VPADGetTPCalibratedPoint(VPAD_CHAN_0, &vpadStatus.tpNormal, &vpadStatus.tpNormal); - ProcessVpadButtons(0, vpadStatus.hold); - ProcessVpadTouch(&vpadStatus.tpNormal); - - ProcessVpadStick(0, PAD_AXIS_LEFT, vpadStatus.leftStick.x, vpadStatus.leftStick.y, delta); - ProcessVpadStick(0, PAD_AXIS_RIGHT, vpadStatus.rightStick.x, vpadStatus.rightStick.y, delta); -} - - -void Window_ProcessGamepads(float delta) { - ProcessVPAD(delta); - ProcessKPAD(delta); -} - - -/*########################################################################################################################* -*------------------------------------------------------Framebuffer--------------------------------------------------------* -*#########################################################################################################################*/ -#define FB_HEAP_TAG (0x200CCBFF) - -static void AllocNativeFramebuffer(void) { - MEMHeapHandle heap = MEMGetBaseHeapHandle(MEM_BASE_HEAP_MEM1); - MEMRecordStateForFrmHeap(heap, FB_HEAP_TAG); - - int tv_size = OSScreenGetBufferSizeEx(SCREEN_TV); - void* tv_data = MEMAllocFromFrmHeapEx(heap, tv_size, 4); - OSScreenSetBufferEx(SCREEN_TV, tv_data); - - int drc_size = OSScreenGetBufferSizeEx(SCREEN_DRC); - void* drc_data = MEMAllocFromFrmHeapEx(heap, drc_size, 4); - OSScreenSetBufferEx(SCREEN_DRC, drc_data); -} - -static void FreeNativeFramebuffer(void) { - MEMHeapHandle heap = MEMGetBaseHeapHandle(MEM_BASE_HEAP_MEM1); - MEMFreeByStateToFrmHeap(heap, FB_HEAP_TAG); -} - -static void LauncherInactiveChanged(void* obj) { - if (Window_Main.Inactive) { - FreeNativeFramebuffer(); - } else { - AllocNativeFramebuffer(); - } -} - -void Window_AllocFramebuffer(struct Bitmap* bmp) { - OSScreenInit(); - AllocNativeFramebuffer(); - OSScreenEnableEx(SCREEN_TV, 1); - OSScreenEnableEx(SCREEN_DRC, 1); - - bmp->scan0 = (BitmapCol*)Mem_Alloc(bmp->width * bmp->height, 4, "window pixels"); -} - -#define TV_OFFSET_X (OSSCREEN_TV_WIDTH - OSSCREEN_DRC_WIDTH ) / 2 -#define TV_OFFSET_Y (OSSCREEN_TV_HEIGHT - OSSCREEN_DRC_HEIGHT) / 2 - -static void DrawTVOutput(struct Bitmap* bmp) { - OSScreenClearBufferEx(SCREEN_TV, 0); - - for (int y = 0; y < bmp->height; y++) - { - cc_uint32* src = bmp->scan0 + y * bmp->width; - - for (int x = 0; x < bmp->width; x++) { - OSScreenPutPixelEx(SCREEN_TV, x + TV_OFFSET_X, y + TV_OFFSET_Y, src[x]); - } - } - OSScreenFlipBuffersEx(SCREEN_TV); -} - -static void DrawDRCOutput(struct Bitmap* bmp) { - for (int y = 0; y < bmp->height; y++) - { - cc_uint32* src = bmp->scan0 + y * bmp->width; - - for (int x = 0; x < bmp->width; x++) { - OSScreenPutPixelEx(SCREEN_DRC, x, y, src[x]); - } - } - OSScreenFlipBuffersEx(SCREEN_DRC); - -} - -void Window_DrawFramebuffer(Rect2D r, struct Bitmap* bmp) { - if (launcherTop || Window_Main.Inactive) return; - - // Draw launcher output on both DRC and TV - // NOTE: Partial redraws produce bogus output, so always have to redraw all - DrawTVOutput(bmp); - DrawDRCOutput(bmp); -} - -void Window_FreeFramebuffer(struct Bitmap* bmp) { - Mem_Free(bmp->scan0); - FreeNativeFramebuffer(); - OSScreenShutdown(); -} - - -/*########################################################################################################################* -*-------------------------------------------------------Misc/Other--------------------------------------------------------* -*#########################################################################################################################*/ -void Window_SetTitle(const cc_string* title) { } -void Clipboard_GetText(cc_string* value) { } -void Clipboard_SetText(const cc_string* value) { } - -int Window_GetWindowState(void) { return WINDOW_STATE_FULLSCREEN; } -cc_result Window_EnterFullscreen(void) { return 0; } -cc_result Window_ExitFullscreen(void) { return 0; } -int Window_IsObscured(void) { return 0; } - -void Window_Show(void) { } -void Window_SetSize(int width, int height) { } - - -void OnscreenKeyboard_Open(struct OpenKeyboardArgs* args) { /* TODO implement */ } -void OnscreenKeyboard_SetText(const cc_string* text) { } -void OnscreenKeyboard_Draw2D(Rect2D* r, struct Bitmap* bmp) { } -void OnscreenKeyboard_Draw3D(void) { } -void OnscreenKeyboard_Close(void) { /* TODO implement */ } - -void Window_ShowDialog(const char* title, const char* msg) { - /* TODO implement */ - Platform_LogConst(title); - Platform_LogConst(msg); -} - -cc_result Window_OpenFileDialog(const struct OpenFileDialogArgs* args) { - return ERR_NOT_SUPPORTED; -} - -cc_result Window_SaveFileDialog(const struct SaveFileDialogArgs* args) { - return ERR_NOT_SUPPORTED; -} -#endif diff --git a/src/Window_WiiU.cpp b/src/Window_WiiU.cpp new file mode 100644 index 000000000..b046ea4cc --- /dev/null +++ b/src/Window_WiiU.cpp @@ -0,0 +1,606 @@ +#include "Core.h" +#if defined CC_BUILD_WIIU +extern "C" { +#include "Window.h" +#include "Platform.h" +#include "Input.h" +#include "Event.h" +#include "String.h" +#include "Funcs.h" +#include "Bitmap.h" +#include "Errors.h" +#include "ExtMath.h" +#include "Graphics.h" +#include "Launcher.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +} +#include + +static cc_bool launcherMode; +static cc_bool keyboardOpen; +struct _DisplayData DisplayInfo; +struct _WindowData WindowInfo; +struct _WindowData Window_Alt; +cc_bool launcherTop; + + + +static void OnscreenKeyboard_Update(void); +static void OnscreenKeyboard_DrawTV(void); +static void OnscreenKeyboard_DrawDRC(void); + +static void LoadTVDimensions(void) { + switch(GX2GetSystemTVScanMode()) + { + case GX2_TV_SCAN_MODE_480I: + case GX2_TV_SCAN_MODE_480P: + DisplayInfo.Width = 854; + DisplayInfo.Height = 480; + break; + case GX2_TV_SCAN_MODE_1080I: + case GX2_TV_SCAN_MODE_1080P: + DisplayInfo.Width = 1920; + DisplayInfo.Height = 1080; + break; + case GX2_TV_SCAN_MODE_720P: + default: + DisplayInfo.Width = 1280; + DisplayInfo.Height = 720; + break; + } +} + +static uint32_t OnAcquired(void* context) { + Window_Main.Inactive = false; + Event_RaiseVoid(&WindowEvents.InactiveChanged); + return 0; +} + +static uint32_t OnReleased(void* context) { + Window_Main.Inactive = true; + Event_RaiseVoid(&WindowEvents.InactiveChanged); + return 0; +} + +void Window_Init(void) { + LoadTVDimensions(); + DisplayInfo.ScaleX = 1; + DisplayInfo.ScaleY = 1; + + Window_Main.Width = DisplayInfo.Width; + Window_Main.Height = DisplayInfo.Height; + Window_Main.Focused = true; + Window_Main.Exists = true; + + Input.Sources = INPUT_SOURCE_GAMEPAD; + DisplayInfo.ContentOffsetX = 10; + DisplayInfo.ContentOffsetY = 10; + + Window_Main.SoftKeyboard = SOFT_KEYBOARD_RESIZE; + Input_SetTouchMode(true); + + Window_Alt.Width = 854; + Window_Alt.Height = 480; + + KPADInit(); + VPADInit(); + + ProcUIRegisterCallback(PROCUI_CALLBACK_ACQUIRE, OnAcquired, NULL, 100); + ProcUIRegisterCallback(PROCUI_CALLBACK_RELEASE, OnReleased, NULL, 100); + WHBGfxInit(); +} + +void Window_Free(void) { } + +// OSScreen is always this buffer size, regardless of the current TV resolution +#define OSSCREEN_TV_WIDTH 1280 +#define OSSCREEN_TV_HEIGHT 720 +#define OSSCREEN_DRC_WIDTH 854 +#define OSSCREEN_DRC_HEIGHT 480 +static void LauncherInactiveChanged(void* obj); +static void Init2DResources(void); + +void Window_Create2D(int width, int height) { + Window_Main.Width = OSSCREEN_DRC_WIDTH; + Window_Main.Height = OSSCREEN_DRC_HEIGHT; + + launcherMode = true; + Event_Register_(&WindowEvents.InactiveChanged, NULL, LauncherInactiveChanged); + Init2DResources(); +} + +void Window_Create3D(int width, int height) { + Window_Main.Width = DisplayInfo.Width; + Window_Main.Height = DisplayInfo.Height; + + launcherMode = false; + Event_Unregister_(&WindowEvents.InactiveChanged, NULL, LauncherInactiveChanged); +} + +void Window_RequestClose(void) { + Event_RaiseVoid(&WindowEvents.Closing); +} + + +/*########################################################################################################################* +*----------------------------------------------------Input processing-----------------------------------------------------* +*#########################################################################################################################*/ +extern Rect2D dirty_rect; +void Window_ProcessEvents(float delta) { + if (!dirty_rect.width) dirty_rect.width = 1; + + if (!WHBProcIsRunning()) { + Window_Main.Exists = false; + Window_RequestClose(); + } +} + +void Window_UpdateRawMouse(void) { } + +void Cursor_SetPosition(int x, int y) { } +void Window_EnableRawMouse(void) { Input.RawMode = true; } +void Window_DisableRawMouse(void) { Input.RawMode = false; } + + +/*########################################################################################################################* +*-------------------------------------------------------Gamepads----------------------------------------------------------* +*#########################################################################################################################*/ +static VPADStatus vpadStatus; +static bool kpad_valid[4]; +static KPADStatus kpads[4]; + +static void ProcessKPadButtons(int port, int mods) { + Gamepad_SetButton(port, CCPAD_L, mods & WPAD_BUTTON_1); + Gamepad_SetButton(port, CCPAD_R, mods & WPAD_BUTTON_2); + + Gamepad_SetButton(port, CCPAD_A, mods & WPAD_BUTTON_A); + Gamepad_SetButton(port, CCPAD_B, mods & WPAD_BUTTON_B); + Gamepad_SetButton(port, CCPAD_X, mods & WPAD_BUTTON_PLUS); + + Gamepad_SetButton(port, CCPAD_START, mods & WPAD_BUTTON_HOME); + Gamepad_SetButton(port, CCPAD_SELECT, mods & WPAD_BUTTON_MINUS); + + Gamepad_SetButton(port, CCPAD_LEFT, mods & WPAD_BUTTON_LEFT); + Gamepad_SetButton(port, CCPAD_RIGHT, mods & WPAD_BUTTON_RIGHT); + Gamepad_SetButton(port, CCPAD_UP, mods & WPAD_BUTTON_UP); + Gamepad_SetButton(port, CCPAD_DOWN, mods & WPAD_BUTTON_DOWN); +} + +static void ProcessNunchuckButtons(int port, int mods) { + Gamepad_SetButton(port, CCPAD_L, mods & WPAD_NUNCHUK_BUTTON_Z); + Gamepad_SetButton(port, CCPAD_R, mods & WPAD_NUNCHUK_BUTTON_C); +} + +static void ProcessClassicButtons(int port, int mods) { + Gamepad_SetButton(port, CCPAD_L, mods & WPAD_CLASSIC_BUTTON_L); + Gamepad_SetButton(port, CCPAD_R, mods & WPAD_CLASSIC_BUTTON_R); + Gamepad_SetButton(port, CCPAD_ZL, mods & WPAD_CLASSIC_BUTTON_ZL); + Gamepad_SetButton(port, CCPAD_ZR, mods & WPAD_CLASSIC_BUTTON_ZR); + + Gamepad_SetButton(port, CCPAD_A, mods & WPAD_CLASSIC_BUTTON_A); + Gamepad_SetButton(port, CCPAD_B, mods & WPAD_CLASSIC_BUTTON_B); + Gamepad_SetButton(port, CCPAD_X, mods & WPAD_CLASSIC_BUTTON_X); + Gamepad_SetButton(port, CCPAD_Y, mods & WPAD_CLASSIC_BUTTON_Y); + + Gamepad_SetButton(port, CCPAD_START, mods & WPAD_CLASSIC_BUTTON_HOME); + Gamepad_SetButton(port, CCPAD_SELECT, mods & WPAD_CLASSIC_BUTTON_MINUS); + Gamepad_SetButton(port, CCPAD_Z, mods & WPAD_CLASSIC_BUTTON_PLUS); + + Gamepad_SetButton(port, CCPAD_LEFT, mods & WPAD_CLASSIC_BUTTON_LEFT); + Gamepad_SetButton(port, CCPAD_RIGHT, mods & WPAD_CLASSIC_BUTTON_RIGHT); + Gamepad_SetButton(port, CCPAD_UP, mods & WPAD_CLASSIC_BUTTON_UP); + Gamepad_SetButton(port, CCPAD_DOWN, mods & WPAD_CLASSIC_BUTTON_DOWN); +} + +static void ProcessProButtons(int port, int mods) { + Gamepad_SetButton(port, CCPAD_L, mods & WPAD_PRO_TRIGGER_L); + Gamepad_SetButton(port, CCPAD_R, mods & WPAD_PRO_TRIGGER_R); + Gamepad_SetButton(port, CCPAD_ZL, mods & WPAD_PRO_TRIGGER_ZL); + Gamepad_SetButton(port, CCPAD_ZR, mods & WPAD_PRO_TRIGGER_ZR); + + Gamepad_SetButton(port, CCPAD_A, mods & WPAD_PRO_BUTTON_A); + Gamepad_SetButton(port, CCPAD_B, mods & WPAD_PRO_BUTTON_B); + Gamepad_SetButton(port, CCPAD_X, mods & WPAD_PRO_BUTTON_X); + Gamepad_SetButton(port, CCPAD_Y, mods & WPAD_PRO_BUTTON_Y); + + Gamepad_SetButton(port, CCPAD_START, mods & WPAD_PRO_BUTTON_HOME); + Gamepad_SetButton(port, CCPAD_SELECT, mods & WPAD_PRO_BUTTON_MINUS); + Gamepad_SetButton(port, CCPAD_Z, mods & WPAD_PRO_BUTTON_PLUS); + Gamepad_SetButton(port, CCPAD_LSTICK, mods & WPAD_PRO_BUTTON_STICK_L); + Gamepad_SetButton(port, CCPAD_RSTICK, mods & WPAD_PRO_BUTTON_STICK_R); + + Gamepad_SetButton(port, CCPAD_LEFT, mods & WPAD_PRO_BUTTON_LEFT); + Gamepad_SetButton(port, CCPAD_RIGHT, mods & WPAD_PRO_BUTTON_RIGHT); + Gamepad_SetButton(port, CCPAD_UP, mods & WPAD_PRO_BUTTON_UP); + Gamepad_SetButton(port, CCPAD_DOWN, mods & WPAD_PRO_BUTTON_DOWN); +} + +static void ProcessKPAD(float delta, int i) { + kpad_valid[i] = false; + int res = KPADRead((WPADChan)(WPAD_CHAN_0 + i), &kpads[i], 1); + + if (res != KPAD_ERROR_OK) return; + kpad_valid[i] = true; + + switch (kpads[i].extensionType) + { + case WPAD_EXT_CLASSIC: + ProcessClassicButtons(i, kpads[i].classic.hold | kpads[i].classic.trigger); + break; + case WPAD_EXT_PRO_CONTROLLER: + ProcessProButtons( i, kpads[i].pro.hold | kpads[i].pro.trigger); + break; + case WPAD_EXT_NUNCHUK: + ProcessKPadButtons(i, kpads[i].hold | kpads[i].trigger); + ProcessNunchuckButtons(i, kpads[i].nunchuck.hold | kpads[i].nunchuck.trigger); + break; + default: + ProcessKPadButtons(i, kpads[i].hold | kpads[i].trigger); + break; + } +} + + +#define AXIS_SCALE 4.0f +static void ProcessVpadStick(int port, int axis, float x, float y, float delta) { + // May not be exactly 0 on actual hardware + if (Math_AbsF(x) <= 0.1f) x = 0; + if (Math_AbsF(y) <= 0.1f) y = 0; + + Gamepad_SetAxis(port, axis, x * AXIS_SCALE, -y * AXIS_SCALE, delta); +} + +static void ProcessVpadButtons(int port, int mods) { + Gamepad_SetButton(port, CCPAD_L, mods & VPAD_BUTTON_L); + Gamepad_SetButton(port, CCPAD_R, mods & VPAD_BUTTON_R); + Gamepad_SetButton(port, CCPAD_ZL, mods & VPAD_BUTTON_ZL); + Gamepad_SetButton(port, CCPAD_ZR, mods & VPAD_BUTTON_ZR); + + Gamepad_SetButton(port, CCPAD_A, mods & VPAD_BUTTON_A); + Gamepad_SetButton(port, CCPAD_B, mods & VPAD_BUTTON_B); + Gamepad_SetButton(port, CCPAD_X, mods & VPAD_BUTTON_X); + Gamepad_SetButton(port, CCPAD_Y, mods & VPAD_BUTTON_Y); + + Gamepad_SetButton(port, CCPAD_START, mods & VPAD_BUTTON_PLUS); + Gamepad_SetButton(port, CCPAD_SELECT, mods & VPAD_BUTTON_MINUS); + + Gamepad_SetButton(port, CCPAD_LEFT, mods & VPAD_BUTTON_LEFT); + Gamepad_SetButton(port, CCPAD_RIGHT, mods & VPAD_BUTTON_RIGHT); + Gamepad_SetButton(port, CCPAD_UP, mods & VPAD_BUTTON_UP); + Gamepad_SetButton(port, CCPAD_DOWN, mods & VPAD_BUTTON_DOWN); + +} + +static void ProcessVpadTouch(VPADTouchData* data) { + static int was_touched; + + // TODO rescale to main screen size + if (data->touched) { + int x = data->x; + int y = data->y; + Platform_Log2("TOUCH: %i, %i", &x, &y); + + x = x * Window_Main.Width / 1280; + y = y * Window_Main.Height / 720; + + Input_AddTouch(0, x, y); + } else if (was_touched) { + Input_RemoveTouch(0, Pointers[0].x, Pointers[0].y); + } + was_touched = data->touched; +} + +static void ProcessVPAD(float delta) { + VPADReadError error = VPAD_READ_SUCCESS; + VPADRead(VPAD_CHAN_0, &vpadStatus, 1, &error); + if (error != VPAD_READ_SUCCESS) return; + + VPADGetTPCalibratedPoint(VPAD_CHAN_0, &vpadStatus.tpNormal, &vpadStatus.tpNormal); + ProcessVpadButtons(0, vpadStatus.hold); + ProcessVpadTouch(&vpadStatus.tpNormal); + + ProcessVpadStick(0, PAD_AXIS_LEFT, vpadStatus.leftStick.x, vpadStatus.leftStick.y, delta); + ProcessVpadStick(0, PAD_AXIS_RIGHT, vpadStatus.rightStick.x, vpadStatus.rightStick.y, delta); +} + + +void Window_ProcessGamepads(float delta) { + ProcessVPAD(delta); + for (int i = 0; i < 4; i++) + ProcessKPAD(delta, i); + + if (keyboardOpen) OnscreenKeyboard_Update(); +} + + +/*########################################################################################################################* +*------------------------------------------------------Framebuffer--------------------------------------------------------* +*#########################################################################################################################*/ +static GfxResourceID framebuffer_vb; + +static void LauncherInactiveChanged(void* obj) { + // TODO +} + +static void Init2DResources(void) { + Gfx_Create(); + if (framebuffer_vb) return; + + struct VertexTextured* data = (struct VertexTextured*)Gfx_RecreateAndLockVb(&framebuffer_vb, + VERTEX_FORMAT_TEXTURED, 4); + data[0].x = -1.0f; data[0].y = -1.0f; data[0].z = 0.0f; data[0].Col = PACKEDCOL_WHITE; data[0].U = 0.0f; data[0].V = 1.0f; + data[1].x = 1.0f; data[1].y = -1.0f; data[1].z = 0.0f; data[1].Col = PACKEDCOL_WHITE; data[1].U = 1.0f; data[1].V = 1.0f; + data[2].x = 1.0f; data[2].y = 1.0f; data[2].z = 0.0f; data[2].Col = PACKEDCOL_WHITE; data[2].U = 1.0f; data[2].V = 0.0f; + data[3].x = -1.0f; data[3].y = 1.0f; data[3].z = 0.0f; data[3].Col = PACKEDCOL_WHITE; data[3].U = 0.0f; data[2].V = 0.0f; + + Gfx_UnlockVb(framebuffer_vb); +} + +static GX2Texture fb; +void Window_AllocFramebuffer(struct Bitmap* bmp) { + fb.surface.width = bmp->width; + fb.surface.height = bmp->height; + fb.surface.depth = 1; + fb.surface.dim = GX2_SURFACE_DIM_TEXTURE_2D; + fb.surface.format = GX2_SURFACE_FORMAT_UNORM_R8_G8_B8_A8; + fb.surface.tileMode = GX2_TILE_MODE_LINEAR_ALIGNED; + fb.viewNumSlices = 1; + fb.compMap = 0x00010203; + GX2CalcSurfaceSizeAndAlignment(&fb.surface); + GX2InitTextureRegs(&fb); + + fb.surface.image = MEMAllocFromDefaultHeapEx(fb.surface.imageSize, fb.surface.alignment); + bmp->scan0 = (BitmapCol*)Mem_Alloc(bmp->width * bmp->height, 4, "window pixels"); +} + +static void DrawLauncher(void) { + Gfx_LoadIdentityMatrix(MATRIX_VIEW); + Gfx_LoadIdentityMatrix(MATRIX_PROJECTION); + Gfx_SetDepthTest(false); + + Gfx_SetVertexFormat(VERTEX_FORMAT_COLOURED); + Gfx_SetVertexFormat(VERTEX_FORMAT_TEXTURED); + Gfx_BindTexture(&fb); + Gfx_BindVb(framebuffer_vb); + Gfx_DrawVb_IndexedTris(4); +} + +static void DrawTV(void) { + WHBGfxBeginRenderTV(); + WHBGfxClearColor(0.7f, 0.7f, 0.7f, 1.0f); + DrawLauncher(); + if (keyboardOpen) OnscreenKeyboard_DrawTV(); + WHBGfxFinishRenderTV(); +} + +static void DrawDRC(void) { + WHBGfxBeginRenderDRC(); + WHBGfxClearColor(0.7f, 0.7f, 0.7f, 1.0f); + DrawLauncher(); + if (keyboardOpen) OnscreenKeyboard_DrawDRC(); + WHBGfxFinishRenderDRC(); +} + +void Window_DrawFramebuffer(Rect2D r, struct Bitmap* bmp) { + if (launcherTop || Window_Main.Inactive) return; + + struct Bitmap part; + part.scan0 = Bitmap_GetRow(bmp, r.y) + r.x; + part.width = r.width; + part.height = r.height; + Gfx_UpdateTexture(&fb, r.x, r.y, &part, bmp->width, false); + + WHBGfxBeginRender(); + DrawDRC(); + DrawTV(); + WHBGfxFinishRender(); +} + +void Window_FreeFramebuffer(struct Bitmap* bmp) { + MEMFreeToDefaultHeap(fb.surface.image); + Mem_Free(bmp->scan0); +} + + +/*########################################################################################################################* +*-------------------------------------------------------Misc/Other--------------------------------------------------------* +*#########################################################################################################################*/ +void Window_SetTitle(const cc_string* title) { } +void Clipboard_GetText(cc_string* value) { } +void Clipboard_SetText(const cc_string* value) { } + +int Window_GetWindowState(void) { return WINDOW_STATE_FULLSCREEN; } +cc_result Window_EnterFullscreen(void) { return 0; } +cc_result Window_ExitFullscreen(void) { return 0; } +int Window_IsObscured(void) { return 0; } + +void Window_Show(void) { } +void Window_SetSize(int width, int height) { } + +void Window_ShowDialog(const char* title, const char* msg) { + /* TODO implement */ + Platform_LogConst(title); + Platform_LogConst(msg); +} + +cc_result Window_OpenFileDialog(const struct OpenFileDialogArgs* args) { + return ERR_NOT_SUPPORTED; +} + +cc_result Window_SaveFileDialog(const struct SaveFileDialogArgs* args) { + return ERR_NOT_SUPPORTED; +} + + +/*########################################################################################################################* +*----------------------------------------------------Onscreen keyboard----------------------------------------------------* +*#########################################################################################################################*/ +static FSClient* fs_client; +static nn::swkbd::CreateArg create_arg; +static nn::swkbd::AppearArg appear_arg; + +static char kb_buffer[512]; +static cc_string kb_str = String_FromArray(kb_buffer); +#define UNI_STR_LENGTH 64 + +static int UniString_Length(const char16_t* raw) { + int length = 0; + while (length < UInt16_MaxValue && *raw) { raw++; length++; } + return length; +} + +static void UniString_WriteConst(const char* src, char16_t* dst) { + while (*src) { *dst++ = *src++; } + *dst = '\0'; +} + +static void UniString_WriteString(const cc_string* src, char16_t* dst) { + int len = min(src->length, UNI_STR_LENGTH); + + for (int i = 0; i < len; i++) + { + *dst++ = Convert_CP437ToUnicode(src->buffer[i]); + } + *dst = '\0'; +} + + +void OnscreenKeyboard_Open(struct OpenKeyboardArgs* args) { + if (keyboardOpen) OnscreenKeyboard_Close(); + char16_t hint[UNI_STR_LENGTH + 1] = { 0 }; + char16_t initial[UNI_STR_LENGTH + 1] = { 0 }; + int mode = args->type & 0xFF; + + kb_str.length = 0; + keyboardOpen = true; + Window_Main.SoftKeyboardFocus = true; + + fs_client = (FSClient *)MEMAllocFromDefaultHeap(sizeof(FSClient)); + FSAddClient(fs_client, FS_ERROR_FLAG_NONE); + + Mem_Set(&create_arg, 0, sizeof(create_arg)); + create_arg.regionType = nn::swkbd::RegionType::Europe; + create_arg.workMemory = MEMAllocFromDefaultHeap(nn::swkbd::GetWorkMemorySize(0)); + create_arg.fsClient = fs_client; + + if (!nn::swkbd::Create(create_arg)) { + Platform_LogConst("nn::swkbd::Create failed"); + return; + } + + nn::swkbd::MuteAllSound(false); + Mem_Set(&appear_arg, 0, sizeof(appear_arg)); + + nn::swkbd::ConfigArg* cfg = &appear_arg.keyboardArg.configArg; + cfg->languageType = nn::swkbd::LanguageType::English; + cfg->okString = args->type & KEYBOARD_FLAG_SEND ? u"Send" : u"OK"; + + if (mode == KEYBOARD_TYPE_INTEGER) { + cfg->keyboardMode = nn::swkbd::KeyboardMode::Numpad; + cfg->numpadCharLeft = '-'; + cfg->numpadCharRight = 0; + } else if (mode == KEYBOARD_TYPE_NUMBER) { + cfg->keyboardMode = nn::swkbd::KeyboardMode::Numpad; + cfg->numpadCharLeft = '-'; + cfg->numpadCharRight = '.'; + } + + nn::swkbd::InputFormArg* ipt = &appear_arg.inputFormArg; + UniString_WriteConst(args->placeholder, hint); + UniString_WriteString(args->text, initial); + ipt->hintText = hint; + ipt->initialText = initial; + + if (mode == KEYBOARD_TYPE_PASSWORD) + ipt->passwordMode = nn::swkbd::PasswordMode::Hide; + + if (!nn::swkbd::AppearInputForm(appear_arg)) { + Platform_LogConst("nn::swkbd::AppearInputForm failed"); + return; + } +} + +static void ProcessKeyboardInput(void) { + char tmpBuffer[NATIVE_STR_LEN]; + cc_string tmp = String_FromArray(tmpBuffer); + + const char16_t* str = nn::swkbd::GetInputFormString(); + if (!str) return; + String_AppendUtf16(&tmp, str, UniString_Length(str)); + + if (String_Equals(&tmp, &kb_str)) return; + String_Copy(&kb_str, &tmp); + Event_RaiseString(&InputEvents.TextChanged, &tmp); +} + +static void OnscreenKeyboard_Update(void) { + nn::swkbd::ControllerInfo controllerInfo; + controllerInfo.vpad = &vpadStatus; + controllerInfo.kpad[0] = kpad_valid[0] ? &kpads[0] : nullptr; + controllerInfo.kpad[1] = kpad_valid[1] ? &kpads[1] : nullptr; + controllerInfo.kpad[2] = kpad_valid[2] ? &kpads[2] : nullptr; + controllerInfo.kpad[3] = kpad_valid[3] ? &kpads[3] : nullptr; + nn::swkbd::Calc(controllerInfo); + + if (nn::swkbd::IsNeedCalcSubThreadFont()) { + nn::swkbd::CalcSubThreadFont(); + } + + if (nn::swkbd::IsNeedCalcSubThreadPredict()) { + nn::swkbd::CalcSubThreadPredict(); + } + ProcessKeyboardInput(); + + if (nn::swkbd::IsDecideOkButton(nullptr)) { + Input_SetPressed(CCKEY_ENTER); + Input_SetReleased(CCKEY_ENTER); + OnscreenKeyboard_Close(); + return; + } + + if (nn::swkbd::IsDecideCancelButton(nullptr)) { + OnscreenKeyboard_Close(); + return; + } +} + +static void OnscreenKeyboard_DrawTV(void) { + nn::swkbd::DrawTV(); +} + +static void OnscreenKeyboard_DrawDRC(void) { + nn::swkbd::DrawDRC(); +} + + +void OnscreenKeyboard_SetText(const cc_string* text) { } +void OnscreenKeyboard_Draw2D(Rect2D* r, struct Bitmap* bmp) { } +void OnscreenKeyboard_Draw3D(void) { } + +void OnscreenKeyboard_Close(void) { + if (!keyboardOpen) return; + keyboardOpen = false; + Window_Main.SoftKeyboardFocus = false; + + nn::swkbd::DisappearInputForm(); + nn::swkbd::Destroy(); + MEMFreeToDefaultHeap(create_arg.workMemory); + + FSDelClient(fs_client, FS_ERROR_FLAG_NONE); + MEMFreeToDefaultHeap(fs_client); +} +#endif diff --git a/src/Window_Win.c b/src/Window_Win.c index bd8efb382..3e8ac81ef 100644 --- a/src/Window_Win.c +++ b/src/Window_Win.c @@ -53,7 +53,7 @@ static cc_bool is_ansiWindow, grabCursor; static int windowX, windowY; static const cc_uint8 key_map[14 * 16] = { - 0, 0, 0, 0, 0, 0, 0, 0, CCKEY_BACKSPACE, CCKEY_TAB, 0, 0, 0, CCKEY_ENTER, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, CCKEY_BACKSPACE, CCKEY_TAB, 0, 0, CCKEY_F5, CCKEY_ENTER, 0, 0, 0, 0, 0, CCKEY_PAUSE, CCKEY_CAPSLOCK, 0, 0, 0, 0, 0, 0, CCKEY_ESCAPE, 0, 0, 0, 0, CCKEY_SPACE, CCKEY_PAGEUP, CCKEY_PAGEDOWN, CCKEY_END, CCKEY_HOME, CCKEY_LEFT, CCKEY_UP, CCKEY_RIGHT, CCKEY_DOWN, 0, CCKEY_PRINTSCREEN, 0, CCKEY_PRINTSCREEN, CCKEY_INSERT, CCKEY_DELETE, 0, '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 0, 0, 0, 0, 0, 0, diff --git a/src/Window_X11.c b/src/Window_X11.c index 0c55e075d..bab0f3756 100644 --- a/src/Window_X11.c +++ b/src/Window_X11.c @@ -474,8 +474,17 @@ static int MapNativeMouse(int button) { if (button == 1) return CCMOUSE_L; if (button == 2) return CCMOUSE_M; if (button == 3) return CCMOUSE_R; - if (button == 8) return CCMOUSE_X1; - if (button == 9) return CCMOUSE_X2; + + if (button == 8) return CCMOUSE_X1; + if (button == 9) return CCMOUSE_X2; + if (button == 10) return CCMOUSE_X3; + if (button == 11) return CCMOUSE_X4; + if (button == 12) return CCMOUSE_X5; + if (button == 13) return CCMOUSE_X6; + + /* Mouse horizontal and vertical scroll */ + if (button >= 4 && button <= 7) return 0; + Platform_Log1("Unknown mouse button: %i", &button); return 0; } diff --git a/src/Window_Xbox.c b/src/Window_Xbox.c index 43f3c0b6c..e6eeac7dc 100644 --- a/src/Window_Xbox.c +++ b/src/Window_Xbox.c @@ -40,6 +40,7 @@ static void OnDataReceived(UTR_T* utr) { } static void OnDeviceChanged(xid_dev_t *xid_dev__, int status__) { + Platform_LogConst("Getting devices"); xid_dev_t* xid_dev = usbh_xid_get_device_list(); Platform_LogConst("Devices check"); @@ -75,11 +76,13 @@ void Window_Init(void) { DisplayInfo.ContentOffsetX = 10; DisplayInfo.ContentOffsetY = 10; +#ifndef CC_BUILD_CXBX usbh_core_init(); usbh_xid_init(); usbh_install_xid_conn_callback(OnDeviceChanged, OnDeviceChanged); OnDeviceChanged(NULL, 0); // TODO useless call? +#endif } void Window_Free(void) { usbh_core_deinit(); } @@ -108,7 +111,9 @@ void Window_RequestClose(void) { *----------------------------------------------------Input processing-----------------------------------------------------* *#########################################################################################################################*/ void Window_ProcessEvents(float delta) { +#ifndef CC_BUILD_CXBX usbh_pooling_hubs(); +#endif } void Cursor_SetPosition(int x, int y) { } // Makes no sense for Xbox diff --git a/src/Window_Xbox360.c b/src/Window_Xbox360.c index 5da252e10..70f18a3ff 100644 --- a/src/Window_Xbox360.c +++ b/src/Window_Xbox360.c @@ -96,8 +96,10 @@ struct controller_data_s */ static void HandleButtons(int port, struct controller_data_s* pad) { - Gamepad_SetButton(port, CCPAD_L, pad->lb); - Gamepad_SetButton(port, CCPAD_R, pad->rb); + Gamepad_SetButton(port, CCPAD_L, pad->lb); + Gamepad_SetButton(port, CCPAD_R, pad->rb); + Gamepad_SetButton(port, CCPAD_LSTICK, pad->lt > 100); + Gamepad_SetButton(port, CCPAD_RSTICK, pad->rt > 100); Gamepad_SetButton(port, CCPAD_A, pad->a); Gamepad_SetButton(port, CCPAD_B, pad->b); @@ -113,12 +115,22 @@ static void HandleButtons(int port, struct controller_data_s* pad) { Gamepad_SetButton(port, CCPAD_DOWN, pad->down); } +#define AXIS_SCALE 8192.0f +static void HandleJoystick(int port, int axis, int x, int y, float delta) { + if (Math_AbsI(x) <= 4096) x = 0; + if (Math_AbsI(y) <= 4096) y = 0; + + Gamepad_SetAxis(port, axis, x / AXIS_SCALE, -y / AXIS_SCALE, delta); +} + void Window_ProcessGamepads(float delta) { struct controller_data_s pad; int res = get_controller_data(&pad, 0); if (res == 0) return; HandleButtons(0, &pad); + HandleJoystick(0, PAD_AXIS_LEFT, pad.s1_x, pad.s1_y, delta); + HandleJoystick(0, PAD_AXIS_RIGHT, pad.s2_x, pad.s2_y, delta); } diff --git a/src/_GLShared.h b/src/_GLShared.h index bc0b47041..4d6f1740e 100644 --- a/src/_GLShared.h +++ b/src/_GLShared.h @@ -177,7 +177,7 @@ void Gfx_DisableMipmaps(void) { } *#########################################################################################################################*/ static PackedCol gfx_clearColor; void Gfx_SetFaceCulling(cc_bool enabled) { gl_Toggle(GL_CULL_FACE); } -void Gfx_SetAlphaBlending(cc_bool enabled) { gl_Toggle(GL_BLEND); } +static void SetAlphaBlend(cc_bool enabled) { gl_Toggle(GL_BLEND); } void Gfx_SetAlphaArgBlend(cc_bool enabled) { } static void GL_ClearColor(PackedCol color) { diff --git a/src/_GraphicsBase.h b/src/_GraphicsBase.h index b61cedb51..b1e9a7e1c 100644 --- a/src/_GraphicsBase.h +++ b/src/_GraphicsBase.h @@ -31,6 +31,23 @@ static float gfx_minFrameMs; *#########################################################################################################################*/ static cc_bool gfx_colorMask[4] = { true, true, true, true }; cc_bool Gfx_GetFog(void) { return gfx_fogEnabled; } +static cc_bool gfx_alphaTest, gfx_alphaBlend; + +static void SetAlphaTest(cc_bool enabled); +void Gfx_SetAlphaTest(cc_bool enabled) { + if (gfx_alphaTest == enabled) return; + + gfx_alphaTest = enabled; + SetAlphaTest(enabled); +} + +static void SetAlphaBlend(cc_bool enabled); +void Gfx_SetAlphaBlending(cc_bool enabled) { + if (gfx_alphaBlend == enabled) return; + + gfx_alphaBlend = enabled; + SetAlphaBlend(enabled); +} /* Initialises/Restores render state */ CC_NOINLINE static void Gfx_RestoreState(void); @@ -256,6 +273,7 @@ void Gfx_Make2DQuad(const struct Texture* tex, PackedCol color, struct VertexTex *vertices = v; } +#ifndef CC_BUILD_PS1 static cc_bool gfx_hadFog; void Gfx_Begin2D(int width, int height) { struct Matrix ortho; @@ -275,6 +293,7 @@ void Gfx_End2D(void) { Gfx_SetAlphaBlending(false); if (gfx_hadFog) Gfx_SetFog(true); } +#endif /*########################################################################################################################* diff --git a/src/_PlatformBase.h b/src/_PlatformBase.h index f6889ce21..d2b9e0b0a 100644 --- a/src/_PlatformBase.h +++ b/src/_PlatformBase.h @@ -2,6 +2,7 @@ #include "String.h" #include "Logger.h" #include "Constants.h" +#include "Errors.h" cc_bool Platform_ReadonlyFilesystem; /*########################################################################################################################* @@ -89,6 +90,21 @@ int Stopwatch_ElapsedMS(cc_uint64 beg, cc_uint64 end) { return (int)raw / 1000; } +cc_result Socket_WriteAll(cc_socket socket, const cc_uint8* data, cc_uint32 count) { + cc_uint32 sent; + cc_result res; + + while (count) + { + if ((res = Socket_Write(socket, data, count, &sent))) return res; + if (!sent) return ERR_END_OF_STREAM; + + data += sent; + count -= sent; + } + return 0; +} + /*########################################################################################################################* *-------------------------------------------------------Dynamic lib-------------------------------------------------------* diff --git a/src/_WindowBase.h b/src/_WindowBase.h index 02fcec3ed..e9adf64f8 100644 --- a/src/_WindowBase.h +++ b/src/_WindowBase.h @@ -74,7 +74,7 @@ void Window_ShowDialog(const char* title, const char* msg) { struct GraphicsMode { int R, G, B, A; }; /* Creates a GraphicsMode compatible with the default display device */ -static void InitGraphicsMode(struct GraphicsMode* m) { +static CC_INLINE void InitGraphicsMode(struct GraphicsMode* m) { int bpp = DisplayInfo.Depth; m->A = 0; diff --git a/src/interop_cocoa.m b/src/interop_cocoa.m index 7e1b36ba9..10c32a1f3 100644 --- a/src/interop_cocoa.m +++ b/src/interop_cocoa.m @@ -434,8 +434,15 @@ static int MapNativeMouse(long button) { if (button == 0) return CCMOUSE_L; if (button == 1) return CCMOUSE_R; if (button == 2) return CCMOUSE_M; + if (button == 3) return CCMOUSE_X1; if (button == 4) return CCMOUSE_X2; + if (button == 5) return CCMOUSE_X3; + if (button == 6) return CCMOUSE_X4; + if (button == 7) return CCMOUSE_X5; + if (button == 8) return CCMOUSE_X6; + + Platform_Log1("Unknown mouse button: %i", &button); return 0; } diff --git a/src/interop_ios.m b/src/interop_ios.m index 25c95d718..417470632 100644 --- a/src/interop_ios.m +++ b/src/interop_ios.m @@ -44,6 +44,7 @@ static CCViewController* cc_controller; static UIWindow* win_handle; static UIView* view_handle; +static cc_bool launcherMode; static void AddTouch(UITouch* t) { CGPoint loc = [t locationInView:view_handle]; @@ -93,6 +94,9 @@ static CGRect GetViewFrame(void) { - (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent *)event { // touchesBegan:withEvent - iOS 2.0 for (UITouch* t in touches) AddTouch(t); + + // clicking on the background should dismiss onscren keyboard + if (launcherMode) { [view_handle endEditing:NO]; } } - (void)touchesMoved:(NSSet*)touches withEvent:(UIEvent *)event { @@ -687,6 +691,7 @@ cc_result Window_SaveFileDialog(const struct SaveFileDialogArgs* args) { *--------------------------------------------------------2D window--------------------------------------------------------* *#########################################################################################################################*/ void Window_Create2D(int width, int height) { + launcherMode = true; CGRect bounds = DoCreateWindow(); view_handle = [[UIView alloc] initWithFrame:bounds]; @@ -716,8 +721,10 @@ static void GLContext_OnLayout(void); @end void Window_Create3D(int width, int height) { - // CAEAGLLayer - iOS 2.0 + launcherMode = false; CGRect bounds = DoCreateWindow(); + + // CAEAGLLayer - iOS 2.0 view_handle = [[CCGLView alloc] initWithFrame:bounds]; view_handle.multipleTouchEnabled = true; cc_controller.view = view_handle; @@ -1828,4 +1835,4 @@ void LBackend_CloseScreen(struct LScreen* s) { { [view removeFromSuperview]; } -} +} \ No newline at end of file diff --git a/src/interop_web.js b/src/interop_web.js index 4d34ade3d..a6bd7c288 100644 --- a/src/interop_web.js +++ b/src/interop_web.js @@ -350,8 +350,8 @@ mergeInto(LibraryManager.library, { // previously you were required to add interop_LoadIndexedDB to Module.preRun array // to load the indexedDB asynchronously *before* starting ClassiCube, because it // could not load indexedDB asynchronously - // however, as ClassiCube now loads IndexedDB asynchronously itself, this is no longer - // necessary, but is kept arounf foe backwards compatibility + // however, as ClassiCube now loads IndexedDB asynchronously itself, this is + // no longer necessary, but is kept around for backwards compatibility }, interop_SaveNode__deps: ['IDBFS_getDB', 'IDBFS_storeRemoteEntry'], interop_SaveNode: function(path) { @@ -441,7 +441,7 @@ mergeInto(LibraryManager.library, { req.onsuccess = function() { db = req.result; window.IDBFS_db = db; - // browser will sometimes close connection behind the scenes + // browser will sometimes close IndexedDB connection behind the scenes db.onclose = function(ev) { console.log('IndexedDB connection closed unexpectedly!'); window.IDBFS_db = null; diff --git a/third_party/gldc/src/aligned_vector.c b/third_party/gldc/src/aligned_vector.c deleted file mode 100644 index 659983557..000000000 --- a/third_party/gldc/src/aligned_vector.c +++ /dev/null @@ -1,27 +0,0 @@ -#include -#include -#include -#include -#include - -#include "private.h" -#include "aligned_vector.h" - -extern inline void* aligned_vector_resize(AlignedVector* vector, const uint32_t element_count); -extern inline void* aligned_vector_extend(AlignedVector* vector, const uint32_t additional_count); -extern inline void* aligned_vector_reserve(AlignedVector* vector, uint32_t element_count); -extern inline void* aligned_vector_push_back(AlignedVector* vector, const void* objs, uint32_t count); - -void aligned_vector_init(AlignedVector* vector, uint32_t element_size) { - /* Now initialize the header*/ - AlignedVectorHeader* const hdr = &vector->hdr; - hdr->size = 0; - hdr->capacity = ALIGNED_VECTOR_CHUNK_SIZE; - hdr->element_size = element_size; - vector->data = NULL; - - /* Reserve some initial capacity. This will do the allocation but not set up the header */ - void* ptr = aligned_vector_reserve(vector, ALIGNED_VECTOR_CHUNK_SIZE); - assert(ptr); - (void) ptr; -} diff --git a/third_party/gldc/src/aligned_vector.h b/third_party/gldc/src/aligned_vector.h index 22bfbace1..7b152dbe0 100644 --- a/third_party/gldc/src/aligned_vector.h +++ b/third_party/gldc/src/aligned_vector.h @@ -56,11 +56,11 @@ AV_FORCE_INLINE void *AV_MEMCPY4(void *dest, const void *src, size_t len) #else #define AV_MEMCPY4 memcpy #endif +#define AV_ELEMENT_SIZE 32 typedef struct { uint32_t size; uint32_t capacity; - uint32_t element_size; } __attribute__((aligned(32))) AlignedVectorHeader; typedef struct { @@ -75,27 +75,24 @@ typedef struct { ((((v) + ALIGNED_VECTOR_CHUNK_SIZE - 1) / ALIGNED_VECTOR_CHUNK_SIZE) * ALIGNED_VECTOR_CHUNK_SIZE) -void aligned_vector_init(AlignedVector* vector, uint32_t element_size); - AV_FORCE_INLINE void* aligned_vector_at(const AlignedVector* vector, const uint32_t index) { const AlignedVectorHeader* hdr = &vector->hdr; assert(index < hdr->size); - return vector->data + (index * hdr->element_size); + return vector->data + (index * AV_ELEMENT_SIZE); } AV_FORCE_INLINE void* aligned_vector_reserve(AlignedVector* vector, uint32_t element_count) { AlignedVectorHeader* hdr = &vector->hdr; + uint32_t original_byte_size = (hdr->size * AV_ELEMENT_SIZE); if(element_count < hdr->capacity) { - return aligned_vector_at(vector, element_count); + return vector->data + original_byte_size; } - uint32_t original_byte_size = (hdr->size * hdr->element_size); - /* We overallocate so that we don't make small allocations during push backs */ element_count = ROUND_TO_CHUNK_SIZE(element_count); - uint32_t new_byte_size = (element_count * hdr->element_size); + uint32_t new_byte_size = (element_count * AV_ELEMENT_SIZE); uint8_t* original_data = vector->data; vector->data = (uint8_t*) memalign(0x20, new_byte_size); @@ -169,10 +166,7 @@ AV_FORCE_INLINE void* aligned_vector_push_back(AlignedVector* vector, const void AlignedVectorHeader* hdr = &vector->hdr; assert(count); - assert(hdr->element_size); - #ifndef NDEBUG - uint32_t element_size = hdr->element_size; uint32_t initial_size = hdr->size; #endif @@ -180,9 +174,8 @@ AV_FORCE_INLINE void* aligned_vector_push_back(AlignedVector* vector, const void assert(dest); /* Copy the objects in */ - AV_MEMCPY4(dest, objs, hdr->element_size * count); + AV_MEMCPY4(dest, objs, count * AV_ELEMENT_SIZE); - assert(hdr->element_size == element_size); assert(hdr->size == initial_size + count); return dest; } @@ -200,6 +193,15 @@ AV_FORCE_INLINE void aligned_vector_clear(AlignedVector* vector){ hdr->size = 0; } +AV_FORCE_INLINE void aligned_vector_init(AlignedVector* vector) { + /* Now initialize the header*/ + AlignedVectorHeader* const hdr = &vector->hdr; + hdr->size = 0; + hdr->capacity = 0; + vector->data = NULL; +} + + #ifdef __cplusplus } #endif diff --git a/third_party/gldc/src/draw.c b/third_party/gldc/src/draw.c index a5b8a77ff..417c6c99a 100644 --- a/third_party/gldc/src/draw.c +++ b/third_party/gldc/src/draw.c @@ -1,114 +1,3 @@ #include #include "private.h" -#include "platform.h" - -static const void* VERTEX_PTR; - -#define ITERATE(count) \ - GLuint i = count; \ - while(i--) - -static void generateColouredQuads(Vertex* dst, const GLsizei first, const GLuint count) { - /* Read from the client buffers and generate an array of ClipVertices */ - GLuint numQuads = count / 4; - /* Copy the pos, uv and color directly in one go */ - const GLubyte* src = VERTEX_PTR + (first * 16); - - const float w = 1.0f; - PREFETCH(src); - - // TODO: optimise - ITERATE(numQuads) { - // 4 vertices per quad - Vertex* it = dst; - - for(GLuint j = 0; j < 4; ++j) { - PREFETCH(src + 16); - TransformVertex((const float*)src, &w, it->xyz, &it->w); - - *((uint32_t*)&it->bgra) = *((uint32_t*)(src + 12)); - it->uv[0] = 0.0f; - it->uv[1] = 0.0f; - - src += 16; - it->flags = GPU_CMD_VERTEX; - it++; - } - - dst[3].flags = GPU_CMD_VERTEX_EOL; - dst += 4; - } -} - -static void generateTexturedQuads(Vertex* dst, const GLsizei first, const GLuint count) { - /* Read from the client buffers and generate an array of ClipVertices */ - GLuint numQuads = count / 4; - /* Copy the pos, uv and color directly in one go */ - const GLubyte* src = VERTEX_PTR + (first * 24); - - const float w = 1.0f; - PREFETCH(src); - - // TODO: optimise - ITERATE(numQuads) { - // 4 vertices per quad - Vertex* it = dst; - - for(GLuint j = 0; j < 4; ++j) { - PREFETCH(src + 24); - TransformVertex((const float*)src, &w, it->xyz, &it->w); - - *((uint32_t*)&it->bgra) = *((uint32_t*)(src + 12)); - *((uint32_t*)&it->uv[0]) = *((uint32_t*)(src + 16)); - *((uint32_t*)&it->uv[1]) = *((uint32_t*)(src + 20)); - - src += 24; - it->flags = GPU_CMD_VERTEX; - it++; - } - - dst[3].flags = GPU_CMD_VERTEX_EOL; - dst += 4; - } -} - -extern void apply_poly_header(PolyHeader* header, PolyList* activePolyList); - -GL_FORCE_INLINE Vertex* submitVertices(GLuint vertexCount) { - TRACE(); - PolyList* output = _glActivePolyList(); - uint32_t header_offset; - uint32_t start_offset; - - uint32_t vector_size = aligned_vector_size(&output->vector); - GLboolean header_required = (vector_size == 0) || STATE_DIRTY; - - header_offset = vector_size; - start_offset = header_offset + (header_required ? 1 : 0); - - /* Make room for the vertices and header */ - aligned_vector_extend(&output->vector, (header_required) + vertexCount); - gl_assert(header_offset < aligned_vector_size(&output->vector)); - - if (header_required) { - apply_poly_header(aligned_vector_at(&output->vector, header_offset), output); - STATE_DIRTY = GL_FALSE; - } - return aligned_vector_at(&output->vector, start_offset); -} - -void APIENTRY glDrawArrays(GLenum mode, GLint first, GLsizei count) { - TRACE(); - if (!count) return; - Vertex* start = submitVertices(count); - - if (TEXTURES_ENABLED) { - generateTexturedQuads(start, first, count); - } else { - generateColouredQuads(start, first, count); - } -} - -void APIENTRY gldcVertexPointer(GLsizei stride, const GLvoid * pointer) { - VERTEX_PTR = pointer; -} \ No newline at end of file +#include "platform.h" \ No newline at end of file diff --git a/third_party/gldc/src/flush.c b/third_party/gldc/src/flush.c index 00b4e65e3..4f3dbde3c 100644 --- a/third_party/gldc/src/flush.c +++ b/third_party/gldc/src/flush.c @@ -33,9 +33,9 @@ void APIENTRY glKosInit() { PT_LIST.list_type = GPU_LIST_PT_POLY; TR_LIST.list_type = GPU_LIST_TR_POLY; - aligned_vector_init(&OP_LIST.vector, sizeof(Vertex)); - aligned_vector_init(&PT_LIST.vector, sizeof(Vertex)); - aligned_vector_init(&TR_LIST.vector, sizeof(Vertex)); + aligned_vector_init(&OP_LIST.vector); + aligned_vector_init(&PT_LIST.vector); + aligned_vector_init(&TR_LIST.vector); aligned_vector_reserve(&OP_LIST.vector, 1024 * 3); aligned_vector_reserve(&PT_LIST.vector, 512 * 3); @@ -45,7 +45,6 @@ void APIENTRY glKosInit() { void APIENTRY glKosSwapBuffers() { TRACE(); - pvr_wait_ready(); pvr_scene_begin(); if(aligned_vector_size(&OP_LIST.vector) > 2) { @@ -72,4 +71,4 @@ void APIENTRY glKosSwapBuffers() { aligned_vector_clear(&TR_LIST.vector); _glApplyScissor(true); -} \ No newline at end of file +} diff --git a/third_party/gldc/src/platform.h b/third_party/gldc/src/platform.h index e326b9c78..f66cef13c 100644 --- a/third_party/gldc/src/platform.h +++ b/third_party/gldc/src/platform.h @@ -133,74 +133,6 @@ typedef enum GPUTextureEnv { GPU_TXRENV_MODULATEALPHA = 3 } GPUTextureEnv; -/* Duplication of pvr_poly_cxt_t from KOS so that we can - * compile on non-KOS platforms for testing */ - -typedef struct { - GPUList list_type; - - struct { - int alpha; - int shading; - int fog_type; - int culling; - int color_clamp; - int clip_mode; - int modifier_mode; - int specular; - int alpha2; - int fog_type2; - int color_clamp2; - } gen; - struct { - int src; - int dst; - int src_enable; - int dst_enable; - int src2; - int dst2; - int src_enable2; - int dst_enable2; - } blend; - struct { - int color; - int uv; - int modifier; - } fmt; - struct { - int comparison; - int write; - } depth; - struct { - int enable; - int filter; - int mipmap; - int mipmap_bias; - int uv_flip; - int uv_clamp; - int alpha; - int env; - int width; - int height; - int format; - void* base; - } txr; - struct { - int enable; - int filter; - int mipmap; - int mipmap_bias; - int uv_flip; - int uv_clamp; - int alpha; - int env; - int width; - int height; - int format; - void* base; - } txr2; -} PolyContext; - typedef struct { uint32_t cmd; uint32_t mode1; @@ -223,96 +155,6 @@ enum GPUCommand { void SceneListSubmit(Vertex* v2, int n); -#define GPU_TA_CMD_TYPE_SHIFT 24 -#define GPU_TA_CMD_TYPE_MASK (7 << GPU_TA_CMD_TYPE_SHIFT) - -#define GPU_TA_CMD_USERCLIP_SHIFT 16 -#define GPU_TA_CMD_USERCLIP_MASK (3 << GPU_TA_CMD_USERCLIP_SHIFT) - -#define GPU_TA_CMD_CLRFMT_SHIFT 4 -#define GPU_TA_CMD_CLRFMT_MASK (7 << GPU_TA_CMD_CLRFMT_SHIFT) - -#define GPU_TA_CMD_SPECULAR_SHIFT 2 -#define GPU_TA_CMD_SPECULAR_MASK (1 << GPU_TA_CMD_SPECULAR_SHIFT) - -#define GPU_TA_CMD_SHADE_SHIFT 1 -#define GPU_TA_CMD_SHADE_MASK (1 << GPU_TA_CMD_SHADE_SHIFT) - -#define GPU_TA_CMD_UVFMT_SHIFT 0 -#define GPU_TA_CMD_UVFMT_MASK (1 << GPU_TA_CMD_UVFMT_SHIFT) - -#define GPU_TA_CMD_MODIFIER_SHIFT 7 -#define GPU_TA_CMD_MODIFIER_MASK (1 << GPU_TA_CMD_MODIFIER_SHIFT) - -#define GPU_TA_CMD_MODIFIERMODE_SHIFT 6 -#define GPU_TA_CMD_MODIFIERMODE_MASK (1 << GPU_TA_CMD_MODIFIERMODE_SHIFT) - -#define GPU_TA_PM1_DEPTHCMP_SHIFT 29 -#define GPU_TA_PM1_DEPTHCMP_MASK (7 << GPU_TA_PM1_DEPTHCMP_SHIFT) - -#define GPU_TA_PM1_CULLING_SHIFT 27 -#define GPU_TA_PM1_CULLING_MASK (3 << GPU_TA_PM1_CULLING_SHIFT) - -#define GPU_TA_PM1_DEPTHWRITE_SHIFT 26 -#define GPU_TA_PM1_DEPTHWRITE_MASK (1 << GPU_TA_PM1_DEPTHWRITE_SHIFT) - -#define GPU_TA_PM1_TXRENABLE_SHIFT 25 -#define GPU_TA_PM1_TXRENABLE_MASK (1 << GPU_TA_PM1_TXRENABLE_SHIFT) - -#define GPU_TA_PM1_MODIFIERINST_SHIFT 29 -#define GPU_TA_PM1_MODIFIERINST_MASK (3 << GPU_TA_PM1_MODIFIERINST_SHIFT) - -#define GPU_TA_PM2_SRCBLEND_SHIFT 29 -#define GPU_TA_PM2_SRCBLEND_MASK (7 << GPU_TA_PM2_SRCBLEND_SHIFT) - -#define GPU_TA_PM2_DSTBLEND_SHIFT 26 -#define GPU_TA_PM2_DSTBLEND_MASK (7 << GPU_TA_PM2_DSTBLEND_SHIFT) - -#define GPU_TA_PM2_SRCENABLE_SHIFT 25 -#define GPU_TA_PM2_SRCENABLE_MASK (1 << GPU_TA_PM2_SRCENABLE_SHIFT) - -#define GPU_TA_PM2_DSTENABLE_SHIFT 24 -#define GPU_TA_PM2_DSTENABLE_MASK (1 << GPU_TA_PM2_DSTENABLE_SHIFT) - -#define GPU_TA_PM2_FOG_SHIFT 22 -#define GPU_TA_PM2_FOG_MASK (3 << GPU_TA_PM2_FOG_SHIFT) - -#define GPU_TA_PM2_CLAMP_SHIFT 21 -#define GPU_TA_PM2_CLAMP_MASK (1 << GPU_TA_PM2_CLAMP_SHIFT) - -#define GPU_TA_PM2_ALPHA_SHIFT 20 -#define GPU_TA_PM2_ALPHA_MASK (1 << GPU_TA_PM2_ALPHA_SHIFT) - -#define GPU_TA_PM2_TXRALPHA_SHIFT 19 -#define GPU_TA_PM2_TXRALPHA_MASK (1 << GPU_TA_PM2_TXRALPHA_SHIFT) - -#define GPU_TA_PM2_UVFLIP_SHIFT 17 -#define GPU_TA_PM2_UVFLIP_MASK (3 << GPU_TA_PM2_UVFLIP_SHIFT) - -#define GPU_TA_PM2_UVCLAMP_SHIFT 15 -#define GPU_TA_PM2_UVCLAMP_MASK (3 << GPU_TA_PM2_UVCLAMP_SHIFT) - -#define GPU_TA_PM2_FILTER_SHIFT 12 -#define GPU_TA_PM2_FILTER_MASK (7 << GPU_TA_PM2_FILTER_SHIFT) - -#define GPU_TA_PM2_MIPBIAS_SHIFT 8 -#define GPU_TA_PM2_MIPBIAS_MASK (15 << GPU_TA_PM2_MIPBIAS_SHIFT) - -#define GPU_TA_PM2_TXRENV_SHIFT 6 -#define GPU_TA_PM2_TXRENV_MASK (3 << GPU_TA_PM2_TXRENV_SHIFT) - -#define GPU_TA_PM2_USIZE_SHIFT 3 -#define GPU_TA_PM2_USIZE_MASK (7 << GPU_TA_PM2_USIZE_SHIFT) - -#define GPU_TA_PM2_VSIZE_SHIFT 0 -#define GPU_TA_PM2_VSIZE_MASK (7 << GPU_TA_PM2_VSIZE_SHIFT) - -#define GPU_TA_PM3_MIPMAP_SHIFT 31 -#define GPU_TA_PM3_MIPMAP_MASK (1 << GPU_TA_PM3_MIPMAP_SHIFT) - -#define GPU_TA_PM3_TXRFMT_SHIFT 0 -#define GPU_TA_PM3_TXRFMT_MASK 0xffffffff - static inline int DimensionFlag(const int w) { switch(w) { case 16: return 1; @@ -328,67 +170,4 @@ static inline int DimensionFlag(const int w) { } } -/* Compile a polygon context into a polygon header */ -static inline void CompilePolyHeader(PolyHeader *dst, const PolyContext *src) { - uint32_t txr_base; - - /* Basically we just take each parameter, clip it, shift it - into place, and OR it into the final result. */ - - /* The base values for CMD */ - dst->cmd = GPU_CMD_POLYHDR; - - dst->cmd |= src->txr.enable << 3; - - /* Or in the list type, shading type, color and UV formats */ - dst->cmd |= (src->list_type << GPU_TA_CMD_TYPE_SHIFT) & GPU_TA_CMD_TYPE_MASK; - dst->cmd |= (src->fmt.color << GPU_TA_CMD_CLRFMT_SHIFT) & GPU_TA_CMD_CLRFMT_MASK; - dst->cmd |= (src->gen.shading << GPU_TA_CMD_SHADE_SHIFT) & GPU_TA_CMD_SHADE_MASK; - dst->cmd |= (src->fmt.uv << GPU_TA_CMD_UVFMT_SHIFT) & GPU_TA_CMD_UVFMT_MASK; - dst->cmd |= (src->gen.clip_mode << GPU_TA_CMD_USERCLIP_SHIFT) & GPU_TA_CMD_USERCLIP_MASK; - dst->cmd |= (src->gen.specular << GPU_TA_CMD_SPECULAR_SHIFT) & GPU_TA_CMD_SPECULAR_MASK; - - /* Polygon mode 1 */ - dst->mode1 = (src->depth.comparison << GPU_TA_PM1_DEPTHCMP_SHIFT) & GPU_TA_PM1_DEPTHCMP_MASK; - dst->mode1 |= (src->gen.culling << GPU_TA_PM1_CULLING_SHIFT) & GPU_TA_PM1_CULLING_MASK; - dst->mode1 |= (src->depth.write << GPU_TA_PM1_DEPTHWRITE_SHIFT) & GPU_TA_PM1_DEPTHWRITE_MASK; - dst->mode1 |= (src->txr.enable << GPU_TA_PM1_TXRENABLE_SHIFT) & GPU_TA_PM1_TXRENABLE_MASK; - - /* Polygon mode 2 */ - dst->mode2 = (src->blend.src << GPU_TA_PM2_SRCBLEND_SHIFT) & GPU_TA_PM2_SRCBLEND_MASK; - dst->mode2 |= (src->blend.dst << GPU_TA_PM2_DSTBLEND_SHIFT) & GPU_TA_PM2_DSTBLEND_MASK; - dst->mode2 |= (src->blend.src_enable << GPU_TA_PM2_SRCENABLE_SHIFT) & GPU_TA_PM2_SRCENABLE_MASK; - dst->mode2 |= (src->blend.dst_enable << GPU_TA_PM2_DSTENABLE_SHIFT) & GPU_TA_PM2_DSTENABLE_MASK; - dst->mode2 |= (src->gen.fog_type << GPU_TA_PM2_FOG_SHIFT) & GPU_TA_PM2_FOG_MASK; - dst->mode2 |= (src->gen.color_clamp << GPU_TA_PM2_CLAMP_SHIFT) & GPU_TA_PM2_CLAMP_MASK; - dst->mode2 |= (src->gen.alpha << GPU_TA_PM2_ALPHA_SHIFT) & GPU_TA_PM2_ALPHA_MASK; - - if(src->txr.enable == GPU_TEXTURE_DISABLE) { - dst->mode3 = 0; - } - else { - dst->mode2 |= (src->txr.alpha << GPU_TA_PM2_TXRALPHA_SHIFT) & GPU_TA_PM2_TXRALPHA_MASK; - dst->mode2 |= (src->txr.uv_flip << GPU_TA_PM2_UVFLIP_SHIFT) & GPU_TA_PM2_UVFLIP_MASK; - dst->mode2 |= (src->txr.uv_clamp << GPU_TA_PM2_UVCLAMP_SHIFT) & GPU_TA_PM2_UVCLAMP_MASK; - dst->mode2 |= (src->txr.filter << GPU_TA_PM2_FILTER_SHIFT) & GPU_TA_PM2_FILTER_MASK; - dst->mode2 |= (src->txr.mipmap_bias << GPU_TA_PM2_MIPBIAS_SHIFT) & GPU_TA_PM2_MIPBIAS_MASK; - dst->mode2 |= (src->txr.env << GPU_TA_PM2_TXRENV_SHIFT) & GPU_TA_PM2_TXRENV_MASK; - - dst->mode2 |= (DimensionFlag(src->txr.width) << GPU_TA_PM2_USIZE_SHIFT) & GPU_TA_PM2_USIZE_MASK; - dst->mode2 |= (DimensionFlag(src->txr.height) << GPU_TA_PM2_VSIZE_SHIFT) & GPU_TA_PM2_VSIZE_MASK; - - /* Polygon mode 3 */ - dst->mode3 = (src->txr.mipmap << GPU_TA_PM3_MIPMAP_SHIFT) & GPU_TA_PM3_MIPMAP_MASK; - dst->mode3 |= (src->txr.format << GPU_TA_PM3_TXRFMT_SHIFT) & GPU_TA_PM3_TXRFMT_MASK; - - /* Convert the texture address */ - txr_base = (uint32_t) src->txr.base; - txr_base = (txr_base & 0x00fffff8) >> 3; - dst->mode3 |= txr_base; - } - - dst->d1 = dst->d2 = 0xffffffff; - dst->d3 = dst->d4 = 0xffffffff; -} - #include "sh4.h" \ No newline at end of file diff --git a/third_party/gldc/src/private.h b/third_party/gldc/src/private.h index c73c4c80f..416aa6678 100644 --- a/third_party/gldc/src/private.h +++ b/third_party/gldc/src/private.h @@ -40,11 +40,6 @@ typedef struct { } PolyList; typedef struct { - GLint x; - GLint y; - GLint width; - GLint height; - float x_plus_hwidth; float y_plus_hheight; float hwidth; /* width * 0.5f */ diff --git a/third_party/gldc/src/sh4.c b/third_party/gldc/src/sh4.c index 54e42c9b5..9060c8bac 100644 --- a/third_party/gldc/src/sh4.c +++ b/third_party/gldc/src/sh4.c @@ -3,7 +3,7 @@ #define CLIP_DEBUG 0 -#define PVR_VERTEX_BUF_SIZE 32 * 30000 +#define PVR_VERTEX_BUF_SIZE 32 * 40000 #define likely(x) __builtin_expect(!!(x), 1) #define unlikely(x) __builtin_expect(!!(x), 0) @@ -87,7 +87,7 @@ static inline void _glPushHeaderOrVertex(Vertex* v) { sq += 8; } -static inline void _glClipEdge(const Vertex* const v1, const Vertex* const v2, Vertex* vout) { +static void _glClipEdge(const Vertex* const v1, const Vertex* const v2, Vertex* vout) { const float d0 = v1->w + v1->xyz[2]; const float d1 = v2->w + v2->xyz[2]; const float t = (fabs(d0) * MATH_fsrra((d1 - d0) * (d1 - d0))) + 0.000001f; @@ -118,53 +118,47 @@ static volatile uint32_t* QACR = (uint32_t*) 0xFF000038; #define V2_VIS (1 << 2) #define V3_VIS (1 << 3) -static void SubmitTriangle(Vertex* v0, Vertex* v1, Vertex* v2, uint8_t visible_mask) { + +// https://casual-effects.com/research/McGuire2011Clipping/clip.glsl +static void SubmitClipped(Vertex* v0, Vertex* v1, Vertex* v2, Vertex* v3, uint8_t visible_mask) { Vertex __attribute__((aligned(32))) scratch[4]; + Vertex* a = &scratch[0]; + Vertex* b = &scratch[1]; switch(visible_mask) { - case V0_VIS | V1_VIS | V2_VIS: // All vertices visible + case V0_VIS: { - _glPerspectiveDivideVertex(v0); - _glPushHeaderOrVertex(v0); - - _glPerspectiveDivideVertex(v1); - _glPushHeaderOrVertex(v1); - - _glPerspectiveDivideVertex(v2); - _glPushHeaderOrVertex(v2); - } - break; - case V0_VIS: // First vertex was visible - { - Vertex* a = &scratch[0]; - Vertex* b = &scratch[1]; - - _glClipEdge(v0, v1, a); - a->flags = GPU_CMD_VERTEX; - - _glClipEdge(v2, v0, b); - b->flags = GPU_CMD_VERTEX_EOL; + // v0 + // / | + // / | + // .....A....B... + // / | + // v3--v2---v1 + _glClipEdge(v3, v0, a); + a->flags = GPU_CMD_VERTEX_EOL; + _glClipEdge(v0, v1, b); + b->flags = GPU_CMD_VERTEX; _glPerspectiveDivideVertex(v0); _glPushHeaderOrVertex(v0); - _glPerspectiveDivideVertex(a); - _glPushHeaderOrVertex(a); - _glPerspectiveDivideVertex(b); _glPushHeaderOrVertex(b); + + _glPerspectiveDivideVertex(a); + _glPushHeaderOrVertex(a); } break; - case V1_VIS: // Second vertex was visible + case V1_VIS: { - /* Second vertex was visible. In self case we need to create a triangle and produce - two new vertices: 1-2, and 2-3. */ - Vertex* a = &scratch[0]; - Vertex* b = &scratch[1]; - + // v1 + // / | + // / | + // ....A.....B... + // / | + // v0--v3---v2 _glClipEdge(v0, v1, a); a->flags = GPU_CMD_VERTEX; - _glClipEdge(v1, v2, b); b->flags = GPU_CMD_VERTEX_EOL; @@ -176,42 +170,88 @@ static void SubmitTriangle(Vertex* v0, Vertex* v1, Vertex* v2, uint8_t visible_m _glPerspectiveDivideVertex(b); _glPushHeaderOrVertex(b); - } - break; - case V0_VIS | V1_VIS: // First and second vertex were visible + } break; + case V2_VIS: { - Vertex* a = &scratch[0]; - Vertex* b = &scratch[1]; - - _glClipEdge(v2, v0, b); - b->flags = GPU_CMD_VERTEX; - - _glPerspectiveDivideVertex(v0); - _glPushHeaderOrVertex(v0); + // v2 + // / | + // / | + // ....A.....B... + // / | + // v1--v0---v3 _glClipEdge(v1, v2, a); - a->flags = GPU_CMD_VERTEX_EOL; + a->flags = GPU_CMD_VERTEX; + _glClipEdge(v2, v3, b); + b->flags = GPU_CMD_VERTEX_EOL; - _glPerspectiveDivideVertex(v1); - _glPushHeaderOrVertex(v1); + _glPerspectiveDivideVertex(a); + _glPushHeaderOrVertex(a); + + _glPerspectiveDivideVertex(v2); + _glPushHeaderOrVertex(v2); + + _glPerspectiveDivideVertex(b); + _glPushHeaderOrVertex(b); + } break; + case V3_VIS: + { + // v3 + // / | + // / | + // ....A.....B... + // / | + // v2--v1---v0 + _glClipEdge(v2, v3, a); + a->flags = GPU_CMD_VERTEX; + _glClipEdge(v3, v0, b); + b->flags = GPU_CMD_VERTEX; _glPerspectiveDivideVertex(b); _glPushHeaderOrVertex(b); _glPerspectiveDivideVertex(a); - _glPushHeaderOrVertex(v1); _glPushHeaderOrVertex(a); + + _glPerspectiveDivideVertex(v3); + _glPushHeaderOrVertex(v3); } break; - case V2_VIS: // Third vertex was visible + case V0_VIS | V1_VIS: { - Vertex* a = &scratch[0]; - Vertex* b = &scratch[1]; - - _glClipEdge(v2, v0, a); + // v0-----------v1 + // \ | + // ....B..........A... + // \ | + // v3-----v2 + _glClipEdge(v1, v2, a); a->flags = GPU_CMD_VERTEX; + _glClipEdge(v3, v0, b); + b->flags = GPU_CMD_VERTEX_EOL; - _glClipEdge(v1, v2, b); + _glPerspectiveDivideVertex(v1); + _glPushHeaderOrVertex(v1); + + _glPerspectiveDivideVertex(a); + _glPushHeaderOrVertex(a); + + _glPerspectiveDivideVertex(v0); + _glPushHeaderOrVertex(v0); + + _glPerspectiveDivideVertex(b); + _glPushHeaderOrVertex(b); + } break; + // case V0_VIS | V2_VIS: degenerate case that should never happen + case V0_VIS | V3_VIS: + { + // v3-----------v0 + // \ | + // ....B..........A... + // \ | + // v2-----v1 + _glClipEdge(v0, v1, a); + a->flags = GPU_CMD_VERTEX; + _glClipEdge(v2, v3, b); b->flags = GPU_CMD_VERTEX; _glPerspectiveDivideVertex(a); @@ -220,21 +260,80 @@ static void SubmitTriangle(Vertex* v0, Vertex* v1, Vertex* v2, uint8_t visible_m _glPerspectiveDivideVertex(b); _glPushHeaderOrVertex(b); + _glPerspectiveDivideVertex(v0); + _glPushHeaderOrVertex(v0); + + _glPerspectiveDivideVertex(v3); + _glPushHeaderOrVertex(v3); + } break; + case V1_VIS | V2_VIS: + { + // v1-----------v2 + // \ | + // ....B..........A... + // \ | + // v0-----v3 + _glClipEdge(v2, v3, a); + a->flags = GPU_CMD_VERTEX_EOL; + _glClipEdge(v0, v1, b); + b->flags = GPU_CMD_VERTEX; + + _glPerspectiveDivideVertex(v1); + _glPushHeaderOrVertex(v1); + + _glPerspectiveDivideVertex(v2); + _glPushHeaderOrVertex(v2); + + _glPerspectiveDivideVertex(b); + _glPushHeaderOrVertex(b); + + _glPerspectiveDivideVertex(a); + _glPushHeaderOrVertex(a); + } break; + // case V1_VIS | V3_VIS: degenerate case that should never happen + case V2_VIS | V3_VIS: + { + // v2-----------v3 + // \ | + // ....B..........A... + // \ | + // v1-----v0 + _glClipEdge(v3, v0, a); + a->flags = GPU_CMD_VERTEX; + _glClipEdge(v1, v2, b); + b->flags = GPU_CMD_VERTEX; + + _glPerspectiveDivideVertex(b); + _glPushHeaderOrVertex(b); + _glPerspectiveDivideVertex(v2); _glPushHeaderOrVertex(v2); - } - break; - case V0_VIS | V2_VIS: // First and third vertex were visible + + _glPerspectiveDivideVertex(a); + _glPushHeaderOrVertex(a); + + _glPerspectiveDivideVertex(v3); + _glPushHeaderOrVertex(v3); + } break; + case V0_VIS | V1_VIS | V2_VIS: { - Vertex* a = &scratch[0]; - Vertex* b = &scratch[1]; - v2->flags = GPU_CMD_VERTEX; - - _glClipEdge(v0, v1, a); + // --v1-- + // v0-- --v2 + // \ | + // .....B.....A... + // \ | + // v3 + // v1,v2,v0 v2,v0,A v0,A,B + _glClipEdge(v2, v3, a); a->flags = GPU_CMD_VERTEX; + _glClipEdge(v3, v0, b); + b->flags = GPU_CMD_VERTEX_EOL; - _glClipEdge(v1, v2, b); - b->flags = GPU_CMD_VERTEX; + _glPerspectiveDivideVertex(v1); + _glPushHeaderOrVertex(v1); + + _glPerspectiveDivideVertex(v2); + _glPushHeaderOrVertex(v2); _glPerspectiveDivideVertex(v0); _glPushHeaderOrVertex(v0); @@ -242,41 +341,100 @@ static void SubmitTriangle(Vertex* v0, Vertex* v1, Vertex* v2, uint8_t visible_m _glPerspectiveDivideVertex(a); _glPushHeaderOrVertex(a); - _glPerspectiveDivideVertex(v2); - _glPushHeaderOrVertex(v2); _glPerspectiveDivideVertex(b); _glPushHeaderOrVertex(b); - - v2->flags = GPU_CMD_VERTEX_EOL; - _glPushHeaderOrVertex(v2); - } - break; - case V1_VIS | V2_VIS: // Second and third vertex were visible + } break; + case V0_VIS | V1_VIS | V3_VIS: { - Vertex* a = &scratch[0]; - Vertex* b = &scratch[1]; + // --v0-- + // v3-- --v1 + // \ | + // .....B.....A... + // \ | + // v2 + // v0,v1,v3 v1,v3,A v3,A,B + _glClipEdge(v1, v2, a); + a->flags = GPU_CMD_VERTEX; + _glClipEdge(v2, v3, b); + b->flags = GPU_CMD_VERTEX_EOL; + v3->flags = GPU_CMD_VERTEX; - _glClipEdge(v0, v1, a); - a->flags = GPU_CMD_VERTEX; - - _glClipEdge(v2, v0, b); - b->flags = GPU_CMD_VERTEX; - - _glPerspectiveDivideVertex(a); - _glPushHeaderOrVertex(a); + _glPerspectiveDivideVertex(v0); + _glPushHeaderOrVertex(v0); _glPerspectiveDivideVertex(v1); _glPushHeaderOrVertex(v1); + _glPerspectiveDivideVertex(v3); + _glPushHeaderOrVertex(v3); + + _glPerspectiveDivideVertex(a); + _glPushHeaderOrVertex(a); + _glPerspectiveDivideVertex(b); _glPushHeaderOrVertex(b); - _glPushHeaderOrVertex(v1); + } break; + case V0_VIS | V2_VIS | V3_VIS: + { + // --v3-- + // v2-- --v0 + // \ | + // .....B.....A... + // \ | + // v1 + // v3,v0,v2 v0,v2,A v2,A,B + _glClipEdge(v0, v1, a); + a->flags = GPU_CMD_VERTEX; + _glClipEdge(v1, v2, b); + b->flags = GPU_CMD_VERTEX_EOL; + v3->flags = GPU_CMD_VERTEX; + + _glPerspectiveDivideVertex(v3); + _glPushHeaderOrVertex(v3); + + _glPerspectiveDivideVertex(v0); + _glPushHeaderOrVertex(v0); _glPerspectiveDivideVertex(v2); _glPushHeaderOrVertex(v2); + + _glPerspectiveDivideVertex(a); + _glPushHeaderOrVertex(a); + + _glPerspectiveDivideVertex(b); + _glPushHeaderOrVertex(b); + } break; + case V1_VIS | V2_VIS | V3_VIS: + { + // --v2-- + // v1-- --v3 + // \ | + // .....B.....A... + // \ | + // v0 + // v2,v3,v1 v3,v1,A v1,A,B + _glClipEdge(v3, v0, a); + a->flags = GPU_CMD_VERTEX; + _glClipEdge(v0, v1, b); + b->flags = GPU_CMD_VERTEX_EOL; + v3->flags = GPU_CMD_VERTEX; + + _glPerspectiveDivideVertex(v2); + _glPushHeaderOrVertex(v2); + + _glPerspectiveDivideVertex(v3); + _glPushHeaderOrVertex(v3); + + _glPerspectiveDivideVertex(v1); + _glPushHeaderOrVertex(v1); + + _glPerspectiveDivideVertex(a); + _glPushHeaderOrVertex(a); + + _glPerspectiveDivideVertex(b); + _glPushHeaderOrVertex(b); + } break; } - break; - } } void SceneListSubmit(Vertex* v3, int n) { @@ -307,7 +465,7 @@ void SceneListSubmit(Vertex* v3, int n) { for(int i = 0; i < n; ++i, ++v3) { PREFETCH(v3 + 1); - switch(v3->flags) { + switch(v3->flags & 0xFF000000) { case GPU_CMD_VERTEX_EOL: break; case GPU_CMD_VERTEX: @@ -317,17 +475,13 @@ void SceneListSubmit(Vertex* v3, int n) { continue; }; - // Quads [0, 1, 2, 3] -> Triangles [{0, 1, 2} {2, 3, 0}] + // Quads [0, 1, 2, 3] -> Triangles [{0, 1, 2} {2, 3, 0}] Vertex* const v0 = v3 - 3; Vertex* const v1 = v3 - 2; Vertex* const v2 = v3 - 1; - visible_mask = ( - (v0->xyz[2] > -v0->w) << 0 | - (v1->xyz[2] > -v1->w) << 1 | - (v2->xyz[2] > -v2->w) << 2 | - (v3->xyz[2] > -v3->w) << 3 - ); + visible_mask = v3->flags & 0xFF; + v3->flags &= ~0xFF; // Stats gathering found that when testing a 64x64x64 sized world, at most // ~400-500 triangles needed clipping @@ -347,7 +501,7 @@ void SceneListSubmit(Vertex* v3, int n) { _glPerspectiveDivideVertex(v2); _glPushHeaderOrVertex(v2); - + _glPerspectiveDivideVertex(v0); _glPushHeaderOrVertex(v0); @@ -356,34 +510,11 @@ void SceneListSubmit(Vertex* v3, int n) { } break; - case 0: // No vertices visible - break; - default: // Some vertices visible - { - // vertices are modified in SubmitTriangle, so need to copy them - Vertex __attribute__((aligned(32))) scratch[4]; - Vertex* a0 = &scratch[0]; - Vertex* a2 = &scratch[1]; - memcpy_vertex(a0, v0); - memcpy_vertex(a2, v2); - - visible_mask &= (V0_VIS | V1_VIS | V2_VIS); - v2->flags = GPU_CMD_VERTEX_EOL; - SubmitTriangle(v0, v1, v2, visible_mask); - - visible_mask = ( - (a2->xyz[2] > -a2->w) << 0 | - (v3->xyz[2] > -v3->w) << 1 | - (a0->xyz[2] > -a0->w) << 2 - ); - v3->flags = GPU_CMD_VERTEX; - a0->flags = GPU_CMD_VERTEX_EOL; - SubmitTriangle(a2, v3, a0, visible_mask); - } - break; + SubmitClipped(v0, v1, v2, v3, visible_mask); + break; } } _glFlushBuffer(); -} \ No newline at end of file +} diff --git a/third_party/gldc/src/sh4.h b/third_party/gldc/src/sh4.h index 56a42a686..13f03ec59 100644 --- a/third_party/gldc/src/sh4.h +++ b/third_party/gldc/src/sh4.h @@ -72,8 +72,4 @@ void InitGPU(_Bool autosort, _Bool fsaa); static inline void GPUSetAlphaCutOff(uint8_t val) { PVR_SET(PT_ALPHA_REF, val); -} - -static inline void GPUSetClearDepth(float v) { - pvr_set_zclip(v); } \ No newline at end of file diff --git a/third_party/gldc/src/state.c b/third_party/gldc/src/state.c index 3d5fa3193..9114ad2d8 100644 --- a/third_party/gldc/src/state.c +++ b/third_party/gldc/src/state.c @@ -132,7 +132,7 @@ GLAPI void APIENTRY glDisable(GLenum cap) { /* Depth Testing */ GLAPI void APIENTRY glClearDepth(GLfloat depth) { /* We reverse because using invW means that farther Z == lower number */ - GPUSetClearDepth(MIN(1.0f - depth, PVR_MIN_Z)); + pvr_set_zclip(MIN(1.0f - depth, PVR_MIN_Z)); } GLAPI void APIENTRY glDepthMask(GLboolean flag) { @@ -264,85 +264,99 @@ void APIENTRY glViewport(GLint x, GLint y, GLsizei width, GLsizei height) { } -GL_FORCE_INLINE void _updatePVRTextureContext(PolyContext *context, GLshort textureUnit) { +void apply_poly_header(PolyHeader* dst, PolyList* activePolyList) { const TextureObject *tx1 = TEXTURE_ACTIVE; - - /* Disable all texturing to start with */ - context->txr.enable = GPU_TEXTURE_DISABLE; - context->txr2.enable = GPU_TEXTURE_DISABLE; - context->txr2.alpha = GPU_TXRALPHA_DISABLE; - - if(!TEXTURES_ENABLED || !tx1 || !tx1->data) { - context->txr.base = NULL; - return; - } - - context->txr.alpha = (BLEND_ENABLED || ALPHA_TEST_ENABLED) ? GPU_TXRALPHA_ENABLE : GPU_TXRALPHA_DISABLE; - - GLuint filter = GPU_FILTER_NEAREST; - - if(tx1->minFilter == GL_LINEAR && tx1->magFilter == GL_LINEAR) { - filter = GPU_FILTER_BILINEAR; - } - - if(tx1->data) { - context->txr.enable = GPU_TEXTURE_ENABLE; - context->txr.filter = filter; - context->txr.width = tx1->width; - context->txr.height = tx1->height; - context->txr.mipmap = GL_FALSE; - context->txr.mipmap_bias = tx1->mipmap_bias; - - context->txr.base = tx1->data; - context->txr.format = tx1->color; - context->txr.env = tx1->env; - context->txr.uv_flip = GPU_UVFLIP_NONE; - context->txr.uv_clamp = GPU_UVCLAMP_NONE; - } -} - -void apply_poly_header(PolyHeader* header, PolyList* activePolyList) { + uint32_t txr_base; TRACE(); - // Compile the header - PolyContext ctx; - memset(&ctx, 0, sizeof(PolyContext)); + int list_type = activePolyList->list_type; + int gen_color_clamp = GPU_CLRCLAMP_DISABLE; - ctx.list_type = activePolyList->list_type; - ctx.fmt.color = GPU_CLRFMT_ARGBPACKED; - ctx.fmt.uv = GPU_UVFMT_32BIT; - ctx.gen.color_clamp = GPU_CLRCLAMP_DISABLE; + int gen_culling = CULLING_ENABLED ? GPU_CULLING_CW : GPU_CULLING_SMALL; + int depth_comp = DEPTH_TEST_ENABLED ? GPU_DEPTHCMP_GEQUAL : GPU_DEPTHCMP_ALWAYS; + int depth_write = DEPTH_MASK_ENABLED ? GPU_DEPTHWRITE_ENABLE : GPU_DEPTHWRITE_DISABLE; - ctx.gen.culling = CULLING_ENABLED ? GPU_CULLING_CW : GPU_CULLING_SMALL; - ctx.depth.comparison = DEPTH_TEST_ENABLED ? GPU_DEPTHCMP_GEQUAL : GPU_DEPTHCMP_ALWAYS; - ctx.depth.write = DEPTH_MASK_ENABLED ? GPU_DEPTHWRITE_ENABLE : GPU_DEPTHWRITE_DISABLE; + int gen_shading = (SHADE_MODEL == GL_SMOOTH) ? GPU_SHADE_GOURAUD : GPU_SHADE_FLAT; + int gen_clip_mode = SCISSOR_TEST_ENABLED ? GPU_USERCLIP_INSIDE : GPU_USERCLIP_DISABLE; + int gen_fog_type = FOG_ENABLED ? GPU_FOG_TABLE : GPU_FOG_DISABLE; - ctx.gen.shading = (SHADE_MODEL == GL_SMOOTH) ? GPU_SHADE_GOURAUD : GPU_SHADE_FLAT; - ctx.gen.clip_mode = SCISSOR_TEST_ENABLED ? GPU_USERCLIP_INSIDE : GPU_USERCLIP_DISABLE; - ctx.gen.fog_type = FOG_ENABLED ? GPU_FOG_TABLE : GPU_FOG_DISABLE; + int gen_alpha = (BLEND_ENABLED || ALPHA_TEST_ENABLED) ? GPU_ALPHA_ENABLE : GPU_ALPHA_DISABLE; + int blend_src = PVR_BLEND_SRCALPHA; + int blend_dst = PVR_BLEND_INVSRCALPHA; - ctx.gen.alpha = (BLEND_ENABLED || ALPHA_TEST_ENABLED) ? GPU_ALPHA_ENABLE : GPU_ALPHA_DISABLE; - ctx.blend.src = PVR_BLEND_SRCALPHA; - ctx.blend.dst = PVR_BLEND_INVSRCALPHA; - - if(ctx.list_type == GPU_LIST_OP_POLY) { + if (list_type == GPU_LIST_OP_POLY) { /* Opaque polys are always one/zero */ - ctx.blend.src = PVR_BLEND_ONE; - ctx.blend.dst = PVR_BLEND_ZERO; - } else if(ctx.list_type == GPU_LIST_PT_POLY) { + blend_src = PVR_BLEND_ONE; + blend_dst = PVR_BLEND_ZERO; + } else if (list_type == GPU_LIST_PT_POLY) { /* Punch-through polys require fixed blending and depth modes */ - ctx.blend.src = PVR_BLEND_SRCALPHA; - ctx.blend.dst = PVR_BLEND_INVSRCALPHA; - ctx.depth.comparison = GPU_DEPTHCMP_LEQUAL; - } else if(ctx.list_type == GPU_LIST_TR_POLY && AUTOSORT_ENABLED) { + blend_src = PVR_BLEND_SRCALPHA; + blend_dst = PVR_BLEND_INVSRCALPHA; + depth_comp = GPU_DEPTHCMP_LEQUAL; + } else if (list_type == GPU_LIST_TR_POLY && AUTOSORT_ENABLED) { /* Autosort mode requires this mode for transparent polys */ - ctx.depth.comparison = GPU_DEPTHCMP_GEQUAL; + depth_comp = GPU_DEPTHCMP_GEQUAL; } - _updatePVRTextureContext(&ctx, 0); - - CompilePolyHeader(header, &ctx); + int txr_enable, txr_alpha; + if (!TEXTURES_ENABLED || !tx1 || !tx1->data) { + /* Disable all texturing to start with */ + txr_enable = GPU_TEXTURE_DISABLE; + } else { + txr_alpha = (BLEND_ENABLED || ALPHA_TEST_ENABLED) ? GPU_TXRALPHA_ENABLE : GPU_TXRALPHA_DISABLE; + txr_enable = GPU_TEXTURE_ENABLE; + } + /* The base values for CMD */ + dst->cmd = GPU_CMD_POLYHDR; + dst->cmd |= txr_enable << 3; /* Force bits 18 and 19 on to switch to 6 triangle strips */ - header->cmd |= 0xC0000; + dst->cmd |= 0xC0000; + + /* Or in the list type, shading type, color and UV formats */ + dst->cmd |= (list_type << PVR_TA_CMD_TYPE_SHIFT) & PVR_TA_CMD_TYPE_MASK; + dst->cmd |= (GPU_CLRFMT_ARGBPACKED << PVR_TA_CMD_CLRFMT_SHIFT) & PVR_TA_CMD_CLRFMT_MASK; + dst->cmd |= (gen_shading << PVR_TA_CMD_SHADE_SHIFT) & PVR_TA_CMD_SHADE_MASK; + dst->cmd |= (GPU_UVFMT_32BIT << PVR_TA_CMD_UVFMT_SHIFT) & PVR_TA_CMD_UVFMT_MASK; + dst->cmd |= (gen_clip_mode << PVR_TA_CMD_USERCLIP_SHIFT) & PVR_TA_CMD_USERCLIP_MASK; + + /* Polygon mode 1 */ + dst->mode1 = (depth_comp << PVR_TA_PM1_DEPTHCMP_SHIFT) & PVR_TA_PM1_DEPTHCMP_MASK; + dst->mode1 |= (gen_culling << PVR_TA_PM1_CULLING_SHIFT) & PVR_TA_PM1_CULLING_MASK; + dst->mode1 |= (depth_write << PVR_TA_PM1_DEPTHWRITE_SHIFT) & PVR_TA_PM1_DEPTHWRITE_MASK; + dst->mode1 |= (txr_enable << PVR_TA_PM1_TXRENABLE_SHIFT) & PVR_TA_PM1_TXRENABLE_MASK; + + /* Polygon mode 2 */ + dst->mode2 = (blend_src << PVR_TA_PM2_SRCBLEND_SHIFT) & PVR_TA_PM2_SRCBLEND_MASK; + dst->mode2 |= (blend_dst << PVR_TA_PM2_DSTBLEND_SHIFT) & PVR_TA_PM2_DSTBLEND_MASK; + dst->mode2 |= (gen_fog_type << PVR_TA_PM2_FOG_SHIFT) & PVR_TA_PM2_FOG_MASK; + dst->mode2 |= (gen_color_clamp << PVR_TA_PM2_CLAMP_SHIFT) & PVR_TA_PM2_CLAMP_MASK; + dst->mode2 |= (gen_alpha << PVR_TA_PM2_ALPHA_SHIFT) & PVR_TA_PM2_ALPHA_MASK; + + if (txr_enable == GPU_TEXTURE_DISABLE) { + dst->mode3 = 0; + } else { + GLuint filter = GPU_FILTER_NEAREST; + if (tx1->minFilter == GL_LINEAR && tx1->magFilter == GL_LINEAR) filter = GPU_FILTER_BILINEAR; + + dst->mode2 |= (txr_alpha << PVR_TA_PM2_TXRALPHA_SHIFT) & PVR_TA_PM2_TXRALPHA_MASK; + dst->mode2 |= (filter << PVR_TA_PM2_FILTER_SHIFT) & PVR_TA_PM2_FILTER_MASK; + dst->mode2 |= (tx1->mipmap_bias << PVR_TA_PM2_MIPBIAS_SHIFT) & PVR_TA_PM2_MIPBIAS_MASK; + dst->mode2 |= (tx1->env << PVR_TA_PM2_TXRENV_SHIFT) & PVR_TA_PM2_TXRENV_MASK; + + dst->mode2 |= (DimensionFlag(tx1->width) << PVR_TA_PM2_USIZE_SHIFT) & PVR_TA_PM2_USIZE_MASK; + dst->mode2 |= (DimensionFlag(tx1->height) << PVR_TA_PM2_VSIZE_SHIFT) & PVR_TA_PM2_VSIZE_MASK; + + /* Polygon mode 3 */ + dst->mode3 = (GL_FALSE << PVR_TA_PM3_MIPMAP_SHIFT) & PVR_TA_PM3_MIPMAP_MASK; + dst->mode3 |= (tx1->color << PVR_TA_PM3_TXRFMT_SHIFT) & PVR_TA_PM3_TXRFMT_MASK; + + /* Convert the texture address */ + txr_base = (uint32_t)tx1->data; + txr_base = (txr_base & 0x00fffff8) >> 3; + dst->mode3 |= txr_base; + } + + dst->d1 = dst->d2 = 0xffffffff; + dst->d3 = dst->d4 = 0xffffffff; } \ No newline at end of file