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