mirror of
https://github.com/XProger/OpenLara.git
synced 2025-02-24 07:22:58 +01:00
#15 add osx gamepad suppport (xbox 360 mapping)
This commit is contained in:
parent
2aa1e131c3
commit
93ce97e183
@ -128,7 +128,7 @@ namespace Input {
|
||||
case jkRT : joy[index].RT = pos.x; break;
|
||||
default : return;
|
||||
}
|
||||
setJoyDown(index, key, pos.x > 0.0f); // gamepad LT, RT auto-down state
|
||||
setJoyDown(index, key, pos.x > EPS); // gamepad LT, RT auto-down state
|
||||
}
|
||||
|
||||
void setJoyVibration(int playerIndex, float L, float R) {
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
523F97E41DDF7AA5006FE2FC /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 523F97E31DDF7AA5006FE2FC /* Cocoa.framework */; };
|
||||
523F97E61DDF926E006FE2FC /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 523F97E51DDF926E006FE2FC /* QuartzCore.framework */; };
|
||||
9938F1A421E830250056E172 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9938F1A021E81EFE0056E172 /* IOKit.framework */; };
|
||||
99713CC9204CAD9900006FAC /* tinflate.c in Sources */ = {isa = PBXBuildFile; fileRef = 99713CC8204CAD9900006FAC /* tinflate.c */; };
|
||||
99BF38CD21E7176900D90A38 /* main.mm in Sources */ = {isa = PBXBuildFile; fileRef = 99BF38CC21E7176900D90A38 /* main.mm */; };
|
||||
99BF38D221E7202500D90A38 /* audio in Resources */ = {isa = PBXBuildFile; fileRef = 99BF38CE21E7202500D90A38 /* audio */; };
|
||||
@ -23,7 +23,7 @@
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
523F97E31DDF7AA5006FE2FC /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
|
||||
523F97E51DDF926E006FE2FC /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; };
|
||||
9938F1A021E81EFE0056E172 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = System/Library/Frameworks/IOKit.framework; sourceTree = SDKROOT; };
|
||||
995C97EF1E91A857003825B2 /* shaders */ = {isa = PBXFileReference; lastKnownFileType = folder; name = shaders; path = ../../shaders; sourceTree = "<group>"; };
|
||||
99713CAE204CA3DA00006FAC /* animation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = animation.h; path = ../../animation.h; sourceTree = "<group>"; };
|
||||
99713CAF204CA3DA00006FAC /* cache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = cache.h; path = ../../cache.h; sourceTree = "<group>"; };
|
||||
@ -60,12 +60,8 @@
|
||||
99BFB6A81DCA87BF00E2E997 /* stb_vorbis.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = stb_vorbis.c; path = ../../libs/stb_vorbis/stb_vorbis.c; sourceTree = "<group>"; };
|
||||
99BFB6AA1DCA87C500E2E997 /* minimp3.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = minimp3.cpp; path = ../../libs/minimp3/minimp3.cpp; sourceTree = "<group>"; };
|
||||
99C4C0931796A96F0032DE85 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; };
|
||||
99C4C0951796A9730032DE85 /* AGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AGL.framework; path = System/Library/Frameworks/AGL.framework; sourceTree = SDKROOT; };
|
||||
99C4C09B1796AACF0032DE85 /* OpenLara.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = OpenLara.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
99C4C0A41796AACF0032DE85 /* OpenLara-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = "OpenLara-Info.plist"; sourceTree = "<group>"; };
|
||||
99C4C0B81796AB7B0032DE85 /* Carbon.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Carbon.framework; path = System/Library/Frameworks/Carbon.framework; sourceTree = SDKROOT; };
|
||||
99DF7BBF1DCBA2BF00C40D0A /* CoreAudio.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreAudio.framework; path = System/Library/Frameworks/CoreAudio.framework; sourceTree = SDKROOT; };
|
||||
99DF7BC11DCBA2D100C40D0A /* CoreAudioKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreAudioKit.framework; path = System/Library/Frameworks/CoreAudioKit.framework; sourceTree = SDKROOT; };
|
||||
99DF7BC31DCBA30B00C40D0A /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
@ -74,7 +70,7 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
523F97E61DDF926E006FE2FC /* QuartzCore.framework in Frameworks */,
|
||||
9938F1A421E830250056E172 /* IOKit.framework in Frameworks */,
|
||||
523F97E41DDF7AA5006FE2FC /* Cocoa.framework in Frameworks */,
|
||||
99DF7BC41DCBA30B00C40D0A /* AudioToolbox.framework in Frameworks */,
|
||||
99C4C0BA1796AB810032DE85 /* OpenGL.framework in Frameworks */,
|
||||
@ -139,14 +135,10 @@
|
||||
99C4C0821796A8230032DE85 /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
523F97E51DDF926E006FE2FC /* QuartzCore.framework */,
|
||||
9938F1A021E81EFE0056E172 /* IOKit.framework */,
|
||||
523F97E31DDF7AA5006FE2FC /* Cocoa.framework */,
|
||||
99DF7BC31DCBA30B00C40D0A /* AudioToolbox.framework */,
|
||||
99DF7BC11DCBA2D100C40D0A /* CoreAudioKit.framework */,
|
||||
99DF7BBF1DCBA2BF00C40D0A /* CoreAudio.framework */,
|
||||
99C4C0B81796AB7B0032DE85 /* Carbon.framework */,
|
||||
99C4C0931796A96F0032DE85 /* OpenGL.framework */,
|
||||
99C4C0951796A9730032DE85 /* AGL.framework */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
|
@ -1,15 +1,28 @@
|
||||
#include <Cocoa/Cocoa.h>
|
||||
#include <mach/mach.h>
|
||||
#include <mach/mach_time.h>
|
||||
#include <IOKit/hid/IOHidLib.h>
|
||||
|
||||
#include "game.h"
|
||||
|
||||
// timing
|
||||
int osGetTime() {
|
||||
static mach_timebase_info_data_t timebaseInfo;
|
||||
if (timebaseInfo.denom == 0) {
|
||||
mach_timebase_info(&timebaseInfo);
|
||||
}
|
||||
|
||||
uint64_t absolute = mach_absolute_time();
|
||||
uint64_t milliseconds = absolute * timebaseInfo.numer / (timebaseInfo.denom * 1000000ULL);
|
||||
return int(milliseconds);
|
||||
}
|
||||
|
||||
// sound
|
||||
#define SND_SIZE 2352
|
||||
|
||||
static AudioQueueRef audioQueue;
|
||||
|
||||
void soundFill(void* inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer) {
|
||||
void sndFill(void* inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer) {
|
||||
void* frames = inBuffer->mAudioData;
|
||||
UInt32 count = inBuffer->mAudioDataBytesCapacity / 4;
|
||||
Sound::fill((Sound::Frame*)frames, count);
|
||||
@ -17,7 +30,7 @@ void soundFill(void* inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffe
|
||||
AudioQueueEnqueueBuffer(audioQueue, inBuffer, 0, NULL);
|
||||
}
|
||||
|
||||
void soundInit() {
|
||||
void sndInit() {
|
||||
AudioStreamBasicDescription deviceFormat;
|
||||
deviceFormat.mSampleRate = 44100;
|
||||
deviceFormat.mFormatID = kAudioFormatLinearPCM;
|
||||
@ -29,12 +42,12 @@ void soundInit() {
|
||||
deviceFormat.mBitsPerChannel = 16;
|
||||
deviceFormat.mReserved = 0;
|
||||
|
||||
AudioQueueNewOutput(&deviceFormat, soundFill, NULL, NULL, NULL, 0, &audioQueue);
|
||||
AudioQueueNewOutput(&deviceFormat, sndFill, NULL, NULL, NULL, 0, &audioQueue);
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
AudioQueueBufferRef mBuffer;
|
||||
AudioQueueAllocateBuffer(audioQueue, SND_SIZE, &mBuffer);
|
||||
soundFill(NULL, audioQueue, mBuffer);
|
||||
sndFill(NULL, audioQueue, mBuffer);
|
||||
}
|
||||
AudioQueueStart(audioQueue, NULL);
|
||||
}
|
||||
@ -51,7 +64,6 @@ InputKey keyToInputKey(int code) {
|
||||
for (int i = 0; i < sizeof(codes) / sizeof(codes[0]); i++)
|
||||
if (codes[i] == code) {
|
||||
return (InputKey)(ikLeft + i);
|
||||
LOG("%d\n", code);
|
||||
}
|
||||
return ikNone;
|
||||
}
|
||||
@ -65,24 +77,133 @@ InputKey mouseToInputKey(int btn) {
|
||||
return ikNone;
|
||||
}
|
||||
|
||||
IOHIDDeviceRef joyDevices[4] = { 0 };
|
||||
IOHIDManagerRef hidManager;
|
||||
|
||||
JoyKey joyButtonToKey(uint32_t button) {
|
||||
static const JoyKey keys[] = { jkA, jkB, jkX, jkY, jkLB, jkRB, jkLT, jkRT, jkStart, jkSelect, jkNone, jkUp, jkDown, jkLeft, jkRight };
|
||||
|
||||
if (button >= 0 || button < COUNT(keys))
|
||||
return keys[button];
|
||||
return jkNone;
|
||||
}
|
||||
|
||||
bool osJoyReady(int index) {
|
||||
return false;
|
||||
if (index < 0 || index >= COUNT(joyDevices))
|
||||
return false;
|
||||
return joyDevices[index] != NULL;
|
||||
}
|
||||
|
||||
void osJoyVibrate(int index, float L, float R) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
// timing
|
||||
int osGetTime() {
|
||||
static mach_timebase_info_data_t timebaseInfo;
|
||||
if (timebaseInfo.denom == 0) {
|
||||
mach_timebase_info(&timebaseInfo);
|
||||
float joyAxisValue(IOHIDValueRef value) {
|
||||
IOHIDElementRef element = IOHIDValueGetElement(value);
|
||||
CFIndex val = IOHIDValueGetIntegerValue(value);
|
||||
CFIndex min = IOHIDElementGetLogicalMin(element);
|
||||
CFIndex max = IOHIDElementGetLogicalMax(element);
|
||||
|
||||
float v = float(val - min) / float(max - min);
|
||||
if (v < 0.2f) v = 0.0f; // check for deadzone
|
||||
return v * 2.0f - 1.0f;
|
||||
}
|
||||
|
||||
void hidValueCallback(void *context, IOReturn result, void *sender, IOHIDValueRef value) {
|
||||
if (result != kIOReturnSuccess)
|
||||
return;
|
||||
|
||||
IOHIDElementRef element = IOHIDValueGetElement(value);
|
||||
IOHIDDeviceRef device = IOHIDElementGetDevice(element);
|
||||
|
||||
int joyIndex = -1;
|
||||
for (int i = 0; i < COUNT(joyDevices); i++) {
|
||||
if (joyDevices[i] == device) {
|
||||
joyIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t absolute = mach_absolute_time();
|
||||
uint64_t milliseconds = absolute * timebaseInfo.numer / (timebaseInfo.denom * 1000000ULL);
|
||||
return int(milliseconds);
|
||||
if (joyIndex == -1) return;
|
||||
|
||||
// TODO: add mapping for most popular gamepads by kIOHIDVendorIDKey / kIOHIDProductIDKey
|
||||
switch (IOHIDElementGetUsagePage(element)) {
|
||||
case kHIDPage_GenericDesktop : {
|
||||
switch (IOHIDElementGetUsage(IOHIDValueGetElement(value))) {
|
||||
case kHIDUsage_GD_X :
|
||||
Input::setJoyPos(joyIndex, jkL, vec2(joyAxisValue(value), Input::joy[joyIndex].L.y));
|
||||
break;
|
||||
case kHIDUsage_GD_Y :
|
||||
Input::setJoyPos(joyIndex, jkL, vec2(Input::joy[joyIndex].L.x, joyAxisValue(value)));
|
||||
break;
|
||||
case kHIDUsage_GD_Rx :
|
||||
Input::setJoyPos(joyIndex, jkR, vec2(joyAxisValue(value), Input::joy[joyIndex].R.y));
|
||||
break;
|
||||
case kHIDUsage_GD_Ry :
|
||||
Input::setJoyPos(joyIndex, jkR, vec2(Input::joy[joyIndex].R.x, joyAxisValue(value)));
|
||||
break;
|
||||
case kHIDUsage_GD_Z :
|
||||
Input::setJoyPos(joyIndex, jkLT, vec2(joyAxisValue(value) * 0.5f + 0.5f, 0.0f));
|
||||
break;
|
||||
case kHIDUsage_GD_Rz :
|
||||
Input::setJoyPos(joyIndex, jkRT, vec2(joyAxisValue(value) * 0.5f + 0.5f, 0.0f));
|
||||
break;
|
||||
default : LOG("! joy: unknown joy 0x%x (%d)\n", IOHIDElementGetUsage(IOHIDValueGetElement(value)), (int)IOHIDValueGetIntegerValue(value));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kHIDPage_Button : {
|
||||
uint32_t button = IOHIDElementGetUsage(IOHIDValueGetElement(value)) - kHIDUsage_Button_1;
|
||||
bool down = IOHIDValueGetIntegerValue(value) != 0;
|
||||
JoyKey key = joyButtonToKey(button);
|
||||
Input::setJoyDown(joyIndex, key, down);
|
||||
if (key == jkNone) LOG("! joy: unknown button %d\n", button);
|
||||
break;
|
||||
}
|
||||
default : ;
|
||||
}
|
||||
}
|
||||
|
||||
void joyAdd(void* context, IOReturn, void*, IOHIDDeviceRef device) {
|
||||
for (int i = 0; i < COUNT(joyDevices); i++) {
|
||||
if (joyDevices[i] == NULL) {
|
||||
joyDevices[i] = device;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void joyRemove(void* context, IOReturn, void*, IOHIDDeviceRef device) {
|
||||
for (int i = 0; i < COUNT(joyDevices); i++) {
|
||||
if (joyDevices[i] == device) {
|
||||
joyDevices[i] = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void joyInit() {
|
||||
hidManager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDManagerOptionNone);
|
||||
|
||||
NSDictionary *matchingGamepad = @{
|
||||
@(kIOHIDDeviceUsagePageKey): @(kHIDPage_GenericDesktop),
|
||||
@(kIOHIDDeviceUsageKey): @(kHIDUsage_GD_GamePad)
|
||||
};
|
||||
NSArray *matchDicts = @[ matchingGamepad ];
|
||||
|
||||
IOHIDManagerSetDeviceMatchingMultiple(hidManager, (__bridge CFArrayRef) matchDicts);
|
||||
IOHIDManagerRegisterDeviceMatchingCallback(hidManager, joyAdd, NULL);
|
||||
IOHIDManagerRegisterDeviceRemovalCallback(hidManager, joyRemove, NULL);
|
||||
IOHIDManagerScheduleWithRunLoop(hidManager, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
|
||||
IOHIDManagerOpen(hidManager, kIOHIDOptionsTypeNone);
|
||||
IOHIDManagerRegisterInputValueCallback(hidManager, hidValueCallback, NULL);
|
||||
}
|
||||
|
||||
void joyFree() {
|
||||
IOHIDManagerUnscheduleFromRunLoop(hidManager, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
|
||||
IOHIDManagerRegisterDeviceMatchingCallback(hidManager, NULL, 0);
|
||||
IOHIDManagerRegisterDeviceRemovalCallback(hidManager, NULL, 0);
|
||||
IOHIDManagerClose(hidManager, kIOHIDOptionsTypeNone);
|
||||
}
|
||||
|
||||
@interface OpenLaraGLView : NSOpenGLView
|
||||
@ -216,10 +337,10 @@ int main() {
|
||||
|
||||
// init window
|
||||
NSRect rect = NSMakeRect(0, 0, 1280, 720);
|
||||
NSWindow *mainWindow = [[NSWindow alloc] initWithContentRect:rect styleMask:NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask backing:NSBackingStoreBuffered defer:YES];
|
||||
mainWindow.title = @"OpenLara";
|
||||
mainWindow.acceptsMouseMovedEvents = YES;
|
||||
mainWindow.delegate = [[OpenLaraWindowDelegate alloc] init];
|
||||
NSWindow *window = [[NSWindow alloc] initWithContentRect:rect styleMask:NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask backing:NSBackingStoreBuffered defer:YES];
|
||||
window.title = @"OpenLara";
|
||||
window.acceptsMouseMovedEvents = YES;
|
||||
window.delegate = [[OpenLaraWindowDelegate alloc] init];
|
||||
|
||||
// init OpenGL context
|
||||
NSOpenGLPixelFormatAttribute attribs[] = {
|
||||
@ -232,9 +353,9 @@ int main() {
|
||||
};
|
||||
NSOpenGLPixelFormat *format = [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs];
|
||||
|
||||
OpenLaraGLView *view = [[OpenLaraGLView alloc] initWithFrame:mainWindow.contentLayoutRect pixelFormat:format];
|
||||
OpenLaraGLView *view = [[OpenLaraGLView alloc] initWithFrame:window.contentLayoutRect pixelFormat:format];
|
||||
view.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
|
||||
mainWindow.contentView = view;
|
||||
window.contentView = view;
|
||||
[view.openGLContext makeCurrentContext];
|
||||
|
||||
// get path to game content
|
||||
@ -244,10 +365,11 @@ int main() {
|
||||
strcat(contentDir, "/");
|
||||
|
||||
// show window
|
||||
[mainWindow center];
|
||||
[mainWindow makeKeyAndOrderFront:nil];
|
||||
[window center];
|
||||
[window makeKeyAndOrderFront:nil];
|
||||
|
||||
soundInit();
|
||||
joyInit();
|
||||
sndInit();
|
||||
Game::init();
|
||||
|
||||
if (!Core::isQuit) {
|
||||
@ -255,6 +377,7 @@ int main() {
|
||||
}
|
||||
|
||||
Game::deinit();
|
||||
joyFree();
|
||||
// TODO: sndFree
|
||||
|
||||
return 0;
|
||||
|
Loading…
x
Reference in New Issue
Block a user