aboutsummaryrefslogtreecommitdiffstats
path: root/Samples/CommonSrc
diff options
context:
space:
mode:
Diffstat (limited to 'Samples/CommonSrc')
-rw-r--r--Samples/CommonSrc/Platform/OSX_Gamepad.cpp430
-rw-r--r--Samples/CommonSrc/Platform/OSX_Gamepad.h66
-rw-r--r--Samples/CommonSrc/Platform/OSX_Platform.h113
-rw-r--r--Samples/CommonSrc/Platform/OSX_Platform.mm553
-rw-r--r--Samples/CommonSrc/Platform/OSX_PlatformObjc.h53
-rw-r--r--Samples/CommonSrc/Platform/OSX_WavPlayer.cpp250
-rw-r--r--Samples/CommonSrc/Platform/OSX_WavPlayer.h72
7 files changed, 1537 insertions, 0 deletions
diff --git a/Samples/CommonSrc/Platform/OSX_Gamepad.cpp b/Samples/CommonSrc/Platform/OSX_Gamepad.cpp
new file mode 100644
index 0000000..69acca4
--- /dev/null
+++ b/Samples/CommonSrc/Platform/OSX_Gamepad.cpp
@@ -0,0 +1,430 @@
+/************************************************************************************
+
+Filename : OSX_Gamepad.cpp
+Content : OSX implementation of Gamepad functionality.
+Created : May 6, 2013
+Authors : Lee Cooper
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+************************************************************************************/
+
+#include "OSX_Gamepad.h"
+
+
+static const UInt32 Logitech_F710_VendorID = 0x046D;
+//static const UInt32 Logitech_F710_ProductID = 0xC219;
+
+static const UInt32 Sony_DualShock3_VendorID = 0x054C;
+//static const UInt32 Sony_DualShock3_ProductID = 0x0268;
+
+
+namespace OVR { namespace OvrPlatform { namespace OSX {
+
+
+GamepadManager::GamepadManager()
+ : bStateChanged(false)
+{
+
+ HidManager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
+ IOHIDManagerOpen(HidManager, kIOHIDOptionsTypeNone);
+ IOHIDManagerScheduleWithRunLoop(HidManager,
+ CFRunLoopGetCurrent(),
+ kCFRunLoopDefaultMode);
+
+
+ // Setup device matching.
+ CFStringRef keys[] = { CFSTR(kIOHIDDeviceUsagePageKey),
+ CFSTR(kIOHIDDeviceUsageKey)};
+
+ int value;
+ CFNumberRef values[2];
+ CFDictionaryRef dictionaries[2];
+
+ // Match joysticks.
+ value = kHIDPage_GenericDesktop;
+ values[0] = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &value);
+
+ value = kHIDUsage_GD_Joystick;
+ values[1] = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &value);
+
+ dictionaries[0] = CFDictionaryCreate(kCFAllocatorDefault,
+ (const void **) keys,
+ (const void **) values,
+ 2,
+ &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+ CFRelease(values[0]);
+ CFRelease(values[1]);
+
+ // Match gamepads.
+ value = kHIDPage_GenericDesktop;
+ values[0] = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &value);
+
+ value = kHIDUsage_GD_GamePad;
+ values[1] = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &value);
+
+ dictionaries[1] = CFDictionaryCreate(kCFAllocatorDefault,
+ (const void **) keys,
+ (const void **) values,
+ 2,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ CFRelease(values[0]);
+ CFRelease(values[1]);
+
+ CFArrayRef array = CFArrayCreate( kCFAllocatorDefault,
+ (const void **) dictionaries,
+ 2,
+ &kCFTypeArrayCallBacks);
+ CFRelease(dictionaries[0]);
+ CFRelease(dictionaries[1]);
+
+ IOHIDManagerSetDeviceMatchingMultiple(HidManager, array);
+
+ CFRelease(array);
+
+
+ IOHIDManagerRegisterDeviceMatchingCallback(HidManager, staticOnDeviceMatched, this);
+ IOHIDManagerRegisterDeviceRemovalCallback(HidManager, staticOnDeviceRemoved, this);
+
+}
+
+GamepadManager::~GamepadManager()
+{
+ CFRelease(HidManager);
+}
+
+UInt32 GamepadManager::GetGamepadCount()
+{
+ return 1;
+}
+
+bool GamepadManager::GetGamepadState(UInt32 index, GamepadState* pState)
+{
+ // For now we just support one gamepad.
+ OVR_UNUSED(index);
+
+ if (!bStateChanged)
+ {
+ return false;
+ }
+
+ bStateChanged = false;
+// State.Debug();
+
+ *pState = State;
+ return true;
+}
+
+int GamepadManager::getIntDeviceProperty(IOHIDDeviceRef device, CFStringRef key)
+{
+ CFTypeRef type = IOHIDDeviceGetProperty(device, key);
+ OVR_ASSERT(type != NULL && CFGetTypeID(type) == CFNumberGetTypeID());
+
+ int value;
+ CFNumberGetValue((CFNumberRef) type, kCFNumberSInt32Type, &value);
+
+ return value;
+}
+
+void GamepadManager::staticOnDeviceMatched(void* context, IOReturn result, void* sender, IOHIDDeviceRef device)
+{
+ OVR_UNUSED(result);
+ OVR_UNUSED(sender);
+ GamepadManager* pManager = (GamepadManager*) context;
+ pManager->onDeviceMatched(device);
+}
+
+void GamepadManager::onDeviceMatched(IOHIDDeviceRef device)
+{
+ IOHIDDeviceRegisterInputValueCallback(device, staticOnDeviceValueChanged, this);
+}
+
+void GamepadManager::staticOnDeviceRemoved(void* context, IOReturn result, void* sender, IOHIDDeviceRef device)
+{
+ OVR_UNUSED(result);
+ OVR_UNUSED(sender);
+ GamepadManager* pManager = (GamepadManager*) context;
+ pManager->onDeviceRemoved(device);
+}
+
+void GamepadManager::onDeviceRemoved(IOHIDDeviceRef device)
+{
+ IOHIDDeviceRegisterInputValueCallback(device, NULL, NULL);
+}
+
+void GamepadManager::staticOnDeviceValueChanged(void* context, IOReturn result, void* sender, IOHIDValueRef value)
+{
+ OVR_UNUSED(result);
+ OVR_UNUSED(sender);
+ GamepadManager* pManager = (GamepadManager*) context;
+ pManager->onDeviceValueChanged(value);
+}
+
+float GamepadManager::mapAnalogAxis(IOHIDValueRef value, IOHIDElementRef element)
+{
+
+ CFIndex val = IOHIDValueGetIntegerValue(value);
+ CFIndex min = IOHIDElementGetLogicalMin(element);
+ CFIndex max = IOHIDElementGetLogicalMax(element);
+
+ float v = (float) (val - min) / (float) (max - min);
+ v = v * 2.0f - 1.0f;
+
+ // Dead zone.
+ if (v < 0.1f && v > -0.1f)
+ {
+ v = 0.0f;
+ }
+
+ return v;
+}
+
+bool GamepadManager::setStateIfDifferent(float& state, float newState)
+{
+ if (state == newState)
+ return false;
+
+ state = newState;
+
+ return true;
+}
+
+void GamepadManager::onDeviceValueChanged(IOHIDValueRef value)
+{
+
+ IOHIDElementRef element = IOHIDValueGetElement(value);
+ IOHIDDeviceRef device = IOHIDElementGetDevice(element);
+
+ unsigned int vendorID = (unsigned int)getIntDeviceProperty(device, CFSTR(kIOHIDVendorIDKey));
+ unsigned int productID = (unsigned int)getIntDeviceProperty(device, CFSTR(kIOHIDProductIDKey));
+ OVR_UNUSED(productID);
+
+ uint32_t usagePage = IOHIDElementGetUsagePage(element);
+ uint32_t usage = IOHIDElementGetUsage(element);
+
+ // The following controller mapping is based on the Logitech F710, however we use it for
+ // all Logitech devices on the assumption that they're likely to share the same mapping.
+ if (vendorID == Logitech_F710_VendorID)
+ {
+ // Logitech F710 mapping.
+ if (usagePage == kHIDPage_Button)
+ {
+ bool buttonState = IOHIDValueGetIntegerValue(value);
+
+ switch(usage)
+ {
+ case kHIDUsage_Button_1:
+ manipulateBitField(State.Buttons, Gamepad_X, buttonState);
+ break;
+ case kHIDUsage_Button_2:
+ manipulateBitField(State.Buttons, Gamepad_A, buttonState);
+ break;
+ case kHIDUsage_Button_3:
+ manipulateBitField(State.Buttons, Gamepad_B, buttonState);
+ break;
+ case kHIDUsage_Button_4:
+ manipulateBitField(State.Buttons, Gamepad_Y, buttonState);
+ break;
+ case 0x05:
+ manipulateBitField(State.Buttons, Gamepad_L1, buttonState);
+ break;
+ case 0x06:
+ manipulateBitField(State.Buttons, Gamepad_R1, buttonState);
+ break;
+ case 0x07:
+ State.LT = buttonState ? 1.0f:0.0f;
+ break;
+ case 0x08:
+ State.RT = buttonState ? 1.0f:0.0f;
+ break;
+ case 0x09:
+ manipulateBitField(State.Buttons, Gamepad_Back, buttonState);
+ break;
+ case 0x0A:
+ manipulateBitField(State.Buttons, Gamepad_Start, buttonState);
+ break;
+ case 0x0B:
+ manipulateBitField(State.Buttons, Gamepad_LStick, buttonState);
+ break;
+ case 0x0C:
+ manipulateBitField(State.Buttons, Gamepad_RStick, buttonState);
+ break;
+ default:
+ return;
+ }
+ }
+ else if (usagePage == kHIDPage_GenericDesktop)
+ {
+ float v;
+ switch(usage)
+ {
+ case kHIDUsage_GD_X:
+ v = mapAnalogAxis(value, element);
+ if (!setStateIfDifferent(State.LX, v))
+ return;
+ break;
+ case kHIDUsage_GD_Y:
+ v = mapAnalogAxis(value, element);
+ if (!setStateIfDifferent(State.LY, -v))
+ return;
+ break;
+ case kHIDUsage_GD_Z:
+ v = mapAnalogAxis(value, element);
+ if (!setStateIfDifferent(State.RX, v))
+ return;
+ break;
+ case kHIDUsage_GD_Rz:
+ v = mapAnalogAxis(value, element);
+ if (!setStateIfDifferent(State.RY, -v))
+ return;
+ break;
+ case kHIDUsage_GD_Hatswitch:
+ {
+ CFIndex integerValue = IOHIDValueGetIntegerValue(value);
+
+ manipulateBitField(State.Buttons,
+ Gamepad_Up,
+ integerValue == 7 || integerValue == 0 || integerValue == 1);
+ manipulateBitField(State.Buttons,
+ Gamepad_Down,
+ integerValue == 3 || integerValue == 4 || integerValue == 5);
+ manipulateBitField(State.Buttons,
+ Gamepad_Left,
+ integerValue == 5 || integerValue == 6 || integerValue == 7);
+ manipulateBitField(State.Buttons,
+ Gamepad_Right,
+ integerValue == 1 || integerValue == 2 || integerValue == 3);
+ }
+ break;
+ default:
+ return;
+ }
+ }
+ }
+ // The following controller mapping is based on the Sony DualShock3, however we use it for
+ // all Sony devices on the assumption that they're likely to share the same mapping.
+ else if (vendorID == Sony_DualShock3_VendorID)
+ {
+ // PS3 Controller.
+ if (usagePage == kHIDPage_Button)
+ {
+ bool buttonState = IOHIDValueGetIntegerValue(value);
+
+ switch(usage)
+ {
+ case kHIDUsage_Button_1:
+ manipulateBitField(State.Buttons, Gamepad_Back, buttonState);
+ break;
+ case kHIDUsage_Button_2:
+ manipulateBitField(State.Buttons, Gamepad_LStick, buttonState);
+ break;
+ case kHIDUsage_Button_3:
+ manipulateBitField(State.Buttons, Gamepad_RStick, buttonState);
+ break;
+ case kHIDUsage_Button_4:
+ manipulateBitField(State.Buttons, Gamepad_Start, buttonState);
+ break;
+ case 0x05:
+ manipulateBitField(State.Buttons, Gamepad_Up, buttonState);
+ break;
+ case 0x06:
+ manipulateBitField(State.Buttons, Gamepad_Right, buttonState);
+ break;
+ case 0x07:
+ manipulateBitField(State.Buttons, Gamepad_Down, buttonState);
+ break;
+ case 0x08:
+ manipulateBitField(State.Buttons, Gamepad_Left, buttonState);
+ break;
+ case 0x09:
+ State.LT = buttonState ? 1.0f:0.0f;
+ break;
+ case 0x0A:
+ State.RT = buttonState ? 1.0f:0.0f;
+ break;
+ case 0x0B:
+ manipulateBitField(State.Buttons, Gamepad_L1, buttonState);
+ break;
+ case 0x0C:
+ manipulateBitField(State.Buttons, Gamepad_R1, buttonState);
+ break;
+ case 0x0D:
+ // PS3 Triangle.
+ manipulateBitField(State.Buttons, Gamepad_TRIANGLE, buttonState);
+ break;
+ case 0x0E:
+ // PS3 Circle
+ manipulateBitField(State.Buttons, Gamepad_CIRCLE, buttonState);
+ break;
+ case 0x0F:
+ // PS3 Cross
+ manipulateBitField(State.Buttons, Gamepad_CROSS, buttonState);
+ break;
+ case 0x10:
+ // PS3 Square
+ manipulateBitField(State.Buttons, Gamepad_SQUARE, buttonState);
+ break;
+ default:
+ return;
+ }
+ }
+ else if (usagePage == kHIDPage_GenericDesktop)
+ {
+ float v;
+ switch(usage)
+ {
+ case kHIDUsage_GD_X:
+ v = mapAnalogAxis(value, element);
+ if (!setStateIfDifferent(State.LX, v))
+ return;
+ break;
+ case kHIDUsage_GD_Y:
+ v = mapAnalogAxis(value, element);
+ if (!setStateIfDifferent(State.LY, -v))
+ return;
+ break;
+ case kHIDUsage_GD_Z:
+ v = mapAnalogAxis(value, element);
+ if (!setStateIfDifferent(State.RX, v))
+ return;
+ break;
+ case kHIDUsage_GD_Rz:
+ v = mapAnalogAxis(value, element);
+ if (!setStateIfDifferent(State.RY, -v))
+ return;
+ break;
+ default:
+ return;
+ }
+ }
+ }
+
+ bStateChanged = true;
+}
+
+void GamepadManager::manipulateBitField(unsigned int& bitfield, unsigned int mask, bool val)
+{
+ if (val)
+ {
+ bitfield |= mask;
+ }
+ else
+ {
+ bitfield &= ~mask;
+ }
+}
+
+}}} // OVR::OvrPlatform::OSX
diff --git a/Samples/CommonSrc/Platform/OSX_Gamepad.h b/Samples/CommonSrc/Platform/OSX_Gamepad.h
new file mode 100644
index 0000000..5abeb56
--- /dev/null
+++ b/Samples/CommonSrc/Platform/OSX_Gamepad.h
@@ -0,0 +1,66 @@
+/************************************************************************************
+
+Filename : OSX_Gamepad.h
+Content : OSX implementation of Gamepad functionality.
+Created : May 6, 2013
+Authors : Lee Cooper
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+************************************************************************************/
+
+#ifndef OVR_OSX_Gamepad_h
+#define OVR_OSX_Gamepad_h
+
+#include <IOKit/IOKitLib.h>
+#include <IOKit/hid/IOHIDManager.h>
+
+#include "Gamepad.h"
+
+namespace OVR { namespace OvrPlatform { namespace OSX {
+
+
+class GamepadManager : public OvrPlatform::GamepadManager
+{
+public:
+ GamepadManager();
+ ~GamepadManager();
+
+ virtual UInt32 GetGamepadCount();
+ virtual bool GetGamepadState(UInt32 index, GamepadState* pState);
+
+private:
+ static void staticOnDeviceMatched(void* context, IOReturn result, void* sender, IOHIDDeviceRef device);
+ void onDeviceMatched(IOHIDDeviceRef device);
+
+ static void staticOnDeviceRemoved(void* context, IOReturn result, void* sender, IOHIDDeviceRef device);
+ void onDeviceRemoved(IOHIDDeviceRef device);
+
+ static void staticOnDeviceValueChanged(void* context, IOReturn result, void* sender, IOHIDValueRef value);
+ void onDeviceValueChanged(IOHIDValueRef value);
+
+ int getIntDeviceProperty(IOHIDDeviceRef device, CFStringRef key);
+ float mapAnalogAxis(IOHIDValueRef value, IOHIDElementRef element);
+ void manipulateBitField(unsigned int& bitfield, unsigned int mask, bool val);
+ bool setStateIfDifferent(float& state, float newState);
+
+ IOHIDManagerRef HidManager;
+ GamepadState State;
+ bool bStateChanged;
+};
+
+}}}
+
+#endif // OVR_OSX_Gamepad_h
diff --git a/Samples/CommonSrc/Platform/OSX_Platform.h b/Samples/CommonSrc/Platform/OSX_Platform.h
new file mode 100644
index 0000000..6803aab
--- /dev/null
+++ b/Samples/CommonSrc/Platform/OSX_Platform.h
@@ -0,0 +1,113 @@
+/************************************************************************************
+
+Filename : OSX_Platform.h
+Content :
+Created :
+Authors :
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+************************************************************************************/
+
+#include "../Platform/Platform.h"
+#include "../Render/Render_GL_Device.h"
+
+namespace OVR { namespace OvrPlatform { namespace OSX {
+
+class PlatformCore : public OvrPlatform::PlatformCore
+{
+public:
+ void* Win;
+ void* View;
+ void* NsApp;
+ bool Quit;
+ int ExitCode;
+ int Width, Height;
+ MouseMode MMode;
+
+ void RunIdle();
+
+public:
+ PlatformCore(Application* app, void* nsapp);
+ ~PlatformCore();
+
+ void* SetupWindow(int w, int h);
+ void Exit(int exitcode);
+
+ RenderDevice* SetupGraphics(const SetupGraphicsDeviceSet& setupGraphicsDesc,
+ const char* gtype, const Render::RendererParams& rp);
+
+ void SetMouseMode(MouseMode mm);
+ void GetWindowSize(int* w, int* h) const;
+
+ void SetWindowTitle(const char*title);
+
+ void ShowWindow(bool show);
+ void DestroyWindow();
+ bool SetFullscreen(const Render::RendererParams& rp, int fullscreen);
+ int GetDisplayCount();
+ Render::DisplayId GetDisplay(int screen);
+
+ String GetContentDirectory() const;
+};
+
+}}
+namespace Render { namespace GL { namespace OSX {
+
+class RenderDevice : public Render::GL::RenderDevice
+{
+public:
+ void* Context;
+
+ RenderDevice(const Render::RendererParams& p, void* context)
+ : GL::RenderDevice(p), Context(context) {}
+
+ virtual void Shutdown();
+ virtual void Present(bool useVsync);
+
+ virtual bool SetFullscreen(DisplayMode fullscreen);
+
+ virtual ovrRenderAPIConfig Get_ovrRenderAPIConfig() const;
+
+ // oswnd = X11::PlatformCore*
+ static Render::RenderDevice* CreateDevice(const RendererParams& rp, void* oswnd);
+};
+
+}}}}
+
+
+// OVR_PLATFORM_APP_ARGS specifies the Application class to use for startup,
+// providing it with startup arguments.
+#define OVR_PLATFORM_APP_ARGS_WITH_LOG(AppClass, LogClass, args) \
+OVR::OvrPlatform::Application* OVR::OvrPlatform::Application::CreateApplication() \
+{ static LogClass log; OVR::System::Init(&log); \
+return new AppClass args; } \
+void OVR::OvrPlatform::Application::DestroyApplication(OVR::OvrPlatform::Application* app) \
+{ OVR::OvrPlatform::PlatformCore* platform = app->pPlatform; \
+delete app; delete platform; OVR::System::Destroy(); };
+
+#define OVR_PLATFORM_APP_ARGS(AppClass, args) \
+ OVR::OvrPlatform::Application* OVR::OvrPlatform::Application::CreateApplication() \
+{ OVR::System::Init(OVR::Log::ConfigureDefaultLog(OVR::LogMask_All)); \
+ return new AppClass args; } \
+ void OVR::OvrPlatform::Application::DestroyApplication(OVR::OvrPlatform::Application* app) \
+{ OVR::OvrPlatform::PlatformCore* platform = app->pPlatform; \
+ delete app; delete platform; OVR::System::Destroy(); };
+
+// OVR_PLATFORM_APP_ARGS specifies the Application startup class with no args.
+#define OVR_PLATFORM_APP(AppClass) OVR_PLATFORM_APP_ARGS(AppClass, ())
+
+#define OVR_PLATFORM_APP_WITH_LOG(AppClass,LogClass) OVR_PLATFORM_APP_ARGS_WITH_LOG(AppClass,LogClass, ())
+
diff --git a/Samples/CommonSrc/Platform/OSX_Platform.mm b/Samples/CommonSrc/Platform/OSX_Platform.mm
new file mode 100644
index 0000000..71e333f
--- /dev/null
+++ b/Samples/CommonSrc/Platform/OSX_Platform.mm
@@ -0,0 +1,553 @@
+/************************************************************************************
+
+Filename : OSX_Platform.mm
+Content :
+Created :
+Authors :
+
+Copyright : Copyright 2012 Oculus, Inc. All Rights reserved.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+************************************************************************************/
+
+#import "../Platform/OSX_PlatformObjc.h"
+
+using namespace OVR;
+using namespace OVR::OvrPlatform;
+
+@implementation OVRApp
+
+- (void)dealloc
+{
+ [super dealloc];
+}
+
+- (void)run
+{
+ NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
+ _running = YES;
+ OVR::OvrPlatform::Application* app;
+ {
+ using namespace OVR;
+ using namespace OVR::OvrPlatform;
+
+ // CreateApplication must be the first call since it does OVR::System::Initialize.
+ app = Application::CreateApplication();
+ OSX::PlatformCore* platform = new OSX::PlatformCore(app, self);
+ // The platform attached to an app will be deleted by DestroyApplication.
+ app->SetPlatformCore(platform);
+
+ [self setApp:app];
+ [self setPlatform:platform];
+
+ const char* argv[] = {"OVRApp"};
+ int exitCode = app->OnStartup(1, argv);
+ if (exitCode)
+ {
+ Application::DestroyApplication(app);
+ exit(exitCode);
+ }
+ }
+ [self finishLaunching];
+ [pool drain];
+
+ while ([self isRunning])
+ {
+ pool = [[NSAutoreleasePool alloc] init];
+ NSEvent* event = [self nextEventMatchingMask:NSAnyEventMask untilDate:nil inMode:NSDefaultRunLoopMode dequeue:YES];
+ if (event)
+ {
+ [self sendEvent:event];
+ }
+ _App->OnIdle();
+ [pool drain];
+ }
+ OVR::OvrPlatform::Application::DestroyApplication(app);
+}
+
+@end
+
+static int KeyMap[][2] =
+{
+ { NSDeleteFunctionKey, OVR::Key_Delete },
+ { '\t', OVR::Key_Tab },
+ { '\n', OVR::Key_Return },
+ { NSPauseFunctionKey, OVR::Key_Pause },
+ { 27, OVR::Key_Escape },
+ { 127, OVR::Key_Backspace },
+ { ' ', OVR::Key_Space },
+ { NSPageUpFunctionKey, OVR::Key_PageUp },
+ { NSPageDownFunctionKey, OVR::Key_PageDown },
+ { NSNextFunctionKey, OVR::Key_PageDown },
+ { NSEndFunctionKey, OVR::Key_End },
+ { NSHomeFunctionKey, OVR::Key_Home },
+ { NSLeftArrowFunctionKey, OVR::Key_Left },
+ { NSUpArrowFunctionKey, OVR::Key_Up },
+ { NSRightArrowFunctionKey, OVR::Key_Right },
+ { NSDownArrowFunctionKey, OVR::Key_Down },
+ { NSInsertFunctionKey, OVR::Key_Insert },
+ { NSDeleteFunctionKey, OVR::Key_Delete },
+ { NSHelpFunctionKey, OVR::Key_Insert },
+};
+
+
+static KeyCode MapToKeyCode(wchar_t vk)
+{
+ unsigned key = Key_None;
+
+ if ((vk >= 'a') && (vk <= 'z'))
+ {
+ key = vk - 'a' + Key_A;
+ }
+ else if ((vk >= ' ') && (vk <= '~'))
+ {
+ key = vk;
+ }
+ else if ((vk >= '0') && (vk <= '9'))
+ {
+ key = vk - '0' + Key_Num0;
+ }
+ else if ((vk >= NSF1FunctionKey) && (vk <= NSF15FunctionKey))
+ {
+ key = vk - NSF1FunctionKey + Key_F1;
+ }
+ else
+ {
+ for (unsigned i = 0; i< (sizeof(KeyMap) / sizeof(KeyMap[1])); i++)
+ {
+ if (vk == KeyMap[i][0])
+ {
+ key = KeyMap[i][1];
+ break;
+ }
+ }
+ }
+
+ return (KeyCode)key;
+}
+
+static int MapModifiers(unsigned long xmod)
+{
+ int mod = 0;
+ if (xmod & NSShiftKeyMask)
+ mod |= OVR::OvrPlatform::Mod_Shift;
+ if (xmod & NSCommandKeyMask)
+ mod |= OVR::OvrPlatform::Mod_Control;
+ if (xmod & NSAlternateKeyMask)
+ mod |= OVR::OvrPlatform::Mod_Alt;
+ if (xmod & NSControlKeyMask)
+ mod |= OVR::OvrPlatform::Mod_Meta;
+ return mod;
+}
+
+@implementation OVRView
+
+-(BOOL) acceptsFirstResponder
+{
+ return YES;
+}
+-(BOOL) acceptsFirstMouse:(NSEvent *)ev
+{
+ return YES;
+}
+
++(CGDirectDisplayID) displayFromScreen:(NSScreen *)s
+{
+ NSNumber* didref = (NSNumber*)[[s deviceDescription] objectForKey:@"NSScreenNumber"];
+ CGDirectDisplayID disp = (CGDirectDisplayID)[didref longValue];
+ return disp;
+}
+
+-(void) warpMouseToCenter
+{
+ NSPoint w;
+ w.x = _Platform->Width/2.0f;
+ w.y = _Platform->Height/2.0f;
+ w = [[self window] convertBaseToScreen:w];
+ CGDirectDisplayID disp = [OVRView displayFromScreen:[[self window] screen]];
+ CGPoint p = {w.x, CGDisplayPixelsHigh(disp)-w.y};
+ CGDisplayMoveCursorToPoint(disp, p);
+}
+
+static bool LookupKey(NSEvent* ev, wchar_t& ch, OVR::KeyCode& key, unsigned& mods)
+{
+ NSString* chars = [ev charactersIgnoringModifiers];
+ if ([chars length] == 0)
+ return false;
+ ch = [chars characterAtIndex:0];
+ mods = MapModifiers([ev modifierFlags]);
+
+ // check for Cmd+Latin Letter
+ NSString* modchars = [ev characters];
+ if ([modchars length])
+ {
+ wchar_t modch = [modchars characterAtIndex:0];
+ if (modch >= 'a' && modch <= 'z')
+ ch = modch;
+ }
+ key = MapToKeyCode(ch);
+ return true;
+}
+
+-(void) keyDown:(NSEvent*)ev
+{
+ OVR::KeyCode key;
+ unsigned mods;
+ wchar_t ch;
+ if (!LookupKey(ev, ch, key, mods))
+ return;
+ if (key == Key_Escape && _Platform->MMode == Mouse_Relative)
+ {
+ [self warpMouseToCenter];
+ CGAssociateMouseAndMouseCursorPosition(true);
+ [NSCursor unhide];
+ _Platform->MMode = Mouse_RelativeEscaped;
+ }
+ _App->OnKey(key, ch, true, mods);
+}
+-(void) keyUp:(NSEvent*)ev
+{
+ OVR::KeyCode key;
+ unsigned mods;
+ wchar_t ch;
+ if (LookupKey(ev, ch, key, mods))
+ _App->OnKey(key, ch, false, mods);
+}
+
+static const OVR::KeyCode ModifierKeys[] = {OVR::Key_None, OVR::Key_Shift, OVR::Key_Control, OVR::Key_Alt, OVR::Key_Meta};
+
+-(void)flagsChanged:(NSEvent *)ev
+{
+ unsigned long cmods = [ev modifierFlags];
+ if ((cmods & 0xffff0000) != _Modifiers)
+ {
+ uint32_t mods = MapModifiers(cmods);
+ for (int i = 1; i <= 4; i++)
+ {
+ unsigned long m = (1 << (16+i));
+ if ((cmods & m) != (_Modifiers & m))
+ {
+ if (cmods & m)
+ _App->OnKey(ModifierKeys[i], 0, true, mods);
+ else
+ _App->OnKey(ModifierKeys[i], 0, false, mods);
+ }
+ }
+ _Modifiers = cmods & 0xffff0000;
+ }
+}
+
+-(void)ProcessMouse:(NSEvent*)ev
+{
+ switch ([ev type])
+ {
+ case NSLeftMouseDragged:
+ case NSRightMouseDragged:
+ case NSOtherMouseDragged:
+ case NSMouseMoved:
+ {
+ if (_Platform->MMode == OVR::OvrPlatform::Mouse_Relative)
+ {
+ int dx = [ev deltaX];
+ int dy = [ev deltaY];
+
+ if (dx != 0 || dy != 0)
+ {
+ _App->OnMouseMove(dx, dy, Mod_MouseRelative|MapModifiers([ev modifierFlags]));
+ [self warpMouseToCenter];
+ }
+ }
+ else
+ {
+ NSPoint p = [ev locationInWindow];
+ _App->OnMouseMove(p.x, p.y, MapModifiers([ev modifierFlags]));
+ }
+ }
+ break;
+ case NSLeftMouseDown:
+ case NSRightMouseDown:
+ case NSOtherMouseDown:
+ break;
+ }
+}
+
+-(void) mouseMoved:(NSEvent*)ev
+{
+ [self ProcessMouse:ev];
+}
+-(void) mouseDragged:(NSEvent*)ev
+{
+ [self ProcessMouse:ev];
+}
+-(void) mouseDown:(NSEvent*)ev
+{
+ if (_Platform->MMode == Mouse_RelativeEscaped)
+ {
+ [self warpMouseToCenter];
+ CGAssociateMouseAndMouseCursorPosition(false);
+ [NSCursor hide];
+ _Platform->MMode = Mouse_Relative;
+ }
+}
+
+//-(void)
+
+-(id) initWithFrame:(NSRect)frameRect
+{
+ NSOpenGLPixelFormatAttribute attr[] =
+ {
+// NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core,
+// NSOpenGLPFAWindow,
+ NSOpenGLPFADoubleBuffer,
+ NSOpenGLPFADepthSize, 24,
+ nil
+ };
+
+ NSOpenGLPixelFormat *pf = [[[NSOpenGLPixelFormat alloc] initWithAttributes:attr] autorelease];
+
+ self = [super initWithFrame:frameRect pixelFormat:pf];
+ GLint swap = 0;
+ [[self openGLContext] setValues:&swap forParameter:NSOpenGLCPSwapInterval];
+ //[self setWantsBestResolutionOpenGLSurface:YES];
+ return self;
+}
+
+-(void) reshape
+{
+ NSRect bounds = [self bounds];
+ _App->OnResize(bounds.size.width, bounds.size.height);
+
+ _Platform->Width = bounds.size.width;
+ _Platform->Height = bounds.size.height;
+
+ if (_Platform->GetRenderer())
+ _Platform->GetRenderer()->SetWindowSize(bounds.size.width, bounds.size.height);
+}
+
+-(BOOL)windowShouldClose:(id)sender
+{
+ if (_Platform)
+ _Platform->Exit(0);
+ else
+ exit(0);
+ return 1;
+}
+
+@end
+
+namespace OVR { namespace OvrPlatform { namespace OSX {
+
+PlatformCore::PlatformCore(Application* app, void* nsapp)
+ : OvrPlatform::PlatformCore(app), NsApp(nsapp), Win(NULL), View(NULL), Quit(0), MMode(Mouse_Normal)
+{
+ pGamepadManager = *new OSX::GamepadManager();
+}
+PlatformCore::~PlatformCore()
+{
+}
+
+void PlatformCore::Exit(int exitcode)
+{
+ OVRApp* nsApp = (OVRApp*)NsApp;
+ [nsApp stop:nil];
+}
+
+String PlatformCore::GetContentDirectory() const
+{
+ NSBundle* bundle = [NSBundle mainBundle];
+ if (bundle)
+ return String([[bundle bundlePath] UTF8String]) + "/Contents/Resources";
+ else
+ return ".";
+}
+
+
+void PlatformCore::SetMouseMode(MouseMode mm)
+{
+ if (mm == MMode)
+ return;
+
+ if (Win)
+ {
+ if (mm == Mouse_Relative)
+ {
+ [NSCursor hide];
+ [(OVRView*)View warpMouseToCenter];
+ CGAssociateMouseAndMouseCursorPosition(false);
+ }
+ else
+ {
+ if (MMode == Mouse_Relative)
+ {
+ CGAssociateMouseAndMouseCursorPosition(true);
+ [NSCursor unhide];
+ [(OVRView*)View warpMouseToCenter];
+ }
+ }
+ }
+ MMode = mm;
+}
+
+
+void PlatformCore::GetWindowSize(int* w, int* h) const
+{
+ *w = Width;
+ *h = Height;
+}
+
+void* PlatformCore::SetupWindow(int w, int h)
+{
+ NSRect winrect;
+ winrect.origin.x = 0;
+ winrect.origin.y = 1000;
+ winrect.size.width = w;
+ winrect.size.height = h;
+ NSWindow* win = [[NSWindow alloc] initWithContentRect:winrect styleMask:NSTitledWindowMask|NSClosableWindowMask backing:NSBackingStoreBuffered defer:NO];
+
+ OVRView* view = [[OVRView alloc] initWithFrame:winrect];
+ [view setPlatform:this];
+ [win setContentView:view];
+ [win setAcceptsMouseMovedEvents:YES];
+ [win setDelegate:view];
+ [view setApp:pApp];
+ Win = win;
+ View = view;
+ return (void*)[win windowNumber];
+}
+
+void PlatformCore::SetWindowTitle(const char* title)
+{
+ [((NSWindow*)Win) setTitle:[[NSString alloc] initWithBytes:title length:strlen(title) encoding:NSUTF8StringEncoding]];
+}
+
+void PlatformCore::ShowWindow(bool show)
+{
+ if (show)
+ [((NSWindow*)Win) makeKeyAndOrderFront:nil];
+ else
+ [((NSWindow*)Win) orderOut:nil];
+}
+
+void PlatformCore::DestroyWindow()
+{
+ [((NSWindow*)Win) close];
+ Win = NULL;
+}
+
+RenderDevice* PlatformCore::SetupGraphics(const SetupGraphicsDeviceSet& setupGraphicsDesc,
+ const char* type, const Render::RendererParams& rp)
+{
+ const SetupGraphicsDeviceSet* setupDesc = setupGraphicsDesc.PickSetupDevice(type);
+ OVR_ASSERT(setupDesc);
+
+ pRender = *setupDesc->pCreateDevice(rp, this);
+ if (pRender)
+ pRender->SetWindowSize(Width, Height);
+
+ return pRender.GetPtr();
+}
+
+int PlatformCore::GetDisplayCount()
+{
+ return (int)[[NSScreen screens] count];
+}
+
+Render::DisplayId PlatformCore::GetDisplay(int i)
+{
+ NSScreen* s = (NSScreen*)[[NSScreen screens] objectAtIndex:i];
+ return Render::DisplayId([OVRView displayFromScreen:s]);
+}
+
+bool PlatformCore::SetFullscreen(const Render::RendererParams& rp, int fullscreen)
+{
+ if (fullscreen == Render::Display_Window)
+ [(OVRView*)View exitFullScreenModeWithOptions:nil];
+ else
+ {
+ NSScreen* usescreen = [NSScreen mainScreen];
+ NSArray* screens = [NSScreen screens];
+ for (int i = 0; i < [screens count]; i++)
+ {
+ NSScreen* s = (NSScreen*)[screens objectAtIndex:i];
+ CGDirectDisplayID disp = [OVRView displayFromScreen:s];
+
+ if (disp == rp.Display.CgDisplayId)
+ usescreen = s;
+ }
+
+ [(OVRView*)View enterFullScreenMode:usescreen withOptions:nil];
+ [(NSWindow*)Win setInitialFirstResponder:(OVRView*)View];
+ [(NSWindow*)Win makeFirstResponder:(OVRView*)View];
+ }
+
+ if (pRender)
+ pRender->SetFullscreen((Render::DisplayMode)fullscreen);
+ return 1;
+}
+
+}}
+// GL
+namespace Render { namespace GL { namespace OSX {
+
+ovrRenderAPIConfig RenderDevice::Get_ovrRenderAPIConfig() const
+{
+ ovrRenderAPIConfig result = ovrRenderAPIConfig();
+ result.Header.API = ovrRenderAPI_OpenGL;
+ result.Header.RTSize = Sizei(WindowWidth, WindowHeight);
+ result.Header.Multisample = Params.Multisample;
+ return result;
+}
+
+Render::RenderDevice* RenderDevice::CreateDevice(const RendererParams& rp, void* oswnd)
+{
+ OvrPlatform::OSX::PlatformCore* PC = (OvrPlatform::OSX::PlatformCore*)oswnd;
+
+ OVRView* view = (OVRView*)PC->View;
+ NSOpenGLContext *context = [view openGLContext];
+ if (!context)
+ return NULL;
+
+ [context makeCurrentContext];
+ [((NSWindow*)PC->Win) makeKeyAndOrderFront:nil];
+
+ return new Render::GL::OSX::RenderDevice(rp, context);
+}
+
+void RenderDevice::Present(bool useVsync)
+{
+ NSOpenGLContext *context = (NSOpenGLContext*)Context;
+ [context flushBuffer];
+}
+
+void RenderDevice::Shutdown()
+{
+ Context = NULL;
+}
+
+bool RenderDevice::SetFullscreen(DisplayMode fullscreen)
+{
+ Params.Fullscreen = fullscreen;
+ return 1;
+}
+
+}}}}
+
+
+int main(int argc, char *argv[])
+{
+ NSApplication* nsapp = [OVRApp sharedApplication];
+ [nsapp run];
+ return 0;
+}
+
diff --git a/Samples/CommonSrc/Platform/OSX_PlatformObjc.h b/Samples/CommonSrc/Platform/OSX_PlatformObjc.h
new file mode 100644
index 0000000..967b5d9
--- /dev/null
+++ b/Samples/CommonSrc/Platform/OSX_PlatformObjc.h
@@ -0,0 +1,53 @@
+/***********************************************************************
+
+Filename : OSX_PlatformObjc.h
+Content :
+Created :
+Authors :
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+************************************************************************/
+
+#import <Cocoa/Cocoa.h>
+#import "OSX_Platform.h"
+#import "OSX_Gamepad.h"
+
+#import <CoreGraphics/CoreGraphics.h>
+#import <CoreGraphics/CGDirectDisplay.h>
+
+@interface OVRApp : NSApplication
+
+@property (assign) IBOutlet NSWindow* win;
+@property (assign) OVR::OvrPlatform::OSX::PlatformCore* Platform;
+@property (assign) OVR::OvrPlatform::Application* App;
+
+-(void) run;
+
+@end
+
+@interface OVRView : NSOpenGLView <NSWindowDelegate>
+
+@property (assign) OVR::OvrPlatform::OSX::PlatformCore* Platform;
+@property (assign) OVR::OvrPlatform::Application* App;
+@property unsigned long Modifiers;
+
+-(void)ProcessMouse:(NSEvent*)event;
+-(void)warpMouseToCenter;
+
++(CGDirectDisplayID) displayFromScreen:(NSScreen*)s;
+
+@end
+
diff --git a/Samples/CommonSrc/Platform/OSX_WavPlayer.cpp b/Samples/CommonSrc/Platform/OSX_WavPlayer.cpp
new file mode 100644
index 0000000..8b4c744
--- /dev/null
+++ b/Samples/CommonSrc/Platform/OSX_WavPlayer.cpp
@@ -0,0 +1,250 @@
+/************************************************************************************
+
+Filename : WavPlayer_OSX.cpp
+Content : An Apple OSX audio handler.
+Created : March 5, 2013
+Authors : Robotic Arm Software - Peter Hoff, Dan Goodman, Bryan Croteau
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+************************************************************************************/
+
+#include "OSX_WavPlayer.h"
+
+namespace OVR { namespace OvrPlatform { namespace OSX {
+
+WavPlayer::WavPlayer(const char* fileName)
+{
+ FileName = fileName;
+}
+
+bool WavPlayer::isDataChunk(unsigned char* buffer, int index)
+{
+ unsigned char a = buffer[index];
+ unsigned char b = buffer[index + 1];
+ unsigned char c = buffer[index + 2];
+ unsigned char d = buffer[index + 3];
+ return (a == 'D' || a == 'd') && (b == 'A' || b == 'a') &&
+ (c == 'T' || c == 't') && (d == 'A' || d == 'a');
+}
+
+int WavPlayer::getWord(unsigned char* buffer, int index)
+{
+ unsigned char a = buffer[index];
+ unsigned char b = buffer[index + 1];
+ unsigned char c = buffer[index + 2];
+ unsigned char d = buffer[index + 3];
+ int result = 0;
+ result |= a;
+ result |= b << 8;
+ result |= c << 16;
+ result |= d << 24;
+ return result;
+}
+
+short WavPlayer::getHalf(unsigned char* buffer, int index)
+{
+ unsigned char a = buffer[index];
+ unsigned char b = buffer[index + 1];
+ short result = 0;
+ result |= a;
+ result |= b << 8;
+ return result;
+}
+
+void *WavPlayer::LoadPCM(const char *filename, unsigned long *len)
+{
+ FILE *file;
+ struct stat s;
+ void *pcm;
+
+ if(stat(filename, &s))
+ {
+ return NULL;
+ }
+ *len = s.st_size;
+ pcm = (void *) malloc(s.st_size);
+ if(!pcm)
+ {
+ return NULL;
+ }
+ file = fopen(filename, "rb");
+ if(!file)
+ {
+ free(pcm);
+ return NULL;
+ }
+ fread(pcm, s.st_size, 1, file);
+ fclose(file);
+ return pcm;
+}
+
+int WavPlayer::PlayBuffer(void *pcmbuffer, unsigned long len)
+{
+ AQCallbackStruct aqc;
+ UInt32 err, bufferSize;
+ int i;
+
+ aqc.DataFormat.mSampleRate = SampleRate;
+ aqc.DataFormat.mFormatID = kAudioFormatLinearPCM;
+ if(BitsPerSample == 16)
+ {
+ aqc.DataFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger
+ | kAudioFormatFlagIsPacked;
+ }
+ aqc.DataFormat.mBytesPerPacket = NumChannels * (BitsPerSample / 8);
+ aqc.DataFormat.mFramesPerPacket = 1;
+ aqc.DataFormat.mBytesPerFrame = NumChannels * (BitsPerSample / 8);
+ aqc.DataFormat.mChannelsPerFrame = NumChannels;
+ aqc.DataFormat.mBitsPerChannel = BitsPerSample;
+ aqc.FrameCount = SampleRate / 60;
+ aqc.SampleLen = (UInt32)(len);
+ aqc.PlayPtr = 0;
+ aqc.PCMBuffer = static_cast<unsigned char*>(pcmbuffer);
+
+ err = AudioQueueNewOutput(&aqc.DataFormat,
+ aqBufferCallback,
+ &aqc,
+ NULL,
+ kCFRunLoopCommonModes,
+ 0,
+ &aqc.Queue);
+ if(err)
+ {
+ return err;
+ }
+
+ aqc.FrameCount = SampleRate / 60;
+ bufferSize = aqc.FrameCount * aqc.DataFormat.mBytesPerPacket;
+
+ for(i = 0; i < AUDIO_BUFFERS; i++)
+ {
+ err = AudioQueueAllocateBuffer(aqc.Queue, bufferSize,
+ &aqc.Buffers[i]);
+ if(err)
+ {
+ return err;
+ }
+ aqBufferCallback(&aqc, aqc.Queue, aqc.Buffers[i]);
+ }
+
+ err = AudioQueueStart(aqc.Queue, NULL);
+ if(err)
+ {
+ return err;
+ }
+
+ while(true)
+ {
+ }
+ sleep(1);
+ return 0;
+}
+
+void WavPlayer::aqBufferCallback(void *in, AudioQueueRef inQ, AudioQueueBufferRef outQB)
+{
+ AQCallbackStruct *aqc;
+ unsigned char *coreAudioBuffer;
+
+ aqc = (AQCallbackStruct *) in;
+ coreAudioBuffer = (unsigned char*) outQB->mAudioData;
+
+ printf("Sync: %u / %u\n", aqc->PlayPtr, aqc->SampleLen);
+
+ if(aqc->FrameCount > 0)
+ {
+ outQB->mAudioDataByteSize = aqc->DataFormat.mBytesPerFrame * aqc->FrameCount;
+ for(int i = 0; i < aqc->FrameCount * aqc->DataFormat.mBytesPerFrame; i++)
+ {
+ if(aqc->PlayPtr > aqc->SampleLen)
+ {
+ aqc->PlayPtr = 0;
+ i = 0;
+ }
+ coreAudioBuffer[i] = aqc->PCMBuffer[aqc->PlayPtr];
+ aqc->PlayPtr++;
+ }
+ AudioQueueEnqueueBuffer(inQ, outQB, 0, NULL);
+ }
+}
+
+int WavPlayer::PlayAudio()
+{
+ unsigned long len;
+ void *pcmbuffer;
+ int ret;
+
+ pcmbuffer = LoadPCM(FileName, &len);
+ if(!pcmbuffer)
+ {
+ fprintf(stderr, "%s: %s\n", FileName, strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ unsigned char* bytes = (unsigned char*)pcmbuffer;
+ int index = 0;
+
+ // 'RIFF'
+ getWord(bytes, index);
+ index += 4;
+ // int Length
+ getWord(bytes, index);
+ index += 4;
+ // 'WAVE'
+ getWord(bytes, index);
+ index += 4;
+ // 'fmt '
+ getWord(bytes, index);
+ index += 4;
+
+ // int Format Length
+ int fmtLen = getWord(bytes, index);
+ index += 4;
+ AudioFormat = getHalf(bytes, index);
+ index += 2;
+ NumChannels = getHalf(bytes, index);
+ index += 2;
+ SampleRate = getWord(bytes, index);
+ index += 4;
+ ByteRate = getWord(bytes, index);
+ index += 4;
+ BlockAlign = getHalf(bytes, index);
+ index += 2;
+ BitsPerSample = getHalf(bytes, index);
+ index += 2;
+ index += fmtLen - 16;
+ while(!isDataChunk(bytes, index))
+ {
+ // Any Chunk
+ getWord(bytes, index);
+ index += 4;
+ // Any Chunk Length
+ int anyChunkLen = getWord(bytes, index);
+ index += 4 + anyChunkLen;
+ }
+ // 'data'
+ getWord(bytes, index);
+ index += 4;
+ // int Data Length
+ unsigned long dataLen = getWord(bytes, index);
+ index += 4;
+ unsigned char* target = &bytes[index];
+
+ ret = PlayBuffer((void *)target, dataLen);
+ free(pcmbuffer);
+ return ret;
+}
+
+}}}
diff --git a/Samples/CommonSrc/Platform/OSX_WavPlayer.h b/Samples/CommonSrc/Platform/OSX_WavPlayer.h
new file mode 100644
index 0000000..c6f2571
--- /dev/null
+++ b/Samples/CommonSrc/Platform/OSX_WavPlayer.h
@@ -0,0 +1,72 @@
+/************************************************************************************
+
+Filename : WavPlayer_OSX.h
+Content : An Apple OSX audio handler.
+Created : March 5, 2013
+Authors : Robotic Arm Software - Peter Hoff, Dan Goodman, Bryan Croteau
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+************************************************************************************/
+
+#ifndef OVR_WavPlayer_h
+#define OVR_WavPlayer_h
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <AudioToolbox/AudioQueue.h>
+
+#define AUDIO_BUFFERS 4
+
+namespace OVR { namespace OvrPlatform { namespace OSX {
+
+typedef struct AQCallbackStruct
+{
+ AudioQueueRef Queue;
+ UInt32 FrameCount;
+ AudioQueueBufferRef Buffers[AUDIO_BUFFERS];
+ AudioStreamBasicDescription DataFormat;
+ UInt32 PlayPtr;
+ UInt32 SampleLen;
+ unsigned char* PCMBuffer;
+} AQCallbackStruct;
+
+class WavPlayer
+{
+public:
+ WavPlayer(const char* fileName);
+ int PlayAudio();
+private:
+ bool isDataChunk(unsigned char* buffer, int index);
+ int getWord(unsigned char* buffer, int index);
+ short getHalf(unsigned char* buffer, int index);
+ void *LoadPCM(const char *filename, unsigned long *len);
+ int PlayBuffer(void *pcm, unsigned long len);
+ static void aqBufferCallback(void *in, AudioQueueRef inQ, AudioQueueBufferRef outQB);
+
+ short AudioFormat;
+ short NumChannels;
+ int SampleRate;
+ int ByteRate;
+ short BlockAlign;
+ short BitsPerSample;
+ const char* FileName;
+};
+
+}}}
+
+#endif