Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ The following demo apps have Xcode projects under their `OSX/` folder:
|-----|--------------|-------|-------|
| **RTBareBones** | `RTBareBones/OSX/RTBareBones.xcodeproj` | Dummy (no audio) | Simplest starting point |
| **RTSimpleApp** | `RTSimpleApp/OSX/RTSimpleApp.xcodeproj` | SDL2_mixer | Basic app with SDL audio |
| **RTLooneyLadders** | `RTLooneyLadders/OSX/RTLooneyLadders.xcodeproj` | SDL2_mixer | Full game with gamepad support (game controllers not yet working on Mac) |
| **RTLooneyLadders** | `RTLooneyLadders/OSX/RTLooneyLadders.xcodeproj` | SDL2_mixer | Full game with gamepad support |

All projects target **macOS 11.0+** and build as **universal binaries** (arm64 + x86_64).

Expand Down
16 changes: 16 additions & 0 deletions RTLooneyLadders/OSX/RTLooneyLadders.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,9 @@ AA000004000000000000AA01 /* AudioManagerSDL.cpp in Sources */ = {isa = PBXBuildF
GPLL0000000000000000000003 /* GamepadSDL2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = GPLL0000000000000000000013 /* GamepadSDL2.cpp */; };
GPLL0000000000000000000004 /* GamepadProvider.cpp in Sources */ = {isa = PBXBuildFile; fileRef = GPLL0000000000000000000014 /* GamepadProvider.cpp */; };
GPLL0000000000000000000005 /* Gamepad.cpp in Sources */ = {isa = PBXBuildFile; fileRef = GPLL0000000000000000000015 /* Gamepad.cpp */; };
GPLL0000000000000000000006 /* GamepadProviderGCController.mm in Sources */ = {isa = PBXBuildFile; fileRef = GPLL0000000000000000000016 /* GamepadProviderGCController.mm */; };
GPLL0000000000000000000007 /* GamepadGCController.mm in Sources */ = {isa = PBXBuildFile; fileRef = GPLL0000000000000000000017 /* GamepadGCController.mm */; };
GPLL0000000000000000000008 /* GameController.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = GPLL0000000000000000000018 /* GameController.framework */; };
/* SDL2 embed build files */
SDLLL00000000000000000001 /* SDL2.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = SDLLL00000000000000000011 /* SDL2.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
SDLLL00000000000000000002 /* SDL2_mixer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = SDLLL00000000000000000012 /* SDL2_mixer.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
Expand Down Expand Up @@ -473,6 +476,11 @@ AA000003000000000000AA02 /* AudioManagerSDL.h */ = {isa = PBXFileReference; file
GPLL0000000000000000000024 /* GamepadProvider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GamepadProvider.h; path = ../../shared/Gamepad/GamepadProvider.h; sourceTree = SOURCE_ROOT; };
GPLL0000000000000000000015 /* Gamepad.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Gamepad.cpp; path = ../../shared/Gamepad/Gamepad.cpp; sourceTree = SOURCE_ROOT; };
GPLL0000000000000000000025 /* Gamepad.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Gamepad.h; path = ../../shared/Gamepad/Gamepad.h; sourceTree = SOURCE_ROOT; };
GPLL0000000000000000000016 /* GamepadProviderGCController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = GamepadProviderGCController.mm; path = ../../shared/Gamepad/GamepadProviderGCController.mm; sourceTree = SOURCE_ROOT; };
GPLL0000000000000000000026 /* GamepadProviderGCController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GamepadProviderGCController.h; path = ../../shared/Gamepad/GamepadProviderGCController.h; sourceTree = SOURCE_ROOT; };
GPLL0000000000000000000017 /* GamepadGCController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = GamepadGCController.mm; path = ../../shared/Gamepad/GamepadGCController.mm; sourceTree = SOURCE_ROOT; };
GPLL0000000000000000000027 /* GamepadGCController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GamepadGCController.h; path = ../../shared/Gamepad/GamepadGCController.h; sourceTree = SOURCE_ROOT; };
GPLL0000000000000000000018 /* GameController.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GameController.framework; path = System/Library/Frameworks/GameController.framework; sourceTree = SDKROOT; };
/* SDL2 framework references */
SDLLL00000000000000000011 /* SDL2.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SDL2.framework; path = "$(HOME)/Library/Frameworks/SDL2.framework"; sourceTree = "<absolute>"; };
SDLLL00000000000000000012 /* SDL2_mixer.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SDL2_mixer.framework; path = "$(HOME)/Library/Frameworks/SDL2_mixer.framework"; sourceTree = "<absolute>"; };
Expand Down Expand Up @@ -521,6 +529,7 @@ AA000003000000000000AA02 /* AudioManagerSDL.h */ = {isa = PBXFileReference; file
8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */,
AFD4D88A113C504F00C2DE76 /* OpenGL.framework in Frameworks */,
AF9DBBC6113C611C00D05754 /* QuartzCore.framework in Frameworks */,
GPLL0000000000000000000008 /* GameController.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -558,6 +567,7 @@ AA000003000000000000AA02 /* AudioManagerSDL.h */ = {isa = PBXFileReference; file
1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */,
AFD4D889113C504F00C2DE76 /* OpenGL.framework */,
AF9DBBC5113C611C00D05754 /* QuartzCore.framework */,
GPLL0000000000000000000018 /* GameController.framework */,
);
name = "Linked Frameworks";
sourceTree = "<group>";
Expand Down Expand Up @@ -715,6 +725,10 @@ AA000003000000000000AA02 /* AudioManagerSDL.h */ = {isa = PBXFileReference; file
GPLL0000000000000000000022 /* GamepadProviderSDL2.h */,
GPLL0000000000000000000013 /* GamepadSDL2.cpp */,
GPLL0000000000000000000023 /* GamepadSDL2.h */,
GPLL0000000000000000000016 /* GamepadProviderGCController.mm */,
GPLL0000000000000000000026 /* GamepadProviderGCController.h */,
GPLL0000000000000000000017 /* GamepadGCController.mm */,
GPLL0000000000000000000027 /* GamepadGCController.h */,
);
name = Gamepad;
sourceTree = "<group>";
Expand Down Expand Up @@ -1266,6 +1280,8 @@ AA000003000000000000AA02 /* AudioManagerSDL.h */ = {isa = PBXFileReference; file
GPLL0000000000000000000001 /* GamepadManager.cpp in Sources */,
GPLL0000000000000000000002 /* GamepadProviderSDL2.cpp in Sources */,
GPLL0000000000000000000003 /* GamepadSDL2.cpp in Sources */,
GPLL0000000000000000000006 /* GamepadProviderGCController.mm in Sources */,
GPLL0000000000000000000007 /* GamepadGCController.mm in Sources */,
LL000001000000000000000001 /* BuildingComponent.cpp in Sources */,
LL000001000000000000000002 /* Character.cpp in Sources */,
LL000001000000000000000003 /* CharComponent.cpp in Sources */,
Expand Down
8 changes: 5 additions & 3 deletions RTLooneyLadders/source/App.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ AudioManagerOS g_audioManager;
#else
//it's being compiled as a native OSX app - use SDL audio, no FMOD required
#include "Audio/AudioManagerSDL.h"
#include "Gamepad/GamepadProviderSDL2.h"
#include "Gamepad/GamepadProviderGCController.h"
#include <SDL2/SDL.h>
AudioManagerSDL g_audioManager;
// Required by MainController.mm and BaseApp.cpp - defined in SDL2Main.cpp for SDL builds
Expand Down Expand Up @@ -129,8 +129,10 @@ bool App::Init()
if (!BaseApp::Init()) return false;

#ifdef PLATFORM_OSX
SDL_Init(SDL_INIT_EVENTS | SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER);
GetGamepadManager()->AddProvider(new GamepadProviderSDL2());
SDL_Init(SDL_INIT_EVENTS);
GetGamepadManager()->AddProvider(new GamepadProviderGCController());
GetGamepadManager()->m_sig_gamepad_connected.connect(1, boost::bind(&App::OnGamepadConnected, this, _1));
GetGamepadManager()->m_sig_gamepad_disconnected.connect(1, boost::bind(&App::OnGamepadDisconnected, this, _1));
#endif

LogMsg("Save path is %s", GetSavePath().c_str());
Expand Down
29 changes: 29 additions & 0 deletions shared/Gamepad/GamepadGCController.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#pragma once

#ifdef PLATFORM_OSX

#include "Gamepad.h"

#ifdef __OBJC__
#import <GameController/GameController.h>
#endif

class GamepadGCController : public Gamepad
{
public:
GamepadGCController();
virtual ~GamepadGCController();

virtual bool Init();
virtual void Kill();
virtual void Update();

#ifdef __OBJC__
void InitWithGCController(GCController* controller);
#endif

protected:
void* m_pGCController; // GCController* stored as void* for non-ObjC translation units
};

#endif // PLATFORM_OSX
169 changes: 169 additions & 0 deletions shared/Gamepad/GamepadGCController.mm
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
#include "PlatformPrecomp.h"

#ifdef PLATFORM_OSX

#include "GamepadGCController.h"
#include "GamepadManager.h"

// Button index constants matching SDL_CONTROLLER_BUTTON_* values,
// used as raw indices into m_buttons[]. No SDL headers needed here.
enum {
GCC_BTN_A = 0,
GCC_BTN_B = 1,
GCC_BTN_X = 2,
GCC_BTN_Y = 3,
GCC_BTN_BACK = 4,
GCC_BTN_GUIDE = 5,
GCC_BTN_START = 6,
GCC_BTN_LEFTSTICK = 7,
GCC_BTN_RIGHTSTICK = 8,
GCC_BTN_LEFTSHOULDER = 9,
GCC_BTN_RIGHTSHOULDER = 10,
GCC_BTN_DPAD_UP = 11,
GCC_BTN_DPAD_DOWN = 12,
GCC_BTN_DPAD_LEFT = 13,
GCC_BTN_DPAD_RIGHT = 14,
};

GamepadGCController::GamepadGCController()
{
m_pGCController = nullptr;
}

GamepadGCController::~GamepadGCController()
{
Kill();
}

bool GamepadGCController::Init()
{
m_axisUsedCount = 6;
m_buttonsUsedCount = 16;
m_name = "GCController";
return true;
}

void GamepadGCController::Kill()
{
if (m_pGCController)
{
m_pGCController = nullptr;
}
}

void GamepadGCController::Update()
{
Gamepad::Update();
}

void GamepadGCController::InitWithGCController(GCController* controller)
{
m_pGCController = (void*)controller;

const char* pName = [controller.vendorName UTF8String];
if (pName)
{
LogMsg("GCController detected: %s", pName);
m_name = pName;
}

// Same button mapping as GamepadSDL2 Windows path
SetRightStickAxis(2, 3);

m_buttons[GCC_BTN_A].m_virtualKey = VIRTUAL_DPAD_BUTTON_DOWN;
m_buttons[GCC_BTN_B].m_virtualKey = VIRTUAL_DPAD_BUTTON_RIGHT;
m_buttons[GCC_BTN_X].m_virtualKey = VIRTUAL_DPAD_BUTTON_LEFT;
m_buttons[GCC_BTN_Y].m_virtualKey = VIRTUAL_DPAD_BUTTON_UP;
m_buttons[GCC_BTN_LEFTSHOULDER].m_virtualKey = VIRTUAL_DPAD_LBUTTON;
m_buttons[GCC_BTN_RIGHTSHOULDER].m_virtualKey = VIRTUAL_DPAD_RBUTTON;
m_buttons[GCC_BTN_BACK].m_virtualKey = VIRTUAL_DPAD_SELECT;
m_buttons[GCC_BTN_START].m_virtualKey = VIRTUAL_DPAD_START;
m_buttons[GCC_BTN_GUIDE].m_virtualKey = VIRTUAL_DPAD_MENU;
m_buttons[GCC_BTN_LEFTSTICK].m_virtualKey = VIRTUAL_JOYSTICK_BUTTON_LEFT;
m_buttons[GCC_BTN_RIGHTSTICK].m_virtualKey = VIRTUAL_JOYSTICK_BUTTON_RIGHT;
m_buttons[GCC_BTN_DPAD_UP].m_virtualKey = VIRTUAL_KEY_DIR_UP;
m_buttons[GCC_BTN_DPAD_DOWN].m_virtualKey = VIRTUAL_KEY_DIR_DOWN;
m_buttons[GCC_BTN_DPAD_LEFT].m_virtualKey = VIRTUAL_KEY_DIR_LEFT;
m_buttons[GCC_BTN_DPAD_RIGHT].m_virtualKey = VIRTUAL_KEY_DIR_RIGHT;

GCExtendedGamepad* pad = controller.extendedGamepad;
if (!pad)
{
LogMsg("GCController has no extendedGamepad profile, ignoring");
return;
}

// Capture a weak ref to self for the block
GamepadGCController* self = this;

pad.buttonA.valueChangedHandler = ^(GCControllerButtonInput*, float, BOOL pressed) {
self->OnButton(pressed, GCC_BTN_A);
};
pad.buttonB.valueChangedHandler = ^(GCControllerButtonInput*, float, BOOL pressed) {
self->OnButton(pressed, GCC_BTN_B);
};
pad.buttonX.valueChangedHandler = ^(GCControllerButtonInput*, float, BOOL pressed) {
self->OnButton(pressed, GCC_BTN_X);
};
pad.buttonY.valueChangedHandler = ^(GCControllerButtonInput*, float, BOOL pressed) {
self->OnButton(pressed, GCC_BTN_Y);
};
pad.leftShoulder.valueChangedHandler = ^(GCControllerButtonInput*, float, BOOL pressed) {
self->OnButton(pressed, GCC_BTN_LEFTSHOULDER);
};
pad.rightShoulder.valueChangedHandler = ^(GCControllerButtonInput*, float, BOOL pressed) {
self->OnButton(pressed, GCC_BTN_RIGHTSHOULDER);
};
pad.leftThumbstickButton.valueChangedHandler = ^(GCControllerButtonInput*, float, BOOL pressed) {
self->OnButton(pressed, GCC_BTN_LEFTSTICK);
};
pad.rightThumbstickButton.valueChangedHandler = ^(GCControllerButtonInput*, float, BOOL pressed) {
self->OnButton(pressed, GCC_BTN_RIGHTSTICK);
};
pad.buttonOptions.valueChangedHandler = ^(GCControllerButtonInput*, float, BOOL pressed) {
self->OnButton(pressed, GCC_BTN_BACK);
};
pad.buttonMenu.valueChangedHandler = ^(GCControllerButtonInput*, float, BOOL pressed) {
self->OnButton(pressed, GCC_BTN_START);
};

// D-pad
pad.dpad.up.valueChangedHandler = ^(GCControllerButtonInput*, float, BOOL pressed) {
self->OnButton(pressed, GCC_BTN_DPAD_UP);
};
pad.dpad.down.valueChangedHandler = ^(GCControllerButtonInput*, float, BOOL pressed) {
self->OnButton(pressed, GCC_BTN_DPAD_DOWN);
};
pad.dpad.left.valueChangedHandler = ^(GCControllerButtonInput*, float, BOOL pressed) {
self->OnButton(pressed, GCC_BTN_DPAD_LEFT);
};
pad.dpad.right.valueChangedHandler = ^(GCControllerButtonInput*, float, BOOL pressed) {
self->OnButton(pressed, GCC_BTN_DPAD_RIGHT);
};

// Left stick
pad.leftThumbstick.xAxis.valueChangedHandler = ^(GCControllerAxisInput*, float value) {
self->SetAxis(0, value);
};
pad.leftThumbstick.yAxis.valueChangedHandler = ^(GCControllerAxisInput*, float value) {
self->SetAxis(1, -value); // GCController Y is inverted vs SDL convention
};

// Right stick
pad.rightThumbstick.xAxis.valueChangedHandler = ^(GCControllerAxisInput*, float value) {
self->SetAxis(2, value);
};
pad.rightThumbstick.yAxis.valueChangedHandler = ^(GCControllerAxisInput*, float value) {
self->SetAxis(3, -value);
};

// Triggers (axes 4 and 5)
pad.leftTrigger.valueChangedHandler = ^(GCControllerButtonInput*, float value, BOOL) {
self->SetAxis(4, value);
};
pad.rightTrigger.valueChangedHandler = ^(GCControllerButtonInput*, float value, BOOL) {
self->SetAxis(5, value);
};
}

#endif // PLATFORM_OSX
25 changes: 25 additions & 0 deletions shared/Gamepad/GamepadProviderGCController.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#pragma once

#ifdef PLATFORM_OSX

#include "GamepadProvider.h"

class GamepadProviderGCController : public GamepadProvider
{
public:
GamepadProviderGCController();
virtual ~GamepadProviderGCController();

virtual string GetName() { return "GCController"; }
virtual bool Init();
virtual void Kill();
virtual void Update();

protected:
void AddControllerByIndex(int index);

void* m_pConnectObserver; // id<NSObject> stored as void*
void* m_pDisconnectObserver; // id<NSObject> stored as void*
};

#endif // PLATFORM_OSX
Loading