mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2024-11-15 05:47:56 -07:00
WiimoteEmu: Update IR camera status from DesiredWiimoteState.
This commit is contained in:
parent
9669722dfc
commit
26fd4ea361
@ -52,36 +52,14 @@ int CameraLogic::BusWrite(u8 slave_addr, u8 addr, int count, const u8* data_in)
|
|||||||
return RawWrite(&m_reg_data, addr, count, data_in);
|
return RawWrite(&m_reg_data, addr, count, data_in);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CameraLogic::Update(const Common::Matrix44& transform, Common::Vec2 field_of_view)
|
std::array<CameraPoint, CameraLogic::NUM_POINTS>
|
||||||
|
CameraLogic::GetCameraPoints(const Common::Matrix44& transform, Common::Vec2 field_of_view)
|
||||||
{
|
{
|
||||||
// IR data is read from offset 0x37 on real hardware.
|
|
||||||
auto& data = m_reg_data.camera_data;
|
|
||||||
data.fill(0xff);
|
|
||||||
|
|
||||||
constexpr u8 OBJECT_TRACKING_ENABLE = 0x08;
|
|
||||||
|
|
||||||
// If Address 0x30 is not 0x08 the camera will return 0xFFs.
|
|
||||||
// The Wii seems to write 0x01 here before changing modes/sensitivities.
|
|
||||||
if (m_reg_data.enable_object_tracking != OBJECT_TRACKING_ENABLE)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// If the sensor bar is off the camera will see no LEDs and return 0xFFs.
|
|
||||||
if (!IOS::g_gpio_out[IOS::GPIO::SENSOR_BAR])
|
|
||||||
return;
|
|
||||||
|
|
||||||
using Common::Matrix33;
|
using Common::Matrix33;
|
||||||
using Common::Matrix44;
|
using Common::Matrix44;
|
||||||
using Common::Vec3;
|
using Common::Vec3;
|
||||||
using Common::Vec4;
|
using Common::Vec4;
|
||||||
|
|
||||||
// FYI: A real wiimote normally only returns 1 point for each LED cluster (2 total).
|
|
||||||
// Sending all 4 points can actually cause some stuttering issues.
|
|
||||||
constexpr int NUM_POINTS = 2;
|
|
||||||
|
|
||||||
// Range from 0-15. Small values (2-4) seem to be very typical.
|
|
||||||
// This is reduced based on distance from sensor bar.
|
|
||||||
constexpr int MAX_POINT_SIZE = 15;
|
|
||||||
|
|
||||||
const std::array<Vec3, NUM_POINTS> leds{
|
const std::array<Vec3, NUM_POINTS> leds{
|
||||||
Vec3{-SENSOR_BAR_LED_SEPARATION / 2, 0, 0},
|
Vec3{-SENSOR_BAR_LED_SEPARATION / 2, 0, 0},
|
||||||
Vec3{SENSOR_BAR_LED_SEPARATION / 2, 0, 0},
|
Vec3{SENSOR_BAR_LED_SEPARATION / 2, 0, 0},
|
||||||
@ -91,12 +69,6 @@ void CameraLogic::Update(const Common::Matrix44& transform, Common::Vec2 field_o
|
|||||||
Matrix44::Perspective(field_of_view.y, field_of_view.x / field_of_view.y, 0.001f, 1000) *
|
Matrix44::Perspective(field_of_view.y, field_of_view.x / field_of_view.y, 0.001f, 1000) *
|
||||||
Matrix44::FromMatrix33(Matrix33::RotateX(float(MathUtil::TAU / 4))) * transform;
|
Matrix44::FromMatrix33(Matrix33::RotateX(float(MathUtil::TAU / 4))) * transform;
|
||||||
|
|
||||||
struct CameraPoint
|
|
||||||
{
|
|
||||||
IRBasic::IRObject position;
|
|
||||||
u8 size = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::array<CameraPoint, leds.size()> camera_points;
|
std::array<CameraPoint, leds.size()> camera_points;
|
||||||
|
|
||||||
std::transform(leds.begin(), leds.end(), camera_points.begin(), [&](const Vec3& v) {
|
std::transform(leds.begin(), leds.end(), camera_points.begin(), [&](const Vec3& v) {
|
||||||
@ -112,13 +84,32 @@ void CameraLogic::Update(const Common::Matrix44& transform, Common::Vec2 field_o
|
|||||||
const auto point_size = std::lround(MAX_POINT_SIZE / point.w / 2);
|
const auto point_size = std::lround(MAX_POINT_SIZE / point.w / 2);
|
||||||
|
|
||||||
if (x >= 0 && y >= 0 && x < CAMERA_RES_X && y < CAMERA_RES_Y)
|
if (x >= 0 && y >= 0 && x < CAMERA_RES_X && y < CAMERA_RES_Y)
|
||||||
return CameraPoint{{u16(x), u16(y)}, u8(point_size)};
|
return CameraPoint({u16(x), u16(y)}, u8(point_size));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 0xFFFFs are interpreted as "not visible".
|
return CameraPoint();
|
||||||
return CameraPoint{{0xffff, 0xffff}, 0xff};
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return camera_points;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CameraLogic::Update(const std::array<CameraPoint, NUM_POINTS>& camera_points)
|
||||||
|
{
|
||||||
|
// IR data is read from offset 0x37 on real hardware.
|
||||||
|
auto& data = m_reg_data.camera_data;
|
||||||
|
data.fill(0xff);
|
||||||
|
|
||||||
|
constexpr u8 OBJECT_TRACKING_ENABLE = 0x08;
|
||||||
|
|
||||||
|
// If Address 0x30 is not 0x08 the camera will return 0xFFs.
|
||||||
|
// The Wii seems to write 0x01 here before changing modes/sensitivities.
|
||||||
|
if (m_reg_data.enable_object_tracking != OBJECT_TRACKING_ENABLE)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// If the sensor bar is off the camera will see no LEDs and return 0xFFs.
|
||||||
|
if (!IOS::g_gpio_out[IOS::GPIO::SENSOR_BAR])
|
||||||
|
return;
|
||||||
|
|
||||||
switch (m_reg_data.mode)
|
switch (m_reg_data.mode)
|
||||||
{
|
{
|
||||||
case IR_MODE_BASIC:
|
case IR_MODE_BASIC:
|
||||||
|
@ -16,11 +16,26 @@ class Matrix44;
|
|||||||
|
|
||||||
namespace WiimoteEmu
|
namespace WiimoteEmu
|
||||||
{
|
{
|
||||||
|
using IRObject = Common::TVec2<u16>;
|
||||||
|
|
||||||
|
struct CameraPoint
|
||||||
|
{
|
||||||
|
IRObject position;
|
||||||
|
u8 size;
|
||||||
|
|
||||||
|
// 0xFFFFs are interpreted as "not visible".
|
||||||
|
constexpr CameraPoint() : position({0xffff, 0xffff}), size(0xff) {}
|
||||||
|
constexpr CameraPoint(IRObject position_, u8 size_) : position(position_), size(size_) {}
|
||||||
|
constexpr bool operator==(const CameraPoint& other) const
|
||||||
|
{
|
||||||
|
return this->position == other.position && this->size == other.size;
|
||||||
|
}
|
||||||
|
constexpr bool operator!=(const CameraPoint& other) const { return !(*this == other); }
|
||||||
|
};
|
||||||
|
|
||||||
// Four bytes for two objects. Filled with 0xFF if empty
|
// Four bytes for two objects. Filled with 0xFF if empty
|
||||||
struct IRBasic
|
struct IRBasic
|
||||||
{
|
{
|
||||||
using IRObject = Common::TVec2<u16>;
|
|
||||||
|
|
||||||
u8 x1;
|
u8 x1;
|
||||||
u8 y1;
|
u8 y1;
|
||||||
u8 x2hi : 2;
|
u8 x2hi : 2;
|
||||||
@ -59,8 +74,8 @@ struct IRExtended
|
|||||||
u8 xhi : 2;
|
u8 xhi : 2;
|
||||||
u8 yhi : 2;
|
u8 yhi : 2;
|
||||||
|
|
||||||
auto GetPosition() const { return IRBasic::IRObject(xhi << 8 | x, yhi << 8 | y); }
|
auto GetPosition() const { return IRObject(xhi << 8 | x, yhi << 8 | y); }
|
||||||
void SetPosition(const IRBasic::IRObject& obj)
|
void SetPosition(const IRObject& obj)
|
||||||
{
|
{
|
||||||
x = obj.x;
|
x = obj.x;
|
||||||
xhi = obj.x >> 8;
|
xhi = obj.x >> 8;
|
||||||
@ -109,9 +124,19 @@ public:
|
|||||||
IR_MODE_FULL = 5,
|
IR_MODE_FULL = 5,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// FYI: A real wiimote normally only returns 1 point for each LED cluster (2 total).
|
||||||
|
// Sending all 4 points can actually cause some stuttering issues.
|
||||||
|
static constexpr int NUM_POINTS = 2;
|
||||||
|
|
||||||
|
// Range from 0-15. Small values (2-4) seem to be very typical.
|
||||||
|
// This is reduced based on distance from sensor bar.
|
||||||
|
static constexpr int MAX_POINT_SIZE = 15;
|
||||||
|
|
||||||
void Reset();
|
void Reset();
|
||||||
void DoState(PointerWrap& p);
|
void DoState(PointerWrap& p);
|
||||||
void Update(const Common::Matrix44& transform, Common::Vec2 field_of_view);
|
static std::array<CameraPoint, NUM_POINTS> GetCameraPoints(const Common::Matrix44& transform,
|
||||||
|
Common::Vec2 field_of_view);
|
||||||
|
void Update(const std::array<CameraPoint, NUM_POINTS>& camera_points);
|
||||||
void SetEnabled(bool is_enabled);
|
void SetEnabled(bool is_enabled);
|
||||||
|
|
||||||
static constexpr u8 I2C_ADDR = 0x58;
|
static constexpr u8 I2C_ADDR = 0x58;
|
||||||
|
@ -3,7 +3,10 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
|
||||||
#include "Core/HW/WiimoteCommon/WiimoteReport.h"
|
#include "Core/HW/WiimoteCommon/WiimoteReport.h"
|
||||||
|
#include "Core/HW/WiimoteEmu/Camera.h"
|
||||||
#include "Core/HW/WiimoteEmu/WiimoteEmu.h"
|
#include "Core/HW/WiimoteEmu/WiimoteEmu.h"
|
||||||
|
|
||||||
namespace WiimoteEmu
|
namespace WiimoteEmu
|
||||||
@ -14,7 +17,11 @@ struct DesiredWiimoteState
|
|||||||
static constexpr WiimoteCommon::AccelData DEFAULT_ACCELERATION = WiimoteCommon::AccelData(
|
static constexpr WiimoteCommon::AccelData DEFAULT_ACCELERATION = WiimoteCommon::AccelData(
|
||||||
{Wiimote::ACCEL_ZERO_G << 2, Wiimote::ACCEL_ZERO_G << 2, Wiimote::ACCEL_ONE_G << 2});
|
{Wiimote::ACCEL_ZERO_G << 2, Wiimote::ACCEL_ZERO_G << 2, Wiimote::ACCEL_ONE_G << 2});
|
||||||
|
|
||||||
|
// No light detected by the IR camera.
|
||||||
|
static constexpr std::array<CameraPoint, 2> DEFAULT_CAMERA = {CameraPoint(), CameraPoint()};
|
||||||
|
|
||||||
WiimoteCommon::ButtonData buttons{}; // non-button state in this is ignored
|
WiimoteCommon::ButtonData buttons{}; // non-button state in this is ignored
|
||||||
WiimoteCommon::AccelData acceleration = DEFAULT_ACCELERATION;
|
WiimoteCommon::AccelData acceleration = DEFAULT_ACCELERATION;
|
||||||
|
std::array<CameraPoint, 2> camera_points = DEFAULT_CAMERA;
|
||||||
};
|
};
|
||||||
} // namespace WiimoteEmu
|
} // namespace WiimoteEmu
|
||||||
|
@ -454,6 +454,12 @@ DesiredWiimoteState Wiimote::BuildDesiredWiimoteState()
|
|||||||
wiimote_state.acceleration =
|
wiimote_state.acceleration =
|
||||||
ConvertAccelData(GetTotalAcceleration(), ACCEL_ZERO_G << 2, ACCEL_ONE_G << 2);
|
ConvertAccelData(GetTotalAcceleration(), ACCEL_ZERO_G << 2, ACCEL_ONE_G << 2);
|
||||||
|
|
||||||
|
// Calculate IR camera state.
|
||||||
|
wiimote_state.camera_points = CameraLogic::GetCameraPoints(
|
||||||
|
GetTotalTransformation(),
|
||||||
|
Common::Vec2(m_fov_x_setting.GetValue(), m_fov_y_setting.GetValue()) / 360 *
|
||||||
|
float(MathUtil::TAU));
|
||||||
|
|
||||||
return wiimote_state;
|
return wiimote_state;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -545,9 +551,7 @@ void Wiimote::SendDataReport(const DesiredWiimoteState& target_state)
|
|||||||
{
|
{
|
||||||
// Note: Camera logic currently contains no changing state so we can just update it here.
|
// Note: Camera logic currently contains no changing state so we can just update it here.
|
||||||
// If that changes this should be moved to Wiimote::Update();
|
// If that changes this should be moved to Wiimote::Update();
|
||||||
m_camera_logic.Update(GetTotalTransformation(),
|
m_camera_logic.Update(target_state.camera_points);
|
||||||
Common::Vec2(m_fov_x_setting.GetValue(), m_fov_y_setting.GetValue()) /
|
|
||||||
360 * float(MathUtil::TAU));
|
|
||||||
|
|
||||||
// The real wiimote reads camera data from the i2c bus starting at offset 0x37:
|
// The real wiimote reads camera data from the i2c bus starting at offset 0x37:
|
||||||
const u8 camera_data_offset =
|
const u8 camera_data_offset =
|
||||||
|
@ -1256,7 +1256,7 @@ void Device::IRState::ProcessData(const std::array<WiimoteEmu::IRBasic, 2>& data
|
|||||||
// A better implementation might extrapolate points when they fall out of camera view.
|
// A better implementation might extrapolate points when they fall out of camera view.
|
||||||
// But just averaging visible points actually seems to work very well.
|
// But just averaging visible points actually seems to work very well.
|
||||||
|
|
||||||
using IRObject = WiimoteEmu::IRBasic::IRObject;
|
using IRObject = WiimoteEmu::IRObject;
|
||||||
|
|
||||||
MathUtil::RunningVariance<Common::Vec2> points;
|
MathUtil::RunningVariance<Common::Vec2> points;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user