mirror of
https://github.com/melonDS-emu/melonDS.git
synced 2024-11-14 13:27:41 -07:00
Merge 30c93d827f
into 5e8beb3ab7
This commit is contained in:
commit
4fcbe968c5
@ -30,6 +30,7 @@ add_library(core STATIC
|
|||||||
FATStorage.cpp
|
FATStorage.cpp
|
||||||
FIFO.h
|
FIFO.h
|
||||||
GBACart.cpp
|
GBACart.cpp
|
||||||
|
GBACartMotionPak.cpp
|
||||||
GPU.cpp
|
GPU.cpp
|
||||||
GPU2D.cpp
|
GPU2D.cpp
|
||||||
GPU2D_Soft.cpp
|
GPU2D_Soft.cpp
|
||||||
|
@ -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))
|
GBACartSlot::GBACartSlot(melonDS::NDS& nds, std::unique_ptr<CartCommon>&& cart) noexcept : NDS(nds), Cart(std::move(cart))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -874,6 +895,15 @@ void GBACartSlot::LoadAddon(void* userdata, int type) noexcept
|
|||||||
case GBAAddon_RumblePak:
|
case GBAAddon_RumblePak:
|
||||||
Cart = std::make_unique<CartRumblePak>(userdata);
|
Cart = std::make_unique<CartRumblePak>(userdata);
|
||||||
break;
|
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:
|
default:
|
||||||
Log(LogLevel::Warn, "GBACart: !! invalid addon type %d\n", type);
|
Log(LogLevel::Warn, "GBACart: !! invalid addon type %d\n", type);
|
||||||
|
@ -33,6 +33,9 @@ enum CartType
|
|||||||
GameSolarSensor = 0x102,
|
GameSolarSensor = 0x102,
|
||||||
RAMExpansion = 0x201,
|
RAMExpansion = 0x201,
|
||||||
RumblePak = 0x202,
|
RumblePak = 0x202,
|
||||||
|
MotionPakHomebrew = 0x203,
|
||||||
|
MotionPakRetail = 0x204,
|
||||||
|
GuitarGrip = 0x205,
|
||||||
};
|
};
|
||||||
|
|
||||||
// CartCommon -- base code shared by all cart types
|
// CartCommon -- base code shared by all cart types
|
||||||
@ -211,11 +214,68 @@ private:
|
|||||||
u16 RumbleState = 0;
|
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
|
// possible inputs for GBA carts that might accept user input
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
Input_SolarSensorDown = 0,
|
Input_SolarSensorDown = 0,
|
||||||
Input_SolarSensorUp,
|
Input_SolarSensorUp,
|
||||||
|
Input_GuitarGripGreen,
|
||||||
|
Input_GuitarGripRed,
|
||||||
|
Input_GuitarGripYellow,
|
||||||
|
Input_GuitarGripBlue,
|
||||||
};
|
};
|
||||||
|
|
||||||
class GBACartSlot
|
class GBACartSlot
|
||||||
|
196
src/GBACartMotionPak.cpp
Normal file
196
src/GBACartMotionPak.cpp
Normal 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -211,6 +211,9 @@ enum
|
|||||||
{
|
{
|
||||||
GBAAddon_RAMExpansion = 1,
|
GBAAddon_RAMExpansion = 1,
|
||||||
GBAAddon_RumblePak = 2,
|
GBAAddon_RumblePak = 2,
|
||||||
|
GBAAddon_MotionPakHomebrew = 3,
|
||||||
|
GBAAddon_MotionPakRetail = 4,
|
||||||
|
GBAAddon_GuitarGrip = 5,
|
||||||
};
|
};
|
||||||
|
|
||||||
class SPU;
|
class SPU;
|
||||||
|
@ -322,6 +322,18 @@ void Camera_CaptureFrame(int num, u32* frame, int width, int height, bool yuv, v
|
|||||||
|
|
||||||
// interface for addon inputs
|
// 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
|
// Called by the DS Rumble Pak emulation to start the necessary
|
||||||
// rumble effects on the connected game controller, if available.
|
// rumble effects on the connected game controller, if available.
|
||||||
// @param len The duration of the controller rumble effect in milliseconds.
|
// @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.
|
// rumble effects on the connected game controller, if available.
|
||||||
void Addon_RumbleStop(void* userdata);
|
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;
|
struct DynamicLibrary;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -169,6 +169,10 @@ LegacyEntry LegacyFile[] =
|
|||||||
{"HKKey_PowerButton", 0, "Keyboard.HK_PowerButton", true},
|
{"HKKey_PowerButton", 0, "Keyboard.HK_PowerButton", true},
|
||||||
{"HKKey_VolumeUp", 0, "Keyboard.HK_VolumeUp", true},
|
{"HKKey_VolumeUp", 0, "Keyboard.HK_VolumeUp", true},
|
||||||
{"HKKey_VolumeDown", 0, "Keyboard.HK_VolumeDown", 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_Lid", 0, "Joystick.HK_Lid", true},
|
||||||
{"HKJoy_Mic", 0, "Joystick.HK_Mic", true},
|
{"HKJoy_Mic", 0, "Joystick.HK_Mic", true},
|
||||||
@ -185,6 +189,10 @@ LegacyEntry LegacyFile[] =
|
|||||||
{"HKJoy_PowerButton", 0, "Joystick.HK_PowerButton", true},
|
{"HKJoy_PowerButton", 0, "Joystick.HK_PowerButton", true},
|
||||||
{"HKJoy_VolumeUp", 0, "Joystick.HK_VolumeUp", true},
|
{"HKJoy_VolumeUp", 0, "Joystick.HK_VolumeUp", true},
|
||||||
{"HKJoy_VolumeDown", 0, "Joystick.HK_VolumeDown", 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},
|
{"JoystickID", 0, "JoystickID", true},
|
||||||
|
|
||||||
|
@ -2088,6 +2088,12 @@ QString EmuInstance::gbaAddonName(int addon)
|
|||||||
return "Rumble Pak";
|
return "Rumble Pak";
|
||||||
case GBAAddon_RAMExpansion:
|
case GBAAddon_RAMExpansion:
|
||||||
return "Memory expansion";
|
return "Memory expansion";
|
||||||
|
case GBAAddon_MotionPakHomebrew:
|
||||||
|
return "Motion Pak (Homebrew)";
|
||||||
|
case GBAAddon_MotionPakRetail:
|
||||||
|
return "Motion Pack (Retail)";
|
||||||
|
case GBAAddon_GuitarGrip:
|
||||||
|
return "Guitar Grip";
|
||||||
}
|
}
|
||||||
|
|
||||||
return "???";
|
return "???";
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
|
|
||||||
#include <SDL2/SDL.h>
|
#include <SDL2/SDL.h>
|
||||||
|
|
||||||
|
#include "Platform.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "NDS.h"
|
#include "NDS.h"
|
||||||
#include "EmuThread.h"
|
#include "EmuThread.h"
|
||||||
@ -50,6 +51,10 @@ enum
|
|||||||
HK_SlowMo,
|
HK_SlowMo,
|
||||||
HK_FastForwardToggle,
|
HK_FastForwardToggle,
|
||||||
HK_SlowMoToggle,
|
HK_SlowMoToggle,
|
||||||
|
HK_GuitarGripGreen,
|
||||||
|
HK_GuitarGripRed,
|
||||||
|
HK_GuitarGripYellow,
|
||||||
|
HK_GuitarGripBlue,
|
||||||
HK_MAX
|
HK_MAX
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -143,6 +148,9 @@ public:
|
|||||||
void inputRumbleStart(melonDS::u32 len_ms);
|
void inputRumbleStart(melonDS::u32 len_ms);
|
||||||
void inputRumbleStop();
|
void inputRumbleStop();
|
||||||
|
|
||||||
|
bool inputHotkeyDown(int id) { return hotkeyDown(id); }
|
||||||
|
float inputMotionQuery(melonDS::Platform::MotionQueryType type);
|
||||||
|
|
||||||
void setJoystick(int id);
|
void setJoystick(int id);
|
||||||
int getJoystickID() { return joystickID; }
|
int getJoystickID() { return joystickID; }
|
||||||
SDL_Joystick* getJoystick() { return joystick; }
|
SDL_Joystick* getJoystick() { return joystick; }
|
||||||
@ -326,6 +334,8 @@ private:
|
|||||||
int joystickID;
|
int joystickID;
|
||||||
SDL_Joystick* joystick;
|
SDL_Joystick* joystick;
|
||||||
SDL_GameController* controller;
|
SDL_GameController* controller;
|
||||||
|
bool hasAccelerometer = false;
|
||||||
|
bool hasGyroscope = false;
|
||||||
bool hasRumble = false;
|
bool hasRumble = false;
|
||||||
bool isRumbling = false;
|
bool isRumbling = false;
|
||||||
|
|
||||||
|
@ -19,6 +19,9 @@
|
|||||||
#include <QKeyEvent>
|
#include <QKeyEvent>
|
||||||
#include <SDL2/SDL.h>
|
#include <SDL2/SDL.h>
|
||||||
|
|
||||||
|
#include "Platform.h"
|
||||||
|
#include "SDL_gamecontroller.h"
|
||||||
|
#include "SDL_sensor.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
|
|
||||||
@ -59,7 +62,11 @@ const char* EmuInstance::hotkeyNames[HK_MAX] =
|
|||||||
"HK_VolumeDown",
|
"HK_VolumeDown",
|
||||||
"HK_SlowMo",
|
"HK_SlowMo",
|
||||||
"HK_FastForwardToggle",
|
"HK_FastForwardToggle",
|
||||||
"HK_SlowMoToggle"
|
"HK_SlowMoToggle",
|
||||||
|
"HK_GuitarGripGreen",
|
||||||
|
"HK_GuitarGripRed",
|
||||||
|
"HK_GuitarGripYellow",
|
||||||
|
"HK_GuitarGripBlue"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -81,6 +88,8 @@ void EmuInstance::inputInit()
|
|||||||
joystick = nullptr;
|
joystick = nullptr;
|
||||||
controller = nullptr;
|
controller = nullptr;
|
||||||
hasRumble = false;
|
hasRumble = false;
|
||||||
|
hasAccelerometer = false;
|
||||||
|
hasGyroscope = false;
|
||||||
isRumbling = false;
|
isRumbling = false;
|
||||||
inputLoadConfig();
|
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)
|
void EmuInstance::setJoystick(int id)
|
||||||
{
|
{
|
||||||
@ -147,6 +198,8 @@ void EmuInstance::openJoystick()
|
|||||||
controller = nullptr;
|
controller = nullptr;
|
||||||
joystick = nullptr;
|
joystick = nullptr;
|
||||||
hasRumble = false;
|
hasRumble = false;
|
||||||
|
hasAccelerometer = false;
|
||||||
|
hasGyroscope = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -163,9 +216,17 @@ void EmuInstance::openJoystick()
|
|||||||
if (controller)
|
if (controller)
|
||||||
{
|
{
|
||||||
if (SDL_GameControllerHasRumble(controller))
|
if (SDL_GameControllerHasRumble(controller))
|
||||||
{
|
{
|
||||||
hasRumble = true;
|
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);
|
SDL_GameControllerClose(controller);
|
||||||
controller = nullptr;
|
controller = nullptr;
|
||||||
hasRumble = false;
|
hasRumble = false;
|
||||||
|
hasAccelerometer = false;
|
||||||
|
hasGyroscope = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (joystick)
|
if (joystick)
|
||||||
{
|
{
|
||||||
SDL_JoystickClose(joystick);
|
SDL_JoystickClose(joystick);
|
||||||
|
@ -32,12 +32,20 @@ static constexpr std::initializer_list<int> hk_addons =
|
|||||||
{
|
{
|
||||||
HK_SolarSensorIncrease,
|
HK_SolarSensorIncrease,
|
||||||
HK_SolarSensorDecrease,
|
HK_SolarSensorDecrease,
|
||||||
|
HK_GuitarGripGreen,
|
||||||
|
HK_GuitarGripRed,
|
||||||
|
HK_GuitarGripYellow,
|
||||||
|
HK_GuitarGripBlue,
|
||||||
};
|
};
|
||||||
|
|
||||||
static constexpr std::initializer_list<const char*> hk_addons_labels =
|
static constexpr std::initializer_list<const char*> hk_addons_labels =
|
||||||
{
|
{
|
||||||
"[Boktai] Sunlight + ",
|
"[Boktai] Sunlight + ",
|
||||||
"[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());
|
static_assert(hk_addons.size() == hk_addons_labels.size());
|
||||||
|
@ -35,6 +35,7 @@
|
|||||||
|
|
||||||
#include "Platform.h"
|
#include "Platform.h"
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
|
#include "EmuInstance.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "CameraManager.h"
|
#include "CameraManager.h"
|
||||||
#include "Net.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);
|
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)
|
void Addon_RumbleStart(u32 len, void* userdata)
|
||||||
{
|
{
|
||||||
((EmuInstance*)userdata)->inputRumbleStart(len);
|
((EmuInstance*)userdata)->inputRumbleStart(len);
|
||||||
@ -559,6 +572,11 @@ void Addon_RumbleStop(void* userdata)
|
|||||||
((EmuInstance*)userdata)->inputRumbleStop();
|
((EmuInstance*)userdata)->inputRumbleStop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float Addon_MotionQuery(MotionQueryType type, void* userdata)
|
||||||
|
{
|
||||||
|
return ((EmuInstance*)userdata)->inputMotionQuery(type);
|
||||||
|
}
|
||||||
|
|
||||||
DynamicLibrary* DynamicLibrary_Load(const char* lib)
|
DynamicLibrary* DynamicLibrary_Load(const char* lib)
|
||||||
{
|
{
|
||||||
return (DynamicLibrary*) SDL_LoadObject(lib);
|
return (DynamicLibrary*) SDL_LoadObject(lib);
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
with melonDS. If not, see http://www.gnu.org/licenses/.
|
with melonDS. If not, see http://www.gnu.org/licenses/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "NDS.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@ -320,7 +321,14 @@ MainWindow::MainWindow(int id, EmuInstance* inst, QWidget* parent) :
|
|||||||
QMenu * submenu = menu->addMenu("Insert add-on cart");
|
QMenu * submenu = menu->addMenu("Insert add-on cart");
|
||||||
QAction *act;
|
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++)
|
for (int i = 0; addons[i] != -1; i++)
|
||||||
{
|
{
|
||||||
int addon = addons[i];
|
int addon = addons[i];
|
||||||
|
@ -307,6 +307,10 @@ int main(int argc, char** argv)
|
|||||||
{
|
{
|
||||||
printf("SDL couldn't init joystick\n");
|
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)
|
if (SDL_Init(SDL_INIT_AUDIO) < 0)
|
||||||
{
|
{
|
||||||
const char* err = SDL_GetError();
|
const char* err = SDL_GetError();
|
||||||
|
Loading…
Reference in New Issue
Block a user