summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDennis Peeten <dpeeten@onsneteindhoven.nl>2008-05-25 21:48:24 (GMT)
committerDennis Peeten <dpeeten@onsneteindhoven.nl>2008-05-25 21:48:24 (GMT)
commitfcca48f210141e14e558a7064bcc6250e7aaf6fb (patch)
tree39a7551f66b56fa6cbb5e28b0bfef1ea3ca6e674
parentf873113aa3c2a8054f16aed8bf249dc4a448189a (diff)
download2iv55-fcca48f210141e14e558a7064bcc6250e7aaf6fb.zip
2iv55-fcca48f210141e14e558a7064bcc6250e7aaf6fb.tar.gz
2iv55-fcca48f210141e14e558a7064bcc6250e7aaf6fb.tar.bz2
-rw-r--r--matchblox/glew32.dllbin0 -> 212992 bytes
-rw-r--r--matchblox/include/wiimote.h335
-rw-r--r--matchblox/include/wiimote_state.h391
3 files changed, 726 insertions, 0 deletions
diff --git a/matchblox/glew32.dll b/matchblox/glew32.dll
new file mode 100644
index 0000000..6ae9984
--- /dev/null
+++ b/matchblox/glew32.dll
Binary files differ
diff --git a/matchblox/include/wiimote.h b/matchblox/include/wiimote.h
new file mode 100644
index 0000000..e208111
--- /dev/null
+++ b/matchblox/include/wiimote.h
@@ -0,0 +1,335 @@
+// _______________________________________________________________________________
+//
+// - WiiYourself! - native C++ Wiimote library v1.00
+// (c) gl.tter 2007-8 - http://gl.tter.org
+//
+// see License.txt for conditions of use. see History.txt for change log.
+// _______________________________________________________________________________
+//
+// wiimote.h (tab = 4 spaces)
+
+#ifdef _MSC_VER // VC
+# pragma once
+#endif
+
+#ifndef _WIIMOTE_H
+# define _WIIMOTE_H
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <tchar.h> // auto Unicode/Ansi support
+#include <queue> // for HID write method
+#include <list> // for state recording
+ using namespace std;
+
+
+#ifdef _MSC_VER // VC-specific: _DEBUG build only _ASSERT() sanity checks
+# include <crtdbg.h>
+#else
+# define _ASSERT // (add your compiler's implementation if you like)
+#endif
+
+#include "wiimote_state.h"
+
+// configs:
+ // we request periodic status report updates to refresh the battery level
+// and to detect connection loss (through failed writes)
+#define REQUEST_STATUS_EVERY_MS 1000
+// all threads (read/parse, audio streaming, async rumble...) use this priority
+#define WORKER_THREAD_PRIORITY THREAD_PRIORITY_HIGHEST
+
+ // internals
+#define WIIYOURSELF_VERSION_MAJOR 1
+#define WIIYOURSELF_VERSION_MINOR1 0
+#define WIIYOURSELF_VERSION_MINOR2 0
+#define WIIYOURSELF_VERSION_STR _T("1.00")
+
+// clarity
+typedef HANDLE EVENT;
+
+
+// state data changes can be signalled to the app via a callback. Set the wiimote
+// object's 'ChangedCallback' any time to enable them. 'changed' is a combination
+// of flags indicating which state has changed since the last callback.
+typedef void (*state_changed_callback) (class wiimote &owner,
+ state_change_flags changed);
+
+// internals
+typedef BOOLEAN (__stdcall *hidwrite_ptr)(HANDLE HidDeviceObject,
+ PVOID ReportBuffer,
+ ULONG ReportBufferLength);
+
+// wiimote class - connects and manages a wiimote and its optional extensions
+// (Nunchuk/Classic Controller), and exposes their state
+class wiimote : public wiimote_state
+ {
+ public:
+ wiimote ();
+ ~wiimote ();
+
+ public:
+ // wiimote data input mode (use with SetReportType())
+ // (only enable what you need to save battery power)
+ enum input_report
+ {
+ // combinations if buttons/acceleration/IR/Extension data
+ IN_BUTTONS = 0x30,
+ IN_BUTTONS_ACCEL = 0x31,
+ IN_BUTTONS_ACCEL_IR = 0x33, // reports IR EXTENDED data (dot sizes)
+ IN_BUTTONS_ACCEL_EXT = 0x35,
+ IN_BUTTONS_ACCEL_IR_EXT = 0x37, // reports IR BASIC data (no dot sizes)
+ };
+
+
+ public: // convenience accessors:
+ inline bool IsConnected () const { return bStatusReceived; }
+ // if IsConnected() unexpectedly returns false, connection was probably lost
+ inline bool ConnectionLost () const { return bConnectionLost; }
+ inline bool NunchukConnected () const { return (Internal.bExtension && (Internal.ExtensionType==wiimote_state::NUNCHUK)); }
+ inline bool ClassicConnected () const { return (Internal.bExtension && (Internal.ExtensionType==wiimote_state::CLASSIC)); }
+ inline bool IsPlayingAudio () const { return (Internal.Speaker.Freq && Internal.Speaker.Volume); }
+ inline bool IsPlayingSample () const { return IsPlayingAudio() && (CurrentSample != NULL); }
+ inline bool IsUsingHIDwrites () const { return bUseHIDwrite; }
+ inline bool IsRecordingState () const { return Recording.bEnabled; }
+
+ static inline unsigned TotalConnected() { return _TotalConnected; }
+
+
+ public: // data
+ // optional callbacks - set these to your own fuctions (if required)
+ state_changed_callback ChangedCallback;
+ // you can avoid unnecessary callback overhead by specifying a mask
+ // of which state changes should trigger them (default is any)
+ state_change_flags CallbackTriggerFlags;
+
+ // get the button name from its bit index (some bits are unused)
+ static const TCHAR* ButtonNameFromBit [16];
+ // same for the Classic Controller
+ static const TCHAR* ClassicButtonNameFromBit [16];
+ // get the frequency from speaker_freq enum
+ static const unsigned FreqLookup [10];
+
+ public: // methods
+ // call Connect() first - returns true if wiimote was found & enabled
+ // - 'wiimote_index' specifies which *installed* (not necessarily
+ // *connected*) wiimote should be tried (0 = first).
+ // if you just want the first *available* wiimote that isn't already
+ // in use, pass in FIRST_AVAILABLE (default).
+ // - 'force_hidwrites' forces HID output method (it's auto-selected
+ // when needed and less efficient, so only force for testing).
+ static const unsigned FIRST_AVAILABLE = 0xffffffff;
+ bool Connect (unsigned wiimote_index = FIRST_AVAILABLE,
+ bool force_hidwrites = false);
+ // disconnect from the controller and stop reading data from it
+ void Disconnect ();
+ // set wiimote reporting mode (call after Connnect())
+ // continous = true forces the wiimote to send constant updates, even when
+ // nothing has changed.
+ // = false only sends data when something has changed (note that
+ // acceleration data will cause frequent updates anyway as it
+ // jitters even when the wiimote is stationary)
+ void SetReportType (input_report type, bool continuous = false);
+
+ // to read the state via polling (reading the public state data direct from
+ // the wiimote object) you must call RefreshState() at the top of every pass.
+ // returns a combination of flags to indicate which state (if any) has
+ // changed since the last call.
+ inline state_change_flags RefreshState () { return _RefreshState(false); }
+
+ // reset the wiimote (changes report type to non-continuous buttons-only,
+ // clears LEDs & rumble, mutes & disables speaker)
+ void Reset ();
+ // set/clear the wiimote LEDs
+ void SetLEDs (BYTE led_bits); // bits 0-3 are valid
+ // set/clear rumble
+ void SetRumble (bool on);
+ // alternative - rumble for a fixed amount of time (asynchronous)
+ void RumbleForAsync (unsigned milliseconds);
+
+ // *experimental* speaker support:
+ bool MuteSpeaker (bool on);
+ bool EnableSpeaker (bool on);
+ bool PlaySquareWave (speaker_freq freq, BYTE volume = 0x40);
+ // note: PlaySample currently streams from the passed-in wiimote_sample -
+ // don't delete it until playback has stopped.
+ bool PlaySample (const wiimote_sample &sample,
+ BYTE volume = 0x40,
+ speaker_freq freq_override = FREQ_NONE);
+
+ // 16bit mono sample loading/conversion to native format:
+ // .wav sample
+ static bool Load16bitMonoSampleWAV (const TCHAR* filepath,
+ wiimote_sample &out);
+ // raw 16bit mono audio data (can be signed or unsigned)
+ static bool Load16BitMonoSampleRAW (const TCHAR* filepath,
+ bool _signed,
+ speaker_freq freq,
+ wiimote_sample &out);
+ // converts a 16bit mono sample array to a wiimote_sample
+ static bool Convert16bitMonoSamples (const short* samples,
+ bool _signed,
+ DWORD length,
+ speaker_freq freq,
+ wiimote_sample &out);
+
+ // state recording - records state snapshots to a 'state_history' supplied
+ // by the caller. states are timestamped and only added
+ // to the list when the specified state changes.
+ struct state_event {
+ DWORD time_ms; // system timestamp in milliseconds
+ wiimote_state state;
+ };
+ typedef list<state_event> state_history;
+ static const unsigned UNTIL_STOP = 0xffffffff;
+ // - pass in a 'state_history' list, and don't destroy/change it until
+ // recording is stopped. note the list will be cleared first.
+ // - you can request a specific duration (and use IsRecordingState() to detect
+ // the end), or UNTIL_STOP. StopRecording() can be called either way.
+ // - you can specify specific state changes that will trigger an insert
+ // into the history (others are ignored).
+ void RecordState (state_history &events_out,
+ unsigned max_time_ms = UNTIL_STOP,
+ state_change_flags change_trigger = CHANGED_ALL);
+ void StopRecording ();
+
+
+ private: // methods
+ // start reading asynchronously from the controller
+ bool BeginAsyncRead ();
+ // request status update (battery level, extension status etc)
+ void RequestStatusReport ();
+ // read address or register from Wiimote asynchronously (the result is
+ // parsed internally whenever it arrives)
+ bool ReadAddress (int address, short size);
+ // write a single BYTE to a wiimote address or register
+ inline void WriteData (int address, BYTE data) { WriteData(address, 1, &data); }
+ // write a BYTE array to a wiimote address or register
+ void WriteData (int address, BYTE size, const BYTE* buff);
+ // callback when data is ready to be processed
+ void OnReadData (DWORD bytes_read);
+ // parse individual reports by type
+ int ParseInput (BYTE* buff);
+ // initializes an extension when plugged in.
+ void InitializeExtension ();
+ // decrypts data sent from the extension
+ void DecryptBuffer (BYTE* buff, unsigned size);
+ // parses a status report
+ int ParseStatus (BYTE* buff);
+ // parses the buttons
+ int ParseButtons (BYTE* buff);
+ // parses accelerometer data
+ int ParseAccel (BYTE* buff);
+ bool EstimateOrientationFrom(wiimote_state::acceleration &accel);
+ void ApplyJoystickDeadZones (wiimote_state::joystick &joy);
+ // parses IR data from report
+ int ParseIR (BYTE* buff);
+ // parses data from an extension.
+ int ParseExtension (BYTE* buff, unsigned offset);
+ // parses data returned from a read report
+ int ParseReadAddress (BYTE* buff);
+ // reads calibration information stored on Wiimote
+ void ReadCalibration ();
+ // turns on the IR sensor (the mode must match the reporting mode caps)
+ void EnableIR (wiimote_state::ir::mode mode);
+ // disables the IR sensor
+ void DisableIR ();
+ // writes a report to the Wiimote (NULL = use 'WriteBuff')
+ bool WriteReport (BYTE* buff);
+ bool StartSampleThread ();
+ // returns the rumble BYTE that needs to be sent with reports.
+ inline BYTE GetRumbleBit () const { return Internal.bRumble? 0x01 : 0x00; }
+ // copy the accumulated parsed state into the public state
+ state_change_flags _RefreshState (bool for_callbacks);
+
+ // static thread funcs:
+ static unsigned __stdcall ReadParseThreadfunc (void* param);
+ static unsigned __stdcall AsyncRumbleThreadfunc (void* param);
+ static unsigned __stdcall SampleStreamThreadfunc(void* param);
+ static unsigned __stdcall HIDwriteThreadfunc (void* param);
+
+ private: // data
+ // wiimote output comands
+ enum output_report
+ {
+ OUT_NONE = 0x00,
+ OUT_LEDs = 0x11,
+ OUT_TYPE = 0x12,
+ OUT_IR = 0x13,
+ OUT_SPEAKER_ENABLE = 0x14,
+ OUT_STATUS = 0x15,
+ OUT_WRITEMEMORY = 0x16,
+ OUT_READMEMORY = 0x17,
+ OUT_SPEAKER_DATA = 0x18,
+ OUT_SPEAKER_MUTE = 0x19,
+ OUT_IR2 = 0x1a,
+ };
+ // input reports used only internally:
+ static const int IN_STATUS = 0x20;
+ static const int IN_READADDRESS = 0x21;
+ // wiimote device IDs:
+ static const int VID = 0x057e; // 'Nintendo'
+ static const int PID = 0x0306; // 'Wiimote'
+ // we could find this out the hard way using HID, but it's 22
+ static const int REPORT_LENGTH = 22;
+ // wiimote registers
+ static const int REGISTER_CALIBRATION = 0x0016;
+ static const int REGISTER_IR = 0x04b00030;
+ static const int REGISTER_IR_SENSITIVITY_1 = 0x04b00000;
+ static const int REGISTER_IR_SENSITIVITY_2 = 0x04b0001a;
+ static const int REGISTER_IR_MODE = 0x04b00033;
+ static const int REGISTER_EXTENSION_INIT = 0x04a40040;
+ static const int REGISTER_EXTENSION_TYPE = 0x04a400fe;
+ static const int REGISTER_EXTENSION_CALIBRATION = 0x04a40020;
+
+ HANDLE Handle; // read/write device handle
+ OVERLAPPED Overlapped; // for async Read/WriteFile() IO
+ HANDLE ReadParseThread; // waits for overlapped reads & parses result
+ EVENT DataRead; // signals overlapped read complete
+ bool bUseHIDwrite; // alternative write method (less efficient
+ // but required for some BT stacks (eg. MS')
+ // HidD_SetOutputReport is only supported from XP onwards, so detect &
+ // load it dynamically:
+ static HMODULE HidDLL;
+ static hidwrite_ptr _HidD_SetOutputReport;
+
+ volatile bool bStatusReceived; // for output method detection
+ volatile bool bConnectionLost; // auto-Disconnect()s if set
+ static unsigned _TotalCreated;
+ static unsigned _TotalConnected;
+ input_report ReportType; // type of data the wiimote delivers
+ // read buffer
+ BYTE ReadBuff [REPORT_LENGTH];
+ // for polling: state is updated on a thread internally, and made public
+ // via _RefreshState()
+ CRITICAL_SECTION StateLock;
+ wiimote_state Internal;
+ state_change_flags InternalChanged; // state changes since last RefreshState()
+ // periodic status report requests (for battery level and connection loss
+ // detection)
+ DWORD NextStatusTime;
+ // async Hidd_WriteReport() thread
+ HANDLE HIDwriteThread;
+ queue<BYTE*> HIDwriteQueue;
+ CRITICAL_SECTION HIDwriteQueueLock; // queue must be locked before being modified
+ // async rumble
+ HANDLE AsyncRumbleThread; // automatically disables rumble if requested
+ volatile DWORD AsyncRumbleTimeout;
+ // orientation estimation
+ unsigned WiimoteNearGUpdates;
+ unsigned NunchukNearGUpdates;
+ // audio
+ HANDLE SampleThread;
+ const wiimote_sample* volatile CurrentSample; // otherwise playing square wave
+ // state recording
+ struct recording
+ {
+ volatile bool bEnabled;
+ state_history *StateHistory;
+ volatile DWORD StartTimeMS;
+ volatile DWORD EndTimeMS; // can be UNTIL_STOP
+ unsigned TriggerFlags; // wiimote changes trigger a state event
+ unsigned ExtTriggerFlags;// extension changes "
+ } Recording;
+ };
+
+#endif // _WIIMOTE_H \ No newline at end of file
diff --git a/matchblox/include/wiimote_state.h b/matchblox/include/wiimote_state.h
new file mode 100644
index 0000000..e7add28
--- /dev/null
+++ b/matchblox/include/wiimote_state.h
@@ -0,0 +1,391 @@
+// _______________________________________________________________________________
+//
+// - WiiYourself! - native C++ Wiimote library v1.00
+// (c) gl.tter 2007-8 - http://gl.tter.org
+//
+// see License.txt for conditions of use. see History.txt for change log.
+// _______________________________________________________________________________
+//
+// wiimote_state.h (tab = 4 spaces)
+
+// the 'wiimote_state' struct contains all the Wiimote and Extension state data
+// (buttons etc) - the wiimote class inherits from this and the app can poll
+// the data there at any time.
+#ifdef _MSC_VER // VC
+# pragma once
+#endif
+
+#ifndef _WIIMOTE_STATE_H
+# define _WIIMOTE_STATE_H
+
+// speaker support:
+enum speaker_freq
+ {
+ // (keep in sync with FreqLookup in wiimote.cpp)
+ FREQ_NONE = 0,
+ // my PC can't keep up with these using bUseHIDwrite, so I haven't
+ // been able to tune them yet
+ FREQ_4200HZ = 1,
+ FREQ_3920HZ = 2,
+ FREQ_3640HZ = 3,
+ FREQ_3360HZ = 4,
+ // these were tuned until the square-wave was glitch-free on my remote -
+ // may not be exactly right
+ FREQ_3130HZ = 5, // +190
+ FREQ_2940HZ = 6, // +180
+ FREQ_2760HZ = 7, // +150
+ FREQ_2610HZ = 8, // +140
+ FREQ_2470HZ = 9,
+ };
+
+// wiimote_sample - holds the audio sample in the native wiimote format
+struct wiimote_sample
+ {
+ wiimote_sample() : samples(NULL), length(0), freq(FREQ_NONE) {}
+ BYTE* samples;
+ DWORD length;
+ speaker_freq freq;
+ };
+
+// flags & masks that indicate which part(s) of the wiimote state have changed
+enum state_change_flags
+ {
+ // state didn't change at all
+ NO_CHANGE = 0,
+
+ // Wiimote specific
+ CONNECTION_LOST = 1<<0,
+ BATTERY_CHANGED = 1<<1,
+ LEDS_CHANGED = 1<<2, // (probably redudant as wiimmote never
+ BUTTONS_CHANGED = 1<<3, // changes them unless requested)
+ ACCEL_CHANGED = 1<<4,
+ ORIENTATION_CHANGED = 1<<5,
+ IR_CHANGED = 1<<6,
+ // all wiimote flags
+ WIIMOTE_CHANGED = CONNECTION_LOST|BATTERY_CHANGED|LEDS_CHANGED|
+ BUTTONS_CHANGED|ACCEL_CHANGED|ORIENTATION_CHANGED|
+ IR_CHANGED,
+ // Extensions - general
+ EXTENSION_DISCONNECTED = 1<<7,
+ EXTENSION_PARTIALLY_INSERTED = 1<<8,
+
+ // Nunchuk specific
+ NUNCHUK_CONNECTED = 1<<9,
+ NUNCHUK_BUTTONS_CHANGED = 1<<10,
+ NUNCHUK_ACCEL_CHANGED = 1<<11,
+ NUNCHUK_ORIENTATION_CHANGED = 1<<12,
+ NUNCHUK_JOYSTICK_CHANGED = 1<<13,
+ // all flags
+ NUNCHUK_CHANGED = NUNCHUK_CONNECTED|NUNCHUK_BUTTONS_CHANGED|
+ NUNCHUK_ACCEL_CHANGED|NUNCHUK_ORIENTATION_CHANGED|
+ NUNCHUK_JOYSTICK_CHANGED,
+ // Classic Controller
+ CLASSIC_CONNECTED = 1<<14,
+ CLASSIC_BUTTONS_CHANGED = 1<<15,
+ CLASSIC_JOYSTICK_L_CHANGED = 1<<16,
+ CLASSIC_JOYSTICK_R_CHANGED = 1<<17,
+ CLASSIC_TRIGGERS_CHANGED = 1<<18,
+ // all flags
+ CLASSIC_CHANGED = CLASSIC_CONNECTED|CLASSIC_BUTTONS_CHANGED|
+ CLASSIC_JOYSTICK_L_CHANGED|
+ CLASSIC_JOYSTICK_R_CHANGED|CLASSIC_TRIGGERS_CHANGED,
+ // ALL extension-related flags
+ EXTENSION_CHANGED = EXTENSION_DISCONNECTED|
+ NUNCHUK_CHANGED|CLASSIC_CHANGED,
+ // ALL flags
+ CHANGED_ALL = WIIMOTE_CHANGED|EXTENSION_CHANGED,
+ };
+
+// wiimote_state (contains the Wiimote and Extension data and settings)
+struct wiimote_state
+ {
+ friend class wiimote; // for Clear()
+
+ // calibration information (stored on the Wiimote)
+ struct calibration_info
+ {
+ BYTE X0, Y0, Z0;
+ BYTE XG, YG, ZG;
+ } CalibrationInfo;
+
+ // button state:
+ struct buttons
+ {
+ // convenience accessors
+ inline bool A () const { return (Bits & _A) != 0; }
+ inline bool B () const { return (Bits & _B) != 0; }
+ inline bool Plus () const { return (Bits & PLUS) != 0; }
+ inline bool Home () const { return (Bits & HOME) != 0; }
+ inline bool Minus () const { return (Bits & MINUS) != 0; }
+ inline bool One () const { return (Bits & ONE) != 0; }
+ inline bool Two () const { return (Bits & TWO) != 0; }
+ inline bool Up () const { return (Bits & UP) != 0; }
+ inline bool Down () const { return (Bits & DOWN) != 0; }
+ inline bool Left () const { return (Bits & LEFT) != 0; }
+ inline bool Right () const { return (Bits & RIGHT) != 0; }
+
+ // all 11 buttons stored as bits (set = pressed)
+ WORD Bits;
+
+ // button bit masks (little-endian order)
+ enum mask
+ {
+ LEFT = 0x0001,
+ RIGHT = 0x0002,
+ DOWN = 0x0004,
+ UP = 0x0008,
+ PLUS = 0x0010,
+ TWO = 0x0100,
+ ONE = 0x0200,
+ _B = 0x0400, // ie. trigger
+ _A = 0x0800,
+ MINUS = 0x1000,
+ HOME = 0x8000,
+ //
+ ALL = LEFT|RIGHT|DOWN|UP|PLUS|TWO|ONE|_A|_B|MINUS|HOME,
+ };
+ } Button;
+
+ // accelerometers state:
+ struct acceleration
+ {
+ BYTE RawX, RawY, RawZ;
+ float X, Y, Z;
+
+ // note: experimental! the orientation values can only be safely estimated
+ // if the controller isn't accelerating (otherwise there is no
+ // simple way to seperate orientation from acceleration - except
+ // perhaps using the IR reference and/or some clever assumptions).
+ // so for now the code only updates orientation if the controller
+ // appear to be stationary (by checking if the acceleration vector
+ // length is near 1G for several updates in a row).
+ // also note that there is no way to detect Yaw from the accelerometer
+ // alone when it's pointing at the screen (and I'm not curently
+ // processing IR):
+ struct orientation
+ {
+ float X, Y, Z;
+ unsigned UpdateAge; // how many acceleration updates ago the last
+ // orientation estimate was made (if this
+ // value is high, the values are out-of-date
+ // and probably shouldn't be used).
+ // Euler angle support (useful for some things).
+ // * note that decomposing to Euler angles is complex, not always reliable,
+ // and also depends on your assumptions about the order each component
+ // is applied in. you may need to handle this yourself for more
+ // complex scenarios *
+ float Pitch; // in degrees (-180 - +180)
+ float Roll; // "
+ // float Yaw;
+ } Orientation;
+ } Acceleration;
+
+ // IR camera state:
+ struct ir
+ {
+ // in theory the IR imager is 1024x768 and so should report raw coords
+ // 0-1023 x 0-767. in practice I have never seen them exceed the values
+ // below, so I'm using them instead to give the full 0-1 float range
+ // (it's possible that the edge pixels are used for processing, or masked
+ // out due to being unreliable)
+ static const unsigned MAX_RAW_X = 1016;
+ static const unsigned MAX_RAW_Y = 760;
+
+ // data mode reported by the IR sensor
+ enum mode
+ {
+ OFF = 0x00,
+ BASIC = 0x01, // 10 bytes
+ EXTENDED = 0x03, // 12 bytes
+ FULL = 0x05, // 16 bytes * 2 (format unknown)
+ };
+ mode Mode;
+
+ struct dot
+ {
+ bool bFound; // wiimote can see it
+ unsigned RawX;
+ unsigned RawY;
+ float X; // 0-1 (left-right)
+ float Y; // " (top -bottom)
+ int Size; // (not available in BASIC mode)
+ } Dot[4];
+ } IR;
+
+ struct leds
+ {
+ // all LEDs stored in bits 0-3 (1 = lit)
+ BYTE Bits;
+
+ // convenience accessors:
+ inline bool Lit (unsigned index)
+ { _ASSERT(index < 4);
+ return (index >= 4)? false : ((Bits & (1<<index)) != 0); }
+ } LED;
+
+ BYTE BatteryRaw; // 0 - ~200 (it seems 200 *may* be the maximum charge)
+ BYTE BatteryPercent; // (using the above assumption, where 200 raw = 100%)
+ bool bRumble;
+ bool bExtension; // an extension (eg. Nunchuk) is connected.
+
+ // speaker state:
+ struct speaker
+ {
+ bool bEnabled;
+ bool bMuted;
+ speaker_freq Freq;
+ BYTE Volume;
+ } Speaker;
+
+ // the extension plugged into the Wiimote (if any)
+ enum extension_type
+ {
+ NONE = 0x0000,
+ NUNCHUK = 0xfefe,
+ CLASSIC = 0xfdfd,
+ CLASSIC_GUITAR = 0xfbfd, // Guitar Hero controller (treated as Classic)
+ PARTIALLY_INSERTED = 0xffff,
+ };
+ extension_type ExtensionType;
+
+ // joystick struct (shared between Nunchuk & Classic Controller)
+ struct joystick
+ {
+ friend class wiimote;
+
+ // raw unprocessed coordinates:
+ float RawX, RawY;
+
+ // processed coordinates in approximately -1 - +1 range (includes calibration
+ // data and deadzones) - note that due to calibration inaccuracies, the
+ // extremes may be slightly over/under (+-)1.0.
+ float X, Y;
+
+ // a 'deadzone' is a user-defined range near the joystick center which
+ // is treated as zero (joysticks often drift a little even at the center
+ // position). you can set a deadzone for each axis at any time, range is
+ // 0.0 (off) to 1.0 (entire range - not useful :). try 0.03.
+ struct deadzone
+ {
+ float X, Y;
+ } DeadZone;
+ };
+
+ // Nunchuk state (if connected)
+ struct nunchuk
+ {
+ struct calibration_info
+ {
+ BYTE X0, Y0, Z0;
+ BYTE XG, YG, ZG;
+ BYTE MinX, MidX, MaxX;
+ BYTE MinY, MidY, MaxY;
+ } CalibrationInfo;
+
+ acceleration Acceleration;
+ joystick Joystick;
+ bool C;
+ bool Z;
+ } Nunchuk;
+
+ // Classic Controller state (if connected)
+ struct classic_controller
+ {
+ // calibration information (stored on the controller)
+ struct calibration_info
+ {
+ BYTE MinXL, MidXL, MaxXL;
+ BYTE MinYL, MidYL, MaxYL;
+ BYTE MinXR, MidXR, MaxXR;
+ BYTE MinYR, MidYR, MaxYR;
+ BYTE MinTriggerL, MaxTriggerL;
+ BYTE MinTriggerR, MaxTriggerR;
+ } CalibrationInfo;
+
+ // button state
+ struct buttons
+ {
+ // convenience accessors
+ inline bool A () const { return (Bits & _A) != 0; }
+ inline bool B () const { return (Bits & _B) != 0; }
+ inline bool Plus () const { return (Bits & PLUS) != 0; }
+ inline bool Minus () const { return (Bits & MINUS) != 0; }
+ inline bool Home () const { return (Bits & HOME) != 0; }
+ inline bool Up () const { return (Bits & UP) != 0; }
+ inline bool Down () const { return (Bits & DOWN) != 0; }
+ inline bool Left () const { return (Bits & LEFT) != 0; }
+ inline bool Right () const { return (Bits & RIGHT) != 0; }
+ inline bool X () const { return (Bits & _X) != 0; }
+ inline bool Y () const { return (Bits & _Y) != 0; }
+ inline bool ZL () const { return (Bits & _ZL) != 0; }
+ inline bool ZR () const { return (Bits & _ZR) != 0; }
+ inline bool TriggerL () const { return (Bits & TRIG_L) != 0; }
+ inline bool TriggerR () const { return (Bits & TRIG_R) != 0; }
+
+ // all 15 buttons stored as bits (set = pressed)
+ WORD Bits;
+
+ // button bitmasks (little-endian order)
+ enum mask
+ {
+ TRIG_R = 0x0002,
+ PLUS = 0x0004,
+ HOME = 0x0008,
+ MINUS = 0x0010,
+ TRIG_L = 0x0020,
+ DOWN = 0x0040,
+ RIGHT = 0x0080,
+ UP = 0x0100,
+ LEFT = 0x0200,
+ _ZR = 0x0400,
+ _X = 0x0800,
+ _A = 0x1000,
+ _Y = 0x2000,
+ _B = 0x4000,
+ _ZL = 0x8000,
+ //
+ ALL = TRIG_R|PLUS|HOME|MINUS|TRIG_L|DOWN|RIGHT|UP|LEFT|
+ _ZR|_X|_A|_Y|_B|_ZL,
+ };
+ } Button;
+
+ // joysticks
+ joystick JoystickL;
+ joystick JoystickR;
+
+ // triggers
+ BYTE RawTriggerL, RawTriggerR;
+ float TriggerL, TriggerR;
+ } ClassicController;
+
+
+ // ---- internal use only ----
+ protected:
+ unsigned WiimoteNearGUpdates;
+ unsigned NunchukNearGUpdates;
+
+ void Clear (bool including_deadzones)
+ {
+ joystick::deadzone nunchuk_deadzone = {0};
+ joystick::deadzone classic_joyl_deadzone = {0};
+ joystick::deadzone classic_joyr_deadzone = {0};
+
+ // preserve the deadzone settings?
+ if(!including_deadzones) {
+ nunchuk_deadzone = Nunchuk.Joystick.DeadZone;
+ classic_joyl_deadzone = ClassicController.JoystickL.DeadZone;
+ classic_joyr_deadzone = ClassicController.JoystickR.DeadZone;
+ }
+
+ memset(this, 0, sizeof(wiimote_state));
+
+ // restore the deadzones?
+ if(!including_deadzones) {
+ Nunchuk.Joystick.DeadZone = nunchuk_deadzone;
+ ClassicController.JoystickL.DeadZone = classic_joyl_deadzone;
+ ClassicController.JoystickR.DeadZone = classic_joyr_deadzone;
+ }
+ }
+ };
+
+#endif // _WIIMOTE_STATE_H \ No newline at end of file