Compare commits

...

9 Commits

Author SHA1 Message Date
Adrian Siekierka 897384f3da
Merge 9222b40650 into 15c3faa26e 2025-01-17 06:50:57 +01:00
Nadia Holmquist Pedersen 15c3faa26e Use GitHub's new arm64 Linux runners for the Ubuntu CI builds 2025-01-17 04:15:13 +01:00
Adrian Siekierka 9222b40650 GBACartMotionPak: Update comment 2025-01-01 09:36:15 +01:00
Adrian Siekierka 882d11ae6e Motion Pak: Add comment 2025-01-01 09:35:39 +01:00
Adrian Siekierka 9eea7a1ee6 Motion Pak: Emulate console laying on a flat table when motion input is not detected 2025-01-01 09:35:39 +01:00
Adrian Siekierka b6ff439708 Fix Motion Pak emulation axes 2025-01-01 09:35:39 +01:00
Adrian Siekierka 10c308a6a4 Simplify Motion Pak acceleration conversion formula 2025-01-01 09:35:39 +01:00
Adrian Siekierka f8af7b98c8 Add retail Motion Pak emulation, Guitar Grip emulation 2025-01-01 09:35:38 +01:00
Adrian Siekierka 664f77b4ac Add DS Motion Pak emulation 2025-01-01 09:35:16 +01:00
15 changed files with 489 additions and 51 deletions

View File

