diff --git a/.github/workflows/build_ds.yml b/.github/workflows/build_ds.yml
index 24a4e1920..a4ac4e0a4 100644
--- a/.github/workflows/build_ds.yml
+++ b/.github/workflows/build_ds.yml
@@ -12,7 +12,7 @@ jobs:
container:
image: skylyrac/blocksds:dev-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: Compile DS build
id: compile
run: |
@@ -20,19 +20,21 @@ jobs:
export BLOCKSDSEXT=/opt/blocksds/external
make ds
+
# otherwise notify_failure doesn't work
- name: Install curl when necessary
if: ${{ always() && steps.compile.outcome == 'failure' }}
- run: apt install curl
+ run: apt-get -y install curl
- uses: ./.github/actions/notify_failure
if: ${{ always() && steps.compile.outcome == 'failure' }}
with:
NOTIFY_MESSAGE: 'Failed to compile DS build'
WEBHOOK_URL: '${{ secrets.WEBHOOK_URL }}'
-
+
+
- uses: ./.github/actions/upload_build
if: ${{ always() && steps.compile.outcome == 'success' }}
with:
SOURCE_FILE: 'classicube.nds'
- DEST_NAME: 'classicube.nds'
\ No newline at end of file
+ DEST_NAME: 'classicube.nds'
diff --git a/.github/workflows/build_n64.yml b/.github/workflows/build_n64.yml
index e9d08f591..ca81cb6be 100644
--- a/.github/workflows/build_n64.yml
+++ b/.github/workflows/build_n64.yml
@@ -26,6 +26,11 @@ jobs:
make n64
+ # otherwise notify_failure doesn't work
+ - name: Install curl when necessary
+ if: ${{ always() && steps.compile.outcome == 'failure' }}
+ run: apt-get -y install curl
+
- uses: ./.github/actions/notify_failure
if: ${{ always() && steps.compile.outcome == 'failure' }}
with:
@@ -37,4 +42,4 @@ jobs:
if: ${{ always() && steps.compile.outcome == 'success' }}
with:
SOURCE_FILE: 'ClassiCube-n64.z64'
- DEST_NAME: 'ClassiCube-n64.z64'
\ No newline at end of file
+ DEST_NAME: 'ClassiCube-n64.z64'
diff --git a/.github/workflows/build_ps3.yml b/.github/workflows/build_ps3.yml
index 1e1e22772..673380c37 100644
--- a/.github/workflows/build_ps3.yml
+++ b/.github/workflows/build_ps3.yml
@@ -10,33 +10,38 @@ jobs:
if: github.ref_name == github.event.repository.default_branch
runs-on: ubuntu-latest
container:
- image: akusiroyo/ps3sdk:latest
+ image: ghcr.io/classicube/minimal-psl1ght:latest
steps:
- uses: actions/checkout@v4
- name: Compile PS3 build
id: compile
run: |
- pacman -S make --noconfirm
- export PSL1GHT=/usr/local/ps3dev
export PS3DEV=/usr/local/ps3dev
+ export PSL1GHT=/usr/local/ps3dev
+ export PATH=$PATH:$PS3DEV/bin
+ export PATH=$PATH:$PS3DEV/ppu/bin
make ps3
-
+
+ # otherwise notify_failure doesn't work
+ - name: Install curl when necessary
+ if: ${{ always() && steps.compile.outcome == 'failure' }}
+ run: apt-get install -y curl
- uses: ./.github/actions/notify_failure
if: ${{ always() && steps.compile.outcome == 'failure' }}
with:
NOTIFY_MESSAGE: 'Failed to compile PS3 build'
WEBHOOK_URL: '${{ secrets.WEBHOOK_URL }}'
-
-
+
+
- uses: ./.github/actions/upload_build
if: ${{ always() && steps.compile.outcome == 'success' }}
with:
- SOURCE_FILE: 'ClassiCube-ps3.pkg'
- DEST_NAME: 'ClassiCube-ps3.pkg'
+ SOURCE_FILE: 'ClassiCube-PS3.self'
+ DEST_NAME: 'ClassiCube-PS3.self'
- uses: ./.github/actions/upload_build
if: ${{ always() && steps.compile.outcome == 'success' }}
with:
- SOURCE_FILE: 'ClassiCube-ps3.elf'
- DEST_NAME: 'ClassiCube-ps3.elf'
\ No newline at end of file
+ SOURCE_FILE: 'ClassiCube-PS3.pkg'
+ DEST_NAME: 'ClassiCube-PS3.pkg'
\ No newline at end of file
diff --git a/misc/ClassicalSharp/ClassicalSharp.zip b/misc/ClassicalSharp/ClassicalSharp.zip
deleted file mode 100644
index 8353d19cf..000000000
Binary files a/misc/ClassicalSharp/ClassicalSharp.zip and /dev/null differ
diff --git a/misc/ClassicalSharp/known_bugs.txt b/misc/ClassicalSharp/known_bugs.txt
deleted file mode 100644
index a7990fc01..000000000
--- a/misc/ClassicalSharp/known_bugs.txt
+++ /dev/null
@@ -1,21 +0,0 @@
-* Blocks over 256 are not saved or loaded at all.
-* Custom block information for blocks over 256 is not saved or loaded at all.
-* /hold 0 prevents you deleting blocks until you change to another.
-* Sometimes when holding air and your own model is a block model, you crash.
-* Labels and buttons overlap in launcher with some fonts. (e.g. Lucida Console)
-* terrain.png with width under 16 insta-crash the game
-* catbox.moe texture packs/terrain.png links insta-crash the game
-* Sometimes you randomly crash reading leveldatachunk packet on OSX
-* Models with size of over 2 are not supported at all
-* Direct3D9 backend uses an ill-formed vertex format that works by accident
-* Alt text doesn't update its Y position if you click on chat
-* Menu inputs (save, edit hotkey, water level, etc) are reset on window resize
-* Chat input caret is reset on window resize
-* Position in chat (if you scrolled up into history) is reset on window resize
-* Two blank lines get shown in chat when you type /client cuboid
-* Alt text is closed on window resize
-* Changing server texture packs sometimes still retains textures from previous one
-* Crashes at startup when another process has exclusively acquired Direct3D9 device
-* Can't bind controls to mouse buttons
-* Does not work at all on 64 bit macOS
-* Making a gas block undeletable doesn't prevent placing blocks over it
\ No newline at end of file
diff --git a/misc/ClassicalSharp/readme.txt b/misc/ClassicalSharp/readme.txt
deleted file mode 100644
index 507d0d061..000000000
--- a/misc/ClassicalSharp/readme.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-Here lies ClassicalSharp, the original C# client. (works with Mono and .NET framework 2.0)
-It has unfixed bugs and missing features. There's no reason to use it anymore.
-
-For licensing, please see license.txt inside ClassicalSharp.zip.
-Absolutely no support or assistance will be provided for ClassicalSharp.
\ No newline at end of file
diff --git a/misc/linux/flatpak/net.classicube.flatpak.client.desktop b/misc/linux/flatpak/net.classicube.flatpak.client.desktop
new file mode 100644
index 000000000..11f416da3
--- /dev/null
+++ b/misc/linux/flatpak/net.classicube.flatpak.client.desktop
@@ -0,0 +1,10 @@
+[Desktop Entry]
+Name=ClassiCube
+Exec=ClassiCubeLauncher
+Comment=Sandbox building-block game
+Type=Application
+Icon=net.classicube.flatpak.client
+Categories=Game;ActionGame;
+Terminal=false
+MimeType=x-scheme-handler/mc;
+StartupWMClass=net.classicube.flatpak.client
\ No newline at end of file
diff --git a/misc/linux/flatpak/net.classicube.flatpak.client.metainfo.xml b/misc/linux/flatpak/net.classicube.flatpak.client.metainfo.xml
new file mode 100644
index 000000000..bcdbe339e
--- /dev/null
+++ b/misc/linux/flatpak/net.classicube.flatpak.client.metainfo.xml
@@ -0,0 +1,145 @@
+
+
+ net.classicube.flatpak.client
+ ClassiCube
+ Sandbox building-block game
+
+ The ClassiCube Project
+
+ CC0-1.0
+ BSD-3-Clause
+
+ ClassiCube brings you back to the days of 2009 where one block game ruled them all, it includes such features as:
+
+ Loads of blocks and items to choose from
+ Chatting with other players
+ An extremely simple network protocol to tinker with
+ Hundreds of creative and inventive worlds to explore online
+ A growing community
+ Hundreds of hours of entertainment
+
+
+
+
+ Classic mode features faithful classic gameplay
+ https://github.com/ClassiCube/ClassiCube/assets/6509348/eedee53f-f53e-456f-b51c-92c62079eee0
+
+
+ Enhanced mode allows hacks like flying and noclipping, it also allows servers to provide many custom features
+ https://github.com/ClassiCube/ClassiCube/assets/6509348/b2fe0e2b-5d76-41ab-909f-048d0ad15f37
+
+
+
+
+ https://github.com/ClassiCube/ClassiCube/releases/tag/1.3.6
+
+
+ https://github.com/ClassiCube/ClassiCube/releases/tag/1.3.5
+
+
+ https://github.com/ClassiCube/ClassiCube/releases/tag/1.3.4
+
+
+ https://github.com/ClassiCube/ClassiCube/releases/tag/1.3.3
+
+
+ https://github.com/ClassiCube/ClassiCube/releases/tag/1.3.2
+
+
+ https://github.com/ClassiCube/ClassiCube/releases/tag/1.3.1
+
+
+ https://github.com/ClassiCube/ClassiCube/releases/tag/1.3.0
+
+
+ https://github.com/ClassiCube/ClassiCube/releases/tag/1.2.9
+
+
+ https://github.com/ClassiCube/ClassiCube/releases/tag/1.2.8
+
+
+ https://github.com/ClassiCube/ClassiCube/releases/tag/1.2.7
+
+
+ https://github.com/ClassiCube/ClassiCube/releases/tag/1.2.6
+
+
+ https://github.com/ClassiCube/ClassiCube/releases/tag/1.2.5
+
+
+ https://github.com/ClassiCube/ClassiCube/releases/tag/1.2.4
+
+
+ https://github.com/ClassiCube/ClassiCube/releases/tag/1.2.3
+
+
+ https://github.com/ClassiCube/ClassiCube/releases/tag/1.2.2
+
+
+ https://github.com/ClassiCube/ClassiCube/releases/tag/1.2.1
+
+
+ https://github.com/ClassiCube/ClassiCube/releases/tag/1.2.0
+
+
+ https://github.com/ClassiCube/ClassiCube/releases/tag/1.1.9
+
+
+ https://github.com/ClassiCube/ClassiCube/releases/tag/1.1.8
+
+
+ https://github.com/ClassiCube/ClassiCube/releases/tag/1.1.7
+
+
+ https://github.com/ClassiCube/ClassiCube/releases/tag/1.1.6
+
+
+ https://github.com/ClassiCube/ClassiCube/releases/tag/1.1.5
+
+
+ https://github.com/ClassiCube/ClassiCube/releases/tag/1.1.4
+
+
+ https://github.com/ClassiCube/ClassiCube/releases/tag/1.1.3
+
+
+ https://github.com/ClassiCube/ClassiCube/releases/tag/1.1.2
+
+
+ https://github.com/ClassiCube/ClassiCube/releases/tag/1.1.1
+
+
+ https://github.com/ClassiCube/ClassiCube/releases/tag/1.10
+
+
+ https://github.com/ClassiCube/ClassiCube/releases/tag/1.0.9
+
+
+ https://github.com/ClassiCube/ClassiCube/releases/tag/1.0.8
+
+
+ https://github.com/ClassiCube/ClassiCube/releases/tag/1.0.7
+
+
+ https://www.classicube.net/
+ https://github.com/ClassiCube/ClassiCube/issues
+ https://www.patreon.com/ClassiCube
+ https://github.com/ClassiCube/ClassiCube
+
+ Game
+ AdventureGame
+ ActionGame
+
+
+ pointing
+ keyboard
+
+
+ moderate
+ intense
+
+ net.classicube.flatpak.client.desktop
+
+ ClassiCube
+
+
diff --git a/misc/linux/flatpak/net.classicube.flatpak.client.svg b/misc/linux/flatpak/net.classicube.flatpak.client.svg
new file mode 100644
index 000000000..44324156b
--- /dev/null
+++ b/misc/linux/flatpak/net.classicube.flatpak.client.svg
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+ image/svg+xml
+
+
+
+
+
+
+
+
+
+
+
diff --git a/misc/linux/flatpak/net.classicube.flatpak.client.yml b/misc/linux/flatpak/net.classicube.flatpak.client.yml
new file mode 100644
index 000000000..760e8b9d2
--- /dev/null
+++ b/misc/linux/flatpak/net.classicube.flatpak.client.yml
@@ -0,0 +1,29 @@
+id: net.classicube.flatpak.client
+runtime: org.freedesktop.Platform
+runtime-version: '23.08'
+sdk: org.freedesktop.Sdk
+command: ClassiCubeLauncher
+finish-args:
+ - --socket=x11
+ - --device=dri
+ - --share=network
+ - --share=ipc
+ - --socket=pulseaudio
+modules:
+ - name: ClassiCube
+ buildsystem: simple
+ build-commands:
+ - gcc -fno-math-errno src/*.c -o src/ClassiCube -O1 -DCC_BUILD_FLATPAK -DCC_BUILD_GLMODERN -rdynamic -lm -lpthread -lX11 -lXi -lGL -ldl
+ - install -Dm755 src/ClassiCube -t ${FLATPAK_DEST}/bin
+ - install -Dm755 ClassiCubeLauncher -t ${FLATPAK_DEST}/bin
+ - install -Dm644 misc/linux/flatpak/net.classicube.flatpak.client.svg ${FLATPAK_DEST}/share/icons/hicolor/scalable/apps/net.classicube.flatpak.client.svg
+ - install -Dm644 misc/linux/flatpak/net.classicube.flatpak.client.desktop ${FLATPAK_DEST}/share/applications/net.classicube.flatpak.client.desktop
+ - install -Dm644 misc/linux/flatpak/net.classicube.flatpak.client.metainfo.xml ${FLATPAK_DEST}/share/metainfo/net.classicube.flatpak.client.metainfo.xml
+ sources:
+ - type: dir
+ path: ../../../
+ - type: script
+ dest-filename: ClassiCubeLauncher
+ commands:
+ - mkdir -p ${XDG_DATA_HOME}/ClassiCube
+ - cd ${XDG_DATA_HOME}/ClassiCube && exec /app/bin/ClassiCube "$@"
diff --git a/misc/os2/Makefile b/misc/os2/Makefile
index bed5227ce..967bd65ae 100644
--- a/misc/os2/Makefile
+++ b/misc/os2/Makefile
@@ -41,7 +41,7 @@ APP_AUTHOR := UnknownShadow200
# options for code generation
#---------------------------------------------------------------------------------
CC := gcc
-CFLAGS := -pipe -fno-math-errno -O3 -g -mtune=pentium4 -msse2 -march=i686 -idirafter /@unixroot/usr/include/os2tk45 -DOS2
+CFLAGS := -pipe -fno-math-errno -O0 -g -mtune=pentium4 -msse2 -march=i686 -idirafter /@unixroot/usr/include/os2tk45 -DOS2
LDFLAGS := -Zhigh-mem -Zomf -Zargs-wild -Zargs-resp -Zlinker DISABLE -Zlinker 1121
LIBS := -lcx -lmmpm2 -lpthread -lSDL2
@@ -53,6 +53,6 @@ $(BUILD_DIR):
$(C_OBJECTS): $(BUILD_DIR)/%.o : $(SOURCE_DIR)/%.c
$(CC) $(CFLAGS) -c $< -o $@
-$(BUILD_DIR)/$(TARGET).res: misc/os2/$(TARGET).rc
+$(BUILD_DIR)/$(TARGET).res: misc/os2/$(TARGET).rc misc/os2/$(TARGET).ico
wrc -r misc/os2/$(TARGET).rc -fo=$@
diff --git a/misc/ps1/classicube.zip b/misc/ps1/classicube.zip
new file mode 100644
index 000000000..bfc089647
Binary files /dev/null and b/misc/ps1/classicube.zip differ
diff --git a/misc/ps1/iso.xml b/misc/ps1/iso.xml
index 96ea23a8c..220f72635 100644
--- a/misc/ps1/iso.xml
+++ b/misc/ps1/iso.xml
@@ -69,6 +69,9 @@
-->
+
+
+
diff --git a/misc/ps3/Makefile b/misc/ps3/Makefile
index b37d83967..e28411b5a 100644
--- a/misc/ps3/Makefile
+++ b/misc/ps3/Makefile
@@ -35,7 +35,7 @@ ICON0 := ../misc/ps3/ICON0.png
CFLAGS = -O2 -DPLAT_PS3 -Wall -mcpu=cell -fno-math-errno $(MACHDEP) $(INCLUDE)
CXXFLAGS = $(CFLAGS)
-LDFLAGS = $(MACHDEP) -Wl,-Map,$(notdir $@).map
+LDFLAGS = $(MACHDEP) -Wl,-Map,$(notdir $@).map -fno-use-linker-plugin
#---------------------------------------------------------------------------------
# any extra libraries we wish to link with the project
@@ -141,4 +141,4 @@ $(OUTPUT).elf: $(OFILES)
#---------------------------------------------------------------------------------
endif
-#---------------------------------------------------------------------------------
\ No newline at end of file
+#---------------------------------------------------------------------------------
diff --git a/readme.md b/readme.md
index efc2bcb45..2e873b0d2 100644
--- a/readme.md
+++ b/readme.md
@@ -21,9 +21,9 @@ ClassiCube is not trying to replicate modern Minecraft versions. It will never s
You can **download ClassiCube** [from here](https://www.classicube.net/download/) and the very latest builds [from here](https://www.classicube.net/nightlies/).
-![classic](https://github.com/ClassiCube/actions-testing-cc/assets/7892772/a233cb4c-296a-4d08-87fc-49874c230d4f)
+![classic](https://github.com/ClassiCube/ClassiCube/assets/6509348/eedee53f-f53e-456f-b51c-92c62079eee0)
-![enhanced](https://github.com/ClassiCube/actions-testing-cc/assets/7892772/61a064bd-cfaa-4a91-bedf-a16c3dd7e8a2)
+![enhanced](https://github.com/ClassiCube/ClassiCube/assets/6509348/b2fe0e2b-5d76-41ab-909f-048d0ad15f37)
# We need your help
@@ -117,13 +117,17 @@ I am assuming you used the installer from https://osdn.net/projects/mingw/
4. Enter `gcc -fno-math-errno *.c -o ClassiCube.exe -mwindows -lwinmm -limagehlp`
##### Using TCC (Tiny C Compiler)
-I am assuming you used `tcc-0.9.27-win64-bin.zip` from https://bellard.org/tcc/
-1. Extract the .zip file
+Setting up TCC:
+1. Download and extract `tcc-0.9.27-win64-bin.zip` from https://bellard.org/tcc/
2. In TCC's `lib/kernel32.def`, add missing `RtlCaptureContext` at line 554 (In between `RtlAddFunctionTable` and `RtlDeleteFunctionTable`)
-3. Copy `winapi` folder and `_mingw_dxhelper.h` from `winapi-full-for-0.9.27.zip` into TCC's `include` folder
-4. Navigate to the directory with ClassiCube's source code
-5. In `ExtMath.c`, change `fabsf` to `fabs` and `sqrtf` to `sqrtf`
-6. Enter `tcc.exe -o ClassiCube.exe *.c -lwinmm -limagehlp -lgdi32 -luser32 -lcomdlg32 -lshell32`
+3. Download `winapi-full-for-0.9.27.zip` from https://bellard.org/tcc/
+4. Copy `winapi` folder and `_mingw_dxhelper.h` from `winapi-full-for-0.9.27.zip` into TCC's `include` folder
+
+Compiling with TCC:
+1. Navigate to the directory with ClassiCube's source code
+2. In `ExtMath.c`, change `fabsf` to `fabs` and `sqrtf` to `sqrt`
+3. Enter `tcc.exe -o ClassiCube.exe *.c -lwinmm -limagehlp -lgdi32 -luser32 -lcomdlg32 -lshell32`
+(Note: You may need to specify the full path to `tcc.exe` instead of just `tcc.exe`)
## Compiling - Linux
diff --git a/src/Animations.c b/src/Animations.c
index 9c469dd64..29196f6ff 100644
--- a/src/Animations.c
+++ b/src/Animations.c
@@ -12,7 +12,12 @@
#include "Options.h"
#include "Logger.h"
-#define LIQUID_ANIM_MAX 64
+#ifdef CC_BUILD_LOWMEM
+ #define LIQUID_ANIM_MAX 16
+#else
+ #define LIQUID_ANIM_MAX 64
+#endif
+
#define WATER_TEX_LOC 14
#define LAVA_TEX_LOC 30
static void Animations_Update(int loc, struct Bitmap* bmp, int stride);
@@ -292,20 +297,20 @@ static void Animations_Clear(void) {
}
static void Animations_Validate(void) {
- struct AnimationData data;
+ struct AnimationData* data;
int maxX, maxY, tileX, tileY;
int i, j;
anims_validated = true;
for (i = 0; i < anims_count; i++) {
- data = anims_list[i];
+ data = &anims_list[i];
- maxX = data.frameX + data.frameSize * data.statesCount;
- maxY = data.frameY + data.frameSize;
- tileX = Atlas2D_TileX(data.texLoc);
- tileY = Atlas2D_TileY(data.texLoc);
+ maxX = data->frameX + data->frameSize * data->statesCount;
+ maxY = data->frameY + data->frameSize;
+ tileX = Atlas2D_TileX(data->texLoc);
+ tileY = Atlas2D_TileY(data->texLoc);
- if (data.frameSize > Atlas2D.TileSize || tileY >= Atlas2D.RowsCount) {
+ if (data->frameSize > Atlas2D.TileSize || tileY >= Atlas2D.RowsCount) {
Chat_Add2("&cAnimation frames for tile (%i, %i) are bigger than the size of a tile in terrain.png", &tileX, &tileY);
} else if (maxX > anims_bmp.width || maxY > anims_bmp.height) {
Chat_Add2("&cSome of the animation frames for tile (%i, %i) are at coordinates outside animations.png", &tileX, &tileY);
@@ -313,8 +318,8 @@ static void Animations_Validate(void) {
/* if user has water/lava animations in their default.zip, disable built-in */
/* However, 'usewateranim' and 'uselavaanim' files should always disable use */
/* of custom water/lava animations, even when they exist in animations.png */
- if (data.texLoc == LAVA_TEX_LOC && !alwaysLavaAnim) useLavaAnim = false;
- if (data.texLoc == WATER_TEX_LOC && !alwaysWaterAnim) useWaterAnim = false;
+ if (data->texLoc == LAVA_TEX_LOC && !alwaysLavaAnim) useLavaAnim = false;
+ if (data->texLoc == WATER_TEX_LOC && !alwaysWaterAnim) useWaterAnim = false;
continue;
}
diff --git a/src/Audio.c b/src/Audio.c
index 407492f46..435f37579 100644
--- a/src/Audio.c
+++ b/src/Audio.c
@@ -12,11 +12,15 @@
#include "Stream.h"
#include "Utils.h"
#include "Options.h"
+#include "Deflate.h"
#ifdef CC_BUILD_ANDROID
/* TODO: Refactor maybe to not rely on checking WinInfo.Handle != NULL */
#include "Window.h"
#endif
+
int Audio_SoundsVolume, Audio_MusicVolume;
+const cc_string Sounds_ZipPathMC = String_FromConst("audio/default.zip");
+const cc_string Sounds_ZipPathCC = String_FromConst("audio/classicube.zip");
static const cc_string audio_dir = String_FromConst("audio");
struct Sound {
@@ -91,7 +95,12 @@ static cc_result Sound_ReadWaveData(struct Stream* stream, struct Sound* snd) {
if ((res = Audio_AllocChunks(size, &snd->data, 1))) return res;
snd->size = size;
- return Stream_Read(stream, (cc_uint8*)snd->data, size);
+ res = Stream_Read(stream, (cc_uint8*)snd->data, size);
+
+ #ifdef CC_BUILD_BIGENDIAN
+ Utils_SwapEndian16((cc_int16*)snd->data, size / 2);
+ #endif
+ return res;
}
/* Skip over unhandled data */
@@ -99,30 +108,18 @@ static cc_result Sound_ReadWaveData(struct Stream* stream, struct Sound* snd) {
}
}
-static cc_result Sound_ReadWave(const cc_string* path, struct Sound* snd) {
- struct Stream stream;
- cc_result res;
-
- res = Stream_OpenFile(&stream, path);
- if (res) return res;
- res = Sound_ReadWaveData(&stream, snd);
-
- /* No point logging error for closing readonly file */
- (void)stream.Close(&stream);
- return res;
-}
-
-static struct SoundGroup* Soundboard_Find(struct Soundboard* board, const cc_string* name) {
+static struct SoundGroup* Soundboard_FindGroup(struct Soundboard* board, const cc_string* name) {
struct SoundGroup* groups = board->groups;
int i;
- for (i = 0; i < SOUND_COUNT; i++) {
+ for (i = 0; i < SOUND_COUNT; i++)
+ {
if (String_CaselessEqualsConst(name, Sound_Names[i])) return &groups[i];
}
return NULL;
}
-static void Soundboard_Load(struct Soundboard* board, const cc_string* boardName, const cc_string* file) {
+static void Soundboard_Load(struct Soundboard* board, const cc_string* boardName, const cc_string* file, struct Stream* stream) {
struct SoundGroup* group;
struct Sound* snd;
cc_string name = *file;
@@ -139,7 +136,7 @@ static void Soundboard_Load(struct Soundboard* board, const cc_string* boardName
name = String_UNSAFE_SubstringAt(&name, boardName->length);
name = String_UNSAFE_Substring(&name, 0, name.length - 1);
- group = Soundboard_Find(board, &name);
+ group = Soundboard_FindGroup(board, &name);
if (!group) {
Chat_Add1("&cUnknown sound group '%s'", &name); return;
}
@@ -148,7 +145,7 @@ static void Soundboard_Load(struct Soundboard* board, const cc_string* boardName
}
snd = &group->sounds[group->count];
- res = Sound_ReadWave(file, snd);
+ res = Sound_ReadWaveData(stream, snd);
if (res) {
Logger_SysWarn2(res, "decoding", file);
@@ -219,12 +216,29 @@ static void Audio_PlayBlockSound(void* obj, IVec3 coords, BlockID old, BlockID n
}
}
-static void Sounds_LoadFile(const cc_string* path, void* obj) {
+static cc_bool SelectZipEntry(const cc_string* path) { return true; }
+static cc_result ProcessZipEntry(const cc_string* path, struct Stream* stream, struct ZipEntry* source) {
static const cc_string dig = String_FromConst("dig_");
static const cc_string step = String_FromConst("step_");
- Soundboard_Load(&digBoard, &dig, path);
- Soundboard_Load(&stepBoard, &step, path);
+ Soundboard_Load(&digBoard, &dig, path, stream);
+ Soundboard_Load(&stepBoard, &step, path, stream);
+ return 0;
+}
+
+static cc_result Sounds_ExtractZip(const cc_string* path) {
+ struct Stream stream;
+ cc_result res;
+
+ res = Stream_OpenFile(&stream, path);
+ if (res) { Logger_SysWarn2(res, "opening", path); return res; }
+
+ res = Zip_Extract(&stream, SelectZipEntry, ProcessZipEntry);
+ if (res) Logger_SysWarn2(res, "extracting", path);
+
+ /* No point logging error for closing readonly file */
+ (void)stream.Close(&stream);
+ return res;
}
/* TODO this is a pretty terrible solution */
@@ -269,7 +283,7 @@ static void InitWebSounds(void) {
static cc_bool sounds_loaded;
static void Sounds_Start(void) {
- int i;
+ cc_result res;
if (!AudioBackend_Init()) {
AudioBackend_Free();
Audio_SoundsVolume = 0;
@@ -281,7 +295,9 @@ static void Sounds_Start(void) {
#ifdef CC_BUILD_WEBAUDIO
InitWebSounds();
#else
- Directory_Enum(&audio_dir, NULL, Sounds_LoadFile);
+ res = Sounds_ExtractZip(&Sounds_ZipPathMC);
+ if (res == ReturnCode_FileNotFound)
+ Sounds_ExtractZip(&Sounds_ZipPathCC);
#endif
}
@@ -336,7 +352,7 @@ static cc_result Music_Buffer(cc_int16* data, int maxSamples, struct VorbisState
static cc_result Music_PlayOgg(struct Stream* source) {
struct OggState ogg;
- struct VorbisState vorbis = { 0 };
+ struct VorbisState vorbis;
int channels, sampleRate, volume;
int chunkSize, samplesPerSecond;
@@ -345,6 +361,7 @@ static cc_result Music_PlayOgg(struct Stream* source) {
cc_result res;
Ogg_Init(&ogg, source);
+ Vorbis_Init(&vorbis);
vorbis.source = &ogg;
if ((res = Vorbis_DecodeHeaders(&vorbis))) goto cleanup;
diff --git a/src/Audio.h b/src/Audio.h
index 416a42b36..e054d1c2d 100644
--- a/src/Audio.h
+++ b/src/Audio.h
@@ -34,6 +34,8 @@ extern int Audio_SoundsVolume;
/* Volume music is played at, from 0-100. */
/* NOTE: Use Audio_SetMusic, don't change this directly. */
extern int Audio_MusicVolume;
+extern const cc_string Sounds_ZipPathMC;
+extern const cc_string Sounds_ZipPathCC;
void Audio_SetMusic(int volume);
void Audio_SetSounds(int volume);
diff --git a/src/AudioBackend.c b/src/AudioBackend.c
index 63efc5c9f..5f750b9c1 100644
--- a/src/AudioBackend.c
+++ b/src/AudioBackend.c
@@ -1133,10 +1133,19 @@ void Audio_FreeChunks(void** chunks, int numChunks) {
#include
#include
#include
+#include
+
+struct AudioBuffer {
+ int available;
+ int size;
+ void* samples;
+};
struct AudioContext {
- int chanID, count;
+ int chanID, count, bufHead;
+ struct AudioBuffer bufs[AUDIO_MAX_BUFFERS];
int channels, sampleRate, volume;
+ cc_bool makeAvailable;
};
cc_bool AudioBackend_Init(void) {
@@ -1152,10 +1161,42 @@ void AudioBackend_Free(void) {
ASND_End();
}
+void MusicCallback(s32 voice) {
+ struct AudioContext* ctx = &music_ctx;
+ struct AudioBuffer* nextBuf = &ctx->bufs[(ctx->bufHead + 1) % ctx->count];
+
+ if (ASND_StatusVoice(voice) != SND_WORKING) return;
+
+ if (ASND_AddVoice(voice, nextBuf->samples, nextBuf->size) == SND_OK) {
+ ctx->bufHead = (ctx->bufHead + 1) % ctx->count;
+ if (ctx->bufHead == 2) ctx->makeAvailable = true;
+ if (ctx->makeAvailable) {
+ int prev = ctx->bufHead - 2;
+ if (prev < 0) prev += 4;
+ ctx->bufs[prev].available = true;
+ }
+ }
+
+ int inUse;
+ Audio_Poll(ctx, &inUse);
+ if (!inUse) {
+ // music has finished, stop the voice so this function isn't called anymore
+ ASND_StopVoice(ctx->chanID);
+ }
+}
+
cc_result Audio_Init(struct AudioContext* ctx, int buffers) {
- ctx->chanID = -1;
- ctx->count = buffers;
- ctx->volume = 255;
+ ctx->chanID = -1;
+ ctx->count = buffers;
+ ctx->volume = 255;
+ ctx->bufHead = 0;
+ ctx->makeAvailable = false;
+
+ Mem_Set(ctx->bufs, 0, sizeof(ctx->bufs));
+ for (int i = 0; i < buffers; i++) {
+ ctx->bufs[i].available = true;
+ }
+
return 0;
}
@@ -1170,6 +1211,7 @@ cc_result Audio_SetFormat(struct AudioContext* ctx, int channels, int sampleRate
ctx->channels = channels;
ctx->sampleRate = sampleRate;
ctx->chanID = ASND_GetFirstUnusedVoice();
+
return 0;
}
@@ -1179,34 +1221,51 @@ void Audio_SetVolume(struct AudioContext* ctx, int volume) {
cc_result Audio_QueueChunk(struct AudioContext* ctx, void* chunk, cc_uint32 dataSize) {
// Audio buffers must be aligned and padded to a multiple of 32 bytes
- if (((uintptr_t)chunk & 0x20) != 0) {
+ if (((uintptr_t)chunk & 0x1F) != 0) {
Platform_Log1("Audio_QueueData: tried to queue buffer with non-aligned audio buffer 0x%x\n", &chunk);
}
- if ((dataSize & 0x20) != 0) {
- Platform_Log1("Audio_QueueData: unaligned audio data size 0x%x\n", &dataSize);
- }
- int format = (ctx->channels == 2) ? VOICE_STEREO_16BIT : VOICE_MONO_16BIT;
- ASND_SetVoice(ctx->chanID, format, ctx->sampleRate, 0, chunk, dataSize, ctx->volume, ctx->volume, NULL);
+ struct AudioBuffer* buf;
- return 0;
+ for (int i = 0; i < ctx->count; i++)
+ {
+ buf = &ctx->bufs[i];
+ if (!buf->available) continue;
+
+ buf->samples = chunk;
+ buf->size = dataSize;
+ buf->available = false;
+
+ return 0;
+ }
// tried to queue data without polling for free buffers first
return ERR_INVALID_ARGUMENT;
}
cc_result Audio_Play(struct AudioContext* ctx) {
+ int format = (ctx->channels == 2) ? VOICE_STEREO_16BIT : VOICE_MONO_16BIT;
+ ASND_SetVoice(ctx->chanID, format, ctx->sampleRate, 0, ctx->bufs[0].samples, ctx->bufs[0].size, ctx->volume, ctx->volume, (ctx->count > 1) ? MusicCallback : NULL);
+ if (ctx->count == 1) ctx->bufs[0].available = true;
+
return 0;
}
cc_result Audio_Poll(struct AudioContext* ctx, int* inUse) {
- int status = ASND_StatusVoice(ctx->chanID);
- *inUse = (status <= 0) ? 0 : ctx->count;
+ struct AudioBuffer* buf;
+ int count = 0;
+ for (int i = 0; i < ctx->count; i++) {
+ buf = &ctx->bufs[i];
+ if (!buf->available) count++;
+ }
+
+ *inUse = count;
return 0;
}
-static cc_bool Audio_FastPlay(struct AudioContext* ctx, struct AudioData* data) {
+
+cc_bool Audio_FastPlay(struct AudioContext* ctx, struct AudioData* data) {
return true;
}
@@ -1216,7 +1275,7 @@ cc_bool Audio_DescribeError(cc_result res, cc_string* dst) {
cc_result Audio_AllocChunks(cc_uint32 size, void** chunks, int numChunks) {
size = (size + 0x1F) & ~0x1F; // round up to nearest multiple of 0x20
- void* dst = aligned_alloc(0x20, size * numChunks);
+ void* dst = memalign(0x20, size);
if (!dst) return ERR_OUT_OF_MEMORY;
for (int i = 0; i < numChunks; i++) {
diff --git a/src/Bitmap.c b/src/Bitmap.c
index 043423fae..6f319a426 100644
--- a/src/Bitmap.c
+++ b/src/Bitmap.c
@@ -645,9 +645,9 @@ static void Png_EncodeRow(const cc_uint8* cur, const cc_uint8* prior, cc_uint8*
best[0] = bestFilter;
}
-static BitmapCol* DefaultGetRow(struct Bitmap* bmp, int y) { return Bitmap_GetRow(bmp, y); }
+static BitmapCol* DefaultGetRow(struct Bitmap* bmp, int y, void* ctx) { return Bitmap_GetRow(bmp, y); }
cc_result Png_Encode(struct Bitmap* bmp, struct Stream* stream,
- Png_RowGetter getRow, cc_bool alpha) {
+ Png_RowGetter getRow, cc_bool alpha, void* ctx) {
cc_uint8 tmp[32];
/* TODO: This should be * 4 for alpha (should switch to mem_alloc though) */
cc_uint8 prevLine[PNG_MAX_DIMS * 3], curLine[PNG_MAX_DIMS * 3];
@@ -691,7 +691,7 @@ cc_result Png_Encode(struct Bitmap* bmp, struct Stream* stream,
Mem_Set(prevLine, 0, lineSize);
for (y = 0; y < bmp->height; y++) {
- BitmapCol* src = getRow(bmp, y);
+ BitmapCol* src = getRow(bmp, y, ctx);
cc_uint8* prev = (y & 1) == 0 ? prevLine : curLine;
cc_uint8* cur = (y & 1) == 0 ? curLine : prevLine;
diff --git a/src/Bitmap.h b/src/Bitmap.h
index ca7cc6d81..c8688cc09 100644
--- a/src/Bitmap.h
+++ b/src/Bitmap.h
@@ -89,7 +89,7 @@ CC_API void Bitmap_Scale(struct Bitmap* dst, struct Bitmap* src,
/* Whether data starts with PNG format signature/identifier. */
cc_bool Png_Detect(const cc_uint8* data, cc_uint32 len);
-typedef BitmapCol* (*Png_RowGetter)(struct Bitmap* bmp, int row);
+typedef BitmapCol* (*Png_RowGetter)(struct Bitmap* bmp, int row, void* ctx);
/*
Decodes a bitmap in PNG format. Partially based off information from
https://handmade.network/forums/wip/t/2363-implementing_a_basic_png_reader_the_handmade_way
@@ -100,5 +100,5 @@ CC_API cc_result Png_Decode(struct Bitmap* bmp, struct Stream* stream);
/* getRow is optional. Can be used to modify how rows are encoded. (e.g. flip image) */
/* if alpha is non-zero, RGBA channels are saved, otherwise only RGB channels are. */
cc_result Png_Encode(struct Bitmap* bmp, struct Stream* stream,
- Png_RowGetter getRow, cc_bool alpha);
+ Png_RowGetter getRow, cc_bool alpha, void* ctx);
#endif
diff --git a/src/ClassiCube.vcxproj.filters b/src/ClassiCube.vcxproj.filters
index 86b40ac23..aef0be6f9 100644
--- a/src/ClassiCube.vcxproj.filters
+++ b/src/ClassiCube.vcxproj.filters
@@ -620,9 +620,6 @@
Source Files\Platform
-
- Source Files\Window
-
Source Files\Window
@@ -713,6 +710,9 @@
Source Files\Graphics
+
+ Source Files\Audio
+
diff --git a/src/Core.h b/src/Core.h
index 43f881e2b..41ea903a9 100644
--- a/src/Core.h
+++ b/src/Core.h
@@ -6,74 +6,74 @@ Copyright 2014-2023 ClassiCube | Licensed under BSD-3
*/
#if _MSC_VER
-typedef signed __int8 cc_int8;
-typedef signed __int16 cc_int16;
-typedef signed __int32 cc_int32;
-typedef signed __int64 cc_int64;
-
-typedef unsigned __int8 cc_uint8;
-typedef unsigned __int16 cc_uint16;
-typedef unsigned __int32 cc_uint32;
-typedef unsigned __int64 cc_uint64;
-#ifdef _WIN64
-typedef unsigned __int64 cc_uintptr;
-#else
-typedef unsigned __int32 cc_uintptr;
-#endif
-
-#define CC_INLINE inline
-#define CC_NOINLINE __declspec(noinline)
-#ifndef CC_API
-#define CC_API __declspec(dllexport, noinline)
-#define CC_VAR __declspec(dllexport)
-#endif
-
-#define CC_HAS_TYPES
-#define CC_HAS_MISC
+ typedef signed __int8 cc_int8;
+ typedef signed __int16 cc_int16;
+ typedef signed __int32 cc_int32;
+ typedef signed __int64 cc_int64;
+
+ typedef unsigned __int8 cc_uint8;
+ typedef unsigned __int16 cc_uint16;
+ typedef unsigned __int32 cc_uint32;
+ typedef unsigned __int64 cc_uint64;
+ #ifdef _WIN64
+ typedef unsigned __int64 cc_uintptr;
+ #else
+ typedef unsigned __int32 cc_uintptr;
+ #endif
+
+ #define CC_INLINE inline
+ #define CC_NOINLINE __declspec(noinline)
+ #ifndef CC_API
+ #define CC_API __declspec(dllexport, noinline)
+ #define CC_VAR __declspec(dllexport)
+ #endif
+
+ #define CC_HAS_TYPES
+ #define CC_HAS_MISC
#elif __GNUC__
-/* really old GCC/clang might not have these defined */
-#ifdef __INT8_TYPE__
-/* avoid including because it breaks defining UNICODE in Platform.c with MinGW */
-typedef __INT8_TYPE__ cc_int8;
-typedef __INT16_TYPE__ cc_int16;
-typedef __INT32_TYPE__ cc_int32;
-typedef __INT64_TYPE__ cc_int64;
-
-#ifdef __UINT8_TYPE__
-typedef __UINT8_TYPE__ cc_uint8;
-typedef __UINT16_TYPE__ cc_uint16;
-typedef __UINT32_TYPE__ cc_uint32;
-typedef __UINT64_TYPE__ cc_uint64;
-typedef __UINTPTR_TYPE__ cc_uintptr;
-#else
-/* clang doesn't define the __UINT8_TYPE__ */
-typedef unsigned __INT8_TYPE__ cc_uint8;
-typedef unsigned __INT16_TYPE__ cc_uint16;
-typedef unsigned __INT32_TYPE__ cc_uint32;
-typedef unsigned __INT64_TYPE__ cc_uint64;
-typedef unsigned __INTPTR_TYPE__ cc_uintptr;
-#endif
-#define CC_HAS_TYPES
-#endif
-
-#define CC_INLINE inline
-#define CC_NOINLINE __attribute__((noinline))
-#ifndef CC_API
-#ifdef _WIN32
-#define CC_API __attribute__((dllexport, noinline))
-#define CC_VAR __attribute__((dllexport))
-#else
-#define CC_API __attribute__((visibility("default"), noinline))
-#define CC_VAR __attribute__((visibility("default")))
-#endif
-#endif
-#define CC_HAS_MISC
-#ifdef __BIG_ENDIAN__
-#define CC_BIG_ENDIAN
-#endif
+ /* really old GCC/clang might not have these defined */
+ #ifdef __INT8_TYPE__
+ /* avoid including because it breaks defining UNICODE in Platform.c with MinGW */
+ typedef __INT8_TYPE__ cc_int8;
+ typedef __INT16_TYPE__ cc_int16;
+ typedef __INT32_TYPE__ cc_int32;
+ typedef __INT64_TYPE__ cc_int64;
+
+ #ifdef __UINT8_TYPE__
+ typedef __UINT8_TYPE__ cc_uint8;
+ typedef __UINT16_TYPE__ cc_uint16;
+ typedef __UINT32_TYPE__ cc_uint32;
+ typedef __UINT64_TYPE__ cc_uint64;
+ typedef __UINTPTR_TYPE__ cc_uintptr;
+ #else
+ /* clang doesn't define the __UINT8_TYPE__ */
+ typedef unsigned __INT8_TYPE__ cc_uint8;
+ typedef unsigned __INT16_TYPE__ cc_uint16;
+ typedef unsigned __INT32_TYPE__ cc_uint32;
+ typedef unsigned __INT64_TYPE__ cc_uint64;
+ typedef unsigned __INTPTR_TYPE__ cc_uintptr;
+ #endif
+ #define CC_HAS_TYPES
+ #endif
+
+ #define CC_INLINE inline
+ #define CC_NOINLINE __attribute__((noinline))
+ #ifndef CC_API
+ #ifdef _WIN32
+ #define CC_API __attribute__((dllexport, noinline))
+ #define CC_VAR __attribute__((dllexport))
+ #else
+ #define CC_API __attribute__((visibility("default"), noinline))
+ #define CC_VAR __attribute__((visibility("default")))
+ #endif
+ #endif
+ #define CC_HAS_MISC
+ #ifdef __BIG_ENDIAN__
+ #define CC_BIG_ENDIAN
+ #endif
#elif __MWERKS__
-/* TODO: Is there actual attribute support for CC_API etc somewhere? */
-#define CC_BIG_ENDIAN
+ /* TODO: Is there actual attribute support for CC_API etc somewhere? */
+ #define CC_BIG_ENDIAN
#endif
/* Unrecognised compiler, so just go with some sensible default typdefs */
@@ -120,31 +120,28 @@ typedef cc_uint8 cc_bool;
#define CC_BUILD_NETWORKING
#define CC_BUILD_FREETYPE
-#ifndef CC_BUILD_FLATPAK
#define CC_BUILD_RESOURCES
-#endif
+#define CC_BUILD_PLUGINS
/*#define CC_BUILD_GL11*/
#ifndef CC_BUILD_MANUAL
#if defined NXDK
/* XBox also defines _WIN32 */
#define CC_BUILD_XBOX
+ #define CC_BUILD_CONSOLE
+ #define CC_BUILD_LOWMEM
#define CC_BUILD_NOMUSIC
#define CC_BUILD_NOSOUNDS
#define CC_BUILD_HTTPCLIENT
#define CC_BUILD_BEARSSL
- #define CC_BUILD_LOWMEM
- #define CC_BUILD_CONSOLE
- #undef CC_BUILD_FREETYPE
#elif defined XENON
/* libxenon also defines __linux__ (yes, really) */
#define CC_BUILD_XBOX360
+ #define CC_BUILD_CONSOLE
+ #define CC_BUILD_LOWMEM
#define CC_BUILD_NOMUSIC
#define CC_BUILD_NOSOUNDS
#define CC_BUILD_HTTPCLIENT
- #define CC_BUILD_LOWMEM
- #define CC_BUILD_CONSOLE
- #undef CC_BUILD_FREETYPE
#elif defined _WIN32
#define CC_BUILD_WIN
#define CC_BUILD_D3D9
@@ -269,128 +266,120 @@ typedef cc_uint8 cc_bool;
#define CC_BUILD_COOPTHREADED
#undef CC_BUILD_FREETYPE
#undef CC_BUILD_RESOURCES
+ #undef CC_BUILD_PLUGINS
#elif defined __psp__
#define CC_BUILD_PSP
+ #define CC_BUILD_CONSOLE
+ #define CC_BUILD_LOWMEM
+ #define CC_BUILD_COOPTHREADED
#define CC_BUILD_OPENAL
#define CC_BUILD_HTTPCLIENT
- #define CC_BUILD_COOPTHREADED
#define CC_BUILD_BEARSSL
- #define CC_BUILD_LOWMEM
- #define CC_BUILD_CONSOLE
- #undef CC_BUILD_FREETYPE
#elif defined __3DS__
#define CC_BUILD_3DS
+ #define CC_BUILD_CONSOLE
+ #define CC_BUILD_LOWMEM
#define CC_BUILD_HTTPCLIENT
#define CC_BUILD_BEARSSL
- #define CC_BUILD_LOWMEM
- #define CC_BUILD_CONSOLE
#define CC_BUILD_TOUCH
#define CC_BUILD_DUALSCREEN
- #undef CC_BUILD_FREETYPE
#elif defined GEKKO
#define CC_BUILD_GCWII
+ #define CC_BUILD_CONSOLE
+ #define CC_BUILD_LOWMEM
+ #define CC_BUILD_COOPTHREADED
#define CC_BUILD_HTTPCLIENT
#define CC_BUILD_BEARSSL
- #define CC_BUILD_COOPTHREADED
- #define CC_BUILD_LOWMEM
- #define CC_BUILD_CONSOLE
- #undef CC_BUILD_FREETYPE
#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
- #define CC_BUILD_LOWMEM
- #define CC_BUILD_CONSOLE
- #undef CC_BUILD_FREETYPE
+ #define CC_BUILD_TOUCH
#elif defined _arch_dreamcast
#define CC_BUILD_DREAMCAST
+ #define CC_BUILD_CONSOLE
+ #define CC_BUILD_LOWMEM
#define CC_BUILD_OPENAL
#define CC_BUILD_HTTPCLIENT
#define CC_BUILD_BEARSSL
- #define CC_BUILD_LOWMEM
- #define CC_BUILD_CONSOLE
- #undef CC_BUILD_FREETYPE
#undef CC_BUILD_RESOURCES
#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_LOWMEM
- #define CC_BUILD_CONSOLE
#define CC_BUILD_BEARSSL
- #undef CC_BUILD_FREETYPE
#elif defined N64
#define CC_BIG_ENDIAN
#define CC_BUILD_N64
- #define CC_BUILD_OPENAL
- #define CC_BUILD_HTTPCLIENT
- #define CC_BUILD_COOPTHREADED
- #define CC_BUILD_LOWMEM
#define CC_BUILD_CONSOLE
- #undef CC_BUILD_FREETYPE
+ #define CC_BUILD_LOWMEM
+ #define CC_BUILD_COOPTHREADED
+ #define CC_BUILD_OPENAL
#undef CC_BUILD_RESOURCES
#undef CC_BUILD_NETWORKING
#elif defined PLAT_PS2
#define CC_BUILD_PS2
+ #define CC_BUILD_CONSOLE
+ #define CC_BUILD_LOWMEM
+ #define CC_BUILD_COOPTHREADED
#define CC_BUILD_OPENAL
#define CC_BUILD_HTTPCLIENT
- #define CC_BUILD_COOPTHREADED
- #define CC_BUILD_LOWMEM
- #define CC_BUILD_CONSOLE
- #undef CC_BUILD_FREETYPE
#elif defined PLAT_NDS
#define CC_BUILD_NDS
+ #define CC_BUILD_CONSOLE
+ #define CC_BUILD_LOWMEM
+ #define CC_BUILD_COOPTHREADED
#define CC_BUILD_NOMUSIC
#define CC_BUILD_NOSOUNDS
#define CC_BUILD_HTTPCLIENT
- #define CC_BUILD_COOPTHREADED
- #define CC_BUILD_LOWMEM
- #define CC_BUILD_CONSOLE
#define CC_BUILD_TOUCH
- #undef CC_BUILD_FREETYPE
#undef CC_BUILD_RESOURCES
#elif defined __WIIU__
#define CC_BUILD_WIIU
+ #define CC_BUILD_CONSOLE
+ #define CC_BUILD_LOWMEM
+ #define CC_BUILD_COOPTHREADED
#define CC_BUILD_OPENAL
#define CC_BUILD_HTTPCLIENT
- #define CC_BUILD_COOPTHREADED
- #define CC_BUILD_LOWMEM
- #define CC_BUILD_CONSOLE
#define CC_BUILD_BEARSSL
- #undef CC_BUILD_FREETYPE
#elif defined __SWITCH__
#define CC_BUILD_SWITCH
+ #define CC_BUILD_CONSOLE
#define CC_BUILD_HTTPCLIENT
#define CC_BUILD_BEARSSL
- #define CC_BUILD_CONSOLE
#define CC_BUILD_TOUCH
#define CC_BUILD_GL
#define CC_BUILD_GLMODERN
#define CC_BUILD_GLES
#define CC_BUILD_EGL
- #undef CC_BUILD_FREETYPE
#elif defined PLAT_PS1
#define CC_BUILD_PS1
- #define CC_BUILD_HTTPCLIENT
- #define CC_BUILD_COOPTHREADED
- #define CC_BUILD_LOWMEM
#define CC_BUILD_CONSOLE
+ #define CC_BUILD_LOWMEM
+ #define CC_BUILD_COOPTHREADED
#define CC_BUILD_NOMUSIC
#define CC_BUILD_NOSOUNDS
- #undef CC_BUILD_FREETYPE
#undef CC_BUILD_RESOURCES
#undef CC_BUILD_NETWORKING
#elif defined OS2
#define CC_BUILD_OS2
#define CC_BUILD_POSIX
#define CC_BUILD_SOFTGPU
- #define CC_BUILD_SDL
+ #define CC_BUILD_SDL2
#define CC_BUILD_CURL
#define CC_BUILD_FREETYPE
#endif
#endif
+#ifdef CC_BUILD_CONSOLE
+#undef CC_BUILD_FREETYPE
+#undef CC_BUILD_PLUGINS
+#endif
#ifndef CC_BUILD_LOWMEM
#define EXTENDED_BLOCKS
diff --git a/src/Entity.c b/src/Entity.c
index ff8f1bdb8..c73062606 100644
--- a/src/Entity.c
+++ b/src/Entity.c
@@ -1025,6 +1025,7 @@ static const struct EntityVTABLE netPlayer_VTABLE = {
void NetPlayer_Init(struct NetPlayer* p) {
Mem_Set(p, 0, sizeof(struct NetPlayer));
Entity_Init(&p->Base);
+ p->Base.Flags |= ENTITY_FLAG_CLASSIC_ADJUST;
p->Base.VTABLE = &netPlayer_VTABLE;
}
diff --git a/src/Entity.h b/src/Entity.h
index 4c6ea5d2e..18fcbd220 100644
--- a/src/Entity.h
+++ b/src/Entity.h
@@ -87,6 +87,9 @@ struct EntityVTABLE {
/* And therefore trying to access the ModelVB Field in entity struct instances created by the CEF plugin */
/* results in attempting to read or write data from potentially invalid memory */
#define ENTITY_FLAG_HAS_MODELVB 0x02
+/* Whether in classic mode, to slightly adjust this entity downwards when rendering it */
+/* to replicate the behaviour of the original vanilla classic client */
+#define ENTITY_FLAG_CLASSIC_ADJUST 0x04
/* Contains a model, along with position, velocity, and rotation. May also contain other fields and properties. */
struct Entity {
diff --git a/src/EntityRenderers.c b/src/EntityRenderers.c
index 4a35f8eb2..863ca2c46 100644
--- a/src/EntityRenderers.c
+++ b/src/EntityRenderers.c
@@ -232,9 +232,9 @@ static void EntityShadows_MakeTexture(void) {
BitmapCol* row = Bitmap_GetRow(&bmp, y);
for (x = 0; x < sh_size; x++) {
- double dist =
- (sh_half - (x + 0.5)) * (sh_half - (x + 0.5)) +
- (sh_half - (y + 0.5)) * (sh_half - (y + 0.5));
+ float dist =
+ (sh_half - (x + 0.5f)) * (sh_half - (x + 0.5f)) +
+ (sh_half - (y + 0.5f)) * (sh_half - (y + 0.5f));
row[x] = dist < sh_half * sh_half ? color : 0;
}
}
diff --git a/src/EnvRenderer.c b/src/EnvRenderer.c
index 453d504e9..5e5cafbff 100644
--- a/src/EnvRenderer.c
+++ b/src/EnvRenderer.c
@@ -73,7 +73,7 @@ static void UpdateFogMinimal(float fogDensity) {
/* Exp fog mode: f = e^(-density*coord) */
/* Solve coord for f = 0.05 (good approx for fog end) */
/* i.e. log(0.05) = -density * coord */
- #define LOG_005 -2.99573227355399
+ #define LOG_005 -2.99573227355399f
dist = (int)(LOG_005 / -fogDensity);
Game_SetViewDistance(min(dist, Game_UserViewDistance));
@@ -83,7 +83,7 @@ static void UpdateFogMinimal(float fogDensity) {
}
static void UpdateFogNormal(float fogDensity, PackedCol fogColor) {
- double density;
+ float density;
if (fogDensity != 0.0f) {
Gfx_SetFogMode(FOG_EXP);
@@ -96,10 +96,10 @@ static void UpdateFogNormal(float fogDensity, PackedCol fogColor) {
0.99=z/end --> z=end*0.99
therefore
d = -ln(0.01)/(end*0.99) */
- #define LOG_001 -4.60517018598809
+ #define LOG_001 -4.60517018598809f
- density = -(LOG_001) / (Game_ViewDistance * 0.99);
- Gfx_SetFogDensity((float)density);
+ density = -LOG_001 / (Game_ViewDistance * 0.99f);
+ Gfx_SetFogDensity(density);
} else {
Gfx_SetFogMode(FOG_LINEAR);
Gfx_SetFogEnd((float)Game_ViewDistance);
diff --git a/src/ExtMath.c b/src/ExtMath.c
index 6196c6785..28f8a1a81 100644
--- a/src/ExtMath.c
+++ b/src/ExtMath.c
@@ -94,7 +94,7 @@ cc_bool Math_IsPowOf2(int value) {
#define RND_MASK ((1ULL << 48) - 1)
void Random_SeedFromCurrentTime(RNGState* rnd) {
- TimeMS now = DateTime_CurrentUTC_MS();
+ cc_uint64 now = Stopwatch_Measure();
Random_Seed(rnd, (int)now);
}
diff --git a/src/Game.c b/src/Game.c
index e813b4b6e..0624b12f9 100644
--- a/src/Game.c
+++ b/src/Game.c
@@ -53,11 +53,11 @@ int Game_MaxViewDistance = DEFAULT_MAX_VIEWDIST;
int Game_FpsLimit, Game_Vertices;
cc_bool Game_SimpleArmsAnim;
static cc_bool gameRunning;
-static cc_bool anaglyph3D;
cc_bool Game_ClassicMode, Game_ClassicHacks;
cc_bool Game_AllowCustomBlocks;
cc_bool Game_AllowServerTextures;
+cc_bool Game_Anaglyph3D;
cc_bool Game_ViewBobbing, Game_HideGui;
cc_bool Game_BreakableLiquids, Game_ScreenshotRequested;
@@ -344,12 +344,10 @@ static void LoadOptions(void) {
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
Options.Set("skip-ssl-check", false);
}*/
- anaglyph3D = Options_GetBool("anaglyph3D", false);
+ Game_Anaglyph3D = Options_GetBool(OPT_ANAGLYPH3D, false);
}
-#ifdef CC_BUILD_MINFILES
-static void LoadPlugins(void) { }
-#else
+#ifdef CC_BUILD_PLUGINS
static void LoadPlugin(const cc_string* path, void* obj) {
void* lib;
void* verSym; /* EXPORT int Plugin_ApiVersion = GAME_API_VER; */
@@ -390,6 +388,8 @@ static void LoadPlugins(void) {
res = Directory_Enum(&dir, NULL, LoadPlugin);
if (res) Logger_SysWarn(res, "enumerating plugins directory");
}
+#else
+static void LoadPlugins(void) { }
#endif
static void Game_Free(void* obj);
@@ -637,7 +637,9 @@ static void Game_RenderFrame(double delta) {
Game.Time += delta;
Game_Vertices = 0;
+ if (Input.Sources & INPUT_SOURCE_GAMEPAD) Gamepad_Tick(delta);
Camera.Active->UpdateMouse(delta);
+
if (!Window_Main.Focused && !Gui.InputGrab) Gui_ShowPauseMenu();
if (KeyBind_IsPressed(KEYBIND_ZOOM_SCROLL) && !Gui.InputGrab) {
@@ -664,7 +666,7 @@ static void Game_RenderFrame(double delta) {
Camera_KeyLookUpdate(delta);
InputHandler_Tick();
- if (anaglyph3D) {
+ if (Game_Anaglyph3D) {
Render3D_Anaglyph(delta, t);
} else {
Render3DFrame(delta, t);
diff --git a/src/Game.h b/src/Game.h
index 6001cac5b..e796dae06 100644
--- a/src/Game.h
+++ b/src/Game.h
@@ -26,7 +26,7 @@ extern cc_string Game_Mppass;
#if defined CC_BUILD_N64
#define DEFAULT_VIEWDIST 20
-#elif defined CC_BUILD_NDS
+#elif defined CC_BUILD_NDS || defined CC_BUILD_PS1
#define DEFAULT_VIEWDIST 192
#else
#define DEFAULT_VIEWDIST 512
@@ -48,6 +48,7 @@ extern cc_bool Game_ClassicHacks;
extern cc_bool Game_AllowCustomBlocks;
extern cc_bool Game_AllowServerTextures;
+extern cc_bool Game_Anaglyph3D;
extern cc_bool Game_ViewBobbing;
extern cc_bool Game_BreakableLiquids;
/* Whether a screenshot should be taken at the end of this frame */
diff --git a/src/Graphics_3DS.c b/src/Graphics_3DS.c
index eff743854..08164e8d9 100644
--- a/src/Graphics_3DS.c
+++ b/src/Graphics_3DS.c
@@ -148,8 +148,9 @@ static GfxResourceID white_square;
void Gfx_Create(void) {
if (!Gfx.Created) InitCitro3D();
- Gfx.MaxTexWidth = 512;
- Gfx.MaxTexHeight = 512;
+ Gfx.MaxTexWidth = 1024;
+ Gfx.MaxTexHeight = 1024;
+ Gfx.MaxTexSize = 512 * 512;
Gfx.Created = true;
gfx_vsync = true;
@@ -406,8 +407,34 @@ static void SetColorWrite(cc_bool r, cc_bool g, cc_bool b, cc_bool a) {
/*########################################################################################################################*
*-----------------------------------------------------------Misc----------------------------------------------------------*
*#########################################################################################################################*/
+static BitmapCol* _3DS_GetRow(struct Bitmap* bmp, int y, void* ctx) {
+ u8* fb = (u8*)ctx;
+ // Framebuffer is rotated 90 degrees
+ int width = bmp->width, height = bmp->height;
+
+ for (int x = 0; x < width; x++)
+ {
+ int addr = (height - 1 - y + x * height) * 3; // TODO -1 or not
+ int b = fb[addr + 0];
+ int g = fb[addr + 1];
+ int r = fb[addr + 2];
+ bmp->scan0[x] = BitmapColor_RGB(r, g, b);
+ }
+ return bmp->scan0;
+}
+
cc_result Gfx_TakeScreenshot(struct Stream* output) {
- return ERR_NOT_SUPPORTED;
+ BitmapCol tmp[512];
+ u16 width, height;
+ u8* fb = gfxGetFramebuffer(GFX_TOP, GFX_LEFT, &width, &height);
+
+ // Framebuffer is rotated 90 degrees
+ struct Bitmap bmp;
+ bmp.scan0 = tmp;
+ bmp.width = height;
+ bmp.height = width;
+
+ return Png_Encode(&bmp, output, _3DS_GetRow, false, fb);
}
void Gfx_GetApiInfo(cc_string* info) {
@@ -445,7 +472,7 @@ void Gfx_EndFrame(void) {
if (gfx_minFrameMs) LimitFPS();
GPUBuffers_DeleteUnreferenced();
- //GPUTextures_DeleteUnreferenced();
+ GPUTextures_DeleteUnreferenced();
frameCounter++;
}
@@ -853,4 +880,4 @@ void Gfx_Draw2DTexture(const struct Texture* tex, PackedCol color) {
C3D_ImmSendAttrib(v[0].U, v[0].V, 0.0f, 0.0f);
C3D_ImmDrawEnd();
}
-#endif
\ No newline at end of file
+#endif
diff --git a/src/Graphics_D3D11.c b/src/Graphics_D3D11.c
index bcb596f09..4954db3a6 100644
--- a/src/Graphics_D3D11.c
+++ b/src/Graphics_D3D11.c
@@ -1055,13 +1055,8 @@ void Gfx_DepthOnlyRendering(cc_bool depthOnly) {
/*########################################################################################################################*
*-----------------------------------------------------------Misc----------------------------------------------------------*
*#########################################################################################################################*/
-static BitmapCol* D3D11_GetRow(struct Bitmap* bmp, int y) {
- // You were expecting a BitmapCol*, but it was me, D3D11_MAPPED_SUBRESOURCE*!
- // This is necessary because the stride of the mapped backbuffer often doesn't equal width of the bitmap
- // e.g. with backbuffer width of 854, stride is 3456 bytes instead of expected 3416 (854*4)
- // Therefore have to calculate row address manually instead of using Bitmap_GetRow
- D3D11_MAPPED_SUBRESOURCE* buffer = (D3D11_MAPPED_SUBRESOURCE*)bmp->scan0;
-
+static BitmapCol* D3D11_GetRow(struct Bitmap* bmp, int y, void* ctx) {
+ D3D11_MAPPED_SUBRESOURCE* buffer = (D3D11_MAPPED_SUBRESOURCE*)ctx;
char* row = (char*)buffer->pData + y * buffer->RowPitch;
return (BitmapCol*)row;
}
@@ -1094,8 +1089,8 @@ cc_result Gfx_TakeScreenshot(struct Stream* output) {
hr = ID3D11DeviceContext_Map(context, tmp, 0, D3D11_MAP_READ, 0, &buffer);
if (hr) goto finished;
{
- Bitmap_Init(bmp, desc.Width, desc.Height, (BitmapCol*)&buffer);
- hr = Png_Encode(&bmp, output, D3D11_GetRow, false);
+ Bitmap_Init(bmp, desc.Width, desc.Height, NULL);
+ hr = Png_Encode(&bmp, output, D3D11_GetRow, false, &buffer);
}
ID3D11DeviceContext_Unmap(context, tmp, 0);
diff --git a/src/Graphics_D3D9.c b/src/Graphics_D3D9.c
index cd980b9ae..8ec050be2 100644
--- a/src/Graphics_D3D9.c
+++ b/src/Graphics_D3D9.c
@@ -335,7 +335,7 @@ static GfxResourceID Gfx_AllocTexture(struct Bitmap* bmp, cc_uint8 flags, cc_boo
int mipmapsLevels = CalcMipmapsLevels(bmp->width, bmp->height);
int levels = 1 + (mipmaps ? mipmapsLevels : 0);
-
+
if (flags & TEXTURE_FLAG_MANAGED) {
while ((res = IDirect3DDevice9_CreateTexture(device, bmp->width, bmp->height, levels,
0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &tex, NULL)))
@@ -812,7 +812,7 @@ cc_result Gfx_TakeScreenshot(struct Stream* output) {
if (res) goto finished;
{
Bitmap_Init(bmp, desc.Width, desc.Height, (BitmapCol*)rect.pBits);
- res = Png_Encode(&bmp, output, NULL, false);
+ res = Png_Encode(&bmp, output, NULL, false, NULL);
if (res) { IDirect3DSurface9_UnlockRect(temp); goto finished; }
}
res = IDirect3DSurface9_UnlockRect(temp);
diff --git a/src/Graphics_Dreamcast.c b/src/Graphics_Dreamcast.c
index af8e53a7a..1dceb9dd1 100644
--- a/src/Graphics_Dreamcast.c
+++ b/src/Graphics_Dreamcast.c
@@ -543,4 +543,4 @@ void Gfx_EndFrame(void) {
void Gfx_OnWindowResize(void) {
glViewport(0, 0, Game.Width, Game.Height);
}
-#endif
\ No newline at end of file
+#endif
diff --git a/src/Graphics_GCWii.c b/src/Graphics_GCWii.c
index d5eb44973..498af41e9 100644
--- a/src/Graphics_GCWii.c
+++ b/src/Graphics_GCWii.c
@@ -50,8 +50,9 @@ static void InitGX(void) {
void Gfx_Create(void) {
if (!Gfx.Created) InitGX();
- Gfx.MaxTexWidth = 512;
- Gfx.MaxTexHeight = 512;
+ Gfx.MaxTexWidth = 1024;
+ Gfx.MaxTexHeight = 1024;
+ Gfx.MaxTexSize = 512 * 512;
Gfx.Created = true;
gfx_vsync = true;
@@ -236,8 +237,53 @@ void Gfx_SetDepthTest(cc_bool enabled) {
/*########################################################################################################################*
*-----------------------------------------------------------Misc----------------------------------------------------------*
*#########################################################################################################################*/
+static BitmapCol* GCWii_GetRow(struct Bitmap* bmp, int y, void* ctx) {
+ u8* buffer = (u8*)ctx;
+ u8 a, r, g, b;
+ int blockYStride = 4 * (bmp->width * 4); // tile row stride = 4 * row stride
+ int blockXStride = (4 * 4) * 4; // 16 pixels per tile
+
+ // Do the inverse of converting from 4x4 tiled to linear
+ for (u32 x = 0; x < bmp->width; x++){
+ int tileY = y >> 2, tileX = x >> 2;
+ int locY = y & 0x3, locX = x & 0x3;
+ int idx = (tileY * blockYStride) + (tileX * blockXStride) + ((locY << 2) + locX) * 2;
+
+ // All 16 pixels are stored with AR first, then GB
+ //a = buffer[idx ];
+ r = buffer[idx + 1];
+ g = buffer[idx + 32];
+ b = buffer[idx + 33];
+
+ bmp->scan0[x] = BitmapColor_RGB(r, g, b);
+ }
+ return bmp->scan0;
+}
+
cc_result Gfx_TakeScreenshot(struct Stream* output) {
- return ERR_NOT_SUPPORTED;
+ BitmapCol tmp[1024];
+ GXRModeObj* vmode = VIDEO_GetPreferredMode(NULL);
+ int width = vmode->fbWidth;
+ int height = vmode->efbHeight;
+
+ u8* buffer = memalign(32, width * height * 4);
+ if (!buffer) return ERR_OUT_OF_MEMORY;
+
+ GX_SetTexCopySrc(0, 0, width, height);
+ GX_SetTexCopyDst(width, height, GX_TF_RGBA8, GX_FALSE);
+ GX_CopyTex(buffer, GX_FALSE);
+ GX_PixModeSync();
+ GX_Flush();
+ DCFlushRange(buffer, width * height * 4);
+
+ struct Bitmap bmp;
+ bmp.scan0 = tmp;
+ bmp.width = width;
+ bmp.height = height;
+
+ cc_result res = Png_Encode(&bmp, output, GCWii_GetRow, false, buffer);
+ free(buffer);
+ return res;
}
void Gfx_GetApiInfo(cc_string* info) {
@@ -282,7 +328,7 @@ cc_bool Gfx_WarnIfNecessary(void) { return false; }
GfxResourceID Gfx_CreateIb2(int count, Gfx_FillIBFunc fillFunc, void* obj) {
//fillFunc(gfx_indices, count, obj);
// not used since render using GX_QUADS anyways
- return 1;
+ return (void*)1;
}
void Gfx_BindIb(GfxResourceID ib) { }
@@ -552,4 +598,4 @@ void Gfx_DrawVb_IndexedTris(int verticesCount) {
void Gfx_DrawIndexedTris_T2fC4b(int verticesCount, int startVertex) {
Draw_TexturedTriangles(verticesCount, startVertex);
}
-#endif
\ No newline at end of file
+#endif
diff --git a/src/Graphics_PS1.c b/src/Graphics_PS1.c
index 8b427d81f..286949f9c 100644
--- a/src/Graphics_PS1.c
+++ b/src/Graphics_PS1.c
@@ -22,7 +22,7 @@
// Size of the buffer GPU commands and primitives are written to. If the program
// crashes due to too many primitives being drawn, increase this value.
-#define BUFFER_LENGTH 8192
+#define BUFFER_LENGTH 32768
typedef struct {
DISPENV disp_env;
@@ -82,12 +82,20 @@ static void* new_primitive(int size) {
return (void*)prim;
}
+static GfxResourceID white_square;
void Gfx_RestoreState(void) {
InitDefaultResources();
+
+ // 2x2 dummy white texture
+ struct Bitmap bmp;
+ BitmapCol pixels[4] = { BITMAPCOLOR_WHITE, BITMAPCOLOR_WHITE, BITMAPCOLOR_WHITE, BITMAPCOLOR_WHITE };
+ Bitmap_Init(bmp, 2, 2, pixels);
+ white_square = Gfx_CreateTexture(&bmp, 0, false);
}
void Gfx_FreeState(void) {
- FreeDefaultResources();
+ FreeDefaultResources();
+ Gfx_DeleteTexture(&white_square);
}
void Gfx_Create(void) {
@@ -115,16 +123,143 @@ void Gfx_Free(void) {
/*########################################################################################################################*
*---------------------------------------------------------Textures--------------------------------------------------------*
*#########################################################################################################################*/
+// 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
+
+#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 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;
+ } else if (width >= 128) {
+ *beg = 4 * TPAGE_HEIGHT;
+ *end = 12 * TPAGE_HEIGHT;
+ } else {
+ *beg = 12 * TPAGE_HEIGHT;
+ *end = 22 * TPAGE_HEIGHT;
+ }
+}
+
+static cc_bool VRAM_IsRangeFree(int beg, int end) {
+ for (int i = beg; i < end; i++)
+ {
+ if (VRAM_IsUsed(i)) return false;
+ }
+ return true;
+}
+
+static int VRAM_FindFreeBlock(int width, int height) {
+ int beg, end;
+ VRAM_GetBlockRange(width, &beg, &end);
+
+ // TODO kinda inefficient
+ for (int i = beg; i < end - height; i++)
+ {
+ if (VRAM_IsUsed(i)) continue;
+
+ if (VRAM_IsRangeFree(i, i + height)) return i;
+ }
+ return -1;
+}
+
+#define TEXTURES_MAX_COUNT 64
+typedef struct GPUTexture {
+ cc_uint16 width, height;
+ cc_uint16 line, tpage;
+} GPUTexture;
+static GPUTexture textures[TEXTURES_MAX_COUNT];
+static GPUTexture* active_tex;
+
+#define BGRA8_to_PS1(src) \
+ ((src[2] & 0xF8) >> 3) | ((src[1] & 0xF8) << 2) | ((src[0] & 0xF8) << 7) | 0x8000
+
+static void* AllocTextureAt(int i, struct Bitmap* bmp) {
+ cc_uint16* tmp = Mem_TryAlloc(bmp->width * bmp->height, 2);
+ if (!tmp) return NULL;
+
+ for (int y = 0; y < bmp->height; y++)
+ {
+ cc_uint32* src = bmp->scan0 + y * bmp->width;
+ cc_uint16* dst = tmp + y * bmp->width;
+
+ for (int x = 0; x < bmp->width; x++) {
+ cc_uint8* color = (cc_uint8*)&src[x];
+ dst[x] = BGRA8_to_PS1(color);
+ }
+ }
+
+ GPUTexture* tex = &textures[i];
+ 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->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;
+
+ for (int i = tex->line; i < tex->line + tex->height; i++)
+ {
+ VRAM_SetUsed(i);
+ }
+ tex->tpage = page;
+ Platform_Log4("%i x %i = %i,%i", &bmp->width, &bmp->height, &line, &page);
+
+ RECT rect;
+ rect.x = ((page % TPAGES_PER_HALF)) * TPAGE_WIDTH;
+ rect.y = ((page / TPAGES_PER_HALF)) * TPAGE_HEIGHT + (line % TPAGE_HEIGHT);
+ rect.w = bmp->width;
+ rect.h = bmp->height;
+
+ int RX = rect.x, RY = rect.y;
+ Platform_Log2("LOAD AT: %i, %i", &RX, &RY);
+ LoadImage2(&rect, tmp);
+
+ Mem_Free(tmp);
+ return tex;
+}
+
static GfxResourceID Gfx_AllocTexture(struct Bitmap* bmp, cc_uint8 flags, cc_bool mipmaps) {
+ for (int i = 0; i < TEXTURES_MAX_COUNT; i++)
+ {
+ if (textures[i].width) continue;
+ return AllocTextureAt(i, bmp);
+ }
+
+ Platform_LogConst("No room for more textures");
return NULL;
}
void Gfx_BindTexture(GfxResourceID texId) {
+ if (!texId) texId = white_square;
+ active_tex = (GPUTexture*)texId;
}
void Gfx_DeleteTexture(GfxResourceID* texId) {
GfxResourceID data = *texId;
- if (data) Mem_Free(data);
+ if (!data) return;
+ GPUTexture* tex = (GPUTexture*)data;
+
+ for (int i = tex->line; i < tex->line + tex->height; i++)
+ {
+ VRAM_UnUsed(i);
+ }
+ tex->width = 0; tex->height = 0;
*texId = NULL;
}
@@ -133,7 +268,7 @@ void Gfx_UpdateTexture(GfxResourceID texId, int x, int y, struct Bitmap* part, i
}
void Gfx_UpdateTexturePart(GfxResourceID texId, int x, int y, struct Bitmap* part, cc_bool mipmaps) {
- // TODO
+ Gfx_UpdateTexture(texId, x, y, part, part->width, mipmaps);
}
void Gfx_EnableMipmaps(void) { }
@@ -387,17 +522,19 @@ static void Transform(Vec3* result, struct VertexTextured* a, const struct Matri
float x = a->x * mat->row1.x + a->y * mat->row2.x + a->z * mat->row3.x + mat->row4.x;
float y = a->x * mat->row1.y + a->y * mat->row2.y + a->z * mat->row3.y + mat->row4.y;
float z = a->x * mat->row1.z + a->y * mat->row2.z + a->z * mat->row3.z + mat->row4.z;
+ float w = a->x * mat->row1.w + a->y * mat->row2.w + a->z * mat->row3.w + mat->row4.w;
- result->x = x * (320/2) + (320/2);
- result->y = y * -(240/2) + (240/2);
- result->z = z * OT_LENGTH;
+ result->x = (x/w) * (320/2) + (320/2);
+ result->y = (y/w) * -(240/2) + (240/2);
+ result->z = (z/w) * OT_LENGTH;
}
cc_bool VERTEX_LOGGING;
-static void DrawQuads(int verticesCount, int startVertex) {
+static void DrawColouredQuads(int verticesCount, int startVertex) {
+ return;
for (int i = 0; i < verticesCount; i += 4)
{
- struct VertexTextured* v = (struct VertexTextured*)gfx_vertices + startVertex + i;
+ struct VertexColoured* v = (struct VertexColoured*)gfx_vertices + startVertex + i;
POLY_F4* poly = new_primitive(sizeof(POLY_F4));
setPolyF4(poly);
@@ -413,18 +550,55 @@ static void DrawQuads(int verticesCount, int startVertex) {
poly->x2 = coords[2].x; poly->y2 = coords[2].y;
poly->x3 = coords[3].x; poly->y3 = coords[3].y;
+ int p = (coords[0].z + coords[1].z + coords[2].z + coords[3].z) / 4;
+ if (p < 0 || p >= OT_LENGTH) continue;
+
int X = v[0].x, Y = v[0].y, Z = v[0].z;
- if (VERTEX_LOGGING) Platform_Log3("IN: %i, %i, %i", &X, &Y, &Z);
+ //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);
+ //if (VERTEX_LOGGING) Platform_Log4("OUT: %i, %i, %i (%i)", &X, &Y, &Z, &p);
- int p = (coords[0].z + coords[1].z + coords[2].z + coords[3].z) / 4;
- if (VERTEX_LOGGING) Platform_Log4("OUT: %i, %i, %i (%i)", &X, &Y, &Z, &p);
+ addPrim(&buffer->ot[p >> 2], poly);
+ }
+}
+
+static void DrawTexturedQuads(int verticesCount, int startVertex) {
+ 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 = active_tex->tpage;
+ poly->clut = 0;
+
+ Vec3 coords[4];
+ Transform(&coords[0], &v[0], &mvp);
+ Transform(&coords[1], &v[1], &mvp);
+ Transform(&coords[2], &v[2], &mvp);
+ Transform(&coords[3], &v[3], &mvp);
+ 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 + active_tex->line;
+ 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 + active_tex->line;
+ 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 + active_tex->line;
+ 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 + active_tex->line;
+
+ int p = (coords[0].z + coords[1].z + coords[2].z + coords[3].z) / 4;
if (p < 0 || p >= OT_LENGTH) continue;
+
+ int X = v[0].x, Y = v[0].y, Z = v[0].z;
+ //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);
+ //if (VERTEX_LOGGING) Platform_Log4("OUT: %i, %i, %i (%i)", &X, &Y, &Z, &p);
+
addPrim(&buffer->ot[p >> 2], poly);
}
}
@@ -498,17 +672,23 @@ static void DrawQuads(int verticesCount, int startVertex) {
}*/
void Gfx_DrawVb_IndexedTris_Range(int verticesCount, int startVertex) {
- if (gfx_format == VERTEX_FORMAT_COLOURED) return;
- DrawQuads(verticesCount, startVertex);
+ if (gfx_format == VERTEX_FORMAT_TEXTURED) {
+ DrawTexturedQuads(verticesCount, startVertex);
+ } else {
+ DrawColouredQuads(verticesCount, startVertex);
+ }
}
void Gfx_DrawVb_IndexedTris(int verticesCount) {
- if (gfx_format == VERTEX_FORMAT_COLOURED) return;
- DrawQuads(verticesCount, 0);
+ if (gfx_format == VERTEX_FORMAT_TEXTURED) {
+ DrawTexturedQuads(verticesCount, 0);
+ } else {
+ DrawColouredQuads(verticesCount, 0);
+ }
}
void Gfx_DrawIndexedTris_T2fC4b(int verticesCount, int startVertex) {
- DrawQuads(verticesCount, startVertex);
+ DrawTexturedQuads(verticesCount, startVertex);
}
diff --git a/src/Graphics_PS3.c b/src/Graphics_PS3.c
index 63c9d4e9d..8bcd00447 100644
--- a/src/Graphics_PS3.c
+++ b/src/Graphics_PS3.c
@@ -711,4 +711,4 @@ void Gfx_DrawVb_IndexedTris(int verticesCount) {/* TODO */
void Gfx_DrawIndexedTris_T2fC4b(int verticesCount, int startVertex) {/* TODO */
rsxDrawVertexArray(context, GCM_TYPE_QUADS, startVertex, verticesCount);
}
-#endif
\ No newline at end of file
+#endif
diff --git a/src/Graphics_PSP.c b/src/Graphics_PSP.c
index 308c0884b..b382f4f3b 100644
--- a/src/Graphics_PSP.c
+++ b/src/Graphics_PSP.c
@@ -44,7 +44,7 @@ static void guInit(void) {
sceGuOffset(2048 - (SCREEN_WIDTH / 2), 2048 - (SCREEN_HEIGHT / 2));
sceGuViewport(2048, 2048, SCREEN_WIDTH, SCREEN_HEIGHT);
sceGuDepthRange(65535,0);
- sceGuFrontFace(GU_CW);
+ sceGuFrontFace(GU_CCW);
sceGuShadeModel(GU_SMOOTH);
sceGuDisable(GU_TEXTURE_2D);
@@ -166,7 +166,7 @@ void Gfx_BindTexture(GfxResourceID texId) {
*-----------------------------------------------------State management----------------------------------------------------*
*#########################################################################################################################*/
static PackedCol gfx_clearColor;
-void Gfx_SetFaceCulling(cc_bool enabled) { /*GU_Toggle(GU_CULL_FACE); */ } // TODO: Fix? GU_CCW instead??
+void Gfx_SetFaceCulling(cc_bool enabled) { GU_Toggle(GU_CULL_FACE); }
void Gfx_SetAlphaBlending(cc_bool enabled) { GU_Toggle(GU_BLEND); }
void Gfx_SetAlphaArgBlend(cc_bool enabled) { }
@@ -233,8 +233,25 @@ void Gfx_CalcPerspectiveMatrix(struct Matrix* matrix, float fov, float aspect, f
/*########################################################################################################################*
*-----------------------------------------------------------Misc----------------------------------------------------------*
*#########################################################################################################################*/
+static BitmapCol* PSP_GetRow(struct Bitmap* bmp, int y, void* ctx) {
+ cc_uint8* fb = (cc_uint8*)ctx;
+ return (BitmapCol*)(fb + y * BUFFER_WIDTH * 4);
+}
+
cc_result Gfx_TakeScreenshot(struct Stream* output) {
- return ERR_NOT_SUPPORTED;
+ int fbWidth, fbFormat;
+ void* fb;
+
+ int res = sceDisplayGetFrameBuf(&fb, &fbWidth, &fbFormat, PSP_DISPLAY_SETBUF_NEXTFRAME);
+ if (res < 0) return res;
+ if (!fb) return ERR_NOT_SUPPORTED;
+
+ struct Bitmap bmp;
+ bmp.scan0 = NULL;
+ bmp.width = SCREEN_WIDTH;
+ bmp.height = SCREEN_HEIGHT;
+
+ return Png_Encode(&bmp, output, PSP_GetRow, false, fb);
}
void Gfx_GetApiInfo(cc_string* info) {
diff --git a/src/Graphics_PSVita.c b/src/Graphics_PSVita.c
index 2ef543520..fbfc41d9d 100644
--- a/src/Graphics_PSVita.c
+++ b/src/Graphics_PSVita.c
@@ -563,8 +563,9 @@ void Gfx_Create(void) {
if (!Gfx.Created) InitGPU();
in_scene = false;
- Gfx.MaxTexWidth = 512;
- Gfx.MaxTexHeight = 512;
+ Gfx.MaxTexWidth = 1024;
+ Gfx.MaxTexHeight = 1024;
+ Gfx.MaxTexSize = 512 * 512;
Gfx.Created = true;
gfx_vsync = true;
@@ -624,15 +625,11 @@ static void GPUTexture_Unref(GfxResourceID* resource) {
struct GPUTexture* tex = (struct GPUTexture*)(*resource);
if (!tex) return;
*resource = NULL;
-
- cc_uintptr addr = tex;
- Platform_Log1("TEX UNREF %h", &addr);
+
LinkedList_Append(tex, del_textures_head, del_textures_tail);
}
static void GPUTexture_Free(struct GPUTexture* tex) {
- cc_uintptr addr = tex;
- Platform_Log1("TEX DELETE %h", &addr);
FreeGPUMemory(tex->uid);
Mem_Free(tex);
}
@@ -838,9 +835,6 @@ struct GPUBuffer* GPUBuffer_Alloc(int size) {
buffer->data = AllocGPUMemory(size,
SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE, SCE_GXM_MEMORY_ATTRIB_READ,
&buffer->uid);
-
- cc_uintptr addr = buffer->data;
- Platform_Log2("VB ALLOC %h = %i bytes", &addr, &size);
return buffer;
}
@@ -851,14 +845,10 @@ static void GPUBuffer_Unref(GfxResourceID* resource) {
if (!buf) return;
*resource = NULL;
- cc_uintptr addr = buf;
- Platform_Log1("VB UNREF %h", &addr);
LinkedList_Append(buf, del_buffers_head, del_buffers_tail);
}
static void GPUBuffer_Free(struct GPUBuffer* buf) {
- cc_uintptr addr = buf;
- Platform_Log1("VB DELETE %h", &addr);
FreeGPUMemory(buf->uid);
Mem_Free(buf);
}
diff --git a/src/Http_Web.c b/src/Http_Web.c
index fe15a6516..c6374acec 100644
--- a/src/Http_Web.c
+++ b/src/Http_Web.c
@@ -139,7 +139,7 @@ static void Http_Init(void) {
Http_InitCommon();
/* If this webpage is https://, browsers deny any http:// downloading */
httpsOnly = interop_IsHttpsOnly();
- startTime = DateTime_CurrentUTC_MS();
+ startTime = DateTime_CurrentUTC();
RequestList_Init(&queuedReqs);
RequestList_Init(&workingReqs);
diff --git a/src/Http_Worker.c b/src/Http_Worker.c
index e5f7b170a..b7c0a625d 100644
--- a/src/Http_Worker.c
+++ b/src/Http_Worker.c
@@ -1164,6 +1164,24 @@ static cc_result HttpBackend_Do(struct HttpRequest* req, cc_string* url) {
CFRelease(request);
return result;
}
+#elif !defined CC_BUILD_NETWORKING
+/*########################################################################################################################*
+*------------------------------------------------------Null backend-------------------------------------------------------*
+*#########################################################################################################################*/
+#include "Errors.h"
+
+static cc_bool HttpBackend_DescribeError(cc_result res, cc_string* dst) {
+ return false;
+}
+
+static void HttpBackend_Init(void) { }
+
+static void Http_AddHeader(struct HttpRequest* req, const char* key, const cc_string* value) { }
+
+static cc_result HttpBackend_Do(struct HttpRequest* req, cc_string* url) {
+ req->progress = 100;
+ return ERR_NOT_SUPPORTED;
+}
#endif
diff --git a/src/Input.c b/src/Input.c
index a648ef063..6edcfb66a 100644
--- a/src/Input.c
+++ b/src/Input.c
@@ -414,6 +414,54 @@ static void KeyBind_Init(void) {
}
+/*########################################################################################################################*
+*---------------------------------------------------------Gamepad---------------------------------------------------------*
+*#########################################################################################################################*/
+#define GAMEPAD_BEG_BTN CCPAD_A
+static float pad_holdtime[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 };
+
+void Gamepad_SetButton(int btn, int pressed) {
+ /* Reset hold tracking time */
+ if (pressed && !Input.Pressed[btn]) pad_holdtime[btn - GAMEPAD_BEG_BTN] = 0;
+
+ Input_SetNonRepeatable(btn, pressed);
+}
+
+void Gamepad_SetAxis(int axis, float x, float y, double delta) {
+ if (!Input.RawMode) return;
+
+ if (Gamepad_AxisBehaviour[axis] == AXIS_BEHAVIOUR_MOVEMENT) {
+ if (x == 0 && y == 0) return;
+
+ Input.JoystickMovement = true;
+ Input.JoystickAngle = Math_Atan2(x, -y);
+ } else {
+ int sensi = Gamepad_AxisSensitivity[axis];
+ float scale = delta * 60.0 * axis_sensiFactor[sensi];
+ Event_RaiseRawMove(&ControllerEvents.RawMoved, x * scale, y * scale);
+ }
+}
+
+void Gamepad_Tick(double delta) {
+ int btn;
+
+ for (btn = GAMEPAD_BEG_BTN; btn < INPUT_COUNT; btn++)
+ {
+ if (!Input.Pressed[btn]) continue;
+ pad_holdtime[btn - GAMEPAD_BEG_BTN] += delta;
+ if (pad_holdtime[btn - GAMEPAD_BEG_BTN] < 1.0) continue;
+
+ /* Held for over a second, trigger a fake press */
+ pad_holdtime[btn - GAMEPAD_BEG_BTN] = 0;
+ Input_SetPressed(btn);
+ }
+}
+
+
/*########################################################################################################################*
*---------------------------------------------------------Hotkeys---------------------------------------------------------*
*#########################################################################################################################*/
diff --git a/src/Input.h b/src/Input.h
index bd2c9715d..38d5ad316 100644
--- a/src/Input.h
+++ b/src/Input.h
@@ -102,15 +102,16 @@ void Input_Clear(void);
#define Input_IsEscapeButton(btn) ((btn) == CCKEY_ESCAPE || (btn) == CCPAD_SELECT)
#if defined CC_BUILD_HAIKU
-/* Haiku uses ALT instead of CTRL for clipboard and stuff */
-#define Input_IsActionPressed() Input_IsAltPressed()
+ /* Haiku uses ALT instead of CTRL for clipboard and stuff */
+ #define Input_IsActionPressed() Input_IsAltPressed()
#elif defined CC_BUILD_DARWIN
-/* macOS uses CMD instead of CTRL for clipboard and stuff */
-#define Input_IsActionPressed() Input_IsWinPressed()
+ /* macOS uses CMD instead of CTRL for clipboard and stuff */
+ #define Input_IsActionPressed() Input_IsWinPressed()
#else
-#define Input_IsActionPressed() Input_IsCtrlPressed()
+ #define Input_IsActionPressed() Input_IsCtrlPressed()
#endif
+
#ifdef CC_BUILD_TOUCH
#define INPUT_MAX_POINTERS 32
enum INPUT_MODE { INPUT_MODE_PLACE, INPUT_MODE_DELETE, INPUT_MODE_NONE, INPUT_MODE_COUNT };
@@ -184,6 +185,23 @@ CC_API cc_bool KeyBind_IsPressed(KeyBind binding);
/* Set the key that the given key binding is bound to. (also updates options list) */
void KeyBind_Set(KeyBind binding, int key, cc_uint8* binds);
+
+/* Gamepad axes. Default behaviour is: */
+/* - left axis: player movement */
+/* - right axis: camera movement */
+enum PAD_AXIS { PAD_AXIS_LEFT, PAD_AXIS_RIGHT };
+enum AXIS_SENSITIVITY { AXIS_SENSI_LOWER, AXIS_SENSI_LOW, AXIS_SENSI_NORMAL, AXIS_SENSI_HIGH, AXIS_SENSI_HIGHER };
+enum AXIS_BEHAVIOUR { AXIS_BEHAVIOUR_MOVEMENT, AXIS_BEHAVIOUR_CAMERA };
+extern int Gamepad_AxisBehaviour[2];
+extern int Gamepad_AxisSensitivity[2];
+
+/* Sets value of the given gamepad button */
+void Gamepad_SetButton(int btn, int pressed);
+/* Sets value of the given axis */
+void Gamepad_SetAxis(int axis, float x, float y, double delta);
+void Gamepad_Tick(double delta);
+
+
/* whether to leave text input open for user to enter further input */
#define HOTKEY_FLAG_STAYS_OPEN 0x01
/* Whether the hotkey was auto defined (e.g. by server) */
@@ -219,6 +237,7 @@ void StoredHotkeys_Remove(int trigger, cc_uint8 modifiers);
/* Adds the given hotkey from options. */
void StoredHotkeys_Add(int trigger, cc_uint8 modifiers, cc_bool moreInput, const cc_string* text);
+
cc_bool InputHandler_SetFOV(int fov);
cc_bool Input_HandleMouseWheel(float delta);
void InputHandler_Tick(void);
diff --git a/src/LBackend.c b/src/LBackend.c
index 28f7610b2..dc55743e5 100644
--- a/src/LBackend.c
+++ b/src/LBackend.c
@@ -534,7 +534,7 @@ void LBackend_CheckboxDraw(struct LCheckbox* w) {
/*########################################################################################################################*
*------------------------------------------------------InputWidget--------------------------------------------------------*
*#########################################################################################################################*/
-static TimeMS caretStart;
+static cc_uint64 caretStart;
static Rect2D caretRect, lastCaretRect;
#define Rect2D_Equals(a, b) a.x == b.x && a.y == b.y && a.Width == b.Width && a.Height == b.Height
@@ -620,7 +620,7 @@ void LBackend_InputTick(struct LInput* w) {
Rect2D r;
if (!caretStart) return;
- elapsed = (int)(DateTime_CurrentUTC_MS() - caretStart);
+ elapsed = Stopwatch_ElapsedMS(caretStart, Stopwatch_Measure());
caretShow = (elapsed % 1000) < 500;
if (caretShow == w->caretShow) return;
@@ -641,7 +641,7 @@ void LBackend_InputTick(struct LInput* w) {
void LBackend_InputSelect(struct LInput* w, int idx, cc_bool wasSelected) {
struct OpenKeyboardArgs args;
- caretStart = DateTime_CurrentUTC_MS();
+ caretStart = Stopwatch_Measure();
w->caretShow = true;
LInput_MoveCaretToCursor(w, idx);
LBackend_MarkDirty(w);
diff --git a/src/LScreens.c b/src/LScreens.c
index ea611bf06..a4a5e25b5 100644
--- a/src/LScreens.c
+++ b/src/LScreens.c
@@ -1012,9 +1012,11 @@ static void CheckResourcesScreen_Next(void* w) {
}
static void CheckResourcesScreen_AddWidgets(struct CheckResourcesScreen* s) {
+ const char* line1_msg = Resources_MissingRequired ? "Some required resources weren't found"
+ : "Some optional resources weren't found";
s->lblStatus.small = true;
- LLabel_Add(s, &s->lblLine1, "Some required resources weren't found", cres_lblLine1);
+ LLabel_Add(s, &s->lblLine1, line1_msg, cres_lblLine1);
LLabel_Add(s, &s->lblLine2, "Okay to download?", cres_lblLine2);
LLabel_Add(s, &s->lblStatus, "", cres_lblStatus);
@@ -1030,7 +1032,7 @@ static void CheckResourcesScreen_Activated(struct LScreen* s_) {
float size;
CheckResourcesScreen_AddWidgets(s);
- size = Resources_Size / 1024.0f;
+ size = Resources_MissingSize / 1024.0f;
String_InitArray(str, buffer);
String_Format1(&str, "&eDownload size: %f2 megabytes", &size);
LLabel_SetText(&s->lblStatus, &str);
@@ -1121,7 +1123,7 @@ static void FetchResourcesScreen_UpdateStatus(struct FetchResourcesScreen* s, in
String_InitArray(str, strBuffer);
count = Fetcher_Downloaded + 1;
- String_Format3(&str, "&eFetching %c.. (%i/%i)", name, &count, &Resources_Count);
+ String_Format3(&str, "&eFetching %c.. (%i/%i)", name, &count, &Resources_MissingCount);
if (String_Equals(&str, &s->lblStatus.text)) return;
LLabel_SetText(&s->lblStatus, &str);
@@ -1600,9 +1602,9 @@ static void UpdatesScreen_Format(struct LLabel* lbl, const char* prefix, cc_uint
if (!timestamp) {
String_AppendConst(&str, "&cCheck failed");
} else {
- now = DateTime_CurrentUTC_MS() - UNIX_EPOCH;
+ now = DateTime_CurrentUTC() - UNIX_EPOCH_SECONDS;
/* must divide as cc_uint64, int delta overflows after 26 days */
- delta = (int)((now / 1000) - timestamp);
+ delta = (int)(now - timestamp);
UpdatesScreen_FormatTime(&str, delta);
}
LLabel_SetText(lbl, &str);
diff --git a/src/Launcher.c b/src/Launcher.c
index 390ead03b..18c939cbc 100644
--- a/src/Launcher.c
+++ b/src/Launcher.c
@@ -260,7 +260,7 @@ void Launcher_Run(void) {
#ifdef CC_BUILD_RESOURCES
Resources_CheckExistence();
- if (Resources_Count) {
+ if (Resources_MissingCount) {
CheckResourcesScreen_SetActive();
} else {
MainScreen_SetActive();
diff --git a/src/Logger.c b/src/Logger.c
index 2957adfb1..06795c5d3 100644
--- a/src/Logger.c
+++ b/src/Logger.c
@@ -8,17 +8,17 @@
#include "Utils.h"
#if defined CC_BUILD_WEB
-/* Can't see native CPU state with javascript */
+ /* Can't see native CPU state with javascript */
#elif defined CC_BUILD_WIN
-#define WIN32_LEAN_AND_MEAN
-#define NOSERVICE
-#define NOMCX
-#define NOIME
-#define CUR_PROCESS_HANDLE ((HANDLE)-1) /* GetCurrentProcess() always returns -1 */
-
-#include
-#include
-static HANDLE curProcess = CUR_PROCESS_HANDLE;
+ #define WIN32_LEAN_AND_MEAN
+ #define NOSERVICE
+ #define NOMCX
+ #define NOIME
+ #define CUR_PROCESS_HANDLE ((HANDLE)-1) /* GetCurrentProcess() always returns -1 */
+
+ #include
+ #include
+ static HANDLE curProcess = CUR_PROCESS_HANDLE;
#elif defined CC_BUILD_OPENBSD || defined CC_BUILD_HAIKU || defined CC_BUILD_SERENITY
#include
/* These operating systems don't provide sys/ucontext.h */
@@ -26,20 +26,21 @@ static HANDLE curProcess = CUR_PROCESS_HANDLE;
#elif defined CC_BUILD_OS2
#include
#include <386/ucontext.h>
+
#elif defined CC_BUILD_LINUX || defined CC_BUILD_ANDROID
-/* Need to define this to get REG_ constants */
-#define _GNU_SOURCE
-#include
-#include
+ /* Need to define this to get REG_ constants */
+ #define _GNU_SOURCE
+ #include
+ #include
#elif defined CC_BUILD_POSIX
-#include
-#include
+ #include
+ #include
#endif
+
#ifdef CC_BUILD_DARWIN
/* Need this to detect macOS < 10.4, and switch to NS* api instead if so */
#include
#endif
-
/* Only show up to 50 frames in backtrace */
#define MAX_BACKTRACE_FRAMES 50
diff --git a/src/Menus.c b/src/Menus.c
index 4ace2f29f..d6a247be5 100644
--- a/src/Menus.c
+++ b/src/Menus.c
@@ -2728,9 +2728,9 @@ static void ClassicOptionsScreen_SetViewDist(const cc_string* v) {
Game_UserSetViewDistance(dist);
}
-static void ClassicOptionsScreen_GetPhysics(cc_string* v) { Menu_GetBool(v, Physics.Enabled); }
-static void ClassicOptionsScreen_SetPhysics(const cc_string* v) {
- Physics_SetEnabled(Menu_SetBool(v, OPT_BLOCK_PHYSICS));
+static void ClassicOptionsScreen_GetAnaglyph(cc_string* v) { Menu_GetBool(v, Game_Anaglyph3D); }
+static void ClassicOptionsScreen_SetAnaglyph(const cc_string* v) {
+ Game_Anaglyph3D = Menu_SetBool(v, OPT_ANAGLYPH3D);
}
static void ClassicOptionsScreen_GetSounds(cc_string* v) { Menu_GetBool(v, Audio_SoundsVolume > 0); }
@@ -2763,8 +2763,8 @@ static void ClassicOptionsScreen_InitWidgets(struct MenuOptionsScreen* s) {
ClassicOptionsScreen_GetInvert, ClassicOptionsScreen_SetInvert },
{ -1, -50, "Render distance", MenuOptionsScreen_Enum,
ClassicOptionsScreen_GetViewDist, ClassicOptionsScreen_SetViewDist },
- { -1, 0, "Block physics", MenuOptionsScreen_Bool,
- ClassicOptionsScreen_GetPhysics, ClassicOptionsScreen_SetPhysics },
+ { -1, 0, "3D anaglyph", MenuOptionsScreen_Bool,
+ ClassicOptionsScreen_GetAnaglyph, ClassicOptionsScreen_SetAnaglyph },
{ 1, -150, "Sound", MenuOptionsScreen_Bool,
ClassicOptionsScreen_GetSounds, ClassicOptionsScreen_SetSounds },
diff --git a/src/Model.c b/src/Model.c
index 1d0dd2678..aa24c21ba 100644
--- a/src/Model.c
+++ b/src/Model.c
@@ -98,7 +98,8 @@ void Model_Render(struct Model* model, struct Entity* e) {
Vec3 pos = e->Position;
if (model->bobbing) pos.y += e->Anim.BobbingModel;
/* Original classic offsets models slightly into ground */
- if (Game_ClassicMode) pos.y -= 1.5f / 16.0f;
+ if (Game_ClassicMode && (e->Flags & ENTITY_FLAG_CLASSIC_ADJUST))
+ pos.y -= 1.5f / 16.0f;
Model_SetupState(model, e);
Gfx_SetVertexFormat(VERTEX_FORMAT_TEXTURED);
diff --git a/src/Options.h b/src/Options.h
index b4d1716c2..62672a86f 100644
--- a/src/Options.h
+++ b/src/Options.h
@@ -79,6 +79,7 @@ Copyright 2014-2023 ClassiCube | Licensed under BSD-3
#define OPT_DPI_SCALING "win-dpi-scaling"
#define OPT_GAME_VERSION "game-version"
#define OPT_INV_SCROLLBAR_SCALE "inv-scrollbar-scale"
+#define OPT_ANAGLYPH3D "anaglyph-3d"
#define OPT_SELECTED_BLOCK_OUTLINE_COLOR "selected-block-outline-color"
#define OPT_SELECTED_BLOCK_OUTLINE_OPACITY "selected-block-outline-opacity"
diff --git a/src/Particle.c b/src/Particle.c
index 4c3e3b81c..3228758d3 100644
--- a/src/Particle.c
+++ b/src/Particle.c
@@ -187,6 +187,30 @@ static void Rain_Tick(double delta) {
}
}
+void Particles_RainSnowEffect(float x, float y, float z) {
+ struct Particle* p;
+ int i, type;
+
+ for (i = 0; i < 2; i++) {
+ if (rain_count == PARTICLES_MAX) Rain_RemoveAt(0);
+ p = &rain_Particles[rain_count++];
+
+ p->velocity.x = Random_Float(&rnd) * 0.8f - 0.4f; /* [-0.4, 0.4] */
+ p->velocity.z = Random_Float(&rnd) * 0.8f - 0.4f;
+ p->velocity.y = Random_Float(&rnd) + 0.4f;
+
+ p->lastPos.x = x + Random_Float(&rnd); /* [0.0, 1.0] */
+ p->lastPos.y = y + Random_Float(&rnd) * 0.1f + 0.01f;
+ p->lastPos.z = z + Random_Float(&rnd);
+
+ p->nextPos = p->lastPos;
+ p->lifetime = 40.0f;
+
+ type = Random_Next(&rnd, 30);
+ p->size = type >= 28 ? 2 : (type >= 25 ? 4 : 3);
+ }
+}
+
/*########################################################################################################################*
*------------------------------------------------------Terrain particle---------------------------------------------------*
@@ -291,9 +315,92 @@ static void Terrain_Tick(double delta) {
}
}
+void Particles_BreakBlockEffect(IVec3 coords, BlockID old, BlockID now) {
+ struct TerrainParticle* p;
+ TextureLoc loc;
+ int texIndex;
+ TextureRec baseRec, rec;
+ Vec3 origin, minBB, maxBB;
+
+ /* texture UV variables */
+ float uScale, vScale, maxU2, maxV2;
+ int minX, minZ, maxX, maxZ;
+ int minU, minV, maxU, maxV;
+ int maxUsedU, maxUsedV;
+
+ /* per-particle variables */
+ float cellX, cellY, cellZ;
+ Vec3 cell;
+ int x, y, z, type;
+
+ if (now != BLOCK_AIR || Blocks.Draw[old] == DRAW_GAS) return;
+ IVec3_ToVec3(&origin, &coords);
+ loc = Block_Tex(old, FACE_XMIN);
+
+ baseRec = Atlas1D_TexRec(loc, 1, &texIndex);
+ uScale = (1.0f/16.0f); vScale = (1.0f/16.0f) * Atlas1D.InvTileSize;
+
+ minBB = Blocks.MinBB[old]; maxBB = Blocks.MaxBB[old];
+ minX = (int)(minBB.x * 16); maxX = (int)(maxBB.x * 16);
+ minZ = (int)(minBB.z * 16); maxZ = (int)(maxBB.z * 16);
+
+ minU = min(minX, minZ); minV = (int)(16 - maxBB.y * 16);
+ maxU = min(maxX, maxZ); maxV = (int)(16 - minBB.y * 16);
+ /* This way we can avoid creating particles which outside the bounds and need to be clamped */
+ maxUsedU = maxU; maxUsedV = maxV;
+ if (minU < 12 && maxU > 12) maxUsedU = 12;
+ if (minV < 12 && maxV > 12) maxUsedV = 12;
+
+ #define GRID_SIZE 4
+ /* gridOffset gives the centre of the cell on a grid */
+ #define CELL_CENTRE ((1.0f / GRID_SIZE) * 0.5f)
+
+ maxU2 = baseRec.U1 + maxU * uScale;
+ maxV2 = baseRec.V1 + maxV * vScale;
+ for (x = 0; x < GRID_SIZE; x++) {
+ for (y = 0; y < GRID_SIZE; y++) {
+ for (z = 0; z < GRID_SIZE; z++) {
+
+ cellX = (float)x / GRID_SIZE; cellY = (float)y / GRID_SIZE; cellZ = (float)z / GRID_SIZE;
+ cell = Vec3_Create3(CELL_CENTRE + cellX, CELL_CENTRE / 2 + cellY, CELL_CENTRE + cellZ);
+ if (cell.x < minBB.x || cell.x > maxBB.x || cell.y < minBB.y
+ || cell.y > maxBB.y || cell.z < minBB.z || cell.z > maxBB.z) continue;
+
+ if (terrain_count == PARTICLES_MAX) Terrain_RemoveAt(0);
+ p = &terrain_particles[terrain_count++];
+
+ /* centre random offset around [-0.2, 0.2] */
+ p->base.velocity.x = CELL_CENTRE + (cellX - 0.5f) + (Random_Float(&rnd) * 0.4f - 0.2f);
+ p->base.velocity.y = CELL_CENTRE + (cellY - 0.0f) + (Random_Float(&rnd) * 0.4f - 0.2f);
+ p->base.velocity.z = CELL_CENTRE + (cellZ - 0.5f) + (Random_Float(&rnd) * 0.4f - 0.2f);
+
+ rec = baseRec;
+ rec.U1 = baseRec.U1 + Random_Range(&rnd, minU, maxUsedU) * uScale;
+ rec.V1 = baseRec.V1 + Random_Range(&rnd, minV, maxUsedV) * vScale;
+ rec.U2 = rec.U1 + 4 * uScale;
+ rec.V2 = rec.V1 + 4 * vScale;
+ rec.U2 = min(rec.U2, maxU2) - 0.01f * uScale;
+ rec.V2 = min(rec.V2, maxV2) - 0.01f * vScale;
+
+ Vec3_Add(&p->base.lastPos, &origin, &cell);
+ p->base.nextPos = p->base.lastPos;
+ p->base.lifetime = 0.3f + Random_Float(&rnd) * 1.2f;
+
+ p->rec = rec;
+ p->texLoc = loc;
+ p->block = old;
+ type = Random_Next(&rnd, 30);
+ p->base.size = type >= 28 ? 12 : (type >= 25 ? 10 : 8);
+ }
+ }
+ }
+}
+
+
/*########################################################################################################################*
*-------------------------------------------------------Custom particle---------------------------------------------------*
*#########################################################################################################################*/
+#ifdef CC_BUILD_NETWORKING
struct CustomParticle {
struct Particle base;
int effectId;
@@ -388,139 +495,6 @@ static void Custom_Tick(double delta) {
}
}
-
-/*########################################################################################################################*
-*--------------------------------------------------------Particles--------------------------------------------------------*
-*#########################################################################################################################*/
-void Particles_Render(float t) {
- if (!terrain_count && !rain_count && !custom_count) return;
-
- if (Gfx.LostContext) return;
- if (!particles_VB)
- particles_VB = Gfx_CreateDynamicVb(VERTEX_FORMAT_TEXTURED, PARTICLES_MAX * 4);
-
- Gfx_SetAlphaTest(true);
-
- Gfx_SetVertexFormat(VERTEX_FORMAT_TEXTURED);
- Terrain_Render(t);
- Rain_Render(t);
- Custom_Render(t);
-
- Gfx_SetAlphaTest(false);
-}
-
-static void Particles_Tick(struct ScheduledTask* task) {
- double delta = task->interval;
- Terrain_Tick(delta);
- Rain_Tick(delta);
- Custom_Tick(delta);
-}
-
-void Particles_BreakBlockEffect(IVec3 coords, BlockID old, BlockID now) {
- struct TerrainParticle* p;
- TextureLoc loc;
- int texIndex;
- TextureRec baseRec, rec;
- Vec3 origin, minBB, maxBB;
-
- /* texture UV variables */
- float uScale, vScale, maxU2, maxV2;
- int minX, minZ, maxX, maxZ;
- int minU, minV, maxU, maxV;
- int maxUsedU, maxUsedV;
-
- /* per-particle variables */
- float cellX, cellY, cellZ;
- Vec3 cell;
- int x, y, z, type;
-
- if (now != BLOCK_AIR || Blocks.Draw[old] == DRAW_GAS) return;
- IVec3_ToVec3(&origin, &coords);
- loc = Block_Tex(old, FACE_XMIN);
-
- baseRec = Atlas1D_TexRec(loc, 1, &texIndex);
- uScale = (1.0f/16.0f); vScale = (1.0f/16.0f) * Atlas1D.InvTileSize;
-
- minBB = Blocks.MinBB[old]; maxBB = Blocks.MaxBB[old];
- minX = (int)(minBB.x * 16); maxX = (int)(maxBB.x * 16);
- minZ = (int)(minBB.z * 16); maxZ = (int)(maxBB.z * 16);
-
- minU = min(minX, minZ); minV = (int)(16 - maxBB.y * 16);
- maxU = min(maxX, maxZ); maxV = (int)(16 - minBB.y * 16);
- /* This way we can avoid creating particles which outside the bounds and need to be clamped */
- maxUsedU = maxU; maxUsedV = maxV;
- if (minU < 12 && maxU > 12) maxUsedU = 12;
- if (minV < 12 && maxV > 12) maxUsedV = 12;
-
- #define GRID_SIZE 4
- /* gridOffset gives the centre of the cell on a grid */
- #define CELL_CENTRE ((1.0f / GRID_SIZE) * 0.5f)
-
- maxU2 = baseRec.U1 + maxU * uScale;
- maxV2 = baseRec.V1 + maxV * vScale;
- for (x = 0; x < GRID_SIZE; x++) {
- for (y = 0; y < GRID_SIZE; y++) {
- for (z = 0; z < GRID_SIZE; z++) {
-
- cellX = (float)x / GRID_SIZE; cellY = (float)y / GRID_SIZE; cellZ = (float)z / GRID_SIZE;
- cell = Vec3_Create3(CELL_CENTRE + cellX, CELL_CENTRE / 2 + cellY, CELL_CENTRE + cellZ);
- if (cell.x < minBB.x || cell.x > maxBB.x || cell.y < minBB.y
- || cell.y > maxBB.y || cell.z < minBB.z || cell.z > maxBB.z) continue;
-
- if (terrain_count == PARTICLES_MAX) Terrain_RemoveAt(0);
- p = &terrain_particles[terrain_count++];
-
- /* centre random offset around [-0.2, 0.2] */
- p->base.velocity.x = CELL_CENTRE + (cellX - 0.5f) + (Random_Float(&rnd) * 0.4f - 0.2f);
- p->base.velocity.y = CELL_CENTRE + (cellY - 0.0f) + (Random_Float(&rnd) * 0.4f - 0.2f);
- p->base.velocity.z = CELL_CENTRE + (cellZ - 0.5f) + (Random_Float(&rnd) * 0.4f - 0.2f);
-
- rec = baseRec;
- rec.U1 = baseRec.U1 + Random_Range(&rnd, minU, maxUsedU) * uScale;
- rec.V1 = baseRec.V1 + Random_Range(&rnd, minV, maxUsedV) * vScale;
- rec.U2 = rec.U1 + 4 * uScale;
- rec.V2 = rec.V1 + 4 * vScale;
- rec.U2 = min(rec.U2, maxU2) - 0.01f * uScale;
- rec.V2 = min(rec.V2, maxV2) - 0.01f * vScale;
-
- Vec3_Add(&p->base.lastPos, &origin, &cell);
- p->base.nextPos = p->base.lastPos;
- p->base.lifetime = 0.3f + Random_Float(&rnd) * 1.2f;
-
- p->rec = rec;
- p->texLoc = loc;
- p->block = old;
- type = Random_Next(&rnd, 30);
- p->base.size = type >= 28 ? 12 : (type >= 25 ? 10 : 8);
- }
- }
- }
-}
-
-void Particles_RainSnowEffect(float x, float y, float z) {
- struct Particle* p;
- int i, type;
-
- for (i = 0; i < 2; i++) {
- if (rain_count == PARTICLES_MAX) Rain_RemoveAt(0);
- p = &rain_Particles[rain_count++];
-
- p->velocity.x = Random_Float(&rnd) * 0.8f - 0.4f; /* [-0.4, 0.4] */
- p->velocity.z = Random_Float(&rnd) * 0.8f - 0.4f;
- p->velocity.y = Random_Float(&rnd) + 0.4f;
-
- p->lastPos.x = x + Random_Float(&rnd); /* [0.0, 1.0] */
- p->lastPos.y = y + Random_Float(&rnd) * 0.1f + 0.01f;
- p->lastPos.z = z + Random_Float(&rnd);
-
- p->nextPos = p->lastPos;
- p->lifetime = 40.0f;
-
- type = Random_Next(&rnd, 30);
- p->size = type >= 28 ? 2 : (type >= 25 ? 4 : 3);
- }
-}
-
void Particles_CustomEffect(int effectID, float x, float y, float z, float originX, float originY, float originZ) {
struct CustomParticle* p;
struct CustomParticleEffect* e = &Particles_CustomEffects[effectID];
@@ -568,6 +542,40 @@ void Particles_CustomEffect(int effectID, float x, float y, float z, float origi
if (IntersectsBlock(&p->base, CustomParticle_CanPass)) custom_count--;
}
}
+#else
+static int custom_count;
+
+static void Custom_Render(float t) { }
+static void Custom_Tick(double delta) { }
+#endif
+
+
+/*########################################################################################################################*
+*--------------------------------------------------------Particles--------------------------------------------------------*
+*#########################################################################################################################*/
+void Particles_Render(float t) {
+ if (!terrain_count && !rain_count && !custom_count) return;
+
+ if (Gfx.LostContext) return;
+ if (!particles_VB)
+ particles_VB = Gfx_CreateDynamicVb(VERTEX_FORMAT_TEXTURED, PARTICLES_MAX * 4);
+
+ Gfx_SetAlphaTest(true);
+
+ Gfx_SetVertexFormat(VERTEX_FORMAT_TEXTURED);
+ Terrain_Render(t);
+ Rain_Render(t);
+ Custom_Render(t);
+
+ Gfx_SetAlphaTest(false);
+}
+
+static void Particles_Tick(struct ScheduledTask* task) {
+ double delta = task->interval;
+ Terrain_Tick(delta);
+ Rain_Tick(delta);
+ Custom_Tick(delta);
+}
/*########################################################################################################################*
diff --git a/src/Platform.h b/src/Platform.h
index 8049a4c5d..7c78eb0d6 100644
--- a/src/Platform.h
+++ b/src/Platform.h
@@ -24,8 +24,8 @@ typedef int cc_file;
/* Origin points for when seeking in a file. */
/* NOTE: These have same values as SEEK_SET/SEEK_CUR/SEEK_END, do not change them */
enum File_SeekFrom { FILE_SEEKFROM_BEGIN, FILE_SEEKFROM_CURRENT, FILE_SEEKFROM_END };
-/* Number of milliseconds since 01/01/0001 to start of unix time. */
-#define UNIX_EPOCH 62135596800000ULL
+/* Number of seconds since 01/01/0001 to start of unix time. */
+#define UNIX_EPOCH_SECONDS 62135596800ULL
extern const cc_result ReturnCode_FileShareViolation;
extern const cc_result ReturnCode_FileNotFound;
@@ -166,8 +166,8 @@ void Platform_Log2(const char* format, const void* a1, const void* a2);
void Platform_Log3(const char* format, const void* a1, const void* a2, const void* a3);
void Platform_Log4(const char* format, const void* a1, const void* a2, const void* a3, const void* a4);
-/* Returns the current UTC time, as number of milliseconds since 1/1/0001 */
-CC_API TimeMS DateTime_CurrentUTC_MS(void);
+/* Returns the current UTC time, as number of seconds since 1/1/0001 */
+CC_API TimeMS DateTime_CurrentUTC(void);
/* Returns the current local Time. */
CC_API void DateTime_CurrentLocal(struct DateTime* t);
/* Takes a platform-specific stopwatch measurement. */
diff --git a/src/Platform_3DS.c b/src/Platform_3DS.c
index 89fd1291d..0c40cd584 100644
--- a/src/Platform_3DS.c
+++ b/src/Platform_3DS.c
@@ -62,11 +62,10 @@ void Platform_Log(const char* msg, int len) {
svcOutputDebugString("\n", 1);
}
-#define UnixTime_TotalMS(time) ((cc_uint64)time.tv_sec * 1000 + UNIX_EPOCH + (time.tv_usec / 1000))
-TimeMS DateTime_CurrentUTC_MS(void) {
+TimeMS DateTime_CurrentUTC(void) {
struct timeval cur;
gettimeofday(&cur, NULL);
- return UnixTime_TotalMS(cur);
+ return (cc_uint64)cur.tv_sec + UNIX_EPOCH_SECONDS;
}
void DateTime_CurrentLocal(struct DateTime* t) {
diff --git a/src/Platform_Dreamcast.c b/src/Platform_Dreamcast.c
index f2ecccad7..095d06bdd 100644
--- a/src/Platform_Dreamcast.c
+++ b/src/Platform_Dreamcast.c
@@ -75,7 +75,7 @@ void Platform_Log(const char* msg, int len) {
LogOnscreen(msg, len);
}
-TimeMS DateTime_CurrentUTC_MS(void) {
+TimeMS DateTime_CurrentUTC(void) {
uint32 secs, ms;
timer_ms_gettime(&secs, &ms);
@@ -86,7 +86,7 @@ TimeMS DateTime_CurrentUTC_MS(void) {
if (boot_time < boot_time_2000) boot_time = boot_time_2024;
cc_uint64 curSecs = boot_time + secs;
- return (curSecs * 1000 + ms) + UNIX_EPOCH;
+ return curSecs + UNIX_EPOCH_SECONDS;
}
void DateTime_CurrentLocal(struct DateTime* t) {
diff --git a/src/Platform_GCWii.c b/src/Platform_GCWii.c
index 97acf81df..33519a7e8 100644
--- a/src/Platform_GCWii.c
+++ b/src/Platform_GCWii.c
@@ -22,6 +22,7 @@
#include
#include
#include
+#include
#ifdef HW_RVL
#include
#endif
@@ -42,30 +43,43 @@ const char* Platform_AppNameSuffix = " GameCube";
/*########################################################################################################################*
*------------------------------------------------------Logging/Time-------------------------------------------------------*
*#########################################################################################################################*/
-// dolphin recognises this function name (if loaded as .elf), and will patch it
-// to also log the message to dolphin's console at OSREPORT-HLE log level
-void CC_NOINLINE __write_console(int fd, const char* msg, const u32* size) {
- write(STDOUT_FILENO, msg, *size); // this can be intercepted by libogc debug console
+// To see these log messages:
+// 1) In the UI, make sure 'Show log configuration' checkbox is checked in View menu
+// 2) Make sure "OSReport EXI (OSREPORT)" log type is enabled
+// 3) In the UI, make sure 'Show log' checkbox is checked in View menu
+static void LogOverEXI(char* msg, int len) {
+ u32 cmd = 0x80000000 | (0x800400 << 6); // write flag, UART base address
+
+ // https://hitmen.c02.at/files/yagcd/yagcd/chap10.html
+ // Try to acquire "MASK ROM"/"IPL" link
+ // Writing to the IPL is used for debug message logging
+ if (EXI_Lock(EXI_CHANNEL_0, EXI_DEVICE_1, NULL) == 0) return;
+ if (EXI_Select(EXI_CHANNEL_0, EXI_DEVICE_1, EXI_SPEED8MHZ) == 0) {
+ EXI_Unlock(EXI_CHANNEL_0); return;
+ }
+
+ EXI_Imm( EXI_CHANNEL_0, &cmd, 4, EXI_WRITE, NULL);
+ EXI_Sync( EXI_CHANNEL_0);
+ EXI_ImmEx( EXI_CHANNEL_0, msg, len, EXI_WRITE);
+ EXI_Deselect(EXI_CHANNEL_0);
+ EXI_Unlock( EXI_CHANNEL_0);
}
+
void Platform_Log(const char* msg, int len) {
- char buffer[256];
- cc_string str = String_Init(buffer, 0, 254); // 2 characters (\n and \0)
- u32 size;
-
- String_AppendAll(&str, msg, len);
- buffer[str.length + 0] = '\n';
- buffer[str.length + 1] = '\0'; // needed to make Dolphin logger happy
-
- size = str.length + 1; // +1 for '\n'
- __write_console(0, buffer, &size);
- // TODO: Just use printf("%s", somehow ???
+ char tmp[256 + 1];
+ len = min(len, 256);
+ // See EXI_DeviceIPL.cpp in Dolphin, \r is what triggers buffered message to be logged
+ Mem_Copy(tmp, msg, len); tmp[len] = '\r';
+
+ LogOverEXI(tmp, len + 1);
}
-#define UnixTime_TotalMS(time) ((cc_uint64)time.tv_sec * 1000 + UNIX_EPOCH + (time.tv_usec / 1000))
-TimeMS DateTime_CurrentUTC_MS(void) {
- struct timeval cur;
- gettimeofday(&cur, NULL);
- return UnixTime_TotalMS(cur);
+#define GCWII_EPOCH_ADJUST 946684800ULL // GameCube/Wii time epoch is year 2000, not 1970
+
+TimeMS DateTime_CurrentUTC(void) {
+ u64 raw = gettime();
+ u64 secs = ticks_to_secs(raw);
+ return secs + UNIX_EPOCH_SECONDS + GCWII_EPOCH_ADJUST;
}
void DateTime_CurrentLocal(struct DateTime* t) {
@@ -594,4 +608,4 @@ static cc_result GetMachineID(cc_uint32* key) {
}
#endif
-#endif
\ No newline at end of file
+#endif
diff --git a/src/Platform_N64.c b/src/Platform_N64.c
index 7b7428caa..1419f94c1 100644
--- a/src/Platform_N64.c
+++ b/src/Platform_N64.c
@@ -48,11 +48,8 @@ void Platform_Log(const char* msg, int len) {
write(STDERR_FILENO, "\n", 1);
}
-#define UnixTime_TotalMS(time) ((cc_uint64)time.tv_sec * 1000 + UNIX_EPOCH + (time.tv_usec / 1000))
-TimeMS DateTime_CurrentUTC_MS(void) {
- struct timeval cur;
- gettimeofday(&cur, NULL);
- return UnixTime_TotalMS(cur);
+TimeMS DateTime_CurrentUTC(void) {
+ return 0;
}
void DateTime_CurrentLocal(struct DateTime* t) {
@@ -177,10 +174,6 @@ void Thread_Run(void** handle, Thread_StartFunc func, int stackSize, const char*
*handle = NULL;
}
-void Thread_Start2(void* handle, Thread_StartFunc func) {
- // TODO: actual multithreading ???
-}
-
void Thread_Detach(void* handle) {
}
@@ -270,10 +263,6 @@ void Platform_Init(void) {
// TODO: Redesign Drawer2D to better handle this
Options_SetBool(OPT_USE_CHAT_FONT, true);
- //console_init();
- //console_set_render_mode(RENDER_AUTOMATIC);
- //console_set_debug(true);
-
dfs_init(DFS_DEFAULT_LOCATION);
timer_init();
rtc_init();
diff --git a/src/Platform_NDS.c b/src/Platform_NDS.c
index 14f0d2b90..e1dc5e382 100644
--- a/src/Platform_NDS.c
+++ b/src/Platform_NDS.c
@@ -84,11 +84,10 @@ void Platform_Log(const char* msg, int len) {
LogNocash(msg, len);
}
-#define UnixTime_TotalMS(time) ((cc_uint64)time.tv_sec * 1000 + UNIX_EPOCH)
-TimeMS DateTime_CurrentUTC_MS(void) {
+TimeMS DateTime_CurrentUTC(void) {
struct timeval cur;
gettimeofday(&cur, NULL);
- return UnixTime_TotalMS(cur); // no usec on the DS
+ return (cc_uint64)cur.tv_sec + UNIX_EPOCH_SECONDS;
}
void DateTime_CurrentLocal(struct DateTime* t) {
diff --git a/src/Platform_PS1.c b/src/Platform_PS1.c
index e654127c9..4708a1534 100644
--- a/src/Platform_PS1.c
+++ b/src/Platform_PS1.c
@@ -8,6 +8,7 @@
#include "Window.h"
#include "Utils.h"
#include "Errors.h"
+#include "Options.h"
#include "PackedCol.h"
#include
#include
@@ -16,7 +17,7 @@
#include
#include
#include
-void exit(int code) { } // TODO how to fix
+void exit(int code) { _boot(); }
#include "_PlatformConsole.h"
const cc_result ReturnCode_FileShareViolation = 1000000000; // not used
@@ -39,8 +40,7 @@ void Platform_Log(const char* msg, int len) {
printf("%s\n", tmp);
}
-#define UnixTime_TotalMS(time) ((cc_uint64)time.tv_sec * 1000 + UNIX_EPOCH + (time.tv_usec / 1000))
-TimeMS DateTime_CurrentUTC_MS(void) {
+TimeMS DateTime_CurrentUTC(void) {
return 0;
}
@@ -78,12 +78,20 @@ static void Stopwatch_Init(void) {
/*########################################################################################################################*
*-----------------------------------------------------Directory/File------------------------------------------------------*
*#########################################################################################################################*/
+static const cc_string root_path = String_FromConst("cdrom:/");
+
+static void GetNativePath(char* str, const cc_string* path) {
+ Mem_Copy(str, root_path.buffer, root_path.length);
+ str += root_path.length;
+ String_EncodeUtf8(str, path);
+}
+
cc_result Directory_Create(const cc_string* path) {
return ERR_NOT_SUPPORTED;
}
int File_Exists(const cc_string* path) {
- return 0;
+ return ERR_NOT_SUPPORTED;
}
cc_result Directory_Enum(const cc_string* dirPath, void* obj, Directory_EnumCallback callback) {
@@ -93,9 +101,11 @@ cc_result Directory_Enum(const cc_string* dirPath, void* obj, Directory_EnumCall
cc_result File_Open(cc_file* file, const cc_string* path) {
return ERR_NOT_SUPPORTED;
}
+
cc_result File_Create(cc_file* file, const cc_string* path) {
return ERR_NOT_SUPPORTED;
}
+
cc_result File_OpenOrCreate(cc_file* file, const cc_string* path) {
return ERR_NOT_SUPPORTED;
}
@@ -109,10 +119,10 @@ cc_result File_Write(cc_file file, const void* data, cc_uint32 count, cc_uint32*
}
cc_result File_Close(cc_file file) {
- return 0;
+ return ERR_NOT_SUPPORTED;
}
-cc_result File_Seek(cc_file file, int offset, int seekType) {
+cc_result File_Seek(cc_file file, int offset, int seekType) {
return ERR_NOT_SUPPORTED;
}
@@ -208,8 +218,10 @@ cc_result Socket_CheckWritable(cc_socket s, cc_bool* writable) {
*--------------------------------------------------------Platform---------------------------------------------------------*
*#########################################################################################################################*/
void Platform_Init(void) {
- ResetGraph( 0 );
+ ResetGraph(0);
Stopwatch_Init();
+
+ Options_SetBool(OPT_USE_CHAT_FONT, true);
}
void Platform_Free(void) { }
diff --git a/src/Platform_PS2.c b/src/Platform_PS2.c
index ada09b7c4..5be4c5480 100644
--- a/src/Platform_PS2.c
+++ b/src/Platform_PS2.c
@@ -56,11 +56,10 @@ void Platform_Log(const char* msg, int len) {
_print("%s", tmp);
}
-#define UnixTime_TotalMS(time) ((cc_uint64)time.tv_sec * 1000 + UNIX_EPOCH + (time.tv_usec / 1000))
-TimeMS DateTime_CurrentUTC_MS(void) {
+TimeMS DateTime_CurrentUTC(void) {
struct timeval cur;
gettimeofday(&cur, NULL);
- return UnixTime_TotalMS(cur);
+ return (cc_uint64)cur.tv_sec + UNIX_EPOCH_SECONDS;
}
void DateTime_CurrentLocal(struct DateTime* t) {
diff --git a/src/Platform_PS3.c b/src/Platform_PS3.c
index a70279d0c..b24744bd0 100644
--- a/src/Platform_PS3.c
+++ b/src/Platform_PS3.c
@@ -52,11 +52,10 @@ void Platform_Log(const char* msg, int len) {
sysTtyWrite(STDOUT_FILENO, "\n", 1, &done);
}
-#define UnixTime_TotalMS(time) ((cc_uint64)time.tv_sec * 1000 + UNIX_EPOCH + (time.tv_usec / 1000))
-TimeMS DateTime_CurrentUTC_MS(void) {
+TimeMS DateTime_CurrentUTC(void) {
struct timeval cur;
gettimeofday(&cur, NULL);
- return UnixTime_TotalMS(cur);
+ return (cc_uint64)cur.tv_sec + UNIX_EPOCH_SECONDS;
}
void DateTime_CurrentLocal(struct DateTime* t) {
@@ -483,4 +482,4 @@ cc_bool Platform_DescribeError(cc_result res, cc_string* dst) {
static cc_result GetMachineID(cc_uint32* key) {
return ERR_NOT_SUPPORTED;
}
-#endif
\ No newline at end of file
+#endif
diff --git a/src/Platform_PSP.c b/src/Platform_PSP.c
index 3667b5dee..014edd575 100644
--- a/src/Platform_PSP.c
+++ b/src/Platform_PSP.c
@@ -54,11 +54,10 @@ void Platform_Log(const char* msg, int len) {
//File_Close(file);
}
-#define UnixTime_TotalMS(time) ((cc_uint64)time.tv_sec * 1000 + UNIX_EPOCH + (time.tv_usec / 1000))
-TimeMS DateTime_CurrentUTC_MS(void) {
+TimeMS DateTime_CurrentUTC(void) {
struct SceKernelTimeval cur;
sceKernelLibcGettimeofday(&cur, NULL);
- return UnixTime_TotalMS(cur);
+ return (cc_uint64)cur.tv_sec + UNIX_EPOCH_SECONDS;
}
void DateTime_CurrentLocal(struct DateTime* t) {
diff --git a/src/Platform_PSVita.c b/src/Platform_PSVita.c
index e5e47c232..e002e5945 100644
--- a/src/Platform_PSVita.c
+++ b/src/Platform_PSVita.c
@@ -37,11 +37,10 @@ void Platform_Log(const char* msg, int len) {
sceIoWrite(stdout_fd, msg, len);
}
-#define UnixTime_TotalMS(time) ((cc_uint64)time.sec * 1000 + UNIX_EPOCH + (time.usec / 1000))
-TimeMS DateTime_CurrentUTC_MS(void) {
+TimeMS DateTime_CurrentUTC(void) {
struct SceKernelTimeval cur;
sceKernelLibcGettimeofday(&cur, NULL);
- return UnixTime_TotalMS(cur);
+ return (cc_uint64)cur.sec + UNIX_EPOCH_SECONDS;
}
void DateTime_CurrentLocal(struct DateTime* t) {
diff --git a/src/Platform_Posix.c b/src/Platform_Posix.c
index 91d81d5e2..4959c00bc 100644
--- a/src/Platform_Posix.c
+++ b/src/Platform_Posix.c
@@ -107,11 +107,10 @@ void Platform_Log(const char* msg, int len) {
}
#endif
-#define UnixTime_TotalMS(time) ((cc_uint64)time.tv_sec * 1000 + UNIX_EPOCH + (time.tv_usec / 1000))
-TimeMS DateTime_CurrentUTC_MS(void) {
+TimeMS DateTime_CurrentUTC(void) {
struct timeval cur;
gettimeofday(&cur, NULL);
- return UnixTime_TotalMS(cur);
+ return (cc_uint64)cur.tv_sec + UNIX_EPOCH_SECONDS;
}
void DateTime_CurrentLocal(struct DateTime* t) {
diff --git a/src/Platform_Switch.c b/src/Platform_Switch.c
index 846b61b27..381831a86 100644
--- a/src/Platform_Switch.c
+++ b/src/Platform_Switch.c
@@ -23,13 +23,10 @@
#include
#include
#include
-#include
#include
#include
#include "_PlatformConsole.h"
-
-
const cc_result ReturnCode_FileShareViolation = 1000000000; // not used
const cc_result ReturnCode_FileNotFound = ENOENT;
const cc_result ReturnCode_SocketInProgess = EINPROGRESS;
@@ -37,7 +34,6 @@ const cc_result ReturnCode_SocketWouldBlock = EWOULDBLOCK;
const cc_result ReturnCode_DirectoryExists = EEXIST;
const char* Platform_AppNameSuffix = " Switch";
-
alignas(16) u8 __nx_exception_stack[0x1000];
u64 __nx_exception_stack_size = sizeof(__nx_exception_stack);
@@ -74,38 +70,37 @@ void __libnx_exception_handler(ThreadExceptionDump *ctx)
cc_uint64 Stopwatch_ElapsedMicroseconds(cc_uint64 beg, cc_uint64 end) {
if (end < beg) return 0;
- return (end - beg) / 1000;
+ // See include/switch/arm/counter.h
+ // static inline u64 armTicksToNs(u64 tick) { return (tick * 625) / 12; }
+ return ((end - beg) * 625) / 12000;
}
cc_uint64 Stopwatch_Measure(void) {
- struct timespec t;
- clock_gettime(CLOCK_MONOTONIC, &t);
- return (cc_uint64)t.tv_sec * 1e9 + t.tv_nsec;
+ return armGetSystemTick();
}
void Platform_Log(const char* msg, int len) {
svcOutputDebugString(msg, len);
}
-#define UnixTime_TotalMS(time) ((cc_uint64)time.tv_sec * 1000 + UNIX_EPOCH + (time.tv_usec / 1000))
-TimeMS DateTime_CurrentUTC_MS(void) {
- struct timeval cur;
- gettimeofday(&cur, NULL);
- return UnixTime_TotalMS(cur);
+TimeMS DateTime_CurrentUTC(void) {
+ u64 timestamp = 0;
+ timeGetCurrentTime(TimeType_Default, ×tamp);
+ return timestamp + UNIX_EPOCH_SECONDS;
}
void DateTime_CurrentLocal(struct DateTime* t) {
- struct timeval cur;
- struct tm loc_time;
- gettimeofday(&cur, NULL);
- localtime_r(&cur.tv_sec, &loc_time);
+ u64 timestamp = 0;
+ TimeCalendarTime calTime = { 0 };
+ timeGetCurrentTime(TimeType_Default, ×tamp);
+ timeToCalendarTimeWithMyRule(timestamp, &calTime, NULL);
- t->year = loc_time.tm_year + 1900;
- t->month = loc_time.tm_mon + 1;
- t->day = loc_time.tm_mday;
- t->hour = loc_time.tm_hour;
- t->minute = loc_time.tm_min;
- t->second = loc_time.tm_sec;
+ t->year = calTime.year;
+ t->month = calTime.month;
+ t->day = calTime.day;
+ t->hour = calTime.hour;
+ t->minute = calTime.minute;
+ t->second = calTime.second;
}
@@ -228,7 +223,7 @@ cc_result File_Length(cc_file file, cc_uint32* len) {
*--------------------------------------------------------Threading--------------------------------------------------------*
*#########################################################################################################################*/
void Thread_Sleep(cc_uint32 milliseconds) {
- cc_uint64 timeout_ns = milliseconds * (1000 * 1000); // to nanoseconds
+ cc_uint64 timeout_ns = (cc_uint64)milliseconds * (1000 * 1000); // to nanoseconds
svcSleepThread(timeout_ns);
}
@@ -244,7 +239,11 @@ void Thread_Run(void** handle, Thread_StartFunc func, int stackSize, const char*
threadStart(thread);
}
-void Thread_Detach(void* handle) { }
+void Thread_Detach(void* handle) {
+ // threadClose frees up resources, **including the stack of the thread**
+ // Which obviously completely breaks the thread - so instead just accept
+ // that there will be a small memory leak when non-joined threads exit
+}
void Thread_Join(void* handle) {
Thread* thread = (Thread*)handle;
@@ -316,7 +315,6 @@ void Waitable_Wait(void* handle) {
void Waitable_WaitFor(void* handle, cc_uint32 milliseconds) {
struct WaitData* ptr = (struct WaitData*)handle;
-
cc_uint64 timeout_ns = (cc_uint64)milliseconds * (1000 * 1000); // to nanoseconds
Mutex_Lock(&ptr->mutex);
@@ -360,10 +358,8 @@ void Waitable_WaitFor(void* handle, cc_uint32 milliseconds) {
union SocketAddress {
struct sockaddr raw;
struct sockaddr_in v4;
- #ifdef AF_INET6
struct sockaddr_in6 v6;
struct sockaddr_storage total;
- #endif
};
static cc_result ParseHost(const char* host, int port, cc_sockaddr* addrs, int* numValidAddrs) {
@@ -420,7 +416,6 @@ cc_result Socket_ParseAddress(const cc_string* address, int port, cc_sockaddr* a
return 0;
}
- #ifdef AF_INET6
if (inet_pton(AF_INET6, str, &addr->v6.sin6_addr) > 0) {
addr->v6.sin6_family = AF_INET6;
addr->v6.sin6_port = htons(port);
@@ -429,7 +424,6 @@ cc_result Socket_ParseAddress(const cc_string* address, int port, cc_sockaddr* a
*numValidAddrs = 1;
return 0;
}
- #endif
return ParseHost(str, port, addrs, numValidAddrs);
}
@@ -442,8 +436,7 @@ cc_result Socket_Connect(cc_socket* s, cc_sockaddr* addr, cc_bool nonblocking) {
if (*s == -1) return errno;
if (nonblocking) {
- int blocking_raw = -1; /* non-blocking mode */
- ioctl(*s, FIONBIO, &blocking_raw);
+ fcntl(*s, F_SETFL, O_NONBLOCK);
}
res = connect(*s, raw, addr->size);
diff --git a/src/Platform_Web.c b/src/Platform_Web.c
index f1b43bec2..2fd862701 100644
--- a/src/Platform_Web.c
+++ b/src/Platform_Web.c
@@ -84,11 +84,10 @@ void Platform_Log(const char* msg, int len) {
interop_Log(msg, len);
}
-#define UnixTime_TotalMS(time) ((cc_uint64)time.tv_sec * 1000 + UNIX_EPOCH + (time.tv_usec / 1000))
-TimeMS DateTime_CurrentUTC_MS(void) {
+TimeMS DateTime_CurrentUTC(void) {
struct timeval cur;
gettimeofday(&cur, NULL);
- return UnixTime_TotalMS(cur);
+ return (cc_uint64)cur.tv_sec + UNIX_EPOCH_SECONDS;
}
extern void interop_GetLocalTime(struct DateTime* t);
diff --git a/src/Platform_WiiU.c b/src/Platform_WiiU.c
index ba3069e48..384956904 100644
--- a/src/Platform_WiiU.c
+++ b/src/Platform_WiiU.c
@@ -58,15 +58,12 @@ void Platform_Log(const char* msg, int len) {
OSReport("%s\n", tmp);
}
-#define WIIU_EPOCH_ADJUST 946684800000ULL // Wii U time epoch is year 2000, not 1970
+#define WIIU_EPOCH_ADJUST 946684800ULL // Wii U time epoch is year 2000, not 1970
-TimeMS DateTime_CurrentUTC_MS(void) {
- OSTime time = OSGetTime();
- // avoid overflow in time calculation
+TimeMS DateTime_CurrentUTC(void) {
+ OSTime time = OSGetTime();
cc_int64 secs = (time_t)OSTicksToSeconds(time);
- time -= OSSecondsToTicks(secs);
- cc_uint64 msecs = OSTicksToMilliseconds(time);
- return (secs * 1000 + msecs) + UNIX_EPOCH + WIIU_EPOCH_ADJUST;
+ return secs + UNIX_EPOCH_SECONDS + WIIU_EPOCH_ADJUST;
}
void DateTime_CurrentLocal(struct DateTime* t) {
@@ -455,4 +452,4 @@ void Platform_Init(void) {
*-------------------------------------------------------Encryption--------------------------------------------------------*
*#########################################################################################################################*/
static cc_result GetMachineID(cc_uint32* key) { return ERR_NOT_SUPPORTED; }
-#endif
\ No newline at end of file
+#endif
diff --git a/src/Platform_Windows.c b/src/Platform_Windows.c
index 52d128dab..00aa6e3b6 100644
--- a/src/Platform_Windows.c
+++ b/src/Platform_Windows.c
@@ -96,18 +96,18 @@ void Platform_Log(const char* msg, int len) {
OutputDebugStringA("\n");
}
-#define FILETIME_EPOCH 50491123200000ULL
-#define FILETIME_UNIX_EPOCH 11644473600LL
-#define FileTime_TotalMS(time) ((time / 10000) + FILETIME_EPOCH)
-#define FileTime_UnixTime(time) ((time / 10000000) - FILETIME_UNIX_EPOCH)
-TimeMS DateTime_CurrentUTC_MS(void) {
+#define FILETIME_EPOCH 50491123200ULL
+#define FILETIME_UNIX_EPOCH 11644473600ULL
+#define FileTime_TotalSecs(time) ((time / 10000000) + FILETIME_EPOCH)
+#define FileTime_UnixTime(time) ((time / 10000000) - FILETIME_UNIX_EPOCH)
+TimeMS DateTime_CurrentUTC(void) {
FILETIME ft;
cc_uint64 raw;
GetSystemTimeAsFileTime(&ft);
/* in 100 nanosecond units, since Jan 1 1601 */
raw = ft.dwLowDateTime | ((cc_uint64)ft.dwHighDateTime << 32);
- return FileTime_TotalMS(raw);
+ return FileTime_TotalSecs(raw);
}
void DateTime_CurrentLocal(struct DateTime* t) {
diff --git a/src/Platform_Xbox.c b/src/Platform_Xbox.c
index f53fe1dd0..80f3f1422 100644
--- a/src/Platform_Xbox.c
+++ b/src/Platform_Xbox.c
@@ -39,16 +39,16 @@ void Platform_Log(const char* msg, int len) {
OutputDebugStringA(tmp);
}
-#define FILETIME_EPOCH 50491123200000ULL
-#define FILETIME_UNIX_EPOCH 11644473600LL
-#define FileTime_TotalMS(time) ((time / 10000) + FILETIME_EPOCH)
-#define FileTime_UnixTime(time) ((time / 10000000) - FILETIME_UNIX_EPOCH)
-TimeMS DateTime_CurrentUTC_MS(void) {
+#define FILETIME_EPOCH 50491123200ULL
+#define FILETIME_UNIX_EPOCH 11644473600ULL
+#define FileTime_TotalSecs(time) ((time / 10000000) + FILETIME_EPOCH)
+#define FileTime_UnixTime(time) ((time / 10000000) - FILETIME_UNIX_EPOCH)
+TimeMS DateTime_CurrentUTC(void) {
LARGE_INTEGER ft;
KeQuerySystemTime(&ft);
/* in 100 nanosecond units, since Jan 1 1601 */
- return FileTime_TotalMS(ft.QuadPart);
+ return FileTime_TotalSecs(ft.QuadPart);
}
void DateTime_CurrentLocal(struct DateTime* t) {
diff --git a/src/Platform_Xbox360.c b/src/Platform_Xbox360.c
index c230bc370..d18920e81 100644
--- a/src/Platform_Xbox360.c
+++ b/src/Platform_Xbox360.c
@@ -41,11 +41,10 @@ void Platform_Log(const char* msg, int len) {
puts(tmp);
}
-#define UnixTime_TotalMS(time) ((cc_uint64)time.tv_sec * 1000 + UNIX_EPOCH + (time.tv_usec / 1000))
-TimeMS DateTime_CurrentUTC_MS(void) {
+TimeMS DateTime_CurrentUTC(void) {
struct timeval cur;
gettimeofday(&cur, NULL);
- return UnixTime_TotalMS(cur);
+ return (cc_uint64)cur.tv_sec + UNIX_EPOCH_SECONDS;
}
void DateTime_CurrentLocal(struct DateTime* t) {
diff --git a/src/Resources.c b/src/Resources.c
index 8420cfb30..167fc7aba 100644
--- a/src/Resources.c
+++ b/src/Resources.c
@@ -14,6 +14,7 @@
#include "LWeb.h"
#include "Http.h"
#include "Game.h"
+#include "Audio.h"
/* Represents a set of assets/resources */
/* E.g. music set, sounds set, textures set */
@@ -28,9 +29,12 @@ struct AssetSet {
const char* (*GetRequestName)(int reqID);
/* Checks if any assets have been downloaded, and processes them if so */
void (*CheckStatus)(void);
+ /* Resets state and frees and allocated memory */
+ void (*ResetState)(void);
};
-int Resources_Count, Resources_Size;
+int Resources_MissingCount, Resources_MissingSize;
+cc_bool Resources_MissingRequired;
union ResourceValue {
cc_uint8* data;
@@ -44,12 +48,336 @@ struct ResourceZipEntry {
union ResourceValue value;
cc_uint32 offset, crc32;
};
+#define RESOURCE_TYPE_DATA 1
+#define RESOURCE_TYPE_PNG 2
+#define RESOURCE_TYPE_CONST 3
+#define RESOURCE_TYPE_SOUND 4
static CC_NOINLINE cc_bool Fetcher_Get(int reqID, struct HttpRequest* item);
CC_NOINLINE static struct ResourceZipEntry* ZipEntries_Find(const cc_string* name);
static cc_result ZipEntry_ExtractData(struct ResourceZipEntry* e, struct Stream* data, struct ZipEntry* source);
+/*########################################################################################################################*
+*------------------------------------------------------Utility functions -------------------------------------------------*
+*#########################################################################################################################*/
+static void ZipFile_InspectEntries(const cc_string* path, Zip_SelectEntry selector) {
+ struct Stream stream;
+ cc_result res;
+
+ res = Stream_OpenFile(&stream, path);
+ if (res == ReturnCode_FileNotFound) return;
+ if (res) { Logger_SysWarn2(res, "opening", path); return; }
+
+ res = Zip_Extract(&stream, selector, NULL);
+ if (res) Logger_SysWarn2(res, "inspecting", path);
+
+ /* No point logging error for closing readonly file */
+ (void)stream.Close(&stream);
+}
+
+static cc_result ZipEntry_ExtractData(struct ResourceZipEntry* e, struct Stream* data, struct ZipEntry* source) {
+ cc_uint32 size = source->UncompressedSize;
+ e->value.data = Mem_TryAlloc(size, 1);
+ e->size = size;
+
+ if (!e->value.data) return ERR_OUT_OF_MEMORY;
+ return Stream_Read(data, e->value.data, size);
+}
+
+
+/*########################################################################################################################*
+*-----------------------------------------------------Sound asset writing ------------------------------------------------*
+*#########################################################################################################################*/
+#define WAV_FourCC(a, b, c, d) (((cc_uint32)a << 24) | ((cc_uint32)b << 16) | ((cc_uint32)c << 8) | (cc_uint32)d)
+#define WAV_HDR_SIZE 44
+
+/* Fixes up the .WAV header after having written all samples */
+static cc_result SoundPatcher_FixupHeader(struct Stream* s, struct VorbisState* ctx, cc_uint32 offset, cc_uint32 len) {
+ cc_uint8 header[WAV_HDR_SIZE];
+ cc_result res = s->Seek(s, offset);
+ if (res) return res;
+
+ Stream_SetU32_BE(header + 0, WAV_FourCC('R','I','F','F'));
+ Stream_SetU32_LE(header + 4, len - 8);
+ Stream_SetU32_BE(header + 8, WAV_FourCC('W','A','V','E'));
+ Stream_SetU32_BE(header + 12, WAV_FourCC('f','m','t',' '));
+ Stream_SetU32_LE(header + 16, 16); /* fmt chunk size */
+ Stream_SetU16_LE(header + 20, 1); /* PCM audio format */
+ Stream_SetU16_LE(header + 22, ctx->channels);
+ Stream_SetU32_LE(header + 24, ctx->sampleRate);
+
+ Stream_SetU32_LE(header + 28, ctx->sampleRate * ctx->channels * 2); /* byte rate */
+ Stream_SetU16_LE(header + 32, ctx->channels * 2); /* block align */
+ Stream_SetU16_LE(header + 34, 16); /* bits per sample */
+ Stream_SetU32_BE(header + 36, WAV_FourCC('d','a','t','a'));
+ Stream_SetU32_LE(header + 40, len - WAV_HDR_SIZE);
+
+ return Stream_Write(s, header, WAV_HDR_SIZE);
+}
+
+/* Decodes all samples, then produces a .WAV file from them */
+static cc_result SoundPatcher_WriteWav(struct Stream* s, struct VorbisState* ctx) {
+ cc_int16* samples;
+ cc_uint32 begOffset;
+ cc_uint32 len = WAV_HDR_SIZE;
+ cc_result res;
+ int count;
+
+ if ((res = s->Position(s, &begOffset))) return res;
+
+ /* reuse context here for a temp garbage header */
+ if ((res = Stream_Write(s, (const cc_uint8*)ctx, WAV_HDR_SIZE))) return res;
+ if ((res = Vorbis_DecodeHeaders(ctx))) return res;
+
+ samples = (cc_int16*)Mem_TryAlloc(ctx->blockSizes[1] * ctx->channels, 2);
+ if (!samples) return ERR_OUT_OF_MEMORY;
+
+ for (;;) {
+ res = Vorbis_DecodeFrame(ctx);
+ if (res == ERR_END_OF_STREAM) {
+ /* reached end of samples, so done */
+ res = SoundPatcher_FixupHeader(s, ctx, begOffset, len);
+ break;
+ }
+ if (res) break;
+
+ count = Vorbis_OutputFrame(ctx, samples);
+ len += count * 2;
+
+#ifdef CC_BUILD_BIGENDIAN
+ Utils_SwapEndian16(samples, count);
+#endif
+ res = Stream_Write(s, (cc_uint8*)samples, count * 2);
+ if (res) break;
+ }
+
+ Mem_Free(samples);
+ if (!res) res = s->Seek(s, begOffset + len);
+ return res;
+}
+
+/* Converts an OGG sound to a WAV sound for faster decoding later */
+static cc_result SoundPatcher_Save(struct Stream* s, struct ResourceZipEntry* e) {
+ struct OggState* ogg = NULL;
+ struct VorbisState* ctx = NULL;
+ struct Stream src;
+ cc_result res;
+
+ ogg = (struct OggState*)Mem_TryAlloc(1, sizeof(struct OggState));
+ if (!ogg) { res = ERR_OUT_OF_MEMORY; goto cleanup; }
+
+ ctx = (struct VorbisState*)Mem_TryAlloc(1, sizeof(struct VorbisState));
+ if (!ctx) { res = ERR_OUT_OF_MEMORY; goto cleanup; }
+
+ Stream_ReadonlyMemory(&src, e->value.data, e->size);
+
+ Ogg_Init(ogg, &src);
+ Vorbis_Init(ctx);
+ ctx->source = ogg;
+ res = SoundPatcher_WriteWav(s, ctx);
+
+cleanup:
+ if (ctx) Vorbis_Free(ctx);
+ Mem_Free(ctx);
+ Mem_Free(ogg);
+ return res;
+}
+
+
+/*########################################################################################################################*
+*------------------------------------------------------Zip entry writer---------------------------------------------------*
+*#########################################################################################################################*/
+static void GetCurrentZipDate(int* modTime, int* modDate) {
+ struct DateTime now;
+ DateTime_CurrentLocal(&now);
+
+ *modTime = (now.second / 2) | (now.minute << 5) | (now.hour << 11);
+ *modDate = (now.day) | (now.month << 5) | ((now.year - 1980) << 9);
+}
+
+static cc_result ZipWriter_LocalFile(struct Stream* s, struct ResourceZipEntry* e) {
+ int filenameLen = String_Length(e->filename);
+ cc_uint8 header[30 + STRING_SIZE];
+ cc_result res;
+ int modTime, modDate;
+
+ GetCurrentZipDate(&modTime, &modDate);
+ if ((res = s->Position(s, &e->offset))) return res;
+
+ Stream_SetU32_LE(header + 0, 0x04034b50); /* signature */
+ Stream_SetU16_LE(header + 4, 20); /* version needed */
+ Stream_SetU16_LE(header + 6, 0); /* bitflags */
+ Stream_SetU16_LE(header + 8, 0); /* compression method */
+ Stream_SetU16_LE(header + 10, modTime); /* last modified */
+ Stream_SetU16_LE(header + 12, modDate); /* last modified */
+
+ Stream_SetU32_LE(header + 14, e->crc32); /* CRC32 */
+ Stream_SetU32_LE(header + 18, e->size); /* Compressed size */
+ Stream_SetU32_LE(header + 22, e->size); /* Uncompressed size */
+
+ Stream_SetU16_LE(header + 26, filenameLen); /* name length */
+ Stream_SetU16_LE(header + 28, 0); /* extra field length */
+
+ Mem_Copy(header + 30, e->filename, filenameLen);
+ return Stream_Write(s, header, 30 + filenameLen);
+}
+
+static cc_result ZipWriter_CentralDir(struct Stream* s, struct ResourceZipEntry* e) {
+ int filenameLen = String_Length(e->filename);
+ cc_uint8 header[46 + STRING_SIZE];
+ int modTime, modDate;
+ GetCurrentZipDate(&modTime, &modDate);
+
+ Stream_SetU32_LE(header + 0, 0x02014b50); /* signature */
+ Stream_SetU16_LE(header + 4, 20); /* version */
+ Stream_SetU16_LE(header + 6, 20); /* version needed */
+ Stream_SetU16_LE(header + 8, 0); /* bitflags */
+ Stream_SetU16_LE(header + 10, 0); /* compression method */
+ Stream_SetU16_LE(header + 12, modTime); /* last modified */
+ Stream_SetU16_LE(header + 14, modDate); /* last modified */
+
+ Stream_SetU32_LE(header + 16, e->crc32); /* CRC32 */
+ Stream_SetU32_LE(header + 20, e->size); /* compressed size */
+ Stream_SetU32_LE(header + 24, e->size); /* uncompressed size */
+
+ Stream_SetU16_LE(header + 28, filenameLen); /* name length */
+ Stream_SetU16_LE(header + 30, 0); /* extra field length */
+ Stream_SetU16_LE(header + 32, 0); /* file comment length */
+ Stream_SetU16_LE(header + 34, 0); /* disk number */
+ Stream_SetU16_LE(header + 36, 0); /* internal attributes */
+ Stream_SetU32_LE(header + 38, 0); /* external attributes */
+ Stream_SetU32_LE(header + 42, e->offset); /* local header offset */
+
+ Mem_Copy(header + 46, e->filename, filenameLen);
+ return Stream_Write(s, header, 46 + filenameLen);
+}
+
+static cc_result ZipWriter_EndOfCentralDir(struct Stream* s, int numEntries,
+ cc_uint32 centralDirBeg, cc_uint32 centralDirEnd) {
+ cc_uint8 header[22];
+
+ Stream_SetU32_LE(header + 0, 0x06054b50); /* signature */
+ Stream_SetU16_LE(header + 4, 0); /* disk number */
+ Stream_SetU16_LE(header + 6, 0); /* disk number of start */
+ Stream_SetU16_LE(header + 8, numEntries); /* disk entries */
+ Stream_SetU16_LE(header + 10, numEntries); /* total entries */
+ Stream_SetU32_LE(header + 12, centralDirEnd - centralDirBeg); /* central dir size */
+ Stream_SetU32_LE(header + 16, centralDirBeg); /* central dir start */
+ Stream_SetU16_LE(header + 20, 0); /* comment length */
+ return Stream_Write(s, header, 22);
+}
+
+static cc_result ZipWriter_FixupLocalFile(struct Stream* s, struct ResourceZipEntry* e) {
+ int filenameLen = String_Length(e->filename);
+ cc_uint8 tmp[2048];
+ cc_uint32 dataBeg, dataEnd;
+ cc_uint32 i, crc, toRead, read;
+ cc_result res;
+
+ dataBeg = e->offset + 30 + filenameLen;
+ if ((res = s->Position(s, &dataEnd))) return res;
+ e->size = dataEnd - dataBeg;
+
+ /* work out the CRC 32 */
+ crc = 0xffffffffUL;
+ if ((res = s->Seek(s, dataBeg))) return res;
+
+ for (; dataBeg < dataEnd; dataBeg += read) {
+ toRead = dataEnd - dataBeg;
+ toRead = min(toRead, sizeof(tmp));
+
+ if ((res = s->Read(s, tmp, toRead, &read))) return res;
+ if (!read) return ERR_END_OF_STREAM;
+
+ for (i = 0; i < read; i++) {
+ crc = Utils_Crc32Table[(crc ^ tmp[i]) & 0xFF] ^ (crc >> 8);
+ }
+ }
+ e->crc32 = crc ^ 0xffffffffUL;
+
+ /* then fixup the header */
+ if ((res = s->Seek(s, e->offset))) return res;
+ if ((res = ZipWriter_LocalFile(s, e))) return res;
+ return s->Seek(s, dataEnd);
+}
+
+static cc_result ZipWriter_WriteData(struct Stream* dst, struct ResourceZipEntry* e) {
+ cc_uint8* data = e->value.data;
+ cc_result res;
+ e->crc32 = Utils_CRC32(data, e->size);
+
+ if ((res = ZipWriter_LocalFile(dst, e))) return res;
+ return Stream_Write(dst, data, e->size);
+}
+
+static cc_result ZipWriter_WritePng(struct Stream* dst, struct ResourceZipEntry* e) {
+ struct Bitmap* src = &e->value.bmp;
+ cc_result res;
+
+ if ((res = ZipWriter_LocalFile(dst, e))) return res;
+ if ((res = Png_Encode(src, dst, NULL, true, NULL))) return res;
+ return ZipWriter_FixupLocalFile(dst, e);
+}
+
+static cc_result ZipWriter_WriteWav(struct Stream* dst, struct ResourceZipEntry* e) {
+ cc_result res;
+
+ if ((res = ZipWriter_LocalFile(dst, e))) return res;
+ if ((res = SoundPatcher_Save(dst, e))) return res;
+ return ZipWriter_FixupLocalFile(dst, e);
+}
+
+
+/*########################################################################################################################*
+*------------------------------------------------------Zip file writer----------------------------------------------------*
+*#########################################################################################################################*/
+static cc_result ZipFile_WriteEntries(struct Stream* s, struct ResourceZipEntry* entries, int numEntries) {
+ struct ResourceZipEntry* e;
+ cc_uint32 beg, end;
+ int i;
+ cc_result res;
+
+ for (i = 0; i < numEntries; i++)
+ {
+ e = &entries[i];
+
+ if (e->type == RESOURCE_TYPE_PNG) {
+ if ((res = ZipWriter_WritePng(s, e))) return res;
+ } else if (e->type == RESOURCE_TYPE_SOUND) {
+ if ((res = ZipWriter_WriteWav(s, e))) return res;
+ } else {
+ if ((res = ZipWriter_WriteData(s, e))) return res;
+ }
+ }
+
+ if ((res = s->Position(s, &beg))) return res;
+ for (i = 0; i < numEntries; i++)
+ {
+ if ((res = ZipWriter_CentralDir(s, &entries[i]))) return res;
+ }
+
+ if ((res = s->Position(s, &end))) return res;
+ return ZipWriter_EndOfCentralDir(s, numEntries, beg, end);
+}
+
+static void ZipFile_Create(const cc_string* path, struct ResourceZipEntry* entries, int numEntries) {
+ struct Stream s;
+ cc_result res;
+
+ res = Stream_CreateFile(&s, path);
+ if (res) {
+ Logger_SysWarn2(res, "creating", path); return;
+ }
+
+ res = ZipFile_WriteEntries(&s, entries, numEntries);
+ if (res) Logger_SysWarn2(res, "making", path);
+
+ res = s.Close(&s);
+ if (res) Logger_SysWarn2(res, "closing", path);
+}
+
+
/*########################################################################################################################*
*---------------------------------------------------------Music assets----------------------------------------------------*
*#########################################################################################################################*/
@@ -89,8 +417,8 @@ static void MusicAssets_CountMissing(void) {
{
if (musicAssets[i].downloaded) continue;
- Resources_Size += musicAssets[i].size;
- Resources_Count++;
+ Resources_MissingSize += musicAssets[i].size;
+ Resources_MissingCount++;
}
}
@@ -158,12 +486,16 @@ static void MusicAssets_CheckStatus(void) {
}
}
+static void MusicAssets_ResetState(void) {
+}
+
static const struct AssetSet mccMusicAssetSet = {
MusicAssets_CheckExistence,
MusicAssets_CountMissing,
MusicAssets_DownloadAssets,
MusicAssets_GetRequestName,
- MusicAssets_CheckStatus
+ MusicAssets_CheckStatus,
+ MusicAssets_ResetState
};
@@ -171,200 +503,161 @@ static const struct AssetSet mccMusicAssetSet = {
*---------------------------------------------------------Sound assets----------------------------------------------------*
*#########################################################################################################################*/
static struct SoundAsset {
- const char* name;
+ const char* filename;
const char* hash;
- int reqID;
+ int reqID, size;
+ void* data;
} soundAssets[] = {
- { "dig_cloth1", "5fd568d724ba7d53911b6cccf5636f859d2662e8" }, { "dig_cloth2", "56c1d0ac0de2265018b2c41cb571cc6631101484" },
- { "dig_cloth3", "9c63f2a3681832dc32d206f6830360bfe94b5bfc" }, { "dig_cloth4", "55da1856e77cfd31a7e8c3d358e1f856c5583198" },
- { "dig_grass1", "41cbf5dd08e951ad65883854e74d2e034929f572" }, { "dig_grass2", "86cb1bb0c45625b18e00a64098cd425a38f6d3f2" },
- { "dig_grass3", "f7d7e5c7089c9b45fa5d1b31542eb455fad995db" }, { "dig_grass4", "c7b1005d4926f6a2e2387a41ab1fb48a72f18e98" },
- { "dig_gravel1", "e8b89f316f3e9989a87f6e6ff12db9abe0f8b09f" }, { "dig_gravel2", "c3b3797d04cb9640e1d3a72d5e96edb410388fa3" },
- { "dig_gravel3", "48f7e1bb098abd36b9760cca27b9d4391a23de26" }, { "dig_gravel4", "7bf3553a4fe41a0078f4988a13d6e1ed8663ef4c" },
- { "dig_sand1", "9e59c3650c6c3fc0a475f1b753b2fcfef430bf81" }, { "dig_sand2", "0fa4234797f336ada4e3735e013e44d1099afe57" },
- { "dig_sand3", "c75589cc0087069f387de127dd1499580498738e" }, { "dig_sand4", "37afa06f97d58767a1cd1382386db878be1532dd" },
- { "dig_snow1", "e9bab7d3d15541f0aaa93fad31ad37fd07e03a6c" }, { "dig_snow2", "5887d10234c4f244ec5468080412f3e6ef9522f3" },
- { "dig_snow3", "a4bc069321a96236fde04a3820664cc23b2ea619" }, { "dig_snow4", "e26fa3036cdab4c2264ceb19e1cd197a2a510227" },
- { "dig_stone1", "4e094ed8dfa98656d8fec52a7d20c5ee6098b6ad" }, { "dig_stone2", "9c92f697142ae320584bf64c0d54381d59703528" },
- { "dig_stone3", "8f23c02475d388b23e5faa680eafe6b991d7a9d4" }, { "dig_stone4", "363545a76277e5e47538b2dd3a0d6aa4f7a87d34" },
- { "dig_wood1", "9bc2a84d0aa98113fc52609976fae8fc88ea6333" }, { "dig_wood2", "98102533e6085617a2962157b4f3658f59aea018" },
- { "dig_wood3", "45b2aef7b5049e81b39b58f8d631563fadcc778b" }, { "dig_wood4", "dc66978374a46ab2b87db6472804185824868095" },
- { "dig_glass1", "7274a2231ed4544a37e599b7b014e589e5377094" }, { "dig_glass2", "87c47bda3645c68f18a49e83cbf06e5302d087ff" },
- { "dig_glass3", "ad7d770b7fff3b64121f75bd60cecfc4866d1cd6" },
-
- { "step_cloth1", "5fd568d724ba7d53911b6cccf5636f859d2662e8" }, { "step_cloth2", "56c1d0ac0de2265018b2c41cb571cc6631101484" },
- { "step_cloth3", "9c63f2a3681832dc32d206f6830360bfe94b5bfc" }, { "step_cloth4", "55da1856e77cfd31a7e8c3d358e1f856c5583198" },
- { "step_grass1", "41cbf5dd08e951ad65883854e74d2e034929f572" }, { "step_grass2", "86cb1bb0c45625b18e00a64098cd425a38f6d3f2" },
- { "step_grass3", "f7d7e5c7089c9b45fa5d1b31542eb455fad995db" }, { "step_grass4", "c7b1005d4926f6a2e2387a41ab1fb48a72f18e98" },
- { "step_gravel1", "e8b89f316f3e9989a87f6e6ff12db9abe0f8b09f" }, { "step_gravel2", "c3b3797d04cb9640e1d3a72d5e96edb410388fa3" },
- { "step_gravel3", "48f7e1bb098abd36b9760cca27b9d4391a23de26" }, { "step_gravel4", "7bf3553a4fe41a0078f4988a13d6e1ed8663ef4c" },
- { "step_sand1", "9e59c3650c6c3fc0a475f1b753b2fcfef430bf81" }, { "step_sand2", "0fa4234797f336ada4e3735e013e44d1099afe57" },
- { "step_sand3", "c75589cc0087069f387de127dd1499580498738e" }, { "step_sand4", "37afa06f97d58767a1cd1382386db878be1532dd" },
- { "step_snow1", "e9bab7d3d15541f0aaa93fad31ad37fd07e03a6c" }, { "step_snow2", "5887d10234c4f244ec5468080412f3e6ef9522f3" },
- { "step_snow3", "a4bc069321a96236fde04a3820664cc23b2ea619" }, { "step_snow4", "e26fa3036cdab4c2264ceb19e1cd197a2a510227" },
- { "step_stone1", "4e094ed8dfa98656d8fec52a7d20c5ee6098b6ad" }, { "step_stone2", "9c92f697142ae320584bf64c0d54381d59703528" },
- { "step_stone3", "8f23c02475d388b23e5faa680eafe6b991d7a9d4" }, { "step_stone4", "363545a76277e5e47538b2dd3a0d6aa4f7a87d34" },
- { "step_wood1", "9bc2a84d0aa98113fc52609976fae8fc88ea6333" }, { "step_wood2", "98102533e6085617a2962157b4f3658f59aea018" },
- { "step_wood3", "45b2aef7b5049e81b39b58f8d631563fadcc778b" }, { "step_wood4", "dc66978374a46ab2b87db6472804185824868095" }
+ { "dig_cloth1.wav", "5fd568d724ba7d53911b6cccf5636f859d2662e8" }, { "dig_cloth2.wav", "56c1d0ac0de2265018b2c41cb571cc6631101484" },
+ { "dig_cloth3.wav", "9c63f2a3681832dc32d206f6830360bfe94b5bfc" }, { "dig_cloth4.wav", "55da1856e77cfd31a7e8c3d358e1f856c5583198" },
+ { "dig_grass1.wav", "41cbf5dd08e951ad65883854e74d2e034929f572" }, { "dig_grass2.wav", "86cb1bb0c45625b18e00a64098cd425a38f6d3f2" },
+ { "dig_grass3.wav", "f7d7e5c7089c9b45fa5d1b31542eb455fad995db" }, { "dig_grass4.wav", "c7b1005d4926f6a2e2387a41ab1fb48a72f18e98" },
+ { "dig_gravel1.wav", "e8b89f316f3e9989a87f6e6ff12db9abe0f8b09f" }, { "dig_gravel2.wav", "c3b3797d04cb9640e1d3a72d5e96edb410388fa3" },
+ { "dig_gravel3.wav", "48f7e1bb098abd36b9760cca27b9d4391a23de26" }, { "dig_gravel4.wav", "7bf3553a4fe41a0078f4988a13d6e1ed8663ef4c" },
+ { "dig_sand1.wav", "9e59c3650c6c3fc0a475f1b753b2fcfef430bf81" }, { "dig_sand2.wav", "0fa4234797f336ada4e3735e013e44d1099afe57" },
+ { "dig_sand3.wav", "c75589cc0087069f387de127dd1499580498738e" }, { "dig_sand4.wav", "37afa06f97d58767a1cd1382386db878be1532dd" },
+ { "dig_snow1.wav", "e9bab7d3d15541f0aaa93fad31ad37fd07e03a6c" }, { "dig_snow2.wav", "5887d10234c4f244ec5468080412f3e6ef9522f3" },
+ { "dig_snow3.wav", "a4bc069321a96236fde04a3820664cc23b2ea619" }, { "dig_snow4.wav", "e26fa3036cdab4c2264ceb19e1cd197a2a510227" },
+ { "dig_stone1.wav", "4e094ed8dfa98656d8fec52a7d20c5ee6098b6ad" }, { "dig_stone2.wav", "9c92f697142ae320584bf64c0d54381d59703528" },
+ { "dig_stone3.wav", "8f23c02475d388b23e5faa680eafe6b991d7a9d4" }, { "dig_stone4.wav", "363545a76277e5e47538b2dd3a0d6aa4f7a87d34" },
+ { "dig_wood1.wav", "9bc2a84d0aa98113fc52609976fae8fc88ea6333" }, { "dig_wood2.wav", "98102533e6085617a2962157b4f3658f59aea018" },
+ { "dig_wood3.wav", "45b2aef7b5049e81b39b58f8d631563fadcc778b" }, { "dig_wood4.wav", "dc66978374a46ab2b87db6472804185824868095" },
+ { "dig_glass1.wav", "7274a2231ed4544a37e599b7b014e589e5377094" }, { "dig_glass2.wav", "87c47bda3645c68f18a49e83cbf06e5302d087ff" },
+ { "dig_glass3.wav", "ad7d770b7fff3b64121f75bd60cecfc4866d1cd6" },
+
+ { "step_cloth1.wav", "5fd568d724ba7d53911b6cccf5636f859d2662e8" }, { "step_cloth2.wav", "56c1d0ac0de2265018b2c41cb571cc6631101484" },
+ { "step_cloth3.wav", "9c63f2a3681832dc32d206f6830360bfe94b5bfc" }, { "step_cloth4.wav", "55da1856e77cfd31a7e8c3d358e1f856c5583198" },
+ { "step_grass1.wav", "41cbf5dd08e951ad65883854e74d2e034929f572" }, { "step_grass2.wav", "86cb1bb0c45625b18e00a64098cd425a38f6d3f2" },
+ { "step_grass3.wav", "f7d7e5c7089c9b45fa5d1b31542eb455fad995db" }, { "step_grass4.wav", "c7b1005d4926f6a2e2387a41ab1fb48a72f18e98" },
+ { "step_gravel1.wav", "e8b89f316f3e9989a87f6e6ff12db9abe0f8b09f" }, { "step_gravel2.wav", "c3b3797d04cb9640e1d3a72d5e96edb410388fa3" },
+ { "step_gravel3.wav", "48f7e1bb098abd36b9760cca27b9d4391a23de26" }, { "step_gravel4.wav", "7bf3553a4fe41a0078f4988a13d6e1ed8663ef4c" },
+ { "step_sand1.wav", "9e59c3650c6c3fc0a475f1b753b2fcfef430bf81" }, { "step_sand2.wav", "0fa4234797f336ada4e3735e013e44d1099afe57" },
+ { "step_sand3.wav", "c75589cc0087069f387de127dd1499580498738e" }, { "step_sand4.wav", "37afa06f97d58767a1cd1382386db878be1532dd" },
+ { "step_snow1.wav", "e9bab7d3d15541f0aaa93fad31ad37fd07e03a6c" }, { "step_snow2.wav", "5887d10234c4f244ec5468080412f3e6ef9522f3" },
+ { "step_snow3.wav", "a4bc069321a96236fde04a3820664cc23b2ea619" }, { "step_snow4.wav", "e26fa3036cdab4c2264ceb19e1cd197a2a510227" },
+ { "step_stone1.wav", "4e094ed8dfa98656d8fec52a7d20c5ee6098b6ad" }, { "step_stone2.wav", "9c92f697142ae320584bf64c0d54381d59703528" },
+ { "step_stone3.wav", "8f23c02475d388b23e5faa680eafe6b991d7a9d4" }, { "step_stone4.wav", "363545a76277e5e47538b2dd3a0d6aa4f7a87d34" },
+ { "step_wood1.wav", "9bc2a84d0aa98113fc52609976fae8fc88ea6333" }, { "step_wood2.wav", "98102533e6085617a2962157b4f3658f59aea018" },
+ { "step_wood3.wav", "45b2aef7b5049e81b39b58f8d631563fadcc778b" }, { "step_wood4.wav", "dc66978374a46ab2b87db6472804185824868095" }
};
static cc_bool allSoundsExist;
-static void SoundAssets_CheckExistence(void) {
- cc_string path; char pathBuffer[FILENAME_SIZE];
+static void SoundAssets_ResetState(void) {
int i;
- String_InitArray(path, pathBuffer);
+ allSoundsExist = false;
- for (i = 0; i < Array_Elems(soundAssets); i++)
+ for (i = 0; i < Array_Elems(soundAssets); i++)
{
- path.length = 0;
- String_Format1(&path, "audio/%c.wav", soundAssets[i].name);
-
- if (File_Exists(&path)) continue;
- allSoundsExist = false;
- return;
+ Mem_Free(soundAssets[i].data);
+ soundAssets[i].data = NULL;
+ soundAssets[i].size = 0;
}
- allSoundsExist = true;
}
-static void SoundAssets_CountMissing(void) {
- if (allSoundsExist) return;
-
- Resources_Count += Array_Elems(soundAssets);
- Resources_Size += 417;
-}
/*########################################################################################################################*
-*-----------------------------------------------------Sound asset fetching -----------------------------------------------*
+*-----------------------------------------------------Sound asset checking -----------------------------------------------*
*#########################################################################################################################*/
-#define SoundAsset_Download(hash) MusicAsset_Download(hash)
+static int soundEntriesFound;
-static void SoundAssets_DownloadAssets(void) {
+static struct SoundAsset* SoundAssest_Find(const cc_string* name) {
+ struct SoundAsset* a;
int i;
- for (i = 0; i < Array_Elems(soundAssets); i++)
- {
- if (allSoundsExist) continue;
- soundAssets[i].reqID = SoundAsset_Download(soundAssets[i].hash);
- }
-}
-static const char* SoundAssets_GetRequestName(int reqID) {
- int i;
for (i = 0; i < Array_Elems(soundAssets); i++)
{
- if (reqID == soundAssets[i].reqID) return soundAssets[i].name;
+ a = &soundAssets[i];
+ if (String_CaselessEqualsConst(name, a->filename)) return a;
}
return NULL;
}
+static cc_bool SoundAssets_CheckEntry(const cc_string* path) {
+ cc_string name = *path;
+ Utils_UNSAFE_GetFilename(&name);
-/*########################################################################################################################*
-*----------------------------------------------------Sound asset processing ----------------------------------------------*
-*#########################################################################################################################*/
-#define WAV_FourCC(a, b, c, d) (((cc_uint32)a << 24) | ((cc_uint32)b << 16) | ((cc_uint32)c << 8) | (cc_uint32)d)
-#define WAV_HDR_SIZE 44
-
-/* Fixes up the .WAV header after having written all samples */
-static void SoundPatcher_FixupHeader(struct Stream* s, struct VorbisState* ctx, cc_uint32 len) {
- cc_uint8 header[WAV_HDR_SIZE];
- cc_result res = s->Seek(s, 0);
- if (res) { Logger_SysWarn(res, "seeking to .wav start"); return; }
-
- Stream_SetU32_BE(header + 0, WAV_FourCC('R','I','F','F'));
- Stream_SetU32_LE(header + 4, len - 8);
- Stream_SetU32_BE(header + 8, WAV_FourCC('W','A','V','E'));
- Stream_SetU32_BE(header + 12, WAV_FourCC('f','m','t',' '));
- Stream_SetU32_LE(header + 16, 16); /* fmt chunk size */
- Stream_SetU16_LE(header + 20, 1); /* PCM audio format */
- Stream_SetU16_LE(header + 22, ctx->channels);
- Stream_SetU32_LE(header + 24, ctx->sampleRate);
-
- Stream_SetU32_LE(header + 28, ctx->sampleRate * ctx->channels * 2); /* byte rate */
- Stream_SetU16_LE(header + 32, ctx->channels * 2); /* block align */
- Stream_SetU16_LE(header + 34, 16); /* bits per sample */
- Stream_SetU32_BE(header + 36, WAV_FourCC('d','a','t','a'));
- Stream_SetU32_LE(header + 40, len - WAV_HDR_SIZE);
-
- res = Stream_Write(s, header, WAV_HDR_SIZE);
- if (res) Logger_SysWarn(res, "fixing .wav header");
+ if (SoundAssest_Find(&name)) soundEntriesFound++;
+ return false;
}
-/* Decodes all samples, then produces a .WAV file from them */
-static void SoundPatcher_WriteWav(struct Stream* s, struct VorbisState* ctx) {
- cc_int16* samples;
- cc_uint32 len = WAV_HDR_SIZE;
- cc_result res;
- int count;
-
- /* ctx is all 0, so reuse here for empty header */
- res = Stream_Write(s, (const cc_uint8*)ctx, WAV_HDR_SIZE);
- if (res) { Logger_SysWarn(res, "writing .wav header"); return; }
-
- res = Vorbis_DecodeHeaders(ctx);
- if (res) { Logger_SysWarn(res, "decoding .ogg header"); return; }
+static void SoundAssets_CheckExistence(void) {
+ soundEntriesFound = 0;
+ ZipFile_InspectEntries(&Sounds_ZipPathMC, SoundAssets_CheckEntry);
- samples = (cc_int16*)Mem_TryAlloc(ctx->blockSizes[1] * ctx->channels, 2);
- if (!samples) { Logger_SysWarn(ERR_OUT_OF_MEMORY, "allocating .ogg samples"); return; }
+ /* >= in case somehow have say "gui.png", "GUI.png" */
+ allSoundsExist = soundEntriesFound >= Array_Elems(soundAssets);
+}
- for (;;) {
- res = Vorbis_DecodeFrame(ctx);
- if (res == ERR_END_OF_STREAM) {
- /* reached end of samples, so done */
- SoundPatcher_FixupHeader(s, ctx, len); break;
- }
- if (res) { Logger_SysWarn(res, "decoding .ogg"); break; }
+static void SoundAssets_CountMissing(void) {
+ if (allSoundsExist) return;
- count = Vorbis_OutputFrame(ctx, samples);
- len += count * 2;
- /* TODO: Do we need to account for big endian */
- res = Stream_Write(s, samples, count * 2);
- if (res) { Logger_SysWarn(res, "writing samples"); break; }
- }
- Mem_Free(samples);
+ Resources_MissingCount += Array_Elems(soundAssets);
+ Resources_MissingSize += 417;
}
-/* Converts an OGG sound to a WAV sound for faster decoding later */
-static void SoundPatcher_Save(const char* name, struct HttpRequest* req) {
- cc_string path; char pathBuffer[STRING_SIZE];
- struct OggState ogg;
- struct Stream src, dst;
- struct VorbisState* ctx;
- cc_result res;
- ctx = (struct VorbisState*)Mem_TryAllocCleared(1, sizeof(struct VorbisState));
- if (!ctx) { Logger_SysWarn(ERR_OUT_OF_MEMORY, "allocating memory"); return; }
+/*########################################################################################################################*
+*----------------------------------------------------Sound asset generation ----------------------------------------------*
+*#########################################################################################################################*/
+static void SoundAsset_CreateZip(void) {
+ struct ResourceZipEntry entries[Array_Elems(soundAssets)];
+ int i;
+
+ for (i = 0; i < Array_Elems(soundAssets); i++)
+ {
+ entries[i].filename = soundAssets[i].filename;
+ entries[i].type = RESOURCE_TYPE_SOUND;
- Stream_ReadonlyMemory(&src, req->data, req->size);
- String_InitArray(path, pathBuffer);
- String_Format1(&path, "audio/%c.wav", name);
+ entries[i].value.data = soundAssets[i].data;
+ entries[i].size = soundAssets[i].size;
+ }
- res = Stream_CreateFile(&dst, &path);
- if (res) { Logger_SysWarn(res, "creating .wav file"); return; }
+ ZipFile_Create(&Sounds_ZipPathMC, entries, Array_Elems(soundAssets));
+ SoundAssets_ResetState();
+}
- Ogg_Init(&ogg, &src);
- ctx->source = &ogg;
- SoundPatcher_WriteWav(&dst, ctx);
- res = dst.Close(&dst);
- if (res) Logger_SysWarn(res, "closing .wav file");
+/*########################################################################################################################*
+*-----------------------------------------------------Sound asset fetching -----------------------------------------------*
+*#########################################################################################################################*/
+#define SoundAsset_Download(hash) MusicAsset_Download(hash)
- Vorbis_Free(ctx);
- Mem_Free(ctx);
+static void SoundAssets_DownloadAssets(void) {
+ int i;
+ for (i = 0; i < Array_Elems(soundAssets); i++)
+ {
+ if (allSoundsExist) continue;
+ soundAssets[i].reqID = SoundAsset_Download(soundAssets[i].hash);
+ }
}
+static const char* SoundAssets_GetRequestName(int reqID) {
+ int i;
+ for (i = 0; i < Array_Elems(soundAssets); i++)
+ {
+ if (reqID == soundAssets[i].reqID) return soundAssets[i].filename;
+ }
+ return NULL;
+}
-static void SoundAsset_Check(const struct SoundAsset* sound) {
+static void SoundAsset_Check(struct SoundAsset* sound, int i) {
struct HttpRequest item;
if (!Fetcher_Get(sound->reqID, &item)) return;
- SoundPatcher_Save(sound->name, &item);
+ sound->data = item.data;
+ sound->size = item.size;
+ item.data = NULL;
HttpRequest_Free(&item);
+
+ if (i == Array_Elems(soundAssets) - 1)
+ SoundAsset_CreateZip();
}
static void SoundAssets_CheckStatus(void) {
int i;
for (i = 0; i < Array_Elems(soundAssets); i++)
{
- SoundAsset_Check(&soundAssets[i]);
+ SoundAsset_Check(&soundAssets[i], i);
}
}
@@ -373,7 +666,8 @@ static const struct AssetSet mccSoundAssetSet = {
SoundAssets_CountMissing,
SoundAssets_DownloadAssets,
SoundAssets_GetRequestName,
- SoundAssets_CheckStatus
+ SoundAssets_CheckStatus,
+ SoundAssets_ResetState
};
@@ -391,8 +685,9 @@ static void CCTextures_CheckExistence(void) {
static void CCTextures_CountMissing(void) {
if (ccTexturesExist) return;
- Resources_Count++;
- Resources_Size += 83;
+ Resources_MissingCount++;
+ Resources_MissingSize += 83;
+ Resources_MissingRequired = true;
}
@@ -414,30 +709,28 @@ static const char* CCTextures_GetRequestName(int reqID) {
/*########################################################################################################################*
*-------------------------------------------------CC texture assets processing -------------------------------------------*
*#########################################################################################################################*/
-#ifdef CC_BUILD_MOBILE
/* Android needs the touch.png */
/* TODO: Unify both android and desktop platforms to both just extract from default.zip */
static cc_bool CCTextures_SelectEntry(const cc_string* path) {
return String_CaselessEqualsConst(path, "touch.png");
}
+
static cc_result CCTextures_ProcessEntry(const cc_string* path, struct Stream* data, struct ZipEntry* source) {
struct ResourceZipEntry* e = ZipEntries_Find(path);
+ if (!e) return 0; /* TODO exteact on PC too */
+
return ZipEntry_ExtractData(e, data, source);
}
static cc_result CCTextures_ExtractZip(struct HttpRequest* req) {
struct Stream src;
- Stream_WriteAllTo(&ccTexPack, req->data, req->size);
- Stream_ReadonlyMemory(&src, req->data, req->size);
+ cc_result res;
+
+ Stream_ReadonlyMemory(&src, req->data, req->size);
+ if ((res = Zip_Extract(&src, CCTextures_SelectEntry, CCTextures_ProcessEntry))) return res;
- return Zip_Extract(&src,
- CCTextures_SelectEntry, CCTextures_ProcessEntry);
-}
-#else
-static cc_result CCTextures_ExtractZip(struct HttpRequest* req) {
return Stream_WriteAllTo(&ccTexPack, req->data, req->size);
}
-#endif
static void CCTextures_CheckStatus(void) {
struct HttpRequest item;
@@ -453,158 +746,24 @@ static void CCTextures_CheckStatus(void) {
HttpRequest_Free(&item);
}
+static void CCTextures_ResetState(void) {
+ ccTexturesExist = false;
+ ccTexturesDownloaded = false;
+}
+
static const struct AssetSet ccTexsAssetSet = {
CCTextures_CheckExistence,
CCTextures_CountMissing,
CCTextures_DownloadAssets,
CCTextures_GetRequestName,
- CCTextures_CheckStatus
+ CCTextures_CheckStatus,
+ CCTextures_ResetState
};
-/*########################################################################################################################*
-*---------------------------------------------------------Zip writer------------------------------------------------------*
-*#########################################################################################################################*/
-static void GetCurrentZipDate(int* modTime, int* modDate) {
- struct DateTime now;
- DateTime_CurrentLocal(&now);
-
- *modTime = (now.second / 2) | (now.minute << 5) | (now.hour << 11);
- *modDate = (now.day) | (now.month << 5) | ((now.year - 1980) << 9);
-}
-
-static cc_result ZipWriter_LocalFile(struct Stream* s, struct ResourceZipEntry* e) {
- int filenameLen = String_Length(e->filename);
- cc_uint8 header[30 + STRING_SIZE];
- cc_result res;
- int modTime, modDate;
-
- GetCurrentZipDate(&modTime, &modDate);
- if ((res = s->Position(s, &e->offset))) return res;
-
- Stream_SetU32_LE(header + 0, 0x04034b50); /* signature */
- Stream_SetU16_LE(header + 4, 20); /* version needed */
- Stream_SetU16_LE(header + 6, 0); /* bitflags */
- Stream_SetU16_LE(header + 8, 0); /* compression method */
- Stream_SetU16_LE(header + 10, modTime); /* last modified */
- Stream_SetU16_LE(header + 12, modDate); /* last modified */
-
- Stream_SetU32_LE(header + 14, e->crc32); /* CRC32 */
- Stream_SetU32_LE(header + 18, e->size); /* Compressed size */
- Stream_SetU32_LE(header + 22, e->size); /* Uncompressed size */
-
- Stream_SetU16_LE(header + 26, filenameLen); /* name length */
- Stream_SetU16_LE(header + 28, 0); /* extra field length */
-
- Mem_Copy(header + 30, e->filename, filenameLen);
- return Stream_Write(s, header, 30 + filenameLen);
-}
-
-static cc_result ZipWriter_CentralDir(struct Stream* s, struct ResourceZipEntry* e) {
- int filenameLen = String_Length(e->filename);
- cc_uint8 header[46 + STRING_SIZE];
- int modTime, modDate;
- GetCurrentZipDate(&modTime, &modDate);
-
- Stream_SetU32_LE(header + 0, 0x02014b50); /* signature */
- Stream_SetU16_LE(header + 4, 20); /* version */
- Stream_SetU16_LE(header + 6, 20); /* version needed */
- Stream_SetU16_LE(header + 8, 0); /* bitflags */
- Stream_SetU16_LE(header + 10, 0); /* compression method */
- Stream_SetU16_LE(header + 12, modTime); /* last modified */
- Stream_SetU16_LE(header + 14, modDate); /* last modified */
-
- Stream_SetU32_LE(header + 16, e->crc32); /* CRC32 */
- Stream_SetU32_LE(header + 20, e->size); /* compressed size */
- Stream_SetU32_LE(header + 24, e->size); /* uncompressed size */
-
- Stream_SetU16_LE(header + 28, filenameLen); /* name length */
- Stream_SetU16_LE(header + 30, 0); /* extra field length */
- Stream_SetU16_LE(header + 32, 0); /* file comment length */
- Stream_SetU16_LE(header + 34, 0); /* disk number */
- Stream_SetU16_LE(header + 36, 0); /* internal attributes */
- Stream_SetU32_LE(header + 38, 0); /* external attributes */
- Stream_SetU32_LE(header + 42, e->offset); /* local header offset */
-
- Mem_Copy(header + 46, e->filename, filenameLen);
- return Stream_Write(s, header, 46 + filenameLen);
-}
-
-static cc_result ZipWriter_EndOfCentralDir(struct Stream* s, int numEntries,
- cc_uint32 centralDirBeg, cc_uint32 centralDirEnd) {
- cc_uint8 header[22];
-
- Stream_SetU32_LE(header + 0, 0x06054b50); /* signature */
- Stream_SetU16_LE(header + 4, 0); /* disk number */
- Stream_SetU16_LE(header + 6, 0); /* disk number of start */
- Stream_SetU16_LE(header + 8, numEntries); /* disk entries */
- Stream_SetU16_LE(header + 10, numEntries); /* total entries */
- Stream_SetU32_LE(header + 12, centralDirEnd - centralDirBeg); /* central dir size */
- Stream_SetU32_LE(header + 16, centralDirBeg); /* central dir start */
- Stream_SetU16_LE(header + 20, 0); /* comment length */
- return Stream_Write(s, header, 22);
-}
-
-static cc_result ZipWriter_FixupLocalFile(struct Stream* s, struct ResourceZipEntry* e) {
- int filenameLen = String_Length(e->filename);
- cc_uint8 tmp[2048];
- cc_uint32 dataBeg, dataEnd;
- cc_uint32 i, crc, toRead, read;
- cc_result res;
-
- dataBeg = e->offset + 30 + filenameLen;
- if ((res = s->Position(s, &dataEnd))) return res;
- e->size = dataEnd - dataBeg;
-
- /* work out the CRC 32 */
- crc = 0xffffffffUL;
- if ((res = s->Seek(s, dataBeg))) return res;
-
- for (; dataBeg < dataEnd; dataBeg += read) {
- toRead = dataEnd - dataBeg;
- toRead = min(toRead, sizeof(tmp));
-
- if ((res = s->Read(s, tmp, toRead, &read))) return res;
- if (!read) return ERR_END_OF_STREAM;
-
- for (i = 0; i < read; i++) {
- crc = Utils_Crc32Table[(crc ^ tmp[i]) & 0xFF] ^ (crc >> 8);
- }
- }
- e->crc32 = crc ^ 0xffffffffUL;
-
- /* then fixup the header */
- if ((res = s->Seek(s, e->offset))) return res;
- if ((res = ZipWriter_LocalFile(s, e))) return res;
- return s->Seek(s, dataEnd);
-}
-
-static cc_result ZipWriter_WriteData(struct Stream* dst, struct ResourceZipEntry* e) {
- cc_uint8* data = e->value.data;
- cc_result res;
- e->crc32 = Utils_CRC32(data, e->size);
-
- if ((res = ZipWriter_LocalFile(dst, e))) return res;
- return Stream_Write(dst, data, e->size);
-}
-
-static cc_result ZipWriter_WritePng(struct Stream* dst, struct ResourceZipEntry* e) {
- struct Bitmap* src = &e->value.bmp;
- cc_result res;
-
- if ((res = ZipWriter_LocalFile(dst, e))) return res;
- if ((res = Png_Encode(src, dst, NULL, true))) return res;
- return ZipWriter_FixupLocalFile(dst, e);
-}
-
-
/*########################################################################################################################*
*----------------------------------------------------default.zip resources------------------------------------------------*
*#########################################################################################################################*/
-#define RESOURCE_TYPE_DATA 1
-#define RESOURCE_TYPE_PNG 2
-#define RESOURCE_TYPE_CONST 3
-
#define ANIMS_TXT \
"# This file defines the animations used in a texture pack for ClassiCube.\r\n" \
"# Each line is in the format : \r\n" \
@@ -656,15 +815,6 @@ CC_NOINLINE static struct ResourceZipEntry* ZipEntries_Find(const cc_string* nam
return NULL;
}
-static cc_result ZipEntry_ExtractData(struct ResourceZipEntry* e, struct Stream* data, struct ZipEntry* source) {
- cc_uint32 size = source->UncompressedSize;
- e->value.data = Mem_TryAlloc(size, 1);
- e->size = size;
-
- if (!e->value.data) return ERR_OUT_OF_MEMORY;
- return Stream_Read(data, e->value.data, size);
-}
-
static cc_result ClassicPatcher_ExtractFiles(struct HttpRequest* req);
static cc_result ModernPatcher_ExtractFiles(struct HttpRequest* req);
@@ -689,6 +839,19 @@ static struct ZipfileSource {
};
static int numDefaultZipSources, numDefaultZipProcessed;
+static void MCCTextures_ResetState(void) {
+ int i;
+ for (i = 0; i < Array_Elems(defaultZipEntries); i++)
+ {
+ if (defaultZipEntries[i].type == RESOURCE_TYPE_CONST) continue;
+
+ /* can reuse value.data for value.bmp case too */
+ Mem_Free(defaultZipEntries[i].value.data);
+ defaultZipEntries[i].value.data = NULL;
+ defaultZipEntries[i].size = 0;
+ }
+}
+
/*########################################################################################################################*
*------------------------------------------------default.zip entry generators---------------------------------------------*
@@ -883,52 +1046,6 @@ static cc_result Classic0023Patcher_OldGold(struct HttpRequest* req) {
}
-/*########################################################################################################################*
-*------------------------------------------------------default.zip writer-------------------------------------------------*
-*#########################################################################################################################*/
-static cc_result DefaultZip_WriteEntries(struct Stream* s) {
- struct ResourceZipEntry* e;
- cc_uint32 beg, end;
- int i;
- cc_result res;
-
- for (i = 0; i < Array_Elems(defaultZipEntries); i++) {
- e = &defaultZipEntries[i];
-
- if (e->type == RESOURCE_TYPE_PNG) {
- if ((res = ZipWriter_WritePng(s, e))) return res;
- } else {
- if ((res = ZipWriter_WriteData(s, e))) return res;
- }
- }
-
- if ((res = s->Position(s, &beg))) return res;
- for (i = 0; i < Array_Elems(defaultZipEntries); i++) {
- if ((res = ZipWriter_CentralDir(s, &defaultZipEntries[i]))) return res;
- }
-
- if ((res = s->Position(s, &end))) return res;
- return ZipWriter_EndOfCentralDir(s, Array_Elems(defaultZipEntries), beg, end);
-}
-
-static void DefaultZip_Create(void) {
- cc_string path = String_FromReadonly(Game_Version.DefaultTexpack);
- struct Stream s;
- cc_result res;
-
- res = Stream_CreateFile(&s, &path);
- if (res) {
- Logger_SysWarn2(res, "creating", &path); return;
- }
-
- res = DefaultZip_WriteEntries(&s);
- if (res) Logger_SysWarn2(res, "making", &path);
-
- res = s.Close(&s);
- if (res) Logger_SysWarn2(res, "closing", &path);
-}
-
-
/*########################################################################################################################*
*-----------------------------------------------Minecraft Classic texture assets------------------------------------------*
*#########################################################################################################################*/
@@ -944,19 +1061,10 @@ static cc_bool DefaultZip_SelectEntry(const cc_string* path) {
}
static void MCCTextures_CheckExistence(void) {
- cc_string path = String_FromReadonly(Game_Version.DefaultTexpack);
- struct Stream stream;
- cc_result res;
+ cc_string path = String_FromReadonly(Game_Version.DefaultTexpack);
+ zipEntriesFound = 0;
- res = Stream_OpenFile(&stream, &path);
- if (res == ReturnCode_FileNotFound) return;
- if (res) { Logger_SysWarn2(res, "opening", &path); return; }
-
- res = Zip_Extract(&stream, DefaultZip_SelectEntry, NULL);
- if (res) Logger_SysWarn2(res, "inspecting", &path);
-
- /* No point logging error for closing readonly file */
- (void)stream.Close(&stream);
+ ZipFile_InspectEntries(&path, DefaultZip_SelectEntry);
/* >= in case somehow have say "gui.png", "GUI.png" */
allZipEntriesExist = zipEntriesFound >= Array_Elems(defaultZipEntries);
@@ -973,8 +1081,8 @@ static void MCCTextures_CountMissing(void) {
if (Game_Version.Version > VERSION_0023) numDefaultZipSources--;
for (i = 0; i < numDefaultZipSources; i++) {
- Resources_Count++;
- Resources_Size += defaultZipSources[i].size;
+ Resources_MissingCount++;
+ Resources_MissingSize += defaultZipSources[i].size;
}
}
@@ -992,6 +1100,7 @@ static void MCCTextures_DownloadAssets(void) {
{
url = String_FromReadonly(defaultZipSources[i].url);
defaultZipSources[i].reqID = Http_AsyncGetData(&url, 0);
+ defaultZipSources[i].downloaded = false;
}
}
@@ -1008,6 +1117,12 @@ static const char* MCCTextures_GetRequestName(int reqID) {
/*########################################################################################################################*
*------------------------------------------Minecraft Classic texture assets processing -----------------------------------*
*#########################################################################################################################*/
+static void MCCTextures_CreateDefaultZip(void) {
+ cc_string path = String_FromReadonly(Game_Version.DefaultTexpack);
+ ZipFile_Create(&path, defaultZipEntries, Array_Elems(defaultZipEntries));
+ MCCTextures_ResetState();
+}
+
static void MCCTextures_CheckSource(struct ZipfileSource* source) {
struct HttpRequest item;
cc_result res;
@@ -1023,7 +1138,7 @@ static void MCCTextures_CheckSource(struct ZipfileSource* source) {
HttpRequest_Free(&item);
if (++numDefaultZipProcessed < numDefaultZipSources) return;
- DefaultZip_Create();
+ MCCTextures_CreateDefaultZip();
}
static void MCCTextures_CheckStatus(void) {
@@ -1040,7 +1155,8 @@ static const struct AssetSet mccTexsAssetSet = {
MCCTextures_CountMissing,
MCCTextures_DownloadAssets,
MCCTextures_GetRequestName,
- MCCTextures_CheckStatus
+ MCCTextures_CheckStatus,
+ MCCTextures_ResetState
};
@@ -1058,10 +1174,20 @@ static const struct AssetSet* const asset_sets[] = {
&mccSoundAssetSet
};
+static void ResetState() {
+ int i;
+ Resources_MissingCount = 0;
+ Resources_MissingSize = 0;
+
+ for (i = 0; i < Array_Elems(asset_sets); i++)
+ {
+ asset_sets[i]->ResetState();
+ }
+}
+
void Resources_CheckExistence(void) {
int i;
- Resources_Count = 0;
- Resources_Size = 0;
+ ResetState();
for (i = 0; i < Array_Elems(asset_sets); i++)
{
@@ -1100,18 +1226,9 @@ void Fetcher_Run(void) {
}
static void Fetcher_Finish(void) {
- int i;
Fetcher_Completed = true;
Fetcher_Working = false;
-
- for (i = 0; i < Array_Elems(defaultZipEntries); i++) {
- if (defaultZipEntries[i].type == RESOURCE_TYPE_CONST) continue;
-
- /* can reuse value.data for value.bmp case too */
- Mem_Free(defaultZipEntries[i].value.data);
- defaultZipEntries[i].value.data = NULL;
- defaultZipEntries[i].size = 0;
- }
+ ResetState();
}
static void Fetcher_Fail(struct HttpRequest* item) {
@@ -1146,7 +1263,7 @@ void Fetcher_Update(void) {
asset_sets[i]->CheckStatus();
}
- if (Fetcher_Downloaded != Resources_Count) return;
+ if (Fetcher_Downloaded != Resources_MissingCount) return;
Fetcher_Finish();
}
#endif
diff --git a/src/Resources.h b/src/Resources.h
index 427da4221..4e629e55d 100644
--- a/src/Resources.h
+++ b/src/Resources.h
@@ -8,9 +8,11 @@ struct HttpRequest;
typedef void (*FetcherErrorCallback)(struct HttpRequest* req);
/* Number of resources that need to be downloaded */
-extern int Resources_Count;
+extern int Resources_MissingCount;
/* Total size of resources that need to be downloaded */
-extern int Resources_Size;
+extern int Resources_MissingSize;
+/* Whether required resources need to be downloaded */
+extern cc_bool Resources_MissingRequired;
/* Checks existence of all assets */
void Resources_CheckExistence(void);
diff --git a/src/SSL.c b/src/SSL.c
index 1bf323e69..389117e96 100644
--- a/src/SSL.c
+++ b/src/SSL.c
@@ -476,7 +476,7 @@ static void InjectEntropy(SSLContext* ctx) {
#endif
static void SetCurrentTime(SSLContext* ctx) {
- cc_uint64 cur = DateTime_CurrentUTC_MS() / 1000;
+ cc_uint64 cur = DateTime_CurrentUTC();
uint32_t days = (uint32_t)(cur / 86400) + 366;
uint32_t secs = (uint32_t)(cur % 86400);
diff --git a/src/SelectionBox.c b/src/SelectionBox.c
index 4f06cc3de..9ee62dd16 100644
--- a/src/SelectionBox.c
+++ b/src/SelectionBox.c
@@ -6,6 +6,7 @@
#include "Game.h"
#include "Camera.h"
+#ifdef CC_BUILD_NETWORKING
/* Data for a selection box. */
struct SelectionBox {
Vec3 p0, p1;
@@ -206,6 +207,11 @@ void Selections_Render(void) {
Gfx_SetDepthWrite(true);
Gfx_SetAlphaBlending(false);
}
+#else
+static int selections_count;
+void Selections_Render(void) { }
+static void Selections_ContextLost(void* obj) { }
+#endif
/*########################################################################################################################*
diff --git a/src/Server.c b/src/Server.c
index 3d1b8dad3..3a60f5b52 100644
--- a/src/Server.c
+++ b/src/Server.c
@@ -67,7 +67,7 @@ int Ping_NextPingId(void) {
head = (head + 1) % Array_Elems(ping_entries);
ping_entries[head].id = next;
- ping_entries[head].sent = DateTime_CurrentUTC_MS();
+ ping_entries[head].sent = Stopwatch_Measure();
ping_entries[head].recv = 0;
ping_head = head;
@@ -79,25 +79,27 @@ void Ping_Update(int id) {
for (i = 0; i < Array_Elems(ping_entries); i++) {
if (ping_entries[i].id != id) continue;
- ping_entries[i].recv = DateTime_CurrentUTC_MS();
+ ping_entries[i].recv = Stopwatch_Measure();
return;
}
}
int Ping_AveragePingMS(void) {
- int i, measures = 0, totalMs = 0;
+ int i, measures = 0, totalMs;
+ cc_int64 total = 0;
for (i = 0; i < Array_Elems(ping_entries); i++) {
struct PingEntry entry = ping_entries[i];
if (!entry.sent || !entry.recv) continue;
- totalMs += (int)(entry.recv - entry.sent);
+ total += entry.recv - entry.sent;
measures++;
}
-
if (!measures) return 0;
- /* (recv - send) is time for packet to be sent to server and then sent back. */
- /* However for ping, only want time to send data to server, so half the total. */
+
+ totalMs = Stopwatch_ElapsedMS(0, total);
+ /* (recv - send) is average time for packet to be sent to server and then sent back. */
+ /* However for ping, only want average time to send data to server, so half the total. */
totalMs /= 2;
return totalMs / measures;
}
diff --git a/src/TexturePack.h b/src/TexturePack.h
index e4858b128..781e38043 100644
--- a/src/TexturePack.h
+++ b/src/TexturePack.h
@@ -20,9 +20,9 @@ extern struct IGameComponent Textures_Component;
#define ATLAS2D_SHIFT 4
/* Maximum supported number of rows in the atlas. */
#ifdef EXTENDED_TEXTURES
-#define ATLAS2D_MAX_ROWS_COUNT 32
+ #define ATLAS2D_MAX_ROWS_COUNT 32
#else
-#define ATLAS2D_MAX_ROWS_COUNT 16
+ #define ATLAS2D_MAX_ROWS_COUNT 16
#endif
/* Maximum possible number of 1D terrain atlases. (worst case, each 1D atlas only has 1 tile) */
#define ATLAS1D_MAX_ATLASES (ATLAS2D_TILES_PER_ROW * ATLAS2D_MAX_ROWS_COUNT)
diff --git a/src/Utils.c b/src/Utils.c
index 9de401d21..6ec7a57b7 100644
--- a/src/Utils.c
+++ b/src/Utils.c
@@ -138,6 +138,19 @@ void Utils_Resize(void** buffer, int* capacity, cc_uint32 elemSize, int defCapac
}
}
+void Utils_SwapEndian16(cc_int16* values, int numValues) {
+ cc_uint8* data = (cc_uint8*)values;
+ int i;
+
+ for (i = 0; i < numValues * 2; i += 2)
+ {
+ cc_uint8 tmp = data[i + 0];
+ data[i + 0] = data[i + 1];
+ data[i + 1] = tmp;
+ }
+}
+
+
static const char base64_table[64] = {
'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
diff --git a/src/Utils.h b/src/Utils.h
index 8cfa7f090..78995c0ef 100644
--- a/src/Utils.h
+++ b/src/Utils.h
@@ -9,7 +9,7 @@ Copyright 2014-2023 ClassiCube | Licensed under BSD-3
struct Bitmap;
struct StringsBuffer;
/* Represents a particular instance in time in some timezone. Not necessarily UTC time. */
-/* NOTE: TimeMS and DateTime_CurrentUTC_MS() should almost always be used instead. */
+/* NOTE: TimeMS and DateTime_CurrentUTC() should almost always be used instead. */
/* This struct should only be used when actually needed. (e.g. log message time) */
struct DateTime {
int year; /* Year, ranges from 0 to 65535 */
@@ -45,6 +45,7 @@ cc_uint32 Utils_CRC32(const cc_uint8* data, cc_uint32 length);
/* NOTE: This cannot be just indexed by byte value - see Utils_CRC32 implementation. */
extern const cc_uint32 Utils_Crc32Table[256];
CC_NOINLINE void Utils_Resize(void** buffer, int* capacity, cc_uint32 elemSize, int defCapacity, int expandElems);
+void Utils_SwapEndian16(cc_int16* values, int numValues);
/* Converts blocks of 3 bytes into 4 ASCII characters. (pads if needed) */
/* Returns the number of ASCII characters written. */
diff --git a/src/Vorbis.c b/src/Vorbis.c
index 2c75d7f72..b0a2e74d5 100644
--- a/src/Vorbis.c
+++ b/src/Vorbis.c
@@ -1229,6 +1229,10 @@ static void Vorbis_CalcWindow(struct VorbisWindow* window, int blockSize) {
}
}
+void Vorbis_Init(struct VorbisState* ctx) {
+ Mem_Set(ctx, 0, sizeof(*ctx) - sizeof(ctx->imdct));
+}
+
void Vorbis_Free(struct VorbisState* ctx) {
int i;
for (i = 0; i < ctx->numCodebooks; i++)
diff --git a/src/Vorbis.h b/src/Vorbis.h
index 56353aa90..b37437ad7 100644
--- a/src/Vorbis.h
+++ b/src/Vorbis.h
@@ -56,7 +56,9 @@ struct VorbisState {
struct imdct_state imdct[2];
};
-/* Frees all dynamic memory allocated to decode the given vorbis audio. */
+/* Initialises the given context to defaults */
+void Vorbis_Init(struct VorbisState* ctx);
+/* Frees all memory dynamically allocated by the given context */
void Vorbis_Free(struct VorbisState* ctx);
/* Reads and decodes the initial vorbis headers and setup data. */
cc_result Vorbis_DecodeHeaders(struct VorbisState* ctx);
diff --git a/src/Window_3DS.c b/src/Window_3DS.c
index 81931ea0b..cb99c7de0 100644
--- a/src/Window_3DS.c
+++ b/src/Window_3DS.c
@@ -36,7 +36,6 @@ void Window_Init(void) {
DisplayInfo.Width = top_width;
DisplayInfo.Height = top_height;
- DisplayInfo.Depth = 4; // 32 bit
DisplayInfo.ScaleX = 0.5f;
DisplayInfo.ScaleY = 0.5f;
@@ -90,52 +89,43 @@ void Window_RequestClose(void) {
*----------------------------------------------------Input processing-----------------------------------------------------*
*#########################################################################################################################*/
static void HandleButtons(u32 mods) {
- Input_SetNonRepeatable(CCPAD_L, mods & KEY_L);
- Input_SetNonRepeatable(CCPAD_R, mods & KEY_R);
+ Gamepad_SetButton(CCPAD_L, mods & KEY_L);
+ Gamepad_SetButton(CCPAD_R, mods & KEY_R);
- Input_SetNonRepeatable(CCPAD_A, mods & KEY_A);
- Input_SetNonRepeatable(CCPAD_B, mods & KEY_B);
- Input_SetNonRepeatable(CCPAD_X, mods & KEY_X);
- Input_SetNonRepeatable(CCPAD_Y, mods & KEY_Y);
+ Gamepad_SetButton(CCPAD_A, mods & KEY_A);
+ Gamepad_SetButton(CCPAD_B, mods & KEY_B);
+ Gamepad_SetButton(CCPAD_X, mods & KEY_X);
+ Gamepad_SetButton(CCPAD_Y, mods & KEY_Y);
- Input_SetNonRepeatable(CCPAD_START, mods & KEY_START);
- Input_SetNonRepeatable(CCPAD_SELECT, mods & KEY_SELECT);
+ Gamepad_SetButton(CCPAD_START, mods & KEY_START);
+ Gamepad_SetButton(CCPAD_SELECT, mods & KEY_SELECT);
- Input_SetNonRepeatable(CCPAD_LEFT, mods & KEY_DLEFT);
- Input_SetNonRepeatable(CCPAD_RIGHT, mods & KEY_DRIGHT);
- Input_SetNonRepeatable(CCPAD_UP, mods & KEY_DUP);
- Input_SetNonRepeatable(CCPAD_DOWN, mods & KEY_DDOWN);
+ Gamepad_SetButton(CCPAD_LEFT, mods & KEY_DLEFT);
+ Gamepad_SetButton(CCPAD_RIGHT, mods & KEY_DRIGHT);
+ Gamepad_SetButton(CCPAD_UP, mods & KEY_DUP);
+ Gamepad_SetButton(CCPAD_DOWN, mods & KEY_DDOWN);
- Input_SetNonRepeatable(CCPAD_ZL, mods & KEY_ZL);
- Input_SetNonRepeatable(CCPAD_ZR, mods & KEY_ZR);
+ Gamepad_SetButton(CCPAD_ZL, mods & KEY_ZL);
+ Gamepad_SetButton(CCPAD_ZR, mods & KEY_ZR);
}
+#define AXIS_SCALE 8.0f
static void ProcessJoystickInput(circlePosition* pos, double delta) {
- float scale = (delta * 60.0) / 8.0f;
-
// May not be exactly 0 on actual hardware
if (Math_AbsI(pos->dx) <= 16) pos->dx = 0;
if (Math_AbsI(pos->dy) <= 16) pos->dy = 0;
- Event_RaiseRawMove(&ControllerEvents.RawMoved, pos->dx * scale, -pos->dy * scale);
+ Gamepad_SetAxis(PAD_AXIS_RIGHT, pos->dx / AXIS_SCALE, -pos->dy / AXIS_SCALE, delta);
}
static void ProcessTouchInput(int mods) {
- static int currX, currY; // current touch position
touchPosition touch;
hidTouchRead(&touch);
- if (hidKeysDown() & KEY_TOUCH) { // stylus went down
- currX = touch.px;
- currY = touch.py;
- Input_AddTouch(0, currX, currY);
- }
- else if (mods & KEY_TOUCH) { // stylus is down
- currX = touch.px;
- currY = touch.py;
- Input_UpdateTouch(0, currX, currY);
- }
- else if (hidKeysUp() & KEY_TOUCH) { // stylus was lifted
- Input_RemoveTouch(0, currX, currY);
+
+ if (mods & KEY_TOUCH) {
+ Input_AddTouch(0, touch.px, touch.py);
+ } else if (hidKeysUp() & KEY_TOUCH) {
+ Input_RemoveTouch(0, Pointers[0].x, Pointers[0].y);
}
}
@@ -275,4 +265,4 @@ cc_result Window_OpenFileDialog(const struct OpenFileDialogArgs* args) {
cc_result Window_SaveFileDialog(const struct SaveFileDialogArgs* args) {
return ERR_NOT_SUPPORTED;
}
-#endif
\ No newline at end of file
+#endif
diff --git a/src/Window_Dreamcast.c b/src/Window_Dreamcast.c
index 0a8670031..a793afe82 100644
--- a/src/Window_Dreamcast.c
+++ b/src/Window_Dreamcast.c
@@ -20,7 +20,6 @@ struct _WindowData WindowInfo;
void Window_Init(void) {
DisplayInfo.Width = vid_mode->width;
DisplayInfo.Height = vid_mode->height;
- DisplayInfo.Depth = 4; // 32 bit
DisplayInfo.ScaleX = 1;
DisplayInfo.ScaleY = 1;
@@ -175,34 +174,34 @@ static void ProcessKeyboardInput(void) {
static void HandleButtons(int mods) {
// TODO CONT_Z
- Input_SetNonRepeatable(CCPAD_A, mods & CONT_A);
- Input_SetNonRepeatable(CCPAD_B, mods & CONT_B);
- Input_SetNonRepeatable(CCPAD_X, mods & CONT_X);
- Input_SetNonRepeatable(CCPAD_Y, mods & CONT_Y);
+ Gamepad_SetButton(CCPAD_A, mods & CONT_A);
+ Gamepad_SetButton(CCPAD_B, mods & CONT_B);
+ Gamepad_SetButton(CCPAD_X, mods & CONT_X);
+ Gamepad_SetButton(CCPAD_Y, mods & CONT_Y);
- Input_SetNonRepeatable(CCPAD_START, mods & CONT_START);
- Input_SetNonRepeatable(CCPAD_SELECT, mods & CONT_D);
+ Gamepad_SetButton(CCPAD_START, mods & CONT_START);
+ Gamepad_SetButton(CCPAD_SELECT, mods & CONT_D);
- Input_SetNonRepeatable(CCPAD_LEFT, mods & CONT_DPAD_LEFT);
- Input_SetNonRepeatable(CCPAD_RIGHT, mods & CONT_DPAD_RIGHT);
- Input_SetNonRepeatable(CCPAD_UP, mods & CONT_DPAD_UP);
- Input_SetNonRepeatable(CCPAD_DOWN, mods & CONT_DPAD_DOWN);
+ Gamepad_SetButton(CCPAD_LEFT, mods & CONT_DPAD_LEFT);
+ Gamepad_SetButton(CCPAD_RIGHT, mods & CONT_DPAD_RIGHT);
+ Gamepad_SetButton(CCPAD_UP, mods & CONT_DPAD_UP);
+ Gamepad_SetButton(CCPAD_DOWN, mods & CONT_DPAD_DOWN);
+}
+
+#define AXIS_SCALE 8.0f
+static void HandleJoystick(int axis, int x, int y, double delta) {
+ if (Math_AbsI(x) <= 8) x = 0;
+ if (Math_AbsI(y) <= 8) y = 0;
+
+ Gamepad_SetAxis(axis, x / AXIS_SCALE, y / AXIS_SCALE, delta);
}
static void HandleController(cont_state_t* state, double delta) {
- Input_SetNonRepeatable(CCPAD_L, state->ltrig > 10);
- Input_SetNonRepeatable(CCPAD_R, state->rtrig > 10);
+ Gamepad_SetButton(CCPAD_L, state->ltrig > 10);
+ Gamepad_SetButton(CCPAD_R, state->rtrig > 10);
// TODO CONT_Z, joysticks
- // TODO: verify values are right
-
- if (Input.RawMode) {
- float scale = (delta * 60.0) / 8.0f;
- int dx = state->joyx, dy = state->joyy;
- if (Math_AbsI(dx) <= 8) dx = 0;
- if (Math_AbsI(dy) <= 8) dy = 0;
-
- Event_RaiseRawMove(&ControllerEvents.RawMoved, dx * scale, dy * scale);
- }
+ // TODO: verify values are right
+ HandleJoystick(PAD_AXIS_RIGHT, state->joyx, state->joyy, delta);
}
static void ProcessControllerInput(double delta) {
@@ -307,4 +306,4 @@ cc_result Window_OpenFileDialog(const struct OpenFileDialogArgs* args) {
cc_result Window_SaveFileDialog(const struct SaveFileDialogArgs* args) {
return ERR_NOT_SUPPORTED;
}
-#endif
\ No newline at end of file
+#endif
diff --git a/src/Window_GCWii.c b/src/Window_GCWii.c
index e05826e2c..7433d0896 100644
--- a/src/Window_GCWii.c
+++ b/src/Window_GCWii.c
@@ -105,48 +105,32 @@ void Window_RequestClose(void) {
*#########################################################################################################################*/
static PADStatus gc_pad;
-static void ProcessPAD_LeftJoystick(void) {
- int dx = gc_pad.stickX;
- int dy = gc_pad.stickY;
-
+#define PAD_AXIS_SCALE 8.0f
+static void ProcessPAD_Joystick(int axis, int x, int y, double delta) {
// May not be exactly 0 on actual hardware
- if (Math_AbsI(dx) <= 8) dx = 0;
- if (Math_AbsI(dy) <= 8) dy = 0;
+ if (Math_AbsI(x) <= 8) x = 0;
+ if (Math_AbsI(y) <= 8) y = 0;
- if (dx == 0 && dy == 0) return;
- Input.JoystickMovement = true;
- Input.JoystickAngle = Math_Atan2(dx, -dy);
-}
-
-static void ProcessPAD_RightJoystick(double delta) {
- float scale = (delta * 60.0) / 8.0f;
- int dx = gc_pad.substickX;
- int dy = gc_pad.substickY;
-
- // May not be exactly 0 on actual hardware
- if (Math_AbsI(dx) <= 8) dx = 0;
- if (Math_AbsI(dy) <= 8) dy = 0;
-
- Event_RaiseRawMove(&ControllerEvents.RawMoved, dx * scale, -dy * scale);
+ Gamepad_SetAxis(axis, x / PAD_AXIS_SCALE, -y / PAD_AXIS_SCALE, delta);
}
static void ProcessPAD_Buttons(void) {
int mods = gc_pad.button;
- Input_SetNonRepeatable(CCPAD_L, mods & PAD_TRIGGER_L);
- Input_SetNonRepeatable(CCPAD_R, mods & PAD_TRIGGER_R);
+ Gamepad_SetButton(CCPAD_L, mods & PAD_TRIGGER_L);
+ Gamepad_SetButton(CCPAD_R, mods & PAD_TRIGGER_R);
- Input_SetNonRepeatable(CCPAD_A, mods & PAD_BUTTON_A);
- Input_SetNonRepeatable(CCPAD_B, mods & PAD_BUTTON_B);
- Input_SetNonRepeatable(CCPAD_X, mods & PAD_BUTTON_X);
- Input_SetNonRepeatable(CCPAD_Y, mods & PAD_BUTTON_Y);
+ Gamepad_SetButton(CCPAD_A, mods & PAD_BUTTON_A);
+ Gamepad_SetButton(CCPAD_B, mods & PAD_BUTTON_B);
+ Gamepad_SetButton(CCPAD_X, mods & PAD_BUTTON_X);
+ Gamepad_SetButton(CCPAD_Y, mods & PAD_BUTTON_Y);
- Input_SetNonRepeatable(CCPAD_START, mods & PAD_BUTTON_START);
- Input_SetNonRepeatable(CCPAD_SELECT, mods & PAD_TRIGGER_Z);
+ Gamepad_SetButton(CCPAD_START, mods & PAD_BUTTON_START);
+ Gamepad_SetButton(CCPAD_SELECT, mods & PAD_TRIGGER_Z);
- Input_SetNonRepeatable(CCPAD_LEFT, mods & PAD_BUTTON_LEFT);
- Input_SetNonRepeatable(CCPAD_RIGHT, mods & PAD_BUTTON_RIGHT);
- Input_SetNonRepeatable(CCPAD_UP, mods & PAD_BUTTON_UP);
- Input_SetNonRepeatable(CCPAD_DOWN, mods & PAD_BUTTON_DOWN);
+ Gamepad_SetButton(CCPAD_LEFT, mods & PAD_BUTTON_LEFT);
+ Gamepad_SetButton(CCPAD_RIGHT, mods & PAD_BUTTON_RIGHT);
+ Gamepad_SetButton(CCPAD_UP, mods & PAD_BUTTON_UP);
+ Gamepad_SetButton(CCPAD_DOWN, mods & PAD_BUTTON_DOWN);
}
static void ProcessPADInput(double delta) {
@@ -163,10 +147,8 @@ static void ProcessPADInput(double delta) {
}
ProcessPAD_Buttons();
- if (Input.RawMode) {
- ProcessPAD_LeftJoystick();
- ProcessPAD_RightJoystick(delta);
- }
+ ProcessPAD_Joystick(PAD_AXIS_LEFT, gc_pad.stickX, gc_pad.stickY, delta);
+ ProcessPAD_Joystick(PAD_AXIS_RIGHT, gc_pad.substickX, gc_pad.substickY, delta);
}
@@ -243,44 +225,44 @@ static int dragStartX, dragStartY;
static cc_bool dragActive;
static void ProcessWPAD_Buttons(int mods) {
- Input_SetNonRepeatable(CCPAD_L, mods & WPAD_BUTTON_1);
- Input_SetNonRepeatable(CCPAD_R, mods & WPAD_BUTTON_2);
+ Gamepad_SetButton(CCPAD_L, mods & WPAD_BUTTON_1);
+ Gamepad_SetButton(CCPAD_R, mods & WPAD_BUTTON_2);
- Input_SetNonRepeatable(CCPAD_A, mods & WPAD_BUTTON_A);
- Input_SetNonRepeatable(CCPAD_B, mods & WPAD_BUTTON_B);
- Input_SetNonRepeatable(CCPAD_X, mods & WPAD_BUTTON_PLUS);
+ Gamepad_SetButton(CCPAD_A, mods & WPAD_BUTTON_A);
+ Gamepad_SetButton(CCPAD_B, mods & WPAD_BUTTON_B);
+ Gamepad_SetButton(CCPAD_X, mods & WPAD_BUTTON_PLUS);
- Input_SetNonRepeatable(CCPAD_START, mods & WPAD_BUTTON_HOME);
- Input_SetNonRepeatable(CCPAD_SELECT, mods & WPAD_BUTTON_MINUS);
+ Gamepad_SetButton(CCPAD_START, mods & WPAD_BUTTON_HOME);
+ Gamepad_SetButton(CCPAD_SELECT, mods & WPAD_BUTTON_MINUS);
- Input_SetNonRepeatable(CCPAD_LEFT, mods & WPAD_BUTTON_LEFT);
- Input_SetNonRepeatable(CCPAD_RIGHT, mods & WPAD_BUTTON_RIGHT);
- Input_SetNonRepeatable(CCPAD_UP, mods & WPAD_BUTTON_UP);
- Input_SetNonRepeatable(CCPAD_DOWN, mods & WPAD_BUTTON_DOWN);
+ Gamepad_SetButton(CCPAD_LEFT, mods & WPAD_BUTTON_LEFT);
+ Gamepad_SetButton(CCPAD_RIGHT, mods & WPAD_BUTTON_RIGHT);
+ Gamepad_SetButton(CCPAD_UP, mods & WPAD_BUTTON_UP);
+ Gamepad_SetButton(CCPAD_DOWN, mods & WPAD_BUTTON_DOWN);
}
static void ProcessNunchuck_Game(int mods, double delta) {
WPADData* wd = WPAD_Data(0);
joystick_t analog = wd->exp.nunchuk.js;
- Input_SetNonRepeatable(CCPAD_L, mods & WPAD_NUNCHUK_BUTTON_C);
- Input_SetNonRepeatable(CCPAD_R, mods & WPAD_NUNCHUK_BUTTON_Z);
+ Gamepad_SetButton(CCPAD_L, mods & WPAD_NUNCHUK_BUTTON_C);
+ Gamepad_SetButton(CCPAD_R, mods & WPAD_NUNCHUK_BUTTON_Z);
- Input_SetNonRepeatable(CCPAD_A, mods & WPAD_BUTTON_A);
- Input_SetNonRepeatable(CCPAD_Y, mods & WPAD_BUTTON_1);
- Input_SetNonRepeatable(CCPAD_X, mods & WPAD_BUTTON_2);
+ Gamepad_SetButton(CCPAD_A, mods & WPAD_BUTTON_A);
+ Gamepad_SetButton(CCPAD_Y, mods & WPAD_BUTTON_1);
+ Gamepad_SetButton(CCPAD_X, mods & WPAD_BUTTON_2);
- Input_SetNonRepeatable(CCPAD_START, mods & WPAD_BUTTON_HOME);
- Input_SetNonRepeatable(CCPAD_SELECT, mods & WPAD_BUTTON_MINUS);
+ Gamepad_SetButton(CCPAD_START, mods & WPAD_BUTTON_HOME);
+ Gamepad_SetButton(CCPAD_SELECT, mods & WPAD_BUTTON_MINUS);
- Input_SetNonRepeatable(KeyBinds_Normal[KEYBIND_FLY], mods & WPAD_BUTTON_LEFT);
+ Gamepad_SetButton(KeyBinds_Normal[KEYBIND_FLY], mods & WPAD_BUTTON_LEFT);
if (mods & WPAD_BUTTON_RIGHT) {
Mouse_ScrollWheel(1.0*delta);
}
- Input_SetNonRepeatable(KeyBinds_Normal[KEYBIND_THIRD_PERSON], mods & WPAD_BUTTON_UP);
- Input_SetNonRepeatable(KeyBinds_Normal[KEYBIND_FLY_DOWN], mods & WPAD_BUTTON_DOWN);
+ Gamepad_SetButton(KeyBinds_Normal[KEYBIND_THIRD_PERSON], mods & WPAD_BUTTON_UP);
+ Gamepad_SetButton(KeyBinds_Normal[KEYBIND_FLY_DOWN], mods & WPAD_BUTTON_DOWN);
const float ANGLE_DELTA = 50;
bool nunchuckUp = (analog.ang > -ANGLE_DELTA) && (analog.ang < ANGLE_DELTA) && (analog.mag > 0.5);
@@ -288,57 +270,43 @@ static void ProcessNunchuck_Game(int mods, double delta) {
bool nunchuckLeft = (analog.ang > -90-ANGLE_DELTA) && (analog.ang < -90+ANGLE_DELTA) && (analog.mag > 0.5);
bool nunchuckRight = (analog.ang > 90-ANGLE_DELTA) && (analog.ang < 90+ANGLE_DELTA) && (analog.mag > 0.5);
- Input_SetNonRepeatable(CCPAD_LEFT, nunchuckLeft);
- Input_SetNonRepeatable(CCPAD_RIGHT, nunchuckRight);
- Input_SetNonRepeatable(CCPAD_UP, nunchuckUp);
- Input_SetNonRepeatable(CCPAD_DOWN, nunchuckDown);
+ Gamepad_SetButton(CCPAD_LEFT, nunchuckLeft);
+ Gamepad_SetButton(CCPAD_RIGHT, nunchuckRight);
+ Gamepad_SetButton(CCPAD_UP, nunchuckUp);
+ Gamepad_SetButton(CCPAD_DOWN, nunchuckDown);
}
-
-static void ProcessClassic_LeftJoystick(struct joystick_t* js) {
- // TODO: need to account for min/max??
- int dx = js->pos.x - js->center.x;
- int dy = js->pos.y - js->center.y;
+#define CLASSIC_AXIS_SCALE 2.0f
+static void ProcessClassic_Joystick(int axis, struct joystick_t* js, double delta) {
+ // TODO: need to account for min/max?? see libogc
+ int x = js->pos.x - js->center.x;
+ int y = js->pos.y - js->center.y;
- if (Math_AbsI(dx) <= 8) dx = 0;
- if (Math_AbsI(dy) <= 8) dy = 0;
+ if (Math_AbsI(x) <= 8) x = 0;
+ if (Math_AbsI(y) <= 8) y = 0;
- if (dx == 0 && dy == 0) return;
- Input.JoystickMovement = true;
- Input.JoystickAngle = (js->ang - 90) * MATH_DEG2RAD;
-}
-
-static void ProcessClassic_RightJoystick(struct joystick_t* js, double delta) {
- float scale = (delta * 60.0) / 2.0f;
- // TODO: need to account for min/max??
- int dx = js->pos.x - js->center.x;
- int dy = js->pos.y - js->center.y;
-
- if (Math_AbsI(dx) <= 8) dx = 0;
- if (Math_AbsI(dy) <= 8) dy = 0;
-
- Event_RaiseRawMove(&ControllerEvents.RawMoved, dx * scale, -dy * scale);
+ Gamepad_SetAxis(axis, x / CLASSIC_AXIS_SCALE, -y / CLASSIC_AXIS_SCALE, delta);
}
static void ProcessClassicButtons(int mods) {
- Input_SetNonRepeatable(CCPAD_L, mods & CLASSIC_CTRL_BUTTON_FULL_L);
- Input_SetNonRepeatable(CCPAD_R, mods & CLASSIC_CTRL_BUTTON_FULL_R);
+ Gamepad_SetButton(CCPAD_L, mods & CLASSIC_CTRL_BUTTON_FULL_L);
+ Gamepad_SetButton(CCPAD_R, mods & CLASSIC_CTRL_BUTTON_FULL_R);
- Input_SetNonRepeatable(CCPAD_A, mods & CLASSIC_CTRL_BUTTON_A);
- Input_SetNonRepeatable(CCPAD_B, mods & CLASSIC_CTRL_BUTTON_B);
- Input_SetNonRepeatable(CCPAD_X, mods & CLASSIC_CTRL_BUTTON_X);
- Input_SetNonRepeatable(CCPAD_Y, mods & CLASSIC_CTRL_BUTTON_Y);
+ Gamepad_SetButton(CCPAD_A, mods & CLASSIC_CTRL_BUTTON_A);
+ Gamepad_SetButton(CCPAD_B, mods & CLASSIC_CTRL_BUTTON_B);
+ Gamepad_SetButton(CCPAD_X, mods & CLASSIC_CTRL_BUTTON_X);
+ Gamepad_SetButton(CCPAD_Y, mods & CLASSIC_CTRL_BUTTON_Y);
- Input_SetNonRepeatable(CCPAD_START, mods & CLASSIC_CTRL_BUTTON_PLUS);
- Input_SetNonRepeatable(CCPAD_SELECT, mods & CLASSIC_CTRL_BUTTON_MINUS);
+ Gamepad_SetButton(CCPAD_START, mods & CLASSIC_CTRL_BUTTON_PLUS);
+ Gamepad_SetButton(CCPAD_SELECT, mods & CLASSIC_CTRL_BUTTON_MINUS);
- Input_SetNonRepeatable(CCPAD_LEFT, mods & CLASSIC_CTRL_BUTTON_LEFT);
- Input_SetNonRepeatable(CCPAD_RIGHT, mods & CLASSIC_CTRL_BUTTON_RIGHT);
- Input_SetNonRepeatable(CCPAD_UP, mods & CLASSIC_CTRL_BUTTON_UP);
- Input_SetNonRepeatable(CCPAD_DOWN, mods & CLASSIC_CTRL_BUTTON_DOWN);
+ Gamepad_SetButton(CCPAD_LEFT, mods & CLASSIC_CTRL_BUTTON_LEFT);
+ Gamepad_SetButton(CCPAD_RIGHT, mods & CLASSIC_CTRL_BUTTON_RIGHT);
+ Gamepad_SetButton(CCPAD_UP, mods & CLASSIC_CTRL_BUTTON_UP);
+ Gamepad_SetButton(CCPAD_DOWN, mods & CLASSIC_CTRL_BUTTON_DOWN);
- Input_SetNonRepeatable(CCPAD_ZL, mods & CLASSIC_CTRL_BUTTON_ZL);
- Input_SetNonRepeatable(CCPAD_ZR, mods & CLASSIC_CTRL_BUTTON_ZR);
+ Gamepad_SetButton(CCPAD_ZL, mods & CLASSIC_CTRL_BUTTON_ZL);
+ Gamepad_SetButton(CCPAD_ZR, mods & CLASSIC_CTRL_BUTTON_ZR);
}
static void ProcessClassicInput(double delta) {
@@ -347,10 +315,8 @@ static void ProcessClassicInput(double delta) {
int mods = ctrls.btns | ctrls.btns_held;
ProcessClassicButtons(mods);
- if (Input.RawMode) {
- ProcessClassic_LeftJoystick(&ctrls.ljs);
- ProcessClassic_RightJoystick(&ctrls.rjs, delta);
- }
+ ProcessClassic_Joystick(PAD_AXIS_LEFT, &ctrls.ljs, delta);
+ ProcessClassic_Joystick(PAD_AXIS_RIGHT, &ctrls.rjs, delta);
}
@@ -459,13 +425,13 @@ static u32 CvtRGB (u8 r1, u8 g1, u8 b1, u8 r2, u8 g2, u8 b2)
{
int y1, cb1, cr1, y2, cb2, cr2, cb, cr;
- y1 = (299 * r1 + 587 * g1 + 114 * b1) / 1000;
+ y1 = (299 * r1 + 587 * g1 + 114 * b1) / 1000;
cb1 = (-16874 * r1 - 33126 * g1 + 50000 * b1 + 12800000) / 100000;
- cr1 = (50000 * r1 - 41869 * g1 - 8131 * b1 + 12800000) / 100000;
+ cr1 = (50000 * r1 - 41869 * g1 - 8131 * b1 + 12800000) / 100000;
- y2 = (299 * r2 + 587 * g2 + 114 * b2) / 1000;
+ y2 = (299 * r2 + 587 * g2 + 114 * b2) / 1000;
cb2 = (-16874 * r2 - 33126 * g2 + 50000 * b2 + 12800000) / 100000;
- cr2 = (50000 * r2 - 41869 * g2 - 8131 * b2 + 12800000) / 100000;
+ cr2 = (50000 * r2 - 41869 * g2 - 8131 * b2 + 12800000) / 100000;
cb = (cb1 + cb2) >> 1;
cr = (cr1 + cr2) >> 1;
@@ -538,4 +504,4 @@ cc_result Window_OpenFileDialog(const struct OpenFileDialogArgs* args) {
cc_result Window_SaveFileDialog(const struct SaveFileDialogArgs* args) {
return ERR_NOT_SUPPORTED;
}
-#endif
\ No newline at end of file
+#endif
diff --git a/src/Window_N64.c b/src/Window_N64.c
index 95633005d..ff7aa100c 100644
--- a/src/Window_N64.c
+++ b/src/Window_N64.c
@@ -23,7 +23,6 @@ void Window_Init(void) {
DisplayInfo.Width = display_get_width();
DisplayInfo.Height = display_get_height();
- DisplayInfo.Depth = 4; // 32 bit
DisplayInfo.ScaleX = 0.5f;
DisplayInfo.ScaleY = 0.5f;
@@ -76,35 +75,35 @@ void Window_RequestClose(void) {
*----------------------------------------------------Input processing-----------------------------------------------------*
*#########################################################################################################################*/
static void HandleButtons(joypad_buttons_t btns) {
- Input_SetNonRepeatable(CCPAD_L, btns.l);
- Input_SetNonRepeatable(CCPAD_R, btns.r);
+ Gamepad_SetButton(CCPAD_L, btns.l);
+ Gamepad_SetButton(CCPAD_R, btns.r);
- Input_SetNonRepeatable(CCPAD_A, btns.a);
- Input_SetNonRepeatable(CCPAD_B, btns.b);
- Input_SetNonRepeatable(CCPAD_Z, btns.z);
+ Gamepad_SetButton(CCPAD_A, btns.a);
+ Gamepad_SetButton(CCPAD_B, btns.b);
+ Gamepad_SetButton(CCPAD_Z, btns.z);
- Input_SetNonRepeatable(CCPAD_START, btns.start);
+ Gamepad_SetButton(CCPAD_START, btns.start);
- Input_SetNonRepeatable(CCPAD_LEFT, btns.d_left);
- Input_SetNonRepeatable(CCPAD_RIGHT, btns.d_right);
- Input_SetNonRepeatable(CCPAD_UP, btns.d_up);
- Input_SetNonRepeatable(CCPAD_DOWN, btns.d_down);
-
- Input_SetNonRepeatable(CCPAD_CLEFT, btns.c_left);
- Input_SetNonRepeatable(CCPAD_CRIGHT, btns.c_right);
- Input_SetNonRepeatable(CCPAD_CUP, btns.c_up);
- Input_SetNonRepeatable(CCPAD_CDOWN, btns.c_down);
+ Gamepad_SetButton(CCPAD_LEFT, btns.d_left);
+ Gamepad_SetButton(CCPAD_RIGHT, btns.d_right);
+ Gamepad_SetButton(CCPAD_UP, btns.d_up);
+ Gamepad_SetButton(CCPAD_DOWN, btns.d_down);
+
+ Gamepad_SetButton(CCPAD_CLEFT, btns.c_left);
+ Gamepad_SetButton(CCPAD_CRIGHT, btns.c_right);
+ Gamepad_SetButton(CCPAD_CUP, btns.c_up);
+ Gamepad_SetButton(CCPAD_CDOWN, btns.c_down);
}
+#define AXIS_SCALE 8.0f
static void ProcessAnalogInput(joypad_inputs_t* inputs, double delta) {
- float scale = (delta * 60.0) / 8.0f;
- int dx = inputs->stick_x;
- int dy = inputs->stick_y;
+ int x = inputs->stick_x;
+ int y = inputs->stick_y;
- if (Math_AbsI(dx) <= 8) dx = 0;
- if (Math_AbsI(dy) <= 8) dy = 0;
-
- Event_RaiseRawMove(&ControllerEvents.RawMoved, dx * scale, -dy * scale);
+ if (Math_AbsI(x) <= 8) x = 0;
+ if (Math_AbsI(y) <= 8) y = 0;
+
+ Gamepad_SetAxis(PAD_AXIS_RIGHT, x / AXIS_SCALE, -y / AXIS_SCALE, delta);
}
void Window_ProcessEvents(double delta) {
@@ -112,8 +111,7 @@ void Window_ProcessEvents(double delta) {
joypad_inputs_t inputs = joypad_get_inputs(JOYPAD_PORT_1);
HandleButtons(inputs.btn);
-
- if (Input.RawMode) ProcessAnalogInput(&inputs, delta);
+ ProcessAnalogInput(&inputs, delta);
}
void Cursor_SetPosition(int x, int y) { } // Makes no sense for PSP
diff --git a/src/Window_NDS.c b/src/Window_NDS.c
index b36ee923b..b6e1caba7 100644
--- a/src/Window_NDS.c
+++ b/src/Window_NDS.c
@@ -43,7 +43,6 @@ static void InitConsoleWindow(void) {
void Window_Init(void) {
DisplayInfo.Width = SCREEN_WIDTH;
DisplayInfo.Height = SCREEN_HEIGHT;
- DisplayInfo.Depth = 4; // 32 bit
DisplayInfo.ScaleX = 0.5f;
DisplayInfo.ScaleY = 0.5f;
@@ -98,40 +97,32 @@ void Window_RequestClose(void) {
*----------------------------------------------------Input processing-----------------------------------------------------*
*#########################################################################################################################*/
static void HandleButtons(int mods) {
- Input_SetNonRepeatable(CCPAD_L, mods & KEY_L);
- Input_SetNonRepeatable(CCPAD_R, mods & KEY_R);
+ Gamepad_SetButton(CCPAD_L, mods & KEY_L);
+ Gamepad_SetButton(CCPAD_R, mods & KEY_R);
- Input_SetNonRepeatable(CCPAD_A, mods & KEY_A);
- Input_SetNonRepeatable(CCPAD_B, mods & KEY_B);
- Input_SetNonRepeatable(CCPAD_X, mods & KEY_X);
- Input_SetNonRepeatable(CCPAD_Y, mods & KEY_Y);
+ Gamepad_SetButton(CCPAD_A, mods & KEY_A);
+ Gamepad_SetButton(CCPAD_B, mods & KEY_B);
+ Gamepad_SetButton(CCPAD_X, mods & KEY_X);
+ Gamepad_SetButton(CCPAD_Y, mods & KEY_Y);
- Input_SetNonRepeatable(CCPAD_START, mods & KEY_START);
- Input_SetNonRepeatable(CCPAD_SELECT, mods & KEY_SELECT);
+ Gamepad_SetButton(CCPAD_START, mods & KEY_START);
+ Gamepad_SetButton(CCPAD_SELECT, mods & KEY_SELECT);
- Input_SetNonRepeatable(CCPAD_LEFT, mods & KEY_LEFT);
- Input_SetNonRepeatable(CCPAD_RIGHT, mods & KEY_RIGHT);
- Input_SetNonRepeatable(CCPAD_UP, mods & KEY_UP);
- Input_SetNonRepeatable(CCPAD_DOWN, mods & KEY_DOWN);
+ Gamepad_SetButton(CCPAD_LEFT, mods & KEY_LEFT);
+ Gamepad_SetButton(CCPAD_RIGHT, mods & KEY_RIGHT);
+ Gamepad_SetButton(CCPAD_UP, mods & KEY_UP);
+ Gamepad_SetButton(CCPAD_DOWN, mods & KEY_DOWN);
}
-// Copied from Window_3DS.c
static void ProcessTouchInput(int mods) {
- static int curX, curY; // current touch position
touchPosition touch;
touchRead(&touch);
Camera.Sensitivity = 100; // TODO not hardcode this
- if (keysDown() & KEY_TOUCH) { // stylus went down
- curX = touch.px;
- curY = touch.py;
- Input_AddTouch(0, curX, curY);
- } else if (mods & KEY_TOUCH) { // stylus is down
- curX = touch.px;
- curY = touch.py;
- Input_UpdateTouch(0, curX, curY);
- } else if (keysUp() & KEY_TOUCH) { // stylus was lifted
- Input_RemoveTouch(0, curX, curY);
+ if (mods & KEY_TOUCH) {
+ Input_AddTouch(0, touch.px, touch.py);
+ } else if (keysUp() & KEY_TOUCH) {
+ Input_RemoveTouch(0, Pointers[0].x, Pointers[0].y);
}
}
diff --git a/src/Window_PS1.c b/src/Window_PS1.c
index df1fa58d1..2aaccd497 100644
--- a/src/Window_PS1.c
+++ b/src/Window_PS1.c
@@ -32,7 +32,6 @@ struct _WindowData WindowInfo;
void Window_Init(void) {
DisplayInfo.Width = SCREEN_XRES;
DisplayInfo.Height = SCREEN_YRES;
- DisplayInfo.Depth = 4; // 32 bit
DisplayInfo.ScaleX = 0.5f;
DisplayInfo.ScaleY = 0.5f;
@@ -84,27 +83,40 @@ static void HandleButtons(int buttons) {
// So just flip the bits to make more sense
buttons = ~buttons;
- Input_SetNonRepeatable(CCPAD_A, buttons & PAD_TRIANGLE);
- Input_SetNonRepeatable(CCPAD_B, buttons & PAD_SQUARE);
- Input_SetNonRepeatable(CCPAD_X, buttons & PAD_CROSS);
- Input_SetNonRepeatable(CCPAD_Y, buttons & PAD_CIRCLE);
+ Gamepad_SetButton(CCPAD_A, buttons & PAD_TRIANGLE);
+ Gamepad_SetButton(CCPAD_B, buttons & PAD_SQUARE);
+ Gamepad_SetButton(CCPAD_X, buttons & PAD_CROSS);
+ Gamepad_SetButton(CCPAD_Y, buttons & PAD_CIRCLE);
- Input_SetNonRepeatable(CCPAD_START, buttons & PAD_START);
- Input_SetNonRepeatable(CCPAD_SELECT, buttons & PAD_SELECT);
+ Gamepad_SetButton(CCPAD_START, buttons & PAD_START);
+ Gamepad_SetButton(CCPAD_SELECT, buttons & PAD_SELECT);
- Input_SetNonRepeatable(CCPAD_LEFT, buttons & PAD_LEFT);
- Input_SetNonRepeatable(CCPAD_RIGHT, buttons & PAD_RIGHT);
- Input_SetNonRepeatable(CCPAD_UP, buttons & PAD_UP);
- Input_SetNonRepeatable(CCPAD_DOWN, buttons & PAD_DOWN);
+ Gamepad_SetButton(CCPAD_LEFT, buttons & PAD_LEFT);
+ Gamepad_SetButton(CCPAD_RIGHT, buttons & PAD_RIGHT);
+ Gamepad_SetButton(CCPAD_UP, buttons & PAD_UP);
+ Gamepad_SetButton(CCPAD_DOWN, buttons & PAD_DOWN);
- Input_SetNonRepeatable(CCPAD_L, buttons & PAD_L1);
- Input_SetNonRepeatable(CCPAD_R, buttons & PAD_R1);
- Input_SetNonRepeatable(CCPAD_ZL, buttons & PAD_L2);
- Input_SetNonRepeatable(CCPAD_ZR, buttons & PAD_R2);
+ Gamepad_SetButton(CCPAD_L, buttons & PAD_L1);
+ Gamepad_SetButton(CCPAD_R, buttons & PAD_R1);
+ Gamepad_SetButton(CCPAD_ZL, buttons & PAD_L2);
+ Gamepad_SetButton(CCPAD_ZR, buttons & PAD_R2);
+}
+
+#define AXIS_SCALE 16.0f
+static void HandleJoystick(int axis, int x, int y, double delta) {
+ if (Math_AbsI(x) <= 8) x = 0;
+ if (Math_AbsI(y) <= 8) y = 0;
+
+ Gamepad_SetAxis(axis, x / AXIS_SCALE, y / AXIS_SCALE, delta);
}
static void ProcessPadInput(PADTYPE* pad, double delta) {
HandleButtons(pad->btn);
+
+ if (pad->type == PAD_ID_ANALOG_STICK || pad->type == PAD_ID_ANALOG) {
+ HandleJoystick(PAD_AXIS_LEFT, pad->ls_x - 0x80, pad->ls_y - 0x80, delta);
+ HandleJoystick(PAD_AXIS_RIGHT, pad->rs_x - 0x80, pad->rs_y - 0x80, delta);
+ }
}
void Window_ProcessEvents(double delta) {
diff --git a/src/Window_PS2.c b/src/Window_PS2.c
index d15d93d8d..6a387882e 100644
--- a/src/Window_PS2.c
+++ b/src/Window_PS2.c
@@ -30,7 +30,6 @@ struct _WindowData WindowInfo;
void Window_Init(void) {
DisplayInfo.Width = 640;
DisplayInfo.Height = graph_get_region() == GRAPH_MODE_PAL ? 512 : 448;
- DisplayInfo.Depth = 4; // 32 bit
DisplayInfo.ScaleX = 1;
DisplayInfo.ScaleY = 1;
@@ -90,48 +89,37 @@ static void HandleButtons(int buttons) {
buttons = buttons ^ 0xFFFF;
//Platform_Log1("BUTTONS: %h", &buttons);
- Input_SetNonRepeatable(CCPAD_A, buttons & PAD_TRIANGLE);
- Input_SetNonRepeatable(CCPAD_B, buttons & PAD_SQUARE);
- Input_SetNonRepeatable(CCPAD_X, buttons & PAD_CROSS);
- Input_SetNonRepeatable(CCPAD_Y, buttons & PAD_CIRCLE);
+ Gamepad_SetButton(CCPAD_A, buttons & PAD_TRIANGLE);
+ Gamepad_SetButton(CCPAD_B, buttons & PAD_SQUARE);
+ Gamepad_SetButton(CCPAD_X, buttons & PAD_CROSS);
+ Gamepad_SetButton(CCPAD_Y, buttons & PAD_CIRCLE);
- Input_SetNonRepeatable(CCPAD_START, buttons & PAD_START);
- Input_SetNonRepeatable(CCPAD_SELECT, buttons & PAD_SELECT);
+ Gamepad_SetButton(CCPAD_START, buttons & PAD_START);
+ Gamepad_SetButton(CCPAD_SELECT, buttons & PAD_SELECT);
- Input_SetNonRepeatable(CCPAD_LEFT, buttons & PAD_LEFT);
- Input_SetNonRepeatable(CCPAD_RIGHT, buttons & PAD_RIGHT);
- Input_SetNonRepeatable(CCPAD_UP, buttons & PAD_UP);
- Input_SetNonRepeatable(CCPAD_DOWN, buttons & PAD_DOWN);
+ Gamepad_SetButton(CCPAD_LEFT, buttons & PAD_LEFT);
+ Gamepad_SetButton(CCPAD_RIGHT, buttons & PAD_RIGHT);
+ Gamepad_SetButton(CCPAD_UP, buttons & PAD_UP);
+ Gamepad_SetButton(CCPAD_DOWN, buttons & PAD_DOWN);
- Input_SetNonRepeatable(CCPAD_L, buttons & PAD_L1);
- Input_SetNonRepeatable(CCPAD_R, buttons & PAD_R1);
- Input_SetNonRepeatable(CCPAD_ZL, buttons & PAD_L2);
- Input_SetNonRepeatable(CCPAD_ZR, buttons & PAD_R2);
+ Gamepad_SetButton(CCPAD_L, buttons & PAD_L1);
+ Gamepad_SetButton(CCPAD_R, buttons & PAD_R1);
+ Gamepad_SetButton(CCPAD_ZL, buttons & PAD_L2);
+ Gamepad_SetButton(CCPAD_ZR, buttons & PAD_R2);
}
-static void HandleJoystick_Left(int x, int y) {
- //Platform_Log2("LEFT: %i, %i", &x, &y);
+#define AXIS_SCALE 16.0f
+static void HandleJoystick(int axis, int x, int y, double delta) {
if (Math_AbsI(x) <= 8) x = 0;
if (Math_AbsI(y) <= 8) y = 0;
- if (x == 0 && y == 0) return;
- Input.JoystickMovement = true;
- Input.JoystickAngle = Math_Atan2(x, -y);
-}
-static void HandleJoystick_Right(int x, int y, double delta) {
- //Platform_Log2("Right: %i, %i", &x, &y);
- float scale = (delta * 60.0) / 16.0f;
-
- if (Math_AbsI(x) <= 8) x = 0;
- if (Math_AbsI(y) <= 8) y = 0;
-
- Event_RaiseRawMove(&ControllerEvents.RawMoved, x * scale, y * scale);
+ Gamepad_SetAxis(axis, x / AXIS_SCALE, y / AXIS_SCALE, delta);
}
static void ProcessPadInput(double delta, struct padButtonStatus* pad) {
HandleButtons(pad->btns);
- HandleJoystick_Left( pad->ljoy_h - 0x80, pad->ljoy_v - 0x80);
- HandleJoystick_Right(pad->rjoy_h - 0x80, pad->rjoy_v - 0x80, delta);
+ HandleJoystick(PAD_AXIS_LEFT, pad->ljoy_h - 0x80, pad->ljoy_v - 0x80, delta);
+ HandleJoystick(PAD_AXIS_RIGHT, pad->rjoy_h - 0x80, pad->rjoy_v - 0x80, delta);
}
static cc_bool setMode;
diff --git a/src/Window_PS3.c b/src/Window_PS3.c
index d9e200f22..1b63a27de 100644
--- a/src/Window_PS3.c
+++ b/src/Window_PS3.c
@@ -46,7 +46,6 @@ void Window_Init(void) {
DisplayInfo.Width = resolution.width;
DisplayInfo.Height = resolution.height;
- DisplayInfo.Depth = 4; // 32 bit
DisplayInfo.ScaleX = 1;
DisplayInfo.ScaleY = 1;
@@ -243,50 +242,39 @@ static void ProcessKBTextInput(void) {
*#########################################################################################################################*/
static void HandleButtons(padData* data) {
//Platform_Log2("BUTTONS: %h (%h)", &data->button[2], &data->button[0]);
- Input_SetNonRepeatable(CCPAD_A, data->BTN_TRIANGLE);
- Input_SetNonRepeatable(CCPAD_B, data->BTN_SQUARE);
- Input_SetNonRepeatable(CCPAD_X, data->BTN_CROSS);
- Input_SetNonRepeatable(CCPAD_Y, data->BTN_CIRCLE);
+ Gamepad_SetButton(CCPAD_A, data->BTN_TRIANGLE);
+ Gamepad_SetButton(CCPAD_B, data->BTN_SQUARE);
+ Gamepad_SetButton(CCPAD_X, data->BTN_CROSS);
+ Gamepad_SetButton(CCPAD_Y, data->BTN_CIRCLE);
- Input_SetNonRepeatable(CCPAD_START, data->BTN_START);
- Input_SetNonRepeatable(CCPAD_SELECT, data->BTN_SELECT);
+ Gamepad_SetButton(CCPAD_START, data->BTN_START);
+ Gamepad_SetButton(CCPAD_SELECT, data->BTN_SELECT);
- Input_SetNonRepeatable(CCPAD_LEFT, data->BTN_LEFT);
- Input_SetNonRepeatable(CCPAD_RIGHT, data->BTN_RIGHT);
- Input_SetNonRepeatable(CCPAD_UP, data->BTN_UP);
- Input_SetNonRepeatable(CCPAD_DOWN, data->BTN_DOWN);
+ Gamepad_SetButton(CCPAD_LEFT, data->BTN_LEFT);
+ Gamepad_SetButton(CCPAD_RIGHT, data->BTN_RIGHT);
+ Gamepad_SetButton(CCPAD_UP, data->BTN_UP);
+ Gamepad_SetButton(CCPAD_DOWN, data->BTN_DOWN);
- Input_SetNonRepeatable(CCPAD_L, data->BTN_L1);
- Input_SetNonRepeatable(CCPAD_R, data->BTN_R1);
- Input_SetNonRepeatable(CCPAD_ZL, data->BTN_L2);
- Input_SetNonRepeatable(CCPAD_ZR, data->BTN_R2);
+ Gamepad_SetButton(CCPAD_L, data->BTN_L1);
+ Gamepad_SetButton(CCPAD_R, data->BTN_R1);
+ Gamepad_SetButton(CCPAD_ZL, data->BTN_L2);
+ Gamepad_SetButton(CCPAD_ZR, data->BTN_R2);
}
-static void HandleJoystick_Left(int x, int y) {
+#define AXIS_SCALE 32.0f
+static void HandleJoystick(int axis, int x, int y, double delta) {
if (Math_AbsI(x) <= 32) x = 0;
if (Math_AbsI(y) <= 32) y = 0;
- if (x == 0 && y == 0) return;
- Input.JoystickMovement = true;
- Input.JoystickAngle = Math_Atan2(x, -y);
-}
-
-static void HandleJoystick_Right(int x, int y, double delta) {
- float scale = (delta * 60.0) / 32.0f;
-
- if (Math_AbsI(x) <= 32) x = 0;
- if (Math_AbsI(y) <= 32) y = 0;
-
- Event_RaiseRawMove(&ControllerEvents.RawMoved, x * scale, y * scale);
+ Gamepad_SetAxis(axis, x / AXIS_SCALE, y / AXIS_SCALE, delta);
}
static void ProcessPadInput(double delta, padData* pad) {
HandleButtons(pad);
- HandleJoystick_Left( pad->ANA_L_H - 0x80, pad->ANA_L_V - 0x80);
- HandleJoystick_Right(pad->ANA_R_H - 0x80, pad->ANA_R_V - 0x80, delta);
+ HandleJoystick(PAD_AXIS_LEFT, pad->ANA_L_H - 0x80, pad->ANA_L_V - 0x80, delta);
+ HandleJoystick(PAD_AXIS_RIGHT, pad->ANA_R_H - 0x80, pad->ANA_R_V - 0x80, delta);
}
-
void Window_ProcessEvents(double delta) {
Input.JoystickMovement = false;
@@ -369,4 +357,4 @@ cc_result Window_OpenFileDialog(const struct OpenFileDialogArgs* args) {
cc_result Window_SaveFileDialog(const struct SaveFileDialogArgs* args) {
return ERR_NOT_SUPPORTED;
}
-#endif
\ No newline at end of file
+#endif
diff --git a/src/Window_PSP.c b/src/Window_PSP.c
index 0710b1293..352b4bc1d 100644
--- a/src/Window_PSP.c
+++ b/src/Window_PSP.c
@@ -26,7 +26,6 @@ struct _WindowData WindowInfo;
void Window_Init(void) {
DisplayInfo.Width = SCREEN_WIDTH;
DisplayInfo.Height = SCREEN_HEIGHT;
- DisplayInfo.Depth = 4; // 32 bit
DisplayInfo.ScaleX = 1;
DisplayInfo.ScaleY = 1;
@@ -68,32 +67,32 @@ void Window_RequestClose(void) {
*----------------------------------------------------Input processing-----------------------------------------------------*
*#########################################################################################################################*/
static void HandleButtons(int mods) {
- Input_SetNonRepeatable(CCPAD_L, mods & PSP_CTRL_LTRIGGER);
- Input_SetNonRepeatable(CCPAD_R, mods & PSP_CTRL_RTRIGGER);
+ Gamepad_SetButton(CCPAD_L, mods & PSP_CTRL_LTRIGGER);
+ Gamepad_SetButton(CCPAD_R, mods & PSP_CTRL_RTRIGGER);
- Input_SetNonRepeatable(CCPAD_A, mods & PSP_CTRL_TRIANGLE);
- Input_SetNonRepeatable(CCPAD_B, mods & PSP_CTRL_SQUARE);
- Input_SetNonRepeatable(CCPAD_X, mods & PSP_CTRL_CROSS);
- Input_SetNonRepeatable(CCPAD_Y, mods & PSP_CTRL_CIRCLE);
+ Gamepad_SetButton(CCPAD_A, mods & PSP_CTRL_TRIANGLE);
+ Gamepad_SetButton(CCPAD_B, mods & PSP_CTRL_SQUARE);
+ Gamepad_SetButton(CCPAD_X, mods & PSP_CTRL_CROSS);
+ Gamepad_SetButton(CCPAD_Y, mods & PSP_CTRL_CIRCLE);
- Input_SetNonRepeatable(CCPAD_START, mods & PSP_CTRL_START);
- Input_SetNonRepeatable(CCPAD_SELECT, mods & PSP_CTRL_SELECT);
+ Gamepad_SetButton(CCPAD_START, mods & PSP_CTRL_START);
+ Gamepad_SetButton(CCPAD_SELECT, mods & PSP_CTRL_SELECT);
- Input_SetNonRepeatable(CCPAD_LEFT, mods & PSP_CTRL_LEFT);
- Input_SetNonRepeatable(CCPAD_RIGHT, mods & PSP_CTRL_RIGHT);
- Input_SetNonRepeatable(CCPAD_UP, mods & PSP_CTRL_UP);
- Input_SetNonRepeatable(CCPAD_DOWN, mods & PSP_CTRL_DOWN);
+ Gamepad_SetButton(CCPAD_LEFT, mods & PSP_CTRL_LEFT);
+ Gamepad_SetButton(CCPAD_RIGHT, mods & PSP_CTRL_RIGHT);
+ Gamepad_SetButton(CCPAD_UP, mods & PSP_CTRL_UP);
+ Gamepad_SetButton(CCPAD_DOWN, mods & PSP_CTRL_DOWN);
}
+#define AXIS_SCALE 16.0f
static void ProcessCircleInput(SceCtrlData* pad, double delta) {
- float scale = (delta * 60.0) / 16.0f;
- int dx = pad->Lx - 127;
- int dy = pad->Ly - 127;
+ int x = pad->Lx - 127;
+ int y = pad->Ly - 127;
- if (Math_AbsI(dx) <= 8) dx = 0;
- if (Math_AbsI(dy) <= 8) dy = 0;
+ if (Math_AbsI(x) <= 8) x = 0;
+ if (Math_AbsI(y) <= 8) y = 0;
- Event_RaiseRawMove(&ControllerEvents.RawMoved, dx * scale, dy * scale);
+ Gamepad_SetAxis(PAD_AXIS_RIGHT, x / AXIS_SCALE, y / AXIS_SCALE, delta);
}
void Window_ProcessEvents(double delta) {
@@ -104,8 +103,7 @@ void Window_ProcessEvents(double delta) {
// TODO: need to use cached version still? like GameCube/Wii
HandleButtons(pad.Buttons);
- if (Input.RawMode)
- ProcessCircleInput(&pad, delta);
+ ProcessCircleInput(&pad, delta);
}
void Cursor_SetPosition(int x, int y) { } // Makes no sense for PSP
diff --git a/src/Window_PSVita.c b/src/Window_PSVita.c
index 2f0638921..db53ec586 100644
--- a/src/Window_PSVita.c
+++ b/src/Window_PSVita.c
@@ -33,7 +33,6 @@ static void DQ_OnNextFrame2D(void* fb);
void Window_Init(void) {
DisplayInfo.Width = DISPLAY_WIDTH;
DisplayInfo.Height = DISPLAY_HEIGHT;
- DisplayInfo.Depth = 4; // 32 bit
DisplayInfo.ScaleX = 1;
DisplayInfo.ScaleY = 1;
@@ -42,7 +41,9 @@ void Window_Init(void) {
Window_Main.Focused = true;
Window_Main.Exists = true;
+ Input_SetTouchMode(true);
Input.Sources = INPUT_SOURCE_GAMEPAD;
+
sceCtrlSetSamplingMode(SCE_CTRL_MODE_ANALOG);
sceTouchSetSamplingState(SCE_TOUCH_PORT_FRONT, SCE_TOUCH_SAMPLING_STATE_START);
sceTouchSetSamplingState(SCE_TOUCH_PORT_BACK, SCE_TOUCH_SAMPLING_STATE_START);
@@ -85,59 +86,42 @@ void Window_RequestClose(void) {
*----------------------------------------------------Input processing-----------------------------------------------------*
*#########################################################################################################################*/
static void HandleButtons(int mods) {
- Input_SetNonRepeatable(CCPAD_A, mods & SCE_CTRL_TRIANGLE);
- Input_SetNonRepeatable(CCPAD_B, mods & SCE_CTRL_SQUARE);
- Input_SetNonRepeatable(CCPAD_X, mods & SCE_CTRL_CROSS);
- Input_SetNonRepeatable(CCPAD_Y, mods & SCE_CTRL_CIRCLE);
+ Gamepad_SetButton(CCPAD_A, mods & SCE_CTRL_TRIANGLE);
+ Gamepad_SetButton(CCPAD_B, mods & SCE_CTRL_SQUARE);
+ Gamepad_SetButton(CCPAD_X, mods & SCE_CTRL_CROSS);
+ Gamepad_SetButton(CCPAD_Y, mods & SCE_CTRL_CIRCLE);
- Input_SetNonRepeatable(CCPAD_START, mods & SCE_CTRL_START);
- Input_SetNonRepeatable(CCPAD_SELECT, mods & SCE_CTRL_SELECT);
-
- Input_SetNonRepeatable(CCPAD_LEFT, mods & SCE_CTRL_LEFT);
- Input_SetNonRepeatable(CCPAD_RIGHT, mods & SCE_CTRL_RIGHT);
- Input_SetNonRepeatable(CCPAD_UP, mods & SCE_CTRL_UP);
- Input_SetNonRepeatable(CCPAD_DOWN, mods & SCE_CTRL_DOWN);
-
- Input_SetNonRepeatable(CCPAD_L, mods & SCE_CTRL_LTRIGGER);
- Input_SetNonRepeatable(CCPAD_R, mods & SCE_CTRL_RTRIGGER);
-}
+ Gamepad_SetButton(CCPAD_START, mods & SCE_CTRL_START);
+ Gamepad_SetButton(CCPAD_SELECT, mods & SCE_CTRL_SELECT);
-static void ProcessLCircleInput(SceCtrlData* pad) {
- int dx = pad->lx - 127;
- int dy = pad->ly - 127;
+ Gamepad_SetButton(CCPAD_LEFT, mods & SCE_CTRL_LEFT);
+ Gamepad_SetButton(CCPAD_RIGHT, mods & SCE_CTRL_RIGHT);
+ Gamepad_SetButton(CCPAD_UP, mods & SCE_CTRL_UP);
+ Gamepad_SetButton(CCPAD_DOWN, mods & SCE_CTRL_DOWN);
- if (Math_AbsI(dx) <= 8) dx = 0;
- if (Math_AbsI(dy) <= 8) dy = 0;
-
- if (dx == 0 && dy == 0) return;
- Input.JoystickMovement = true;
- Input.JoystickAngle = Math_Atan2(dx, dy);
+ Gamepad_SetButton(CCPAD_L, mods & SCE_CTRL_LTRIGGER);
+ Gamepad_SetButton(CCPAD_R, mods & SCE_CTRL_RTRIGGER);
}
-static void ProcessRCircleInput(SceCtrlData* pad, double delta) {
- float scale = (delta * 60.0) / 16.0f;
- int dx = pad->rx - 127;
- int dy = pad->ry - 127;
-
- if (Math_AbsI(dx) <= 8) dx = 0;
- if (Math_AbsI(dy) <= 8) dy = 0;
+#define AXIS_SCALE 16.0f
+static void ProcessCircleInput(int axis, int x, int y, double delta) {
+ // May not be exactly 0 on actual hardware
+ if (Math_AbsI(x) <= 8) x = 0;
+ if (Math_AbsI(y) <= 8) y = 0;
- Event_RaiseRawMove(&ControllerEvents.RawMoved, dx * scale, dy * scale);
+ Gamepad_SetAxis(axis, x / AXIS_SCALE, y / AXIS_SCALE, delta);
}
-static void ProcessTouchPress(int x, int y) {
- if (!frontPanel.maxDispX || !frontPanel.maxDispY) {
- // TODO: Shouldn't ever happen? need to check
- Pointer_SetPosition(0, x, y);
- return;
- }
+static void AdjustTouchPress(int* x, int* y) {
+ if (!frontPanel.maxDispX || !frontPanel.maxDispY) return;
+ // TODO: Shouldn't ever happen? need to check
// rescale from touch range to screen range
- x = (x - frontPanel.minDispX) * DISPLAY_WIDTH / frontPanel.maxDispX;
- y = (y - frontPanel.minDispY) * DISPLAY_HEIGHT / frontPanel.maxDispY;
- Pointer_SetPosition(0, x, y);
+ *x = (*x - frontPanel.minDispX) * DISPLAY_WIDTH / frontPanel.maxDispX;
+ *y = (*y - frontPanel.minDispY) * DISPLAY_HEIGHT / frontPanel.maxDispY;
}
+static cc_bool touch_pressed;
static void ProcessTouchInput(void) {
SceTouchData touch;
@@ -146,12 +130,19 @@ static void ProcessTouchInput(void) {
if (res == 0) return; // no data available yet
if (res < 0) return; // error occurred
- if (touch.reportNum > 0) {
+ cc_bool isPressed = touch.reportNum > 0;
+ if (isPressed) {
int x = touch.report[0].x;
int y = touch.report[0].y;
- ProcessTouchPress(x, y);
+ AdjustTouchPress(&x, &y);
+
+ Input_AddTouch(0, x, y);
+ touch_pressed = true;
+ } else if (touch_pressed) {
+ // touch.report[0].xy will be 0 when touch.reportNum is 0
+ Input_RemoveTouch(0, Pointers[0].x, Pointers[0].y);
+ touch_pressed = false;
}
- Input_SetNonRepeatable(CCMOUSE_L, touch.reportNum > 0);
}
static void ProcessPadInput(double delta) {
@@ -164,10 +155,8 @@ static void ProcessPadInput(double delta) {
// TODO: need to use cached version still? like GameCube/Wii
HandleButtons(pad.buttons);
- if (Input.RawMode) {
- ProcessLCircleInput(&pad);
- ProcessRCircleInput(&pad, delta);
- }
+ ProcessCircleInput(PAD_AXIS_LEFT, pad.lx - 127, pad.ly - 127, delta);
+ ProcessCircleInput(PAD_AXIS_RIGHT, pad.rx - 127, pad.ry - 127, delta);
}
void Window_ProcessEvents(double delta) {
diff --git a/src/Window_SDL.c b/src/Window_SDL.c
index a6fcff2d6..8360878d5 100644
--- a/src/Window_SDL.c
+++ b/src/Window_SDL.c
@@ -1,5 +1,5 @@
#include "Core.h"
-#if defined CC_BUILD_SDL
+#if defined CC_BUILD_SDL2
#include "_WindowBase.h"
#include "Graphics.h"
#include "String.h"
@@ -11,8 +11,33 @@ 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
+#define INCL_PM
+#include
+// Internal OS/2 driver data
+typedef struct _WINDATA {
+ SDL_Window *window;
+ void *pOutput; /* Video output routines */
+ HWND hwndFrame;
+ HWND hwnd;
+ PFNWP fnUserWndProc;
+ PFNWP fnWndFrameProc;
+
+ void *pVOData; /* Video output data */
+
+ HRGN hrgnShape;
+ HPOINTER hptrIcon;
+ RECTL rectlBeforeFS;
+
+ LONG lSkipWMSize;
+ LONG lSkipWMMove;
+ LONG lSkipWMMouseMove;
+ LONG lSkipWMVRNEnabled;
+ LONG lSkipWMAdjustFramePos;
+} WINDATA;
#endif
+
static void RefreshWindowBounds(void) {
SDL_GetWindowSize(win_handle, &Window_Main.Width, &Window_Main.Height);
}
@@ -43,10 +68,7 @@ void Window_Init(void) {
void Window_Free(void) { }
static void DoCreateWindow(int width, int height, int flags) {
- int x = Display_CentreX(width);
- int y = Display_CentreY(height);
-
- win_handle = SDL_CreateWindow(NULL, x, y, width, height,
+ win_handle = SDL_CreateWindow(NULL, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height,
flags | SDL_WINDOW_RESIZABLE);
if (!win_handle) Window_SDLFail("creating window");
@@ -289,11 +311,53 @@ static void ShowDialogCore(const char* title, const char* msg) {
}
cc_result Window_OpenFileDialog(const struct OpenFileDialogArgs* args) {
+#if defined CC_BUILD_OS2
+ FILEDLG fileDialog;
+ HWND hDialog;
+
+ memset(&fileDialog, 0, sizeof(FILEDLG));
+ fileDialog.cbSize = sizeof(FILEDLG);
+ fileDialog.fl = FDS_HELPBUTTON | FDS_CENTER | FDS_PRELOAD_VOLINFO | FDS_OPEN_DIALOG;
+ fileDialog.pszTitle = args->description;
+ fileDialog.pszOKButton = NULL;
+ fileDialog.pfnDlgProc = WinDefFileDlgProc;
+
+ Mem_Copy(fileDialog.szFullFile, *args->filters, CCHMAXPATH);
+ hDialog = WinFileDlg(HWND_DESKTOP, 0, &fileDialog);
+ if (fileDialog.lReturn == DID_OK) {
+ cc_string temp = String_FromRaw(fileDialog.szFullFile, CCHMAXPATH);
+ args->Callback(&temp);
+ }
+
+ return 0;
+#else
return ERR_NOT_SUPPORTED;
+#endif
}
cc_result Window_SaveFileDialog(const struct SaveFileDialogArgs* args) {
+#if defined CC_BUILD_OS2
+ FILEDLG fileDialog;
+ HWND hDialog;
+
+ memset(&fileDialog, 0, sizeof(FILEDLG));
+ fileDialog.cbSize = sizeof(FILEDLG);
+ fileDialog.fl = FDS_HELPBUTTON | FDS_CENTER | FDS_PRELOAD_VOLINFO | FDS_SAVEAS_DIALOG;
+ fileDialog.pszTitle = args->titles;
+ fileDialog.pszOKButton = NULL;
+ fileDialog.pfnDlgProc = WinDefFileDlgProc;
+
+ Mem_Copy(fileDialog.szFullFile, *args->filters, CCHMAXPATH);
+ hDialog = WinFileDlg(HWND_DESKTOP, 0, &fileDialog);
+ if (fileDialog.lReturn == DID_OK) {
+ cc_string temp = String_FromRaw(fileDialog.szFullFile, CCHMAXPATH);
+ args->Callback(&temp);
+ }
+
+ return 0;
+#else
return ERR_NOT_SUPPORTED;
+#endif
}
static SDL_Surface* win_surface;
@@ -376,6 +440,9 @@ void GLContext_Create(void) {
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, GLCONTEXT_DEFAULT_DEPTH);
SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 0);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, true);
+#ifdef CC_BUILD_GLES
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
+#endif
win_ctx = SDL_GL_CreateContext(win_handle);
if (!win_ctx) Window_SDLFail("creating OpenGL context");
diff --git a/src/Window_SDL3.c b/src/Window_SDL3.c
new file mode 100644
index 000000000..d4731b1fe
--- /dev/null
+++ b/src/Window_SDL3.c
@@ -0,0 +1,502 @@
+#include "Core.h"
+#if defined CC_BUILD_SDL3
+#include "_WindowBase.h"
+#include "Graphics.h"
+#include "String.h"
+#include "Funcs.h"
+#include "Bitmap.h"
+#include "Errors.h"
+#include
+static SDL_Window* win_handle;
+static Uint32 dlg_event;
+
+static void RefreshWindowBounds(void) {
+ SDL_GetWindowSize(win_handle, &Window_Main.Width, &Window_Main.Height);
+}
+
+static void Window_SDLFail(const char* place) {
+ char strBuffer[256];
+ cc_string str;
+ String_InitArray_NT(str, strBuffer);
+
+ String_Format2(&str, "Error when %c: %c", place, SDL_GetError());
+ str.buffer[str.length] = '\0';
+ Logger_Abort(str.buffer);
+}
+
+void Window_Init(void) {
+ SDL_Init(SDL_INIT_VIDEO);
+ #ifdef CC_BUILD_FLATPAK
+ SDL_SetHint(SDL_HINT_APP_ID, "net.classicube.flatpak.client");
+ #endif
+ int displayID = SDL_GetPrimaryDisplay();
+ Input.Sources = INPUT_SOURCE_NORMAL;
+
+ const SDL_DisplayMode* mode = SDL_GetDesktopDisplayMode(displayID);
+ dlg_event = SDL_RegisterEvents(1);
+
+ DisplayInfo.Width = mode->w;
+ DisplayInfo.Height = mode->h;
+ DisplayInfo.Depth = SDL_BITSPERPIXEL(mode->format);
+ DisplayInfo.ScaleX = 1;
+ DisplayInfo.ScaleY = 1;
+}
+
+void Window_Free(void) { }
+
+static void DoCreateWindow(int width, int height, int flags) {
+ SDL_PropertiesID props = SDL_CreateProperties();
+ SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_X_NUMBER, SDL_WINDOWPOS_CENTERED);
+ SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_Y_NUMBER, SDL_WINDOWPOS_CENTERED);
+ SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_WIDTH_NUMBER, width);
+ SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_HEIGHT_NUMBER, height);
+ SDL_SetNumberProperty(props, "flags", flags | SDL_WINDOW_RESIZABLE);
+
+ win_handle = SDL_CreateWindowWithProperties(props);
+ if (!win_handle) Window_SDLFail("creating window");
+ SDL_DestroyProperties(props);
+
+ RefreshWindowBounds();
+ Window_Main.Exists = true;
+ Window_Main.Handle = win_handle;
+ /* TODO grab using SDL_SetWindowGrab? seems to be unnecessary on Linux at least */
+}
+void Window_Create2D(int width, int height) { DoCreateWindow(width, height, 0); }
+void Window_Create3D(int width, int height) { DoCreateWindow(width, height, SDL_WINDOW_OPENGL); }
+
+void Window_SetTitle(const cc_string* title) {
+ char str[NATIVE_STR_LEN];
+ String_EncodeUtf8(str, title);
+ SDL_SetWindowTitle(win_handle, str);
+}
+
+void Clipboard_GetText(cc_string* value) {
+ char* ptr = SDL_GetClipboardText();
+ if (!ptr) return;
+
+ int len = String_Length(ptr);
+ String_AppendUtf8(value, ptr, len);
+ SDL_free(ptr);
+}
+
+void Clipboard_SetText(const cc_string* value) {
+ char str[NATIVE_STR_LEN];
+ String_EncodeUtf8(str, value);
+ SDL_SetClipboardText(str);
+}
+
+int Window_GetWindowState(void) {
+ Uint32 flags = SDL_GetWindowFlags(win_handle);
+
+ if (flags & SDL_WINDOW_MINIMIZED) return WINDOW_STATE_MINIMISED;
+ if (flags & SDL_WINDOW_FULLSCREEN) return WINDOW_STATE_FULLSCREEN;
+ return WINDOW_STATE_NORMAL;
+}
+
+cc_result Window_EnterFullscreen(void) {
+ return SDL_SetWindowFullscreen(win_handle, true);
+}
+cc_result Window_ExitFullscreen(void) {
+ return SDL_SetWindowFullscreen(win_handle, false);
+}
+
+int Window_IsObscured(void) {
+ Uint32 flags = SDL_GetWindowFlags(win_handle);
+ return flags & SDL_WINDOW_OCCLUDED;
+}
+
+void Window_Show(void) {
+ SDL_ShowWindow(win_handle);
+}
+
+void Window_SetSize(int width, int height) {
+ SDL_SetWindowSize(win_handle, width, height);
+}
+
+void Window_RequestClose(void) {
+ SDL_Event e;
+ e.type = SDL_EVENT_QUIT;
+ SDL_PushEvent(&e);
+}
+
+static int MapNativeKey(SDL_Keycode k) {
+ if (k >= SDLK_0 && k <= SDLK_9) { return '0' + (k - SDLK_0); }
+ if (k >= SDLK_a && k <= SDLK_z) { return 'A' + (k - SDLK_a); }
+ if (k >= SDLK_F1 && k <= SDLK_F12) { return CCKEY_F1 + (k - SDLK_F1); }
+ if (k >= SDLK_F13 && k <= SDLK_F24) { return CCKEY_F13 + (k - SDLK_F13); }
+ /* SDLK_KP_0 isn't before SDLK_KP_1 */
+ if (k >= SDLK_KP_1 && k <= SDLK_KP_9) { return CCKEY_KP1 + (k - SDLK_KP_1); }
+
+ switch (k) {
+ case SDLK_RETURN: return CCKEY_ENTER;
+ case SDLK_ESCAPE: return CCKEY_ESCAPE;
+ case SDLK_BACKSPACE: return CCKEY_BACKSPACE;
+ case SDLK_TAB: return CCKEY_TAB;
+ case SDLK_SPACE: return CCKEY_SPACE;
+ case SDLK_QUOTE: return CCKEY_QUOTE;
+ case SDLK_EQUALS: return CCKEY_EQUALS;
+ case SDLK_COMMA: return CCKEY_COMMA;
+ case SDLK_MINUS: return CCKEY_MINUS;
+ case SDLK_PERIOD: return CCKEY_PERIOD;
+ case SDLK_SLASH: return CCKEY_SLASH;
+ case SDLK_SEMICOLON: return CCKEY_SEMICOLON;
+ case SDLK_LEFTBRACKET: return CCKEY_LBRACKET;
+ case SDLK_BACKSLASH: return CCKEY_BACKSLASH;
+ case SDLK_RIGHTBRACKET: return CCKEY_RBRACKET;
+ case SDLK_BACKQUOTE: return CCKEY_TILDE;
+ case SDLK_CAPSLOCK: return CCKEY_CAPSLOCK;
+ case SDLK_PRINTSCREEN: return CCKEY_PRINTSCREEN;
+ case SDLK_SCROLLLOCK: return CCKEY_SCROLLLOCK;
+ case SDLK_PAUSE: return CCKEY_PAUSE;
+ case SDLK_INSERT: return CCKEY_INSERT;
+ case SDLK_HOME: return CCKEY_HOME;
+ case SDLK_PAGEUP: return CCKEY_PAGEUP;
+ case SDLK_DELETE: return CCKEY_DELETE;
+ case SDLK_END: return CCKEY_END;
+ case SDLK_PAGEDOWN: return CCKEY_PAGEDOWN;
+ case SDLK_RIGHT: return CCKEY_RIGHT;
+ case SDLK_LEFT: return CCKEY_LEFT;
+ case SDLK_DOWN: return CCKEY_DOWN;
+ case SDLK_UP: return CCKEY_UP;
+
+ case SDLK_NUMLOCKCLEAR: return CCKEY_NUMLOCK;
+ case SDLK_KP_DIVIDE: return CCKEY_KP_DIVIDE;
+ case SDLK_KP_MULTIPLY: return CCKEY_KP_MULTIPLY;
+ case SDLK_KP_MINUS: return CCKEY_KP_MINUS;
+ case SDLK_KP_PLUS: return CCKEY_KP_PLUS;
+ case SDLK_KP_ENTER: return CCKEY_KP_ENTER;
+ case SDLK_KP_0: return CCKEY_KP0;
+ case SDLK_KP_PERIOD: return CCKEY_KP_DECIMAL;
+
+ case SDLK_LCTRL: return CCKEY_LCTRL;
+ case SDLK_LSHIFT: return CCKEY_LSHIFT;
+ case SDLK_LALT: return CCKEY_LALT;
+ case SDLK_LGUI: return CCKEY_LWIN;
+ case SDLK_RCTRL: return CCKEY_RCTRL;
+ case SDLK_RSHIFT: return CCKEY_RSHIFT;
+ case SDLK_RALT: return CCKEY_RALT;
+ case SDLK_RGUI: return CCKEY_RWIN;
+ }
+ return INPUT_NONE;
+}
+
+static void OnKeyEvent(const SDL_Event* e) {
+ cc_bool pressed = e->key.state == SDL_PRESSED;
+ int key = MapNativeKey(e->key.keysym.sym);
+ if (key) Input_Set(key, pressed);
+}
+
+static void OnMouseEvent(const SDL_Event* e) {
+ cc_bool pressed = e->button.state == SDL_PRESSED;
+ int btn;
+ switch (e->button.button) {
+ case SDL_BUTTON_LEFT: btn = CCMOUSE_L; break;
+ case SDL_BUTTON_MIDDLE: btn = CCMOUSE_M; break;
+ case SDL_BUTTON_RIGHT: btn = CCMOUSE_R; break;
+ case SDL_BUTTON_X1: btn = CCMOUSE_X1; break;
+ case SDL_BUTTON_X2: btn = CCMOUSE_X2; break;
+ default: return;
+ }
+ Input_Set(btn, pressed);
+}
+
+static void OnTextEvent(const SDL_Event* e) {
+ cc_codepoint cp;
+ const char* src;
+ int i, len;
+
+ src = e->text.text;
+ len = String_Length(src);
+
+ while (len > 0) {
+ i = Convert_Utf8ToCodepoint(&cp, src, len);
+ if (!i) break;
+
+ Event_RaiseInt(&InputEvents.Press, cp);
+ src += i; len -= i;
+ }
+}
+static void ProcessDialogEvent(SDL_Event* e);
+
+void Window_ProcessEvents(double delta) {
+ SDL_Event e;
+ while (SDL_PollEvent(&e)) {
+ switch (e.type) {
+
+ case SDL_EVENT_KEY_DOWN:
+ case SDL_EVENT_KEY_UP:
+ OnKeyEvent(&e); break;
+ case SDL_EVENT_MOUSE_BUTTON_DOWN:
+ case SDL_EVENT_MOUSE_BUTTON_UP:
+ OnMouseEvent(&e); break;
+ case SDL_EVENT_MOUSE_WHEEL:
+ Mouse_ScrollWheel(e.wheel.y);
+ break;
+ case SDL_EVENT_MOUSE_MOTION:
+ Pointer_SetPosition(0, e.motion.x, e.motion.y);
+ if (Input.RawMode) Event_RaiseRawMove(&PointerEvents.RawMoved, e.motion.xrel, e.motion.yrel);
+ break;
+ case SDL_EVENT_TEXT_INPUT:
+ OnTextEvent(&e); break;
+
+ case SDL_EVENT_QUIT:
+ Window_Main.Exists = false;
+ Event_RaiseVoid(&WindowEvents.Closing);
+ SDL_DestroyWindow(win_handle);
+ break;
+
+ case SDL_EVENT_RENDER_DEVICE_RESET:
+ Gfx_LoseContext("SDL device reset event");
+ Gfx_RecreateContext();
+ break;
+
+
+ case SDL_EVENT_WINDOW_EXPOSED:
+ Event_RaiseVoid(&WindowEvents.RedrawNeeded);
+ break;
+ case SDL_EVENT_WINDOW_RESIZED: // TODO SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED
+ RefreshWindowBounds();
+ Event_RaiseVoid(&WindowEvents.Resized);
+ break;
+ case SDL_EVENT_WINDOW_MINIMIZED:
+ case SDL_EVENT_WINDOW_MAXIMIZED:
+ case SDL_EVENT_WINDOW_RESTORED:
+ Event_RaiseVoid(&WindowEvents.StateChanged);
+ break;
+ case SDL_EVENT_WINDOW_FOCUS_GAINED:
+ Window_Main.Focused = true;
+ Event_RaiseVoid(&WindowEvents.FocusChanged);
+ break;
+ case SDL_EVENT_WINDOW_FOCUS_LOST:
+ Window_Main.Focused = false;
+ Event_RaiseVoid(&WindowEvents.FocusChanged);
+ break;
+ case SDL_EVENT_WINDOW_CLOSE_REQUESTED:
+ Window_RequestClose();
+ break;
+ default:
+ if (e.type == dlg_event) ProcessDialogEvent(&e);
+ break;
+ }
+ }
+}
+
+static void Cursor_GetRawPos(int* x, int* y) {
+ float xPos, yPos;
+ SDL_GetMouseState(&xPos, &yPos);
+ *x = xPos; *y = yPos;
+}
+void Cursor_SetPosition(int x, int y) {
+ SDL_WarpMouseInWindow(win_handle, x, y);
+}
+
+static void Cursor_DoSetVisible(cc_bool visible) {
+ if (visible) {
+ SDL_ShowCursor();
+ } else {
+ SDL_HideCursor();
+ }
+}
+
+static void ShowDialogCore(const char* title, const char* msg) {
+ SDL_ShowSimpleMessageBox(0, title, msg, win_handle);
+}
+
+static FileDialogCallback dlgCallback;
+static SDL_DialogFileFilter* save_filters;
+
+static void ProcessDialogEvent(SDL_Event* e) {
+ char* result = e->user.data1;
+ int length = e->user.code;
+
+ cc_string path; char pathBuffer[1024];
+ String_InitArray(path, pathBuffer);
+ String_AppendUtf8(&path, result, length);
+
+ dlgCallback(&path);
+ dlgCallback = NULL;
+ Mem_Free(result);
+}
+
+static void DialogCallback(void *userdata, const char* const* filelist, int filter) {
+ if (!filelist) return; /* Error occurred */
+ const char* result = filelist[0];
+ if (!result) return; /* No file provided */
+
+ char* path = Mem_Alloc(NATIVE_STR_LEN, 1, "Dialog path");
+ cc_string str = String_Init(path, 0, NATIVE_STR_LEN);
+ String_AppendUtf8(&str, result, String_Length(result));
+
+ // May need to add file extension when saving, e.g. on Windows
+ if (save_filters && filter >= 0 && save_filters[filter].pattern)
+ String_Format1(&str, ".%c", save_filters[filter].pattern);
+
+ // Dialog callback may not be called from the main thread
+ // (E.g. on windows it is called from a background thread)
+ SDL_Event e = { 0 };
+ e.type = SDL_EVENT_USER;
+ e.user.code = str.length;
+ e.user.data1 = path;
+ SDL_PushEvent(&e);
+}
+
+cc_result Window_OpenFileDialog(const struct OpenFileDialogArgs* args) {
+ // TODO free memory
+ char* pattern = Mem_Alloc(301, 1, "OpenDialog pattern");
+ SDL_DialogFileFilter* filters = Mem_Alloc(2, sizeof(SDL_DialogFileFilter), "OpenDialog filters");
+ int i;
+
+ cc_string str = String_Init(pattern, 0, 300);
+ for (i = 0; ; i++)
+ {
+ if (!args->filters[i]) break;
+ if (i) String_Append(&str, ';');
+ String_AppendConst(&str, args->filters[i] + 1);
+ }
+
+ pattern[str.length] = '\0';
+ filters[0].name = args->description;
+ filters[0].pattern = pattern;
+ filters[1].name = NULL;
+ filters[1].pattern = NULL;
+
+ dlgCallback = args->Callback;
+ save_filters = NULL;
+ SDL_ShowOpenFileDialog(DialogCallback, NULL, win_handle, filters, NULL, false);
+ return 0;
+}
+
+#define MAX_SAVE_DIALOG_FILTERS 10
+cc_result Window_SaveFileDialog(const struct SaveFileDialogArgs* args) {
+ // TODO free memory
+ char* defName = Mem_Alloc(NATIVE_STR_LEN, 1, "SaveDialog default");
+ SDL_DialogFileFilter* filters = Mem_Alloc(MAX_SAVE_DIALOG_FILTERS + 1, sizeof(SDL_DialogFileFilter), "SaveDialog filters");
+ int i;
+ String_EncodeUtf8(defName, &args->defaultName);
+
+ for (i = 0; i < MAX_SAVE_DIALOG_FILTERS; i++)
+ {
+ if (!args->filters[i]) break;
+ filters[i].name = args->titles[i];
+ filters[i].pattern = args->filters[i] + 1; // skip .
+ }
+
+ filters[i].name = NULL;
+ filters[i].pattern = NULL;
+
+ dlgCallback = args->Callback;
+ save_filters = filters;
+ SDL_ShowSaveFileDialog(DialogCallback, NULL, win_handle, filters, defName);
+ return 0;
+}
+
+static SDL_Surface* win_surface;
+static SDL_Surface* blit_surface;
+
+void Window_AllocFramebuffer(struct Bitmap* bmp) {
+ SDL_PixelFormat* fmt;
+ win_surface = SDL_GetWindowSurface(win_handle);
+ if (!win_surface) Window_SDLFail("getting window surface");
+
+ fmt = win_surface->format;
+ if (fmt->bits_per_pixel != 32) {
+ /* Slow path: e.g. 15 or 16 bit pixels */
+ Platform_Log1("Slow color depth: %b bpp", &fmt->bits_per_pixel);
+ blit_surface = SDL_CreateSurface(win_surface->w, win_surface->h, SDL_PIXELFORMAT_RGBA32);
+ if (!blit_surface) Window_SDLFail("creating blit surface");
+
+ SDL_SetSurfaceBlendMode(blit_surface, SDL_BLENDMODE_NONE);
+ bmp->scan0 = blit_surface->pixels;
+ } else {
+ /* Fast path: 32 bit pixels */
+ if (SDL_MUSTLOCK(win_surface)) {
+ int ret = SDL_LockSurface(win_surface);
+ if (ret < 0) Window_SDLFail("locking window surface");
+ }
+ bmp->scan0 = win_surface->pixels;
+ }
+}
+
+void Window_DrawFramebuffer(Rect2D r, struct Bitmap* bmp) {
+ SDL_Rect rect;
+ rect.x = r.x; rect.w = r.Width;
+ rect.y = r.y; rect.h = r.Height;
+
+ if (blit_surface) SDL_BlitSurface(blit_surface, &rect, win_surface, &rect);
+ SDL_UpdateWindowSurfaceRects(win_handle, &rect, 1);
+}
+
+void Window_FreeFramebuffer(struct Bitmap* bmp) {
+ if (blit_surface) SDL_DestroySurface(blit_surface);
+ blit_surface = NULL;
+
+ /* SDL docs explicitly say to NOT free window surface */
+ /* https://wiki.libsdl.org/SDL_GetWindowSurface */
+ /* TODO: Do we still need to unlock it though? */
+}
+
+void Window_OpenKeyboard(struct OpenKeyboardArgs* args) { SDL_StartTextInput(); }
+void Window_SetKeyboardText(const cc_string* text) { }
+void Window_CloseKeyboard(void) { SDL_StopTextInput(); }
+
+void Window_EnableRawMouse(void) {
+ RegrabMouse();
+ SDL_SetRelativeMouseMode(true);
+ Input.RawMode = true;
+}
+void Window_UpdateRawMouse(void) { CentreMousePosition(); }
+
+void Window_DisableRawMouse(void) {
+ RegrabMouse();
+ SDL_SetRelativeMouseMode(false);
+ Input.RawMode = false;
+}
+
+
+/*########################################################################################################################*
+*-----------------------------------------------------OpenGL context------------------------------------------------------*
+*#########################################################################################################################*/
+#if defined CC_BUILD_GL && !defined CC_BUILD_EGL
+static SDL_GLContext win_ctx;
+
+void GLContext_Create(void) {
+ struct GraphicsMode mode;
+ InitGraphicsMode(&mode);
+ SDL_GL_SetAttribute(SDL_GL_RED_SIZE, mode.R);
+ SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, mode.G);
+ SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, mode.B);
+ SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, mode.A);
+
+ SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, GLCONTEXT_DEFAULT_DEPTH);
+ SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 0);
+ SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, true);
+#ifdef CC_BUILD_GLES
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
+#endif
+
+ win_ctx = SDL_GL_CreateContext(win_handle);
+ if (!win_ctx) Window_SDLFail("creating OpenGL context");
+}
+
+void GLContext_Update(void) { }
+cc_bool GLContext_TryRestore(void) { return true; }
+void GLContext_Free(void) {
+ SDL_GL_DeleteContext(win_ctx);
+ win_ctx = NULL;
+}
+
+void* GLContext_GetAddress(const char* function) {
+ return SDL_GL_GetProcAddress(function);
+}
+
+cc_bool GLContext_SwapBuffers(void) {
+ SDL_GL_SwapWindow(win_handle);
+ return true;
+}
+
+void GLContext_SetFpsLimit(cc_bool vsync, float minFrameMs) {
+ SDL_GL_SetSwapInterval(vsync);
+}
+void GLContext_GetApiInfo(cc_string* info) { }
+#endif
+#endif
diff --git a/src/Window_Switch.c b/src/Window_Switch.c
index d45708346..8108b5348 100644
--- a/src/Window_Switch.c
+++ b/src/Window_Switch.c
@@ -58,7 +58,7 @@ void Window_Init(void) {
// Initialize the default gamepad (which reads handheld mode inputs as well as the first connected controller)
padInitializeDefault(&pad);
- DisplayInfo.Depth = 4; // 32 bit
+ DisplayInfo.Depth = 4; // 32 bit TODO wrong, this is actually 4 bit
DisplayInfo.ScaleX = 1;
DisplayInfo.ScaleY = 1;
@@ -108,58 +108,42 @@ void Window_RequestClose(void) {
*----------------------------------------------------Input processing-----------------------------------------------------*
*#########################################################################################################################*/
static void HandleButtons(u64 mods) {
- Input_SetNonRepeatable(CCPAD_L, mods & HidNpadButton_L);
- Input_SetNonRepeatable(CCPAD_R, mods & HidNpadButton_R);
+ Gamepad_SetButton(CCPAD_L, mods & HidNpadButton_L);
+ Gamepad_SetButton(CCPAD_R, mods & HidNpadButton_R);
- Input_SetNonRepeatable(CCPAD_A, mods & HidNpadButton_A);
- Input_SetNonRepeatable(CCPAD_B, mods & HidNpadButton_B);
- Input_SetNonRepeatable(CCPAD_X, mods & HidNpadButton_X);
- Input_SetNonRepeatable(CCPAD_Y, mods & HidNpadButton_Y);
+ Gamepad_SetButton(CCPAD_A, mods & HidNpadButton_A);
+ Gamepad_SetButton(CCPAD_B, mods & HidNpadButton_B);
+ Gamepad_SetButton(CCPAD_X, mods & HidNpadButton_X);
+ Gamepad_SetButton(CCPAD_Y, mods & HidNpadButton_Y);
- Input_SetNonRepeatable(CCPAD_START, mods & HidNpadButton_Plus);
- Input_SetNonRepeatable(CCPAD_SELECT, mods & HidNpadButton_Minus);
+ Gamepad_SetButton(CCPAD_START, mods & HidNpadButton_Plus);
+ Gamepad_SetButton(CCPAD_SELECT, mods & HidNpadButton_Minus);
- Input_SetNonRepeatable(CCPAD_LEFT, mods & HidNpadButton_Left);
- Input_SetNonRepeatable(CCPAD_RIGHT, mods & HidNpadButton_Right);
- Input_SetNonRepeatable(CCPAD_UP, mods & HidNpadButton_Up);
- Input_SetNonRepeatable(CCPAD_DOWN, mods & HidNpadButton_Down);
+ Gamepad_SetButton(CCPAD_LEFT, mods & HidNpadButton_Left);
+ Gamepad_SetButton(CCPAD_RIGHT, mods & HidNpadButton_Right);
+ Gamepad_SetButton(CCPAD_UP, mods & HidNpadButton_Up);
+ Gamepad_SetButton(CCPAD_DOWN, mods & HidNpadButton_Down);
}
-static void ProcessJoystickInput_L(HidAnalogStickState* pos) {
+#define AXIS_SCALE 512.0f
+static void ProcessJoystickInput(int axis, HidAnalogStickState* pos, double delta) {
// May not be exactly 0 on actual hardware
if (Math_AbsI(pos->x) <= 16) pos->x = 0;
if (Math_AbsI(pos->y) <= 16) pos->y = 0;
- Input.JoystickMovement = (pos->x != 0 || pos->y != 0);
- if (!Input.JoystickMovement) return;
- Input.JoystickAngle = Math_Atan2(pos->x, -pos->y);
-}
-
-static void ProcessJoystickInput_R(HidAnalogStickState* pos) {
- // May not be exactly 0 on actual hardware
- if (Math_AbsI(pos->x) <= 16) pos->x = 0;
- if (Math_AbsI(pos->y) <= 16) pos->y = 0;
-
- Event_RaiseRawMove(&ControllerEvents.RawMoved, pos->x / 512.f, -pos->y / 512.f);
+ Gamepad_SetAxis(axis, pos->x / AXIS_SCALE, -pos->y / AXIS_SCALE, delta);
}
static void ProcessTouchInput(void) {
- static int currX, currY, prev_touchcount=0;
- HidTouchScreenState state={0};
+ static int prev_touchcount = 0;
+ HidTouchScreenState state = {0};
hidGetTouchScreenStates(&state, 1);
- if (state.count && !prev_touchcount) { // stylus went down
- currX = state.touches[0].x;
- currY = state.touches[0].y;
- Input_AddTouch(0, currX, currY);
- } else if (state.count) { // stylus is down
- currX = state.touches[0].x;
- currY = state.touches[0].y;
- Input_UpdateTouch(0, currX, currY);
- } else if (!state.count && prev_touchcount) { // stylus was lifted
- Input_RemoveTouch(0, currX, currY);
+ if (state.count) {
+ Input_AddTouch(0, state.touches[0].x, state.touches[0].y);
+ } else if (prev_touchcount) {
+ Input_RemoveTouch(0, Pointers[0].x, Pointers[0].y);
}
-
prev_touchcount = state.count;
}
@@ -179,8 +163,8 @@ void Window_ProcessEvents(double delta) {
// Read the sticks' position
HidAnalogStickState analog_stick_l = padGetStickPos(&pad, 0);
HidAnalogStickState analog_stick_r = padGetStickPos(&pad, 1);
- ProcessJoystickInput_L(&analog_stick_l);
- ProcessJoystickInput_R(&analog_stick_r);
+ ProcessJoystickInput(PAD_AXIS_LEFT, &analog_stick_l, delta);
+ ProcessJoystickInput(PAD_AXIS_RIGHT, &analog_stick_r, delta);
ProcessTouchInput();
}
diff --git a/src/Window_Web.c b/src/Window_Web.c
index f51bbedae..054589b60 100644
--- a/src/Window_Web.c
+++ b/src/Window_Web.c
@@ -534,46 +534,34 @@ static void ProcessPendingResize(void) {
static void ProcessGamepadButtons(EmscriptenGamepadEvent* ev) {
int numButtons = ev->numButtons;
- Input_SetNonRepeatable(CCPAD_A, GetGamepadButton(0));
- Input_SetNonRepeatable(CCPAD_B, GetGamepadButton(1));
- Input_SetNonRepeatable(CCPAD_X, GetGamepadButton(2));
- Input_SetNonRepeatable(CCPAD_Y, GetGamepadButton(3));
-
- Input_SetNonRepeatable(CCPAD_ZL, GetGamepadButton(4));
- Input_SetNonRepeatable(CCPAD_ZR, GetGamepadButton(5));
- Input_SetNonRepeatable(CCPAD_L, GetGamepadButton(6));
- Input_SetNonRepeatable(CCPAD_R, GetGamepadButton(7));
-
- Input_SetNonRepeatable(CCPAD_SELECT, GetGamepadButton( 8));
- Input_SetNonRepeatable(CCPAD_START, GetGamepadButton( 9));
- Input_SetNonRepeatable(CCPAD_LSTICK, GetGamepadButton(10));
- Input_SetNonRepeatable(CCPAD_RSTICK, GetGamepadButton(11));
+ Gamepad_SetButton(CCPAD_A, GetGamepadButton(0));
+ Gamepad_SetButton(CCPAD_B, GetGamepadButton(1));
+ Gamepad_SetButton(CCPAD_X, GetGamepadButton(2));
+ Gamepad_SetButton(CCPAD_Y, GetGamepadButton(3));
+
+ Gamepad_SetButton(CCPAD_ZL, GetGamepadButton(4));
+ Gamepad_SetButton(CCPAD_ZR, GetGamepadButton(5));
+ Gamepad_SetButton(CCPAD_L, GetGamepadButton(6));
+ Gamepad_SetButton(CCPAD_R, GetGamepadButton(7));
+
+ Gamepad_SetButton(CCPAD_SELECT, GetGamepadButton( 8));
+ Gamepad_SetButton(CCPAD_START, GetGamepadButton( 9));
+ Gamepad_SetButton(CCPAD_LSTICK, GetGamepadButton(10));
+ Gamepad_SetButton(CCPAD_RSTICK, GetGamepadButton(11));
- Input_SetNonRepeatable(CCPAD_UP, GetGamepadButton(12));
- Input_SetNonRepeatable(CCPAD_DOWN, GetGamepadButton(13));
- Input_SetNonRepeatable(CCPAD_LEFT, GetGamepadButton(14));
- Input_SetNonRepeatable(CCPAD_RIGHT, GetGamepadButton(15));
+ Gamepad_SetButton(CCPAD_UP, GetGamepadButton(12));
+ Gamepad_SetButton(CCPAD_DOWN, GetGamepadButton(13));
+ Gamepad_SetButton(CCPAD_LEFT, GetGamepadButton(14));
+ Gamepad_SetButton(CCPAD_RIGHT, GetGamepadButton(15));
}
-static void ProcessGamepadCamera(float x, float y, double delta) {
- float scale = (delta * 60.0) * 8.0f;
-
- /* Deadzone adjustment */
- if (x >= -0.1 && x <= 0.1) x = 0;
- if (y >= -0.1 && y <= 0.1) y = 0;
- if (x == 0 && y == 0) return;
-
- Event_RaiseRawMove(&ControllerEvents.RawMoved, x * scale, y * scale);
-}
-
-static void ProcessGamepadMovement(float x, float y) {
+#define AXIS_SCALE 8.0f
+static void ProcessGamepadAxis(int axis, float x, float y, double delta) {
/* Deadzone adjustment */
if (x >= -0.1 && x <= 0.1) x = 0;
if (y >= -0.1 && y <= 0.1) y = 0;
- if (x == 0 && y == 0) return;
- Input.JoystickMovement = true;
- Input.JoystickAngle = Math_Atan2(x, y);
+ Gamepad_SetAxis(axis, x * AXIS_SCALE, y * AXIS_SCALE, delta);
}
static void ProcessGamepadInput(EmscriptenGamepadEvent* ev, double delta) {
@@ -582,10 +570,10 @@ static void ProcessGamepadInput(EmscriptenGamepadEvent* ev, double delta) {
ProcessGamepadButtons(ev);
if (ev->numAxes >= 4) {
- ProcessGamepadMovement(ev->axis[0], ev->axis[1]);
- ProcessGamepadCamera( ev->axis[2], ev->axis[3], delta);
+ ProcessGamepadAxis(PAD_AXIS_LEFT, ev->axis[0], ev->axis[1], delta);
+ ProcessGamepadAxis(PAD_AXIS_RIGHT, ev->axis[2], ev->axis[3], delta);
} else if (ev->numAxes >= 2) {
- ProcessGamepadCamera(ev->axis[0], ev->axis[1], delta);
+ ProcessGamepadAxis(PAD_AXIS_RIGHT, ev->axis[0], ev->axis[1], delta);
}
}
diff --git a/src/Window_WiiU.c b/src/Window_WiiU.c
index f910abdc6..f3a09fbb2 100644
--- a/src/Window_WiiU.c
+++ b/src/Window_WiiU.c
@@ -78,23 +78,23 @@ void Window_RequestClose(void) {
}
static void ProcessVpadButtons(int mods) {
- Input_SetNonRepeatable(CCPAD_L, mods & VPAD_BUTTON_L);
- Input_SetNonRepeatable(CCPAD_R, mods & VPAD_BUTTON_R);
- Input_SetNonRepeatable(CCPAD_ZL, mods & VPAD_BUTTON_ZL);
- Input_SetNonRepeatable(CCPAD_ZR, mods & VPAD_BUTTON_ZR);
+ Gamepad_SetButton(CCPAD_L, mods & VPAD_BUTTON_L);
+ Gamepad_SetButton(CCPAD_R, mods & VPAD_BUTTON_R);
+ Gamepad_SetButton(CCPAD_ZL, mods & VPAD_BUTTON_ZL);
+ Gamepad_SetButton(CCPAD_ZR, mods & VPAD_BUTTON_ZR);
- Input_SetNonRepeatable(CCPAD_A, mods & VPAD_BUTTON_A);
- Input_SetNonRepeatable(CCPAD_B, mods & VPAD_BUTTON_B);
- Input_SetNonRepeatable(CCPAD_X, mods & VPAD_BUTTON_X);
- Input_SetNonRepeatable(CCPAD_Y, mods & VPAD_BUTTON_Y);
+ Gamepad_SetButton(CCPAD_A, mods & VPAD_BUTTON_A);
+ Gamepad_SetButton(CCPAD_B, mods & VPAD_BUTTON_B);
+ Gamepad_SetButton(CCPAD_X, mods & VPAD_BUTTON_X);
+ Gamepad_SetButton(CCPAD_Y, mods & VPAD_BUTTON_Y);
- Input_SetNonRepeatable(CCPAD_START, mods & VPAD_BUTTON_PLUS);
- Input_SetNonRepeatable(CCPAD_SELECT, mods & VPAD_BUTTON_MINUS);
+ Gamepad_SetButton(CCPAD_START, mods & VPAD_BUTTON_PLUS);
+ Gamepad_SetButton(CCPAD_SELECT, mods & VPAD_BUTTON_MINUS);
- Input_SetNonRepeatable(CCPAD_LEFT, mods & VPAD_BUTTON_LEFT);
- Input_SetNonRepeatable(CCPAD_RIGHT, mods & VPAD_BUTTON_RIGHT);
- Input_SetNonRepeatable(CCPAD_UP, mods & VPAD_BUTTON_UP);
- Input_SetNonRepeatable(CCPAD_DOWN, mods & VPAD_BUTTON_DOWN);
+ Gamepad_SetButton(CCPAD_LEFT, mods & VPAD_BUTTON_LEFT);
+ Gamepad_SetButton(CCPAD_RIGHT, mods & VPAD_BUTTON_RIGHT);
+ Gamepad_SetButton(CCPAD_UP, mods & VPAD_BUTTON_UP);
+ Gamepad_SetButton(CCPAD_DOWN, mods & VPAD_BUTTON_DOWN);
}
@@ -186,4 +186,4 @@ cc_result Window_OpenFileDialog(const struct OpenFileDialogArgs* args) {
cc_result Window_SaveFileDialog(const struct SaveFileDialogArgs* args) {
return ERR_NOT_SUPPORTED;
}
-#endif
\ No newline at end of file
+#endif
diff --git a/src/Window_X11.c b/src/Window_X11.c
index d820ac7dc..6bb0c01a1 100644
--- a/src/Window_X11.c
+++ b/src/Window_X11.c
@@ -1,5 +1,5 @@
#include "Core.h"
-#if defined CC_BUILD_X11 && !defined CC_BUILD_SDL
+#if defined CC_BUILD_X11 && !defined CC_BUILD_SDL2 && !defined CC_BUILD_SDL3
#include "_WindowBase.h"
#include "String.h"
#include "Funcs.h"
@@ -338,8 +338,13 @@ static void DoCreateWindow(int width, int height) {
/* So right name appears in e.g. Ubuntu Unity launchbar */
XClassHint hint = { 0 };
- hint.res_name = GAME_APP_TITLE;
- hint.res_class = GAME_APP_TITLE;
+ #ifdef CC_BUILD_FLATPAK
+ hint.res_name = "net.classicube.flatpak.client";
+ hint.res_class = "net.classicube.flatpak.client";
+ #else
+ hint.res_name = GAME_APP_TITLE;
+ hint.res_class = GAME_APP_TITLE;
+ #endif
XSetClassHint(win_display, win_handle, &hint);
ApplyIcon();
diff --git a/src/Window_Xbox.c b/src/Window_Xbox.c
index af156d201..f4bfee284 100644
--- a/src/Window_Xbox.c
+++ b/src/Window_Xbox.c
@@ -62,7 +62,6 @@ void Window_Init(void) {
DisplayInfo.Width = mode.width;
DisplayInfo.Height = mode.height;
- DisplayInfo.Depth = 4; // 32 bit
DisplayInfo.ScaleX = 1;
DisplayInfo.ScaleY = 1;
@@ -120,43 +119,33 @@ void Window_RequestClose(void) {
static void HandleButtons(xid_gamepad_in* gp) {
int mods = gp->dButtons;
- Input_SetNonRepeatable(CCPAD_L, gp->l > 0x7F);
- Input_SetNonRepeatable(CCPAD_R, gp->r > 0x7F);
- Input_SetNonRepeatable(CCPAD_ZL, gp->white > 0x7F);
- Input_SetNonRepeatable(CCPAD_ZR, gp->black > 0x7F);
+ Gamepad_SetButton(CCPAD_L, gp->l > 0x7F);
+ Gamepad_SetButton(CCPAD_R, gp->r > 0x7F);
+ Gamepad_SetButton(CCPAD_ZL, gp->white > 0x7F);
+ Gamepad_SetButton(CCPAD_ZR, gp->black > 0x7F);
- Input_SetNonRepeatable(CCPAD_A, gp->a > 0x7F);
- Input_SetNonRepeatable(CCPAD_B, gp->b > 0x7F);
- Input_SetNonRepeatable(CCPAD_X, gp->x > 0x7F);
- Input_SetNonRepeatable(CCPAD_Y, gp->y > 0x7F);
+ Gamepad_SetButton(CCPAD_A, gp->a > 0x7F);
+ Gamepad_SetButton(CCPAD_B, gp->b > 0x7F);
+ Gamepad_SetButton(CCPAD_X, gp->x > 0x7F);
+ Gamepad_SetButton(CCPAD_Y, gp->y > 0x7F);
- Input_SetNonRepeatable(CCPAD_START, mods & XINPUT_GAMEPAD_START);
- Input_SetNonRepeatable(CCPAD_SELECT, mods & XINPUT_GAMEPAD_BACK);
- Input_SetNonRepeatable(CCPAD_LSTICK, mods & XINPUT_GAMEPAD_LEFT_THUMB);
- Input_SetNonRepeatable(CCPAD_RSTICK, mods & XINPUT_GAMEPAD_RIGHT_THUMB);
+ Gamepad_SetButton(CCPAD_START, mods & XINPUT_GAMEPAD_START);
+ Gamepad_SetButton(CCPAD_SELECT, mods & XINPUT_GAMEPAD_BACK);
+ Gamepad_SetButton(CCPAD_LSTICK, mods & XINPUT_GAMEPAD_LEFT_THUMB);
+ Gamepad_SetButton(CCPAD_RSTICK, mods & XINPUT_GAMEPAD_RIGHT_THUMB);
- Input_SetNonRepeatable(CCPAD_LEFT, mods & XINPUT_GAMEPAD_DPAD_LEFT);
- Input_SetNonRepeatable(CCPAD_RIGHT, mods & XINPUT_GAMEPAD_DPAD_RIGHT);
- Input_SetNonRepeatable(CCPAD_UP, mods & XINPUT_GAMEPAD_DPAD_UP);
- Input_SetNonRepeatable(CCPAD_DOWN, mods & XINPUT_GAMEPAD_DPAD_DOWN);
+ Gamepad_SetButton(CCPAD_LEFT, mods & XINPUT_GAMEPAD_DPAD_LEFT);
+ Gamepad_SetButton(CCPAD_RIGHT, mods & XINPUT_GAMEPAD_DPAD_RIGHT);
+ Gamepad_SetButton(CCPAD_UP, mods & XINPUT_GAMEPAD_DPAD_UP);
+ Gamepad_SetButton(CCPAD_DOWN, mods & XINPUT_GAMEPAD_DPAD_DOWN);
}
-static void HandleJoystick_Left(int x, int y) {
+#define AXIS_SCALE 8192.0f
+static void HandleJoystick(int axis, int x, int y, double delta) {
if (Math_AbsI(x) <= 512) x = 0;
if (Math_AbsI(y) <= 512) y = 0;
- if (x == 0 && y == 0) return;
- Input.JoystickMovement = true;
- Input.JoystickAngle = Math_Atan2(x, -y);
-}
-
-static void HandleJoystick_Right(int x, int y, double delta) {
- float scale = (delta * 60.0) / 8192.0f;
-
- if (Math_AbsI(x) <= 512) x = 0;
- if (Math_AbsI(y) <= 512) y = 0;
-
- Event_RaiseRawMove(&ControllerEvents.RawMoved, x * scale, -y * scale);
+ Gamepad_SetAxis(axis, x / AXIS_SCALE, -y / AXIS_SCALE, delta);
}
void Window_ProcessEvents(double delta) {
@@ -165,8 +154,8 @@ void Window_ProcessEvents(double delta) {
if (!xid_ctrl) return;
HandleButtons(&gp_state);
- HandleJoystick_Left( gp_state.leftStickX, gp_state.leftStickY );
- HandleJoystick_Right(gp_state.rightStickX, gp_state.rightStickY, delta);
+ HandleJoystick(PAD_AXIS_LEFT, gp_state.leftStickX, gp_state.leftStickY, delta);
+ HandleJoystick(PAD_AXIS_RIGHT, gp_state.rightStickX, gp_state.rightStickY, delta);
}
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 64cbf8fbb..9d9ab8592 100644
--- a/src/Window_Xbox360.c
+++ b/src/Window_Xbox360.c
@@ -33,7 +33,6 @@ void Window_Init(void) {
DisplayInfo.Width = ai->width;
DisplayInfo.Height = ai->height;
- DisplayInfo.Depth = 4; // 32 bit
DisplayInfo.ScaleX = 1;
DisplayInfo.ScaleY = 1;
@@ -87,21 +86,21 @@ struct controller_data_s
*/
static void HandleButtons(struct controller_data_s* pad) {
- Input_SetNonRepeatable(CCPAD_L, pad->lb);
- Input_SetNonRepeatable(CCPAD_R, pad->rb);
+ Gamepad_SetButton(CCPAD_L, pad->lb);
+ Gamepad_SetButton(CCPAD_R, pad->rb);
- Input_SetNonRepeatable(CCPAD_A, pad->a);
- Input_SetNonRepeatable(CCPAD_B, pad->b);
- Input_SetNonRepeatable(CCPAD_X, pad->x);
- Input_SetNonRepeatable(CCPAD_Y, pad->y);
+ Gamepad_SetButton(CCPAD_A, pad->a);
+ Gamepad_SetButton(CCPAD_B, pad->b);
+ Gamepad_SetButton(CCPAD_X, pad->x);
+ Gamepad_SetButton(CCPAD_Y, pad->y);
- Input_SetNonRepeatable(CCPAD_START, pad->start);
- Input_SetNonRepeatable(CCPAD_SELECT, pad->back);
+ Gamepad_SetButton(CCPAD_START, pad->start);
+ Gamepad_SetButton(CCPAD_SELECT, pad->back);
- Input_SetNonRepeatable(CCPAD_LEFT, pad->left);
- Input_SetNonRepeatable(CCPAD_RIGHT, pad->right);
- Input_SetNonRepeatable(CCPAD_UP, pad->up);
- Input_SetNonRepeatable(CCPAD_DOWN, pad->down);
+ Gamepad_SetButton(CCPAD_LEFT, pad->left);
+ Gamepad_SetButton(CCPAD_RIGHT, pad->right);
+ Gamepad_SetButton(CCPAD_UP, pad->up);
+ Gamepad_SetButton(CCPAD_DOWN, pad->down);
}
void Window_ProcessEvents(double delta) {
diff --git a/src/_GLShared.h b/src/_GLShared.h
index c6d7fa10d..ca82a6ace 100644
--- a/src/_GLShared.h
+++ b/src/_GLShared.h
@@ -232,7 +232,7 @@ void Gfx_CalcPerspectiveMatrix(struct Matrix* matrix, float fov, float aspect, f
/*########################################################################################################################*
*-----------------------------------------------------------Misc----------------------------------------------------------*
*#########################################################################################################################*/
-static BitmapCol* GL_GetRow(struct Bitmap* bmp, int y) {
+static BitmapCol* GL_GetRow(struct Bitmap* bmp, int y, void* ctx) {
/* OpenGL stores bitmap in bottom-up order, so flip order when saving */
return Bitmap_GetRow(bmp, (bmp->height - 1) - y);
}
@@ -249,7 +249,7 @@ cc_result Gfx_TakeScreenshot(struct Stream* output) {
if (!bmp.scan0) return ERR_OUT_OF_MEMORY;
glReadPixels(0, 0, bmp.width, bmp.height, PIXEL_FORMAT, TRANSFER_FORMAT, bmp.scan0);
- res = Png_Encode(&bmp, output, GL_GetRow, false);
+ res = Png_Encode(&bmp, output, GL_GetRow, false, NULL);
Mem_Free(bmp.scan0);
return res;
}
diff --git a/src/_GraphicsBase.h b/src/_GraphicsBase.h
index 8fd3e41ae..3efd775b6 100644
--- a/src/_GraphicsBase.h
+++ b/src/_GraphicsBase.h
@@ -136,7 +136,7 @@ void Gfx_RecreateContext(void) {
}
cc_bool reducedPerformance;
-static void TickReducedPerformance(void) {
+static CC_INLINE void TickReducedPerformance(void) {
Thread_Sleep(100); /* 10 FPS */
if (reducedPerformance) return;
@@ -144,7 +144,7 @@ static void TickReducedPerformance(void) {
Chat_AddOf(&Gfx_LowPerfMessage, MSG_TYPE_EXTRASTATUS_2);
}
-static void EndReducedPerformance(void) {
+static CC_INLINE void EndReducedPerformance(void) {
if (!reducedPerformance) return;
reducedPerformance = false;
Chat_AddOf(&String_Empty, MSG_TYPE_EXTRASTATUS_2);
diff --git a/src/_HttpBase.h b/src/_HttpBase.h
index 55a11a15e..d0b0c4bc5 100644
--- a/src/_HttpBase.h
+++ b/src/_HttpBase.h
@@ -192,7 +192,7 @@ static void Http_FinishRequest(struct HttpRequest* req) {
Mutex_Lock(processedMutex);
{
- req->timeDownloaded = DateTime_CurrentUTC_MS();
+ req->timeDownloaded = DateTime_CurrentUTC();
RequestList_Append(&processedReqs, req, false);
}
Mutex_Unlock(processedMutex);
@@ -205,10 +205,10 @@ static void Http_CleanCacheTask(struct ScheduledTask* task) {
Mutex_Lock(processedMutex);
{
- TimeMS now = DateTime_CurrentUTC_MS();
+ TimeMS now = DateTime_CurrentUTC();
for (i = processedReqs.count - 1; i >= 0; i--) {
item = &processedReqs.entries[i];
- if (item->timeDownloaded + (10 * 1000) >= now) continue;
+ if (now > item->timeDownloaded + 10) continue;
HttpRequest_Free(item);
RequestList_RemoveAt(&processedReqs, i);
diff --git a/src/_WindowBase.h b/src/_WindowBase.h
index 81011c01f..02fcec3ed 100644
--- a/src/_WindowBase.h
+++ b/src/_WindowBase.h
@@ -43,18 +43,18 @@ static void RegrabMouse(void) {
CentreMousePosition();
}
-static void DefaultEnableRawMouse(void) {
+static CC_INLINE void DefaultEnableRawMouse(void) {
Input.RawMode = true;
RegrabMouse();
Cursor_SetVisible(false);
}
-static void DefaultUpdateRawMouse(void) {
+static CC_INLINE void DefaultUpdateRawMouse(void) {
MoveRawUsingCursorDelta();
CentreMousePosition();
}
-static void DefaultDisableRawMouse(void) {
+static CC_INLINE void DefaultDisableRawMouse(void) {
Input.RawMode = false;
RegrabMouse();
Cursor_SetVisible(true);
diff --git a/src/interop_ios.m b/src/interop_ios.m
index c94410cb9..54faee342 100644
--- a/src/interop_ios.m
+++ b/src/interop_ios.m
@@ -34,7 +34,7 @@
@interface CCWindow : UIWindow
@end
-@interface CCViewController : UIViewController
+@interface CCViewController : UIViewController
@end
@interface CCAppDelegate : UIResponder
@@ -217,6 +217,12 @@ - (UIRectEdge)preferredScreenEdgesDeferringSystemGestures {
// significantly the chance of accidentally triggering this gesture
return UIRectEdgeBottom;
}
+
+// == UIAlertViewDelegate ==
+static int alert_completed;
+- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex {
+ alert_completed = true;
+}
@end
@implementation CCAppDelegate
@@ -430,20 +436,27 @@ void Window_ProcessEvents(double delta) {
void ShowDialogCore(const char* title, const char* msg) {
// UIAlertController - iOS 8.0
// UIAlertAction - iOS 8.0
+ // UIAlertView - iOS 2.0
Platform_LogConst(title);
Platform_LogConst(msg);
NSString* _title = [NSString stringWithCString:title encoding:NSASCIIStringEncoding];
NSString* _msg = [NSString stringWithCString:msg encoding:NSASCIIStringEncoding];
- __block int completed = false;
+ alert_completed = false;
+#ifdef TARGET_OS_TV
UIAlertController* alert = [UIAlertController alertControllerWithTitle:_title message:_msg preferredStyle:UIAlertControllerStyleAlert];
- UIAlertAction* okBtn = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction* act) { completed = true; }];
+ UIAlertAction* okBtn = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction* act) { alert_completed = true; }];
[alert addAction:okBtn];
[cc_controller presentViewController:alert animated:YES completion: Nil];
+#else
+ UIAlertView* alert = [UIAlertView alloc];
+ alert = [alert initWithTitle:_title message:_msg delegate:cc_controller cancelButtonTitle:@"OK" otherButtonTitles:nil];
+ [alert show];
+#endif
// TODO clicking outside message box crashes launcher
// loop until alert is closed TODO avoid sleeping
- while (!completed) {
+ while (!alert_completed) {
Window_ProcessEvents(0.0);
Thread_Sleep(16);
}