@ -4,6 +4,7 @@ on:
push:
branches:
- master
- ci/*
pull_request:
branches:
- master
@ -15,16 +16,24 @@ env:
MELONDS_VERSION_SUFFIX: " RC"
jobs:
build-x86_64:
name: x86_64
runs-on: ubuntu-22.04
build:
continue-on-error: true
strategy:
matrix:
arch:
- runner: ubuntu-22.04
name: x86_64
- runner: ubuntu-22.04-arm
name: aarch64
name: ${{ matrix.arch.name }}
runs-on: ${{ matrix.arch.runner }}
steps:
- uses: actions/checkout@v4
name: Check out sources
- name: Install dependencies
run: |
sudo rm -f /etc/apt/sources.list.d/dotnetdev.list /etc/apt/sources.list.d/microsoft-prod.list
sudo apt update
sudo apt install --allow-downgrades cmake ninja-build extra-cmake-modules libpcap0.8-dev libsdl2-dev libenet-dev \
qt6-{base,base-private,multimedia}-dev libqt6svg6-dev libarchive-dev libzstd-dev libfuse2
@ -36,56 +45,23 @@ jobs:
DESTDIR=AppDir cmake --install build
- uses: actions/upload-artifact@v4
with:
name: melonDS-ubuntu-x86_64
name: melonDS-ubuntu-${{ matrix.arch.name }}
path: AppDir/usr/bin/melonDS
- name: Fetch AppImage tools
# linuxdeploy doesn't seem to work on the aarch64 runners?
if: matrix.arch.name != 'aarch64'
run: |
wget https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage
wget https://github.com/linuxdeploy/linuxdeploy-plugin-qt/releases/download/continuous/linuxdeploy-plugin-qt-x86_64.AppImage
wget https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-${{ matrix.arch.name }}.AppImage
wget https://github.com/linuxdeploy/linuxdeploy-plugin-qt/releases/download/continuous/linuxdeploy-plugin-qt-${{ matrix.arch.name }}.AppImage
chmod a+x linuxdeploy-*.AppImage
- name: Build the AppImage
if: matrix.arch.name != 'aarch64'
env:
QMAKE: /usr/lib/qt6/bin/qmake
run: |
./linuxdeploy-x86_64.AppImage --appdir AppDir --plugin qt --output appimage
./linuxdeploy-${{ matrix.arch.name }}.AppImage --appdir AppDir --plugin qt --output appimage
- uses: actions/upload-artifact@v4
if: matrix.arch.name != 'aarch64'
with:
name: melonDS-appimage-x86_64
name: melonDS-appimage-${{ matrix.arch.name }}
path: melonDS*.AppImage
build-aarch64:
name: aarch64
runs-on: ubuntu-latest
container: ubuntu:22.04
steps:
- name: Prepare system
shell: bash
run: |
dpkg --add-architecture arm64
sh -c "sed \"s|^deb \([a-z\.:/]*\) \([a-z\-]*\) \(.*\)$|deb [arch=amd64] \1 \2 \3\ndeb [arch=arm64] http://ports.ubuntu.com/ubuntu-ports \2 \3|\" /etc/apt/sources.list > /etc/apt/sources.list.new"
rm /etc/apt/sources.list
mv /etc/apt/sources.list{.new,}
apt update
apt -y full-upgrade
apt -y install git {gcc-12,g++-12}-aarch64-linux-gnu cmake ninja-build extra-cmake-modules \
{libsdl2,qt6-{base,base-private,multimedia},libqt6svg6,libarchive,libzstd,libenet}-dev:arm64 \
pkg-config dpkg-dev
- name: Check out source
uses: actions/checkout@v4
- name: Configure
shell: bash
run: |
cmake -B build -G Ninja \
-DPKG_CONFIG_EXECUTABLE=/usr/bin/aarch64-linux-gnu-pkg-config \
-DCMAKE_C_COMPILER=aarch64-linux-gnu-gcc-12 \
-DCMAKE_CXX_COMPILER=aarch64-linux-gnu-g++-12 \
-DMELONDS_EMBED_BUILD_INFO=ON
- name: Build
shell: bash
run: |
cmake --build build
- uses: actions/upload-artifact@v4
with:
name: melonDS-ubuntu-aarch64
path: build/melonDS

View File

@ -30,6 +30,7 @@ add_library(core STATIC
FATStorage.cpp
FIFO.h
GBACart.cpp
GBACartMotionPak.cpp
GPU.cpp
GPU2D.cpp
GPU2D_Soft.cpp

View File

@ -724,6 +724,27 @@ void CartRumblePak::ROMWrite(u32 addr, u16 val)
}
}
CartGuitarGrip::CartGuitarGrip(void* userdata) :
CartCommon(GuitarGrip),
UserData(userdata)
{
}
CartGuitarGrip::~CartGuitarGrip() = default;
u16 CartGuitarGrip::ROMRead(u32 addr) const
{
return 0xF9FF;
}
u8 CartGuitarGrip::SRAMRead(u32 addr)
{
return ~((Platform::Addon_KeyDown(Platform::KeyGuitarGripGreen, UserData) ? 0x40 : 0)
| (Platform::Addon_KeyDown(Platform::KeyGuitarGripRed, UserData) ? 0x20 : 0)
| (Platform::Addon_KeyDown(Platform::KeyGuitarGripYellow, UserData) ? 0x10 : 0)
| (Platform::Addon_KeyDown(Platform::KeyGuitarGripBlue, UserData) ? 0x08 : 0));
}
GBACartSlot::GBACartSlot(melonDS::NDS& nds, std::unique_ptr<CartCommon>&& cart) noexcept : NDS(nds), Cart(std::move(cart))
{
}
@ -843,6 +864,15 @@ std::unique_ptr<CartCommon> LoadAddon(int type, void* userdata)
case GBAAddon_RumblePak:
cart = std::make_unique<CartRumblePak>(userdata);
break;
case GBAAddon_MotionPakHomebrew:
cart = std::make_unique<CartMotionPakHomebrew>(userdata);
break;
case GBAAddon_MotionPakRetail:
cart = std::make_unique<CartMotionPakRetail>(userdata);
break;
case GBAAddon_GuitarGrip:
cart = std::make_unique<CartGuitarGrip>(userdata);
break;
default:
Log(LogLevel::Warn, "GBACart: !! invalid addon type %d\n", type);

View File

@ -33,6 +33,9 @@ enum CartType
GameSolarSensor = 0x102,
RAMExpansion = 0x201,
RumblePak = 0x202,
MotionPakHomebrew = 0x203,
MotionPakRetail = 0x204,
GuitarGrip = 0x205,
};
// CartCommon -- base code shared by all cart types
@ -211,11 +214,68 @@ private:
u16 RumbleState = 0;
};
// CartGuitarGrip -- DS Guitar Grip (used in various NDS games)
class CartGuitarGrip : public CartCommon
{
public:
CartGuitarGrip(void* userdata);
~CartGuitarGrip() override;
u16 ROMRead(u32 addr) const override;
u8 SRAMRead(u32 addr) override;
private:
void* UserData;
};
// CartMotionPakHomebrew -- DS Motion Pak (Homebrew)
class CartMotionPakHomebrew : public CartCommon
{
public:
CartMotionPakHomebrew(void* userdata);
~CartMotionPakHomebrew() override;
void Reset() override;
void DoSavestate(Savestate* file) override;
u16 ROMRead(u32 addr) const override;
u8 SRAMRead(u32 addr) override;
private:
void* UserData;
u16 ShiftVal = 0;
};
// CartMotionPakRetail -- DS Motion Pack (Retail)
class CartMotionPakRetail : public CartCommon
{
public:
CartMotionPakRetail(void* userdata);
~CartMotionPakRetail() override;
void Reset() override;
void DoSavestate(Savestate* file) override;
u16 ROMRead(u32 addr) const override;
u8 SRAMRead(u32 addr) override;
private:
void* UserData;
u8 Value;
u8 Step = 16;
};
// possible inputs for GBA carts that might accept user input
enum
{
Input_SolarSensorDown = 0,
Input_SolarSensorUp,
Input_GuitarGripGreen,
Input_GuitarGripRed,
Input_GuitarGripYellow,
Input_GuitarGripBlue,
};
class GBACartSlot

196
src/GBACartMotionPak.cpp Normal file
View File

@ -0,0 +1,196 @@
/*
Copyright 2016-2024 melonDS team
This file is part of melonDS.
melonDS is free software: you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation, either version 3 of the License, or (at your option)
any later version.
melonDS is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with melonDS. If not, see http://www.gnu.org/licenses/.
*/
#include <assert.h>
#include "NDS.h"
#include "GBACart.h"
#include "Platform.h"
#include <algorithm>
#include "math.h"
namespace melonDS
{
using Platform::Log;
using Platform::LogLevel;
namespace GBACart
{
CartMotionPakHomebrew::CartMotionPakHomebrew(void* userdata) :
CartCommon(MotionPakHomebrew),
UserData(userdata)
{
}
CartMotionPakHomebrew::~CartMotionPakHomebrew() = default;
void CartMotionPakHomebrew::Reset()
{
ShiftVal = 0;
}
void CartMotionPakHomebrew::DoSavestate(Savestate* file)
{
CartCommon::DoSavestate(file);
file->Var16(&ShiftVal);
}
u16 CartMotionPakHomebrew::ROMRead(u32 addr) const
{
// CHECKME: Does this apply to the homebrew cart as well?
return 0xFCFF;
}
static int AccelerationToMotionPak(float accel)
{
const float GRAVITY_M_S2 = 9.80665f;
return std::clamp(
(int) ((accel / (5 * GRAVITY_M_S2) + 0.5) * 4096),
0, 4095
);
}
static int AccelerationToMotionPakRetail(float accel)
{
const float GRAVITY_M_S2 = 9.80665f;
return std::clamp(
(int) ((accel / (5 * GRAVITY_M_S2) + 0.5) * 256),
0, 254
);
}
static int RotationToMotionPak(float rot)
{
const float DEGREES_PER_RAD = 180 / M_PI;
const float COUNTS_PER_DEG_PER_SEC = 0.825;
const int CENTER = 1680;
return std::clamp(
(int) ((rot * DEGREES_PER_RAD * COUNTS_PER_DEG_PER_SEC) + CENTER + 0.5),
0, 4095
);
}
u8 CartMotionPakHomebrew::SRAMRead(u32 addr)
{
// CHECKME: SRAM address mask
addr &= 0xFFFF;
switch (addr)
{
case 0:
// Read next byte
break;
case 2:
// Read X acceleration
ShiftVal = AccelerationToMotionPak(Platform::Addon_MotionQuery(Platform::MotionAccelerationX, UserData)) << 4;
// CHECKME: First byte returned when reading acceleration/rotation
return 0;
case 4:
// Read Y acceleration
ShiftVal = AccelerationToMotionPak(Platform::Addon_MotionQuery(Platform::MotionAccelerationY, UserData)) << 4;
return 0;
case 6:
// Read Z acceleration
ShiftVal = AccelerationToMotionPak(Platform::Addon_MotionQuery(Platform::MotionAccelerationZ, UserData)) << 4;
return 0;
case 8:
// Read Z rotation
// CHECKME: This is a guess, compare with real hardware
ShiftVal = RotationToMotionPak(-Platform::Addon_MotionQuery(Platform::MotionRotationZ, UserData)) << 4;
return 0;
case 10:
// Identify cart
ShiftVal = 0xF00F;
return 0;
case 12:
case 14:
case 16:
case 18:
// Read/enable analog inputs
//
// These are not connected by defualt and require do-it-yourself cart
// modification, so there is no reason to emulate them.
ShiftVal = 0;
break;
}
// Read high byte from the emulated shift register
u8 val = ShiftVal >> 8;
ShiftVal <<= 8;
return val;
}
CartMotionPakRetail::CartMotionPakRetail(void* userdata) :
CartCommon(MotionPakRetail),
UserData(userdata)
{
}
CartMotionPakRetail::~CartMotionPakRetail() = default;
void CartMotionPakRetail::Reset()
{
Value = 0;
Step = 16;
}
void CartMotionPakRetail::DoSavestate(Savestate* file)
{
CartCommon::DoSavestate(file);
file->Var8(&Value);
file->Var8(&Step);
}
u16 CartMotionPakRetail::ROMRead(u32 addr) const
{
// A9-A8 is pulled low on a real Motion Pack.
return 0xFCFF;
}
u8 CartMotionPakRetail::SRAMRead(u32 addr)
{
switch (Step)
{
case 0: // Synchronization - read 0xFF
Value = 0xFF;
break;
case 4: // X acceleration
Value = AccelerationToMotionPakRetail(Platform::Addon_MotionQuery(Platform::MotionAccelerationX, UserData));
break;
case 8: // Y acceleration
Value = AccelerationToMotionPakRetail(Platform::Addon_MotionQuery(Platform::MotionAccelerationY, UserData));
break;
case 12: // Z acceleration
Value = AccelerationToMotionPakRetail(Platform::Addon_MotionQuery(Platform::MotionAccelerationZ, UserData));
break;
case 16: // Synchronization - read 0b00
Step = 0;
return 0;
}
int shift = 6 - ((Step & 3) * 2);
Step++;
return (Value >> shift) & 0x03;
}
}
}

View File

@ -215,6 +215,9 @@ enum
{
GBAAddon_RAMExpansion = 1,
GBAAddon_RumblePak = 2,
GBAAddon_MotionPakHomebrew = 3,
GBAAddon_MotionPakRetail = 4,
GBAAddon_GuitarGrip = 5,
};
class SPU;

View File

@ -322,6 +322,18 @@ void Camera_CaptureFrame(int num, u32* frame, int width, int height, bool yuv, v
// interface for addon inputs
enum KeyType
{
KeyGuitarGripGreen,
KeyGuitarGripRed,
KeyGuitarGripYellow,
KeyGuitarGripBlue,
};
// Check if a given key is being pressed.
// @param type The type of the key to check.
bool Addon_KeyDown(KeyType type, void* userdata);
// Called by the DS Rumble Pak emulation to start the necessary
// rumble effects on the connected game controller, if available.
// @param len The duration of the controller rumble effect in milliseconds.
@ -331,6 +343,42 @@ void Addon_RumbleStart(u32 len, void* userdata);
// rumble effects on the connected game controller, if available.
void Addon_RumbleStop(void* userdata);
enum MotionQueryType
{
/**
* @brief X axis acceleration, measured in SI meters per second squared.
* On a DS, the X axis refers to the top screen X-axis (left ... right).
*/
MotionAccelerationX,
/**
* @brief Y axis acceleration, measured in SI meters per second squared.
* On a DS, the Y axis refers to the top screen Y-axis (bottom ... top).
*/
MotionAccelerationY,
/**
* @brief Z axis acceleration, measured in SI meters per second squared.
* On a DS, the Z axis refers to the axis perpendicular to the top screen (farther ... closer).
*/
MotionAccelerationZ,
/**
* @brief X axis rotation, measured in radians per second.
*/
MotionRotationX,
/**
* @brief Y axis rotation, measured in radians per second.
*/
MotionRotationY,
/**
* @brief Z axis rotation, measured in radians per second.
*/
MotionRotationZ,
};
// Called by the DS Motion Pak emulation to query the game controller's
// aceelration and rotation, if available.
// @param type The value being queried.
float Addon_MotionQuery(MotionQueryType type, void* userdata);
struct DynamicLibrary;
/**

View File

@ -169,6 +169,10 @@ LegacyEntry LegacyFile[] =
{"HKKey_PowerButton", 0, "Keyboard.HK_PowerButton", true},
{"HKKey_VolumeUp", 0, "Keyboard.HK_VolumeUp", true},
{"HKKey_VolumeDown", 0, "Keyboard.HK_VolumeDown", true},
{"HKKey_GuitarGripGreen", 0, "Keyboard.HK_GuitarGripGreen", true},
{"HKKey_GuitarGripRed", 0, "Keyboard.HK_GuitarGripRed", true},
{"HKKey_GuitarGripYellow", 0, "Keyboard.HK_GuitarGripYellow", true},
{"HKKey_GuitarGripBlue", 0, "Keyboard.HK_GuitarGripBlue", true},
{"HKJoy_Lid", 0, "Joystick.HK_Lid", true},
{"HKJoy_Mic", 0, "Joystick.HK_Mic", true},
@ -185,6 +189,10 @@ LegacyEntry LegacyFile[] =
{"HKJoy_PowerButton", 0, "Joystick.HK_PowerButton", true},
{"HKJoy_VolumeUp", 0, "Joystick.HK_VolumeUp", true},
{"HKJoy_VolumeDown", 0, "Joystick.HK_VolumeDown", true},
{"HKJoy_GuitarGripGreen", 0, "Joystick.HK_GuitarGripGreen", true},
{"HKJoy_GuitarGripRed", 0, "Joystick.HK_GuitarGripRed", true},
{"HKJoy_GuitarGripYellow", 0, "Joystick.HK_GuitarGripYellow", true},
{"HKJoy_GuitarGripBlue", 0, "Joystick.HK_GuitarGripBlue", true},
{"JoystickID", 0, "JoystickID", true},

View File

@ -2142,6 +2142,12 @@ QString EmuInstance::gbaAddonName(int addon)
return "Rumble Pak";
case GBAAddon_RAMExpansion:
return "Memory expansion";
case GBAAddon_MotionPakHomebrew:
return "Motion Pak (Homebrew)";
case GBAAddon_MotionPakRetail:
return "Motion Pack (Retail)";
case GBAAddon_GuitarGrip:
return "Guitar Grip";
}
return "???";

View File

@ -21,6 +21,7 @@
#include <SDL2/SDL.h>
#include "Platform.h"
#include "main.h"
#include "NDS.h"
#include "EmuThread.h"
@ -50,6 +51,10 @@ enum
HK_SlowMo,
HK_FastForwardToggle,
HK_SlowMoToggle,
HK_GuitarGripGreen,
HK_GuitarGripRed,
HK_GuitarGripYellow,
HK_GuitarGripBlue,
HK_MAX
};
@ -143,6 +148,9 @@ public:
void inputRumbleStart(melonDS::u32 len_ms);
void inputRumbleStop();
bool inputHotkeyDown(int id) { return hotkeyDown(id); }
float inputMotionQuery(melonDS::Platform::MotionQueryType type);
void setJoystick(int id);
int getJoystickID() { return joystickID; }
SDL_Joystick* getJoystick() { return joystick; }
@ -332,6 +340,8 @@ private:
int joystickID;
SDL_Joystick* joystick;
SDL_GameController* controller;
bool hasAccelerometer = false;
bool hasGyroscope = false;
bool hasRumble = false;
bool isRumbling = false;

View File

@ -19,6 +19,9 @@
#include <QKeyEvent>
#include <SDL2/SDL.h>
#include "Platform.h"
#include "SDL_gamecontroller.h"
#include "SDL_sensor.h"
#include "main.h"
#include "Config.h"
@ -59,7 +62,11 @@ const char* EmuInstance::hotkeyNames[HK_MAX] =
"HK_VolumeDown",
"HK_SlowMo",
"HK_FastForwardToggle",
"HK_SlowMoToggle"
"HK_SlowMoToggle",
"HK_GuitarGripGreen",
"HK_GuitarGripRed",
"HK_GuitarGripYellow",
"HK_GuitarGripBlue"
};
@ -81,6 +88,8 @@ void EmuInstance::inputInit()
joystick = nullptr;
controller = nullptr;
hasRumble = false;
hasAccelerometer = false;
hasGyroscope = false;
isRumbling = false;
inputLoadConfig();
}
@ -128,6 +137,48 @@ void EmuInstance::inputRumbleStop()
}
}
float EmuInstance::inputMotionQuery(melonDS::Platform::MotionQueryType type)
{
float values[3];
if (type <= melonDS::Platform::MotionAccelerationZ)
{
if (controller && hasAccelerometer)
if (SDL_GameControllerGetSensorData(controller, SDL_SENSOR_ACCEL, values, 3) == 0)
{
// Map values from DS console orientation to SDL controller orientation.
switch (type)
{
case melonDS::Platform::MotionAccelerationX:
return values[0];
case melonDS::Platform::MotionAccelerationY:
return -values[2];
case melonDS::Platform::MotionAccelerationZ:
return values[1];
}
}
}
else if (type <= melonDS::Platform::MotionRotationZ)
{
if (controller && hasGyroscope)
if (SDL_GameControllerGetSensorData(controller, SDL_SENSOR_GYRO, values, 3) == 0)
{
// Map values from DS console orientation to SDL controller orientation.
switch (type)
{
case melonDS::Platform::MotionRotationX:
return values[0];
case melonDS::Platform::MotionRotationY:
return -values[2];
case melonDS::Platform::MotionRotationZ:
return values[1];
}
}
}
if (type == melonDS::Platform::MotionAccelerationZ)
return SDL_STANDARD_GRAVITY;
return 0.0f;
}
void EmuInstance::setJoystick(int id)
{
@ -147,6 +198,8 @@ void EmuInstance::openJoystick()
controller = nullptr;
joystick = nullptr;
hasRumble = false;
hasAccelerometer = false;
hasGyroscope = false;
return;
}
@ -163,9 +216,17 @@ void EmuInstance::openJoystick()
if (controller)
{
if (SDL_GameControllerHasRumble(controller))
{
{
hasRumble = true;
}
}
if (SDL_GameControllerHasSensor(controller, SDL_SENSOR_ACCEL))
{
hasAccelerometer = SDL_GameControllerSetSensorEnabled(controller, SDL_SENSOR_ACCEL, SDL_TRUE) == 0;
}
if (SDL_GameControllerHasSensor(controller, SDL_SENSOR_GYRO))
{
hasGyroscope = SDL_GameControllerSetSensorEnabled(controller, SDL_SENSOR_GYRO, SDL_TRUE) == 0;
}
}
}
@ -176,8 +237,9 @@ void EmuInstance::closeJoystick()
SDL_GameControllerClose(controller);
controller = nullptr;
hasRumble = false;
hasAccelerometer = false;
hasGyroscope = false;
}
if (joystick)
{
SDL_JoystickClose(joystick);

View File

@ -32,12 +32,20 @@ static constexpr std::initializer_list<int> hk_addons =
{
HK_SolarSensorIncrease,
HK_SolarSensorDecrease,
HK_GuitarGripGreen,
HK_GuitarGripRed,
HK_GuitarGripYellow,
HK_GuitarGripBlue,
};
static constexpr std::initializer_list<const char*> hk_addons_labels =
{
"[Boktai] Sunlight + ",
"[Boktai] Sunlight - ",
"[Guitar Grip] Green",
"[Guitar Grip] Red",
"[Guitar Grip] Yellow",
"[Guitar Grip] Blue",
};
static_assert(hk_addons.size() == hk_addons_labels.size());

View File

@ -35,6 +35,7 @@
#include "Platform.h"
#include "Config.h"
#include "EmuInstance.h"
#include "main.h"
#include "CameraManager.h"
#include "Net.h"
@ -549,6 +550,18 @@ void Camera_CaptureFrame(int num, u32* frame, int width, int height, bool yuv, v
return camManager[num]->captureFrame(frame, width, height, yuv);
}
static const int hotkeyMap[] = {
HK_GuitarGripGreen,
HK_GuitarGripRed,
HK_GuitarGripYellow,
HK_GuitarGripBlue,
};
bool Addon_KeyDown(KeyType type, void* userdata)
{
return ((EmuInstance*)userdata)->inputHotkeyDown(hotkeyMap[type]);
}
void Addon_RumbleStart(u32 len, void* userdata)
{
((EmuInstance*)userdata)->inputRumbleStart(len);
@ -559,6 +572,11 @@ void Addon_RumbleStop(void* userdata)
((EmuInstance*)userdata)->inputRumbleStop();
}
float Addon_MotionQuery(MotionQueryType type, void* userdata)
{
return ((EmuInstance*)userdata)->inputMotionQuery(type);
}
DynamicLibrary* DynamicLibrary_Load(const char* lib)
{
return (DynamicLibrary*) SDL_LoadObject(lib);

View File

@ -16,6 +16,7 @@
with melonDS. If not, see http://www.gnu.org/licenses/.
*/
#include "NDS.h"
#include <stdlib.h>
#include <time.h>
#include <stdio.h>
@ -320,7 +321,14 @@ MainWindow::MainWindow(int id, EmuInstance* inst, QWidget* parent) :
QMenu * submenu = menu->addMenu("Insert add-on cart");
QAction *act;
int addons[] = {GBAAddon_RAMExpansion, GBAAddon_RumblePak, -1};
int addons[] = {
GBAAddon_RAMExpansion,
GBAAddon_RumblePak,
GBAAddon_MotionPakHomebrew,
GBAAddon_MotionPakRetail,
GBAAddon_GuitarGrip,
-1
};
for (int i = 0; addons[i] != -1; i++)
{
int addon = addons[i];

View File

@ -307,6 +307,10 @@ int main(int argc, char** argv)
{
printf("SDL couldn't init joystick\n");
}
if (SDL_Init(SDL_INIT_SENSOR) < 0)
{
printf("SDL couldn't init motion sensors\n");
}
if (SDL_Init(SDL_INIT_AUDIO) < 0)
{
const char* err = SDL_GetError();