diff --git a/README.md b/README.md index a042759b66..44b623dde3 100644 --- a/README.md +++ b/README.md @@ -413,7 +413,10 @@ For additional Windows samples, see [Windows on GitHub](http://microsoft.github. + + +
Holographic face trackingHolographic mixed reality capture Holographic spatial mapping
Tag-along hologram
diff --git a/Samples/AdaptiveStreaming/cs/Scenario2_EventHandlers.xaml.cs b/Samples/AdaptiveStreaming/cs/Scenario2_EventHandlers.xaml.cs index 6d5fecc4fb..fd33a1009d 100644 --- a/Samples/AdaptiveStreaming/cs/Scenario2_EventHandlers.xaml.cs +++ b/Samples/AdaptiveStreaming/cs/Scenario2_EventHandlers.xaml.cs @@ -341,7 +341,7 @@ private void Source_OpenOperationCompleted(MediaSource sender, MediaSourceOpenOp // This extension method in MediaPlaybackItemStringExtensions dumps all the properties from all the tracks. var allProperties = item.ToFormattedString(); - Log(allProperties); + Log($"MediaPlaybackItem nested properties: {allProperties}"); // The AdaptiveMediaSource can manage multiple video tracks internally, // but only a single video track is exposed in the MediaPlaybackItem, not a collection. } @@ -354,6 +354,7 @@ private void RegisterForMediaPlaybackItemEvents(MediaPlaybackItem item) { item.AudioTracks.SelectedIndexChanged += AudioTracks_SelectedIndexChanged; item.AudioTracksChanged += Item_AudioTracksChanged; + item.VideoTracksChanged += Item_VideoTracksChanged; item.TimedMetadataTracksChanged += Item_TimedMetadataTracksChanged; } @@ -365,11 +366,16 @@ private void UnregisterForMediaPlaybackItemEvents(MediaPlaybackItem item) } item.AudioTracks.SelectedIndexChanged -= AudioTracks_SelectedIndexChanged; item.AudioTracksChanged -= Item_AudioTracksChanged; + item.VideoTracksChanged -= Item_VideoTracksChanged; item.TimedMetadataTracksChanged -= Item_TimedMetadataTracksChanged; foreach (AudioTrack audioTrack in item.AudioTracks) { audioTrack.OpenFailed -= AudioTrack_OpenFailed; } + foreach (VideoTrack videoTrack in item.VideoTracks) + { + videoTrack.OpenFailed -= VideoTrack_OpenFailed; + } } private void AudioTracks_SelectedIndexChanged(ISingleSelectMediaTrackList sender, object args) @@ -412,6 +418,25 @@ private void Item_AudioTracksChanged(MediaPlaybackItem sender, IVectorChangedEve } } + private void Item_VideoTracksChanged(MediaPlaybackItem sender, IVectorChangedEventArgs args) + { + Log($"item.VideoTracksChanged: CollectionChange:{args.CollectionChange} Index:{args.Index} Total:{sender.VideoTracks.Count}"); + + switch (args.CollectionChange) + { + case CollectionChange.Reset: + foreach (VideoTrack track in sender.VideoTracks) + { + track.OpenFailed += VideoTrack_OpenFailed; + } + break; + case CollectionChange.ItemInserted: + VideoTrack newTrack = sender.VideoTracks[(int)args.Index]; + newTrack.OpenFailed += VideoTrack_OpenFailed; + break; + } + } + private void Item_TimedMetadataTracksChanged(MediaPlaybackItem sender, IVectorChangedEventArgs args) { Log($"item.TimedMetadataTracksChanged: CollectionChange:{args.CollectionChange} Index:{args.Index} Total:{sender.TimedMetadataTracks.Count}"); @@ -425,6 +450,12 @@ private void AudioTrack_OpenFailed(AudioTrack sender, AudioTrackOpenFailedEventA Log($"AudioTrack.OpenFailed: ExtendedError:{args.ExtendedError} DecoderStatus:{sender.SupportInfo.DecoderStatus} MediaSourceStatus:{sender.SupportInfo.MediaSourceStatus}"); } + private void VideoTrack_OpenFailed(VideoTrack sender, VideoTrackOpenFailedEventArgs args) + { + Log($"VideoTrack.OpenFailed: ExtendedError:{args.ExtendedError} DecoderStatus:{sender.SupportInfo.DecoderStatus} MediaSourceStatus:{sender.SupportInfo.MediaSourceStatus}"); + } + + #endregion #region AdaptiveMediaSource Event Handlers diff --git a/Samples/AllJoyn/shared/AllJoynHelpers.h b/Samples/AllJoyn/Common/Scenario1WinRTComponent/AllJoynHelpers.h similarity index 87% rename from Samples/AllJoyn/shared/AllJoynHelpers.h rename to Samples/AllJoyn/Common/Scenario1WinRTComponent/AllJoynHelpers.h index 170e22504b..360af60c5d 100644 --- a/Samples/AllJoyn/shared/AllJoynHelpers.h +++ b/Samples/AllJoyn/Common/Scenario1WinRTComponent/AllJoynHelpers.h @@ -9,24 +9,13 @@ // //********************************************************* //----------------------------------------------------------------------------- -// -// This code was generated by a tool. -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -// Tool: AllJoynCodeGenerator.exe -// -// This tool is located in the Windows 10 SDK and the Windows 10 AllJoyn -// Visual Studio Extension in the Visual Studio Gallery. +// +// This code was generated by a tool. // -// The generated code should be packaged in a Windows 10 C++/CX Runtime -// Component which can be consumed in any UWP-supported language using -// APIs that are available in Windows.Devices.AllJoyn. +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. // -// Using AllJoynCodeGenerator - Invoke the following command with a valid -// Introspection XML file and a writable output directory: -// AllJoynCodeGenerator -i -o +// For more information, see: http://go.microsoft.com/fwlink/?LinkID=623246 // //----------------------------------------------------------------------------- #pragma once @@ -46,6 +35,23 @@ if (Windows::Devices::AllJoyn::AllJoynStatus::Ok != alljoynStatus) \ } \ } +namespace com { namespace microsoft { namespace Samples { namespace SecureInterface { + +public interface class ISignalEmitter +{ + property Windows::Devices::AllJoyn::AllJoynBusObject^ BusObject + { + Windows::Devices::AllJoyn::AllJoynBusObject^ get(); + } + + property Windows::Devices::AllJoyn::AllJoynSession^ Session + { + Windows::Devices::AllJoyn::AllJoynSession^ get(); + } +}; + +} } } } + class AllJoynHelpers { public: @@ -53,6 +59,10 @@ class AllJoynHelpers // function gets the underlying alljoyn_busattachment. static alljoyn_busattachment GetInternalBusAttachment(_In_ Windows::Devices::AllJoyn::AllJoynBusAttachment^ busAttachment); + // The Windows::Devices::AllJoyn::AllJoynBusObject class wraps the alljoyn_busobject type. This + // function gets the underlying alljoyn_busobject. + static alljoyn_busobject AllJoynHelpers::GetInternalBusObject(_In_ Windows::Devices::AllJoyn::AllJoynBusObject^ busObject); + // Create the alljoyn_interfacedescriptions described in introspectionXml and add them to the busAttachment. static QStatus CreateInterfaces(_Inout_ Windows::Devices::AllJoyn::AllJoynBusAttachment^ busAttachment, _In_ PCSTR introspectionXml); @@ -69,21 +79,6 @@ class AllJoynHelpers // Determine whether the supplied set of AuthenticationMechanisms is sufficient for securing an AllJoyn connection. static bool CanSecure(_In_ Windows::Foundation::Collections::IVector^ authenticationMechanisms); - // Callback for alljoyn_about_announced_ptr. - // This callback expects the context to be of type T, which must implement the OnAnnounce function. - template - static void AJ_CALL AnnounceHandler( - _In_ const void* context, - _In_ PCSTR name, - _In_ uint16_t version, - _In_ alljoyn_sessionport port, - _In_ alljoyn_msgarg objectDescriptionArg, - _In_ const alljoyn_msgarg aboutDataArg) - { - T^ caller = static_cast(context)->Resolve(); - caller->OnAnnounce(name, version, port, objectDescriptionArg, aboutDataArg); - } - // Callback for alljoyn_proxybusobject_listener_propertieschanged_ptr. // This callback expects the context to be of type T, which must implement the OnPropertyChanged function. template diff --git a/Samples/AllJoyn/Common/Scenario1WinRTComponent/ISecureInterfaceService.h b/Samples/AllJoyn/Common/Scenario1WinRTComponent/ISecureInterfaceService.h index b0a805a5eb..14b2c214bb 100644 --- a/Samples/AllJoyn/Common/Scenario1WinRTComponent/ISecureInterfaceService.h +++ b/Samples/AllJoyn/Common/Scenario1WinRTComponent/ISecureInterfaceService.h @@ -25,14 +25,17 @@ namespace com { namespace microsoft { namespace Samples { namespace SecureInterf public interface class ISecureInterfaceService { public: + // "Concatenate two input strings and returns the concatenated string as output" // Implement this function to handle calls to the Concatenate method. Windows::Foundation::IAsyncOperation^ ConcatenateAsync(_In_ Windows::Devices::AllJoyn::AllJoynMessageInfo^ info , _In_ Platform::String^ interfaceMemberInStr1, _In_ Platform::String^ interfaceMemberInStr2); + // "Determine if the output of the Concatenate method is returned as upper case string or not" // Implement this function to handle requests for the value of the IsUpperCaseEnabled property. // // Currently, info will always be null, because no information is available about the requestor. Windows::Foundation::IAsyncOperation^ GetIsUpperCaseEnabledAsync(Windows::Devices::AllJoyn::AllJoynMessageInfo^ info); + // "Determine if the output of the Concatenate method is returned as upper case string or not" // Implement this function to handle requests to set the IsUpperCaseEnabled property. // // Currently, info will always be null, because no information is available about the requestor. diff --git a/Samples/AllJoyn/Common/Scenario1WinRTComponent/Scenario1WinRTComponent.vcxproj b/Samples/AllJoyn/Common/Scenario1WinRTComponent/Scenario1WinRTComponent.vcxproj index f956dd8e4a..b418745e04 100644 --- a/Samples/AllJoyn/Common/Scenario1WinRTComponent/Scenario1WinRTComponent.vcxproj +++ b/Samples/AllJoyn/Common/Scenario1WinRTComponent/Scenario1WinRTComponent.vcxproj @@ -221,18 +221,18 @@ - + + - @@ -247,11 +247,11 @@ Create + - diff --git a/Samples/AllJoyn/Common/Scenario1WinRTComponent/Scenario1WinRTComponent.vcxproj.filters b/Samples/AllJoyn/Common/Scenario1WinRTComponent/Scenario1WinRTComponent.vcxproj.filters index 3288c2691e..c0e053639e 100644 --- a/Samples/AllJoyn/Common/Scenario1WinRTComponent/Scenario1WinRTComponent.vcxproj.filters +++ b/Samples/AllJoyn/Common/Scenario1WinRTComponent/Scenario1WinRTComponent.vcxproj.filters @@ -11,27 +11,27 @@ + - - + + - \ No newline at end of file diff --git a/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceConsumer.cpp b/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceConsumer.cpp index 60c5a14347..f65069e25c 100644 --- a/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceConsumer.cpp +++ b/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceConsumer.cpp @@ -28,59 +28,38 @@ using namespace Windows::Devices::AllJoyn; using namespace com::microsoft::Samples::SecureInterface; std::map SecureInterfaceConsumer::SourceInterfaces; +PCSTR SecureInterfaceConsumer::m_interfaceName = "com.microsoft.Samples.SecureInterface"; SecureInterfaceConsumer::SecureInterfaceConsumer(AllJoynBusAttachment^ busAttachment) : m_busAttachment(busAttachment), m_proxyBusObject(nullptr), - m_busObject(nullptr), - m_sessionListener(nullptr), - m_sessionId(0) + m_busObject(nullptr) { m_weak = new WeakReference(this); m_signals = ref new SecureInterfaceSignals(); m_nativeBusAttachment = AllJoynHelpers::GetInternalBusAttachment(m_busAttachment); -} -SecureInterfaceConsumer::~SecureInterfaceConsumer() -{ - AllJoynBusObjectManager::ReleaseBusObject(m_nativeBusAttachment, AllJoynHelpers::PlatformToMultibyteString(ServiceObjectPath).data()); - if (SessionListener != nullptr) - { - alljoyn_busattachment_setsessionlistener(m_nativeBusAttachment, m_sessionId, nullptr); - alljoyn_sessionlistener_destroy(SessionListener); - } - if (nullptr != ProxyBusObject) - { - alljoyn_proxybusobject_destroy(ProxyBusObject); - } - delete m_weak; -} + GUID result; + HRESULT hr = CoCreateGuid(&result); -void SecureInterfaceConsumer::OnSessionLost(_In_ alljoyn_sessionid sessionId, _In_ alljoyn_sessionlostreason reason) -{ - if (sessionId == m_sessionId) + if (FAILED(hr)) { - AllJoynSessionLostEventArgs^ args = ref new AllJoynSessionLostEventArgs(static_cast(reason)); - SessionLost(this, args); + throw ref new Exception(hr); } -} -void SecureInterfaceConsumer::OnSessionMemberAdded(_In_ alljoyn_sessionid sessionId, _In_ PCSTR uniqueName) -{ - if (sessionId == m_sessionId) - { - auto args = ref new AllJoynSessionMemberAddedEventArgs(AllJoynHelpers::MultibyteToPlatformString(uniqueName)); - SessionMemberAdded(this, args); - } + // The consumer needs a bus object to share signals, and its object path must be unique in + // case multiple consumers are created using the same bus attachment. + Guid gd(result); + ServiceObjectPath = gd.ToString(); } -void SecureInterfaceConsumer::OnSessionMemberRemoved(_In_ alljoyn_sessionid sessionId, _In_ PCSTR uniqueName) +SecureInterfaceConsumer::~SecureInterfaceConsumer() { - if (sessionId == m_sessionId) + if (nullptr != ProxyBusObject) { - auto args = ref new AllJoynSessionMemberRemovedEventArgs(AllJoynHelpers::MultibyteToPlatformString(uniqueName)); - SessionMemberRemoved(this, args); + alljoyn_proxybusobject_destroy(ProxyBusObject); } + delete m_weak; } QStatus SecureInterfaceConsumer::AddSignalHandler(_In_ alljoyn_busattachment busAttachment, _In_ alljoyn_interfacedescription interfaceDescription, _In_ PCSTR methodName, _In_ alljoyn_messagereceiver_signalhandler_ptr handler) @@ -94,14 +73,53 @@ QStatus SecureInterfaceConsumer::AddSignalHandler(_In_ alljoyn_busattachment bus return alljoyn_busattachment_registersignalhandler(busAttachment, handler, member, NULL); } -IAsyncOperation^ SecureInterfaceConsumer::JoinSessionAsync( - _In_ AllJoynServiceInfo^ serviceInfo, _Inout_ SecureInterfaceWatcher^ watcher) +IAsyncOperation^ SecureInterfaceConsumer::FromIdAsync(_In_ Platform::String^ deviceId) { - return create_async([serviceInfo, watcher]() -> SecureInterfaceJoinSessionResult^ + return SecureInterfaceConsumer::FromIdAsync(deviceId, AllJoynBusAttachment::GetDefault()); +} + +IAsyncOperation^ SecureInterfaceConsumer::FromIdAsync(_In_ Platform::String^ deviceId, _In_ AllJoynBusAttachment^ busAttachment) +{ + return create_async([deviceId, busAttachment]() -> SecureInterfaceConsumer^ { - auto result = ref new SecureInterfaceJoinSessionResult(); - result->Consumer = ref new SecureInterfaceConsumer(watcher->BusAttachment); - result->Status = result->Consumer->JoinSession(serviceInfo); + SecureInterfaceConsumer^ result; + create_task(AllJoynServiceInfo::FromIdAsync(deviceId)).then([busAttachment, &result](AllJoynServiceInfo^ serviceInfo) + { + if (serviceInfo != nullptr) + { + int32 status = AllJoynStatus::Ok; + if (busAttachment->State == AllJoynBusAttachmentState::Disconnected) + { + event connectedEvent; + auto token = busAttachment->StateChanged += ref new TypedEventHandler([&connectedEvent](AllJoynBusAttachment^, AllJoynBusAttachmentStateChangedEventArgs^ arg) + { + if (arg->State == AllJoynBusAttachmentState::Connected) + { + connectedEvent.set(); + } + }); + + status = AllJoynHelpers::CreateInterfaces(busAttachment, c_SecureInterfaceIntrospectionXml); + if (status == AllJoynStatus::Ok) + { + busAttachment->Connect(); + connectedEvent.wait(); + } + busAttachment->StateChanged -= token; + } + + if (status == AllJoynStatus::Ok) + { + auto consumer = ref new SecureInterfaceConsumer(busAttachment); + status = consumer->Initialize(serviceInfo); + if (status == AllJoynStatus::Ok) + { + result = consumer; + } + } + } + }).wait(); + return result; }); } @@ -111,24 +129,22 @@ IAsyncOperation^ SecureInterfaceConsumer::Con return create_async([this, interfaceMemberInStr1, interfaceMemberInStr2]() -> SecureInterfaceConcatenateResult^ { auto result = ref new SecureInterfaceConcatenateResult(); - + alljoyn_message message = alljoyn_message_create(m_nativeBusAttachment); size_t argCount = 2; alljoyn_msgarg inputs = alljoyn_msgarg_array_create(argCount); QStatus status = ER_OK; + status = static_cast(TypeConversionHelpers::SetAllJoynMessageArg(alljoyn_msgarg_array_element(inputs, 0), "s", interfaceMemberInStr1)); if (ER_OK == status) { - status = static_cast(TypeConversionHelpers::SetAllJoynMessageArg(alljoyn_msgarg_array_element(inputs, 0), "s", interfaceMemberInStr1)); + status = static_cast(TypeConversionHelpers::SetAllJoynMessageArg(alljoyn_msgarg_array_element(inputs, 1), "s", interfaceMemberInStr2)); } - - status = static_cast(TypeConversionHelpers::SetAllJoynMessageArg(alljoyn_msgarg_array_element(inputs, 1), "s", interfaceMemberInStr2)); - if (ER_OK == status) { status = alljoyn_proxybusobject_methodcall( ProxyBusObject, - "com.microsoft.Samples.SecureInterface", + m_interfaceName, "Concatenate", inputs, argCount, @@ -137,7 +153,7 @@ IAsyncOperation^ SecureInterfaceConsumer::Con 0); } result->Status = static_cast(status); - if (ER_OK == status) + if (ER_OK == status) { result->Status = AllJoynStatus::Ok; Platform::String^ argument0; @@ -163,7 +179,7 @@ IAsyncOperation^ SecureInterfaceConsumer::Con } result->Status = static_cast(status); } - + alljoyn_message_destroy(message); alljoyn_msgarg_destroy(inputs); @@ -183,7 +199,7 @@ IAsyncOperation^ SecureInterfaceCon { status = alljoyn_proxybusobject_setpropertyasync( ProxyBusObject, - "com.microsoft.Samples.SecureInterface", + m_interfaceName, "IsUpperCaseEnabled", inputArgument, [](QStatus status, alljoyn_proxybusobject obj, void* context) @@ -213,10 +229,10 @@ IAsyncOperation^ SecureInterfaceCon return create_async([this]() -> SecureInterfaceGetIsUpperCaseEnabledResult^ { PropertyGetContext getContext; - + alljoyn_proxybusobject_getpropertyasync( ProxyBusObject, - "com.microsoft.Samples.SecureInterface", + m_interfaceName, "IsUpperCaseEnabled", [](QStatus status, alljoyn_proxybusobject obj, const alljoyn_msgarg value, void* context) { @@ -301,39 +317,31 @@ void SecureInterfaceConsumer::CallTextSentSignalHandler(_In_ const alljoyn_inter } } -int32 SecureInterfaceConsumer::JoinSession(_In_ AllJoynServiceInfo^ serviceInfo) +int32 SecureInterfaceConsumer::Initialize(_In_ AllJoynServiceInfo^ serviceInfo) { - alljoyn_sessionlistener_callbacks callbacks = - { - AllJoynHelpers::SessionLostHandler, - AllJoynHelpers::SessionMemberAddedHandler, - AllJoynHelpers::SessionMemberRemovedHandler - }; - - alljoyn_busattachment_enableconcurrentcallbacks(AllJoynHelpers::GetInternalBusAttachment(m_busAttachment)); - - SessionListener = alljoyn_sessionlistener_create(&callbacks, m_weak); - alljoyn_sessionopts sessionOpts = alljoyn_sessionopts_create(ALLJOYN_TRAFFIC_TYPE_MESSAGES, true, ALLJOYN_PROXIMITY_ANY, ALLJOYN_TRANSPORT_ANY); - std::vector sessionNameUtf8 = AllJoynHelpers::PlatformToMultibyteString(serviceInfo->UniqueName); - RETURN_IF_QSTATUS_ERROR(alljoyn_busattachment_joinsession( - m_nativeBusAttachment, - &sessionNameUtf8[0], - serviceInfo->SessionPort, - SessionListener, - &m_sessionId, - sessionOpts)); - alljoyn_sessionopts_destroy(sessionOpts); ServiceObjectPath = serviceInfo->ObjectPath; std::vector objectPath = AllJoynHelpers::PlatformToMultibyteString(ServiceObjectPath); + RETURN_IF_QSTATUS_ERROR(AllJoynHelpers::CreateInterfaces(m_busAttachment, c_SecureInterfaceIntrospectionXml)); + + m_session = create_task(AllJoynSession::GetFromServiceInfoAsync(serviceInfo, m_busAttachment)).get(); + if (nullptr == m_session) + { + return AllJoynStatus::Fail; + } + else if (m_session->Status != AllJoynStatus::Ok) + { + return m_session->Status; + } + if (objectPath.empty()) { return AllJoynStatus::Fail; } - ProxyBusObject = alljoyn_proxybusobject_create(m_nativeBusAttachment, &sessionNameUtf8[0], &objectPath[0], m_sessionId); + ProxyBusObject = alljoyn_proxybusobject_create(m_nativeBusAttachment, &sessionNameUtf8[0], &objectPath[0], m_session->Id); if (nullptr == ProxyBusObject) { return AllJoynStatus::Fail; @@ -343,31 +351,35 @@ int32 SecureInterfaceConsumer::JoinSession(_In_ AllJoynServiceInfo^ serviceInfo) RETURN_IF_QSTATUS_ERROR(alljoyn_proxybusobject_registerpropertieschangedlistener( ProxyBusObject, - "com.microsoft.Samples.SecureInterface", + m_interfaceName, propertyNames, _countof(propertyNames), - AllJoynHelpers::PropertyChangedHandler, + AllJoynHelpers::PropertyChangedHandler, m_weak)); - alljoyn_interfacedescription description = alljoyn_busattachment_getinterface(m_nativeBusAttachment, "com.microsoft.Samples.SecureInterface"); + alljoyn_interfacedescription description = alljoyn_busattachment_getinterface(m_nativeBusAttachment, m_interfaceName); if (nullptr == description) { return AllJoynStatus::Fail; } - RETURN_IF_QSTATUS_ERROR(AllJoynBusObjectManager::GetBusObject(m_nativeBusAttachment, AllJoynHelpers::PlatformToMultibyteString(ServiceObjectPath).data(), &m_busObject)); - - if (!AllJoynBusObjectManager::BusObjectIsRegistered(m_nativeBusAttachment, m_busObject)) + m_busObject = ref new Windows::Devices::AllJoyn::AllJoynBusObject(ServiceObjectPath, m_busAttachment); + m_nativeBusObject = AllJoynHelpers::GetInternalBusObject(m_busObject); + + QStatus status = alljoyn_busobject_addinterface(m_nativeBusObject, description); + if ((status != ER_OK) && (status != ER_BUS_IFACE_ALREADY_EXISTS)) { - RETURN_IF_QSTATUS_ERROR(alljoyn_busobject_addinterface(BusObject, description)); + return status; } + QStatus result = AddSignalHandler( m_nativeBusAttachment, description, "TextSent", [](const alljoyn_interfacedescription_member* member, PCSTR srcPath, alljoyn_message message) { UNREFERENCED_PARAMETER(srcPath); CallTextSentSignalHandler(member, message); }); + if (ER_OK != result) { return static_cast(result); @@ -379,7 +391,7 @@ int32 SecureInterfaceConsumer::JoinSession(_In_ AllJoynServiceInfo^ serviceInfo) bool authenticationMechanismsContainsNone = m_busAttachment->AuthenticationMechanisms->IndexOf(AllJoynAuthenticationMechanism::None, &noneMechanismIndex); QCC_BOOL interfaceIsSecure = alljoyn_interfacedescription_issecure(description); - // If the current set of AuthenticationMechanisms supports authentication, + // If the current set of AuthenticationMechanisms supports authentication, // determine whether to secure the connection. if (AllJoynHelpers::CanSecure(m_busAttachment->AuthenticationMechanisms)) { @@ -388,11 +400,11 @@ int32 SecureInterfaceConsumer::JoinSession(_In_ AllJoynServiceInfo^ serviceInfo) if (!authenticationMechanismsContainsNone || interfaceIsSecure) { RETURN_IF_QSTATUS_ERROR(alljoyn_proxybusobject_secureconnection(ProxyBusObject, QCC_FALSE)); - RETURN_IF_QSTATUS_ERROR(AllJoynBusObjectManager::TryRegisterBusObject(m_nativeBusAttachment, BusObject, true)); + m_busObject->Start(); } else { - RETURN_IF_QSTATUS_ERROR(AllJoynBusObjectManager::TryRegisterBusObject(m_nativeBusAttachment, BusObject, false)); + m_busObject->Start(); } } else @@ -405,13 +417,13 @@ int32 SecureInterfaceConsumer::JoinSession(_In_ AllJoynServiceInfo^ serviceInfo) } else { - RETURN_IF_QSTATUS_ERROR(AllJoynBusObjectManager::TryRegisterBusObject(m_nativeBusAttachment, BusObject, false)); + m_busObject->Start(); } } RETURN_IF_QSTATUS_ERROR(alljoyn_proxybusobject_addinterface(ProxyBusObject, description)); - - m_signals->Initialize(BusObject, m_sessionId); + + m_signals->Initialize(this); return AllJoynStatus::Ok; } diff --git a/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceConsumer.h b/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceConsumer.h index a9be5118d7..50cb866700 100644 --- a/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceConsumer.h +++ b/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceConsumer.h @@ -24,24 +24,30 @@ namespace com { namespace microsoft { namespace Samples { namespace SecureInterf public interface class ISecureInterfaceConsumer { - event Windows::Foundation::TypedEventHandler^ SessionLost; - event Windows::Foundation::TypedEventHandler^ SessionMemberAdded; - event Windows::Foundation::TypedEventHandler^ SessionMemberRemoved; event Windows::Foundation::TypedEventHandler^ IsUpperCaseEnabledChanged; }; -public ref class SecureInterfaceConsumer sealed : [Windows::Foundation::Metadata::Default] ISecureInterfaceConsumer +public ref class SecureInterfaceConsumer sealed : [Windows::Foundation::Metadata::Default] ISecureInterfaceConsumer, ISignalEmitter { public: SecureInterfaceConsumer(Windows::Devices::AllJoyn::AllJoynBusAttachment^ busAttachment); virtual ~SecureInterfaceConsumer(); - // Join the AllJoyn session specified by sessionName. + // Create a consumer from a device Id asynchronously. // - // This will usually be called after the unique name of a producer has been reported - // in the Added callback on the Watcher. - static Windows::Foundation::IAsyncOperation^ JoinSessionAsync(_In_ Windows::Devices::AllJoyn::AllJoynServiceInfo^ serviceInfo, _Inout_ SecureInterfaceWatcher^ watcher); + // This is usually called to create a consumer after the unique name of a producer has been reported + // in the Added callback on the DeviceWatcher. + static Windows::Foundation::IAsyncOperation^ FromIdAsync(_In_ Platform::String^ deviceId); + // Create a consumer from a device Id asynchronously with the provided bus attachment. + // + // This is usually called to create a consumer after the unique name of a producer has been reported + // in the Added callback on the DeviceWatcher. + static Windows::Foundation::IAsyncOperation^ FromIdAsync(_In_ Platform::String^ deviceId, _In_ Windows::Devices::AllJoyn::AllJoynBusAttachment^ busAttachment); + + int32 SecureInterfaceConsumer::Initialize(_In_ Windows::Devices::AllJoyn::AllJoynServiceInfo^ serviceInfo); + + // "Concatenate two input strings and returns the concatenated string as output" // Call the Concatenate method Windows::Foundation::IAsyncOperation^ ConcatenateAsync(_In_ Platform::String^ interfaceMemberInStr1, _In_ Platform::String^ interfaceMemberInStr2); @@ -66,10 +72,12 @@ public ref class SecureInterfaceConsumer sealed : [Windows::Foundation::Metadat _IsUpperCaseEnabledChanged(sender, args); } } - + + // "Determine if the output of the Concatenate method is returned as upper case string or not" // Get the value of the IsUpperCaseEnabled property. Windows::Foundation::IAsyncOperation^ GetIsUpperCaseEnabledAsync(); + // "Determine if the output of the Concatenate method is returned as upper case string or not" // Set the value of the IsUpperCaseEnabled property. Windows::Foundation::IAsyncOperation^ SetIsUpperCaseEnabledAsync(_In_ bool value); @@ -79,91 +87,37 @@ public ref class SecureInterfaceConsumer sealed : [Windows::Foundation::Metadat SecureInterfaceSignals^ get() { return m_signals; } } - // This event will fire whenever the consumer loses the session that it is a member of. - virtual event Windows::Foundation::TypedEventHandler^ SessionLost - { - Windows::Foundation::EventRegistrationToken add(Windows::Foundation::TypedEventHandler^ handler) - { - return _SessionLost += ref new Windows::Foundation::EventHandler - ([handler](Platform::Object^ sender, Platform::Object^ args) - { - handler->Invoke(safe_cast(sender), safe_cast(args)); - }, Platform::CallbackContext::Same); - } - void remove(Windows::Foundation::EventRegistrationToken token) - { - _SessionLost -= token; - } - internal: - void raise(SecureInterfaceConsumer^ sender, Windows::Devices::AllJoyn::AllJoynSessionLostEventArgs^ args) - { - _SessionLost(sender, args); - } + // Used to get the name of the interface this consumer implements. + static property Platform::String^ InterfaceName + { + Platform::String^ get() { return AllJoynHelpers::MultibyteToPlatformString(m_interfaceName); } } - // This event will fire whenever a member joins the session. - virtual event Windows::Foundation::TypedEventHandler^ SessionMemberAdded - { - Windows::Foundation::EventRegistrationToken add(Windows::Foundation::TypedEventHandler^ handler) - { - return _SessionMemberAdded += ref new Windows::Foundation::EventHandler - ([handler](Platform::Object^ sender, Platform::Object^ args) - { - handler->Invoke(safe_cast(sender), safe_cast(args)); - }, Platform::CallbackContext::Same); - } - void remove(Windows::Foundation::EventRegistrationToken token) - { - _SessionMemberAdded -= token; - } - internal: - void raise(SecureInterfaceConsumer^ sender, Windows::Devices::AllJoyn::AllJoynSessionMemberAddedEventArgs^ args) - { - _SessionMemberAdded(sender, args); - } + virtual property Windows::Devices::AllJoyn::AllJoynBusObject^ BusObject + { + Windows::Devices::AllJoyn::AllJoynBusObject^ get() { return m_busObject; } } - // This event will fire whenever a member leaves the session. - virtual event Windows::Foundation::TypedEventHandler^ SessionMemberRemoved - { - Windows::Foundation::EventRegistrationToken add(Windows::Foundation::TypedEventHandler^ handler) - { - return _SessionMemberRemoved += ref new Windows::Foundation::EventHandler - ([handler](Platform::Object^ sender, Platform::Object^ args) - { - handler->Invoke(safe_cast(sender), safe_cast(args)); - }, Platform::CallbackContext::Same); - } - void remove(Windows::Foundation::EventRegistrationToken token) - { - _SessionMemberRemoved -= token; - } - internal: - void raise(SecureInterfaceConsumer^ sender, Windows::Devices::AllJoyn::AllJoynSessionMemberRemovedEventArgs^ args) - { - _SessionMemberRemoved(sender, args); - } + virtual property Windows::Devices::AllJoyn::AllJoynSession^ Session + { + Windows::Devices::AllJoyn::AllJoynSession^ get() { return m_session; } } internal: // Consumers do not support property get. - QStatus OnPropertyGet(_In_ PCSTR interfaceName, _In_ PCSTR propertyName, _Inout_ alljoyn_msgarg val) - { - UNREFERENCED_PARAMETER(interfaceName); UNREFERENCED_PARAMETER(propertyName); UNREFERENCED_PARAMETER(val); - return ER_NOT_IMPLEMENTED; + QStatus OnPropertyGet(_In_ PCSTR interfaceName, _In_ PCSTR propertyName, _Inout_ alljoyn_msgarg val) + { + UNREFERENCED_PARAMETER(interfaceName); UNREFERENCED_PARAMETER(propertyName); UNREFERENCED_PARAMETER(val); + return ER_NOT_IMPLEMENTED; } // Consumers do not support property set. - QStatus OnPropertySet(_In_ PCSTR interfaceName, _In_ PCSTR propertyName, _In_ alljoyn_msgarg val) - { + QStatus OnPropertySet(_In_ PCSTR interfaceName, _In_ PCSTR propertyName, _In_ alljoyn_msgarg val) + { UNREFERENCED_PARAMETER(interfaceName); UNREFERENCED_PARAMETER(propertyName); UNREFERENCED_PARAMETER(val); return ER_NOT_IMPLEMENTED; } - void OnSessionLost(_In_ alljoyn_sessionid sessionId, _In_ alljoyn_sessionlostreason reason); - void OnSessionMemberAdded(_In_ alljoyn_sessionid sessionId, _In_ PCSTR uniqueName); - void OnSessionMemberRemoved(_In_ alljoyn_sessionid sessionId, _In_ PCSTR uniqueName); - void OnPropertyChanged(_In_ alljoyn_proxybusobject obj, _In_ PCSTR interfaceName, _In_ const alljoyn_msgarg changed, _In_ const alljoyn_msgarg invalidated); property Platform::String^ ServiceObjectPath @@ -178,44 +132,27 @@ public ref class SecureInterfaceConsumer sealed : [Windows::Foundation::Metadat void set(alljoyn_proxybusobject value) { m_proxyBusObject = value; } } - property alljoyn_busobject BusObject - { - alljoyn_busobject get() { return m_busObject; } - void set(alljoyn_busobject value) { m_busObject = value; } - } - - property alljoyn_sessionlistener SessionListener - { - alljoyn_sessionlistener get() { return m_sessionListener; } - void set(alljoyn_sessionlistener value) { m_sessionListener = value; } - } - - property alljoyn_sessionid SessionId - { - alljoyn_sessionid get() { return m_sessionId; } - } - private: virtual event Windows::Foundation::EventHandler^ _SessionLost; virtual event Windows::Foundation::EventHandler^ _SessionMemberAdded; virtual event Windows::Foundation::EventHandler^ _SessionMemberRemoved; virtual event Windows::Foundation::EventHandler^ _IsUpperCaseEnabledChanged; - int32 JoinSession(_In_ Windows::Devices::AllJoyn::AllJoynServiceInfo^ serviceInfo); - // Register a callback function to handle incoming signals. QStatus AddSignalHandler(_In_ alljoyn_busattachment busAttachment, _In_ alljoyn_interfacedescription interfaceDescription, _In_ PCSTR methodName, _In_ alljoyn_messagereceiver_signalhandler_ptr handler); + // "This signal is emitted when producer sends a text message to consumer" static void CallTextSentSignalHandler(_In_ const alljoyn_interfacedescription_member* member, _In_ alljoyn_message message); - + Windows::Devices::AllJoyn::AllJoynBusAttachment^ m_busAttachment; + Windows::Devices::AllJoyn::AllJoynBusObject^ m_busObject; + Windows::Devices::AllJoyn::AllJoynSession^ m_session; SecureInterfaceSignals^ m_signals; Platform::String^ m_ServiceObjectPath; alljoyn_proxybusobject m_proxyBusObject; - alljoyn_busobject m_busObject; alljoyn_sessionlistener m_sessionListener; - alljoyn_sessionid m_sessionId; + alljoyn_busobject m_nativeBusObject; alljoyn_busattachment m_nativeBusAttachment; // Used to pass a pointer to this class to callbacks @@ -225,6 +162,9 @@ public ref class SecureInterfaceConsumer sealed : [Windows::Foundation::Metadat // handlers, but the current AllJoyn C API does not allow passing a context to these // callbacks. static std::map SourceInterfaces; + + // The name of the interface this consumer implements. + static PCSTR m_interfaceName; }; } } } } diff --git a/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceEventArgs.h b/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceEventArgs.h index 7916683af3..5711a7a189 100644 --- a/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceEventArgs.h +++ b/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceEventArgs.h @@ -23,6 +23,7 @@ namespace com { namespace microsoft { namespace Samples { namespace SecureInterface { // Signals +// "This signal is emitted when producer sends a text message to consumer" public ref class SecureInterfaceTextSentReceivedEventArgs sealed { public: diff --git a/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceLegacySignals.cpp b/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceLegacySignals.cpp new file mode 100644 index 0000000000..5d17129347 --- /dev/null +++ b/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceLegacySignals.cpp @@ -0,0 +1,67 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// This code is licensed under the MIT License (MIT). +// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY +// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR +// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. +// +//********************************************************* +//----------------------------------------------------------------------------- +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// For more information, see: http://go.microsoft.com/fwlink/?LinkID=623246 +// +//----------------------------------------------------------------------------- +#include "pch.h" + +using namespace Microsoft::WRL; +using namespace Platform; +using namespace Windows::Devices::AllJoyn; +using namespace Windows::Foundation; +using namespace com::microsoft::Samples::SecureInterface; + +void SecureInterfaceLegacySignals::Initialize(_In_ alljoyn_busobject busObject, _In_ alljoyn_sessionid sessionId) +{ + m_busObject = busObject; + m_sessionId = sessionId; + + auto interfaceDefinition = alljoyn_busattachment_getinterface(alljoyn_busobject_getbusattachment(busObject), "com.microsoft.Samples.SecureInterface"); + alljoyn_interfacedescription_getmember(interfaceDefinition, "TextSent", &m_memberTextSent); +} + +void SecureInterfaceLegacySignals::TextSent(_In_ Platform::String^ interfaceMemberMessage) +{ + if (nullptr == m_busObject) + { + return; + } + + size_t argCount = 1; + alljoyn_msgarg arguments = alljoyn_msgarg_array_create(argCount); + (void)TypeConversionHelpers::SetAllJoynMessageArg(alljoyn_msgarg_array_element(arguments, 0), "s", interfaceMemberMessage); + + alljoyn_busobject_signal( + m_busObject, + NULL, // Generated code only supports broadcast signals. + m_sessionId, + m_memberTextSent, + arguments, + argCount, + 0, // A signal with a TTL of 0 will be sent to every member of the session, regardless of how long it takes to deliver the message + ALLJOYN_MESSAGE_FLAG_GLOBAL_BROADCAST, // Broadcast to everyone in the session. + NULL); // The generated code does not need the generated signal message + + alljoyn_msgarg_destroy(arguments); +} + +void SecureInterfaceLegacySignals::CallTextSentReceived(_In_ SecureInterfaceLegacySignals^ sender, _In_ SecureInterfaceTextSentReceivedEventArgs^ args) +{ + TextSentReceived(sender, args); +} + diff --git a/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceLegacySignals.h b/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceLegacySignals.h new file mode 100644 index 0000000000..3a8f7aafcf --- /dev/null +++ b/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceLegacySignals.h @@ -0,0 +1,74 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// This code is licensed under the MIT License (MIT). +// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY +// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR +// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. +// +//********************************************************* +//----------------------------------------------------------------------------- +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// For more information, see: http://go.microsoft.com/fwlink/?LinkID=623246 +// +//----------------------------------------------------------------------------- +#pragma once + +namespace com { namespace microsoft { namespace Samples { namespace SecureInterface { + +ref class SecureInterfaceLegacySignals; + +public interface class ISecureInterfaceLegacySignals +{ + event Windows::Foundation::TypedEventHandler^ TextSentReceived; +}; + +public ref class SecureInterfaceLegacySignals sealed : [Windows::Foundation::Metadata::Default] ISecureInterfaceLegacySignals +{ +public: + // "This signal is emitted when producer sends a text message to consumer" + // Calling this method will send the TextSent signal to every member of the session. + void TextSent(_In_ Platform::String^ interfaceMemberMessage); + + // This event fires whenever the TextSent signal is sent by another member of the session. + virtual event Windows::Foundation::TypedEventHandler^ TextSentReceived + { + Windows::Foundation::EventRegistrationToken add(Windows::Foundation::TypedEventHandler^ handler) + { + return _TextSentReceived += ref new Windows::Foundation::EventHandler + ([handler](Platform::Object^ sender, Platform::Object^ args) + { + handler->Invoke(safe_cast(sender), safe_cast(args)); + }, Platform::CallbackContext::Same); + } + void remove(Windows::Foundation::EventRegistrationToken token) + { + _TextSentReceived -= token; + } + internal: + void raise(SecureInterfaceLegacySignals^ sender, SecureInterfaceTextSentReceivedEventArgs^ args) + { + _TextSentReceived(sender, args); + } + } + +internal: + void Initialize(_In_ alljoyn_busobject busObject, _In_ alljoyn_sessionid sessionId); + void CallTextSentReceived(_In_ SecureInterfaceLegacySignals^ sender, _In_ SecureInterfaceTextSentReceivedEventArgs^ args); + +private: + alljoyn_busobject m_busObject; + alljoyn_sessionid m_sessionId; + + virtual event Windows::Foundation::EventHandler^ _TextSentReceived; + + alljoyn_interfacedescription_member m_memberTextSent; +}; + +} } } } \ No newline at end of file diff --git a/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceMethodResults.h b/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceMethodResults.h index dd3399d5de..5634f79b49 100644 --- a/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceMethodResults.h +++ b/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceMethodResults.h @@ -98,6 +98,7 @@ public ref class SecureInterfaceGetIsUpperCaseEnabledResult sealed void set(_In_ int32 value) { m_status = value; } } + // "Determine if the output of the Concatenate method is returned as upper case string or not" property bool IsUpperCaseEnabled { bool get() { return m_value; } diff --git a/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceProducer.cpp b/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceProducer.cpp index 6c62846f37..2a6078ee6a 100644 --- a/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceProducer.cpp +++ b/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceProducer.cpp @@ -39,7 +39,7 @@ SecureInterfaceProducer::SecureInterfaceProducer(AllJoynBusAttachment^ busAttach { m_weak = new WeakReference(this); ServiceObjectPath = ref new String(L"/Service"); - m_signals = ref new SecureInterfaceSignals(); + m_signals = ref new SecureInterfaceLegacySignals(); m_busAttachmentStateChangedToken.Value = 0; } @@ -444,4 +444,4 @@ PCSTR com::microsoft::Samples::SecureInterface::c_SecureInterfaceIntrospectionXm " " " " "" -; +; \ No newline at end of file diff --git a/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceProducer.h b/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceProducer.h index 6fbdda65d3..bc79c29320 100644 --- a/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceProducer.h +++ b/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceProducer.h @@ -48,9 +48,9 @@ public ref class SecureInterfaceProducer sealed : [Windows::Foundation::Metadata } // Used to send signals or register functions to handle received signals. - property SecureInterfaceSignals^ Signals + property SecureInterfaceLegacySignals^ Signals { - SecureInterfaceSignals^ get() { return m_signals; } + SecureInterfaceLegacySignals^ get() { return m_signals; } } // This event will fire whenever this producer is stopped. @@ -209,7 +209,9 @@ public ref class SecureInterfaceProducer sealed : [Windows::Foundation::Metadata virtual event Windows::Foundation::EventHandler^ _SessionMemberAdded; virtual event Windows::Foundation::EventHandler^ _SessionMemberRemoved; + // "Concatenate two input strings and returns the concatenated string as output" static void CallConcatenateHandler(_Inout_ alljoyn_busobject busObject, _In_ alljoyn_message message); + // "This signal is emitted when producer sends a text message to consumer" static void CallTextSentSignalHandler(_In_ const alljoyn_interfacedescription_member* member, _In_ alljoyn_message message); // Register a callback function to handle methods. @@ -221,7 +223,7 @@ public ref class SecureInterfaceProducer sealed : [Windows::Foundation::Metadata Windows::Devices::AllJoyn::AllJoynBusAttachment^ m_busAttachment; Windows::Foundation::EventRegistrationToken m_busAttachmentStateChangedToken; - SecureInterfaceSignals^ m_signals; + SecureInterfaceLegacySignals^ m_signals; ISecureInterfaceService^ m_serviceInterface; Platform::String^ m_ServiceObjectPath; @@ -241,4 +243,4 @@ public ref class SecureInterfaceProducer sealed : [Windows::Foundation::Metadata static std::map SourceInterfaces; }; -} } } } +} } } } \ No newline at end of file diff --git a/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceServiceEventAdapter.cpp b/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceServiceEventAdapter.cpp index c994e0e9b5..39df1b9014 100644 --- a/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceServiceEventAdapter.cpp +++ b/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceServiceEventAdapter.cpp @@ -9,24 +9,13 @@ // //********************************************************* //----------------------------------------------------------------------------- -// -// This code was generated by a tool. -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -// Tool: AllJoynCodeGenerator.exe +// +// This code was generated by a tool. // -// This tool is located in the Windows 10 SDK and the Windows 10 AllJoyn -// Visual Studio Extension in the Visual Studio Gallery. -// -// The generated code should be packaged in a Windows 10 C++/CX Runtime -// Component which can be consumed in any UWP-supported language using -// APIs that are available in Windows.Devices.AllJoyn. +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. // -// Using AllJoynCodeGenerator - Invoke the following command with a valid -// Introspection XML file and a writable output directory: -// AllJoynCodeGenerator -i -o +// For more information, see: http://go.microsoft.com/fwlink/?LinkID=623246 // //----------------------------------------------------------------------------- #include "pch.h" diff --git a/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceServiceEventAdapter.h b/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceServiceEventAdapter.h index 02b0ffe768..1824eb9bff 100644 --- a/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceServiceEventAdapter.h +++ b/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceServiceEventAdapter.h @@ -9,24 +9,13 @@ // //********************************************************* //----------------------------------------------------------------------------- -// -// This code was generated by a tool. -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -// Tool: AllJoynCodeGenerator.exe +// +// This code was generated by a tool. // -// This tool is located in the Windows 10 SDK and the Windows 10 AllJoyn -// Visual Studio Extension in the Visual Studio Gallery. -// -// The generated code should be packaged in a Windows 10 C++/CX Runtime -// Component which can be consumed in any UWP-supported language using -// APIs that are available in Windows.Devices.AllJoyn. +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. // -// Using AllJoynCodeGenerator - Invoke the following command with a valid -// Introspection XML file and a writable output directory: -// AllJoynCodeGenerator -i -o +// For more information, see: http://go.microsoft.com/fwlink/?LinkID=623246 // //----------------------------------------------------------------------------- #pragma once diff --git a/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceServiceEventArgs.cpp b/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceServiceEventArgs.cpp index 2d384de757..19021f61df 100644 --- a/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceServiceEventArgs.cpp +++ b/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceServiceEventArgs.cpp @@ -9,24 +9,13 @@ // //********************************************************* //----------------------------------------------------------------------------- -// -// This code was generated by a tool. -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -// Tool: AllJoynCodeGenerator.exe +// +// This code was generated by a tool. // -// This tool is located in the Windows 10 SDK and the Windows 10 AllJoyn -// Visual Studio Extension in the Visual Studio Gallery. -// -// The generated code should be packaged in a Windows 10 C++/CX Runtime -// Component which can be consumed in any UWP-supported language using -// APIs that are available in Windows.Devices.AllJoyn. +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. // -// Using AllJoynCodeGenerator - Invoke the following command with a valid -// Introspection XML file and a writable output directory: -// AllJoynCodeGenerator -i -o +// For more information, see: http://go.microsoft.com/fwlink/?LinkID=623246 // //----------------------------------------------------------------------------- #include "pch.h" @@ -51,7 +40,7 @@ SecureInterfaceConcatenateCalledEventArgs::SecureInterfaceConcatenateCalledEvent m_interfaceMemberInStr1(interfaceMemberInStr1), m_interfaceMemberInStr2(interfaceMemberInStr2) { - m_result = SecureInterfaceConcatenateResult::CreateFailureResult(ER_NOT_IMPLEMENTED); + m_result = SecureInterfaceConcatenateResult::CreateFailureResult(ER_NOT_IMPLEMENTED); } Deferral^ SecureInterfaceConcatenateCalledEventArgs::GetDeferral() @@ -127,7 +116,7 @@ SecureInterfaceGetIsUpperCaseEnabledRequestedEventArgs::SecureInterfaceGetIsUppe m_completionsRequired(0), m_messageInfo(info) { - m_result = SecureInterfaceGetIsUpperCaseEnabledResult::CreateFailureResult(ER_NOT_IMPLEMENTED); + m_result = SecureInterfaceGetIsUpperCaseEnabledResult::CreateFailureResult(ER_NOT_IMPLEMENTED); } Deferral^ SecureInterfaceGetIsUpperCaseEnabledRequestedEventArgs::GetDeferral() @@ -205,7 +194,7 @@ SecureInterfaceSetIsUpperCaseEnabledRequestedEventArgs::SecureInterfaceSetIsUppe m_messageInfo(info), m_value(value) { - m_result = SecureInterfaceSetIsUpperCaseEnabledResult::CreateFailureResult(ER_NOT_IMPLEMENTED); + m_result = SecureInterfaceSetIsUpperCaseEnabledResult::CreateFailureResult(ER_NOT_IMPLEMENTED); } Deferral^ SecureInterfaceSetIsUpperCaseEnabledRequestedEventArgs::GetDeferral() diff --git a/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceServiceEventArgs.h b/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceServiceEventArgs.h index 82476f6f47..68e0f0f19e 100644 --- a/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceServiceEventArgs.h +++ b/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceServiceEventArgs.h @@ -9,24 +9,13 @@ // //********************************************************* //----------------------------------------------------------------------------- -// -// This code was generated by a tool. -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -// Tool: AllJoynCodeGenerator.exe +// +// This code was generated by a tool. // -// This tool is located in the Windows 10 SDK and the Windows 10 AllJoyn -// Visual Studio Extension in the Visual Studio Gallery. -// -// The generated code should be packaged in a Windows 10 C++/CX Runtime -// Component which can be consumed in any UWP-supported language using -// APIs that are available in Windows.Devices.AllJoyn. +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. // -// Using AllJoynCodeGenerator - Invoke the following command with a valid -// Introspection XML file and a writable output directory: -// AllJoynCodeGenerator -i -o +// For more information, see: http://go.microsoft.com/fwlink/?LinkID=623246 // //----------------------------------------------------------------------------- #pragma once diff --git a/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceSignals.cpp b/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceSignals.cpp index 04959ba630..7663d85e25 100644 --- a/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceSignals.cpp +++ b/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceSignals.cpp @@ -26,18 +26,17 @@ using namespace Windows::Devices::AllJoyn; using namespace Windows::Foundation; using namespace com::microsoft::Samples::SecureInterface; -void SecureInterfaceSignals::Initialize(_In_ alljoyn_busobject busObject, _In_ alljoyn_sessionid sessionId) +void SecureInterfaceSignals::Initialize(_In_ ISignalEmitter^ emitter) { - m_busObject = busObject; - m_sessionId = sessionId; - - auto interfaceDefinition = alljoyn_busattachment_getinterface(alljoyn_busobject_getbusattachment(busObject), "com.microsoft.Samples.SecureInterface"); + m_emitter = emitter; + alljoyn_busattachment nativeBusAttachment = AllJoynHelpers::GetInternalBusAttachment(m_emitter->BusObject->BusAttachment); + auto interfaceDefinition = alljoyn_busattachment_getinterface(nativeBusAttachment, "com.microsoft.Samples.SecureInterface"); alljoyn_interfacedescription_getmember(interfaceDefinition, "TextSent", &m_memberTextSent); } void SecureInterfaceSignals::TextSent(_In_ Platform::String^ interfaceMemberMessage) { - if (nullptr == m_busObject) + if (nullptr == AllJoynHelpers::GetInternalBusObject(m_emitter->BusObject)) { return; } @@ -47,9 +46,9 @@ void SecureInterfaceSignals::TextSent(_In_ Platform::String^ interfaceMemberMess (void)TypeConversionHelpers::SetAllJoynMessageArg(alljoyn_msgarg_array_element(arguments, 0), "s", interfaceMemberMessage); alljoyn_busobject_signal( - m_busObject, + AllJoynHelpers::GetInternalBusObject(m_emitter->BusObject), NULL, // Generated code only supports broadcast signals. - m_sessionId, + m_emitter->Session->Id, m_memberTextSent, arguments, argCount, diff --git a/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceSignals.h b/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceSignals.h index 85bb579e67..d3fd1adb00 100644 --- a/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceSignals.h +++ b/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceSignals.h @@ -32,6 +32,7 @@ public interface class ISecureInterfaceSignals public ref class SecureInterfaceSignals sealed : [Windows::Foundation::Metadata::Default] ISecureInterfaceSignals { public: + // "This signal is emitted when producer sends a text message to consumer" // Calling this method will send the TextSent signal to every member of the session. void TextSent(_In_ Platform::String^ interfaceMemberMessage); @@ -58,12 +59,11 @@ public ref class SecureInterfaceSignals sealed : [Windows::Foundation::Metadata: } internal: - void Initialize(_In_ alljoyn_busobject busObject, _In_ alljoyn_sessionid sessionId); + void Initialize(_In_ ISignalEmitter^ emitter); void CallTextSentReceived(_In_ SecureInterfaceSignals^ sender, _In_ SecureInterfaceTextSentReceivedEventArgs^ args); private: - alljoyn_busobject m_busObject; - alljoyn_sessionid m_sessionId; + ISignalEmitter^ m_emitter; virtual event Windows::Foundation::EventHandler^ _TextSentReceived; diff --git a/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceWatcher.cpp b/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceWatcher.cpp deleted file mode 100644 index 60f2763d63..0000000000 --- a/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceWatcher.cpp +++ /dev/null @@ -1,142 +0,0 @@ -//********************************************************* -// -// Copyright (c) Microsoft. All rights reserved. -// This code is licensed under the MIT License (MIT). -// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF -// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY -// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR -// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. -// -//********************************************************* -//----------------------------------------------------------------------------- -// -// This code was generated by a tool. -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -// For more information, see: http://go.microsoft.com/fwlink/?LinkID=623246 -// -//----------------------------------------------------------------------------- -#include "pch.h" - -using namespace concurrency; -using namespace Microsoft::WRL; -using namespace Platform; -using namespace Windows::Foundation; -using namespace Windows::Devices::AllJoyn; -using namespace com::microsoft::Samples::SecureInterface; - -SecureInterfaceWatcher::SecureInterfaceWatcher(AllJoynBusAttachment^ busAttachment) : - m_aboutListener(nullptr) -{ - m_busAttachment = busAttachment; - m_weak = new WeakReference(this); - m_busAttachmentStateChangedToken.Value = 0; -} - -SecureInterfaceWatcher::~SecureInterfaceWatcher() -{ - UnregisterFromBus(); -} - -void SecureInterfaceWatcher::UnregisterFromBus() -{ - if (nullptr != m_aboutListener) - { - PCSTR interfaces[] = { "com.microsoft.Samples.SecureInterface" }; - alljoyn_busattachment_cancelwhoimplements_interfaces( - AllJoynHelpers::GetInternalBusAttachment(m_busAttachment), - interfaces, - _countof(interfaces)); - - alljoyn_busattachment_unregisteraboutlistener(AllJoynHelpers::GetInternalBusAttachment(m_busAttachment), m_aboutListener); - alljoyn_aboutlistener_destroy(m_aboutListener); - m_aboutListener = nullptr; - } - if ((nullptr != m_busAttachment) && (0 != m_busAttachmentStateChangedToken.Value)) - { - m_busAttachment->StateChanged -= m_busAttachmentStateChangedToken; - } -} - -void SecureInterfaceWatcher::OnAnnounce( - _In_ PCSTR name, - _In_ uint16_t version, - _In_ alljoyn_sessionport port, - _In_ alljoyn_msgarg objectDescriptionArg, - _In_ const alljoyn_msgarg aboutDataArg) -{ - UNREFERENCED_PARAMETER(version); - UNREFERENCED_PARAMETER(aboutDataArg); - - alljoyn_aboutobjectdescription objectDescription = alljoyn_aboutobjectdescription_create_full(objectDescriptionArg); - - if (alljoyn_aboutobjectdescription_hasinterface(objectDescription, "com.microsoft.Samples.SecureInterface")) - { - AllJoynServiceInfo^ args = ref new AllJoynServiceInfo( - AllJoynHelpers::MultibyteToPlatformString(name), - AllJoynHelpers::GetObjectPath(objectDescription, "com.microsoft.Samples.SecureInterface"), - port); - Added(this, args); - } - alljoyn_aboutobjectdescription_destroy(objectDescription); -} - -void SecureInterfaceWatcher::BusAttachmentStateChanged(_In_ AllJoynBusAttachment^ sender, _In_ AllJoynBusAttachmentStateChangedEventArgs^ args) -{ - if (args->State == AllJoynBusAttachmentState::Connected) - { - alljoyn_aboutlistener_callback callbacks = - { - AllJoynHelpers::AnnounceHandler - }; - m_aboutListener = alljoyn_aboutlistener_create(&callbacks, m_weak); - - alljoyn_busattachment_registeraboutlistener(AllJoynHelpers::GetInternalBusAttachment(sender), m_aboutListener); - PCSTR interfaces[] = { "com.microsoft.Samples.SecureInterface" }; - - auto status = alljoyn_busattachment_whoimplements_interfaces( - AllJoynHelpers::GetInternalBusAttachment(sender), - interfaces, - _countof(interfaces)); - if (ER_OK != status) - { - StopInternal(status); - } - } - else if (args->State == AllJoynBusAttachmentState::Disconnected) - { - StopInternal(ER_BUS_STOPPING); - } -} - -void SecureInterfaceWatcher::Start() -{ - if (nullptr == m_busAttachment) - { - StopInternal(ER_FAIL); - return; - } - - int32 result = AllJoynHelpers::CreateInterfaces(m_busAttachment, c_SecureInterfaceIntrospectionXml); - if (result != AllJoynStatus::Ok) - { - StopInternal(result); - return; - } - - m_busAttachmentStateChangedToken = m_busAttachment->StateChanged += ref new TypedEventHandler(this, &SecureInterfaceWatcher::BusAttachmentStateChanged); - m_busAttachment->Connect(); -} - -void SecureInterfaceWatcher::Stop() -{ - StopInternal(AllJoynStatus::Ok); -} - -void SecureInterfaceWatcher::StopInternal(int32 status) -{ - UnregisterFromBus(); - Stopped(this, ref new AllJoynProducerStoppedEventArgs(status)); -} \ No newline at end of file diff --git a/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceWatcher.h b/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceWatcher.h deleted file mode 100644 index 97ba78d8b0..0000000000 --- a/Samples/AllJoyn/Common/Scenario1WinRTComponent/SecureInterfaceWatcher.h +++ /dev/null @@ -1,127 +0,0 @@ -//********************************************************* -// -// Copyright (c) Microsoft. All rights reserved. -// This code is licensed under the MIT License (MIT). -// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF -// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY -// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR -// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. -// -//********************************************************* -//----------------------------------------------------------------------------- -// -// This code was generated by a tool. -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -// For more information, see: http://go.microsoft.com/fwlink/?LinkID=623246 -// -//----------------------------------------------------------------------------- -#pragma once - -namespace com { namespace microsoft { namespace Samples { namespace SecureInterface { - -ref class SecureInterfaceWatcher; - -public interface class ISecureInterfaceWatcher -{ - event Windows::Foundation::TypedEventHandler^ Added; - event Windows::Foundation::TypedEventHandler^ Stopped; -}; - -public ref class SecureInterfaceWatcher sealed : [Windows::Foundation::Metadata::Default] ISecureInterfaceWatcher -{ -public: - SecureInterfaceWatcher(Windows::Devices::AllJoyn::AllJoynBusAttachment^ busAttachment); - virtual ~SecureInterfaceWatcher(); - - // This event will fire whenever a producer for this service is found. - virtual event Windows::Foundation::TypedEventHandler^ Added - { - Windows::Foundation::EventRegistrationToken add(Windows::Foundation::TypedEventHandler^ handler) - { - return _Added += ref new Windows::Foundation::EventHandler - ([handler](Platform::Object^ sender, Platform::Object^ args) - { - handler->Invoke(safe_cast(sender), safe_cast(args)); - }, Platform::CallbackContext::Same); - } - void remove(Windows::Foundation::EventRegistrationToken token) - { - _Added -= token; - } - internal: - void raise(SecureInterfaceWatcher^ sender, Windows::Devices::AllJoyn::AllJoynServiceInfo^ args) - { - _Added(sender, args); - } - } - - // This event will fire whenever the watcher is stopped. - virtual event Windows::Foundation::TypedEventHandler^ Stopped - { - Windows::Foundation::EventRegistrationToken add(Windows::Foundation::TypedEventHandler^ handler) - { - return _Stopped += ref new Windows::Foundation::EventHandler - ([handler](Platform::Object^ sender, Platform::Object^ args) - { - handler->Invoke(safe_cast(sender), safe_cast(args)); - }, Platform::CallbackContext::Same); - } - void remove(Windows::Foundation::EventRegistrationToken token) - { - _Stopped -= token; - } - internal: - void raise(SecureInterfaceWatcher^ sender, Windows::Devices::AllJoyn::AllJoynProducerStoppedEventArgs^ args) - { - _Stopped(sender, args); - } - } - - // Start watching for producers advertising this service. - void Start(); - - // Stop watching for producers for this service. - void Stop(); - -internal: - void OnAnnounce( - _In_ PCSTR name, - _In_ uint16_t version, - _In_ alljoyn_sessionport port, - _In_ alljoyn_msgarg objectDescriptionArg, - _In_ const alljoyn_msgarg aboutDataArg); - - void OnPropertyChanged(_In_ PCSTR prop_name, _In_ alljoyn_msgarg prop_value) - { - UNREFERENCED_PARAMETER(prop_name); UNREFERENCED_PARAMETER(prop_value); - } - - property Windows::Devices::AllJoyn::AllJoynBusAttachment^ BusAttachment - { - Windows::Devices::AllJoyn::AllJoynBusAttachment^ get() { return m_busAttachment; } - } - - // Stop watching for producers advertising this service and pass status to anyone listening for the Stopped event. - void StopInternal(int32 status); - - void BusAttachmentStateChanged(_In_ Windows::Devices::AllJoyn::AllJoynBusAttachment^ sender, _In_ Windows::Devices::AllJoyn::AllJoynBusAttachmentStateChangedEventArgs^ args); - -private: - virtual event Windows::Foundation::EventHandler^ _Added; - virtual event Windows::Foundation::EventHandler^ _Stopped; - - void UnregisterFromBus(); - - Windows::Devices::AllJoyn::AllJoynBusAttachment^ m_busAttachment; - Windows::Foundation::EventRegistrationToken m_busAttachmentStateChangedToken; - - alljoyn_aboutlistener m_aboutListener; - - // Used to pass a pointer to this class to callbacks. - Platform::WeakReference* m_weak; -}; - -} } } } \ No newline at end of file diff --git a/Samples/AllJoyn/Common/Scenario1WinRTComponent/pch.h b/Samples/AllJoyn/Common/Scenario1WinRTComponent/pch.h index d75dfddc21..74ad51f3b1 100644 --- a/Samples/AllJoyn/Common/Scenario1WinRTComponent/pch.h +++ b/Samples/AllJoyn/Common/Scenario1WinRTComponent/pch.h @@ -45,8 +45,8 @@ #include "SecureInterfaceEventArgs.h" #include "ISecureInterfaceService.h" #include "SecureInterfaceSignals.h" +#include "SecureInterfaceLegacySignals.h" #include "SecureInterfaceProducer.h" -#include "SecureInterfaceWatcher.h" #include "SecureInterfaceConsumer.h" #include "SecureInterfaceServiceEventArgs.h" #include "SecureInterfaceServiceEventAdapter.h" \ No newline at end of file diff --git a/Samples/AllJoyn/Common/Scenario2WinRTComponent/AllJoynHelpers.h b/Samples/AllJoyn/Common/Scenario2WinRTComponent/AllJoynHelpers.h new file mode 100644 index 0000000000..1987e10a79 --- /dev/null +++ b/Samples/AllJoyn/Common/Scenario2WinRTComponent/AllJoynHelpers.h @@ -0,0 +1,277 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// This code is licensed under the MIT License (MIT). +// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY +// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR +// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. +// +//********************************************************* +//----------------------------------------------------------------------------- +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// For more information, see: http://go.microsoft.com/fwlink/?LinkID=623246 +// +//----------------------------------------------------------------------------- +#pragma once + +// The amount of time to wait (ms) for a response after sending a message before timing out. +const int c_MessageTimeoutInMilliseconds = 10000; + +// The maximum length of an AllJoyn type signature allowed by the AllJoyn Core library. +const int c_MaximumSignatureLength = 255; + +#define RETURN_IF_QSTATUS_ERROR(status) \ +{ \ +int32 alljoynStatus = static_cast(status); \ +if (Windows::Devices::AllJoyn::AllJoynStatus::Ok != alljoynStatus) \ +{ \ + return status; \ +} \ +} + +namespace org { namespace alljoyn { namespace Onboarding { + +public interface class ISignalEmitter +{ + property Windows::Devices::AllJoyn::AllJoynBusObject^ BusObject + { + Windows::Devices::AllJoyn::AllJoynBusObject^ get(); + } + + property Windows::Devices::AllJoyn::AllJoynSession^ Session + { + Windows::Devices::AllJoyn::AllJoynSession^ get(); + } +}; + +} } } + +class AllJoynHelpers +{ +public: + // The Windows::Devices::AllJoyn::AllJoynBusAttachment class wraps the alljoyn_busattachment type. This + // function gets the underlying alljoyn_busattachment. + static alljoyn_busattachment GetInternalBusAttachment(_In_ Windows::Devices::AllJoyn::AllJoynBusAttachment^ busAttachment); + + // The Windows::Devices::AllJoyn::AllJoynBusObject class wraps the alljoyn_busobject type. This + // function gets the underlying alljoyn_busobject. + static alljoyn_busobject AllJoynHelpers::GetInternalBusObject(_In_ Windows::Devices::AllJoyn::AllJoynBusObject^ busObject); + + // Create the alljoyn_interfacedescriptions described in introspectionXml and add them to the busAttachment. + static QStatus CreateInterfaces(_Inout_ Windows::Devices::AllJoyn::AllJoynBusAttachment^ busAttachment, _In_ PCSTR introspectionXml); + + // Convert a UTF8 string to a wide character Platform::String. + static Platform::String^ MultibyteToPlatformString(_In_ PCSTR); + + // Convert a wide character Platform::String to a UTF8 string. + static std::vector PlatformToMultibyteString(_In_ Platform::String^ str); + + // Get the service object path from an objectDescriptionArg. The objectDescriptionArg should + // come from an Announce signal. + static Platform::String^ GetObjectPath(_In_ alljoyn_aboutobjectdescription objectDescription, _In_ PCSTR interfaceName); + + // Determine whether the supplied set of AuthenticationMechanisms is sufficient for securing an AllJoyn connection. + static bool CanSecure(_In_ Windows::Foundation::Collections::IVector^ authenticationMechanisms); + + // Callback for alljoyn_proxybusobject_listener_propertieschanged_ptr. + // This callback expects the context to be of type T, which must implement the OnPropertyChanged function. + template + static void AJ_CALL PropertyChangedHandler(_In_ alljoyn_proxybusobject obj, _In_ PCSTR interfaceName, _In_ const alljoyn_msgarg changed, _In_ const alljoyn_msgarg invalidated, _In_ void* context) + { + T^ caller = static_cast(context)->Resolve(); + caller->OnPropertyChanged(obj, interfaceName, changed, invalidated); + } + + // Callback for alljoyn_busobject_prop_get_ptr. + template + static QStatus AJ_CALL PropertyGetHandler(_In_ const void* context, _In_ PCSTR interfaceName, _In_ PCSTR propertyName, _In_ alljoyn_msgarg value) + { + T^ caller = static_cast(context)->Resolve(); + return caller->OnPropertyGet(interfaceName, propertyName, value); + } + + // Callback for alljoyn_busobject_prop_set_ptr. + template + static QStatus AJ_CALL PropertySetHandler(_In_ const void* context, _In_ PCSTR interfaceName, _In_ PCSTR propertyName, _In_ alljoyn_msgarg value) + { + T^ caller = static_cast(context)->Resolve(); + return caller->OnPropertySet(interfaceName, propertyName, value); + } + + // Callback for alljoyn_sessionlistener_sessionlost_ptr. + template + static void AJ_CALL SessionLostHandler(_In_ const void* context, _In_ alljoyn_sessionid sessionId, _In_ alljoyn_sessionlostreason reason) + { + T^ caller = static_cast(context)->Resolve(); + caller->OnSessionLost(sessionId, reason); + } + + // Callback for alljoyn_sessionlistener_sessionmemberadded_ptr. + template + static void AJ_CALL SessionMemberAddedHandler(_In_ const void* context, _In_ alljoyn_sessionid sessionId, _In_ PCSTR uniqueName) + { + T^ caller = static_cast(context)->Resolve(); + caller->OnSessionMemberAdded(sessionId, uniqueName); + } + + // Callback for alljoyn_sessionlistener_sessionmemberremoved_ptr. + template + static void AJ_CALL SessionMemberRemovedHandler(_In_ const void* context, _In_ alljoyn_sessionid sessionId, _In_ PCSTR uniqueName) + { + T^ caller = static_cast(context)->Resolve(); + caller->OnSessionMemberRemoved(sessionId, uniqueName); + } + + // Create an AllJoyn bus object. + template + static QStatus CreateBusObject(_Inout_ Platform::WeakReference* target) + { + alljoyn_busobject_callbacks callbacks = + { + PropertyGetHandler, + PropertySetHandler, + nullptr, + nullptr, + }; + + T^ caller = target->Resolve(); + + auto serviceObjectPath = PlatformToMultibyteString(caller->ServiceObjectPath); + alljoyn_busobject busObject = alljoyn_busobject_create(serviceObjectPath.data(), false, &callbacks, target); + if (busObject == nullptr) + { + return ER_FAIL; + } + + caller->BusObject = busObject; + + return ER_OK; + } + + // Callback for alljoyn_sessionportlistener_acceptsessionjoiner_ptr. + // This callback expects the context to be of type T, which must implement the OnAcceptSessionJoiner function. + template + static QCC_BOOL AJ_CALL AcceptSessionJoinerHandler( + _In_ const void* context, + _In_ alljoyn_sessionport sessionPort, + _In_ PCSTR joiner, + _In_ const alljoyn_sessionopts opts) + { + T^ caller = static_cast(context)->Resolve(); + return caller->OnAcceptSessionJoiner(sessionPort, joiner, opts); + } + + // Callback for alljoyn_sessionportlistener_sessionjoined_ptr. + // This callback expects the context to be of type T, which must implement the OnSessionJoined function. + template + static void AJ_CALL SessionJoinedHandler( + _In_ const void* context, + _In_ alljoyn_sessionport sessionPort, + _In_ alljoyn_sessionid id, + _In_ PCSTR joiner) + { + T^ caller = static_cast(context)->Resolve(); + caller->OnSessionJoined(sessionPort, id, joiner); + } + + // Create the session for an AllJoyn producer. + template + static QStatus CreateProducerSession(_Inout_ Windows::Devices::AllJoyn::AllJoynBusAttachment^ busAttachment, _Inout_ Platform::WeakReference* target) + { + alljoyn_sessionopts opts = alljoyn_sessionopts_create(ALLJOYN_TRAFFIC_TYPE_MESSAGES, true, ALLJOYN_PROXIMITY_ANY, ALLJOYN_TRANSPORT_ANY); + + alljoyn_sessionportlistener_callbacks callbacks = + { + AcceptSessionJoinerHandler, + SessionJoinedHandler + }; + + T^ producer = target->Resolve(); + producer->SessionPortListener = alljoyn_sessionportlistener_create(&callbacks, target); + + alljoyn_sessionport sessionPort = 42; + alljoyn_busattachment_unbindsessionport(AllJoynHelpers::GetInternalBusAttachment(busAttachment), sessionPort); + RETURN_IF_QSTATUS_ERROR(alljoyn_busattachment_bindsessionport(AllJoynHelpers::GetInternalBusAttachment(busAttachment), &sessionPort, opts, producer->SessionPortListener)); + producer->SessionPort = sessionPort; + + alljoyn_sessionopts_destroy(opts); + + return ER_OK; + } +}; + +// Passed to property get callbacks to allow them to report when the async operation is completed. +template +class PropertyGetContext +{ +public: + void SetEvent() + { + m_event.set(); + } + + void Wait() + { + m_event.wait(); + } + + QStatus GetStatus() + { + return m_status; + } + + void SetStatus(QStatus value) + { + m_status = value; + } + + T GetValue() + { + return m_value; + } + + void SetValue(T value) + { + m_value = value; + } + +private: + Concurrency::event m_event; + QStatus m_status; + T m_value; +}; + +// Passed to property set callbacks to allow them to report when the async operation is completed. +class PropertySetContext +{ +public: + void SetEvent() + { + m_event.set(); + } + + void Wait() + { + m_event.wait(); + } + + QStatus GetStatus() + { + return m_status; + } + + void SetStatus(QStatus value) + { + m_status = value; + } + +private: + Concurrency::event m_event; + QStatus m_status; +}; diff --git a/Samples/AllJoyn/Common/Scenario2WinRTComponent/IOnboardingService.h b/Samples/AllJoyn/Common/Scenario2WinRTComponent/IOnboardingService.h index ab25d032de..65ba47eb2c 100644 --- a/Samples/AllJoyn/Common/Scenario2WinRTComponent/IOnboardingService.h +++ b/Samples/AllJoyn/Common/Scenario2WinRTComponent/IOnboardingService.h @@ -25,28 +25,35 @@ namespace org { namespace alljoyn { namespace Onboarding { public interface class IOnboardingService { public: + // "Sends the personal AP information to the onboardee" // Implement this function to handle calls to the ConfigureWiFi method. Windows::Foundation::IAsyncOperation^ ConfigureWiFiAsync(_In_ Windows::Devices::AllJoyn::AllJoynMessageInfo^ info , _In_ Platform::String^ interfaceMemberSSID, _In_ Platform::String^ interfaceMemberPassphrase, _In_ int16 interfaceMemberAuthType); + // "Tells the onboardee to connect to the personal AP" // Implement this function to handle calls to the Connect method. Windows::Foundation::IAsyncOperation^ ConnectAsync(_In_ Windows::Devices::AllJoyn::AllJoynMessageInfo^ info ); + // "Tells the onboardee to disconnect from the personal AP" // Implement this function to handle calls to the Offboard method. Windows::Foundation::IAsyncOperation^ OffboardAsync(_In_ Windows::Devices::AllJoyn::AllJoynMessageInfo^ info ); + // "Scans all the Wi-Fi access points in the onboardee's proximity" // Implement this function to handle calls to the GetScanInfo method. Windows::Foundation::IAsyncOperation^ GetScanInfoAsync(_In_ Windows::Devices::AllJoyn::AllJoynMessageInfo^ info ); + // "Interface version number" // Implement this function to handle requests for the value of the Version property. // // Currently, info will always be null, because no information is available about the requestor. Windows::Foundation::IAsyncOperation^ GetVersionAsync(Windows::Devices::AllJoyn::AllJoynMessageInfo^ info); + // "The configuration state" // Implement this function to handle requests for the value of the State property. // // Currently, info will always be null, because no information is available about the requestor. Windows::Foundation::IAsyncOperation^ GetStateAsync(Windows::Devices::AllJoyn::AllJoynMessageInfo^ info); + // "The last error code and error message" // Implement this function to handle requests for the value of the LastError property. // // Currently, info will always be null, because no information is available about the requestor. diff --git a/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingConsumer.cpp b/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingConsumer.cpp index 746bbf8a87..783f0f682b 100644 --- a/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingConsumer.cpp +++ b/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingConsumer.cpp @@ -28,59 +28,38 @@ using namespace Windows::Devices::AllJoyn; using namespace org::alljoyn::Onboarding; std::map OnboardingConsumer::SourceInterfaces; +PCSTR OnboardingConsumer::m_interfaceName = "org.alljoyn.Onboarding"; OnboardingConsumer::OnboardingConsumer(AllJoynBusAttachment^ busAttachment) : m_busAttachment(busAttachment), m_proxyBusObject(nullptr), - m_busObject(nullptr), - m_sessionListener(nullptr), - m_sessionId(0) + m_busObject(nullptr) { m_weak = new WeakReference(this); m_signals = ref new OnboardingSignals(); m_nativeBusAttachment = AllJoynHelpers::GetInternalBusAttachment(m_busAttachment); -} -OnboardingConsumer::~OnboardingConsumer() -{ - AllJoynBusObjectManager::ReleaseBusObject(m_nativeBusAttachment, AllJoynHelpers::PlatformToMultibyteString(ServiceObjectPath).data()); - if (SessionListener != nullptr) - { - alljoyn_busattachment_setsessionlistener(m_nativeBusAttachment, m_sessionId, nullptr); - alljoyn_sessionlistener_destroy(SessionListener); - } - if (nullptr != ProxyBusObject) - { - alljoyn_proxybusobject_destroy(ProxyBusObject); - } - delete m_weak; -} + GUID result; + HRESULT hr = CoCreateGuid(&result); -void OnboardingConsumer::OnSessionLost(_In_ alljoyn_sessionid sessionId, _In_ alljoyn_sessionlostreason reason) -{ - if (sessionId == m_sessionId) + if (FAILED(hr)) { - AllJoynSessionLostEventArgs^ args = ref new AllJoynSessionLostEventArgs(static_cast(reason)); - SessionLost(this, args); + throw ref new Exception(hr); } -} -void OnboardingConsumer::OnSessionMemberAdded(_In_ alljoyn_sessionid sessionId, _In_ PCSTR uniqueName) -{ - if (sessionId == m_sessionId) - { - auto args = ref new AllJoynSessionMemberAddedEventArgs(AllJoynHelpers::MultibyteToPlatformString(uniqueName)); - SessionMemberAdded(this, args); - } + // The consumer needs a bus object to share signals, and its object path must be unique in + // case multiple consumers are created using the same bus attachment. + Guid gd(result); + ServiceObjectPath = gd.ToString(); } -void OnboardingConsumer::OnSessionMemberRemoved(_In_ alljoyn_sessionid sessionId, _In_ PCSTR uniqueName) +OnboardingConsumer::~OnboardingConsumer() { - if (sessionId == m_sessionId) + if (nullptr != ProxyBusObject) { - auto args = ref new AllJoynSessionMemberRemovedEventArgs(AllJoynHelpers::MultibyteToPlatformString(uniqueName)); - SessionMemberRemoved(this, args); + alljoyn_proxybusobject_destroy(ProxyBusObject); } + delete m_weak; } QStatus OnboardingConsumer::AddSignalHandler(_In_ alljoyn_busattachment busAttachment, _In_ alljoyn_interfacedescription interfaceDescription, _In_ PCSTR methodName, _In_ alljoyn_messagereceiver_signalhandler_ptr handler) @@ -94,14 +73,53 @@ QStatus OnboardingConsumer::AddSignalHandler(_In_ alljoyn_busattachment busAttac return alljoyn_busattachment_registersignalhandler(busAttachment, handler, member, NULL); } -IAsyncOperation^ OnboardingConsumer::JoinSessionAsync( - _In_ AllJoynServiceInfo^ serviceInfo, _Inout_ OnboardingWatcher^ watcher) +IAsyncOperation^ OnboardingConsumer::FromIdAsync(_In_ Platform::String^ deviceId) { - return create_async([serviceInfo, watcher]() -> OnboardingJoinSessionResult^ + return OnboardingConsumer::FromIdAsync(deviceId, AllJoynBusAttachment::GetDefault()); +} + +IAsyncOperation^ OnboardingConsumer::FromIdAsync(_In_ Platform::String^ deviceId, _In_ AllJoynBusAttachment^ busAttachment) +{ + return create_async([deviceId, busAttachment]() -> OnboardingConsumer^ { - auto result = ref new OnboardingJoinSessionResult(); - result->Consumer = ref new OnboardingConsumer(watcher->BusAttachment); - result->Status = result->Consumer->JoinSession(serviceInfo); + OnboardingConsumer^ result; + create_task(AllJoynServiceInfo::FromIdAsync(deviceId)).then([busAttachment, &result](AllJoynServiceInfo^ serviceInfo) + { + if (serviceInfo != nullptr) + { + int32 status = AllJoynStatus::Ok; + if (busAttachment->State == AllJoynBusAttachmentState::Disconnected) + { + event connectedEvent; + auto token = busAttachment->StateChanged += ref new TypedEventHandler([&connectedEvent](AllJoynBusAttachment^, AllJoynBusAttachmentStateChangedEventArgs^ arg) + { + if (arg->State == AllJoynBusAttachmentState::Connected) + { + connectedEvent.set(); + } + }); + + status = AllJoynHelpers::CreateInterfaces(busAttachment, c_OnboardingIntrospectionXml); + if (status == AllJoynStatus::Ok) + { + busAttachment->Connect(); + connectedEvent.wait(); + } + busAttachment->StateChanged -= token; + } + + if (status == AllJoynStatus::Ok) + { + auto consumer = ref new OnboardingConsumer(busAttachment); + status = consumer->Initialize(serviceInfo); + if (status == AllJoynStatus::Ok) + { + result = consumer; + } + } + } + }).wait(); + return result; }); } @@ -111,26 +129,26 @@ IAsyncOperation^ OnboardingConsumer::ConfigureWi return create_async([this, interfaceMemberSSID, interfaceMemberPassphrase, interfaceMemberAuthType]() -> OnboardingConfigureWiFiResult^ { auto result = ref new OnboardingConfigureWiFiResult(); - + alljoyn_message message = alljoyn_message_create(m_nativeBusAttachment); size_t argCount = 3; alljoyn_msgarg inputs = alljoyn_msgarg_array_create(argCount); QStatus status = ER_OK; + status = static_cast(TypeConversionHelpers::SetAllJoynMessageArg(alljoyn_msgarg_array_element(inputs, 0), "s", interfaceMemberSSID)); + if (ER_OK == status) + { + status = static_cast(TypeConversionHelpers::SetAllJoynMessageArg(alljoyn_msgarg_array_element(inputs, 1), "s", interfaceMemberPassphrase)); + } if (ER_OK == status) { - status = static_cast(TypeConversionHelpers::SetAllJoynMessageArg(alljoyn_msgarg_array_element(inputs, 0), "s", interfaceMemberSSID)); + status = static_cast(TypeConversionHelpers::SetAllJoynMessageArg(alljoyn_msgarg_array_element(inputs, 2), "n", interfaceMemberAuthType)); } - - status = static_cast(TypeConversionHelpers::SetAllJoynMessageArg(alljoyn_msgarg_array_element(inputs, 1), "s", interfaceMemberPassphrase)); - - status = static_cast(TypeConversionHelpers::SetAllJoynMessageArg(alljoyn_msgarg_array_element(inputs, 2), "n", interfaceMemberAuthType)); - if (ER_OK == status) { status = alljoyn_proxybusobject_methodcall( ProxyBusObject, - "org.alljoyn.Onboarding", + m_interfaceName, "ConfigureWiFi", inputs, argCount, @@ -139,7 +157,7 @@ IAsyncOperation^ OnboardingConsumer::ConfigureWi 0); } result->Status = static_cast(status); - if (ER_OK == status) + if (ER_OK == status) { result->Status = AllJoynStatus::Ok; int16 argument0; @@ -165,7 +183,7 @@ IAsyncOperation^ OnboardingConsumer::ConfigureWi } result->Status = static_cast(status); } - + alljoyn_message_destroy(message); alljoyn_msgarg_destroy(inputs); @@ -177,7 +195,7 @@ IAsyncOperation^ OnboardingConsumer::ConnectAsync() return create_async([this]() -> OnboardingConnectResult^ { auto result = ref new OnboardingConnectResult(); - + alljoyn_message message = alljoyn_message_create(m_nativeBusAttachment); size_t argCount = 0; alljoyn_msgarg inputs = alljoyn_msgarg_array_create(argCount); @@ -187,7 +205,7 @@ IAsyncOperation^ OnboardingConsumer::ConnectAsync() { status = alljoyn_proxybusobject_methodcall( ProxyBusObject, - "org.alljoyn.Onboarding", + m_interfaceName, "Connect", inputs, argCount, @@ -196,7 +214,7 @@ IAsyncOperation^ OnboardingConsumer::ConnectAsync() 0); } result->Status = static_cast(status); - + alljoyn_message_destroy(message); alljoyn_msgarg_destroy(inputs); @@ -208,7 +226,7 @@ IAsyncOperation^ OnboardingConsumer::OffboardAsync() return create_async([this]() -> OnboardingOffboardResult^ { auto result = ref new OnboardingOffboardResult(); - + alljoyn_message message = alljoyn_message_create(m_nativeBusAttachment); size_t argCount = 0; alljoyn_msgarg inputs = alljoyn_msgarg_array_create(argCount); @@ -218,7 +236,7 @@ IAsyncOperation^ OnboardingConsumer::OffboardAsync() { status = alljoyn_proxybusobject_methodcall( ProxyBusObject, - "org.alljoyn.Onboarding", + m_interfaceName, "Offboard", inputs, argCount, @@ -227,7 +245,7 @@ IAsyncOperation^ OnboardingConsumer::OffboardAsync() 0); } result->Status = static_cast(status); - + alljoyn_message_destroy(message); alljoyn_msgarg_destroy(inputs); @@ -239,7 +257,7 @@ IAsyncOperation^ OnboardingConsumer::GetScanInfoAs return create_async([this]() -> OnboardingGetScanInfoResult^ { auto result = ref new OnboardingGetScanInfoResult(); - + alljoyn_message message = alljoyn_message_create(m_nativeBusAttachment); size_t argCount = 0; alljoyn_msgarg inputs = alljoyn_msgarg_array_create(argCount); @@ -249,7 +267,7 @@ IAsyncOperation^ OnboardingConsumer::GetScanInfoAs { status = alljoyn_proxybusobject_methodcall( ProxyBusObject, - "org.alljoyn.Onboarding", + m_interfaceName, "GetScanInfo", inputs, argCount, @@ -258,7 +276,7 @@ IAsyncOperation^ OnboardingConsumer::GetScanInfoAs 0); } result->Status = static_cast(status); - if (ER_OK == status) + if (ER_OK == status) { result->Status = AllJoynStatus::Ok; uint16 argument0; @@ -292,7 +310,7 @@ IAsyncOperation^ OnboardingConsumer::GetScanInfoAs } result->Status = static_cast(status); } - + alljoyn_message_destroy(message); alljoyn_msgarg_destroy(inputs); @@ -305,10 +323,10 @@ IAsyncOperation^ OnboardingConsumer::GetVersionAsyn return create_async([this]() -> OnboardingGetVersionResult^ { PropertyGetContext getContext; - + alljoyn_proxybusobject_getpropertyasync( ProxyBusObject, - "org.alljoyn.Onboarding", + m_interfaceName, "Version", [](QStatus status, alljoyn_proxybusobject obj, const alljoyn_msgarg value, void* context) { @@ -342,10 +360,10 @@ IAsyncOperation^ OnboardingConsumer::GetStateAsync() return create_async([this]() -> OnboardingGetStateResult^ { PropertyGetContext getContext; - + alljoyn_proxybusobject_getpropertyasync( ProxyBusObject, - "org.alljoyn.Onboarding", + m_interfaceName, "State", [](QStatus status, alljoyn_proxybusobject obj, const alljoyn_msgarg value, void* context) { @@ -379,10 +397,10 @@ IAsyncOperation^ OnboardingConsumer::GetLastError return create_async([this]() -> OnboardingGetLastErrorResult^ { PropertyGetContext getContext; - + alljoyn_proxybusobject_getpropertyasync( ProxyBusObject, - "org.alljoyn.Onboarding", + m_interfaceName, "LastError", [](QStatus status, alljoyn_proxybusobject obj, const alljoyn_msgarg value, void* context) { @@ -443,63 +461,59 @@ void OnboardingConsumer::CallConnectionResultSignalHandler(_In_ const alljoyn_in } } -int32 OnboardingConsumer::JoinSession(_In_ AllJoynServiceInfo^ serviceInfo) +int32 OnboardingConsumer::Initialize(_In_ AllJoynServiceInfo^ serviceInfo) { - alljoyn_sessionlistener_callbacks callbacks = - { - AllJoynHelpers::SessionLostHandler, - AllJoynHelpers::SessionMemberAddedHandler, - AllJoynHelpers::SessionMemberRemovedHandler - }; - - alljoyn_busattachment_enableconcurrentcallbacks(AllJoynHelpers::GetInternalBusAttachment(m_busAttachment)); - - SessionListener = alljoyn_sessionlistener_create(&callbacks, m_weak); - alljoyn_sessionopts sessionOpts = alljoyn_sessionopts_create(ALLJOYN_TRAFFIC_TYPE_MESSAGES, true, ALLJOYN_PROXIMITY_ANY, ALLJOYN_TRANSPORT_ANY); - std::vector sessionNameUtf8 = AllJoynHelpers::PlatformToMultibyteString(serviceInfo->UniqueName); - RETURN_IF_QSTATUS_ERROR(alljoyn_busattachment_joinsession( - m_nativeBusAttachment, - &sessionNameUtf8[0], - serviceInfo->SessionPort, - SessionListener, - &m_sessionId, - sessionOpts)); - alljoyn_sessionopts_destroy(sessionOpts); ServiceObjectPath = serviceInfo->ObjectPath; std::vector objectPath = AllJoynHelpers::PlatformToMultibyteString(ServiceObjectPath); + RETURN_IF_QSTATUS_ERROR(AllJoynHelpers::CreateInterfaces(m_busAttachment, c_OnboardingIntrospectionXml)); + + m_session = create_task(AllJoynSession::GetFromServiceInfoAsync(serviceInfo, m_busAttachment)).get(); + if (nullptr == m_session) + { + return AllJoynStatus::Fail; + } + else if (m_session->Status != AllJoynStatus::Ok) + { + return m_session->Status; + } + if (objectPath.empty()) { return AllJoynStatus::Fail; } - ProxyBusObject = alljoyn_proxybusobject_create(m_nativeBusAttachment, &sessionNameUtf8[0], &objectPath[0], m_sessionId); + ProxyBusObject = alljoyn_proxybusobject_create(m_nativeBusAttachment, &sessionNameUtf8[0], &objectPath[0], m_session->Id); if (nullptr == ProxyBusObject) { return AllJoynStatus::Fail; } - alljoyn_interfacedescription description = alljoyn_busattachment_getinterface(m_nativeBusAttachment, "org.alljoyn.Onboarding"); + alljoyn_interfacedescription description = alljoyn_busattachment_getinterface(m_nativeBusAttachment, m_interfaceName); if (nullptr == description) { return AllJoynStatus::Fail; } - RETURN_IF_QSTATUS_ERROR(AllJoynBusObjectManager::GetBusObject(m_nativeBusAttachment, AllJoynHelpers::PlatformToMultibyteString(ServiceObjectPath).data(), &m_busObject)); - - if (!AllJoynBusObjectManager::BusObjectIsRegistered(m_nativeBusAttachment, m_busObject)) + m_busObject = ref new Windows::Devices::AllJoyn::AllJoynBusObject(ServiceObjectPath, m_busAttachment); + m_nativeBusObject = AllJoynHelpers::GetInternalBusObject(m_busObject); + + QStatus status = alljoyn_busobject_addinterface(m_nativeBusObject, description); + if ((status != ER_OK) && (status != ER_BUS_IFACE_ALREADY_EXISTS)) { - RETURN_IF_QSTATUS_ERROR(alljoyn_busobject_addinterface(BusObject, description)); + return status; } + QStatus result = AddSignalHandler( m_nativeBusAttachment, description, "ConnectionResult", [](const alljoyn_interfacedescription_member* member, PCSTR srcPath, alljoyn_message message) { UNREFERENCED_PARAMETER(srcPath); CallConnectionResultSignalHandler(member, message); }); + if (ER_OK != result) { return static_cast(result); @@ -511,7 +525,7 @@ int32 OnboardingConsumer::JoinSession(_In_ AllJoynServiceInfo^ serviceInfo) bool authenticationMechanismsContainsNone = m_busAttachment->AuthenticationMechanisms->IndexOf(AllJoynAuthenticationMechanism::None, &noneMechanismIndex); QCC_BOOL interfaceIsSecure = alljoyn_interfacedescription_issecure(description); - // If the current set of AuthenticationMechanisms supports authentication, + // If the current set of AuthenticationMechanisms supports authentication, // determine whether to secure the connection. if (AllJoynHelpers::CanSecure(m_busAttachment->AuthenticationMechanisms)) { @@ -520,11 +534,11 @@ int32 OnboardingConsumer::JoinSession(_In_ AllJoynServiceInfo^ serviceInfo) if (!authenticationMechanismsContainsNone || interfaceIsSecure) { RETURN_IF_QSTATUS_ERROR(alljoyn_proxybusobject_secureconnection(ProxyBusObject, QCC_FALSE)); - RETURN_IF_QSTATUS_ERROR(AllJoynBusObjectManager::TryRegisterBusObject(m_nativeBusAttachment, BusObject, true)); + m_busObject->Start(); } else { - RETURN_IF_QSTATUS_ERROR(AllJoynBusObjectManager::TryRegisterBusObject(m_nativeBusAttachment, BusObject, false)); + m_busObject->Start(); } } else @@ -537,13 +551,13 @@ int32 OnboardingConsumer::JoinSession(_In_ AllJoynServiceInfo^ serviceInfo) } else { - RETURN_IF_QSTATUS_ERROR(AllJoynBusObjectManager::TryRegisterBusObject(m_nativeBusAttachment, BusObject, false)); + m_busObject->Start(); } } RETURN_IF_QSTATUS_ERROR(alljoyn_proxybusobject_addinterface(ProxyBusObject, description)); - - m_signals->Initialize(BusObject, m_sessionId); + + m_signals->Initialize(this); return AllJoynStatus::Ok; } diff --git a/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingConsumer.h b/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingConsumer.h index ff1b84da82..f185881069 100644 --- a/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingConsumer.h +++ b/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingConsumer.h @@ -24,38 +24,50 @@ namespace org { namespace alljoyn { namespace Onboarding { public interface class IOnboardingConsumer { - event Windows::Foundation::TypedEventHandler^ SessionLost; - event Windows::Foundation::TypedEventHandler^ SessionMemberAdded; - event Windows::Foundation::TypedEventHandler^ SessionMemberRemoved; }; -public ref class OnboardingConsumer sealed : [Windows::Foundation::Metadata::Default] IOnboardingConsumer +public ref class OnboardingConsumer sealed : [Windows::Foundation::Metadata::Default] IOnboardingConsumer, ISignalEmitter { public: OnboardingConsumer(Windows::Devices::AllJoyn::AllJoynBusAttachment^ busAttachment); virtual ~OnboardingConsumer(); - // Join the AllJoyn session specified by sessionName. + // Create a consumer from a device Id asynchronously. // - // This will usually be called after the unique name of a producer has been reported - // in the Added callback on the Watcher. - static Windows::Foundation::IAsyncOperation^ JoinSessionAsync(_In_ Windows::Devices::AllJoyn::AllJoynServiceInfo^ serviceInfo, _Inout_ OnboardingWatcher^ watcher); + // This is usually called to create a consumer after the unique name of a producer has been reported + // in the Added callback on the DeviceWatcher. + static Windows::Foundation::IAsyncOperation^ FromIdAsync(_In_ Platform::String^ deviceId); + // Create a consumer from a device Id asynchronously with the provided bus attachment. + // + // This is usually called to create a consumer after the unique name of a producer has been reported + // in the Added callback on the DeviceWatcher. + static Windows::Foundation::IAsyncOperation^ FromIdAsync(_In_ Platform::String^ deviceId, _In_ Windows::Devices::AllJoyn::AllJoynBusAttachment^ busAttachment); + + int32 OnboardingConsumer::Initialize(_In_ Windows::Devices::AllJoyn::AllJoynServiceInfo^ serviceInfo); + + // "Sends the personal AP information to the onboardee" // Call the ConfigureWiFi method Windows::Foundation::IAsyncOperation^ ConfigureWiFiAsync(_In_ Platform::String^ interfaceMemberSSID, _In_ Platform::String^ interfaceMemberPassphrase, _In_ int16 interfaceMemberAuthType); + // "Tells the onboardee to connect to the personal AP" // Call the Connect method Windows::Foundation::IAsyncOperation^ ConnectAsync(); + // "Tells the onboardee to disconnect from the personal AP" // Call the Offboard method Windows::Foundation::IAsyncOperation^ OffboardAsync(); + // "Scans all the Wi-Fi access points in the onboardee's proximity" // Call the GetScanInfo method Windows::Foundation::IAsyncOperation^ GetScanInfoAsync(); + // "Interface version number" // Get the value of the Version property. Windows::Foundation::IAsyncOperation^ GetVersionAsync(); + // "The configuration state" // Get the value of the State property. Windows::Foundation::IAsyncOperation^ GetStateAsync(); + // "The last error code and error message" // Get the value of the LastError property. Windows::Foundation::IAsyncOperation^ GetLastErrorAsync(); @@ -66,91 +78,37 @@ public ref class OnboardingConsumer sealed : [Windows::Foundation::Metadata::De OnboardingSignals^ get() { return m_signals; } } - // This event will fire whenever the consumer loses the session that it is a member of. - virtual event Windows::Foundation::TypedEventHandler^ SessionLost - { - Windows::Foundation::EventRegistrationToken add(Windows::Foundation::TypedEventHandler^ handler) - { - return _SessionLost += ref new Windows::Foundation::EventHandler - ([handler](Platform::Object^ sender, Platform::Object^ args) - { - handler->Invoke(safe_cast(sender), safe_cast(args)); - }, Platform::CallbackContext::Same); - } - void remove(Windows::Foundation::EventRegistrationToken token) - { - _SessionLost -= token; - } - internal: - void raise(OnboardingConsumer^ sender, Windows::Devices::AllJoyn::AllJoynSessionLostEventArgs^ args) - { - _SessionLost(sender, args); - } + // Used to get the name of the interface this consumer implements. + static property Platform::String^ InterfaceName + { + Platform::String^ get() { return AllJoynHelpers::MultibyteToPlatformString(m_interfaceName); } } - // This event will fire whenever a member joins the session. - virtual event Windows::Foundation::TypedEventHandler^ SessionMemberAdded - { - Windows::Foundation::EventRegistrationToken add(Windows::Foundation::TypedEventHandler^ handler) - { - return _SessionMemberAdded += ref new Windows::Foundation::EventHandler - ([handler](Platform::Object^ sender, Platform::Object^ args) - { - handler->Invoke(safe_cast(sender), safe_cast(args)); - }, Platform::CallbackContext::Same); - } - void remove(Windows::Foundation::EventRegistrationToken token) - { - _SessionMemberAdded -= token; - } - internal: - void raise(OnboardingConsumer^ sender, Windows::Devices::AllJoyn::AllJoynSessionMemberAddedEventArgs^ args) - { - _SessionMemberAdded(sender, args); - } + virtual property Windows::Devices::AllJoyn::AllJoynBusObject^ BusObject + { + Windows::Devices::AllJoyn::AllJoynBusObject^ get() { return m_busObject; } } - // This event will fire whenever a member leaves the session. - virtual event Windows::Foundation::TypedEventHandler^ SessionMemberRemoved - { - Windows::Foundation::EventRegistrationToken add(Windows::Foundation::TypedEventHandler^ handler) - { - return _SessionMemberRemoved += ref new Windows::Foundation::EventHandler - ([handler](Platform::Object^ sender, Platform::Object^ args) - { - handler->Invoke(safe_cast(sender), safe_cast(args)); - }, Platform::CallbackContext::Same); - } - void remove(Windows::Foundation::EventRegistrationToken token) - { - _SessionMemberRemoved -= token; - } - internal: - void raise(OnboardingConsumer^ sender, Windows::Devices::AllJoyn::AllJoynSessionMemberRemovedEventArgs^ args) - { - _SessionMemberRemoved(sender, args); - } + virtual property Windows::Devices::AllJoyn::AllJoynSession^ Session + { + Windows::Devices::AllJoyn::AllJoynSession^ get() { return m_session; } } internal: // Consumers do not support property get. - QStatus OnPropertyGet(_In_ PCSTR interfaceName, _In_ PCSTR propertyName, _Inout_ alljoyn_msgarg val) - { - UNREFERENCED_PARAMETER(interfaceName); UNREFERENCED_PARAMETER(propertyName); UNREFERENCED_PARAMETER(val); - return ER_NOT_IMPLEMENTED; + QStatus OnPropertyGet(_In_ PCSTR interfaceName, _In_ PCSTR propertyName, _Inout_ alljoyn_msgarg val) + { + UNREFERENCED_PARAMETER(interfaceName); UNREFERENCED_PARAMETER(propertyName); UNREFERENCED_PARAMETER(val); + return ER_NOT_IMPLEMENTED; } // Consumers do not support property set. - QStatus OnPropertySet(_In_ PCSTR interfaceName, _In_ PCSTR propertyName, _In_ alljoyn_msgarg val) - { + QStatus OnPropertySet(_In_ PCSTR interfaceName, _In_ PCSTR propertyName, _In_ alljoyn_msgarg val) + { UNREFERENCED_PARAMETER(interfaceName); UNREFERENCED_PARAMETER(propertyName); UNREFERENCED_PARAMETER(val); return ER_NOT_IMPLEMENTED; } - void OnSessionLost(_In_ alljoyn_sessionid sessionId, _In_ alljoyn_sessionlostreason reason); - void OnSessionMemberAdded(_In_ alljoyn_sessionid sessionId, _In_ PCSTR uniqueName); - void OnSessionMemberRemoved(_In_ alljoyn_sessionid sessionId, _In_ PCSTR uniqueName); - void OnPropertyChanged(_In_ alljoyn_proxybusobject obj, _In_ PCSTR interfaceName, _In_ const alljoyn_msgarg changed, _In_ const alljoyn_msgarg invalidated); property Platform::String^ ServiceObjectPath @@ -165,43 +123,26 @@ public ref class OnboardingConsumer sealed : [Windows::Foundation::Metadata::De void set(alljoyn_proxybusobject value) { m_proxyBusObject = value; } } - property alljoyn_busobject BusObject - { - alljoyn_busobject get() { return m_busObject; } - void set(alljoyn_busobject value) { m_busObject = value; } - } - - property alljoyn_sessionlistener SessionListener - { - alljoyn_sessionlistener get() { return m_sessionListener; } - void set(alljoyn_sessionlistener value) { m_sessionListener = value; } - } - - property alljoyn_sessionid SessionId - { - alljoyn_sessionid get() { return m_sessionId; } - } - private: virtual event Windows::Foundation::EventHandler^ _SessionLost; virtual event Windows::Foundation::EventHandler^ _SessionMemberAdded; virtual event Windows::Foundation::EventHandler^ _SessionMemberRemoved; - int32 JoinSession(_In_ Windows::Devices::AllJoyn::AllJoynServiceInfo^ serviceInfo); - // Register a callback function to handle incoming signals. QStatus AddSignalHandler(_In_ alljoyn_busattachment busAttachment, _In_ alljoyn_interfacedescription interfaceDescription, _In_ PCSTR methodName, _In_ alljoyn_messagereceiver_signalhandler_ptr handler); + // "This signal is emitted when the connection attempt against the personal AP is completed" static void CallConnectionResultSignalHandler(_In_ const alljoyn_interfacedescription_member* member, _In_ alljoyn_message message); - + Windows::Devices::AllJoyn::AllJoynBusAttachment^ m_busAttachment; + Windows::Devices::AllJoyn::AllJoynBusObject^ m_busObject; + Windows::Devices::AllJoyn::AllJoynSession^ m_session; OnboardingSignals^ m_signals; Platform::String^ m_ServiceObjectPath; alljoyn_proxybusobject m_proxyBusObject; - alljoyn_busobject m_busObject; alljoyn_sessionlistener m_sessionListener; - alljoyn_sessionid m_sessionId; + alljoyn_busobject m_nativeBusObject; alljoyn_busattachment m_nativeBusAttachment; // Used to pass a pointer to this class to callbacks @@ -211,6 +152,9 @@ public ref class OnboardingConsumer sealed : [Windows::Foundation::Metadata::De // handlers, but the current AllJoyn C API does not allow passing a context to these // callbacks. static std::map SourceInterfaces; + + // The name of the interface this consumer implements. + static PCSTR m_interfaceName; }; } } } diff --git a/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingEventArgs.h b/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingEventArgs.h index 5b9cee1df3..ff8beb311c 100644 --- a/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingEventArgs.h +++ b/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingEventArgs.h @@ -23,6 +23,7 @@ namespace org { namespace alljoyn { namespace Onboarding { // Signals +// "This signal is emitted when the connection attempt against the personal AP is completed" public ref class OnboardingConnectionResultReceivedEventArgs sealed { public: diff --git a/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingLegacySignals.cpp b/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingLegacySignals.cpp new file mode 100644 index 0000000000..3943ad7944 --- /dev/null +++ b/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingLegacySignals.cpp @@ -0,0 +1,67 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// This code is licensed under the MIT License (MIT). +// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY +// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR +// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. +// +//********************************************************* +//----------------------------------------------------------------------------- +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// For more information, see: http://go.microsoft.com/fwlink/?LinkID=623246 +// +//----------------------------------------------------------------------------- +#include "pch.h" + +using namespace Microsoft::WRL; +using namespace Platform; +using namespace Windows::Devices::AllJoyn; +using namespace Windows::Foundation; +using namespace org::alljoyn::Onboarding; + +void OnboardingLegacySignals::Initialize(_In_ alljoyn_busobject busObject, _In_ alljoyn_sessionid sessionId) +{ + m_busObject = busObject; + m_sessionId = sessionId; + + auto interfaceDefinition = alljoyn_busattachment_getinterface(alljoyn_busobject_getbusattachment(busObject), "org.alljoyn.Onboarding"); + alljoyn_interfacedescription_getmember(interfaceDefinition, "ConnectionResult", &m_memberConnectionResult); +} + +void OnboardingLegacySignals::ConnectionResult(_In_ Onboarding^ interfaceMemberArg) +{ + if (nullptr == m_busObject) + { + return; + } + + size_t argCount = 1; + alljoyn_msgarg arguments = alljoyn_msgarg_array_create(argCount); + (void)TypeConversionHelpers::SetAllJoynMessageArg(alljoyn_msgarg_array_element(arguments, 0), "(ns)", interfaceMemberArg); + + alljoyn_busobject_signal( + m_busObject, + NULL, // Generated code only supports broadcast signals. + m_sessionId, + m_memberConnectionResult, + arguments, + argCount, + 0, // A signal with a TTL of 0 will be sent to every member of the session, regardless of how long it takes to deliver the message + ALLJOYN_MESSAGE_FLAG_GLOBAL_BROADCAST, // Broadcast to everyone in the session. + NULL); // The generated code does not need the generated signal message + + alljoyn_msgarg_destroy(arguments); +} + +void OnboardingLegacySignals::CallConnectionResultReceived(_In_ OnboardingLegacySignals^ sender, _In_ OnboardingConnectionResultReceivedEventArgs^ args) +{ + ConnectionResultReceived(sender, args); +} + diff --git a/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingLegacySignals.h b/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingLegacySignals.h new file mode 100644 index 0000000000..3e3aac566d --- /dev/null +++ b/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingLegacySignals.h @@ -0,0 +1,74 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// This code is licensed under the MIT License (MIT). +// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY +// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR +// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. +// +//********************************************************* +//----------------------------------------------------------------------------- +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// For more information, see: http://go.microsoft.com/fwlink/?LinkID=623246 +// +//----------------------------------------------------------------------------- +#pragma once + +namespace org { namespace alljoyn { namespace Onboarding { + +ref class OnboardingLegacySignals; + +public interface class IOnboardingLegacySignals +{ + event Windows::Foundation::TypedEventHandler^ ConnectionResultReceived; +}; + +public ref class OnboardingLegacySignals sealed : [Windows::Foundation::Metadata::Default] IOnboardingLegacySignals +{ +public: + // "This signal is emitted when the connection attempt against the personal AP is completed" + // Calling this method will send the ConnectionResult signal to every member of the session. + void ConnectionResult(_In_ Onboarding^ interfaceMemberArg); + + // This event fires whenever the ConnectionResult signal is sent by another member of the session. + virtual event Windows::Foundation::TypedEventHandler^ ConnectionResultReceived + { + Windows::Foundation::EventRegistrationToken add(Windows::Foundation::TypedEventHandler^ handler) + { + return _ConnectionResultReceived += ref new Windows::Foundation::EventHandler + ([handler](Platform::Object^ sender, Platform::Object^ args) + { + handler->Invoke(safe_cast(sender), safe_cast(args)); + }, Platform::CallbackContext::Same); + } + void remove(Windows::Foundation::EventRegistrationToken token) + { + _ConnectionResultReceived -= token; + } + internal: + void raise(OnboardingLegacySignals^ sender, OnboardingConnectionResultReceivedEventArgs^ args) + { + _ConnectionResultReceived(sender, args); + } + } + +internal: + void Initialize(_In_ alljoyn_busobject busObject, _In_ alljoyn_sessionid sessionId); + void CallConnectionResultReceived(_In_ OnboardingLegacySignals^ sender, _In_ OnboardingConnectionResultReceivedEventArgs^ args); + +private: + alljoyn_busobject m_busObject; + alljoyn_sessionid m_sessionId; + + virtual event Windows::Foundation::EventHandler^ _ConnectionResultReceived; + + alljoyn_interfacedescription_member m_memberConnectionResult; +}; + +} } } \ No newline at end of file diff --git a/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingMethodResults.h b/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingMethodResults.h index 538d345cb3..eabd9c7507 100644 --- a/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingMethodResults.h +++ b/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingMethodResults.h @@ -210,6 +210,7 @@ public ref class OnboardingGetVersionResult sealed void set(_In_ int32 value) { m_status = value; } } + // "Interface version number" property uint16 Version { uint16 get() { return m_value; } @@ -250,6 +251,7 @@ public ref class OnboardingGetStateResult sealed void set(_In_ int32 value) { m_status = value; } } + // "The configuration state" property int16 State { int16 get() { return m_value; } @@ -290,6 +292,7 @@ public ref class OnboardingGetLastErrorResult sealed void set(_In_ int32 value) { m_status = value; } } + // "The last error code and error message" property OnboardingLastError^ LastError { OnboardingLastError^ get() { return m_value; } diff --git a/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingProducer.cpp b/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingProducer.cpp index 053efac993..904d310aeb 100644 --- a/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingProducer.cpp +++ b/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingProducer.cpp @@ -39,7 +39,7 @@ OnboardingProducer::OnboardingProducer(AllJoynBusAttachment^ busAttachment) { m_weak = new WeakReference(this); ServiceObjectPath = ref new String(L"/Service"); - m_signals = ref new OnboardingSignals(); + m_signals = ref new OnboardingLegacySignals(); m_busAttachmentStateChangedToken.Value = 0; } @@ -635,4 +635,4 @@ PCSTR org::alljoyn::Onboarding::c_OnboardingIntrospectionXml = "" " " "" -; +; \ No newline at end of file diff --git a/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingProducer.h b/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingProducer.h index e93d5f6526..497043ca94 100644 --- a/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingProducer.h +++ b/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingProducer.h @@ -48,9 +48,9 @@ public ref class OnboardingProducer sealed : [Windows::Foundation::Metadata::Def } // Used to send signals or register functions to handle received signals. - property OnboardingSignals^ Signals + property OnboardingLegacySignals^ Signals { - OnboardingSignals^ get() { return m_signals; } + OnboardingLegacySignals^ get() { return m_signals; } } // This event will fire whenever this producer is stopped. @@ -206,10 +206,15 @@ public ref class OnboardingProducer sealed : [Windows::Foundation::Metadata::Def virtual event Windows::Foundation::EventHandler^ _SessionMemberAdded; virtual event Windows::Foundation::EventHandler^ _SessionMemberRemoved; + // "Sends the personal AP information to the onboardee" static void CallConfigureWiFiHandler(_Inout_ alljoyn_busobject busObject, _In_ alljoyn_message message); + // "Tells the onboardee to connect to the personal AP" static void CallConnectHandler(_Inout_ alljoyn_busobject busObject, _In_ alljoyn_message message); + // "Tells the onboardee to disconnect from the personal AP" static void CallOffboardHandler(_Inout_ alljoyn_busobject busObject, _In_ alljoyn_message message); + // "Scans all the Wi-Fi access points in the onboardee's proximity" static void CallGetScanInfoHandler(_Inout_ alljoyn_busobject busObject, _In_ alljoyn_message message); + // "This signal is emitted when the connection attempt against the personal AP is completed" static void CallConnectionResultSignalHandler(_In_ const alljoyn_interfacedescription_member* member, _In_ alljoyn_message message); // Register a callback function to handle methods. @@ -221,7 +226,7 @@ public ref class OnboardingProducer sealed : [Windows::Foundation::Metadata::Def Windows::Devices::AllJoyn::AllJoynBusAttachment^ m_busAttachment; Windows::Foundation::EventRegistrationToken m_busAttachmentStateChangedToken; - OnboardingSignals^ m_signals; + OnboardingLegacySignals^ m_signals; IOnboardingService^ m_serviceInterface; Platform::String^ m_ServiceObjectPath; @@ -241,4 +246,4 @@ public ref class OnboardingProducer sealed : [Windows::Foundation::Metadata::Def static std::map SourceInterfaces; }; -} } } +} } } \ No newline at end of file diff --git a/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingServiceEventAdapter.cpp b/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingServiceEventAdapter.cpp index abdc80b635..1a86b78f0c 100644 --- a/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingServiceEventAdapter.cpp +++ b/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingServiceEventAdapter.cpp @@ -9,24 +9,13 @@ // //********************************************************* //----------------------------------------------------------------------------- -// -// This code was generated by a tool. -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -// Tool: AllJoynCodeGenerator.exe +// +// This code was generated by a tool. // -// This tool is located in the Windows 10 SDK and the Windows 10 AllJoyn -// Visual Studio Extension in the Visual Studio Gallery. -// -// The generated code should be packaged in a Windows 10 C++/CX Runtime -// Component which can be consumed in any UWP-supported language using -// APIs that are available in Windows.Devices.AllJoyn. +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. // -// Using AllJoynCodeGenerator - Invoke the following command with a valid -// Introspection XML file and a writable output directory: -// AllJoynCodeGenerator -i -o +// For more information, see: http://go.microsoft.com/fwlink/?LinkID=623246 // //----------------------------------------------------------------------------- #include "pch.h" diff --git a/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingServiceEventAdapter.h b/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingServiceEventAdapter.h index b9fcff51e7..c6a5f2a4d8 100644 --- a/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingServiceEventAdapter.h +++ b/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingServiceEventAdapter.h @@ -9,24 +9,13 @@ // //********************************************************* //----------------------------------------------------------------------------- -// -// This code was generated by a tool. -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -// Tool: AllJoynCodeGenerator.exe +// +// This code was generated by a tool. // -// This tool is located in the Windows 10 SDK and the Windows 10 AllJoyn -// Visual Studio Extension in the Visual Studio Gallery. -// -// The generated code should be packaged in a Windows 10 C++/CX Runtime -// Component which can be consumed in any UWP-supported language using -// APIs that are available in Windows.Devices.AllJoyn. +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. // -// Using AllJoynCodeGenerator - Invoke the following command with a valid -// Introspection XML file and a writable output directory: -// AllJoynCodeGenerator -i -o +// For more information, see: http://go.microsoft.com/fwlink/?LinkID=623246 // //----------------------------------------------------------------------------- #pragma once diff --git a/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingServiceEventArgs.cpp b/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingServiceEventArgs.cpp index 19e7b05b6f..fde0ade6cb 100644 --- a/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingServiceEventArgs.cpp +++ b/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingServiceEventArgs.cpp @@ -9,24 +9,13 @@ // //********************************************************* //----------------------------------------------------------------------------- -// -// This code was generated by a tool. -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -// Tool: AllJoynCodeGenerator.exe +// +// This code was generated by a tool. // -// This tool is located in the Windows 10 SDK and the Windows 10 AllJoyn -// Visual Studio Extension in the Visual Studio Gallery. -// -// The generated code should be packaged in a Windows 10 C++/CX Runtime -// Component which can be consumed in any UWP-supported language using -// APIs that are available in Windows.Devices.AllJoyn. +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. // -// Using AllJoynCodeGenerator - Invoke the following command with a valid -// Introspection XML file and a writable output directory: -// AllJoynCodeGenerator -i -o +// For more information, see: http://go.microsoft.com/fwlink/?LinkID=623246 // //----------------------------------------------------------------------------- #include "pch.h" @@ -53,7 +42,7 @@ OnboardingConfigureWiFiCalledEventArgs::OnboardingConfigureWiFiCalledEventArgs( m_interfaceMemberPassphrase(interfaceMemberPassphrase), m_interfaceMemberAuthType(interfaceMemberAuthType) { - m_result = OnboardingConfigureWiFiResult::CreateFailureResult(ER_NOT_IMPLEMENTED); + m_result = OnboardingConfigureWiFiResult::CreateFailureResult(ER_NOT_IMPLEMENTED); } Deferral^ OnboardingConfigureWiFiCalledEventArgs::GetDeferral() @@ -128,7 +117,7 @@ OnboardingConnectCalledEventArgs::OnboardingConnectCalledEventArgs( m_completionsRequired(0), m_messageInfo(info) { - m_result = OnboardingConnectResult::CreateFailureResult(ER_NOT_IMPLEMENTED); + m_result = OnboardingConnectResult::CreateFailureResult(ER_NOT_IMPLEMENTED); } Deferral^ OnboardingConnectCalledEventArgs::GetDeferral() @@ -203,7 +192,7 @@ OnboardingOffboardCalledEventArgs::OnboardingOffboardCalledEventArgs( m_completionsRequired(0), m_messageInfo(info) { - m_result = OnboardingOffboardResult::CreateFailureResult(ER_NOT_IMPLEMENTED); + m_result = OnboardingOffboardResult::CreateFailureResult(ER_NOT_IMPLEMENTED); } Deferral^ OnboardingOffboardCalledEventArgs::GetDeferral() @@ -278,7 +267,7 @@ OnboardingGetScanInfoCalledEventArgs::OnboardingGetScanInfoCalledEventArgs( m_completionsRequired(0), m_messageInfo(info) { - m_result = OnboardingGetScanInfoResult::CreateFailureResult(ER_NOT_IMPLEMENTED); + m_result = OnboardingGetScanInfoResult::CreateFailureResult(ER_NOT_IMPLEMENTED); } Deferral^ OnboardingGetScanInfoCalledEventArgs::GetDeferral() @@ -354,7 +343,7 @@ OnboardingGetVersionRequestedEventArgs::OnboardingGetVersionRequestedEventArgs( m_completionsRequired(0), m_messageInfo(info) { - m_result = OnboardingGetVersionResult::CreateFailureResult(ER_NOT_IMPLEMENTED); + m_result = OnboardingGetVersionResult::CreateFailureResult(ER_NOT_IMPLEMENTED); } Deferral^ OnboardingGetVersionRequestedEventArgs::GetDeferral() @@ -429,7 +418,7 @@ OnboardingGetStateRequestedEventArgs::OnboardingGetStateRequestedEventArgs( m_completionsRequired(0), m_messageInfo(info) { - m_result = OnboardingGetStateResult::CreateFailureResult(ER_NOT_IMPLEMENTED); + m_result = OnboardingGetStateResult::CreateFailureResult(ER_NOT_IMPLEMENTED); } Deferral^ OnboardingGetStateRequestedEventArgs::GetDeferral() @@ -504,7 +493,7 @@ OnboardingGetLastErrorRequestedEventArgs::OnboardingGetLastErrorRequestedEventAr m_completionsRequired(0), m_messageInfo(info) { - m_result = OnboardingGetLastErrorResult::CreateFailureResult(ER_NOT_IMPLEMENTED); + m_result = OnboardingGetLastErrorResult::CreateFailureResult(ER_NOT_IMPLEMENTED); } Deferral^ OnboardingGetLastErrorRequestedEventArgs::GetDeferral() diff --git a/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingServiceEventArgs.h b/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingServiceEventArgs.h index 3610c12a76..d09643578e 100644 --- a/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingServiceEventArgs.h +++ b/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingServiceEventArgs.h @@ -9,24 +9,13 @@ // //********************************************************* //----------------------------------------------------------------------------- -// -// This code was generated by a tool. -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -// Tool: AllJoynCodeGenerator.exe +// +// This code was generated by a tool. // -// This tool is located in the Windows 10 SDK and the Windows 10 AllJoyn -// Visual Studio Extension in the Visual Studio Gallery. -// -// The generated code should be packaged in a Windows 10 C++/CX Runtime -// Component which can be consumed in any UWP-supported language using -// APIs that are available in Windows.Devices.AllJoyn. +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. // -// Using AllJoynCodeGenerator - Invoke the following command with a valid -// Introspection XML file and a writable output directory: -// AllJoynCodeGenerator -i -o +// For more information, see: http://go.microsoft.com/fwlink/?LinkID=623246 // //----------------------------------------------------------------------------- #pragma once diff --git a/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingSignals.cpp b/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingSignals.cpp index 78d54a8d2c..5baf4b55f6 100644 --- a/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingSignals.cpp +++ b/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingSignals.cpp @@ -26,18 +26,17 @@ using namespace Windows::Devices::AllJoyn; using namespace Windows::Foundation; using namespace org::alljoyn::Onboarding; -void OnboardingSignals::Initialize(_In_ alljoyn_busobject busObject, _In_ alljoyn_sessionid sessionId) +void OnboardingSignals::Initialize(_In_ ISignalEmitter^ emitter) { - m_busObject = busObject; - m_sessionId = sessionId; - - auto interfaceDefinition = alljoyn_busattachment_getinterface(alljoyn_busobject_getbusattachment(busObject), "org.alljoyn.Onboarding"); + m_emitter = emitter; + alljoyn_busattachment nativeBusAttachment = AllJoynHelpers::GetInternalBusAttachment(m_emitter->BusObject->BusAttachment); + auto interfaceDefinition = alljoyn_busattachment_getinterface(nativeBusAttachment, "org.alljoyn.Onboarding"); alljoyn_interfacedescription_getmember(interfaceDefinition, "ConnectionResult", &m_memberConnectionResult); } void OnboardingSignals::ConnectionResult(_In_ Onboarding^ interfaceMemberArg) { - if (nullptr == m_busObject) + if (nullptr == AllJoynHelpers::GetInternalBusObject(m_emitter->BusObject)) { return; } @@ -47,9 +46,9 @@ void OnboardingSignals::ConnectionResult(_In_ Onboarding^ interfaceMemberArg) (void)TypeConversionHelpers::SetAllJoynMessageArg(alljoyn_msgarg_array_element(arguments, 0), "(ns)", interfaceMemberArg); alljoyn_busobject_signal( - m_busObject, + AllJoynHelpers::GetInternalBusObject(m_emitter->BusObject), NULL, // Generated code only supports broadcast signals. - m_sessionId, + m_emitter->Session->Id, m_memberConnectionResult, arguments, argCount, diff --git a/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingSignals.h b/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingSignals.h index 1453c464cc..c6a6adb804 100644 --- a/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingSignals.h +++ b/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingSignals.h @@ -32,6 +32,7 @@ public interface class IOnboardingSignals public ref class OnboardingSignals sealed : [Windows::Foundation::Metadata::Default] IOnboardingSignals { public: + // "This signal is emitted when the connection attempt against the personal AP is completed" // Calling this method will send the ConnectionResult signal to every member of the session. void ConnectionResult(_In_ Onboarding^ interfaceMemberArg); @@ -58,12 +59,11 @@ public ref class OnboardingSignals sealed : [Windows::Foundation::Metadata::Defa } internal: - void Initialize(_In_ alljoyn_busobject busObject, _In_ alljoyn_sessionid sessionId); + void Initialize(_In_ ISignalEmitter^ emitter); void CallConnectionResultReceived(_In_ OnboardingSignals^ sender, _In_ OnboardingConnectionResultReceivedEventArgs^ args); private: - alljoyn_busobject m_busObject; - alljoyn_sessionid m_sessionId; + ISignalEmitter^ m_emitter; virtual event Windows::Foundation::EventHandler^ _ConnectionResultReceived; diff --git a/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingWatcher.cpp b/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingWatcher.cpp deleted file mode 100644 index 2d284cb4d5..0000000000 --- a/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingWatcher.cpp +++ /dev/null @@ -1,142 +0,0 @@ -//********************************************************* -// -// Copyright (c) Microsoft. All rights reserved. -// This code is licensed under the MIT License (MIT). -// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF -// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY -// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR -// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. -// -//********************************************************* -//----------------------------------------------------------------------------- -// -// This code was generated by a tool. -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -// For more information, see: http://go.microsoft.com/fwlink/?LinkID=623246 -// -//----------------------------------------------------------------------------- -#include "pch.h" - -using namespace concurrency; -using namespace Microsoft::WRL; -using namespace Platform; -using namespace Windows::Foundation; -using namespace Windows::Devices::AllJoyn; -using namespace org::alljoyn::Onboarding; - -OnboardingWatcher::OnboardingWatcher(AllJoynBusAttachment^ busAttachment) : - m_aboutListener(nullptr) -{ - m_busAttachment = busAttachment; - m_weak = new WeakReference(this); - m_busAttachmentStateChangedToken.Value = 0; -} - -OnboardingWatcher::~OnboardingWatcher() -{ - UnregisterFromBus(); -} - -void OnboardingWatcher::UnregisterFromBus() -{ - if (nullptr != m_aboutListener) - { - PCSTR interfaces[] = { "org.alljoyn.Onboarding" }; - alljoyn_busattachment_cancelwhoimplements_interfaces( - AllJoynHelpers::GetInternalBusAttachment(m_busAttachment), - interfaces, - _countof(interfaces)); - - alljoyn_busattachment_unregisteraboutlistener(AllJoynHelpers::GetInternalBusAttachment(m_busAttachment), m_aboutListener); - alljoyn_aboutlistener_destroy(m_aboutListener); - m_aboutListener = nullptr; - } - if ((nullptr != m_busAttachment) && (0 != m_busAttachmentStateChangedToken.Value)) - { - m_busAttachment->StateChanged -= m_busAttachmentStateChangedToken; - } -} - -void OnboardingWatcher::OnAnnounce( - _In_ PCSTR name, - _In_ uint16_t version, - _In_ alljoyn_sessionport port, - _In_ alljoyn_msgarg objectDescriptionArg, - _In_ const alljoyn_msgarg aboutDataArg) -{ - UNREFERENCED_PARAMETER(version); - UNREFERENCED_PARAMETER(aboutDataArg); - - alljoyn_aboutobjectdescription objectDescription = alljoyn_aboutobjectdescription_create_full(objectDescriptionArg); - - if (alljoyn_aboutobjectdescription_hasinterface(objectDescription, "org.alljoyn.Onboarding")) - { - AllJoynServiceInfo^ args = ref new AllJoynServiceInfo( - AllJoynHelpers::MultibyteToPlatformString(name), - AllJoynHelpers::GetObjectPath(objectDescription, "org.alljoyn.Onboarding"), - port); - Added(this, args); - } - alljoyn_aboutobjectdescription_destroy(objectDescription); -} - -void OnboardingWatcher::BusAttachmentStateChanged(_In_ AllJoynBusAttachment^ sender, _In_ AllJoynBusAttachmentStateChangedEventArgs^ args) -{ - if (args->State == AllJoynBusAttachmentState::Connected) - { - alljoyn_aboutlistener_callback callbacks = - { - AllJoynHelpers::AnnounceHandler - }; - m_aboutListener = alljoyn_aboutlistener_create(&callbacks, m_weak); - - alljoyn_busattachment_registeraboutlistener(AllJoynHelpers::GetInternalBusAttachment(sender), m_aboutListener); - PCSTR interfaces[] = { "org.alljoyn.Onboarding" }; - - auto status = alljoyn_busattachment_whoimplements_interfaces( - AllJoynHelpers::GetInternalBusAttachment(sender), - interfaces, - _countof(interfaces)); - if (ER_OK != status) - { - StopInternal(status); - } - } - else if (args->State == AllJoynBusAttachmentState::Disconnected) - { - StopInternal(ER_BUS_STOPPING); - } -} - -void OnboardingWatcher::Start() -{ - if (nullptr == m_busAttachment) - { - StopInternal(ER_FAIL); - return; - } - - int32 result = AllJoynHelpers::CreateInterfaces(m_busAttachment, c_OnboardingIntrospectionXml); - if (result != AllJoynStatus::Ok) - { - StopInternal(result); - return; - } - - m_busAttachmentStateChangedToken = m_busAttachment->StateChanged += ref new TypedEventHandler(this, &OnboardingWatcher::BusAttachmentStateChanged); - m_busAttachment->Connect(); -} - -void OnboardingWatcher::Stop() -{ - StopInternal(AllJoynStatus::Ok); -} - -void OnboardingWatcher::StopInternal(int32 status) -{ - UnregisterFromBus(); - Stopped(this, ref new AllJoynProducerStoppedEventArgs(status)); -} \ No newline at end of file diff --git a/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingWatcher.h b/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingWatcher.h deleted file mode 100644 index 48a811a800..0000000000 --- a/Samples/AllJoyn/Common/Scenario2WinRTComponent/OnboardingWatcher.h +++ /dev/null @@ -1,127 +0,0 @@ -//********************************************************* -// -// Copyright (c) Microsoft. All rights reserved. -// This code is licensed under the MIT License (MIT). -// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF -// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY -// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR -// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. -// -//********************************************************* -//----------------------------------------------------------------------------- -// -// This code was generated by a tool. -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -// For more information, see: http://go.microsoft.com/fwlink/?LinkID=623246 -// -//----------------------------------------------------------------------------- -#pragma once - -namespace org { namespace alljoyn { namespace Onboarding { - -ref class OnboardingWatcher; - -public interface class IOnboardingWatcher -{ - event Windows::Foundation::TypedEventHandler^ Added; - event Windows::Foundation::TypedEventHandler^ Stopped; -}; - -public ref class OnboardingWatcher sealed : [Windows::Foundation::Metadata::Default] IOnboardingWatcher -{ -public: - OnboardingWatcher(Windows::Devices::AllJoyn::AllJoynBusAttachment^ busAttachment); - virtual ~OnboardingWatcher(); - - // This event will fire whenever a producer for this service is found. - virtual event Windows::Foundation::TypedEventHandler^ Added - { - Windows::Foundation::EventRegistrationToken add(Windows::Foundation::TypedEventHandler^ handler) - { - return _Added += ref new Windows::Foundation::EventHandler - ([handler](Platform::Object^ sender, Platform::Object^ args) - { - handler->Invoke(safe_cast(sender), safe_cast(args)); - }, Platform::CallbackContext::Same); - } - void remove(Windows::Foundation::EventRegistrationToken token) - { - _Added -= token; - } - internal: - void raise(OnboardingWatcher^ sender, Windows::Devices::AllJoyn::AllJoynServiceInfo^ args) - { - _Added(sender, args); - } - } - - // This event will fire whenever the watcher is stopped. - virtual event Windows::Foundation::TypedEventHandler^ Stopped - { - Windows::Foundation::EventRegistrationToken add(Windows::Foundation::TypedEventHandler^ handler) - { - return _Stopped += ref new Windows::Foundation::EventHandler - ([handler](Platform::Object^ sender, Platform::Object^ args) - { - handler->Invoke(safe_cast(sender), safe_cast(args)); - }, Platform::CallbackContext::Same); - } - void remove(Windows::Foundation::EventRegistrationToken token) - { - _Stopped -= token; - } - internal: - void raise(OnboardingWatcher^ sender, Windows::Devices::AllJoyn::AllJoynProducerStoppedEventArgs^ args) - { - _Stopped(sender, args); - } - } - - // Start watching for producers advertising this service. - void Start(); - - // Stop watching for producers for this service. - void Stop(); - -internal: - void OnAnnounce( - _In_ PCSTR name, - _In_ uint16_t version, - _In_ alljoyn_sessionport port, - _In_ alljoyn_msgarg objectDescriptionArg, - _In_ const alljoyn_msgarg aboutDataArg); - - void OnPropertyChanged(_In_ PCSTR prop_name, _In_ alljoyn_msgarg prop_value) - { - UNREFERENCED_PARAMETER(prop_name); UNREFERENCED_PARAMETER(prop_value); - } - - property Windows::Devices::AllJoyn::AllJoynBusAttachment^ BusAttachment - { - Windows::Devices::AllJoyn::AllJoynBusAttachment^ get() { return m_busAttachment; } - } - - // Stop watching for producers advertising this service and pass status to anyone listening for the Stopped event. - void StopInternal(int32 status); - - void BusAttachmentStateChanged(_In_ Windows::Devices::AllJoyn::AllJoynBusAttachment^ sender, _In_ Windows::Devices::AllJoyn::AllJoynBusAttachmentStateChangedEventArgs^ args); - -private: - virtual event Windows::Foundation::EventHandler^ _Added; - virtual event Windows::Foundation::EventHandler^ _Stopped; - - void UnregisterFromBus(); - - Windows::Devices::AllJoyn::AllJoynBusAttachment^ m_busAttachment; - Windows::Foundation::EventRegistrationToken m_busAttachmentStateChangedToken; - - alljoyn_aboutlistener m_aboutListener; - - // Used to pass a pointer to this class to callbacks. - Platform::WeakReference* m_weak; -}; - -} } } \ No newline at end of file diff --git a/Samples/AllJoyn/Common/Scenario2WinRTComponent/Scenario2WinRTComponent.vcxproj b/Samples/AllJoyn/Common/Scenario2WinRTComponent/Scenario2WinRTComponent.vcxproj index 2e88d35a2e..ad22319a04 100644 --- a/Samples/AllJoyn/Common/Scenario2WinRTComponent/Scenario2WinRTComponent.vcxproj +++ b/Samples/AllJoyn/Common/Scenario2WinRTComponent/Scenario2WinRTComponent.vcxproj @@ -221,17 +221,17 @@ - + + - @@ -239,11 +239,11 @@ + - Create Create diff --git a/Samples/AllJoyn/Common/Scenario2WinRTComponent/Scenario2WinRTComponent.vcxproj.filters b/Samples/AllJoyn/Common/Scenario2WinRTComponent/Scenario2WinRTComponent.vcxproj.filters index 00ac637f66..bc561c71cb 100644 --- a/Samples/AllJoyn/Common/Scenario2WinRTComponent/Scenario2WinRTComponent.vcxproj.filters +++ b/Samples/AllJoyn/Common/Scenario2WinRTComponent/Scenario2WinRTComponent.vcxproj.filters @@ -11,27 +11,27 @@ + - - + + - \ No newline at end of file diff --git a/Samples/AllJoyn/Common/Scenario2WinRTComponent/pch.h b/Samples/AllJoyn/Common/Scenario2WinRTComponent/pch.h index 158fc61b39..754d9b45ce 100644 --- a/Samples/AllJoyn/Common/Scenario2WinRTComponent/pch.h +++ b/Samples/AllJoyn/Common/Scenario2WinRTComponent/pch.h @@ -45,8 +45,8 @@ #include "OnboardingEventArgs.h" #include "IOnboardingService.h" #include "OnboardingSignals.h" +#include "OnboardingLegacySignals.h" #include "OnboardingProducer.h" -#include "OnboardingWatcher.h" #include "OnboardingConsumer.h" #include "OnboardingServiceEventArgs.h" #include "OnboardingServiceEventAdapter.h" \ No newline at end of file diff --git a/Samples/AllJoyn/ConsumerExperiences/cs/Scenario1ViewModel.cs b/Samples/AllJoyn/ConsumerExperiences/cs/Scenario1ViewModel.cs index c17beb20a1..df9a986bb0 100644 --- a/Samples/AllJoyn/ConsumerExperiences/cs/Scenario1ViewModel.cs +++ b/Samples/AllJoyn/ConsumerExperiences/cs/Scenario1ViewModel.cs @@ -12,12 +12,14 @@ using com.microsoft.Samples.SecureInterface; using SDKTemplate; using System; +using System.Collections.Generic; using System.ComponentModel; using System.Runtime.CompilerServices; using System.Threading.Tasks; using System.Windows.Input; using Windows.Data.Xml.Dom; using Windows.Devices.AllJoyn; +using Windows.Devices.Enumeration; using Windows.UI.Core; using Windows.UI.Notifications; using Windows.UI.Xaml; @@ -29,7 +31,7 @@ class Scenario1ViewModel : INotifyPropertyChanged private MainPage m_rootPage; private CoreDispatcher m_dispatcher; private AllJoynBusAttachment m_busAttachment = null; - private SecureInterfaceWatcher m_watcher = null; + private DeviceWatcher m_watcher = null; private SecureInterfaceConsumer m_consumer = null; private TaskCompletionSource m_authenticateClicked = null; private Visibility m_authVisibility = Visibility.Collapsed; @@ -38,7 +40,7 @@ class Scenario1ViewModel : INotifyPropertyChanged private bool m_isCredentialsRequested = false; private bool m_isUpperCaseEnabled = false; private bool m_callSetProperty = true; - private string m_key = ""; + private string m_key = string.Empty; public Scenario1ViewModel() { @@ -180,7 +182,7 @@ private void Start() m_busAttachment.CredentialsRequested += BusAttachment_CredentialsRequested; // Initialize a watcher object to listen for about interfaces. - m_watcher = new SecureInterfaceWatcher(m_busAttachment); + m_watcher = AllJoynBusAttachment.GetWatcher(new List { "com.microsoft.Samples.SecureInterface" }); // Subscribing to the added event that will be raised whenever a producer for this service is found. m_watcher.Added += Watcher_Added; @@ -292,10 +294,10 @@ private async void BusAttachment_CredentialsRequested(AllJoynBusAttachment sende credentialsDeferral.Complete(); } - private async void Watcher_Added(SecureInterfaceWatcher sender, AllJoynServiceInfo args) + private async void Watcher_Added(DeviceWatcher sender, DeviceInformation args) { // Optional - Get the About data of the producer. - AllJoynAboutDataView aboutData = await AllJoynAboutDataView.GetDataBySessionPortAsync(args.UniqueName, m_busAttachment, args.SessionPort); + AllJoynAboutDataView aboutData = await m_busAttachment.GetAboutDataAsync(await AllJoynServiceInfo.FromIdAsync(args.Id)); // Check to see if device name is populated in the about data, since device name is not a mandatory field. if (string.IsNullOrEmpty(aboutData.DeviceName)) @@ -307,16 +309,14 @@ private async void Watcher_Added(SecureInterfaceWatcher sender, AllJoynServiceIn UpdateStatusAsync(string.Format("Found {0} on {1} from manufacturer: {2}. Connecting...", aboutData.AppName, aboutData.DeviceName, aboutData.Manufacturer), NotifyType.StatusMessage); } - // Attempt to join the session when a producer is discovered. - SecureInterfaceJoinSessionResult joinSessionResult = await SecureInterfaceConsumer.JoinSessionAsync(args, sender); - - if (joinSessionResult.Status == AllJoynStatus.Ok) + DisposeConsumer(); + UpdateStatusAsync("Joining session...", NotifyType.StatusMessage); + m_consumer = await SecureInterfaceConsumer.FromIdAsync(args.Id, m_busAttachment); + if (m_consumer != null) { - DisposeConsumer(); - m_consumer = joinSessionResult.Consumer; m_consumer.IsUpperCaseEnabledChanged += Consumer_IsUpperCaseEnabledChanged; m_consumer.Signals.TextSentReceived += Signals_TextSentReceived; - m_consumer.SessionLost += Consumer_SessionLost; + m_consumer.Session.Lost += Consumer_SessionLost; // At the time of connection, the request credentials callback not being invoked is an // indication that the consumer and producer are already authenticated from a previous session. @@ -341,11 +341,11 @@ private async void Watcher_Added(SecureInterfaceWatcher sender, AllJoynServiceIn } else { - UpdateStatusAsync(string.Format("Attempt to connect failed with AllJoyn error: 0x{0:X}.", joinSessionResult.Status), NotifyType.ErrorMessage); + UpdateStatusAsync("Attempt to join session failed.", NotifyType.ErrorMessage); } } - private void Consumer_SessionLost(SecureInterfaceConsumer sender, AllJoynSessionLostEventArgs args) + private void Consumer_SessionLost(AllJoynSession sender, AllJoynSessionLostEventArgs args) { UpdateStatusAsync(string.Format("AllJoyn session with the producer lost due to {0}.", args.Reason.ToString()), NotifyType.StatusMessage); ConsumerOptionsVisibility = Visibility.Collapsed; @@ -407,7 +407,7 @@ private void DisposeConsumer() { if (m_consumer != null) { - m_consumer.SessionLost -= Consumer_SessionLost; + m_consumer.Session.Lost -= Consumer_SessionLost; m_consumer.Signals.TextSentReceived -= Signals_TextSentReceived; m_consumer.IsUpperCaseEnabledChanged -= Consumer_IsUpperCaseEnabledChanged; m_consumer.Dispose(); @@ -421,7 +421,6 @@ private void DisposeWatcher() { m_watcher.Added -= Watcher_Added; m_watcher.Stop(); - m_watcher.Dispose(); m_watcher = null; } } diff --git a/Samples/AllJoyn/ConsumerExperiences/cs/Scenario2ViewModel.cs b/Samples/AllJoyn/ConsumerExperiences/cs/Scenario2ViewModel.cs index c63cde8c0e..886563aa25 100644 --- a/Samples/AllJoyn/ConsumerExperiences/cs/Scenario2ViewModel.cs +++ b/Samples/AllJoyn/ConsumerExperiences/cs/Scenario2ViewModel.cs @@ -20,6 +20,7 @@ using System.Threading.Tasks; using System.Windows.Input; using Windows.Devices.AllJoyn; +using Windows.Devices.Enumeration; using Windows.Devices.WiFi; using Windows.Networking.Connectivity; using Windows.Security.Credentials; @@ -62,7 +63,7 @@ class Scenario2ViewModel : INotifyPropertyChanged private bool m_showOnboardeeSsidList = true; private bool m_showOnboarderSsidList = false; private AllJoynBusAttachment m_busAttachment = null; - private OnboardingWatcher m_watcher = null; + private DeviceWatcher m_watcher = null; private OnboardingConsumer m_consumer = null; private OnboardingAuthenticationType m_selectedAuthType = OnboardingAuthenticationType.Any; private TaskCompletionSource m_authenticateClicked = null; @@ -692,7 +693,7 @@ private void ScanForOnboardingInterfaces() m_busAttachment.AuthenticationMechanisms.Add(AllJoynAuthenticationMechanism.EcdheSpeke); m_busAttachment.AuthenticationComplete += BusAttachment_AuthenticationComplete; m_busAttachment.CredentialsRequested += BusAttachment_CredentialsRequested; - m_watcher = new OnboardingWatcher(m_busAttachment); + m_watcher = AllJoynBusAttachment.GetWatcher(new List { "org.alljoyn.Onboarding" }); m_watcher.Added += Watcher_Added; UpdateStatusAsync("Searching for onboarding interface...", NotifyType.StatusMessage); m_watcher.Start(); @@ -756,7 +757,7 @@ private async void BusAttachment_CredentialsRequested(AllJoynBusAttachment sende credentialsDeferral.Complete(); } - private async void Watcher_Added(OnboardingWatcher sender, AllJoynServiceInfo args) + private async void Watcher_Added(DeviceWatcher sender, DeviceInformation args) { // This demo supports a single onboarding producer, if there are multiple onboarding producers found, then they are ignored. // Another approach would be to create a list of all producers found and then allow the user to choose the one they want @@ -766,25 +767,22 @@ private async void Watcher_Added(OnboardingWatcher sender, AllJoynServiceInfo ar return; } + DisposeConsumer(); UpdateStatusAsync("Joining session...", NotifyType.StatusMessage); + m_consumer = await OnboardingConsumer.FromIdAsync(args.Id, m_busAttachment); - OnboardingJoinSessionResult joinSessionResult = await OnboardingConsumer.JoinSessionAsync(args, sender); - if (joinSessionResult.Status == AllJoynStatus.Ok) + if (m_consumer != null) { - UpdateStatusAsync("Session Joined.", NotifyType.ErrorMessage); - DisposeConsumer(); - m_consumer = joinSessionResult.Consumer; - m_consumer.SessionLost += Consumer_SessionLost; - + m_consumer.Session.Lost += Consumer_SessionLost; GetOnboardeeNetworkListAsync(); } else { - UpdateStatusAsync(string.Format("Attempt to join session failed with AllJoyn error: 0x{0:X}.", joinSessionResult.Status), NotifyType.ErrorMessage); + UpdateStatusAsync("Attempt to join session failed.", NotifyType.ErrorMessage); } } - private void Consumer_SessionLost(OnboardingConsumer sender, AllJoynSessionLostEventArgs args) + private void Consumer_SessionLost(AllJoynSession sender, AllJoynSessionLostEventArgs args) { UpdateStatusAsync(string.Format("AllJoyn session with the onboardee lost due to {0}.", args.Reason.ToString()), NotifyType.StatusMessage); DisposeConsumer(); @@ -987,7 +985,7 @@ private void DisposeConsumer() { if (m_consumer != null) { - m_consumer.SessionLost -= Consumer_SessionLost; + m_consumer.Session.Lost -= Consumer_SessionLost; m_consumer.Dispose(); m_consumer = null; } @@ -999,7 +997,6 @@ private void DisposeWatcher() { m_watcher.Added -= Watcher_Added; m_watcher.Stop(); - m_watcher.Dispose(); m_watcher = null; } } diff --git a/Samples/AllJoyn/ConsumerExperiences/js/js/scenario1.js b/Samples/AllJoyn/ConsumerExperiences/js/js/scenario1.js index 960a9fb15f..131e9e67f5 100644 --- a/Samples/AllJoyn/ConsumerExperiences/js/js/scenario1.js +++ b/Samples/AllJoyn/ConsumerExperiences/js/js/scenario1.js @@ -55,7 +55,7 @@ busAttachment.oncredentialsrequested = credentialsRequestedHandler; // Initialize a watcher object to listen for about interfaces. - watcher = new secureInterface.SecureInterfaceWatcher(busAttachment); + watcher = new allJoyn.AllJoynBusAttachment.getWatcher(["com.microsoft.Samples.SecureInterface"]); // Subscribing to the added event that will be raised whenever a producer for this service is found. watcher.onadded = watcherAddedHandler; @@ -113,47 +113,51 @@ function watcherAddedHandler(args) { // Optional - Get the About data of the producer. - allJoyn.AllJoynAboutDataView.getDataBySessionPortAsync(args.detail[0].uniqueName, busAttachment, args.detail[0].sessionPort) - .then(function (aboutData) { - if (aboutData != null) { - // Check to see if device name is populated in the about data, since device name is not a mandatory field. - if (aboutData.deviceName != null) { - reportStatus("Found " + aboutData.appName + " on " + aboutData.deviceName + " from manufacturer: " + aboutData.manufacturer + ". Connecting..."); - } else { - reportStatus("Found " + aboutData.appName + " from manufacturer: " + aboutData.manufacturer + ". Connecting..."); - } - } else { - reportError("Unable to get About data."); - } - }) - .then(function () { - // Attempt to join the session when a producer is discovered. - secureInterface.SecureInterfaceConsumer.joinSessionAsync(args, watcher) - .then(function (joinSessionResult) { - if (joinSessionResult.status === allJoyn.AllJoynStatus.ok) { - disposeConsumer(); - consumer = joinSessionResult.consumer; - consumer.onisuppercaseenabledchanged = isUpperCaseEnabledChangedHandler; - consumer.signals.ontextsentreceived = textSentReceivedHandler; - consumer.onsessionlost = sessionLostHandler; - - // At the time of connection, the request credentials callback not being invoked is an - // indication that the consumer and producer are already authenticated from a previous session. - if (!isCredentialsRequested) { - reportStatus("Connected and already authenticated from previous session."); - isUpperCaseEnabledChangedHandler(); + allJoyn.AllJoynServiceInfo.fromIdAsync(args.id) + .then(function (alljoynServiceInfo) { + busAttachment.getAboutDataAsync(alljoynServiceInfo) + .then(function (aboutData) { + if (aboutData != null) { + // Check to see if device name is populated in the about data, since device name is not a mandatory field. + if (aboutData.deviceName != null) { + reportStatus("Found " + aboutData.appName + " on " + aboutData.deviceName + " from manufacturer: " + aboutData.manufacturer + ". Connecting..."); } else { - if (isAuthenticated) { - reportStatus("Connected with authentication."); - isUpperCaseEnabledChangedHandler(); - } else { - reportError("Connected but authentication failed."); - } + reportStatus("Found " + aboutData.appName + " from manufacturer: " + aboutData.manufacturer + ". Connecting..."); } - consumerOptions.style.display = "block"; } else { - reportError("Attempt to connect failed with AllJoyn error: 0x" + joinSessionResult.status.toString(16)); + reportError("Unable to get About data."); } + }) + .then(function () { + reportStatus("Joining session..."); + // Attempt to join the session when a producer is discovered. + secureInterface.SecureInterfaceConsumer.fromIdAsync(args.id, busAttachment) + .then(function (secureInterfaceConsumer) { + if (secureInterfaceConsumer != null) { + disposeConsumer(); + consumer = secureInterfaceConsumer; + consumer.onisuppercaseenabledchanged = isUpperCaseEnabledChangedHandler; + consumer.signals.ontextsentreceived = textSentReceivedHandler; + consumer.session.onlost = sessionLostHandler; + + // At the time of connection, the request credentials callback not being invoked is an + // indication that the consumer and producer are already authenticated from a previous session. + if (!isCredentialsRequested) { + reportStatus("Connected and already authenticated from previous session."); + isUpperCaseEnabledChangedHandler(); + } else { + if (isAuthenticated) { + reportStatus("Connected with authentication."); + isUpperCaseEnabledChangedHandler(); + } else { + reportError("Connected but authentication failed."); + } + } + consumerOptions.style.display = "block"; + } else { + reportError("Attempt to join session failed."); + } + }); }); }); } @@ -231,7 +235,7 @@ if (consumer != null) { consumer.onisuppercaseenabledchanged = null; consumer.signals.ontextsentreceived = null; - consumer.onsessionlost = null; + consumer.session.onlost = null; consumer.close(); consumer = null; } @@ -241,7 +245,6 @@ if (watcher != null) { watcher.onadded = null; watcher.stop(); - watcher.close(); watcher = null; } } diff --git a/Samples/AllJoyn/ConsumerExperiences/js/js/scenario2.js b/Samples/AllJoyn/ConsumerExperiences/js/js/scenario2.js index 8e48efe73e..77c9c7769d 100644 --- a/Samples/AllJoyn/ConsumerExperiences/js/js/scenario2.js +++ b/Samples/AllJoyn/ConsumerExperiences/js/js/scenario2.js @@ -85,7 +85,7 @@ busAttachment.authenticationMechanisms.append(allJoyn.AllJoynAuthenticationMechanism.ecdheSpeke); busAttachment.onauthenticationcomplete = authenticationCompleteHandler; busAttachment.oncredentialsrequested = credentialsRequestedHandler; - watcher = new onboarding.OnboardingWatcher(busAttachment); + watcher = new allJoyn.AllJoynBusAttachment.getWatcher(["org.alljoyn.Onboarding"]); watcher.onadded = watcherAddedHandler; reportStatus("Searching for onboarding interface..."); watcher.start(); @@ -136,18 +136,18 @@ function watcherAddedHandler(args) { reportStatus("Joining session..."); - onboarding.OnboardingConsumer.joinSessionAsync(args, watcher) - .then(function (joinSessionResult) { - if (joinSessionResult.status === allJoyn.AllJoynStatus.ok) { + onboarding.OnboardingConsumer.fromIdAsync(args.id, busAttachment) + .then(function (onboardingConsumer) { + if (onboardingConsumer != null) { disposeConsumer(); - consumer = joinSessionResult.consumer; - consumer.onsessionlost = sessionLostHandler; + consumer = onboardingConsumer; + consumer.session.onlost = sessionLostHandler; if (!isCredentialRequested || isAuthenticated) { getOnboardeeNetworkList(); } } else { - reportError("Attempt to join session failed with AllJoyn error: 0x" + joinSessionResult.status.toString(16)); + reportError("Attempt to join session failed."); } }); } @@ -446,7 +446,7 @@ function disposeConsumer() { if (consumer != null) { - consumer.onsessionlost = null; + consumer.session.onlost = null; consumer.close(); consumer = null; } diff --git a/Samples/AllJoyn/shared/AllJoynBusObjectManager.cpp b/Samples/AllJoyn/shared/AllJoynBusObjectManager.cpp index 276e214bff..d0e7b15bd9 100644 --- a/Samples/AllJoyn/shared/AllJoynBusObjectManager.cpp +++ b/Samples/AllJoyn/shared/AllJoynBusObjectManager.cpp @@ -9,24 +9,13 @@ // //********************************************************* //----------------------------------------------------------------------------- -// -// This code was generated by a tool. -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -// Tool: AllJoynCodeGenerator.exe +// +// This code was generated by a tool. // -// This tool is located in the Windows 10 SDK and the Windows 10 AllJoyn -// Visual Studio Extension in the Visual Studio Gallery. -// -// The generated code should be packaged in a Windows 10 C++/CX Runtime -// Component which can be consumed in any UWP-supported language using -// APIs that are available in Windows.Devices.AllJoyn. +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. // -// Using AllJoynCodeGenerator - Invoke the following command with a valid -// Introspection XML file and a writable output directory: -// AllJoynCodeGenerator -i -o +// For more information, see: http://go.microsoft.com/fwlink/?LinkID=623246 // //----------------------------------------------------------------------------- #include "pch.h" diff --git a/Samples/AllJoyn/shared/AllJoynBusObjectManager.h b/Samples/AllJoyn/shared/AllJoynBusObjectManager.h index 776bbe6e7b..95c287da1e 100644 --- a/Samples/AllJoyn/shared/AllJoynBusObjectManager.h +++ b/Samples/AllJoyn/shared/AllJoynBusObjectManager.h @@ -9,24 +9,13 @@ // //********************************************************* //----------------------------------------------------------------------------- -// -// This code was generated by a tool. -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -// Tool: AllJoynCodeGenerator.exe +// +// This code was generated by a tool. // -// This tool is located in the Windows 10 SDK and the Windows 10 AllJoyn -// Visual Studio Extension in the Visual Studio Gallery. -// -// The generated code should be packaged in a Windows 10 C++/CX Runtime -// Component which can be consumed in any UWP-supported language using -// APIs that are available in Windows.Devices.AllJoyn. +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. // -// Using AllJoynCodeGenerator - Invoke the following command with a valid -// Introspection XML file and a writable output directory: -// AllJoynCodeGenerator -i -o +// For more information, see: http://go.microsoft.com/fwlink/?LinkID=623246 // //----------------------------------------------------------------------------- #pragma once diff --git a/Samples/AllJoyn/shared/AllJoynHelpers.cpp b/Samples/AllJoyn/shared/AllJoynHelpers.cpp index 771404bca0..4e72e2c239 100644 --- a/Samples/AllJoyn/shared/AllJoynHelpers.cpp +++ b/Samples/AllJoyn/shared/AllJoynHelpers.cpp @@ -9,24 +9,13 @@ // //********************************************************* //----------------------------------------------------------------------------- -// -// This code was generated by a tool. -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -// Tool: AllJoynCodeGenerator.exe -// -// This tool is located in the Windows 10 SDK and the Windows 10 AllJoyn -// Visual Studio Extension in the Visual Studio Gallery. +// +// This code was generated by a tool. // -// The generated code should be packaged in a Windows 10 C++/CX Runtime -// Component which can be consumed in any UWP-supported language using -// APIs that are available in Windows.Devices.AllJoyn. +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. // -// Using AllJoynCodeGenerator - Invoke the following command with a valid -// Introspection XML file and a writable output directory: -// AllJoynCodeGenerator -i -o +// For more information, see: http://go.microsoft.com/fwlink/?LinkID=623246 // //----------------------------------------------------------------------------- #include "pch.h" @@ -43,10 +32,20 @@ alljoyn_busattachment AllJoynHelpers::GetInternalBusAttachment(_In_ AllJoynBusAt ComPtr interop; iUnknown.As(&interop); UINT64 win32handle; - interop->get_Win32Handle(&win32handle); + (void)interop->get_Win32Handle(&win32handle); return reinterpret_cast(win32handle); } +alljoyn_busobject AllJoynHelpers::GetInternalBusObject(_In_ AllJoynBusObject^ busObject) +{ + ComPtr iUnknown = reinterpret_cast(busObject); + ComPtr interop; + iUnknown.As(&interop); + UINT64 win32handle; + (void)interop->get_Win32Handle(&win32handle); + return reinterpret_cast(win32handle); +} + String^ AllJoynHelpers::MultibyteToPlatformString(_In_ PCSTR str) { size_t length = strlen(str); diff --git a/Samples/AllJoyn/shared/TypeConversionHelpers.cpp b/Samples/AllJoyn/shared/TypeConversionHelpers.cpp index 0f3328824d..955dcb7ef0 100644 --- a/Samples/AllJoyn/shared/TypeConversionHelpers.cpp +++ b/Samples/AllJoyn/shared/TypeConversionHelpers.cpp @@ -9,24 +9,13 @@ // //********************************************************* //----------------------------------------------------------------------------- -// -// This code was generated by a tool. -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -// Tool: AllJoynCodeGenerator.exe +// +// This code was generated by a tool. // -// This tool is located in the Windows 10 SDK and the Windows 10 AllJoyn -// Visual Studio Extension in the Visual Studio Gallery. -// -// The generated code should be packaged in a Windows 10 C++/CX Runtime -// Component which can be consumed in any UWP-supported language using -// APIs that are available in Windows.Devices.AllJoyn. +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. // -// Using AllJoynCodeGenerator - Invoke the following command with a valid -// Introspection XML file and a writable output directory: -// AllJoynCodeGenerator -i -o +// For more information, see: http://go.microsoft.com/fwlink/?LinkID=623246 // //----------------------------------------------------------------------------- #include "pch.h" diff --git a/Samples/AllJoyn/shared/TypeConversionHelpers.h b/Samples/AllJoyn/shared/TypeConversionHelpers.h index bd44a36b16..a6e6524944 100644 --- a/Samples/AllJoyn/shared/TypeConversionHelpers.h +++ b/Samples/AllJoyn/shared/TypeConversionHelpers.h @@ -9,24 +9,13 @@ // //********************************************************* //----------------------------------------------------------------------------- -// -// This code was generated by a tool. -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -// Tool: AllJoynCodeGenerator.exe +// +// This code was generated by a tool. // -// This tool is located in the Windows 10 SDK and the Windows 10 AllJoyn -// Visual Studio Extension in the Visual Studio Gallery. -// -// The generated code should be packaged in a Windows 10 C++/CX Runtime -// Component which can be consumed in any UWP-supported language using -// APIs that are available in Windows.Devices.AllJoyn. +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. // -// Using AllJoynCodeGenerator - Invoke the following command with a valid -// Introspection XML file and a writable output directory: -// AllJoynCodeGenerator -i -o +// For more information, see: http://go.microsoft.com/fwlink/?LinkID=623246 // //----------------------------------------------------------------------------- #pragma once @@ -132,7 +121,7 @@ ref class TypeConversionHelpers *value = ref new Platform::Collections::Vector(); if (signature[0] != 'a') { - return ER_BUS_BAD_SIGNATURE; + return ER_BUS_SIGNATURE_MISMATCH; } if (IsArrayOfPrimitives(signature)) @@ -164,7 +153,13 @@ ref class TypeConversionHelpers { if (signature[0] != 'a') { - return ER_BUS_BAD_SIGNATURE; + return ER_BUS_SIGNATURE_MISMATCH; + } + + // An empty or null vector will cause errors in AllJoyn. + if (value == nullptr || value->Size < 1) + { + return ER_INVALID_DATA; } // Remove the 'a' to get the signature of an array element. @@ -198,6 +193,12 @@ ref class TypeConversionHelpers static _Check_return_ int32 SetAllJoynMessageArg(_In_ alljoyn_msgarg argument, _In_ PCSTR signature, _In_ Windows::Foundation::Collections::IVectorView^ value) { + // An empty or null vector will cause errors in AllJoyn. + if (value == nullptr || value->Size < 1) + { + return ER_INVALID_DATA; + } + std::vector> strings; for (unsigned int i = 0; i < value->Size; i++) { @@ -316,6 +317,12 @@ ref class TypeConversionHelpers std::vector valueType; RETURN_IF_QSTATUS_ERROR(GetDictionaryTypeSignatures(signature, &keyType, &valueType)); + // An empty or null vector will cause errors in AllJoyn. + if (value == nullptr || value->Size < 1) + { + return ER_INVALID_DATA; + } + alljoyn_msgarg dictionaryArg = alljoyn_msgarg_array_create(value->Size); int i = 0; diff --git a/Samples/CameraFrames/cpp/CameraFrames.vcxproj b/Samples/CameraFrames/cpp/CameraFrames.vcxproj index 6e64393147..59d17dd659 100644 --- a/Samples/CameraFrames/cpp/CameraFrames.vcxproj +++ b/Samples/CameraFrames/cpp/CameraFrames.vcxproj @@ -8,8 +8,8 @@ true Windows Store 10.0 - 10.0.14366.0 - 10.0.14366.0 + 10.0.14393.0 + 10.0.14393.0 diff --git a/Samples/D2DCustomEffects/README.md b/Samples/D2DCustomEffects/README.md index 8d0059adc8..25c782b0dc 100644 --- a/Samples/D2DCustomEffects/README.md +++ b/Samples/D2DCustomEffects/README.md @@ -19,6 +19,44 @@ To obtain information about Windows 10 development, go to the [Windows Dev Cente To obtain information about Microsoft Visual Studio 2015 and the tools for developing Windows apps, go to [Visual Studio 2015](http://go.microsoft.com/fwlink/?LinkID=532422) +## Sample project files + +This sample contains three separate projects, demonstrating a custom pixel, vertex, and compute shader effect. +Each project has a similar set of files that follow the same pattern. + +### Custom Direct2D effect implementation +The following files are the core effect implementation, i.e. the main educational content of the sample: + +- ***.hlsl:** The core shader routines that operate on image data. These are written using standard HLSL with some helper Direct2D intrinsics that enable the custom effect to take advantage of shader linking. +[TODO: link to the intrinsics/shader linking page] +- ***Effect.cpp/.h,** ***Transform.cpp/.h:** Implementation of the Direct2D effect interfaces, e.g. ID2D1EffectImpl. This code is called by the Direct2D renderer to setup and control the effect shader operation. + +### Demo app +A custom Direct2D effect does nothing on its own, as it must be loaded and executed by a calling app. The following files provide a simple demo environment to exercise the effect: + +- App.cpp/.h +- *Main.cpp/.h, *Renderer.cpp/.h + +### DirectX SDK sample common files +The following files provide common functionality needed by DirectX SDK samples: + +- **DeviceResources.cpp/.h:** Manages creation and lifetime of the core Direct3D and Direct2D device-dependent resources. Handles cases such as device lost and window size and orientation changes. +- **DirectXHelper.h:** Common inline helper functions, including ThrowIfFailed which converts HRESULT-based APIs into an exception model. +- **BasicReaderWriter.cpp/.h:** Basic file I/O functionality, needed for things like loading shaders, textures and geometry. +- **SampleOverlay.cpp/.h:** Renders the Windows SDK overlay badge on top of sample content. +- **BasicTimer.cpp/.h:** Wraps QueryPerformanceCounter to provide an accurate, low-overhead timer. + +All DX SDK samples and the Visual Studio template DX project contain a version of these files (some are not always needed). These common files demonstrate important best practices for DX UWP apps, and you are encouraged to use them in your own projects. + +### C++ UWP common files +Variants of the following files are found in every UWP app written in C++: + +- Package.appxmanifest +- pch.cpp/.h +- *.vcxproj +- *.vcxproj.filters +- *.sln + ## Related topics ### Feature areas diff --git a/Samples/D2DCustomEffects/cpp/ComputeShader/App.cpp b/Samples/D2DCustomEffects/cpp/ComputeShader/App.cpp index caa57a950d..9db6955424 100644 --- a/Samples/D2DCustomEffects/cpp/ComputeShader/App.cpp +++ b/Samples/D2DCustomEffects/cpp/ComputeShader/App.cpp @@ -62,9 +62,23 @@ void App::Initialize(_In_ CoreApplicationView^ applicationView) CoreApplication::Resuming += ref new EventHandler(this, &App::OnResuming); - // At this point we have access to the device. + // At this point we have access to the device. // We can create the device-dependent resources. m_deviceResources = std::make_shared(); + + auto device = m_deviceResources->GetD3DDevice(); + + // Check whether the graphics hardware supports compute shaders. If not, switch to a WARP device + // which is guaranteed to support at least D3D_FEATURE_LEVEL_11_0. + if (device->GetFeatureLevel() < D3D_FEATURE_LEVEL_11_0) + { + D3D11_FEATURE_DATA_D3D10_X_HARDWARE_OPTIONS hwopts = { 0 }; + DX::ThrowIfFailed(device->CheckFeatureSupport(D3D11_FEATURE_D3D10_X_HARDWARE_OPTIONS, &hwopts, sizeof(hwopts))); + if (!hwopts.ComputeShaders_Plus_RawAndStructuredBuffers_Via_Shader_4_x) + { + m_deviceResources.reset(new DX::DeviceResources(true)); + } + } } // Called when the CoreWindow object is created (or re-created). diff --git a/Samples/D2DCustomEffects/cpp/ComputeShader/DeviceResources.cpp b/Samples/D2DCustomEffects/cpp/ComputeShader/DeviceResources.cpp index 5ed9298006..e015539727 100644 --- a/Samples/D2DCustomEffects/cpp/ComputeShader/DeviceResources.cpp +++ b/Samples/D2DCustomEffects/cpp/ComputeShader/DeviceResources.cpp @@ -59,7 +59,13 @@ namespace ScreenRotation }; // Constructor for DeviceResources. -DX::DeviceResources::DeviceResources() : +DX::DeviceResources::DeviceResources() : + DeviceResources(false /* _In_ bool forceWarpDevice */) +{} + +// Constructor for DeviceResources; allows the caller to force usage of the WARP software +// device which is useful if we need to use D3D features that are unsupported by the hardware. +DX::DeviceResources::DeviceResources(_In_ bool forceWarpDevice) : m_screenViewport(), m_d3dFeatureLevel(D3D_FEATURE_LEVEL_9_1), m_d3dRenderTargetSize(), @@ -68,7 +74,8 @@ DX::DeviceResources::DeviceResources() : m_nativeOrientation(DisplayOrientations::None), m_currentOrientation(DisplayOrientations::None), m_dpi(-1.0f), - m_deviceNotify(nullptr) + m_deviceNotify(nullptr), + m_forceWarpDevice(forceWarpDevice) { CreateDeviceIndependentResources(); CreateDeviceResources(); @@ -150,9 +157,12 @@ void DX::DeviceResources::CreateDeviceResources() ComPtr device; ComPtr context; + // Create a device using the hardware graphics driver, unless WARP override is set. + D3D_DRIVER_TYPE driverType = m_forceWarpDevice ? D3D_DRIVER_TYPE_WARP : D3D_DRIVER_TYPE_HARDWARE; + HRESULT hr = D3D11CreateDevice( nullptr, // Specify nullptr to use the default adapter. - D3D_DRIVER_TYPE_HARDWARE, // Create a device using the hardware graphics driver. + driverType, 0, // Should be 0 unless the driver is D3D_DRIVER_TYPE_SOFTWARE. creationFlags, // Set debug and Direct2D compatibility flags. featureLevels, // List of feature levels this app can support. diff --git a/Samples/D2DCustomEffects/cpp/ComputeShader/DeviceResources.h b/Samples/D2DCustomEffects/cpp/ComputeShader/DeviceResources.h index 4faeabbbc6..f62bca8488 100644 --- a/Samples/D2DCustomEffects/cpp/ComputeShader/DeviceResources.h +++ b/Samples/D2DCustomEffects/cpp/ComputeShader/DeviceResources.h @@ -25,6 +25,7 @@ namespace DX { public: DeviceResources(); + DeviceResources(_In_ bool forceWarpDevice); void SetWindow(Windows::UI::Core::CoreWindow^ window); void SetLogicalSize(Windows::Foundation::Size logicalSize); void SetCurrentOrientation(Windows::Graphics::Display::DisplayOrientations currentOrientation); @@ -95,6 +96,7 @@ namespace DX Windows::Graphics::Display::DisplayOrientations m_nativeOrientation; Windows::Graphics::Display::DisplayOrientations m_currentOrientation; float m_dpi; + bool m_forceWarpDevice; // Transforms used for display orientation. D2D1::Matrix3x2F m_orientationTransform2D; diff --git a/Samples/D2DCustomEffects/cpp/ComputeShader/DftEffect.cpp b/Samples/D2DCustomEffects/cpp/ComputeShader/DftEffect.cpp index 0a9e2f2c0b..7387006b6f 100644 --- a/Samples/D2DCustomEffects/cpp/ComputeShader/DftEffect.cpp +++ b/Samples/D2DCustomEffects/cpp/ComputeShader/DftEffect.cpp @@ -78,10 +78,10 @@ IFACEMETHODIMP DftEffect::Initialize( sizeof(hardwareOptions) ); - // As stated above, not all DX Feature Level 10_0 parts support compute shaders. In this app's case, - // it checks for compute shader support at device creation in DirectXBase.cpp. If support is missing, - // it uses a software fallback (WARP). All effects that use compute shaders should perform this - // check at instantiation. + // As stated above, not all DX Feature Level 10_0 parts support compute shaders. In this sample's case, + // it checks for compute shader support at device creation in DeviceResources. If support is missing, + // it uses the WARP software fallback, which is guaranteed to support compute. + // All effects that use compute shaders should perform this check at instantiation. if (SUCCEEDED(hr)) { if (!hardwareOptions.computeShaders_Plus_RawAndStructuredBuffers_Via_Shader_4_x) diff --git a/Samples/D2DGradientMesh/README.md b/Samples/D2DGradientMesh/README.md index f270c20ec8..5aed7d5727 100644 --- a/Samples/D2DGradientMesh/README.md +++ b/Samples/D2DGradientMesh/README.md @@ -13,6 +13,37 @@ Some important APIs used in this sample are: - The [**ID2D1DeviceContext2::CreateGradientMesh**](http://msdn.microsoft.com/en-us/library/windows/desktop/dn890790) method, which creates an [**ID2D1GradientMesh**](http://msdn.microsoft.com/en-us/library/windows/desktop/dn900410) object on the Direct2D device. - The [**ID2D1DeviceContext2::DrawGradientMesh**](http://msdn.microsoft.com/en-us/library/windows/desktop/dn900378) method, which renders the ID2D1GradientMesh object to the device context. +## Sample project files + +The sample's project files fall into the following categories. + +### Sample-specific files +The following files exercise the gradient mesh APIs and form the main educational content of the sample: + +- App.cpp/.h +- D2DGradientMeshMain.cpp/.h +- D2DGradientMeshRenderer.cpp/.h + +D2DGradientMeshRenderer contains most of the gradient mesh-specific code. + +### DirectX SDK sample common files +The following files provide common functionality needed by DirectX SDK samples: + +- **DeviceResources.cpp/.h:** Manages creation and lifetime of the core Direct3D and Direct2D device-dependent resources. Handles cases such as device lost and window size and orientation changes. +- **DirectXHelper.h:** Common inline helper functions, including ThrowIfFailed which converts HRESULT-based APIs into an exception model. +- **SampleOverlay.cpp/.h:** Renders the Windows SDK overlay badge on top of sample content. + +All DX SDK samples and the Visual Studio template DX project contain a version of these files. These common files demonstrate important best practices for DX UWP apps, and you are encouraged to use them in your own projects. + +### C++ UWP common files +Variants of the following files are found in every UWP app written in C++: + +- Package.appxmanifest +- pch.cpp/.h +- D2DGradientMesh.vcxproj +- D2DGradientMesh.vcxproj.filters +- D2DGradientMesh.sln + ## Related topics [**D2D1\_GRADIENT\_MESH\_PATCH** structure](http://msdn.microsoft.com/en-us/library/windows/desktop/dn890726) diff --git a/Samples/D2DPhotoAdjustment/README.md b/Samples/D2DPhotoAdjustment/README.md index f6dda133f7..bbaf73891b 100644 --- a/Samples/D2DPhotoAdjustment/README.md +++ b/Samples/D2DPhotoAdjustment/README.md @@ -21,11 +21,35 @@ This sample uses the following Direct2D effects: - [Contrast](http://msdn.microsoft.com/en-us/library/windows/desktop/dn890716) - [Highlights and Shadows](http://msdn.microsoft.com/en-us/library/windows/desktop/dn890773) -**Note** The Windows universal samples require Visual Studio 2015 to build and Windows 10 to execute. - -To obtain information about Windows 10 development, go to the [Windows Dev Center](http://go.microsoft.com/fwlink/?LinkID=532421) +## Sample project files -To obtain information about Microsoft Visual Studio 2015 and the tools for developing Windows apps, go to [Visual Studio 2015](http://go.microsoft.com/fwlink/?LinkID=532422) +The sample's project files fall into the following categories. + +### Sample-specific files +The following files form the main educational content of the sample: + +- **DirectXPage.xaml/.cpp/.h/:** Implements a XAML-based UI to drive the photo pipeline. Hosts the DirectX content in a SwapChainPanel. +- **App.xaml/.cpp/.h:** The app's main entry point. +- **D2DPhotoAdjustmentRenderer.cpp/.h:** The core implementation of the Direct2D photo pipeline using effects. +- **D2DPhotoAdjustmentProperties.h:** Defines the struct used for databinding effect properties with the UI. + +### DirectX SDK sample common files +The following files provide common functionality needed by DirectX SDK samples: + +- **DeviceResources.cpp/.h:** Manages creation and lifetime of the core Direct3D and Direct2D device-dependent resources. Handles cases such as device lost and window size and orientation changes. +- **DirectXHelper.h:** Common inline helper functions, including ThrowIfFailed which converts HRESULT-based APIs into an exception model. +- **SampleOverlay.cpp/.h:** Renders the Windows SDK overlay badge on top of sample content. + +All DX SDK samples and the Visual Studio template DX project contain a version of these files. These common files demonstrate important best practices for DX UWP apps, and you are encouraged to use them in your own projects. + +### C++ UWP common files +Variants of the following files are found in every UWP app written in C++: + +- Package.appxmanifest +- pch.cpp/.h +- D2DPhotoAdjustment.vcxproj +- D2DPhotoAdjustment.vcxproj.filters +- D2DPhotoAdjustment.sln ## Related topics diff --git a/Samples/DWriteLineSpacingModes/README.md b/Samples/DWriteLineSpacingModes/README.md index 7c709c9ec2..3b4f0cca90 100644 --- a/Samples/DWriteLineSpacingModes/README.md +++ b/Samples/DWriteLineSpacingModes/README.md @@ -11,7 +11,7 @@ In previous versions, DirectWrite supported two different line spacing methods: Line metrics sound straightforward: line height, ascender and descender. But when you get into details of various scenarios, it's actually somewhat difficult to understand in the abstract. For that reason, in addition to demonstrating use of the DirectWrite APIs, this sample also allows you to explore and see visually how different input parameters affect the computed results. -##Sample project files +## Sample project files The sample is intended to demonstrate how to use the DirectWrite text layout line spacing APIs and the effects of the various input parameters. The app is comprised of two projects: * The DWriteTextLayoutImplementation project provides the implementation of DirectWrite APIs for text layout and line spacing that are the main focus of this sample. It is implemented as a Windows Runtime Component that wraps around DirectWrite and enables interop with the sample client app. It also uses other DirectX APIs to implement a XAML SurfaceImageSource as a means of displaying the text layout. @@ -19,13 +19,13 @@ The sample is intended to demonstrate how to use the DirectWrite text layout lin This organization suits the needs of this sample app, utilizing the simplicity of XAML for UI to navigate between scenarios while keeping the native DirectWrite code that's of primary interest separate and easier for you to focus on. -###DWriteTextLayoutImplementation project +### DWriteTextLayoutImplementation project Within the DWriteTextLayoutImplementation project, the following files are significant: * The TextLayout.h/.cpp files wrap the DirectWrite text layout and related line spacing APIs. * The TextLayoutImageSource.h/.cpp files implement a XAML SurfaceImageSource using DirectX APIs for rendering the text layout. -###DWriteTextLayoutCloudFont project +### DWriteTextLayoutCloudFont project Within the DWriteTextLayoutCloudFont project, the following files are significant: * The Scenario1\_DefaultSpacing.\*, Scenario2\_UniformSpacing.\* and Scenario3\_ProportionalSpacing.\* files each demonstrate a different line spacing method. @@ -34,7 +34,7 @@ Other files are boilerplate files used for UWP sample apps. -##Related topics +## Related topics [IDWriteTextLayout3 interface](https://msdn.microsoft.com/en-us/library/windows/desktop/dn900405) [IDWriteTextLayout3::SetLineSpacing method](https://msdn.microsoft.com/en-us/library/windows/desktop/dn900409) diff --git a/Samples/DWriteTextLayoutCloudFont/README.md b/Samples/DWriteTextLayoutCloudFont/README.md index 20b6375c68..59374e88ae 100644 --- a/Samples/DWriteTextLayoutCloudFont/README.md +++ b/Samples/DWriteTextLayoutCloudFont/README.md @@ -9,7 +9,7 @@ This sample demonstrates how to use DirectWrite downloadable fonts, a feature ad A new capability in DirectWrite for Windows 10 allows an app to format text content using fonts that may not be installed on a device, and for the font to be downloaded on demand from a Microsoft service. DirectWrite now includes low-level APIs for using downloadable fonts. An easy way to leverage the downloadable font mechanism is to use DirectWrite's text layout (IDWriteTextLayout3), which integrates the lower-level APIs and does part of the work for you. When a text layout is created with a Windows font that is not locally installed, the text layout will automatically add requests for the font data to a font download queue. You need to add code that initiates the download and that responds when the download is completed. -##Sample project files +## Sample project files The sample is intended to demonstrate how to use the DirectWrite downloadable font mechanism together with DirectWrite's text layout API. The app is comprised of two projects: * The DWriteTextLayoutCloudFontImplementation project provides the implementation of DirectWrite APIs for text layout and downloadable fonts that are the main focus of this sample. It is implemented as a Windows Runtime Component that wraps around DirectWrite and enables interop with the sample client app. It also uses other DirectX APIs to implement a XAML SurfaceImageSource as a means of displaying the text layout. @@ -17,7 +17,7 @@ The sample is intended to demonstrate how to use the DirectWrite downloadable fo This organization suits the needs of this sample app, utilizing the simplicity of XAML for UI to navigate between scenarios while keeping the native DirectWrite code that's of primary interest separate and easier for you to focus on. -###DWriteTextLayoutCloudFontImplementation project +### DWriteTextLayoutCloudFontImplementation project Within the DWriteTextLayoutCloudFontImplementation project, the following files are significant: * The TextLayout.h/.cpp files wrap the DirectWrite text layout API. @@ -25,7 +25,7 @@ Within the DWriteTextLayoutCloudFontImplementation project, the following files * The FontNameCollector.h/.cpp files wrap additional DirectWrite APIs to determine which fonts are actually used in text layout. They are not needed to use the font download mechanism but provide you more insight, while the sample app is running, into how the text layout and font download mechanisms are interacting. * The TextLayoutImageSource.h/.cpp files implement a XAML SurfaceImageSource using DirectX APIs for rendering the text layout. -###DWriteTextLayoutCloudFont project +### DWriteTextLayoutCloudFont project Within the DWriteTextLayoutCloudFont project, the following files are significant: * The Scenario\_Document1.\*, Scenario\_Document2.\* and Scenario\_Document3.\* files each invoke text layout using a different downloadable font, and then invoke and respond to the downloadable font mechanism. @@ -34,12 +34,10 @@ Within the DWriteTextLayoutCloudFont project, the following files are significan Other files are boilerplate files used for UWP sample apps. -###Other files +### Other files The ClearDownloadableFontCache.ps1 file is not part of the sample project itself, but is a PowerShell script that can be used to reset the state of the downloadable font mechanism (clearing cached data) before or after running the sample app. Instructions for using this script are given in the sample app. - - -##Related topics +## Related topics [IDWriteFactory3::GetSystemFontCollection method](https://msdn.microsoft.com/en-us/library/windows/desktop/dn890761) [IDWriteTextLayout3 interface](https://msdn.microsoft.com/en-us/library/windows/desktop/dn900405) diff --git a/Samples/HolographicMixedRealityCapture/README.md b/Samples/HolographicMixedRealityCapture/README.md new file mode 100644 index 0000000000..ee564d034f --- /dev/null +++ b/Samples/HolographicMixedRealityCapture/README.md @@ -0,0 +1,100 @@ + + +# Holographic Mixed Reality Capture sample + +This sample demonstrates how to capture mixed reality photo and video by using Windows.Media.Capture.MediaCapture and +MixedRealityCapture video/audio effects. + +## Holographic Mixed Reality Capture sample application (HolographicMRCapture solution) + +This solution is based on the Holographic DirectX application template with basic UI controls and a custom MediaCaptureManager class. + +The MediaCaptureManager class manages the Windows::Media::Capture::MediaCapture runtime class and adds/removes Mixed Reality Capture Audio and Video effects. + +## Mixed Reality Capture (MRC) Effect Definitions (MrcEffectDefinitions solution) + +Reusable solution to make using mixed reality capture video and audio effects more convenient. +This solution contains audio and video effect definitions for the built-in +MixedRealityCaptureAudioEffect and MixedRealityCaptureVideoEffect classes. + +## Additional remarks + +**Note** The Windows universal samples for Windows 10 Holographic require Visual Studio 2015 Update 2 +to build, and a Windows Holographic device to execute. Windows Holographic devices include the +Microsoft HoloLens and the Microsoft HoloLens Emulator. + +To obtain information about Windows 10 development, go to the [Windows Dev Center](http://go.microsoft.com/fwlink/?LinkID=532421). + +To obtain information about the tools used for Windows Holographic development, including +Microsoft Visual Studio 2015 Update 2 and the Microsoft HoloLens Emulator, go to +[Install the tools](https://developer.microsoft.com/windows/holographic/install_the_tools). + +## Reference + +The following are used to demonstrate spatial mapping in this code sample: + +* [Windows.Media.Capture namespace] (https://msdn.microsoft.com/library/windows/apps/windows.media.capture.aspx) + * [MediaCapture class] (https://msdn.microsoft.com/library/windows/apps/windows.media.capture.mediacapture.aspx) + +* [Mixed reality capture for developers](https://developer.microsoft.com/en-us/windows/holographic/mixed_reality_capture_for_developers) + +## System requirements + +**Client:** Windows 10 Holographic + +**Phone:** Not supported + +## Build the sample + +1. If you download the samples ZIP, be sure to unzip the entire archive, not just the folder with + the sample you want to build. +2. Start Microsoft Visual Studio 2015 and select **File** \> **Open** \> **Project/Solution**. +3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the + subfolder for this specific sample, then the subfolder for your preferred language (C++, C#, or + JavaScript). Double-click the Visual Studio 2015 Solution (.sln) file. +4. Press Ctrl+Shift+B, or select **Build** \> **Build Solution**. + +## Run the sample + +The next steps depend on whether you just want to deploy the sample or you want to both deploy and +run it. + +### Deploying the sample to the Microsoft HoloLens emulator + +- Click the debug target drop-down, and select **Microsoft HoloLens Emulator**. +- Select **Build** \> **Deploy** Solution. + +### Deploying the sample to a Microsoft HoloLens + +- Developer unlock your Microsoft HoloLens. For instructions, go to [Enable your device for development] + (https://msdn.microsoft.com/windows/uwp/get-started/enable-your-device-for-development#enable-your-windows-10-devices). +- Find the IP address of your Microsoft HoloLens. The IP address can be found in **Settings** + \> **Network & Internet** \> **Wi-Fi** \> **Advanced options**. Or, you can ask Cortana for this + information by saying: "Hey Cortana, what's my IP address?" +- Right-click on your project in Visual Studio, and then select **Properties**. +- In the Debugging pane, click the drop-down and select **Remote Machine**. +- Enter the IP address of your Microsoft HoloLens into the field labelled **Machine Name**. +- Click **OK**. +- Select **Build** \> **Deploy** Solution. + +### Pairing your developer-unlocked Microsoft HoloLens with Visual Studio + +The first time you deploy from your development PC to your developer-unlocked Microsoft HoloLens, +you will need to use a PIN to pair your PC with the Microsoft HoloLens. +- When you select **Build** \> **Deploy Solution**, a dialog box will appear for Visual Studio to + accept the PIN. +- On your Microsoft HoloLens, go to **Settings** \> **Update** \> **For developers**, and click on + **Pair**. +- Type the PIN displayed by your Microsoft HoloLens into the Visual Studio dialog box and click + **OK**. +- On your Microsoft HoloLens, select **Done** to accept the pairing. +- The solution will then start to deploy. + +### Deploying and running the sample + +- To debug the sample and then run it, follow the steps listed above to connect your + developer-unlocked Microsoft HoloLens, then press F5 or select **Debug** \> **Start Debugging**. + To run the sample without debugging, press Ctrl+F5 or select **Debug** \> **Start Without Debugging**. diff --git a/Samples/HolographicMixedRealityCapture/cpp/AppView.cpp b/Samples/HolographicMixedRealityCapture/cpp/AppView.cpp new file mode 100644 index 0000000000..05192b4833 --- /dev/null +++ b/Samples/HolographicMixedRealityCapture/cpp/AppView.cpp @@ -0,0 +1,195 @@ +#include "pch.h" +#include "AppView.h" + +#include + +using namespace HolographicMRCSample; + +using namespace concurrency; +using namespace Windows::ApplicationModel; +using namespace Windows::ApplicationModel::Activation; +using namespace Windows::ApplicationModel::Core; +using namespace Windows::Foundation; +using namespace Windows::Graphics::Holographic; +using namespace Windows::UI::Core; + +// The main function is only used to initialize our IFrameworkView class. +// Under most circumstances, you should not need to modify this function. +[Platform::MTAThread] +int main(Platform::Array^) +{ + AppViewSource^ appViewSource = ref new ::AppViewSource(); + CoreApplication::Run(appViewSource); + return 0; +} + +IFrameworkView^ AppViewSource::CreateView() +{ + return ref new AppView(); +} + +AppView::AppView() +{ +} + + +// IFrameworkView methods + +// The first method called when the IFrameworkView is being created. +// Use this method to subscribe for Windows shell events and to initialize your app. +void AppView::Initialize(CoreApplicationView^ applicationView) +{ + applicationView->Activated += + ref new TypedEventHandler(this, &AppView::OnViewActivated); + + // Register event handlers for app lifecycle. + CoreApplication::Suspending += + ref new EventHandler(this, &AppView::OnSuspending); + + CoreApplication::Resuming += + ref new EventHandler(this, &AppView::OnResuming); + + // At this point we have access to the device and we can create device-dependent + // resources. + m_deviceResources = std::make_shared(); + + m_main = std::make_unique(m_deviceResources); +} + +// Called when the CoreWindow object is created (or re-created). +void AppView::SetWindow(CoreWindow^ window) +{ + // Register for keypress notifications. + window->KeyDown += + ref new TypedEventHandler(this, &AppView::OnKeyPressed); + + // Register for notification that the app window is being closed. + window->Closed += + ref new TypedEventHandler(this, &AppView::OnWindowClosed); + + // Register for notifications that the app window is losing focus. + window->VisibilityChanged += + ref new TypedEventHandler(this, &AppView::OnVisibilityChanged); + + // Create a holographic space for the core window for the current view. + // Presenting holographic frames that are created by this holographic space will put + // the app into exclusive mode. + m_holographicSpace = HolographicSpace::CreateForCoreWindow(window); + + // The DeviceResources class uses the preferred DXGI adapter ID from the holographic + // space (when available) to create a Direct3D device. The HolographicSpace + // uses this ID3D11Device to create and manage device-based resources such as + // swap chains. + m_deviceResources->SetHolographicSpace(m_holographicSpace).then([this]() + { + // The main class uses the holographic space for updates and rendering. + m_main->SetHolographicSpace(m_holographicSpace); + }); +} + +// The Load method can be used to initialize scene resources or to load a +// previously saved app state. +void AppView::Load(Platform::String^ entryPoint) +{ +} + +// This method is called after the window becomes active. It oversees the +// update, draw, and present loop, and it also oversees window message processing. +void AppView::Run() +{ + while (!m_windowClosed) + { + if (m_windowVisible && (m_holographicSpace != nullptr)) + { + CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessAllIfPresent); + + HolographicFrame^ holographicFrame = m_main->Update(); + + if (holographicFrame) + { + if (m_main->Render(holographicFrame)) + { + // The holographic frame has an API that presents the swap chain for each + // holographic camera. + m_deviceResources->Present(holographicFrame); + } + } + } + else + { + CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessOneAndAllPending); + } + } +} + +// Terminate events do not cause Uninitialize to be called. It will be called if your IFrameworkView +// class is torn down while the app is in the foreground. +// This method is not often used, but IFrameworkView requires it and it will be called for +// holographic apps. +void AppView::Uninitialize() +{ + +} + + +// Application lifecycle event handlers + +// Called when the app view is activated. Activates the app's CoreWindow. +void AppView::OnViewActivated(CoreApplicationView^ sender, IActivatedEventArgs^ args) +{ + // Run() won't start until the CoreWindow is activated. + sender->CoreWindow->Activate(); +} + +void AppView::OnSuspending(Platform::Object^ sender, SuspendingEventArgs^ args) +{ + // Save app state asynchronously after requesting a deferral. Holding a deferral + // indicates that the application is busy performing suspending operations. Be + // aware that a deferral may not be held indefinitely; after about five seconds, + // the app will be forced to exit. + SuspendingDeferral^ deferral = args->SuspendingOperation->GetDeferral(); + + create_task([this, deferral] () + { + m_deviceResources->Trim(); + + if (m_main != nullptr) + { + m_main->SaveAppState(); + } + + deferral->Complete(); + }); +} + +void AppView::OnResuming(Platform::Object^ sender, Platform::Object^ args) +{ + // Restore any data or state that was unloaded on suspend. By default, data + // and state are persisted when resuming from suspend. Note that this event + // does not occur if the app was previously terminated. + + if (m_main != nullptr) + { + m_main->LoadAppState(); + } +} + + +// Window event handlers + +void AppView::OnVisibilityChanged(CoreWindow^ sender, VisibilityChangedEventArgs^ args) +{ + m_windowVisible = args->Visible; +} + +void AppView::OnWindowClosed(CoreWindow^ sender, CoreWindowEventArgs^ args) +{ + m_windowClosed = true; +} + + +// Input event handlers + +void AppView::OnKeyPressed(CoreWindow^ sender, KeyEventArgs^ args) +{ +} diff --git a/Samples/HolographicMixedRealityCapture/cpp/AppView.h b/Samples/HolographicMixedRealityCapture/cpp/AppView.h new file mode 100644 index 0000000000..287080b39f --- /dev/null +++ b/Samples/HolographicMixedRealityCapture/cpp/AppView.h @@ -0,0 +1,52 @@ +#pragma once + +#include "Common\DeviceResources.h" +#include "HolographicMRCSampleMain.h" + +namespace HolographicMRCSample +{ + // IFrameworkView class. Connects the app with the Windows shell and handles application lifecycle events. + ref class AppView sealed : public Windows::ApplicationModel::Core::IFrameworkView + { + public: + AppView(); + + // IFrameworkView methods. + virtual void Initialize(Windows::ApplicationModel::Core::CoreApplicationView^ applicationView); + virtual void SetWindow(Windows::UI::Core::CoreWindow^ window); + virtual void Load(Platform::String^ entryPoint); + virtual void Run(); + virtual void Uninitialize(); + + protected: + // Application lifecycle event handlers. + void OnViewActivated(Windows::ApplicationModel::Core::CoreApplicationView^ sender, Windows::ApplicationModel::Activation::IActivatedEventArgs^ args); + void OnSuspending(Platform::Object^ sender, Windows::ApplicationModel::SuspendingEventArgs^ args); + void OnResuming(Platform::Object^ sender, Platform::Object^ args); + + // Window event handlers. + void OnVisibilityChanged(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::VisibilityChangedEventArgs^ args); + void OnWindowClosed(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::CoreWindowEventArgs^ args); + + // CoreWindow input event handlers. + void OnKeyPressed(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::KeyEventArgs^ args); + + private: + std::unique_ptr m_main; + + std::shared_ptr m_deviceResources; + bool m_windowClosed = false; + bool m_windowVisible = true; + + // The holographic space the app will use for rendering. + Windows::Graphics::Holographic::HolographicSpace^ m_holographicSpace = nullptr; + }; + + // The entry point for the app. + ref class AppViewSource sealed : Windows::ApplicationModel::Core::IFrameworkViewSource + { + public: + virtual Windows::ApplicationModel::Core::IFrameworkView^ CreateView(); + }; +} + diff --git a/Samples/HolographicMixedRealityCapture/cpp/Assets/Cursor.png b/Samples/HolographicMixedRealityCapture/cpp/Assets/Cursor.png new file mode 100644 index 0000000000..31d9a7cf39 Binary files /dev/null and b/Samples/HolographicMixedRealityCapture/cpp/Assets/Cursor.png differ diff --git a/Samples/HolographicMixedRealityCapture/cpp/Assets/Hologram.png b/Samples/HolographicMixedRealityCapture/cpp/Assets/Hologram.png new file mode 100644 index 0000000000..a97a565112 Binary files /dev/null and b/Samples/HolographicMixedRealityCapture/cpp/Assets/Hologram.png differ diff --git a/Samples/HolographicMixedRealityCapture/cpp/Assets/Init.png b/Samples/HolographicMixedRealityCapture/cpp/Assets/Init.png new file mode 100644 index 0000000000..3be2855a2d Binary files /dev/null and b/Samples/HolographicMixedRealityCapture/cpp/Assets/Init.png differ diff --git a/Samples/HolographicMixedRealityCapture/cpp/Assets/Photo.png b/Samples/HolographicMixedRealityCapture/cpp/Assets/Photo.png new file mode 100644 index 0000000000..1b480fba69 Binary files /dev/null and b/Samples/HolographicMixedRealityCapture/cpp/Assets/Photo.png differ diff --git a/Samples/HolographicMixedRealityCapture/cpp/Assets/SysAudio.png b/Samples/HolographicMixedRealityCapture/cpp/Assets/SysAudio.png new file mode 100644 index 0000000000..eb40a10ff4 Binary files /dev/null and b/Samples/HolographicMixedRealityCapture/cpp/Assets/SysAudio.png differ diff --git a/Samples/HolographicMixedRealityCapture/cpp/Assets/Video.png b/Samples/HolographicMixedRealityCapture/cpp/Assets/Video.png new file mode 100644 index 0000000000..0749cf2d20 Binary files /dev/null and b/Samples/HolographicMixedRealityCapture/cpp/Assets/Video.png differ diff --git a/Samples/HolographicMixedRealityCapture/cpp/Common/CameraResources.cpp b/Samples/HolographicMixedRealityCapture/cpp/Common/CameraResources.cpp new file mode 100644 index 0000000000..195d5b4ebe --- /dev/null +++ b/Samples/HolographicMixedRealityCapture/cpp/Common/CameraResources.cpp @@ -0,0 +1,295 @@ +#include "pch.h" + +#include "CameraResources.h" +#include "Common\DirectXHelper.h" +#include "DeviceResources.h" +#include + +using namespace DirectX; +using namespace Microsoft::WRL; +using namespace Windows::Graphics::DirectX::Direct3D11; +using namespace Windows::Graphics::Holographic; +using namespace Windows::Perception::Spatial; + +DX::CameraResources::CameraResources(HolographicCamera^ camera) : + m_holographicCamera(camera), + m_isStereo(camera->IsStereo), + m_d3dRenderTargetSize(camera->RenderTargetSize) +{ + m_d3dViewport = CD3D11_VIEWPORT( + 0.f, 0.f, + m_d3dRenderTargetSize.Width, + m_d3dRenderTargetSize.Height + ); +}; + +// Updates resources associated with a holographic camera's swap chain. +// The app does not access the swap chain directly, but it does create +// resource views for the back buffer. +void DX::CameraResources::CreateResourcesForBackBuffer( + DX::DeviceResources* pDeviceResources, + HolographicCameraRenderingParameters^ cameraParameters + ) +{ + const auto device = pDeviceResources->GetD3DDevice(); + + // Get the WinRT object representing the holographic camera's back buffer. + IDirect3DSurface^ surface = cameraParameters->Direct3D11BackBuffer; + + // Get a DXGI interface for the holographic camera's back buffer. + // Holographic cameras do not provide the DXGI swap chain, which is owned + // by the system. The Direct3D back buffer resource is provided using WinRT + // interop APIs. + ComPtr resource; + ThrowIfFailed( + GetDXGIInterfaceFromObject(surface, IID_PPV_ARGS(&resource)) + ); + + // Get a Direct3D interface for the holographic camera's back buffer. + ComPtr cameraBackBuffer; + ThrowIfFailed( + resource.As(&cameraBackBuffer) + ); + + // Determine if the back buffer has changed. If so, ensure that the render target view + // is for the current back buffer. + if (m_d3dBackBuffer.Get() != cameraBackBuffer.Get()) + { + // This can change every frame as the system moves to the next buffer in the + // swap chain. This mode of operation will occur when certain rendering modes + // are activated. + m_d3dBackBuffer = cameraBackBuffer; + + // Create a render target view of the back buffer. + // Creating this resource is inexpensive, and is better than keeping track of + // the back buffers in order to pre-allocate render target views for each one. + DX::ThrowIfFailed( + device->CreateRenderTargetView( + m_d3dBackBuffer.Get(), + nullptr, + &m_d3dRenderTargetView + ) + ); + + // Get the DXGI format for the back buffer. + // This information can be accessed by the app using CameraResources::GetBackBufferDXGIFormat(). + D3D11_TEXTURE2D_DESC backBufferDesc; + m_d3dBackBuffer->GetDesc(&backBufferDesc); + m_dxgiFormat = backBufferDesc.Format; + + // Check for render target size changes. + Windows::Foundation::Size currentSize = m_holographicCamera->RenderTargetSize; + if (m_d3dRenderTargetSize != currentSize) + { + // Set render target size. + m_d3dRenderTargetSize = currentSize; + + // A new depth stencil view is also needed. + m_d3dDepthStencilView.Reset(); + } + } + + // Refresh depth stencil resources, if needed. + if (m_d3dDepthStencilView == nullptr) + { + // Create a depth stencil view for use with 3D rendering if needed. + CD3D11_TEXTURE2D_DESC depthStencilDesc( + DXGI_FORMAT_D16_UNORM, + static_cast(m_d3dRenderTargetSize.Width), + static_cast(m_d3dRenderTargetSize.Height), + m_isStereo ? 2 : 1, // Create two textures when rendering in stereo. + 1, // Use a single mipmap level. + D3D11_BIND_DEPTH_STENCIL + ); + + ComPtr depthStencil; + DX::ThrowIfFailed( + device->CreateTexture2D( + &depthStencilDesc, + nullptr, + &depthStencil + ) + ); + + CD3D11_DEPTH_STENCIL_VIEW_DESC depthStencilViewDesc( + m_isStereo ? D3D11_DSV_DIMENSION_TEXTURE2DARRAY : D3D11_DSV_DIMENSION_TEXTURE2D + ); + DX::ThrowIfFailed( + device->CreateDepthStencilView( + depthStencil.Get(), + &depthStencilViewDesc, + &m_d3dDepthStencilView + ) + ); + } + + // Create the constant buffer, if needed. + if (m_viewProjectionConstantBuffer == nullptr) + { + // Create a constant buffer to store view and projection matrices for the camera. + CD3D11_BUFFER_DESC constantBufferDesc(sizeof(ViewProjectionConstantBuffer), D3D11_BIND_CONSTANT_BUFFER); + DX::ThrowIfFailed( + device->CreateBuffer( + &constantBufferDesc, + nullptr, + &m_viewProjectionConstantBuffer + ) + ); + } + + if (m_blendState == nullptr) + { + D3D11_BLEND_DESC blendStateDesc; + ZeroMemory(&blendStateDesc, sizeof(D3D11_BLEND_DESC)); + blendStateDesc.AlphaToCoverageEnable = FALSE; + blendStateDesc.IndependentBlendEnable = FALSE; + blendStateDesc.RenderTarget[0].BlendEnable = TRUE; + blendStateDesc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA; + blendStateDesc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA; + blendStateDesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD; + blendStateDesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE; + blendStateDesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO; + blendStateDesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; + blendStateDesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; + + DX::ThrowIfFailed( + device->CreateBlendState(&blendStateDesc, m_blendState.ReleaseAndGetAddressOf()) + ); + + } +} + +// Releases resources associated with a back buffer. +void DX::CameraResources::ReleaseResourcesForBackBuffer(DX::DeviceResources* pDeviceResources) +{ + const auto context = pDeviceResources->GetD3DDeviceContext(); + + // Release camera-specific resources. + m_d3dBackBuffer.Reset(); + m_d3dRenderTargetView.Reset(); + m_d3dDepthStencilView.Reset(); + m_viewProjectionConstantBuffer.Reset(); + + // Ensure system references to the back buffer are released by clearing the render + // target from the graphics pipeline state, and then flushing the Direct3D context. + ID3D11RenderTargetView* nullViews[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT] = { nullptr }; + context->OMSetRenderTargets(ARRAYSIZE(nullViews), nullViews, nullptr); + context->Flush(); +} + +// Updates the view/projection constant buffer for a holographic camera. +void DX::CameraResources::UpdateViewProjectionBuffer( + std::shared_ptr deviceResources, + HolographicCameraPose^ cameraPose, + SpatialCoordinateSystem^ coordinateSystem + ) +{ + // The system changes the viewport on a per-frame basis for system optimizations. + m_d3dViewport = CD3D11_VIEWPORT( + cameraPose->Viewport.Left, + cameraPose->Viewport.Top, + cameraPose->Viewport.Width, + cameraPose->Viewport.Height + ); + + // The projection transform for each frame is provided by the HolographicCameraPose. + HolographicStereoTransform cameraProjectionTransform = cameraPose->ProjectionTransform; + + // Get a container object with the view and projection matrices for the given + // pose in the given coordinate system. + Platform::IBox^ viewTransformContainer = cameraPose->TryGetViewTransform(coordinateSystem); + + // If TryGetViewTransform returns a null pointer, that means the pose and coordinate + // system cannot be understood relative to one another; content cannot be rendered + // in this coordinate system for the duration of the current frame. + // This usually means that positional tracking is not active for the current frame, in + // which case it is possible to use a SpatialLocatorAttachedFrameOfReference to render + // content that is not world-locked instead. + DX::ViewProjectionConstantBuffer viewProjectionConstantBufferData; + bool viewTransformAcquired = viewTransformContainer != nullptr; + if (viewTransformAcquired) + { + // Otherwise, the set of view transforms can be retrieved. + HolographicStereoTransform viewCoordinateSystemTransform = viewTransformContainer->Value; + + // Update the view matrices. Holographic cameras (such as Microsoft HoloLens) are + // constantly moving relative to the world. The view matrices need to be updated + // every frame. + XMStoreFloat4x4( + &viewProjectionConstantBufferData.viewProjection[0], + XMMatrixTranspose(XMLoadFloat4x4(&viewCoordinateSystemTransform.Left) * XMLoadFloat4x4(&cameraProjectionTransform.Left)) + ); + XMStoreFloat4x4( + &viewProjectionConstantBufferData.viewProjection[1], + XMMatrixTranspose(XMLoadFloat4x4(&viewCoordinateSystemTransform.Right) * XMLoadFloat4x4(&cameraProjectionTransform.Right)) + ); + } + + // Use the D3D device context to update Direct3D device-based resources. + const auto context = deviceResources->GetD3DDeviceContext(); + + // Loading is asynchronous. Resources must be created before they can be updated. + if (context == nullptr || m_viewProjectionConstantBuffer == nullptr || !viewTransformAcquired) + { + m_framePending = false; + } + else + { + // Update the view and projection matrices. + context->UpdateSubresource( + m_viewProjectionConstantBuffer.Get(), + 0, + nullptr, + &viewProjectionConstantBufferData, + 0, + 0 + ); + + m_framePending = true; + } +} + +// Gets the view-projection constant buffer for the HolographicCamera and attaches it +// to the shader pipeline. +bool DX::CameraResources::AttachViewProjectionBuffer( + std::shared_ptr deviceResources + ) +{ + // This method uses Direct3D device-based resources. + const auto context = deviceResources->GetD3DDeviceContext(); + + // Loading is asynchronous. Resources must be created before they can be updated. + // Cameras can also be added asynchronously, in which case they must be initialized + // before they can be used. + if (context == nullptr || m_viewProjectionConstantBuffer == nullptr || m_framePending == false) + { + return false; + } + + // Set the viewport for this camera. + context->RSSetViewports(1, &m_d3dViewport); + + // Send the constant buffer to the vertex shader. + context->VSSetConstantBuffers( + 1, + 1, + m_viewProjectionConstantBuffer.GetAddressOf() + ); + + // The template includes a pass-through geometry shader that is used by + // default on systems that don't support the D3D11_FEATURE_D3D11_OPTIONS3:: + // VPAndRTArrayIndexFromAnyShaderFeedingRasterizer extension. The shader + // will be enabled at run-time on systems that require it. + // If your app will also use the geometry shader for other tasks and those + // tasks require the view/projection matrix, uncomment the following line + // of code to send the constant buffer to the geometry shader as well. + /*context->GSSetConstantBuffers( + 1, + 1, + m_viewProjectionConstantBuffer.GetAddressOf() + );*/ + + m_framePending = false; + + return true; +} diff --git a/Samples/HolographicMixedRealityCapture/cpp/Common/CameraResources.h b/Samples/HolographicMixedRealityCapture/cpp/Common/CameraResources.h new file mode 100644 index 0000000000..891be23fa1 --- /dev/null +++ b/Samples/HolographicMixedRealityCapture/cpp/Common/CameraResources.h @@ -0,0 +1,78 @@ +#pragma once + +namespace DX +{ + class DeviceResources; + + // Constant buffer used to send the view-projection matrices to the shader pipeline. + struct ViewProjectionConstantBuffer + { + DirectX::XMFLOAT4X4 viewProjection[2]; + }; + + // Assert that the constant buffer remains 16-byte aligned (best practice). + static_assert((sizeof(ViewProjectionConstantBuffer) % (sizeof(float) * 4)) == 0, "ViewProjection constant buffer size must be 16-byte aligned (16 bytes is the length of four floats)."); + + // Manages DirectX device resources that are specific to a holographic camera, such as the + // back buffer, ViewProjection constant buffer, and viewport. + class CameraResources + { + public: + CameraResources(Windows::Graphics::Holographic::HolographicCamera^ holographicCamera); + + void CreateResourcesForBackBuffer( + DX::DeviceResources* pDeviceResources, + Windows::Graphics::Holographic::HolographicCameraRenderingParameters^ cameraParameters + ); + void ReleaseResourcesForBackBuffer( + DX::DeviceResources* pDeviceResources + ); + + void UpdateViewProjectionBuffer( + std::shared_ptr deviceResources, + Windows::Graphics::Holographic::HolographicCameraPose^ cameraPose, + Windows::Perception::Spatial::SpatialCoordinateSystem^ coordinateSystem); + + bool AttachViewProjectionBuffer( + std::shared_ptr deviceResources); + + // Direct3D device resources. + ID3D11RenderTargetView* GetBackBufferRenderTargetView() const { return m_d3dRenderTargetView.Get(); } + ID3D11DepthStencilView* GetDepthStencilView() const { return m_d3dDepthStencilView.Get(); } + ID3D11Texture2D* GetBackBufferTexture2D() const { return m_d3dBackBuffer.Get(); } + D3D11_VIEWPORT GetViewport() const { return m_d3dViewport; } + DXGI_FORMAT GetBackBufferDXGIFormat() const { return m_dxgiFormat; } + ID3D11BlendState* GetBlendState() const { return m_blendState.Get(); } + + // Render target properties. + Windows::Foundation::Size GetRenderTargetSize() const { return m_d3dRenderTargetSize; } + bool IsRenderingStereoscopic() const { return m_isStereo; } + + // The holographic camera these resources are for. + Windows::Graphics::Holographic::HolographicCamera^ GetHolographicCamera() const { return m_holographicCamera; } + + private: + // Direct3D rendering objects. Required for 3D. + Microsoft::WRL::ComPtr m_d3dRenderTargetView; + Microsoft::WRL::ComPtr m_d3dDepthStencilView; + Microsoft::WRL::ComPtr m_d3dBackBuffer; + Microsoft::WRL::ComPtr m_blendState; + + // Device resource to store view and projection matrices. + Microsoft::WRL::ComPtr m_viewProjectionConstantBuffer; + + // Direct3D rendering properties. + DXGI_FORMAT m_dxgiFormat; + Windows::Foundation::Size m_d3dRenderTargetSize; + D3D11_VIEWPORT m_d3dViewport; + + // Indicates whether the camera supports stereoscopic rendering. + bool m_isStereo = false; + + // Indicates whether this camera has a pending frame. + bool m_framePending = false; + + // Pointer to the holographic camera these resources are for. + Windows::Graphics::Holographic::HolographicCamera^ m_holographicCamera = nullptr; + }; +} diff --git a/Samples/HolographicMixedRealityCapture/cpp/Common/DeviceResources.cpp b/Samples/HolographicMixedRealityCapture/cpp/Common/DeviceResources.cpp new file mode 100644 index 0000000000..edad2f5b0c --- /dev/null +++ b/Samples/HolographicMixedRealityCapture/cpp/Common/DeviceResources.cpp @@ -0,0 +1,507 @@ + +#include "pch.h" +#include "DeviceResources.h" +#include "DirectXHelper.h" + +#include +#include + +using namespace D2D1; +using namespace Microsoft::WRL; +using namespace Windows::Graphics::DirectX::Direct3D11; +using namespace Windows::Graphics::Display; +using namespace Windows::Graphics::Holographic; + +static const std::wstring s_VertexShaderFiles[DX::VertexShader_Max] = +{ + L"ms-appx:///VertexShader.cso", + L"ms-appx:///VprtVertexShader.cso", + L"ms-appx:///VertexShaderTexture.cso", + L"ms-appx:///VprtVertexShaderTexture.cso" +}; + +static const std::wstring s_PixelShaderFiles[DX::PixelShader_Max] = +{ + L"ms-appx:///PixelShader.cso", + L"ms-appx:///PixelShaderCursor.cso", + L"ms-appx:///PixelShaderTexture.cso", +}; + +static const std::wstring s_GeometryShaderFiles[DX::GeometryShader_Max] = +{ + L"ms-appx:///GeometryShader.cso", + L"ms-appx:///GeometryShaderTexture.cso" +}; + +static const std::wstring s_TextureFiles[DX::Texture_Max] = +{ + L"ms-appx:////Assets//Cursor.png", + L"ms-appx:////Assets//Init.png", + L"ms-appx:////Assets//Hologram.png", + L"ms-appx:////Assets//SysAudio.png", + L"ms-appx:////Assets//Photo.png", + L"ms-appx:////Assets//Video.png" +}; + +// Constructor for DeviceResources. +DX::DeviceResources::DeviceResources() +{ + CreateDeviceIndependentResources(); +} + +// Configures resources that don't depend on the Direct3D device. +void DX::DeviceResources::CreateDeviceIndependentResources() +{ + // Initialize Direct2D resources. + D2D1_FACTORY_OPTIONS options {}; + +#if defined(_DEBUG) + // If the project is in a debug build, enable Direct2D debugging via SDK Layers. + options.debugLevel = D2D1_DEBUG_LEVEL_INFORMATION; +#endif + + // Initialize the Direct2D Factory. + DX::ThrowIfFailed( + D2D1CreateFactory( + D2D1_FACTORY_TYPE_SINGLE_THREADED, + __uuidof(ID2D1Factory2), + &options, + &m_d2dFactory + ) + ); + + // Initialize the DirectWrite Factory. + DX::ThrowIfFailed( + DWriteCreateFactory( + DWRITE_FACTORY_TYPE_SHARED, + __uuidof(IDWriteFactory2), + &m_dwriteFactory + ) + ); + + // Initialize the Windows Imaging Component (WIC) Factory. + DX::ThrowIfFailed( + CoCreateInstance( + CLSID_WICImagingFactory2, + nullptr, + CLSCTX_INPROC_SERVER, + IID_PPV_ARGS(&m_wicFactory) + ) + ); +} + +Concurrency::task DX::DeviceResources::SetHolographicSpace(HolographicSpace^ holographicSpace) +{ + // Cache the holographic space. Used to re-initalize during device-lost scenarios. + m_holographicSpace = holographicSpace; + + InitializeUsingHolographicSpace(); + + return LoadShaders(); +} + +void DX::DeviceResources::InitializeUsingHolographicSpace() +{ + // The holographic space might need to determine which adapter supports + // holograms, in which case it will specify a non-zero PrimaryAdapterId. + LUID id = + { + m_holographicSpace->PrimaryAdapterId.LowPart, + m_holographicSpace->PrimaryAdapterId.HighPart + }; + + // When a primary adapter ID is given to the app, the app should find + // the corresponding DXGI adapter and use it to create Direct3D devices + // and device contexts. Otherwise, there is no restriction on the DXGI + // adapter the app can use. + if ((id.HighPart != 0) && (id.LowPart != 0)) + { + UINT createFlags = 0; +#ifdef DEBUG + if (DX::SdkLayersAvailable()) + { + createFlags |= DXGI_CREATE_FACTORY_DEBUG; + } +#endif + // Create the DXGI factory. + ComPtr dxgiFactory; + DX::ThrowIfFailed( + CreateDXGIFactory2( + createFlags, + IID_PPV_ARGS(&dxgiFactory) + ) + ); + ComPtr dxgiFactory4; + DX::ThrowIfFailed(dxgiFactory.As(&dxgiFactory4)); + + // Retrieve the adapter specified by the holographic space. + DX::ThrowIfFailed( + dxgiFactory4->EnumAdapterByLuid( + id, + IID_PPV_ARGS(&m_dxgiAdapter) + ) + ); + } + else + { + m_dxgiAdapter.Reset(); + } + + CreateDeviceResources(); + + m_holographicSpace->SetDirect3D11Device(m_d3dInteropDevice); +} + +// Configures the Direct3D device, and stores handles to it and the device context. +void DX::DeviceResources::CreateDeviceResources() +{ + // This flag adds support for surfaces with a different color channel ordering + // than the API default. It is required for compatibility with Direct2D. + UINT creationFlags = D3D11_CREATE_DEVICE_BGRA_SUPPORT; + +#if defined(_DEBUG) + if (DX::SdkLayersAvailable()) + { + // If the project is in a debug build, enable debugging via SDK Layers with this flag. + creationFlags |= D3D11_CREATE_DEVICE_DEBUG; + } +#endif + + // This array defines the set of DirectX hardware feature levels this app will support. + // Note the ordering should be preserved. + // Note that HoloLens supports feature level 11.1. The HoloLens emulator is also capable + // of running on graphics cards starting with feature level 10.0. + D3D_FEATURE_LEVEL featureLevels [] = + { + D3D_FEATURE_LEVEL_12_1, + D3D_FEATURE_LEVEL_12_0, + D3D_FEATURE_LEVEL_11_1, + D3D_FEATURE_LEVEL_11_0, + D3D_FEATURE_LEVEL_10_1, + D3D_FEATURE_LEVEL_10_0 + }; + + // Create the Direct3D 11 API device object and a corresponding context. + ComPtr device; + ComPtr context; + + const HRESULT hr = D3D11CreateDevice( + m_dxgiAdapter.Get(), // Either nullptr, or the primary adapter determined by Windows Holographic. + D3D_DRIVER_TYPE_HARDWARE, // Create a device using the hardware graphics driver. + 0, // Should be 0 unless the driver is D3D_DRIVER_TYPE_SOFTWARE. + creationFlags, // Set debug and Direct2D compatibility flags. + featureLevels, // List of feature levels this app can support. + ARRAYSIZE(featureLevels), // Size of the list above. + D3D11_SDK_VERSION, // Always set this to D3D11_SDK_VERSION for Windows Store apps. + &device, // Returns the Direct3D device created. + &m_d3dFeatureLevel, // Returns feature level of device created. + &context // Returns the device immediate context. + ); + + if (FAILED(hr)) + { + // If the initialization fails, fall back to the WARP device. + // For more information on WARP, see: + // http://go.microsoft.com/fwlink/?LinkId=286690 + DX::ThrowIfFailed( + D3D11CreateDevice( + nullptr, // Use the default DXGI adapter for WARP. + D3D_DRIVER_TYPE_WARP, // Create a WARP device instead of a hardware device. + 0, + creationFlags, + featureLevels, + ARRAYSIZE(featureLevels), + D3D11_SDK_VERSION, + &device, + &m_d3dFeatureLevel, + &context + ) + ); + } + + // Store pointers to the Direct3D device and immediate context. + DX::ThrowIfFailed( + device.As(&m_d3dDevice) + ); + + DX::ThrowIfFailed( + context.As(&m_d3dContext) + ); + + // Acquire the DXGI interface for the Direct3D device. + ComPtr dxgiDevice; + DX::ThrowIfFailed( + m_d3dDevice.As(&dxgiDevice) + ); + + // Wrap the native device using a WinRT interop object. + m_d3dInteropDevice = CreateDirect3DDevice(dxgiDevice.Get()); + + // Cache the DXGI adapter. + // This is for the case of no preferred DXGI adapter, or fallback to WARP. + ComPtr dxgiAdapter; + DX::ThrowIfFailed( + dxgiDevice->GetAdapter(&dxgiAdapter) + ); + DX::ThrowIfFailed( + dxgiAdapter.As(&m_dxgiAdapter) + ); + + // Check for device support for the optional feature that allows setting the render target array index from the vertex shader stage. + D3D11_FEATURE_DATA_D3D11_OPTIONS3 options; + m_d3dDevice->CheckFeatureSupport(D3D11_FEATURE_D3D11_OPTIONS3, &options, sizeof(options)); + if (options.VPAndRTArrayIndexFromAnyShaderFeedingRasterizer) + { + m_supportsVprt = true; + } +} + +// Validates the back buffer for each HolographicCamera and recreates +// resources for back buffers that have changed. +// Locks the set of holographic camera resources until the function exits. +void DX::DeviceResources::EnsureCameraResources( + HolographicFrame^ frame, + HolographicFramePrediction^ prediction) +{ + UseHolographicCameraResources([this, frame, prediction](std::map>& cameraResourceMap) + { + for (HolographicCameraPose^ pose : prediction->CameraPoses) + { + HolographicCameraRenderingParameters^ renderingParameters = frame->GetRenderingParameters(pose); + CameraResources* pCameraResources = cameraResourceMap[pose->HolographicCamera->Id].get(); + + pCameraResources->CreateResourcesForBackBuffer(this, renderingParameters); + } + }); +} + +// Prepares to allocate resources and adds resource views for a camera. +// Locks the set of holographic camera resources until the function exits. +void DX::DeviceResources::AddHolographicCamera(HolographicCamera^ camera) +{ + UseHolographicCameraResources([this, camera](std::map>& cameraResourceMap) + { + cameraResourceMap[camera->Id] = std::make_unique(camera); + }); +} + +// Deallocates resources for a camera and removes the camera from the set. +// Locks the set of holographic camera resources until the function exits. +void DX::DeviceResources::RemoveHolographicCamera(HolographicCamera^ camera) +{ + UseHolographicCameraResources([this, camera](std::map>& cameraResourceMap) + { + CameraResources* pCameraResources = cameraResourceMap[camera->Id].get(); + + if (pCameraResources != nullptr) + { + pCameraResources->ReleaseResourcesForBackBuffer(this); + cameraResourceMap.erase(camera->Id); + } + }); +} + +// Recreate all device resources and set them back to the current state. +// Locks the set of holographic camera resources until the function exits. +void DX::DeviceResources::HandleDeviceLost() +{ + if (m_deviceNotify != nullptr) + { + m_deviceNotify->OnDeviceLost(); + } + + UseHolographicCameraResources([this](std::map>& cameraResourceMap) + { + for (auto& pair : cameraResourceMap) + { + CameraResources* pCameraResources = pair.second.get(); + pCameraResources->ReleaseResourcesForBackBuffer(this); + } + }); + + InitializeUsingHolographicSpace(); + + LoadShaders().then([this]() + { + if (m_deviceNotify != nullptr) + { + m_deviceNotify->OnDeviceRestored(); + } + }); +} + +// Register our DeviceNotify to be informed on device lost and creation. +void DX::DeviceResources::RegisterDeviceNotify(DX::IDeviceNotify* deviceNotify) +{ + m_deviceNotify = deviceNotify; +} + +// Call this method when the app suspends. It provides a hint to the driver that the app +// is entering an idle state and that temporary buffers can be reclaimed for use by other apps. +void DX::DeviceResources::Trim() +{ + m_d3dContext->ClearState(); + + ComPtr dxgiDevice; + DX::ThrowIfFailed(m_d3dDevice.As(&dxgiDevice)); + dxgiDevice->Trim(); +} + +// Present the contents of the swap chain to the screen. +// Locks the set of holographic camera resources until the function exits. +void DX::DeviceResources::Present(HolographicFrame^ frame) +{ + // By default, this API waits for the frame to finish before it returns. + // Holographic apps should wait for the previous frame to finish before + // starting work on a new frame. This allows for better results from + // holographic frame predictions. + HolographicFramePresentResult presentResult = frame->PresentUsingCurrentPrediction(); + + HolographicFramePrediction^ prediction = frame->CurrentPrediction; + UseHolographicCameraResources([this, prediction](std::map>& cameraResourceMap) + { + for (auto cameraPose : prediction->CameraPoses) + { + // This represents the device-based resources for a HolographicCamera. + DX::CameraResources* pCameraResources = cameraResourceMap[cameraPose->HolographicCamera->Id].get(); + + // Discard the contents of the render target. + // This is a valid operation only when the existing contents will be + // entirely overwritten. If dirty or scroll rects are used, this call + // should be removed. + m_d3dContext->DiscardView(pCameraResources->GetBackBufferRenderTargetView()); + + // Discard the contents of the depth stencil. + m_d3dContext->DiscardView(pCameraResources->GetDepthStencilView()); + } + }); + + // The PresentUsingCurrentPrediction API will detect when the graphics device + // changes or becomes invalid. When this happens, it is considered a Direct3D + // device lost scenario. + if (presentResult == HolographicFramePresentResult::DeviceRemoved) + { + // The Direct3D device, context, and resources should be recreated. + HandleDeviceLost(); + } +} + +Concurrency::task DX::DeviceResources::LoadShaders() +{ + std::vector> shaderTaskGroup; + + // Load vertex shaders and input layouts + for (int i = 0; i < VertexShader_Max; i++) + { + Concurrency::task> loadVSTask = DX::ReadDataAsync(s_VertexShaderFiles[i]); + + Concurrency::task createVSTask = loadVSTask.then([this, i](const std::vector& fileData) + { + DX::ThrowIfFailed( + m_d3dDevice->CreateVertexShader( + &fileData[0], + fileData.size(), + nullptr, + m_vertexShaders[i].ReleaseAndGetAddressOf())); + + switch (i) + { + case VertexShader_Simple: + case VertexShader_VPRT: + { + const D3D11_INPUT_ELEMENT_DESC vertexDesc[] = + { + { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "COLOR", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 }, + }; + + DX::ThrowIfFailed( + m_d3dDevice->CreateInputLayout( + vertexDesc, + ARRAYSIZE(vertexDesc), + &fileData[0], + fileData.size(), + m_inputLayouts[i].ReleaseAndGetAddressOf())); + } + break; + case VertexShader_Texture: + case VertexShader_TextureVPRT: + { + const D3D11_INPUT_ELEMENT_DESC vertexDesc[] = + { + { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 }, + }; + + DX::ThrowIfFailed( + m_d3dDevice->CreateInputLayout( + vertexDesc, + ARRAYSIZE(vertexDesc), + &fileData[0], + fileData.size(), + m_inputLayouts[i].ReleaseAndGetAddressOf())); + } + break; + } + }); + + shaderTaskGroup.push_back(createVSTask); + } + + // Load pixel shaders + for (int i = 0; i < PixelShader_Max; i++) + { + Concurrency::task> loadPSTask = DX::ReadDataAsync(s_PixelShaderFiles[i]); + + Concurrency::task createPSTask = loadPSTask.then([this, i](const std::vector& fileData) + { + DX::ThrowIfFailed( + m_d3dDevice->CreatePixelShader( + &fileData[0], + fileData.size(), + nullptr, + m_pixelShaders[i].ReleaseAndGetAddressOf())); + }); + + shaderTaskGroup.push_back(createPSTask); + } + + // Load geometry shaders + for (int i = 0; i < GeometryShader_Max; i++) + { + Concurrency::task> loadGSTask = DX::ReadDataAsync(s_GeometryShaderFiles[i]); + + Concurrency::task createGSTask = loadGSTask.then([this, i](const std::vector& fileData) + { + DX::ThrowIfFailed( + m_d3dDevice->CreateGeometryShader( + &fileData[0], + fileData.size(), + nullptr, + m_geometryShaders[i].ReleaseAndGetAddressOf())); + }); + + shaderTaskGroup.push_back(createGSTask); + } + + // Load textures + for (int i = 0; i < Texture_Max; i++) + { + Concurrency::task> loadTextureTask = DX::ReadDataAsync(s_TextureFiles[i]); + + Concurrency::task createTextureTask = loadTextureTask.then([this, i](const std::vector& fileData) + { + DX::ThrowIfFailed( + DX::CreateWICTextureFromMemory( + m_d3dDevice.Get(), + &fileData[0], + fileData.size(), + m_textures[i].ReleaseAndGetAddressOf(), + nullptr)); + }); + + shaderTaskGroup.push_back(createTextureTask); + } + + return when_all(std::begin(shaderTaskGroup), std::end(shaderTaskGroup)); +} diff --git a/Samples/HolographicMixedRealityCapture/cpp/Common/DeviceResources.h b/Samples/HolographicMixedRealityCapture/cpp/Common/DeviceResources.h new file mode 100644 index 0000000000..8b01e53aa6 --- /dev/null +++ b/Samples/HolographicMixedRealityCapture/cpp/Common/DeviceResources.h @@ -0,0 +1,159 @@ + +#pragma once + +#include "CameraResources.h" +#include + +namespace DX +{ + typedef enum + { + VertexShader_Simple = 0, + VertexShader_VPRT, + VertexShader_Texture, + VertexShader_TextureVPRT, + VertexShader_Max + } VertexShaderIndex; + + typedef enum + { + PixelShader_Simple = 0, + PixelShader_Cursor, + PixelShader_Texture, + PixelShader_Max + } PixelShaderIndex; + + typedef enum + { + GeometryShader_Simple = 0, + GeometryShader_Texture, + GeometryShader_Max + } GeometryShaderIndex; + + typedef enum + { + Texture_Cursor = 0, + Texture_Init, + Texture_Hologram, + Texture_SysAudio, + Texture_Photo, + Texture_Video, + Texture_Max + } TextureIndex; + + // Provides an interface for an application that owns DeviceResources to be notified of the device being lost or created. + interface IDeviceNotify + { + virtual void OnDeviceLost() = 0; + virtual void OnDeviceRestored() = 0; + }; + + // Creates and manages a Direct3D device and immediate context, Direct2D device and context (for debug), and the holographic swap chain. + class DeviceResources + { + public: + DeviceResources(); + + // Public methods related to Direct3D devices. + void HandleDeviceLost(); + void RegisterDeviceNotify(IDeviceNotify* deviceNotify); + void Trim(); + void Present(Windows::Graphics::Holographic::HolographicFrame^ frame); + + // Public methods related to holographic devices. + Concurrency::task SetHolographicSpace(Windows::Graphics::Holographic::HolographicSpace^ space); + void EnsureCameraResources( + Windows::Graphics::Holographic::HolographicFrame^ frame, + Windows::Graphics::Holographic::HolographicFramePrediction^ prediction); + + void AddHolographicCamera(Windows::Graphics::Holographic::HolographicCamera^ camera); + void RemoveHolographicCamera(Windows::Graphics::Holographic::HolographicCamera^ camera); + + // Holographic accessors. + template + RetType UseHolographicCameraResources(const LCallback& callback); + + Windows::Graphics::DirectX::Direct3D11::IDirect3DDevice^ + GetD3DInteropDevice() const { return m_d3dInteropDevice; } + + // D3D accessors. + ID3D11Device4* GetD3DDevice() const { return m_d3dDevice.Get(); } + ID3D11DeviceContext3* GetD3DDeviceContext() const { return m_d3dContext.Get(); } + D3D_FEATURE_LEVEL GetDeviceFeatureLevel() const { return m_d3dFeatureLevel; } + bool GetDeviceSupportsVprt() const { return m_supportsVprt; } + + // DXGI acessors. + IDXGIAdapter3* GetDXGIAdapter() const { return m_dxgiAdapter.Get(); } + + // D2D accessors. + ID2D1Factory2* GetD2DFactory() const { return m_d2dFactory.Get(); } + IDWriteFactory2* GetDWriteFactory() const { return m_dwriteFactory.Get(); } + IWICImagingFactory2* GetWicImagingFactory() const { return m_wicFactory.Get(); } + + // Shader accessors. + ID3D11VertexShader* GetVertexShader(const VertexShaderIndex index) { return m_vertexShaders[index].Get(); } + ID3D11InputLayout* GetInputLayout(const VertexShaderIndex index) { return m_inputLayouts[index].Get(); } + ID3D11PixelShader* GetPixelShader(const PixelShaderIndex index) { return m_pixelShaders[index].Get(); } + ID3D11GeometryShader* GetGeometryShader(const GeometryShaderIndex index) { return m_geometryShaders[index].Get(); } + ID3D11Resource* GetTexture(const TextureIndex index) { return m_textures[index].Get(); } + + private: + // Private methods related to the Direct3D device, and resources based on that device. + void CreateDeviceIndependentResources(); + void InitializeUsingHolographicSpace(); + void CreateDeviceResources(); + Concurrency::task LoadShaders(); + + // Direct3D objects. + Microsoft::WRL::ComPtr m_d3dDevice; + Microsoft::WRL::ComPtr m_d3dContext; + Microsoft::WRL::ComPtr m_dxgiAdapter; + + // Direct3D interop objects. + Windows::Graphics::DirectX::Direct3D11::IDirect3DDevice^ m_d3dInteropDevice; + + // Direct2D factories. + Microsoft::WRL::ComPtr m_d2dFactory; + Microsoft::WRL::ComPtr m_dwriteFactory; + Microsoft::WRL::ComPtr m_wicFactory; + + // The holographic space provides a preferred DXGI adapter ID. + Windows::Graphics::Holographic::HolographicSpace^ m_holographicSpace = nullptr; + + // Properties of the Direct3D device currently in use. + D3D_FEATURE_LEVEL m_d3dFeatureLevel = D3D_FEATURE_LEVEL_10_0; + + // The IDeviceNotify can be held directly as it owns the DeviceResources. + IDeviceNotify* m_deviceNotify = nullptr; + + // Whether or not the current Direct3D device supports the optional feature + // for setting the render target array index from the vertex shader stage. + bool m_supportsVprt = false; + + // Back buffer resources, etc. for attached holographic cameras. + std::map> m_cameraResources; + + // Shader resources + Microsoft::WRL::ComPtr m_inputLayouts[VertexShader_Max]; + Microsoft::WRL::ComPtr m_vertexShaders[VertexShader_Max]; + Microsoft::WRL::ComPtr m_pixelShaders[PixelShader_Max]; + Microsoft::WRL::ComPtr m_geometryShaders[GeometryShader_Max]; + Microsoft::WRL::ComPtr m_textures[Texture_Max]; + + std::mutex m_cameraResourcesLock; + }; +} + +// Device-based resources for holographic cameras are stored in a std::map. Access this list by providing a +// callback to this function, and the std::map will be guarded from add and remove +// events until the callback returns. The callback is processed immediately and must +// not contain any nested calls to UseHolographicCameraResources. +// The callback takes a parameter of type std::map>& +// through which the list of cameras will be accessed. +template +RetType DX::DeviceResources::UseHolographicCameraResources(const LCallback& callback) +{ + std::lock_guard guard(m_cameraResourcesLock); + return callback(m_cameraResources); +} + diff --git a/Samples/HolographicMixedRealityCapture/cpp/Common/DirectXHelper.cpp b/Samples/HolographicMixedRealityCapture/cpp/Common/DirectXHelper.cpp new file mode 100644 index 0000000000..fd47138c0e --- /dev/null +++ b/Samples/HolographicMixedRealityCapture/cpp/Common/DirectXHelper.cpp @@ -0,0 +1,652 @@ +//-------------------------------------------------------------------------------------- +// This file is adapted from the file WICTextureLoader.cpp in the DirectXTex project. +// +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +// PARTICULAR PURPOSE. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// http://go.microsoft.com/fwlink/?LinkId=248926 +// http://go.microsoft.com/fwlink/?LinkId=248929 +//-------------------------------------------------------------------------------------- +#include +#include "DirectXHelper.h" +#include + +using namespace Microsoft::WRL; + +//------------------------------------------------------------------------------------- +// WIC Pixel Format Translation Data +//------------------------------------------------------------------------------------- +struct WICTranslate +{ + GUID wic; + DXGI_FORMAT format; +}; + +static WICTranslate g_WICFormats[] = +{ + { GUID_WICPixelFormat128bppRGBAFloat, DXGI_FORMAT_R32G32B32A32_FLOAT }, + + { GUID_WICPixelFormat64bppRGBAHalf, DXGI_FORMAT_R16G16B16A16_FLOAT }, + { GUID_WICPixelFormat64bppRGBA, DXGI_FORMAT_R16G16B16A16_UNORM }, + + { GUID_WICPixelFormat32bppRGBA, DXGI_FORMAT_R8G8B8A8_UNORM }, + { GUID_WICPixelFormat32bppBGRA, DXGI_FORMAT_B8G8R8A8_UNORM }, // DXGI 1.1 + { GUID_WICPixelFormat32bppBGR, DXGI_FORMAT_B8G8R8X8_UNORM }, // DXGI 1.1 + + { GUID_WICPixelFormat32bppRGBA1010102XR, DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM }, // DXGI 1.1 + { GUID_WICPixelFormat32bppRGBA1010102, DXGI_FORMAT_R10G10B10A2_UNORM }, + + { GUID_WICPixelFormat16bppBGRA5551, DXGI_FORMAT_B5G5R5A1_UNORM }, + { GUID_WICPixelFormat16bppBGR565, DXGI_FORMAT_B5G6R5_UNORM }, + + { GUID_WICPixelFormat32bppGrayFloat, DXGI_FORMAT_R32_FLOAT }, + { GUID_WICPixelFormat16bppGrayHalf, DXGI_FORMAT_R16_FLOAT }, + { GUID_WICPixelFormat16bppGray, DXGI_FORMAT_R16_UNORM }, + { GUID_WICPixelFormat8bppGray, DXGI_FORMAT_R8_UNORM }, + + { GUID_WICPixelFormat8bppAlpha, DXGI_FORMAT_A8_UNORM }, + + { GUID_WICPixelFormat96bppRGBFloat, DXGI_FORMAT_R32G32B32_FLOAT }, +}; + +//------------------------------------------------------------------------------------- +// WIC Pixel Format nearest conversion table +//------------------------------------------------------------------------------------- + +struct WICConvert +{ + GUID source; + GUID target; +}; + +static WICConvert g_WICConvert[] = +{ + // Note target GUID in this conversion table must be one of those directly supported formats (above). + + { GUID_WICPixelFormatBlackWhite, GUID_WICPixelFormat8bppGray }, // DXGI_FORMAT_R8_UNORM + + { GUID_WICPixelFormat1bppIndexed, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM + { GUID_WICPixelFormat2bppIndexed, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM + { GUID_WICPixelFormat4bppIndexed, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM + { GUID_WICPixelFormat8bppIndexed, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM + + { GUID_WICPixelFormat2bppGray, GUID_WICPixelFormat8bppGray }, // DXGI_FORMAT_R8_UNORM + { GUID_WICPixelFormat4bppGray, GUID_WICPixelFormat8bppGray }, // DXGI_FORMAT_R8_UNORM + + { GUID_WICPixelFormat16bppGrayFixedPoint, GUID_WICPixelFormat16bppGrayHalf }, // DXGI_FORMAT_R16_FLOAT + { GUID_WICPixelFormat32bppGrayFixedPoint, GUID_WICPixelFormat32bppGrayFloat }, // DXGI_FORMAT_R32_FLOAT + + { GUID_WICPixelFormat16bppBGR555, GUID_WICPixelFormat16bppBGRA5551 }, // DXGI_FORMAT_B5G5R5A1_UNORM + + { GUID_WICPixelFormat32bppBGR101010, GUID_WICPixelFormat32bppRGBA1010102 }, // DXGI_FORMAT_R10G10B10A2_UNORM + + { GUID_WICPixelFormat24bppBGR, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM + { GUID_WICPixelFormat24bppRGB, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM + { GUID_WICPixelFormat32bppPBGRA, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM + { GUID_WICPixelFormat32bppPRGBA, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM + + { GUID_WICPixelFormat48bppRGB, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM + { GUID_WICPixelFormat48bppBGR, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM + { GUID_WICPixelFormat64bppBGRA, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM + { GUID_WICPixelFormat64bppPRGBA, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM + { GUID_WICPixelFormat64bppPBGRA, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM + + { GUID_WICPixelFormat48bppRGBFixedPoint, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT + { GUID_WICPixelFormat48bppBGRFixedPoint, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT + { GUID_WICPixelFormat64bppRGBAFixedPoint, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT + { GUID_WICPixelFormat64bppBGRAFixedPoint, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT + { GUID_WICPixelFormat64bppRGBFixedPoint, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT + { GUID_WICPixelFormat64bppRGBHalf, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT + { GUID_WICPixelFormat48bppRGBHalf, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT + + { GUID_WICPixelFormat128bppPRGBAFloat, GUID_WICPixelFormat128bppRGBAFloat }, // DXGI_FORMAT_R32G32B32A32_FLOAT + { GUID_WICPixelFormat128bppRGBFloat, GUID_WICPixelFormat128bppRGBAFloat }, // DXGI_FORMAT_R32G32B32A32_FLOAT + { GUID_WICPixelFormat128bppRGBAFixedPoint, GUID_WICPixelFormat128bppRGBAFloat }, // DXGI_FORMAT_R32G32B32A32_FLOAT + { GUID_WICPixelFormat128bppRGBFixedPoint, GUID_WICPixelFormat128bppRGBAFloat }, // DXGI_FORMAT_R32G32B32A32_FLOAT + { GUID_WICPixelFormat32bppRGBE, GUID_WICPixelFormat128bppRGBAFloat }, // DXGI_FORMAT_R32G32B32A32_FLOAT + + { GUID_WICPixelFormat32bppCMYK, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM + { GUID_WICPixelFormat64bppCMYK, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM + { GUID_WICPixelFormat40bppCMYKAlpha, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM + { GUID_WICPixelFormat80bppCMYKAlpha, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM + + { GUID_WICPixelFormat32bppRGB, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM + { GUID_WICPixelFormat64bppRGB, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM + { GUID_WICPixelFormat64bppPRGBAHalf, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT + + { GUID_WICPixelFormat96bppRGBFixedPoint, GUID_WICPixelFormat96bppRGBFloat }, // DXGI_FORMAT_R32G32B32_FLOAT + + // We don't support n-channel formats +}; + +static IWICImagingFactory* _GetWIC() +{ + static INIT_ONCE s_initOnce = INIT_ONCE_STATIC_INIT; + + void* result = nullptr; + InitOnceExecuteOnce( + &s_initOnce, + [](_In_ PINIT_ONCE, void*, void** context) -> BOOL + { + HRESULT hr = CoCreateInstance( + CLSID_WICImagingFactory2, + nullptr, + CLSCTX_INPROC_SERVER, + __uuidof(IWICImagingFactory2), + context); + return SUCCEEDED(hr); + }, + nullptr, + &result); + + return reinterpret_cast(result); +} + +//--------------------------------------------------------------------------------- +static DXGI_FORMAT _WICToDXGI(const GUID& guid) +{ + for (size_t i = 0; i < _countof(g_WICFormats); ++i) + { + if (memcmp(&g_WICFormats[i].wic, &guid, sizeof(GUID)) == 0) + return g_WICFormats[i].format; + } + + return DXGI_FORMAT_UNKNOWN; +} + +//--------------------------------------------------------------------------------- +static size_t _WICBitsPerPixel(REFGUID targetGuid) +{ + IWICImagingFactory* pWIC = _GetWIC(); + if (!pWIC) + return 0; + + ComPtr cinfo; + if (FAILED(pWIC->CreateComponentInfo(targetGuid, cinfo.GetAddressOf()))) + return 0; + + WICComponentType type; + if (FAILED(cinfo->GetComponentType(&type))) + return 0; + + if (type != WICPixelFormat) + return 0; + + ComPtr pfinfo; + if (FAILED(cinfo.As(&pfinfo))) + return 0; + + UINT bpp; + if (FAILED(pfinfo->GetBitsPerPixel(&bpp))) + return 0; + + return bpp; +} + + +//-------------------------------------------------------------------------------------- +static DXGI_FORMAT MakeSRGB(_In_ DXGI_FORMAT format) +{ + switch (format) + { + case DXGI_FORMAT_R8G8B8A8_UNORM: + return DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; + + case DXGI_FORMAT_BC1_UNORM: + return DXGI_FORMAT_BC1_UNORM_SRGB; + + case DXGI_FORMAT_BC2_UNORM: + return DXGI_FORMAT_BC2_UNORM_SRGB; + + case DXGI_FORMAT_BC3_UNORM: + return DXGI_FORMAT_BC3_UNORM_SRGB; + + case DXGI_FORMAT_B8G8R8A8_UNORM: + return DXGI_FORMAT_B8G8R8A8_UNORM_SRGB; + + case DXGI_FORMAT_B8G8R8X8_UNORM: + return DXGI_FORMAT_B8G8R8X8_UNORM_SRGB; + + case DXGI_FORMAT_BC7_UNORM: + return DXGI_FORMAT_BC7_UNORM_SRGB; + + default: + return format; + } +} + +static HRESULT CreateTextureFromWIC(_In_ ID3D11Device* d3dDevice, + _In_opt_ ID3D11DeviceContext* d3dContext, + _In_ IWICBitmapFrameDecode *frame, + _In_ size_t maxsize, + _In_ D3D11_USAGE usage, + _In_ unsigned int bindFlags, + _In_ unsigned int cpuAccessFlags, + _In_ unsigned int miscFlags, + _In_ bool forceSRGB, + _Out_opt_ ID3D11Resource** texture, + _Out_opt_ ID3D11ShaderResourceView** textureView) +{ + UINT width, height; + HRESULT hr = frame->GetSize(&width, &height); + if (FAILED(hr)) + return hr; + + assert(width > 0 && height > 0); + + if (!maxsize) + { + // This is a bit conservative because the hardware could support larger textures than + // the Feature Level defined minimums, but doing it this way is much easier and more + // performant for WIC than the 'fail and retry' model used by DDSTextureLoader + + switch (d3dDevice->GetFeatureLevel()) + { + case D3D_FEATURE_LEVEL_9_1: + case D3D_FEATURE_LEVEL_9_2: + maxsize = 2048 /*D3D_FL9_1_REQ_TEXTURE2D_U_OR_V_DIMENSION*/; + break; + + case D3D_FEATURE_LEVEL_9_3: + maxsize = 4096 /*D3D_FL9_3_REQ_TEXTURE2D_U_OR_V_DIMENSION*/; + break; + + case D3D_FEATURE_LEVEL_10_0: + case D3D_FEATURE_LEVEL_10_1: + maxsize = 8192 /*D3D10_REQ_TEXTURE2D_U_OR_V_DIMENSION*/; + break; + + default: + maxsize = D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION; + break; + } + } + + assert(maxsize > 0); + + UINT twidth, theight; + if (width > maxsize || height > maxsize) + { + float ar = static_cast(height) / static_cast(width); + if (width > height) + { + twidth = static_cast(maxsize); + theight = static_cast(static_cast(maxsize) * ar); + } + else + { + theight = static_cast(maxsize); + twidth = static_cast(static_cast(maxsize) / ar); + } + assert(twidth <= maxsize && theight <= maxsize); + } + else + { + twidth = width; + theight = height; + } + + // Determine format + WICPixelFormatGUID pixelFormat; + hr = frame->GetPixelFormat(&pixelFormat); + if (FAILED(hr)) + return hr; + + WICPixelFormatGUID convertGUID; + memcpy(&convertGUID, &pixelFormat, sizeof(WICPixelFormatGUID)); + + size_t bpp = 0; + + DXGI_FORMAT format = _WICToDXGI(pixelFormat); + if (format == DXGI_FORMAT_UNKNOWN) + { + for (size_t i = 0; i < _countof(g_WICConvert); ++i) + { + if (memcmp(&g_WICConvert[i].source, &pixelFormat, sizeof(WICPixelFormatGUID)) == 0) + { + memcpy(&convertGUID, &g_WICConvert[i].target, sizeof(WICPixelFormatGUID)); + + format = _WICToDXGI(g_WICConvert[i].target); + assert(format != DXGI_FORMAT_UNKNOWN); + bpp = _WICBitsPerPixel(convertGUID); + break; + } + } + + if (format == DXGI_FORMAT_UNKNOWN) + return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); + } + else + { + bpp = _WICBitsPerPixel(pixelFormat); + } + + if ((format == DXGI_FORMAT_R32G32B32_FLOAT) && d3dContext != 0 && textureView != 0) + { + // Special case test for optional device support for autogen mipchains for R32G32B32_FLOAT + UINT fmtSupport = 0; + hr = d3dDevice->CheckFormatSupport(DXGI_FORMAT_R32G32B32_FLOAT, &fmtSupport); + if (FAILED(hr) || !(fmtSupport & D3D11_FORMAT_SUPPORT_MIP_AUTOGEN)) + { + // Use R32G32B32A32_FLOAT instead which is required for Feature Level 10.0 and up + memcpy(&convertGUID, &GUID_WICPixelFormat128bppRGBAFloat, sizeof(WICPixelFormatGUID)); + format = DXGI_FORMAT_R32G32B32A32_FLOAT; + bpp = 128; + } + } + + if (!bpp) + return E_FAIL; + + // Handle sRGB formats + if (forceSRGB) + { + format = MakeSRGB(format); + } + else + { + ComPtr metareader; + if (SUCCEEDED(frame->GetMetadataQueryReader(metareader.GetAddressOf()))) + { + GUID containerFormat; + if (SUCCEEDED(metareader->GetContainerFormat(&containerFormat))) + { + // Check for sRGB colorspace metadata + bool sRGB = false; + + PROPVARIANT value; + PropVariantInit(&value); + + if (memcmp(&containerFormat, &GUID_ContainerFormatPng, sizeof(GUID)) == 0) + { + // Check for sRGB chunk + if (SUCCEEDED(metareader->GetMetadataByName(L"/sRGB/RenderingIntent", &value)) && value.vt == VT_UI1) + { + sRGB = true; + } + } + else if (SUCCEEDED(metareader->GetMetadataByName(L"System.Image.ColorSpace", &value)) && value.vt == VT_UI2 && value.uiVal == 1) + { + sRGB = true; + } + + PropVariantClear(&value); + + if (sRGB) + format = MakeSRGB(format); + } + } + } + + // Verify our target format is supported by the current device + // (handles WDDM 1.0 or WDDM 1.1 device driver cases as well as DirectX 11.0 Runtime without 16bpp format support) + UINT support = 0; + hr = d3dDevice->CheckFormatSupport(format, &support); + if (FAILED(hr) || !(support & D3D11_FORMAT_SUPPORT_TEXTURE2D)) + { + // Fallback to RGBA 32-bit format which is supported by all devices + memcpy(&convertGUID, &GUID_WICPixelFormat32bppRGBA, sizeof(WICPixelFormatGUID)); + format = DXGI_FORMAT_R8G8B8A8_UNORM; + bpp = 32; + } + + // Allocate temporary memory for image + size_t rowPitch = (twidth * bpp + 7) / 8; + size_t imageSize = rowPitch * theight; + + std::unique_ptr temp(new (std::nothrow) uint8_t[imageSize]); + if (!temp) + return E_OUTOFMEMORY; + + // Load image data + if (memcmp(&convertGUID, &pixelFormat, sizeof(GUID)) == 0 + && twidth == width + && theight == height) + { + // No format conversion or resize needed + hr = frame->CopyPixels(0, static_cast(rowPitch), static_cast(imageSize), temp.get()); + if (FAILED(hr)) + return hr; + } + else if (twidth != width || theight != height) + { + // Resize + IWICImagingFactory* pWIC = _GetWIC(); + if (!pWIC) + return E_NOINTERFACE; + + ComPtr scaler; + hr = pWIC->CreateBitmapScaler(scaler.GetAddressOf()); + if (FAILED(hr)) + return hr; + + hr = scaler->Initialize(frame, twidth, theight, WICBitmapInterpolationModeFant); + if (FAILED(hr)) + return hr; + + WICPixelFormatGUID pfScaler; + hr = scaler->GetPixelFormat(&pfScaler); + if (FAILED(hr)) + return hr; + + if (memcmp(&convertGUID, &pfScaler, sizeof(GUID)) == 0) + { + // No format conversion needed + hr = scaler->CopyPixels(0, static_cast(rowPitch), static_cast(imageSize), temp.get()); + if (FAILED(hr)) + return hr; + } + else + { + ComPtr FC; + hr = pWIC->CreateFormatConverter(FC.GetAddressOf()); + if (FAILED(hr)) + return hr; + + BOOL canConvert = FALSE; + hr = FC->CanConvert(pfScaler, convertGUID, &canConvert); + if (FAILED(hr) || !canConvert) + { + return E_UNEXPECTED; + } + + hr = FC->Initialize(scaler.Get(), convertGUID, WICBitmapDitherTypeErrorDiffusion, 0, 0, WICBitmapPaletteTypeCustom); + if (FAILED(hr)) + return hr; + + hr = FC->CopyPixels(0, static_cast(rowPitch), static_cast(imageSize), temp.get()); + if (FAILED(hr)) + return hr; + } + } + else + { + // Format conversion but no resize + IWICImagingFactory* pWIC = _GetWIC(); + if (!pWIC) + return E_NOINTERFACE; + + ComPtr FC; + hr = pWIC->CreateFormatConverter(FC.GetAddressOf()); + if (FAILED(hr)) + return hr; + + BOOL canConvert = FALSE; + hr = FC->CanConvert(pixelFormat, convertGUID, &canConvert); + if (FAILED(hr) || !canConvert) + { + return E_UNEXPECTED; + } + + hr = FC->Initialize(frame, convertGUID, WICBitmapDitherTypeErrorDiffusion, 0, 0, WICBitmapPaletteTypeCustom); + if (FAILED(hr)) + return hr; + + hr = FC->CopyPixels(0, static_cast(rowPitch), static_cast(imageSize), temp.get()); + if (FAILED(hr)) + return hr; + } + + // See if format is supported for auto-gen mipmaps (varies by feature level) + bool autogen = false; + if (d3dContext != 0 && textureView != 0) // Must have context and shader-view to auto generate mipmaps + { + UINT fmtSupport = 0; + hr = d3dDevice->CheckFormatSupport(format, &fmtSupport); + if (SUCCEEDED(hr) && (fmtSupport & D3D11_FORMAT_SUPPORT_MIP_AUTOGEN)) + { + autogen = true; + } + } + + // Create texture + D3D11_TEXTURE2D_DESC desc; + desc.Width = twidth; + desc.Height = theight; + desc.MipLevels = (autogen) ? 0 : 1; + desc.ArraySize = 1; + desc.Format = format; + desc.SampleDesc.Count = 1; + desc.SampleDesc.Quality = 0; + desc.Usage = usage; + desc.CPUAccessFlags = cpuAccessFlags; + + if (autogen) + { + desc.BindFlags = bindFlags | D3D11_BIND_RENDER_TARGET; + desc.MiscFlags = miscFlags | D3D11_RESOURCE_MISC_GENERATE_MIPS; + } + else + { + desc.BindFlags = bindFlags; + desc.MiscFlags = miscFlags; + } + + D3D11_SUBRESOURCE_DATA initData; + initData.pSysMem = temp.get(); + initData.SysMemPitch = static_cast(rowPitch); + initData.SysMemSlicePitch = static_cast(imageSize); + + ID3D11Texture2D* tex = nullptr; + hr = d3dDevice->CreateTexture2D(&desc, (autogen) ? nullptr : &initData, &tex); + if (SUCCEEDED(hr) && tex != 0) + { + if (textureView != 0) + { + D3D11_SHADER_RESOURCE_VIEW_DESC SRVDesc; + memset(&SRVDesc, 0, sizeof(SRVDesc)); + SRVDesc.Format = desc.Format; + + SRVDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; + SRVDesc.Texture2D.MipLevels = (autogen) ? -1 : 1; + + hr = d3dDevice->CreateShaderResourceView(tex, &SRVDesc, textureView); + if (FAILED(hr)) + { + tex->Release(); + return hr; + } + + if (autogen) + { + assert(d3dContext != 0); + d3dContext->UpdateSubresource(tex, 0, nullptr, temp.get(), static_cast(rowPitch), static_cast(imageSize)); + d3dContext->GenerateMips(*textureView); + } + } + + if (texture != 0) + { + *texture = tex; + } + else + { + tex->Release(); + } + } + + return hr; +} + +HRESULT DX::CreateWICTextureFromMemoryEx(ID3D11Device* d3dDevice, + const uint8_t* wicData, + size_t wicDataSize, + size_t maxsize, + D3D11_USAGE usage, + unsigned int bindFlags, + unsigned int cpuAccessFlags, + unsigned int miscFlags, + bool forceSRGB, + ID3D11Resource** texture, + ID3D11ShaderResourceView** textureView) +{ + if (texture) + { + *texture = nullptr; + } + if (textureView) + { + *textureView = nullptr; + } + + if (!d3dDevice || !wicData || (!texture && !textureView)) + return E_INVALIDARG; + + if (!wicDataSize) + return E_FAIL; + +#ifdef _WIN64 + if (wicDataSize > 0xFFFFFFFF) + return HRESULT_FROM_WIN32(ERROR_FILE_TOO_LARGE); +#endif + + IWICImagingFactory* pWIC = _GetWIC(); + if (!pWIC) + return E_NOINTERFACE; + + // Create input stream for memory + ComPtr stream; + HRESULT hr = pWIC->CreateStream(stream.GetAddressOf()); + if (FAILED(hr)) + return hr; + + hr = stream->InitializeFromMemory(const_cast(wicData), static_cast(wicDataSize)); + if (FAILED(hr)) + return hr; + + // Initialize WIC + ComPtr decoder; + hr = pWIC->CreateDecoderFromStream(stream.Get(), 0, WICDecodeMetadataCacheOnDemand, decoder.GetAddressOf()); + if (FAILED(hr)) + return hr; + + ComPtr frame; + hr = decoder->GetFrame(0, frame.GetAddressOf()); + if (FAILED(hr)) + return hr; + + hr = CreateTextureFromWIC(d3dDevice, nullptr, + frame.Get(), maxsize, + usage, bindFlags, cpuAccessFlags, miscFlags, forceSRGB, + texture, textureView); + + return hr; +} + + +HRESULT DX::CreateWICTextureFromMemory(ID3D11Device* d3dDevice, + const uint8_t* wicData, + size_t wicDataSize, + ID3D11Resource** texture, + ID3D11ShaderResourceView** textureView, + size_t maxsize) +{ + return CreateWICTextureFromMemoryEx(d3dDevice, wicData, wicDataSize, maxsize, + D3D11_USAGE_DEFAULT, D3D11_BIND_SHADER_RESOURCE, 0, 0, false, + texture, textureView); +} + diff --git a/Samples/HolographicMixedRealityCapture/cpp/Common/DirectXHelper.h b/Samples/HolographicMixedRealityCapture/cpp/Common/DirectXHelper.h new file mode 100644 index 0000000000..dca6e7b369 --- /dev/null +++ b/Samples/HolographicMixedRealityCapture/cpp/Common/DirectXHelper.h @@ -0,0 +1,78 @@ +#pragma once + +#include // For create_task + +namespace DX +{ + inline void ThrowIfFailed(HRESULT hr) + { + if (FAILED(hr)) + { + // Set a breakpoint on this line to catch Win32 API errors. + throw Platform::Exception::CreateException(hr); + } + } + + // Function that reads from a binary file asynchronously. + inline Concurrency::task> ReadDataAsync(const std::wstring& filename) + { + using namespace Windows::Storage; + using namespace Concurrency; + + return create_task(PathIO::ReadBufferAsync(Platform::StringReference(filename.c_str()))).then( + [] (Streams::IBuffer^ fileBuffer) -> std::vector + { + std::vector returnBuffer; + returnBuffer.resize(fileBuffer->Length); + Streams::DataReader::FromBuffer(fileBuffer)->ReadBytes(Platform::ArrayReference(returnBuffer.data(), returnBuffer.size())); + return returnBuffer; + }); + } + + // Converts a length in device-independent pixels (DIPs) to a length in physical pixels. + inline float ConvertDipsToPixels(float dips, float dpi) + { + static const float dipsPerInch = 96.0f; + return floorf(dips * dpi / dipsPerInch + 0.5f); // Round to nearest integer. + } + + HRESULT CreateWICTextureFromMemoryEx(ID3D11Device* d3dDevice, + const uint8_t* wicData, + size_t wicDataSize, + size_t maxsize, + D3D11_USAGE usage, + unsigned int bindFlags, + unsigned int cpuAccessFlags, + unsigned int miscFlags, + bool forceSRGB, + ID3D11Resource** texture, + ID3D11ShaderResourceView** textureView); + + HRESULT CreateWICTextureFromMemory(ID3D11Device* d3dDevice, + const uint8_t* wicData, + size_t wicDataSize, + ID3D11Resource** texture, + ID3D11ShaderResourceView** textureView, + size_t maxsize = 0); + +#if defined(_DEBUG) + // Check for SDK Layer support. + inline bool SdkLayersAvailable() + { + HRESULT hr = D3D11CreateDevice( + nullptr, + D3D_DRIVER_TYPE_NULL, // There is no need to create a real hardware device. + 0, + D3D11_CREATE_DEVICE_DEBUG, // Check for the SDK layers. + nullptr, // Any feature level will do. + 0, + D3D11_SDK_VERSION, // Always set this to D3D11_SDK_VERSION for Windows Store apps. + nullptr, // No need to keep the D3D device reference. + nullptr, // No need to know the feature level. + nullptr // No need to keep the D3D device context reference. + ); + + return SUCCEEDED(hr); + } +#endif +} diff --git a/Samples/HolographicMixedRealityCapture/cpp/Common/StepTimer.h b/Samples/HolographicMixedRealityCapture/cpp/Common/StepTimer.h new file mode 100644 index 0000000000..eb9f8f6d72 --- /dev/null +++ b/Samples/HolographicMixedRealityCapture/cpp/Common/StepTimer.h @@ -0,0 +1,189 @@ +#pragma once + +namespace DX +{ + // Helper class for animation and simulation timing. + class StepTimer + { + public: + StepTimer() : + m_elapsedTicks(0), + m_totalTicks(0), + m_leftOverTicks(0), + m_frameCount(0), + m_framesPerSecond(0), + m_framesThisSecond(0), + m_qpcSecondCounter(0), + m_isFixedTimeStep(false), + m_targetElapsedTicks(TicksPerSecond / 60) + { + m_qpcFrequency = GetPerformanceFrequency(); + + // Initialize max delta to 1/10 of a second. + m_qpcMaxDelta = m_qpcFrequency / 10; + } + + // Get elapsed time since the previous Update call. + uint64 GetElapsedTicks() const { return m_elapsedTicks; } + double GetElapsedSeconds() const { return TicksToSeconds(m_elapsedTicks); } + + // Get total time since the start of the program. + uint64 GetTotalTicks() const { return m_totalTicks; } + double GetTotalSeconds() const { return TicksToSeconds(m_totalTicks); } + + // Get total number of updates since start of the program. + uint32 GetFrameCount() const { return m_frameCount; } + + // Get the current framerate. + uint32 GetFramesPerSecond() const { return m_framesPerSecond; } + + // Set whether to use fixed or variable timestep mode. + void SetFixedTimeStep(bool isFixedTimestep) { m_isFixedTimeStep = isFixedTimestep; } + + // Set how often to call Update when in fixed timestep mode. + void SetTargetElapsedTicks(uint64 targetElapsed) { m_targetElapsedTicks = targetElapsed; } + void SetTargetElapsedSeconds(double targetElapsed) { m_targetElapsedTicks = SecondsToTicks(targetElapsed); } + + // Integer format represents time using 10,000,000 ticks per second. + static const uint64 TicksPerSecond = 10'000'000; + + static double TicksToSeconds(uint64 ticks) { return static_cast(ticks) / TicksPerSecond; } + static uint64 SecondsToTicks(double seconds) { return static_cast(seconds * TicksPerSecond); } + + // Convenient wrapper for QueryPerformanceFrequency. Throws an exception if + // the call to QueryPerformanceFrequency fails. + static inline uint64 GetPerformanceFrequency() + { + LARGE_INTEGER freq; + if (!QueryPerformanceFrequency(&freq)) + { + throw ref new Platform::FailureException(); + } + return freq.QuadPart; + } + + // Gets the current number of ticks from QueryPerformanceCounter. Throws an + // exception if the call to QueryPerformanceCounter fails. + static inline int64 GetTicks() + { + LARGE_INTEGER ticks; + if (!QueryPerformanceCounter(&ticks)) + { + throw ref new Platform::FailureException(); + } + return ticks.QuadPart; + } + + // After an intentional timing discontinuity (for instance a blocking IO operation) + // call this to avoid having the fixed timestep logic attempt a set of catch-up + // Update calls. + + void ResetElapsedTime() + { + m_qpcLastTime = GetTicks(); + + m_leftOverTicks = 0; + m_framesPerSecond = 0; + m_framesThisSecond = 0; + m_qpcSecondCounter = 0; + } + + // Update timer state, calling the specified Update function the appropriate number of times. + template + void Tick(const TUpdate& update) + { + // Query the current time. + uint64 currentTime = GetTicks(); + uint64 timeDelta = currentTime - m_qpcLastTime; + + m_qpcLastTime = currentTime; + m_qpcSecondCounter += timeDelta; + + // Clamp excessively large time deltas (e.g. after paused in the debugger). + if (timeDelta > m_qpcMaxDelta) + { + timeDelta = m_qpcMaxDelta; + } + + // Convert QPC units into a canonical tick format. This cannot overflow due to the previous clamp. + timeDelta *= TicksPerSecond; + timeDelta /= m_qpcFrequency; + + uint32 lastFrameCount = m_frameCount; + + if (m_isFixedTimeStep) + { + // Fixed timestep update logic + + // If the app is running very close to the target elapsed time (within 1/4 of a millisecond) just clamp + // the clock to exactly match the target value. This prevents tiny and irrelevant errors + // from accumulating over time. Without this clamping, a game that requested a 60 fps + // fixed update, running with vsync enabled on a 59.94 NTSC display, would eventually + // accumulate enough tiny errors that it would drop a frame. It is better to just round + // small deviations down to zero to leave things running smoothly. + + if (abs(static_cast(timeDelta - m_targetElapsedTicks)) < TicksPerSecond / 4000) + { + timeDelta = m_targetElapsedTicks; + } + + m_leftOverTicks += timeDelta; + + while (m_leftOverTicks >= m_targetElapsedTicks) + { + m_elapsedTicks = m_targetElapsedTicks; + m_totalTicks += m_targetElapsedTicks; + m_leftOverTicks -= m_targetElapsedTicks; + m_frameCount++; + + update(); + } + } + else + { + // Variable timestep update logic. + m_elapsedTicks = timeDelta; + m_totalTicks += timeDelta; + m_leftOverTicks = 0; + m_frameCount++; + + update(); + } + + // Track the current framerate. + if (m_frameCount != lastFrameCount) + { + m_framesThisSecond++; + } + + if (m_qpcSecondCounter >= static_cast(m_qpcFrequency)) + { + m_framesPerSecond = m_framesThisSecond; + m_framesThisSecond = 0; + m_qpcSecondCounter %= m_qpcFrequency; + } + } + + private: + + // Source timing data uses QPC units. + uint64 m_qpcFrequency; + uint64 m_qpcLastTime; + uint64 m_qpcMaxDelta; + + // Derived timing data uses a canonical tick format. + uint64 m_elapsedTicks; + uint64 m_totalTicks; + uint64 m_leftOverTicks; + + // Members for tracking the framerate. + uint32 m_frameCount; + uint32 m_framesPerSecond; + uint32 m_framesThisSecond; + uint64 m_qpcSecondCounter; + + // Members for configuring fixed timestep mode. + bool m_isFixedTimeStep; + uint64 m_targetElapsedTicks; + }; +} diff --git a/Samples/HolographicMixedRealityCapture/cpp/Content/Button.cpp b/Samples/HolographicMixedRealityCapture/cpp/Content/Button.cpp new file mode 100644 index 0000000000..ec9a9a61b9 --- /dev/null +++ b/Samples/HolographicMixedRealityCapture/cpp/Content/Button.cpp @@ -0,0 +1,371 @@ +#include "pch.h" +#include "Button.h" +#include "Common\DirectXHelper.h" + +using namespace HolographicMRCSample; +using namespace Concurrency; +using namespace DirectX; +using namespace Windows::Foundation::Numerics; +using namespace Windows::UI::Input::Spatial; + +Button::Button(const Windows::Foundation::Numerics::float3 size, + const Windows::Foundation::Numerics::float4 color, + const Windows::Foundation::Numerics::float4 focusColor, + const Windows::Foundation::Numerics::float4 turnedOnColor, + const DX::TextureIndex textureId) : + m_size(size), + m_color(color), + m_colorFocus(focusColor), + m_colorOn(turnedOnColor), + m_textureIndex(textureId) +{ + m_type = Control_Button; +} + +// Called once per frame. Rotates the cube, and calculates and sets the model matrix +// relative to the position transform indicated by hologramPositionTransform. +void Button::DoUpdate( + const DX::StepTimer& timer, + HolographicFrame^ holographicFrame, + SpatialCoordinateSystem^ currentCoordinateSystem, + SpatialInteractionSourceState^ interactionSource, + const DirectX::XMMATRIX &parentTransform) +{ + // Rotate the cube. + const XMMATRIX modelRotation = XMMatrixRotationRollPitchYawFromVector(XMLoadFloat3(&m_rotation)); + + // Position the cube. + const XMMATRIX modelTranslation = XMMatrixTranslationFromVector(XMLoadFloat3(&m_position)); + + // Multiply to get the transform matrix. + // Note that this transform does not enforce a particular coordinate system. The calling + // class is responsible for rendering this content in a consistent manner. + const XMMATRIX modelTransform = modelRotation * modelTranslation * parentTransform; + XMStoreFloat4x4(&m_transform, modelTransform); + + // The view and projection matrices are provided by the system; they are associated + // with holographic cameras, and updated on a per-camera basis. + // Here, we provide the model transform for the sample hologram. The model transform + // matrix is transposed to prepare it for the shader. + XMStoreFloat4x4(&m_modelConstantBufferData.model, XMMatrixTranspose(modelTransform)); + + auto pointerPose = SpatialPointerPose::TryGetAtTimestamp(currentCoordinateSystem, holographicFrame->CurrentPrediction->Timestamp); + if (pointerPose != nullptr) + { + // Get the gaze direction relative to the given coordinate system. + const float3 position = pointerPose->Head->Position; + const float3 direction = pointerPose->Head->ForwardDirection; + + XMFLOAT3 headPosition = XMFLOAT3(position.x, position.y, position.z); + XMFLOAT3 headDirection = XMFLOAT3(direction.x, direction.y, direction.z); + float distance = 0.0f; + + BoundingOrientedBox currentBoundingBox; + GetBoundingBox(currentBoundingBox); + + m_focused = currentBoundingBox.Intersects(XMLoadFloat3(&headPosition), XMLoadFloat3(&headDirection), distance); + } + + if (m_enabled) + { + if (m_focused) + { + m_modelConstantBufferData.color.x = m_colorFocus.x; + m_modelConstantBufferData.color.y = m_colorFocus.y; + m_modelConstantBufferData.color.z = m_colorFocus.z; + m_modelConstantBufferData.color.w = m_colorFocus.w; + } + else + { + if (m_turnedOn) + { + m_modelConstantBufferData.color.x = m_colorOn.x; + m_modelConstantBufferData.color.y = m_colorOn.y; + m_modelConstantBufferData.color.z = m_colorOn.z; + m_modelConstantBufferData.color.w = m_colorOn.w; + } + else + { + m_modelConstantBufferData.color.x = m_color.x; + m_modelConstantBufferData.color.y = m_color.y; + m_modelConstantBufferData.color.z = m_color.z; + m_modelConstantBufferData.color.w = m_color.w; + } + } + } + else + { + m_modelConstantBufferData.color.x = 0.5f; + m_modelConstantBufferData.color.y = 0.5f; + m_modelConstantBufferData.color.z = 0.5f; + m_modelConstantBufferData.color.w = 1.0f; + } + + if (interactionSource) + { + if (m_focused && m_enabled && interactionSource->IsPressed && m_onAirTapCallback != nullptr) + { + Concurrency::task callbackTask = Concurrency::create_task([this]() + { + m_onAirTapCallback(); + }); + } + } +} + +// Renders one frame using the vertex and pixel shaders. +// On devices that do not support the D3D11_FEATURE_D3D11_OPTIONS3:: +// VPAndRTArrayIndexFromAnyShaderFeedingRasterizer optional feature, +// a pass-through geometry shader is also used to set the render +// target array index. +void Button::DoRender() +{ + // Loading is asynchronous. Resources must be created before drawing can occur. + if (!m_loadingComplete) + { + return; + } + + const auto context = m_deviceResources->GetD3DDeviceContext(); + + // Update the model transform buffer for the hologram. + context->UpdateSubresource( + m_modelConstantBuffer.Get(), + 0, + nullptr, + &m_modelConstantBufferData, + 0, + 0 + ); + + // Each vertex is one instance of the VertexPositionTexture struct. + const UINT stride = sizeof(VertexPositionTexture); + const UINT offset = 0; + context->IASetVertexBuffers( + 0, + 1, + m_vertexBuffer.GetAddressOf(), + &stride, + &offset + ); + context->IASetIndexBuffer( + m_indexBuffer.Get(), + DXGI_FORMAT_R16_UINT, // Each index is one 16-bit unsigned integer (short). + 0 + ); + context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + context->IASetInputLayout(m_inputLayout.Get()); + + // Attach the vertex shader. + context->VSSetShader( + m_vertexShader.Get(), + nullptr, + 0 + ); + // Apply the model constant buffer to the vertex shader. + context->VSSetConstantBuffers( + 0, + 1, + m_modelConstantBuffer.GetAddressOf() + ); + + if (!m_usingVprtShaders) + { + // On devices that do not support the D3D11_FEATURE_D3D11_OPTIONS3:: + // VPAndRTArrayIndexFromAnyShaderFeedingRasterizer optional feature, + // a pass-through geometry shader is used to set the render target + // array index. + context->GSSetShader( + m_geometryShader.Get(), + nullptr, + 0 + ); + } + + // Set Texture Resource view + context->PSSetShaderResources(0, 1, m_textureView.GetAddressOf()); + + // Set Sampler + context->PSSetSamplers(0, 1, m_samplerState.GetAddressOf()); + + // Attach the pixel shader. + context->PSSetShader( + m_pixelShader.Get(), + nullptr, + 0 + ); + + // Draw the objects. + context->DrawIndexedInstanced( + m_indexCount, // Index count per instance. + 2, // Instance count. + 0, // Start index location. + 0, // Base vertex location. + 0 // Start instance location. + ); +} + +void Button::DoCreateDeviceDependentResources() +{ + if (m_loadingComplete) + { + return; + } + + m_usingVprtShaders = m_deviceResources->GetDeviceSupportsVprt(); + + // On devices that do support the D3D11_FEATURE_D3D11_OPTIONS3:: + // VPAndRTArrayIndexFromAnyShaderFeedingRasterizer optional feature + // we can avoid using a pass-through geometry shader to set the render + // target array index, thus avoiding any overhead that would be + // incurred by setting the geometry shader stage. + + m_vertexShader = m_deviceResources->GetVertexShader(m_usingVprtShaders ? DX::VertexShader_TextureVPRT : DX::VertexShader_Texture); + m_inputLayout = m_deviceResources->GetInputLayout(m_usingVprtShaders ? DX::VertexShader_TextureVPRT : DX::VertexShader_Texture); + m_pixelShader = m_deviceResources->GetPixelShader(DX::PixelShader_Texture); + + D3D11_TEXTURE2D_DESC texDesc; + D3D11_SHADER_RESOURCE_VIEW_DESC viewDesc; + ZeroMemory(&viewDesc, sizeof(D3D11_SHADER_RESOURCE_VIEW_DESC)); + const auto context = m_deviceResources->GetD3DDeviceContext(); + + // Load Pressed Button texture and create resource view + Microsoft::WRL::ComPtr spResource; + Microsoft::WRL::ComPtr spTexture; + spResource = m_deviceResources->GetTexture(m_textureIndex); + DX::ThrowIfFailed(spResource.As(&spTexture)); + + spTexture->GetDesc(&texDesc); + viewDesc.Format = texDesc.Format; + viewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; + viewDesc.Texture2D.MostDetailedMip = 0; + viewDesc.Texture2D.MipLevels = 1; + DX::ThrowIfFailed(m_deviceResources->GetD3DDevice()->CreateShaderResourceView(spResource.Get(), &viewDesc, m_textureView.ReleaseAndGetAddressOf())); + + if (!m_usingVprtShaders) + { + // Get the pass-through geometry shader. + m_geometryShader = m_deviceResources->GetGeometryShader(DX::GeometryShader_Texture); + } + + // After the pixel shader file is loaded, create the shader and constant buffer. + const CD3D11_BUFFER_DESC constantBufferDesc(sizeof(ModelColorConstantBuffer), D3D11_BIND_CONSTANT_BUFFER); + DX::ThrowIfFailed( + m_deviceResources->GetD3DDevice()->CreateBuffer( + &constantBufferDesc, + nullptr, + &m_modelConstantBuffer)); + + // Once all shaders are loaded, create the mesh. + { + float halfWidth = m_size.x * 0.5f; + float halfHeight = m_size.y * 0.5f; + float halfDepth = m_size.z * 0.5f; + XMFLOAT3 color(m_color.x, m_color.y, m_color.z); + + m_boundingBox = BoundingOrientedBox(XMFLOAT3(0.0f, 0.0f, 0.0f), XMFLOAT3(halfWidth, halfHeight, halfDepth), XMFLOAT4(0.0f, 0.0f, 0.0f, 1.0f)); + + // Load mesh vertices. Each vertex has a position and a color. + const VertexPositionTexture cubeVertices[] = + { + { XMFLOAT3(-halfWidth, -halfHeight, -halfDepth), XMFLOAT2(0.0f, 0.0f) }, // 0 + { XMFLOAT3(-halfWidth, -halfHeight, halfDepth), XMFLOAT2(0.0f, 1.0f) }, // 1 + { XMFLOAT3(-halfWidth, halfHeight, -halfDepth), XMFLOAT2(0.0f, 0.0f) }, // 2 + { XMFLOAT3(-halfWidth, halfHeight, halfDepth), XMFLOAT2(0.0f, 0.0f) }, // 3 + { XMFLOAT3( halfWidth, -halfHeight, -halfDepth), XMFLOAT2(0.0f, 0.0f) }, // 4 + { XMFLOAT3( halfWidth, -halfHeight, halfDepth), XMFLOAT2(1.0f, 1.0f) }, // 5 + { XMFLOAT3( halfWidth, halfHeight, -halfDepth), XMFLOAT2(0.0f, 0.0f) }, // 6 + { XMFLOAT3( halfWidth, halfHeight, halfDepth), XMFLOAT2(1.0f, 0.0f) }, // 7 + }; + + D3D11_SUBRESOURCE_DATA vertexBufferData = {0}; + vertexBufferData.pSysMem = cubeVertices; + vertexBufferData.SysMemPitch = 0; + vertexBufferData.SysMemSlicePitch = 0; + const CD3D11_BUFFER_DESC vertexBufferDesc(sizeof(cubeVertices), D3D11_BIND_VERTEX_BUFFER); + DX::ThrowIfFailed( + m_deviceResources->GetD3DDevice()->CreateBuffer( + &vertexBufferDesc, + &vertexBufferData, + &m_vertexBuffer + ) + ); + + // Load mesh indices. Each trio of indices represents + // a triangle to be rendered on the screen. + // For example: 2,1,0 means that the vertices with indexes + // 2, 1, and 0 from the vertex buffer compose the + // first triangle of this mesh. + // Note that the winding order is clockwise by default. + static const unsigned short cubeIndices [] = + { + 2,1,0, // -x + 2,3,1, + + 6,4,5, // +x + 6,5,7, + + 0,1,5, // -y + 0,5,4, + + 2,6,7, // +y + 2,7,3, + + 0,4,6, // -z + 0,6,2, + + 1,3,7, // +z + 1,7,5, + }; + + m_indexCount = ARRAYSIZE(cubeIndices); + + D3D11_SUBRESOURCE_DATA indexBufferData = {0}; + indexBufferData.pSysMem = cubeIndices; + indexBufferData.SysMemPitch = 0; + indexBufferData.SysMemSlicePitch = 0; + const CD3D11_BUFFER_DESC indexBufferDesc(sizeof(cubeIndices), D3D11_BIND_INDEX_BUFFER); + DX::ThrowIfFailed( + m_deviceResources->GetD3DDevice()->CreateBuffer( + &indexBufferDesc, + &indexBufferData, + &m_indexBuffer + ) + ); + } + + // Create the sample state + D3D11_SAMPLER_DESC sampDesc; + ZeroMemory(&sampDesc, sizeof(sampDesc)); + sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP; + sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP; + sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP; + sampDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; + sampDesc.MaxLOD = D3D11_FLOAT32_MAX; + sampDesc.ComparisonFunc = D3D11_COMPARISON_NEVER; + + DX::ThrowIfFailed( + m_deviceResources->GetD3DDevice()->CreateSamplerState( + &sampDesc, + m_samplerState.ReleaseAndGetAddressOf())); + + + // Once the cube is loaded, the object is ready to be rendered. + m_loadingComplete = true; +} + +void Button::DoReleaseDeviceDependentResources() +{ + m_inputLayout.Reset(); + m_vertexBuffer.Reset(); + m_indexBuffer.Reset(); + m_vertexShader.Reset(); + m_geometryShader.Reset(); + m_pixelShader.Reset(); + m_modelConstantBuffer.Reset(); + m_samplerState.Reset(); + m_textureView.Reset(); + + m_loadingComplete = false; + m_usingVprtShaders = false; +} diff --git a/Samples/HolographicMixedRealityCapture/cpp/Content/Button.h b/Samples/HolographicMixedRealityCapture/cpp/Content/Button.h new file mode 100644 index 0000000000..b8c0c8047f --- /dev/null +++ b/Samples/HolographicMixedRealityCapture/cpp/Content/Button.h @@ -0,0 +1,63 @@ +#pragma once + +#include "ControlBase.h" + +namespace HolographicMRCSample +{ + // This sample renderer instantiates a basic rendering pipeline. + class Button : public ControlBase + { + public: + Button(const Windows::Foundation::Numerics::float3 size, + const Windows::Foundation::Numerics::float4 color, + const Windows::Foundation::Numerics::float4 focusColor, + const Windows::Foundation::Numerics::float4 turnedOnColor, + const DX::TextureIndex textureId); + + void SetSwitch(const bool isOn) { m_turnedOn = isOn; } + bool GetSwitch() { return m_turnedOn; } + + protected: + virtual void DoCreateDeviceDependentResources(); + virtual void DoReleaseDeviceDependentResources(); + + virtual void DoUpdate( + const DX::StepTimer& timer, + HolographicFrame^ holographicFrame, + SpatialCoordinateSystem^ currentCoordinateSystem, + SpatialInteractionSourceState^ interactionSource, + const DirectX::XMMATRIX &parentTransform); + virtual void DoRender(); + + private: + // Direct3D resources for cube geometry. + Microsoft::WRL::ComPtr m_inputLayout; + Microsoft::WRL::ComPtr m_vertexBuffer; + Microsoft::WRL::ComPtr m_indexBuffer; + Microsoft::WRL::ComPtr m_vertexShader; + Microsoft::WRL::ComPtr m_geometryShader; + Microsoft::WRL::ComPtr m_pixelShader; + Microsoft::WRL::ComPtr m_modelConstantBuffer; + Microsoft::WRL::ComPtr m_samplerState; + Microsoft::WRL::ComPtr m_textureView; + + // System resources for cube geometry. + ModelColorConstantBuffer m_modelConstantBufferData; + uint32 m_indexCount = 0; + + Windows::Foundation::Numerics::float3 m_size; + Windows::Foundation::Numerics::float4 m_color; + Windows::Foundation::Numerics::float4 m_colorFocus; + Windows::Foundation::Numerics::float4 m_colorOn; + DX::TextureIndex m_textureIndex; + + bool m_turnedOn = false; + + // Variables used with the rendering loop. + bool m_loadingComplete = false; + + // If the current D3D Device supports VPRT, we can avoid using a geometry + // shader just to set the render target array index. + bool m_usingVprtShaders = false; + }; +} diff --git a/Samples/HolographicMixedRealityCapture/cpp/Content/ControlBase.cpp b/Samples/HolographicMixedRealityCapture/cpp/Content/ControlBase.cpp new file mode 100644 index 0000000000..70a8bd91d5 --- /dev/null +++ b/Samples/HolographicMixedRealityCapture/cpp/Content/ControlBase.cpp @@ -0,0 +1,80 @@ +#include "pch.h" +#include "ControlBase.h" +#include "Common\DirectXHelper.h" + +using namespace HolographicMRCSample; +using namespace Concurrency; +using namespace DirectX; +using namespace Windows::Foundation::Numerics; +using namespace Windows::UI::Input::Spatial; + +// Loads vertex and pixel shaders from files and instantiates the cube geometry. +ControlBase::ControlBase() +{ +} + +void ControlBase::Initialize(const std::shared_ptr& deviceResources) +{ + m_deviceResources = deviceResources; + + CreateDeviceDependentResources(); +} + +ControlBase::~ControlBase() +{ + m_children.clear(); +} + +void ControlBase::CreateDeviceDependentResources() +{ + DoCreateDeviceDependentResources(); + + for (auto it = m_children.begin(); it != m_children.end(); it++) + { + it->get()->CreateDeviceDependentResources(); + } +} + +void ControlBase::ReleaseDeviceDependentResources() +{ + DoReleaseDeviceDependentResources(); + + for (auto it = m_children.begin(); it != m_children.end(); it++) + { + it->get()->ReleaseDeviceDependentResources(); + } +} + +void ControlBase::Update( + const DX::StepTimer& timer, + HolographicFrame^ holographicFrame, + SpatialCoordinateSystem^ currentCoordinateSystem, + SpatialInteractionSourceState^ interactionSource) +{ + Update(timer, holographicFrame, currentCoordinateSystem, interactionSource, DirectX::XMMatrixIdentity()); +} + +void ControlBase::Update( + const DX::StepTimer& timer, + HolographicFrame^ holographicFrame, + SpatialCoordinateSystem^ currentCoordinateSystem, + SpatialInteractionSourceState^ interactionSource, + const DirectX::XMMATRIX &parentTransform) +{ + DoUpdate(timer, holographicFrame, currentCoordinateSystem, interactionSource, parentTransform); + + for (auto it = m_children.begin(); it != m_children.end(); it++) + { + it->get()->Update(timer, holographicFrame, currentCoordinateSystem, interactionSource, DirectX::XMLoadFloat4x4(&m_transform)); + } +} + +void ControlBase::Render() +{ + DoRender(); + + for (auto it = m_children.begin(); it != m_children.end(); it++) + { + it->get()->Render(); + } +} diff --git a/Samples/HolographicMixedRealityCapture/cpp/Content/ControlBase.h b/Samples/HolographicMixedRealityCapture/cpp/Content/ControlBase.h new file mode 100644 index 0000000000..ba7802b60a --- /dev/null +++ b/Samples/HolographicMixedRealityCapture/cpp/Content/ControlBase.h @@ -0,0 +1,96 @@ +#pragma once + +#include "IControl.h" +#include "ShaderStructures.h" +#include +#include + +using namespace Windows::Graphics::Holographic; +using namespace Windows::Perception::Spatial; +using namespace Windows::UI::Input::Spatial; + +namespace HolographicMRCSample +{ + // This sample renderer instantiates a basic rendering pipeline. + class ControlBase : public IControl + { + public: + ControlBase(); + virtual ~ControlBase(); + + // IObject + virtual void Initialize(const std::shared_ptr& deviceResources); + virtual void CreateDeviceDependentResources(); + virtual void ReleaseDeviceDependentResources(); + virtual void Update( + const DX::StepTimer& timer, + HolographicFrame^ holographicFrame, + SpatialCoordinateSystem^ currentCoordinateSystem, + SpatialInteractionSourceState^ interactionSource); + virtual void Update( + const DX::StepTimer& timer, + HolographicFrame^ holographicFrame, + SpatialCoordinateSystem^ currentCoordinateSystem, + SpatialInteractionSourceState^ interactionSource, + const DirectX::XMMATRIX &parentTransform); + virtual void Render(); + + virtual void AddChild(const std::shared_ptr& object) { m_children.push_back(object); } + + virtual void SetPosition(Windows::Foundation::Numerics::float3 pos) { m_position = pos; } + virtual void SetRotation(Windows::Foundation::Numerics::float3 rot) { m_rotation = rot; } + virtual void SetScale(Windows::Foundation::Numerics::float3 scale) { m_scale = scale; } + + virtual Windows::Foundation::Numerics::float3 GetPosition() { return m_position; } + virtual Windows::Foundation::Numerics::float3 GetRotation() { return m_rotation; } + virtual Windows::Foundation::Numerics::float3 GetScale() { return m_scale; } + + virtual ControlType Type() { return m_type; } + virtual bool IsFocused() { return m_focused; } + virtual bool IsEnabled() { return m_enabled; } + + virtual void SetEnabled(const bool enabled) { m_enabled = enabled; } + + virtual void GetBoundingBox(DirectX::BoundingOrientedBox &boundingBox) + { + m_boundingBox.Transform(boundingBox, DirectX::XMLoadFloat4x4(&m_transform)); + } + + virtual void SetOnAirTapCallback(std::function callback) + { + m_onAirTapCallback = callback; + } + + protected: + virtual void DoCreateDeviceDependentResources() = 0; + virtual void DoReleaseDeviceDependentResources() = 0; + + virtual void DoUpdate( + const DX::StepTimer& timer, + HolographicFrame^ holographicFrame, + SpatialCoordinateSystem^ currentCoordinateSystem, + SpatialInteractionSourceState^ interactionSource, + const DirectX::XMMATRIX &parentTransform) = 0; + virtual void DoRender() = 0; + + protected: + // Cached pointer to device resources. + std::shared_ptr m_deviceResources; + + Windows::Foundation::Numerics::float3 m_position = { 0.0f, 0.0f, 0.0f }; + Windows::Foundation::Numerics::float3 m_rotation = { 0.0f, 0.0f, 0.0f }; + Windows::Foundation::Numerics::float3 m_scale = { 1.0f, 1.0f, 1.0f }; + + ControlType m_type = Control_Unknown; + bool m_enabled = true; + bool m_focused = false; + + std::function m_onAirTapCallback; + + DirectX::XMFLOAT4X4 m_transform; + + std::vector> m_children; + + DirectX::BoundingOrientedBox m_boundingBox; + }; +} diff --git a/Samples/HolographicMixedRealityCapture/cpp/Content/Cursor.cpp b/Samples/HolographicMixedRealityCapture/cpp/Content/Cursor.cpp new file mode 100644 index 0000000000..3a97e85094 --- /dev/null +++ b/Samples/HolographicMixedRealityCapture/cpp/Content/Cursor.cpp @@ -0,0 +1,309 @@ +#include "pch.h" +#include "Cursor.h" +#include "Common\DirectXHelper.h" + +using namespace HolographicMRCSample; +using namespace Concurrency; +using namespace DirectX; +using namespace Windows::Foundation::Numerics; +using namespace Windows::UI::Input::Spatial; + +// Loads vertex and pixel shaders from files and instantiates the cube geometry. +Cursor::Cursor(const float width, const float height) : + m_size(float2(width, height)), + m_textureIndex(DX::Texture_Cursor) +{ +} + +void Cursor::Initialize(const std::shared_ptr& deviceResources) +{ + m_deviceResources = deviceResources; + + CreateDeviceDependentResources(); +} + +// Called once per frame. Rotates the cube, and calculates and sets the model matrix +// relative to the position transform indicated by hologramPositionTransform. +void Cursor::Update( + const DX::StepTimer& timer, + HolographicFrame^ holographicFrame, + SpatialCoordinateSystem^ currentCoordinateSystem, + SpatialInteractionSourceState^ interactionSource) +{ + XMMATRIX modelTransform; + + PositionCursor(SpatialPointerPose::TryGetAtTimestamp(currentCoordinateSystem, + holographicFrame->CurrentPrediction->Timestamp), + modelTransform); + + // The view and projection matrices are provided by the system; they are associated + // with holographic cameras, and updated on a per-camera basis. + // Here, we provide the model transform for the sample hologram. The model transform + // matrix is transposed to prepare it for the shader. + XMStoreFloat4x4(&m_modelConstantBufferData.model, XMMatrixTranspose(modelTransform)); + m_modelConstantBufferData.color.x = 0.0f; + m_modelConstantBufferData.color.y = 0.0f; + m_modelConstantBufferData.color.z = 0.0f; + m_modelConstantBufferData.color.w = 0.0f; +} + +// Renders one frame using the vertex and pixel shaders. +// On devices that do not support the D3D11_FEATURE_D3D11_OPTIONS3:: +// VPAndRTArrayIndexFromAnyShaderFeedingRasterizer optional feature, +// a pass-through geometry shader is also used to set the render +// target array index. +void Cursor::Render() +{ + // Loading is asynchronous. Resources must be created before drawing can occur. + if (!m_loadingComplete) + { + return; + } + + const auto context = m_deviceResources->GetD3DDeviceContext(); + + // Update the model transform buffer for the hologram. + context->UpdateSubresource( + m_modelConstantBuffer.Get(), + 0, + nullptr, + &m_modelConstantBufferData, + 0, + 0 + ); + + // Each vertex is one instance of the VertexPositionTexture struct. + const UINT stride = sizeof(VertexPositionTexture); + const UINT offset = 0; + context->IASetVertexBuffers( + 0, + 1, + m_vertexBuffer.GetAddressOf(), + &stride, + &offset + ); + context->IASetIndexBuffer( + m_indexBuffer.Get(), + DXGI_FORMAT_R16_UINT, // Each index is one 16-bit unsigned integer (short). + 0 + ); + context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + context->IASetInputLayout(m_inputLayout.Get()); + + // Attach the vertex shader. + context->VSSetShader( + m_vertexShader.Get(), + nullptr, + 0 + ); + // Apply the model constant buffer to the vertex shader. + context->VSSetConstantBuffers( + 0, + 1, + m_modelConstantBuffer.GetAddressOf() + ); + + if (!m_usingVprtShaders) + { + // On devices that do not support the D3D11_FEATURE_D3D11_OPTIONS3:: + // VPAndRTArrayIndexFromAnyShaderFeedingRasterizer optional feature, + // a pass-through geometry shader is used to set the render target + // array index. + context->GSSetShader( + m_geometryShader.Get(), + nullptr, + 0 + ); + } + + // Set Texture Resource view + context->PSSetShaderResources(0, 1, m_cursorTextureView.GetAddressOf()); + + // Set Sampler + context->PSSetSamplers(0, 1, m_samplerState.GetAddressOf()); + + // Attach the pixel shader. + context->PSSetShader( + m_pixelShader.Get(), + nullptr, + 0 + ); + + // Draw the objects. + context->DrawIndexedInstanced( + m_indexCount, // Index count per instance. + 2, // Instance count. + 0, // Start index location. + 0, // Base vertex location. + 0 // Start instance location. + ); +} + +void Cursor::CreateDeviceDependentResources() +{ + if (m_loadingComplete) + { + return; + } + + m_usingVprtShaders = m_deviceResources->GetDeviceSupportsVprt(); + + // On devices that do support the D3D11_FEATURE_D3D11_OPTIONS3:: + // VPAndRTArrayIndexFromAnyShaderFeedingRasterizer optional feature + // we can avoid using a pass-through geometry shader to set the render + // target array index, thus avoiding any overhead that would be + // incurred by setting the geometry shader stage. + + m_vertexShader = m_deviceResources->GetVertexShader(m_usingVprtShaders ? DX::VertexShader_TextureVPRT : DX::VertexShader_Texture); + m_inputLayout = m_deviceResources->GetInputLayout(m_usingVprtShaders ? DX::VertexShader_TextureVPRT : DX::VertexShader_Texture); + m_pixelShader = m_deviceResources->GetPixelShader(DX::PixelShader_Cursor); + + D3D11_TEXTURE2D_DESC texDesc; + D3D11_SHADER_RESOURCE_VIEW_DESC viewDesc; + ZeroMemory(&viewDesc, sizeof(D3D11_SHADER_RESOURCE_VIEW_DESC)); + const auto context = m_deviceResources->GetD3DDeviceContext(); + + // Load Pressed Button texture and create resource view + Microsoft::WRL::ComPtr spResource; + Microsoft::WRL::ComPtr spTexture; + spResource = m_deviceResources->GetTexture(DX::Texture_Cursor); + DX::ThrowIfFailed(spResource.As(&spTexture)); + + spTexture->GetDesc(&texDesc); + viewDesc.Format = texDesc.Format; + viewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; + viewDesc.Texture2D.MostDetailedMip = 0; + viewDesc.Texture2D.MipLevels = 1; + DX::ThrowIfFailed(m_deviceResources->GetD3DDevice()->CreateShaderResourceView(spResource.Get(), &viewDesc, m_cursorTextureView.ReleaseAndGetAddressOf())); + + if (!m_usingVprtShaders) + { + // Get the pass-through geometry shader. + m_geometryShader = m_deviceResources->GetGeometryShader(DX::GeometryShader_Texture); + } + + // After the pixel shader file is loaded, create the shader and constant buffer. + const CD3D11_BUFFER_DESC constantBufferDesc(sizeof(ModelColorConstantBuffer), D3D11_BIND_CONSTANT_BUFFER); + DX::ThrowIfFailed( + m_deviceResources->GetD3DDevice()->CreateBuffer( + &constantBufferDesc, + nullptr, + &m_modelConstantBuffer)); + + // Once all shaders are loaded, create the mesh. + { + float halfWidth = m_size.x * 0.5f; + float halfHeight = m_size.y * 0.5f; + + // Load mesh vertices. Each vertex has a position and a texture UV. + const VertexPositionTexture cubeVertices[] = + { + { XMFLOAT3(-halfWidth, -halfHeight, 0.0f), XMFLOAT2(0.0f, 1.0f) }, // 0 (1) + { XMFLOAT3(-halfWidth, halfHeight, 0.0f), XMFLOAT2(0.0f, 0.0f) }, // 1 (3) + { XMFLOAT3( halfWidth, -halfHeight, 0.0f), XMFLOAT2(1.0f, 1.0f) }, // 2 (5) + { XMFLOAT3( halfWidth, halfHeight, 0.0f), XMFLOAT2(1.0f, 0.0f) }, // 3 (7) + }; + + D3D11_SUBRESOURCE_DATA vertexBufferData = {0}; + vertexBufferData.pSysMem = cubeVertices; + vertexBufferData.SysMemPitch = 0; + vertexBufferData.SysMemSlicePitch = 0; + const CD3D11_BUFFER_DESC vertexBufferDesc(sizeof(cubeVertices), D3D11_BIND_VERTEX_BUFFER); + DX::ThrowIfFailed( + m_deviceResources->GetD3DDevice()->CreateBuffer( + &vertexBufferDesc, + &vertexBufferData, + &m_vertexBuffer + ) + ); + + // Load mesh indices. Each trio of indices represents + // a triangle to be rendered on the screen. + // For example: 2,1,0 means that the vertices with indexes + // 2, 1, and 0 from the vertex buffer compose the + // first triangle of this mesh. + // Note that the winding order is clockwise by default. + static const unsigned short cubeIndices [] = + { + 0,1,3, + 0,3,2, + }; + + m_indexCount = ARRAYSIZE(cubeIndices); + + D3D11_SUBRESOURCE_DATA indexBufferData = {0}; + indexBufferData.pSysMem = cubeIndices; + indexBufferData.SysMemPitch = 0; + indexBufferData.SysMemSlicePitch = 0; + const CD3D11_BUFFER_DESC indexBufferDesc(sizeof(cubeIndices), D3D11_BIND_INDEX_BUFFER); + DX::ThrowIfFailed( + m_deviceResources->GetD3DDevice()->CreateBuffer( + &indexBufferDesc, + &indexBufferData, + &m_indexBuffer + ) + ); + } + + // Create the sample state + D3D11_SAMPLER_DESC sampDesc; + ZeroMemory(&sampDesc, sizeof(sampDesc)); + sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP; + sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP; + sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP; + sampDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; + sampDesc.MaxLOD = D3D11_FLOAT32_MAX; + sampDesc.ComparisonFunc = D3D11_COMPARISON_NEVER; + + DX::ThrowIfFailed( + m_deviceResources->GetD3DDevice()->CreateSamplerState( + &sampDesc, + m_samplerState.ReleaseAndGetAddressOf())); + + + // Once the cube is loaded, the object is ready to be rendered. + m_loadingComplete = true; +} + +void Cursor::ReleaseDeviceDependentResources() +{ + m_inputLayout.Reset(); + m_vertexBuffer.Reset(); + m_indexBuffer.Reset(); + m_vertexShader.Reset(); + m_geometryShader.Reset(); + m_pixelShader.Reset(); + m_modelConstantBuffer.Reset(); + m_samplerState.Reset(); + m_cursorTextureView.Reset(); + + m_loadingComplete = false; + m_usingVprtShaders = false; +} + +void Cursor::PositionCursor( + SpatialPointerPose^ pointerPose, + XMMATRIX &modelRotation) +{ + if (pointerPose != nullptr) + { + // Get the gaze direction relative to the given coordinate system. + const float3 headPosition = pointerPose->Head->Position; + const float3 headDirection = pointerPose->Head->ForwardDirection; + + const float3 gazeAtTwoMeters = headPosition + (m_distance * headDirection); + + // This will be used as the translation component of the hologram's + // model transform. + const float3 position = gazeAtTwoMeters; + + XMVECTOR facingNormal = XMVector3Normalize(-XMLoadFloat3(&position)); + XMVECTOR xAxisRotation = XMVector3Normalize(XMVectorSet(XMVectorGetZ(facingNormal), 0.0f, -XMVectorGetX(facingNormal), 0.0f)); + XMVECTOR yAxisRotation = XMVector3Normalize(XMVector3Cross(facingNormal, xAxisRotation)); + modelRotation = XMMATRIX(xAxisRotation, + yAxisRotation, + facingNormal, + XMVectorSet(0.0f, 0.0f, 0.0f, 1.0f)) * + XMMatrixTranslationFromVector(XMLoadFloat3(&position)); + } +} diff --git a/Samples/HolographicMixedRealityCapture/cpp/Content/Cursor.h b/Samples/HolographicMixedRealityCapture/cpp/Content/Cursor.h new file mode 100644 index 0000000000..4e60e2e941 --- /dev/null +++ b/Samples/HolographicMixedRealityCapture/cpp/Content/Cursor.h @@ -0,0 +1,57 @@ +#pragma once + +#include "Panel.h" + +namespace HolographicMRCSample +{ + class Cursor + { + public: + Cursor(const float width, const float height); + void Initialize(const std::shared_ptr& deviceResources); + + void CreateDeviceDependentResources(); + void ReleaseDeviceDependentResources(); + + void SetDistance(const float distance) { m_distance = distance; } + + void Update( + const DX::StepTimer& timer, + HolographicFrame^ holographicFrame, + SpatialCoordinateSystem^ currentCoordinateSystem, + SpatialInteractionSourceState^ interactionSource); + void Render(); + + private: + // Repositions the sample hologram. + void PositionCursor(Windows::UI::Input::Spatial::SpatialPointerPose^ pointerPose, + DirectX::XMMATRIX &modelTransform); + + // Cached pointer to device resources. + std::shared_ptr m_deviceResources; + + Microsoft::WRL::ComPtr m_inputLayout; + Microsoft::WRL::ComPtr m_vertexBuffer; + Microsoft::WRL::ComPtr m_indexBuffer; + Microsoft::WRL::ComPtr m_vertexShader; + Microsoft::WRL::ComPtr m_geometryShader; + Microsoft::WRL::ComPtr m_pixelShader; + Microsoft::WRL::ComPtr m_modelConstantBuffer; + Microsoft::WRL::ComPtr m_samplerState; + Microsoft::WRL::ComPtr m_cursorTextureView; + + ModelColorConstantBuffer m_modelConstantBufferData; + uint32 m_indexCount = 0; + + Windows::Foundation::Numerics::float2 m_size; + DX::TextureIndex m_textureIndex; + float m_distance = 2.0f; + + // Variables used with the rendering loop. + bool m_loadingComplete = false; + + // If the current D3D Device supports VPRT, we can avoid using a geometry + // shader just to set the render target array index. + bool m_usingVprtShaders = false; + }; +} diff --git a/Samples/HolographicMixedRealityCapture/cpp/Content/GeometryShader.hlsl b/Samples/HolographicMixedRealityCapture/cpp/Content/GeometryShader.hlsl new file mode 100644 index 0000000000..b966621d48 --- /dev/null +++ b/Samples/HolographicMixedRealityCapture/cpp/Content/GeometryShader.hlsl @@ -0,0 +1,31 @@ +// Per-vertex data from the vertex shader. +struct GeometryShaderInput +{ + min16float4 pos : SV_POSITION; + min16float3 color : COLOR0; + uint instId : TEXCOORD0; +}; + +// Per-vertex data passed to the rasterizer. +struct GeometryShaderOutput +{ + min16float4 pos : SV_POSITION; + min16float3 color : COLOR0; + uint rtvId : SV_RenderTargetArrayIndex; +}; + +// This geometry shader is a pass-through that leaves the geometry unmodified +// and sets the render target array index. +[maxvertexcount(3)] +void main(triangle GeometryShaderInput input[3], inout TriangleStream outStream) +{ + GeometryShaderOutput output; + [unroll(3)] + for (int i = 0; i < 3; ++i) + { + output.pos = input[i].pos; + output.color = input[i].color; + output.rtvId = input[i].instId; + outStream.Append(output); + } +} diff --git a/Samples/HolographicMixedRealityCapture/cpp/Content/GeometryShaderTexture.hlsl b/Samples/HolographicMixedRealityCapture/cpp/Content/GeometryShaderTexture.hlsl new file mode 100644 index 0000000000..5e18545796 --- /dev/null +++ b/Samples/HolographicMixedRealityCapture/cpp/Content/GeometryShaderTexture.hlsl @@ -0,0 +1,34 @@ +// Per-vertex data from the vertex shader. +struct GeometryShaderInput +{ + min16float4 pos : SV_POSITION; + min16float4 color : COLOR0; + min16float2 uv : TEXCOORD0; + uint instId : TEXCOORD1; +}; + +// Per-vertex data passed to the rasterizer. +struct GeometryShaderOutput +{ + min16float4 pos : SV_POSITION; + min16float4 color : COLOR0; + min16float2 uv : TEXCOORD0; + uint rtvId : SV_RenderTargetArrayIndex; +}; + +// This geometry shader is a pass-through that leaves the geometry unmodified +// and sets the render target array index. +[maxvertexcount(3)] +void main(triangle GeometryShaderInput input[3], inout TriangleStream outStream) +{ + GeometryShaderOutput output; + [unroll(3)] + for (int i = 0; i < 3; ++i) + { + output.pos = input[i].pos; + output.color = input[i].color; + output.uv = input[i].uv; + output.rtvId = input[i].instId; + outStream.Append(output); + } +} diff --git a/Samples/HolographicMixedRealityCapture/cpp/Content/IControl.h b/Samples/HolographicMixedRealityCapture/cpp/Content/IControl.h new file mode 100644 index 0000000000..e96d6295fb --- /dev/null +++ b/Samples/HolographicMixedRealityCapture/cpp/Content/IControl.h @@ -0,0 +1,58 @@ +#pragma once + +#include +#include "..\Common\DeviceResources.h" +#include "..\Common\StepTimer.h" +#include + +namespace HolographicMRCSample +{ + typedef enum + { + Control_Unknown = 0, + Control_Panel, + Control_Button, + Control_CameraPreview + } ControlType; + + class IControl + { + public: + virtual void Initialize(const std::shared_ptr& deviceResources) = 0; + virtual void CreateDeviceDependentResources() = 0; + virtual void ReleaseDeviceDependentResources() = 0; + + virtual void Update( + const DX::StepTimer& timer, + Windows::Graphics::Holographic::HolographicFrame^ holographicFrame, + Windows::Perception::Spatial::SpatialCoordinateSystem^ currentCoordinateSystem, + Windows::UI::Input::Spatial::SpatialInteractionSourceState^ interactionSource) = 0; + virtual void Update( + const DX::StepTimer& timer, + Windows::Graphics::Holographic::HolographicFrame^ holographicFrame, + Windows::Perception::Spatial::SpatialCoordinateSystem^ currentCoordinateSystem, + Windows::UI::Input::Spatial::SpatialInteractionSourceState^ interactionSource, + const DirectX::XMMATRIX &parentTransform) = 0; + virtual void Render() = 0; + + virtual void AddChild(const std::shared_ptr& object) = 0; + + virtual void SetPosition(Windows::Foundation::Numerics::float3 pos) = 0; + virtual void SetRotation(Windows::Foundation::Numerics::float3 rot) = 0; + virtual void SetScale(Windows::Foundation::Numerics::float3 scale) = 0; + + virtual Windows::Foundation::Numerics::float3 GetPosition() = 0; + virtual Windows::Foundation::Numerics::float3 GetRotation() = 0; + virtual Windows::Foundation::Numerics::float3 GetScale() = 0; + + virtual ControlType Type() = 0; + virtual bool IsFocused() = 0; + virtual bool IsEnabled() = 0; + + virtual void SetEnabled(const bool enabled) = 0; + + virtual void GetBoundingBox(DirectX::BoundingOrientedBox &boundingBox) = 0; + + virtual void SetOnAirTapCallback(std::function callback) = 0; + }; +} diff --git a/Samples/HolographicMixedRealityCapture/cpp/Content/Panel.cpp b/Samples/HolographicMixedRealityCapture/cpp/Content/Panel.cpp new file mode 100644 index 0000000000..b62f86a1a3 --- /dev/null +++ b/Samples/HolographicMixedRealityCapture/cpp/Content/Panel.cpp @@ -0,0 +1,264 @@ +#include "pch.h" +#include "Panel.h" +#include "Common\DirectXHelper.h" + +using namespace HolographicMRCSample; +using namespace Concurrency; +using namespace DirectX; +using namespace Windows::Foundation::Numerics; +using namespace Windows::UI::Input::Spatial; + +// Loads vertex and pixel shaders from files and instantiates the cube geometry. +Panel::Panel(const float width, const float height, const float depth, + const float red, const float green, const float blue, const float alpha) : + m_size(Windows::Foundation::Numerics::float3(width, height, depth)), + m_color(Windows::Foundation::Numerics::float4(red, green, blue, alpha)) +{ +} + +// Called once per frame. Rotates the cube, and calculates and sets the model matrix +// relative to the position transform indicated by hologramPositionTransform. +void Panel::DoUpdate( + const DX::StepTimer& timer, + HolographicFrame^ holographicFrame, + SpatialCoordinateSystem^ currentCoordinateSystem, + SpatialInteractionSourceState^ interactionSource, + const DirectX::XMMATRIX &parentTransform) +{ + // Rotate the cube. + const XMMATRIX modelRotation = XMMatrixRotationRollPitchYawFromVector(XMLoadFloat3(&m_rotation)); + + // Position the cube. + const XMMATRIX modelTranslation = XMMatrixTranslationFromVector(XMLoadFloat3(&m_position)); + + // Multiply to get the transform matrix. + // Note that this transform does not enforce a particular coordinate system. The calling + // class is responsible for rendering this content in a consistent manner. + const XMMATRIX modelTransform = modelRotation * modelTranslation * parentTransform; + XMStoreFloat4x4(&m_transform, modelTransform); + + // The view and projection matrices are provided by the system; they are associated + // with holographic cameras, and updated on a per-camera basis. + // Here, we provide the model transform for the sample hologram. The model transform + // matrix is transposed to prepare it for the shader. + XMStoreFloat4x4(&m_modelConstantBufferData.model, XMMatrixTranspose(modelTransform)); +} + +// Renders one frame using the vertex and pixel shaders. +// On devices that do not support the D3D11_FEATURE_D3D11_OPTIONS3:: +// VPAndRTArrayIndexFromAnyShaderFeedingRasterizer optional feature, +// a pass-through geometry shader is also used to set the render +// target array index. +void Panel::DoRender() +{ + // Loading is asynchronous. Resources must be created before drawing can occur. + if (!m_loadingComplete) + { + return; + } + + const auto context = m_deviceResources->GetD3DDeviceContext(); + + // Update the model transform buffer for the hologram. + context->UpdateSubresource( + m_modelConstantBuffer.Get(), + 0, + nullptr, + &m_modelConstantBufferData, + 0, + 0 + ); + + // Each vertex is one instance of the VertexPositionColor struct. + const UINT stride = sizeof(VertexPositionColor); + const UINT offset = 0; + context->IASetVertexBuffers( + 0, + 1, + m_vertexBuffer.GetAddressOf(), + &stride, + &offset + ); + context->IASetIndexBuffer( + m_indexBuffer.Get(), + DXGI_FORMAT_R16_UINT, // Each index is one 16-bit unsigned integer (short). + 0 + ); + context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + context->IASetInputLayout(m_inputLayout.Get()); + + // Attach the vertex shader. + context->VSSetShader( + m_vertexShader.Get(), + nullptr, + 0 + ); + // Apply the model constant buffer to the vertex shader. + context->VSSetConstantBuffers( + 0, + 1, + m_modelConstantBuffer.GetAddressOf() + ); + + if (!m_usingVprtShaders) + { + // On devices that do not support the D3D11_FEATURE_D3D11_OPTIONS3:: + // VPAndRTArrayIndexFromAnyShaderFeedingRasterizer optional feature, + // a pass-through geometry shader is used to set the render target + // array index. + context->GSSetShader( + m_geometryShader.Get(), + nullptr, + 0 + ); + } + + // Attach the pixel shader. + context->PSSetShader( + m_pixelShader.Get(), + nullptr, + 0 + ); + + // Draw the objects. + context->DrawIndexedInstanced( + m_indexCount, // Index count per instance. + 2, // Instance count. + 0, // Start index location. + 0, // Base vertex location. + 0 // Start instance location. + ); +} + +void Panel::DoCreateDeviceDependentResources() +{ + if (m_loadingComplete) + { + return; + } + + m_usingVprtShaders = m_deviceResources->GetDeviceSupportsVprt(); + + // On devices that do support the D3D11_FEATURE_D3D11_OPTIONS3:: + // VPAndRTArrayIndexFromAnyShaderFeedingRasterizer optional feature + // we can avoid using a pass-through geometry shader to set the render + // target array index, thus avoiding any overhead that would be + // incurred by setting the geometry shader stage. + + m_vertexShader = m_deviceResources->GetVertexShader(m_usingVprtShaders ? DX::VertexShader_VPRT : DX::VertexShader_Simple); + m_inputLayout = m_deviceResources->GetInputLayout(m_usingVprtShaders ? DX::VertexShader_VPRT : DX::VertexShader_Simple); + m_pixelShader = m_deviceResources->GetPixelShader(DX::PixelShader_Simple); + + if (!m_usingVprtShaders) + { + // Get the pass-through geometry shader. + m_geometryShader = m_deviceResources->GetGeometryShader(DX::GeometryShader_Simple); + } + + // After the pixel shader file is loaded, create the shader and constant buffer. + const CD3D11_BUFFER_DESC constantBufferDesc(sizeof(ModelConstantBuffer), D3D11_BIND_CONSTANT_BUFFER); + DX::ThrowIfFailed( + m_deviceResources->GetD3DDevice()->CreateBuffer( + &constantBufferDesc, + nullptr, + &m_modelConstantBuffer)); + + // Once all shaders are loaded, create the mesh. + { + float halfWidth = m_size.x * 0.5f; + float halfHeight = m_size.y * 0.5f; + float halfDepth = m_size.z * 0.5f; + XMFLOAT4 color(m_color.x, m_color.y, m_color.z, m_color.w); + + // initiate bounding box + m_boundingBox = BoundingOrientedBox(XMFLOAT3(0.0f, 0.0f, 0.0f), XMFLOAT3(halfWidth, halfHeight, halfDepth), XMFLOAT4(0.0f, 0.0f, 0.0f, 1.0f)); + + // Load mesh vertices. Each vertex has a position and a color. + // Note that the cube size has changed from the default DirectX app + // template. Windows Holographic is scaled in meters, so to draw the + // cube at a comfortable size we made the cube width 0.2 m (20 cm). + const VertexPositionColor cubeVertices[] = + { + { XMFLOAT3(-halfWidth, -halfHeight, -halfDepth), color }, + { XMFLOAT3(-halfWidth, -halfHeight, halfDepth), color }, + { XMFLOAT3(-halfWidth, halfHeight, -halfDepth), color }, + { XMFLOAT3(-halfWidth, halfHeight, halfDepth), color }, + { XMFLOAT3( halfWidth, -halfHeight, -halfDepth), color }, + { XMFLOAT3( halfWidth, -halfHeight, halfDepth), color }, + { XMFLOAT3( halfWidth, halfHeight, -halfDepth), color }, + { XMFLOAT3( halfWidth, halfHeight, halfDepth), color }, + }; + + D3D11_SUBRESOURCE_DATA vertexBufferData = {0}; + vertexBufferData.pSysMem = cubeVertices; + vertexBufferData.SysMemPitch = 0; + vertexBufferData.SysMemSlicePitch = 0; + const CD3D11_BUFFER_DESC vertexBufferDesc(sizeof(cubeVertices), D3D11_BIND_VERTEX_BUFFER); + DX::ThrowIfFailed( + m_deviceResources->GetD3DDevice()->CreateBuffer( + &vertexBufferDesc, + &vertexBufferData, + &m_vertexBuffer + ) + ); + + // Load mesh indices. Each trio of indices represents + // a triangle to be rendered on the screen. + // For example: 2,1,0 means that the vertices with indexes + // 2, 1, and 0 from the vertex buffer compose the + // first triangle of this mesh. + // Note that the winding order is clockwise by default. + static const unsigned short cubeIndices [] = + { + 2,1,0, // -x + 2,3,1, + + 6,4,5, // +x + 6,5,7, + + 0,1,5, // -y + 0,5,4, + + 2,6,7, // +y + 2,7,3, + + 0,4,6, // -z + 0,6,2, + + 1,3,7, // +z + 1,7,5, + }; + + m_indexCount = ARRAYSIZE(cubeIndices); + + D3D11_SUBRESOURCE_DATA indexBufferData = {0}; + indexBufferData.pSysMem = cubeIndices; + indexBufferData.SysMemPitch = 0; + indexBufferData.SysMemSlicePitch = 0; + const CD3D11_BUFFER_DESC indexBufferDesc(sizeof(cubeIndices), D3D11_BIND_INDEX_BUFFER); + DX::ThrowIfFailed( + m_deviceResources->GetD3DDevice()->CreateBuffer( + &indexBufferDesc, + &indexBufferData, + &m_indexBuffer + ) + ); + } + + // Once the cube is loaded, the object is ready to be rendered. + m_loadingComplete = true; +} + +void Panel::DoReleaseDeviceDependentResources() +{ + m_inputLayout.Reset(); + m_vertexBuffer.Reset(); + m_indexBuffer.Reset(); + m_vertexShader.Reset(); + m_geometryShader.Reset(); + m_pixelShader.Reset(); + m_modelConstantBuffer.Reset(); + + m_loadingComplete = false; + m_usingVprtShaders = false; +} diff --git a/Samples/HolographicMixedRealityCapture/cpp/Content/Panel.h b/Samples/HolographicMixedRealityCapture/cpp/Content/Panel.h new file mode 100644 index 0000000000..ddf818532e --- /dev/null +++ b/Samples/HolographicMixedRealityCapture/cpp/Content/Panel.h @@ -0,0 +1,50 @@ +#pragma once + +#include "ControlBase.h" + +namespace HolographicMRCSample +{ + // This sample renderer instantiates a basic rendering pipeline. + class Panel : public ControlBase + { + public: + Panel(const float width, const float height, const float depth, + const float red, const float green, const float blue, const float alpha); + + protected: + virtual void DoCreateDeviceDependentResources(); + virtual void DoReleaseDeviceDependentResources(); + + virtual void DoUpdate( + const DX::StepTimer& timer, + HolographicFrame^ holographicFrame, + SpatialCoordinateSystem^ currentCoordinateSystem, + SpatialInteractionSourceState^ interactionSource, + const DirectX::XMMATRIX &parentTransform); + virtual void DoRender(); + + private: + // Direct3D resources for cube geometry. + Microsoft::WRL::ComPtr m_inputLayout; + Microsoft::WRL::ComPtr m_vertexBuffer; + Microsoft::WRL::ComPtr m_indexBuffer; + Microsoft::WRL::ComPtr m_vertexShader; + Microsoft::WRL::ComPtr m_geometryShader; + Microsoft::WRL::ComPtr m_pixelShader; + Microsoft::WRL::ComPtr m_modelConstantBuffer; + + // System resources for cube geometry. + ModelConstantBuffer m_modelConstantBufferData; + uint32 m_indexCount = 0; + + Windows::Foundation::Numerics::float3 m_size; + Windows::Foundation::Numerics::float4 m_color; + + // Variables used with the rendering loop. + bool m_loadingComplete = false; + + // If the current D3D Device supports VPRT, we can avoid using a geometry + // shader just to set the render target array index. + bool m_usingVprtShaders = false; + }; +} diff --git a/Samples/HolographicMixedRealityCapture/cpp/Content/PixelShader.hlsl b/Samples/HolographicMixedRealityCapture/cpp/Content/PixelShader.hlsl new file mode 100644 index 0000000000..fd857896f5 --- /dev/null +++ b/Samples/HolographicMixedRealityCapture/cpp/Content/PixelShader.hlsl @@ -0,0 +1,13 @@ +// Per-pixel color data passed through the pixel shader. +struct PixelShaderInput +{ + min16float4 pos : SV_POSITION; + min16float3 color : COLOR0; +}; + +// The pixel shader passes through the color data. The color data from +// is interpolated and assigned to a pixel at the rasterization step. +min16float4 main(PixelShaderInput input) : SV_TARGET +{ + return min16float4(input.color, 1.0f); +} diff --git a/Samples/HolographicMixedRealityCapture/cpp/Content/PixelShaderCursor.hlsl b/Samples/HolographicMixedRealityCapture/cpp/Content/PixelShaderCursor.hlsl new file mode 100644 index 0000000000..3fc04b40b7 --- /dev/null +++ b/Samples/HolographicMixedRealityCapture/cpp/Content/PixelShaderCursor.hlsl @@ -0,0 +1,17 @@ +// Per-pixel color data passed through the pixel shader. +struct PixelShaderInput +{ + min16float4 pos : SV_POSITION; + min16float4 color : COLOR0; + min16float2 uv : TEXCOORD0; +}; + +Texture2D texturedata : register(t0); +SamplerState samp : register(s0); + +// The pixel shader passes through the color data. The color data from +// is interpolated and assigned to a pixel at the rasterization step. +min16float4 main(PixelShaderInput input) : SV_TARGET +{ + return texturedata.Sample(samp, input.uv); +} diff --git a/Samples/HolographicMixedRealityCapture/cpp/Content/PixelShaderNV12Texture.hlsl b/Samples/HolographicMixedRealityCapture/cpp/Content/PixelShaderNV12Texture.hlsl new file mode 100644 index 0000000000..32a8925708 --- /dev/null +++ b/Samples/HolographicMixedRealityCapture/cpp/Content/PixelShaderNV12Texture.hlsl @@ -0,0 +1,43 @@ +// Per-pixel color data passed through the pixel shader. +struct PixelShaderInput +{ + min16float4 pos : SV_POSITION; + min16float4 color : COLOR0; + min16float2 uv : TEXCOORD0; +}; + +Texture2D LumaData : register(t0); +Texture2D ChromaData : register(t1); +SamplerState samp : register(s0); + +min16float3 ToRGB(min16float Luma, min16float2 Chroma) +{ + min16float OneHalf = (min16float) 0.5f; + min16float One = (min16float) 1.0f; + min16float Zero = (min16float) 0.0f; + min16float RVCoeff = (min16float) 1.402f; + min16float GUCoeff = (min16float) - 0.344f; + min16float GVCoeff = (min16float) - 0.714f; + min16float BUCoeff = (min16float) 1.772f; + + min16float3 RCoeffs = min16float3(One, Zero, RVCoeff); + min16float3 GCoeffs = min16float3(One, GUCoeff, GVCoeff); + min16float3 BCoeffs = min16float3(One, BUCoeff, Zero); + + min16float3 Yuv = min16float3(Luma, Chroma - OneHalf); + min16float R = dot(Yuv, RCoeffs); + min16float G = dot(Yuv, GCoeffs); + min16float B = dot(Yuv, BCoeffs); + + return min16float3(R, G, B); +} + +// The pixel shader passes through the color data. The color data from +// is interpolated and assigned to a pixel at the rasterization step. +min16float4 main(PixelShaderInput input) : SV_TARGET +{ + min16float textureLuma = LumaData.Sample(samp, input.uv); + min16float2 textureChroma = ChromaData.Sample(samp, input.uv); + + return min16float4(ToRGB(textureLuma, textureChroma), 1.0f); +} diff --git a/Samples/HolographicMixedRealityCapture/cpp/Content/PixelShaderTexture.hlsl b/Samples/HolographicMixedRealityCapture/cpp/Content/PixelShaderTexture.hlsl new file mode 100644 index 0000000000..d159d88a2b --- /dev/null +++ b/Samples/HolographicMixedRealityCapture/cpp/Content/PixelShaderTexture.hlsl @@ -0,0 +1,18 @@ +// Per-pixel color data passed through the pixel shader. +struct PixelShaderInput +{ + min16float4 pos : SV_POSITION; + min16float4 color : COLOR0; + min16float2 uv : TEXCOORD0; +}; + +Texture2D texturedata : register(t0); +SamplerState samp : register(s0); + +// The pixel shader passes through the color data. The color data from +// is interpolated and assigned to a pixel at the rasterization step. +min16float4 main(PixelShaderInput input) : SV_TARGET +{ + min16float4 textureColor = texturedata.Sample(samp, input.uv); + return min16float4(lerp(input.color.rgb, textureColor.rgb, textureColor.a), input.color.a); +} diff --git a/Samples/HolographicMixedRealityCapture/cpp/Content/ShaderStructures.h b/Samples/HolographicMixedRealityCapture/cpp/Content/ShaderStructures.h new file mode 100644 index 0000000000..3b084c2604 --- /dev/null +++ b/Samples/HolographicMixedRealityCapture/cpp/Content/ShaderStructures.h @@ -0,0 +1,41 @@ +#pragma once + +namespace HolographicMRCSample +{ + // Constant buffer used to send hologram position transform to the shader pipeline. + struct ModelConstantBuffer + { + DirectX::XMFLOAT4X4 model; + }; + + // Assert that the constant buffer remains 16-byte aligned (best practice). + static_assert((sizeof(ModelConstantBuffer) % (sizeof(float) * 4)) == 0, "Model constant buffer size must be 16-byte aligned (16 bytes is the length of four floats)."); + + // Constant buffer used to send hologram position transform to the shader pipeline. + struct ModelColorConstantBuffer + { + DirectX::XMFLOAT4X4 model; + DirectX::XMFLOAT4 color; + }; + + // Assert that the constant buffer remains 16-byte aligned (best practice). + static_assert((sizeof(ModelColorConstantBuffer) % (sizeof(float) * 4)) == 0, "Model color constant buffer size must be 16-byte aligned (16 bytes is the length of four floats)."); + + // Used to send per-vertex data to the vertex shader. + struct VertexPosition + { + DirectX::XMFLOAT3 pos; + }; + + struct VertexPositionColor + { + DirectX::XMFLOAT3 pos; + DirectX::XMFLOAT4 color; + }; + + struct VertexPositionTexture + { + DirectX::XMFLOAT3 pos; + DirectX::XMFLOAT2 uv; + }; +} \ No newline at end of file diff --git a/Samples/HolographicMixedRealityCapture/cpp/Content/SpatialInputHandler.cpp b/Samples/HolographicMixedRealityCapture/cpp/Content/SpatialInputHandler.cpp new file mode 100644 index 0000000000..8efe22d6aa --- /dev/null +++ b/Samples/HolographicMixedRealityCapture/cpp/Content/SpatialInputHandler.cpp @@ -0,0 +1,45 @@ +#include "pch.h" +#include "SpatialInputHandler.h" +#include + +using namespace HolographicMRCSample; + +using namespace Windows::Foundation; +using namespace Windows::UI::Input::Spatial; +using namespace std::placeholders; + +// Creates and initializes a GestureRecognizer that listens to a Person. +SpatialInputHandler::SpatialInputHandler() +{ + // The interaction manager provides an event that informs the app when + // spatial interactions are detected. + m_interactionManager = SpatialInteractionManager::GetForCurrentView(); + + // Bind a handler to the SourcePressed event. + m_sourcePressedEventToken = + m_interactionManager->SourcePressed += + ref new TypedEventHandler( + bind(&SpatialInputHandler::OnSourcePressed, this, _1, _2) + ); +} + +SpatialInputHandler::~SpatialInputHandler() +{ + // Unregister our handler for the OnSourcePressed event. + m_interactionManager->SourcePressed -= m_sourcePressedEventToken; +} + +// Checks if the user performed an input gesture since the last call to this method. +// Allows the main update loop to check for asynchronous changes to the user +// input state. +SpatialInteractionSourceState^ SpatialInputHandler::CheckForInput() +{ + SpatialInteractionSourceState^ sourceState = m_sourceState; + m_sourceState = nullptr; + return sourceState; +} + +void SpatialInputHandler::OnSourcePressed(SpatialInteractionManager^ sender, SpatialInteractionSourceEventArgs^ args) +{ + m_sourceState = args->State; +} diff --git a/Samples/HolographicMixedRealityCapture/cpp/Content/SpatialInputHandler.h b/Samples/HolographicMixedRealityCapture/cpp/Content/SpatialInputHandler.h new file mode 100644 index 0000000000..4cc102a1eb --- /dev/null +++ b/Samples/HolographicMixedRealityCapture/cpp/Content/SpatialInputHandler.h @@ -0,0 +1,30 @@ +#pragma once + +namespace HolographicMRCSample +{ + // Sample gesture handler. + // Hooks up events to recognize a tap gesture, and keeps track of input using a boolean value. + class SpatialInputHandler + { + public: + SpatialInputHandler(); + ~SpatialInputHandler(); + + Windows::UI::Input::Spatial::SpatialInteractionSourceState^ CheckForInput(); + + private: + // Interaction event handler. + void OnSourcePressed( + Windows::UI::Input::Spatial::SpatialInteractionManager^ sender, + Windows::UI::Input::Spatial::SpatialInteractionSourceEventArgs^ args); + + // API objects used to process gesture input, and generate gesture events. + Windows::UI::Input::Spatial::SpatialInteractionManager^ m_interactionManager; + + // Event registration token. + Windows::Foundation::EventRegistrationToken m_sourcePressedEventToken; + + // Used to indicate that a Pressed input event was received this frame. + Windows::UI::Input::Spatial::SpatialInteractionSourceState^ m_sourceState = nullptr; + }; +} diff --git a/Samples/HolographicMixedRealityCapture/cpp/Content/SpinningCubeRenderer.cpp b/Samples/HolographicMixedRealityCapture/cpp/Content/SpinningCubeRenderer.cpp new file mode 100644 index 0000000000..24f36ac49f --- /dev/null +++ b/Samples/HolographicMixedRealityCapture/cpp/Content/SpinningCubeRenderer.cpp @@ -0,0 +1,273 @@ +#include "pch.h" +#include "SpinningCubeRenderer.h" +#include "Common\DirectXHelper.h" + +using namespace HolographicMRCSample; +using namespace Concurrency; +using namespace DirectX; +using namespace Windows::Foundation::Numerics; +using namespace Windows::UI::Input::Spatial; + +// Loads vertex and pixel shaders from files and instantiates the cube geometry. +SpinningCubeRenderer::SpinningCubeRenderer(const std::shared_ptr& deviceResources) : + m_deviceResources(deviceResources) +{ + CreateDeviceDependentResources(); +} + +// This function uses a SpatialPointerPose to position the world-locked hologram +// two meters in front of the user's heading. +void SpinningCubeRenderer::PositionHologram(SpatialPointerPose^ pointerPose) +{ + if (pointerPose != nullptr) + { + // Get the gaze direction relative to the given coordinate system. + const float3 headPosition = pointerPose->Head->Position; + const float3 headDirection = pointerPose->Head->ForwardDirection; + + // The hologram is positioned two meters along the user's gaze direction. + static const float distanceFromUser = 2.0f; // meters + const float3 gazeAtTwoMeters = headPosition + (distanceFromUser * headDirection); + + // This will be used as the translation component of the hologram's + // model transform. + SetPosition(gazeAtTwoMeters); + } +} + +// Called once per frame. Rotates the cube, and calculates and sets the model matrix +// relative to the position transform indicated by hologramPositionTransform. +void SpinningCubeRenderer::Update(const DX::StepTimer& timer) +{ + // Rotate the cube. + // Convert degrees to radians, then convert seconds to rotation angle. + const float radiansPerSecond = XMConvertToRadians(m_degreesPerSecond); + const double totalRotation = timer.GetTotalSeconds() * radiansPerSecond; + const float radians = static_cast(fmod(totalRotation, XM_2PI)); + const XMMATRIX modelRotation = XMMatrixRotationY(-radians); + + // Position the cube. + const XMMATRIX modelTranslation = XMMatrixTranslationFromVector(XMLoadFloat3(&m_position)); + + // Multiply to get the transform matrix. + // Note that this transform does not enforce a particular coordinate system. The calling + // class is responsible for rendering this content in a consistent manner. + const XMMATRIX modelTransform = XMMatrixMultiply(modelRotation, modelTranslation); + + // The view and projection matrices are provided by the system; they are associated + // with holographic cameras, and updated on a per-camera basis. + // Here, we provide the model transform for the sample hologram. The model transform + // matrix is transposed to prepare it for the shader. + XMStoreFloat4x4(&m_modelConstantBufferData.model, XMMatrixTranspose(modelTransform)); + + // Loading is asynchronous. Resources must be created before they can be updated. + if (!m_loadingComplete) + { + return; + } + + // Use the D3D device context to update Direct3D device-based resources. + const auto context = m_deviceResources->GetD3DDeviceContext(); + + // Update the model transform buffer for the hologram. + context->UpdateSubresource( + m_modelConstantBuffer.Get(), + 0, + nullptr, + &m_modelConstantBufferData, + 0, + 0 + ); +} + +// Renders one frame using the vertex and pixel shaders. +// On devices that do not support the D3D11_FEATURE_D3D11_OPTIONS3:: +// VPAndRTArrayIndexFromAnyShaderFeedingRasterizer optional feature, +// a pass-through geometry shader is also used to set the render +// target array index. +void SpinningCubeRenderer::Render() +{ + // Loading is asynchronous. Resources must be created before drawing can occur. + if (!m_loadingComplete) + { + return; + } + + const auto context = m_deviceResources->GetD3DDeviceContext(); + + // Each vertex is one instance of the VertexPositionColor struct. + const UINT stride = sizeof(VertexPositionColor); + const UINT offset = 0; + context->IASetVertexBuffers( + 0, + 1, + m_vertexBuffer.GetAddressOf(), + &stride, + &offset + ); + context->IASetIndexBuffer( + m_indexBuffer.Get(), + DXGI_FORMAT_R16_UINT, // Each index is one 16-bit unsigned integer (short). + 0 + ); + context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + context->IASetInputLayout(m_inputLayout.Get()); + + // Attach the vertex shader. + context->VSSetShader( + m_vertexShader.Get(), + nullptr, + 0 + ); + // Apply the model constant buffer to the vertex shader. + context->VSSetConstantBuffers( + 0, + 1, + m_modelConstantBuffer.GetAddressOf() + ); + + if (!m_usingVprtShaders) + { + // On devices that do not support the D3D11_FEATURE_D3D11_OPTIONS3:: + // VPAndRTArrayIndexFromAnyShaderFeedingRasterizer optional feature, + // a pass-through geometry shader is used to set the render target + // array index. + context->GSSetShader( + m_geometryShader.Get(), + nullptr, + 0 + ); + } + + // Attach the pixel shader. + context->PSSetShader( + m_pixelShader.Get(), + nullptr, + 0 + ); + + // Draw the objects. + context->DrawIndexedInstanced( + m_indexCount, // Index count per instance. + 2, // Instance count. + 0, // Start index location. + 0, // Base vertex location. + 0 // Start instance location. + ); +} + +void SpinningCubeRenderer::CreateDeviceDependentResources() +{ + m_usingVprtShaders = m_deviceResources->GetDeviceSupportsVprt(); + + // On devices that do support the D3D11_FEATURE_D3D11_OPTIONS3:: + // VPAndRTArrayIndexFromAnyShaderFeedingRasterizer optional feature + // we can avoid using a pass-through geometry shader to set the render + // target array index, thus avoiding any overhead that would be + // incurred by setting the geometry shader stage. + + m_vertexShader = m_deviceResources->GetVertexShader(m_usingVprtShaders ? DX::VertexShader_VPRT : DX::VertexShader_Simple); + m_inputLayout = m_deviceResources->GetInputLayout(m_usingVprtShaders ? DX::VertexShader_VPRT : DX::VertexShader_Simple); + m_pixelShader = m_deviceResources->GetPixelShader(DX::PixelShader_Simple); + + if (!m_usingVprtShaders) + { + m_geometryShader = m_deviceResources->GetGeometryShader(DX::GeometryShader_Simple); + } + + const CD3D11_BUFFER_DESC constantBufferDesc(sizeof(ModelConstantBuffer), D3D11_BIND_CONSTANT_BUFFER); + DX::ThrowIfFailed( + m_deviceResources->GetD3DDevice()->CreateBuffer( + &constantBufferDesc, + nullptr, + &m_modelConstantBuffer + ) + ); + + // Load mesh vertices. Each vertex has a position and a color. + // Note that the cube size has changed from the default DirectX app + // template. Windows Holographic is scaled in meters, so to draw the + // cube at a comfortable size we made the cube width 0.2 m (20 cm). + static const VertexPositionColor cubeVertices[] = + { + { XMFLOAT3(-0.1f, -0.1f, -0.1f), XMFLOAT4(0.0f, 0.0f, 0.0f, 1.0f) }, + { XMFLOAT3(-0.1f, -0.1f, 0.1f), XMFLOAT4(0.0f, 0.0f, 1.0f, 1.0f) }, + { XMFLOAT3(-0.1f, 0.1f, -0.1f), XMFLOAT4(0.0f, 1.0f, 0.0f, 1.0f) }, + { XMFLOAT3(-0.1f, 0.1f, 0.1f), XMFLOAT4(0.0f, 1.0f, 1.0f, 1.0f) }, + { XMFLOAT3( 0.1f, -0.1f, -0.1f), XMFLOAT4(1.0f, 0.0f, 0.0f, 1.0f) }, + { XMFLOAT3( 0.1f, -0.1f, 0.1f), XMFLOAT4(1.0f, 0.0f, 1.0f, 1.0f) }, + { XMFLOAT3( 0.1f, 0.1f, -0.1f), XMFLOAT4(1.0f, 1.0f, 0.0f, 1.0f) }, + { XMFLOAT3( 0.1f, 0.1f, 0.1f), XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f) }, + }; + + D3D11_SUBRESOURCE_DATA vertexBufferData = {0}; + vertexBufferData.pSysMem = cubeVertices; + vertexBufferData.SysMemPitch = 0; + vertexBufferData.SysMemSlicePitch = 0; + const CD3D11_BUFFER_DESC vertexBufferDesc(sizeof(cubeVertices), D3D11_BIND_VERTEX_BUFFER); + DX::ThrowIfFailed( + m_deviceResources->GetD3DDevice()->CreateBuffer( + &vertexBufferDesc, + &vertexBufferData, + &m_vertexBuffer + ) + ); + + // Load mesh indices. Each trio of indices represents + // a triangle to be rendered on the screen. + // For example: 2,1,0 means that the vertices with indexes + // 2, 1, and 0 from the vertex buffer compose the + // first triangle of this mesh. + // Note that the winding order is clockwise by default. + static const unsigned short cubeIndices [] = + { + 2,1,0, // -x + 2,3,1, + + 6,4,5, // +x + 6,5,7, + + 0,1,5, // -y + 0,5,4, + + 2,6,7, // +y + 2,7,3, + + 0,4,6, // -z + 0,6,2, + + 1,3,7, // +z + 1,7,5, + }; + + m_indexCount = ARRAYSIZE(cubeIndices); + + D3D11_SUBRESOURCE_DATA indexBufferData = {0}; + indexBufferData.pSysMem = cubeIndices; + indexBufferData.SysMemPitch = 0; + indexBufferData.SysMemSlicePitch = 0; + const CD3D11_BUFFER_DESC indexBufferDesc(sizeof(cubeIndices), D3D11_BIND_INDEX_BUFFER); + DX::ThrowIfFailed( + m_deviceResources->GetD3DDevice()->CreateBuffer( + &indexBufferDesc, + &indexBufferData, + &m_indexBuffer + ) + ); + + // Once the cube is loaded, the object is ready to be rendered. + m_loadingComplete = true; +} + +void SpinningCubeRenderer::ReleaseDeviceDependentResources() +{ + m_loadingComplete = false; + m_usingVprtShaders = false; + m_vertexShader.Reset(); + m_inputLayout.Reset(); + m_pixelShader.Reset(); + m_geometryShader.Reset(); + m_modelConstantBuffer.Reset(); + m_vertexBuffer.Reset(); + m_indexBuffer.Reset(); +} diff --git a/Samples/HolographicMixedRealityCapture/cpp/Content/SpinningCubeRenderer.h b/Samples/HolographicMixedRealityCapture/cpp/Content/SpinningCubeRenderer.h new file mode 100644 index 0000000000..7a61ccf628 --- /dev/null +++ b/Samples/HolographicMixedRealityCapture/cpp/Content/SpinningCubeRenderer.h @@ -0,0 +1,52 @@ +#pragma once + +#include "..\Common\DeviceResources.h" +#include "..\Common\StepTimer.h" +#include "ShaderStructures.h" + +namespace HolographicMRCSample +{ + // This sample renderer instantiates a basic rendering pipeline. + class SpinningCubeRenderer + { + public: + SpinningCubeRenderer(const std::shared_ptr& deviceResources); + void CreateDeviceDependentResources(); + void ReleaseDeviceDependentResources(); + void Update(const DX::StepTimer& timer); + void Render(); + + // Repositions the sample hologram. + void PositionHologram(Windows::UI::Input::Spatial::SpatialPointerPose^ pointerPose); + + // Property accessors. + void SetPosition(Windows::Foundation::Numerics::float3 pos) { m_position = pos; } + Windows::Foundation::Numerics::float3 GetPosition() { return m_position; } + + private: + // Cached pointer to device resources. + std::shared_ptr m_deviceResources; + + // Direct3D resources for cube geometry. + Microsoft::WRL::ComPtr m_inputLayout; + Microsoft::WRL::ComPtr m_vertexBuffer; + Microsoft::WRL::ComPtr m_indexBuffer; + Microsoft::WRL::ComPtr m_vertexShader; + Microsoft::WRL::ComPtr m_geometryShader; + Microsoft::WRL::ComPtr m_pixelShader; + Microsoft::WRL::ComPtr m_modelConstantBuffer; + + // System resources for cube geometry. + ModelConstantBuffer m_modelConstantBufferData; + uint32 m_indexCount = 0; + + // Variables used with the rendering loop. + bool m_loadingComplete = false; + float m_degreesPerSecond = 45.f; + Windows::Foundation::Numerics::float3 m_position = { 0.f, 0.f, -2.f }; + + // If the current D3D Device supports VPRT, we can avoid using a geometry + // shader just to set the render target array index. + bool m_usingVprtShaders = false; + }; +} diff --git a/Samples/HolographicMixedRealityCapture/cpp/Content/VPRTVertexShader.hlsl b/Samples/HolographicMixedRealityCapture/cpp/Content/VPRTVertexShader.hlsl new file mode 100644 index 0000000000..59330e7fe5 --- /dev/null +++ b/Samples/HolographicMixedRealityCapture/cpp/Content/VPRTVertexShader.hlsl @@ -0,0 +1,56 @@ +// A constant buffer that stores the model transform. +cbuffer ModelConstantBuffer : register(b0) +{ + float4x4 model; +}; + +// A constant buffer that stores each set of view and projection matrices in column-major format. +cbuffer ViewProjectionConstantBuffer : register(b1) +{ + float4x4 viewProjection[2]; +}; + +// Per-vertex data used as input to the vertex shader. +struct VertexShaderInput +{ + min16float3 pos : POSITION; + min16float3 color : COLOR0; + uint instId : SV_InstanceID; +}; + +// Per-vertex data passed to the geometry shader. +// Note that the render target array index is set here in the vertex shader. +struct VertexShaderOutput +{ + min16float4 pos : SV_POSITION; + min16float3 color : COLOR0; + uint rtvId : SV_RenderTargetArrayIndex; // SV_InstanceID % 2 +}; + +// Simple shader to do vertex processing on the GPU. +VertexShaderOutput main(VertexShaderInput input) +{ + VertexShaderOutput output; + float4 pos = float4(input.pos, 1.0f); + + // Note which view this vertex has been sent to. Used for matrix lookup. + // Taking the modulo of the instance ID allows geometry instancing to be used + // along with stereo instanced drawing; in that case, two copies of each + // instance would be drawn, one for left and one for right. + int idx = input.instId % 2; + + // Transform the vertex position into world space. + pos = mul(pos, model); + + // Correct for perspective and project the vertex position onto the screen. + pos = mul(pos, viewProjection[idx]); + output.pos = (min16float4)pos; + + // Pass the color through without modification. + output.color = input.color; + + // Set the render target array index. + output.rtvId = idx; + + return output; +} diff --git a/Samples/HolographicMixedRealityCapture/cpp/Content/VPRTVertexShaderTexture.hlsl b/Samples/HolographicMixedRealityCapture/cpp/Content/VPRTVertexShaderTexture.hlsl new file mode 100644 index 0000000000..cd42a4ca98 --- /dev/null +++ b/Samples/HolographicMixedRealityCapture/cpp/Content/VPRTVertexShaderTexture.hlsl @@ -0,0 +1,61 @@ +// A constant buffer that stores the model transform. +cbuffer ModelConstantBuffer : register(b0) +{ + float4x4 model; + float4 color; +}; + +// A constant buffer that stores each set of view and projection matrices in column-major format. +cbuffer ViewProjectionConstantBuffer : register(b1) +{ + float4x4 viewProjection[2]; +}; + +// Per-vertex data used as input to the vertex shader. +struct VertexShaderInput +{ + min16float3 pos : POSITION; + min16float2 uv : TEXCOORD0; + uint instId : SV_InstanceID; +}; + +// Per-vertex data passed to the geometry shader. +// Note that the render target array index is set here in the vertex shader. +struct VertexShaderOutput +{ + min16float4 pos : SV_POSITION; + min16float4 color : COLOR0; + min16float2 uv : TEXCOORD0; + uint rtvId : SV_RenderTargetArrayIndex; // SV_InstanceID % 2 +}; + +// Simple shader to do vertex processing on the GPU. +VertexShaderOutput main(VertexShaderInput input) +{ + VertexShaderOutput output; + float4 pos = float4(input.pos, 1.0f); + + // Note which view this vertex has been sent to. Used for matrix lookup. + // Taking the modulo of the instance ID allows geometry instancing to be used + // along with stereo instanced drawing; in that case, two copies of each + // instance would be drawn, one for left and one for right. + int idx = input.instId % 2; + + // Transform the vertex position into world space. + pos = mul(pos, model); + + // Correct for perspective and project the vertex position onto the screen. + pos = mul(pos, viewProjection[idx]); + output.pos = (min16float4)pos; + + // Pass the color through without modification. + output.color = (min16float4)color; + + // Pass the texture coordinates + output.uv = input.uv; + + // Set the render target array index. + output.rtvId = idx; + + return output; +} diff --git a/Samples/HolographicMixedRealityCapture/cpp/Content/VertexShader.hlsl b/Samples/HolographicMixedRealityCapture/cpp/Content/VertexShader.hlsl new file mode 100644 index 0000000000..7ebedb86f2 --- /dev/null +++ b/Samples/HolographicMixedRealityCapture/cpp/Content/VertexShader.hlsl @@ -0,0 +1,58 @@ +// A constant buffer that stores the model transform. +cbuffer ModelConstantBuffer : register(b0) +{ + float4x4 model; +}; + +// A constant buffer that stores each set of view and projection matrices in column-major format. +cbuffer ViewProjectionConstantBuffer : register(b1) +{ + float4x4 viewProjection[2]; +}; + +// Per-vertex data used as input to the vertex shader. +struct VertexShaderInput +{ + min16float3 pos : POSITION; + min16float3 color : COLOR0; + uint instId : SV_InstanceID; +}; + +// Per-vertex data passed to the geometry shader. +// Note that the render target array index will be set by the geometry shader +// using the value of viewId. +struct VertexShaderOutput +{ + min16float4 pos : SV_POSITION; + min16float3 color : COLOR0; + uint viewId : TEXCOORD0; // SV_InstanceID % 2 +}; + +// Simple shader to do vertex processing on the GPU. +VertexShaderOutput main(VertexShaderInput input) +{ + VertexShaderOutput output; + float4 pos = float4(input.pos, 1.0f); + + // Note which view this vertex has been sent to. Used for matrix lookup. + // Taking the modulo of the instance ID allows geometry instancing to be used + // along with stereo instanced drawing; in that case, two copies of each + // instance would be drawn, one for left and one for right. + int idx = input.instId % 2; + + // Transform the vertex position into world space. + pos = mul(pos, model); + + // Correct for perspective and project the vertex position onto the screen. + pos = mul(pos, viewProjection[idx]); + output.pos = (min16float4)pos; + + // Pass the color through without modification. + output.color = input.color; + + // Set the instance ID. The pass-through geometry shader will set the + // render target array index to whatever value is set here. + output.viewId = idx; + + return output; +} diff --git a/Samples/HolographicMixedRealityCapture/cpp/Content/VertexShaderTexture.hlsl b/Samples/HolographicMixedRealityCapture/cpp/Content/VertexShaderTexture.hlsl new file mode 100644 index 0000000000..674c6adee8 --- /dev/null +++ b/Samples/HolographicMixedRealityCapture/cpp/Content/VertexShaderTexture.hlsl @@ -0,0 +1,63 @@ +// A constant buffer that stores the model transform. +cbuffer ModelConstantBuffer : register(b0) +{ + min16float4x4 model; + min16float4 color; +}; + +// A constant buffer that stores each set of view and projection matrices in column-major format. +cbuffer ViewProjectionConstantBuffer : register(b1) +{ + min16float4x4 viewProjection[2]; +}; + +// Per-vertex data used as input to the vertex shader. +struct VertexShaderInput +{ + min16float3 pos : POSITION; + min16float2 uv : TEXCOORD0; + uint instId : SV_InstanceID; +}; + +// Per-vertex data passed to the geometry shader. +// Note that the render target array index will be set by the geometry shader +// using the value of viewId. +struct VertexShaderOutput +{ + min16float4 pos : SV_POSITION; + min16float4 color : COLOR0; + min16float2 uv : TEXCOORD0; + uint viewId : TEXCOORD1; // SV_InstanceID % 2 +}; + +// Simple shader to do vertex processing on the GPU. +VertexShaderOutput main(VertexShaderInput input) +{ + VertexShaderOutput output; + min16float4 pos = min16float4(input.pos, 1.0f); + + // Note which view this vertex has been sent to. Used for matrix lookup. + // Taking the modulo of the instance ID allows geometry instancing to be used + // along with stereo instanced drawing; in that case, two copies of each + // instance would be drawn, one for left and one for right. + int idx = input.instId % 2; + + // Transform the vertex position into world space. + pos = mul(pos, model); + + // Correct for perspective and project the vertex position onto the screen. + pos = mul(pos, viewProjection[idx]); + output.pos = pos; + + // Pass the color through without modification. + output.color = color; + + // Pass the texture coordinates + output.uv = input.uv; + + // Set the instance ID. The pass-through geometry shader will set the + // render target array index to whatever value is set here. + output.viewId = idx; + + return output; +} diff --git a/Samples/HolographicMixedRealityCapture/cpp/HolographicMRCSampleMain.cpp b/Samples/HolographicMixedRealityCapture/cpp/HolographicMRCSampleMain.cpp new file mode 100644 index 0000000000..bf256e8f6c --- /dev/null +++ b/Samples/HolographicMixedRealityCapture/cpp/HolographicMRCSampleMain.cpp @@ -0,0 +1,624 @@ +#include "pch.h" +#include "HolographicMRCSampleMain.h" +#include "Common\DirectXHelper.h" + +#include +#include + + +using namespace HolographicMRCSample; + +using namespace concurrency; +using namespace Platform; +using namespace Windows::Foundation; +using namespace Windows::Foundation::Numerics; +using namespace Windows::Graphics::Holographic; +using namespace Windows::Perception::Spatial; +using namespace Windows::UI::Input::Spatial; +using namespace std::placeholders; + +// Loads and initializes application assets when the application is loaded. +HolographicMRCSampleMain::HolographicMRCSampleMain(const std::shared_ptr& deviceResources) : + m_deviceResources(deviceResources), + m_recording(false) +{ + // Register to be notified if the device is lost or recreated. + m_deviceResources->RegisterDeviceNotify(this); +} + +void HolographicMRCSampleMain::SetHolographicSpace(HolographicSpace^ holographicSpace) +{ + UnregisterHolographicEventHandlers(); + + m_holographicSpace = holographicSpace; + +#ifdef DRAW_SAMPLE_CONTENT + m_cursor = std::make_unique(0.01f, 0.01f); + m_cursor->Initialize(m_deviceResources); + + m_mainPanel = std::make_unique(0.20f, 0.60f, 0.01f, // Size + 0.5f, 0.5f, 0.5f, 1.0f); // Color + m_mainPanel->Initialize(m_deviceResources); + m_mainPanel->SetPosition(Windows::Foundation::Numerics::float3(-0.25f, 0.0f, -2.0f)); + + // Init button + m_initButton.reset(new Button(Windows::Foundation::Numerics::float3(0.14f, 0.07f, 0.01f), // Size + Windows::Foundation::Numerics::float4(1.0f, 1.0f, 0.5f, 1.0f), // Color + Windows::Foundation::Numerics::float4(1.0f, 1.0f, 0.9f, 1.0f), // Focused Color + Windows::Foundation::Numerics::float4(0.0f, 0.0f, 0.5f, 1.0f), // Turned on Color + DX::Texture_Init)); + m_initButton->Initialize(m_deviceResources); + m_initButton->SetPosition(Windows::Foundation::Numerics::float3(0.0f, 0.25f, 0.01f)); + m_initButton->SetOnAirTapCallback(std::bind(&HolographicMRCSampleMain::OnButtonInitTapped, this)); + m_initButton->SetEnabled(true); + m_mainPanel->AddChild(m_initButton); + + // Photo button + m_photoButton.reset(new Button(Windows::Foundation::Numerics::float3(0.14f, 0.07f, 0.01f), // Size + Windows::Foundation::Numerics::float4(1.0f, 1.0f, 0.5f, 1.0f), // Color + Windows::Foundation::Numerics::float4(1.0f, 1.0f, 0.9f, 1.0f), // Focused Color + Windows::Foundation::Numerics::float4(0.0f, 0.0f, 0.5f, 1.0f), // Turned on Color + DX::Texture_Photo)); + m_photoButton->Initialize(m_deviceResources); + m_photoButton->SetPosition(Windows::Foundation::Numerics::float3(0.0f, 0.15f, 0.01f)); + m_photoButton->SetOnAirTapCallback(std::bind(&HolographicMRCSampleMain::OnButtonPhotoTapped, this)); + m_photoButton->SetEnabled(false); + m_mainPanel->AddChild(m_photoButton); + + // Video button + m_videoButton.reset(new Button(Windows::Foundation::Numerics::float3(0.14f, 0.07f, 0.01f), // Size + Windows::Foundation::Numerics::float4(1.0f, 1.0f, 0.5f, 1.0f), // Color + Windows::Foundation::Numerics::float4(1.0f, 1.0f, 0.9f, 1.0f), // Focused Color + Windows::Foundation::Numerics::float4(0.0f, 0.0f, 0.5f, 1.0f), // Turned on Color + DX::Texture_Video)); + m_videoButton->Initialize(m_deviceResources); + m_videoButton->SetPosition(Windows::Foundation::Numerics::float3(0.0f, 0.05f, 0.01f)); + m_videoButton->SetOnAirTapCallback(std::bind(&HolographicMRCSampleMain::OnButtonVideoTapped, this)); + m_videoButton->SetEnabled(false); + m_mainPanel->AddChild(m_videoButton); + + // Hologram button + m_hologramButton.reset(new Button(Windows::Foundation::Numerics::float3(0.14f, 0.07f, 0.01f), // Size + Windows::Foundation::Numerics::float4(1.0f, 1.0f, 0.5f, 1.0f), // Color + Windows::Foundation::Numerics::float4(1.0f, 1.0f, 0.9f, 1.0f), // Focused Color + Windows::Foundation::Numerics::float4(0.0f, 0.0f, 0.5f, 1.0f), // Turned on Color + DX::Texture_Hologram)); + m_hologramButton->Initialize(m_deviceResources); + m_hologramButton->SetPosition(Windows::Foundation::Numerics::float3(0.0f, -0.05f, 0.01f)); + m_hologramButton->SetOnAirTapCallback(std::bind(&HolographicMRCSampleMain::OnButtonHologramTapped, this)); + m_hologramButton->SetEnabled(true); + m_mainPanel->AddChild(m_hologramButton); + + // System Audio button + m_sysAudioButton.reset(new Button(Windows::Foundation::Numerics::float3(0.14f, 0.07f, 0.01f), // Size + Windows::Foundation::Numerics::float4(1.0f, 1.0f, 0.5f, 1.0f), // Color + Windows::Foundation::Numerics::float4(1.0f, 1.0f, 0.9f, 1.0f), // Focused Color + Windows::Foundation::Numerics::float4(0.0f, 0.0f, 0.5f, 1.0f), // Turned on Color + DX::Texture_SysAudio)); + m_sysAudioButton->Initialize(m_deviceResources); + m_sysAudioButton->SetPosition(Windows::Foundation::Numerics::float3(0.0f, -0.15f, 0.01f)); + m_sysAudioButton->SetOnAirTapCallback(std::bind(&HolographicMRCSampleMain::OnButtonSysAudioTapped, this)); + m_sysAudioButton->SetEnabled(true); + m_mainPanel->AddChild(m_sysAudioButton); + + // Spinning Cubes + m_cube1 = std::make_unique(m_deviceResources); + m_cube1->SetPosition(Windows::Foundation::Numerics::float3(0.0f, 0.0f, -2.0f)); // Front + + m_cube2 = std::make_unique(m_deviceResources); + m_cube2->SetPosition(Windows::Foundation::Numerics::float3(0.0f, 0.0f, 2.0f)); // Back + + m_cube3 = std::make_unique(m_deviceResources); + m_cube3->SetPosition(Windows::Foundation::Numerics::float3(2.0f, 0.0f, 0.0f)); // Right + + m_cube4 = std::make_unique(m_deviceResources); + m_cube4->SetPosition(Windows::Foundation::Numerics::float3(-2.0f, 0.0f, 0.0f)); // Left + + // Spatial Input Handler + m_spatialInputHandler = std::make_unique(); + + // Media Capture Manager + m_mediaCapture = std::make_unique(); +#endif + + // Use the default SpatialLocator to track the motion of the device. + m_locator = SpatialLocator::GetDefault(); + + // Be able to respond to changes in the positional tracking state. + m_locatabilityChangedToken = + m_locator->LocatabilityChanged += + ref new Windows::Foundation::TypedEventHandler( + std::bind(&HolographicMRCSampleMain::OnLocatabilityChanged, this, _1, _2) + ); + + // Respond to camera added events by creating any resources that are specific + // to that camera, such as the back buffer render target view. + // When we add an event handler for CameraAdded, the API layer will avoid putting + // the new camera in new HolographicFrames until we complete the deferral we created + // for that handler, or return from the handler without creating a deferral. This + // allows the app to take more than one frame to finish creating resources and + // loading assets for the new holographic camera. + // This function should be registered before the app creates any HolographicFrames. + m_cameraAddedToken = + m_holographicSpace->CameraAdded += + ref new Windows::Foundation::TypedEventHandler( + std::bind(&HolographicMRCSampleMain::OnCameraAdded, this, _1, _2) + ); + + // Respond to camera removed events by releasing resources that were created for that + // camera. + // When the app receives a CameraRemoved event, it releases all references to the back + // buffer right away. This includes render target views, Direct2D target bitmaps, and so on. + // The app must also ensure that the back buffer is not attached as a render target, as + // shown in DeviceResources::ReleaseResourcesForBackBuffer. + m_cameraRemovedToken = + m_holographicSpace->CameraRemoved += + ref new Windows::Foundation::TypedEventHandler( + std::bind(&HolographicMRCSampleMain::OnCameraRemoved, this, _1, _2) + ); + + // The simplest way to render world-locked holograms is to create a stationary reference frame + // when the app is launched. This is roughly analogous to creating a "world" coordinate system + // with the origin placed at the device's position as the app is launched. + m_referenceFrame = m_locator->CreateStationaryFrameOfReferenceAtCurrentLocation(); + + // Notes on spatial tracking APIs: + // * Stationary reference frames are designed to provide a best-fit position relative to the + // overall space. Individual positions within that reference frame are allowed to drift slightly + // as the device learns more about the environment. + // * When precise placement of individual holograms is required, a SpatialAnchor should be used to + // anchor the individual hologram to a position in the real world - for example, a point the user + // indicates to be of special interest. Anchor positions do not drift, but can be corrected; the + // anchor will use the corrected position starting in the next frame after the correction has + // occurred. +} + +void HolographicMRCSampleMain::UnregisterHolographicEventHandlers() +{ + if (m_holographicSpace != nullptr) + { + // Clear previous event registrations. + + if (m_cameraAddedToken.Value != 0) + { + m_holographicSpace->CameraAdded -= m_cameraAddedToken; + m_cameraAddedToken.Value = 0; + } + + if (m_cameraRemovedToken.Value != 0) + { + m_holographicSpace->CameraRemoved -= m_cameraRemovedToken; + m_cameraRemovedToken.Value = 0; + } + } + + if (m_locator != nullptr) + { + m_locator->LocatabilityChanged -= m_locatabilityChangedToken; + } +} + +HolographicMRCSampleMain::~HolographicMRCSampleMain() +{ + // Deregister device notification. + m_deviceResources->RegisterDeviceNotify(nullptr); + + UnregisterHolographicEventHandlers(); +} + +// Updates the application state once per frame. +HolographicFrame^ HolographicMRCSampleMain::Update() +{ + if (m_holographicSpace) + { + // Before doing the timer update, there is some work to do per-frame + // to maintain holographic rendering. First, we will get information + // about the current frame. + + // The HolographicFrame has information that the app needs in order + // to update and render the current frame. The app begins each new + // frame by calling CreateNextFrame. + HolographicFrame^ holographicFrame = m_holographicSpace->CreateNextFrame(); + + // Get a prediction of where holographic cameras will be when this frame + // is presented. + HolographicFramePrediction^ prediction = holographicFrame->CurrentPrediction; + + // Back buffers can change from frame to frame. Validate each buffer, and recreate + // resource views and depth buffers as needed. + m_deviceResources->EnsureCameraResources(holographicFrame, prediction); + + // Next, we get a coordinate system from the attached frame of reference that is + // associated with the current frame. Later, this coordinate system is used for + // for creating the stereo view matrices when rendering the sample content. + SpatialCoordinateSystem^ currentCoordinateSystem = m_referenceFrame->CoordinateSystem; + +#ifdef DRAW_SAMPLE_CONTENT + // Check for new input state since the last frame. + SpatialInteractionSourceState^ pointerState = m_spatialInputHandler->CheckForInput(); +#endif + + m_timer.Tick([&]() + { + // + // Update scene objects. + // + // Put time-based updates here. By default this code will run once per frame, + // but if you change the StepTimer to use a fixed time step this code will + // run as many times as needed to get to the current step. + // + +#ifdef DRAW_SAMPLE_CONTENT + m_cube1->Update(m_timer); + m_cube2->Update(m_timer); + m_cube3->Update(m_timer); + m_cube4->Update(m_timer); + m_mainPanel->Update(m_timer, holographicFrame, currentCoordinateSystem, pointerState); + + DirectX::BoundingOrientedBox panelBoundingBox; + m_mainPanel->GetBoundingBox(panelBoundingBox); + + auto pointerPose = SpatialPointerPose::TryGetAtTimestamp(currentCoordinateSystem, prediction->Timestamp); + if (pointerPose != nullptr) + { + // Get the gaze direction relative to the given coordinate system. + const float3 position = pointerPose->Head->Position; + const float3 direction = pointerPose->Head->ForwardDirection; + + DirectX::XMFLOAT3 headPosition = DirectX::XMFLOAT3(position.x, position.y, position.z); + DirectX::XMFLOAT3 headDirection = DirectX::XMFLOAT3(direction.x, direction.y, direction.z); + float distance = 0.0f; + + if (panelBoundingBox.Intersects(XMLoadFloat3(&headPosition), XMLoadFloat3(&headDirection), distance)) + { + m_cursor->SetDistance(distance - 0.05f); + } + else + { + m_cursor->SetDistance(2.0f); + } + } + else + { + m_cursor->SetDistance(2.0f); + } + + m_cursor->Update(m_timer, holographicFrame, currentCoordinateSystem, nullptr); +#endif + }); + + // We complete the frame update by using information about our content positioning + // to set the focus point. + + for (auto cameraPose : prediction->CameraPoses) + { +#ifdef DRAW_SAMPLE_CONTENT + // The HolographicCameraRenderingParameters class provides access to set + // the image stabilization parameters. + HolographicCameraRenderingParameters^ renderingParameters = holographicFrame->GetRenderingParameters(cameraPose); + + // SetFocusPoint informs the system about a specific point in your scene to + // prioritize for image stabilization. The focus point is set independently + // for each holographic camera. + // You should set the focus point near the content that the user is looking at. + // In this example, we put the focus point at the center of the sample hologram, + // since that is the only hologram available for the user to focus on. + // You can also set the relative velocity and facing of that content; the sample + // hologram is at a fixed point so we only need to indicate its position. + renderingParameters->SetFocusPoint( + currentCoordinateSystem, + m_mainPanel->GetPosition() + ); +#endif + } + + // The holographic frame will be used to get up-to-date view and projection matrices and + // to present the swap chain. + return holographicFrame; + } + + return nullptr; +} + +// Renders the current frame to each holographic camera, according to the +// current application and spatial positioning state. Returns true if the +// frame was rendered to at least one camera. +bool HolographicMRCSampleMain::Render(Windows::Graphics::Holographic::HolographicFrame^ holographicFrame) +{ + // Don't try to render anything before the first Update. + if (m_timer.GetFrameCount() == 0) + { + return false; + } + + // + // Take care of any tasks that are not specific to an individual holographic + // camera. This includes anything that doesn't need the final view or projection + // matrix, such as lighting maps. + // + + // Lock the set of holographic camera resources, then draw to each camera + // in this frame. + return m_deviceResources->UseHolographicCameraResources( + [this, holographicFrame](std::map>& cameraResourceMap) + { + // Up-to-date frame predictions enhance the effectiveness of image stablization and + // allow more accurate positioning of holograms. + holographicFrame->UpdateCurrentPrediction(); + HolographicFramePrediction^ prediction = holographicFrame->CurrentPrediction; + + bool atLeastOneCameraRendered = false; + for (auto cameraPose : prediction->CameraPoses) + { + // This represents the device-based resources for a HolographicCamera. + DX::CameraResources* pCameraResources = cameraResourceMap[cameraPose->HolographicCamera->Id].get(); + + // Get the device context. + const auto context = m_deviceResources->GetD3DDeviceContext(); + const auto depthStencilView = pCameraResources->GetDepthStencilView(); + const auto blendState = pCameraResources->GetBlendState(); + + // Set render targets to the current holographic camera. + ID3D11RenderTargetView *const targets[1] = { pCameraResources->GetBackBufferRenderTargetView() }; + context->OMSetRenderTargets(1, targets, depthStencilView); + + // Set blend state + context->OMSetBlendState(blendState, NULL, 0xffffffff); + + // Clear the back buffer and depth stencil view. + context->ClearRenderTargetView(targets[0], DirectX::Colors::Transparent); + context->ClearDepthStencilView(depthStencilView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0); + + // The view and projection matrices for each holographic camera will change + // every frame. This function refreshes the data in the constant buffer for + // the holographic camera indicated by cameraPose. + pCameraResources->UpdateViewProjectionBuffer(m_deviceResources, cameraPose, m_referenceFrame->CoordinateSystem); + + // Attach the view/projection constant buffer for this camera to the graphics pipeline. + bool cameraActive = pCameraResources->AttachViewProjectionBuffer(m_deviceResources); + +#ifdef DRAW_SAMPLE_CONTENT + // Only render world-locked content when positional tracking is active. + if (cameraActive) + { + m_cube1->Render(); + m_cube2->Render(); + m_cube3->Render(); + m_cube4->Render(); + m_mainPanel->Render(); + m_cursor->Render(); + } +#endif + atLeastOneCameraRendered = true; + } + + return atLeastOneCameraRendered; + }); +} + +void HolographicMRCSampleMain::SaveAppState() +{ +} + +void HolographicMRCSampleMain::LoadAppState() +{ +} + +// Notifies classes that use Direct3D device resources that the device resources +// need to be released before this method returns. +void HolographicMRCSampleMain::OnDeviceLost() +{ +#ifdef DRAW_SAMPLE_CONTENT + m_cube1->ReleaseDeviceDependentResources(); + m_cube2->ReleaseDeviceDependentResources(); + m_cube3->ReleaseDeviceDependentResources(); + m_cube4->ReleaseDeviceDependentResources(); + + m_cursor->ReleaseDeviceDependentResources(); + m_mainPanel->ReleaseDeviceDependentResources(); +#endif +} + +// Notifies classes that use Direct3D device resources that the device resources +// may now be recreated. +void HolographicMRCSampleMain::OnDeviceRestored() +{ +#ifdef DRAW_SAMPLE_CONTENT + m_cube1->CreateDeviceDependentResources(); + m_cube2->CreateDeviceDependentResources(); + m_cube3->CreateDeviceDependentResources(); + m_cube4->CreateDeviceDependentResources(); + + m_cursor->CreateDeviceDependentResources(); + m_mainPanel->CreateDeviceDependentResources(); +#endif +} + +void HolographicMRCSampleMain::OnLocatabilityChanged(SpatialLocator^ sender, Object^ args) +{ + switch (sender->Locatability) + { + case SpatialLocatability::Unavailable: + // Holograms cannot be rendered. + { + String^ message = L"Warning! Positional tracking is " + + sender->Locatability.ToString() + L".\n"; + OutputDebugStringW(message->Data()); + } + break; + + // In the following three cases, it is still possible to place holograms using a + // SpatialLocatorAttachedFrameOfReference. + case SpatialLocatability::PositionalTrackingActivating: + // The system is preparing to use positional tracking. + + case SpatialLocatability::OrientationOnly: + // Positional tracking has not been activated. + + case SpatialLocatability::PositionalTrackingInhibited: + // Positional tracking is temporarily inhibited. User action may be required + // in order to restore positional tracking. + break; + + case SpatialLocatability::PositionalTrackingActive: + // Positional tracking is active. World-locked content can be rendered. + break; + } +} + +void HolographicMRCSampleMain::OnCameraAdded( + HolographicSpace^ sender, + HolographicSpaceCameraAddedEventArgs^ args + ) +{ + Deferral^ deferral = args->GetDeferral(); + HolographicCamera^ holographicCamera = args->Camera; + create_task([this, deferral, holographicCamera] () + { + // Create device-based resources for the holographic camera and add it to the list of + // cameras used for updates and rendering. Notes: + // * Since this function may be called at any time, the AddHolographicCamera function + // waits until it can get a lock on the set of holographic camera resources before + // adding the new camera. At 60 frames per second this wait should not take long. + // * A subsequent Update will take the back buffer from the RenderingParameters of this + // camera's CameraPose and use it to create the ID3D11RenderTargetView for this camera. + // Content can then be rendered for the HolographicCamera. + m_deviceResources->AddHolographicCamera(holographicCamera); + + // Holographic frame predictions will not include any information about this camera until + // the deferral is completed. + deferral->Complete(); + }); +} + +void HolographicMRCSampleMain::OnCameraRemoved( + HolographicSpace^ sender, + HolographicSpaceCameraRemovedEventArgs^ args + ) +{ + create_task([this]() + { + }); + + // Before letting this callback return, ensure that all references to the back buffer + // are released. + // Since this function may be called at any time, the RemoveHolographicCamera function + // waits until it can get a lock on the set of holographic camera resources before + // deallocating resources for this camera. At 60 frames per second this wait should + // not take long. + m_deviceResources->RemoveHolographicCamera(args->Camera); +} + +void HolographicMRCSampleMain::OnButtonInitTapped() +{ + DisableAllButtons(); + + try + { + Concurrency::create_task(m_mediaCapture->InitializeAsync()).then([this]() + { + m_photoButton->SetEnabled(true); + m_videoButton->SetEnabled(true); + m_hologramButton->SetEnabled(true); + m_sysAudioButton->SetEnabled(true); + }); + } + catch (Platform::Exception ^e) + { + OutputDebugString(e->Message->Data()); + } +} + +void HolographicMRCSampleMain::OnButtonVideoTapped() +{ + DisableAllButtons(); + + if (m_recording) + { + try + { + // Stop Recording + m_mediaCapture->StopRecordingAsync().then([this]() + { + m_recording = false; + + m_initButton->SetEnabled(false); + m_photoButton->SetEnabled(m_mediaCapture->CanTakePhoto()); + m_videoButton->SetEnabled(true); + m_hologramButton->SetEnabled(true); + m_sysAudioButton->SetEnabled(true); + }); + } + catch (Platform::Exception ^e) + { + OutputDebugString(e->Message->Data()); + } + } + else + { + try + { + // Start Recording + m_mediaCapture->StartRecordingAsync().then([this]() + { + m_recording = true; + + m_initButton->SetEnabled(false); + m_photoButton->SetEnabled(m_mediaCapture->CanTakePhoto()); + m_videoButton->SetEnabled(true); + m_hologramButton->SetEnabled(false); + m_sysAudioButton->SetEnabled(false); + }); + } + catch (Platform::Exception ^e) + { + OutputDebugString(e->Message->Data()); + } + } +} + +void HolographicMRCSampleMain::OnButtonPhotoTapped() +{ + DisableAllButtons(); + + try + { + m_mediaCapture->TakePhotoAsync().then([this]() + { + m_initButton->SetEnabled(false); + m_photoButton->SetEnabled(m_mediaCapture->CanTakePhoto()); + m_videoButton->SetEnabled(true); + m_hologramButton->SetEnabled(true); + m_sysAudioButton->SetEnabled(true); + }); + } + catch (Platform::Exception ^e) + { + OutputDebugString(e->Message->Data()); + } +} + +void HolographicMRCSampleMain::OnButtonHologramTapped() +{ + // Toggle button switch state + m_hologramButton->SetSwitch(!m_hologramButton->GetSwitch()); + + m_mediaCapture->SetHologramEnabled(m_hologramButton->GetSwitch()); +} + +void HolographicMRCSampleMain::OnButtonSysAudioTapped() +{ + // Toggle button switch state + m_sysAudioButton->SetSwitch(!m_sysAudioButton->GetSwitch()); + + m_mediaCapture->SetSystemAudioEnabled(m_sysAudioButton->GetSwitch()); +} + +void HolographicMRCSampleMain::DisableAllButtons() +{ + m_initButton->SetEnabled(false); + m_photoButton->SetEnabled(false); + m_videoButton->SetEnabled(false); + m_hologramButton->SetEnabled(false); + m_sysAudioButton->SetEnabled(false); +} diff --git a/Samples/HolographicMixedRealityCapture/cpp/HolographicMRCSampleMain.h b/Samples/HolographicMixedRealityCapture/cpp/HolographicMRCSampleMain.h new file mode 100644 index 0000000000..bbd2e86d72 --- /dev/null +++ b/Samples/HolographicMixedRealityCapture/cpp/HolographicMRCSampleMain.h @@ -0,0 +1,128 @@ +#pragma once + +// +// Comment out this preprocessor definition to disable all of the +// sample content. +// +// To remove the content after disabling it: +// * Remove the unused code from your app's Main class. +// * Delete the Content folder provided with this template. +// +#define DRAW_SAMPLE_CONTENT + +#include "Common\DeviceResources.h" +#include "Common\StepTimer.h" + +#ifdef DRAW_SAMPLE_CONTENT +#include "Content\SpinningCubeRenderer.h" +#include "Content\Panel.h" +#include "Content\Button.h" +#include "Content\Cursor.h" +#include "Content\SpatialInputHandler.h" + +#include "MediaCaptureManager.h" +#endif + +// Updates, renders, and presents holographic content using Direct3D. +namespace HolographicMRCSample +{ + class HolographicMRCSampleMain : public DX::IDeviceNotify + { + public: + HolographicMRCSampleMain(const std::shared_ptr& deviceResources); + ~HolographicMRCSampleMain(); + + // Sets the holographic space. This is our closest analogue to setting a new window + // for the app. + void SetHolographicSpace(Windows::Graphics::Holographic::HolographicSpace^ holographicSpace); + + // Starts the holographic frame and updates the content. + Windows::Graphics::Holographic::HolographicFrame^ Update(); + + // Renders holograms, including world-locked content. + bool Render(Windows::Graphics::Holographic::HolographicFrame^ holographicFrame); + + // Handle saving and loading of app state owned by AppMain. + void SaveAppState(); + void LoadAppState(); + + // IDeviceNotify + virtual void OnDeviceLost(); + virtual void OnDeviceRestored(); + + private: + // Asynchronously creates resources for new holographic cameras. + void OnCameraAdded( + Windows::Graphics::Holographic::HolographicSpace^ sender, + Windows::Graphics::Holographic::HolographicSpaceCameraAddedEventArgs^ args); + + // Synchronously releases resources for holographic cameras that are no longer + // attached to the system. + void OnCameraRemoved( + Windows::Graphics::Holographic::HolographicSpace^ sender, + Windows::Graphics::Holographic::HolographicSpaceCameraRemovedEventArgs^ args); + + // Used to notify the app when the positional tracking state changes. + void OnLocatabilityChanged( + Windows::Perception::Spatial::SpatialLocator^ sender, + Platform::Object^ args); + + // Clears event registration state. Used when changing to a new HolographicSpace + // and when tearing down AppMain. + void UnregisterHolographicEventHandlers(); + + void OnButtonInitTapped(); + void OnButtonVideoTapped(); + void OnButtonPhotoTapped(); + void OnButtonHologramTapped(); + void OnButtonSysAudioTapped(); + + void DisableAllButtons(); + +#ifdef DRAW_SAMPLE_CONTENT + // Renders a colorful holographic cube that's 20 centimeters wide. This sample content + // is used to demonstrate world-locked rendering. + std::unique_ptr m_cube1; + std::unique_ptr m_cube2; + std::unique_ptr m_cube3; + std::unique_ptr m_cube4; + + std::unique_ptr m_mainPanel; + std::shared_ptr diff --git a/SharedContent/js/js/default.js b/SharedContent/js/js/default.js index e3eadcd403..5abeeba4c8 100644 --- a/SharedContent/js/js/default.js +++ b/SharedContent/js/js/default.js @@ -9,19 +9,20 @@ var splitView; WinJS.Namespace.define("SdkSample", { - paneHiddenInitially: false + paneOpenInitially: false }); function activated(eventObject) { var activationKind = eventObject.detail.kind; var activatedEventArgs = eventObject.detail.detail; - SdkSample.paneHiddenInitially = window.innerWidth <= 768; + SdkSample.paneOpenInitially = window.innerWidth > 768; var p = WinJS.UI.processAll(). then(function () { splitView = document.querySelector("#root").winControl; splitView.onbeforeclose = function () { WinJS.Utilities.addClass(splitView.element, "hiding"); }; splitView.onafterclose = function () { WinJS.Utilities.removeClass(splitView.element, "hiding"); }; + splitView.onafteropen = handleOpened; window.addEventListener("resize", handleResize); handleResize(); @@ -84,6 +85,12 @@ splitView.paneOpened = !splitView.paneOpened; } + function handleOpened() { + // Different SplitView openedDisplayModes handle focus differently when opened. + // Normalize them and always put focus onto the SplitView pane element when opened. + splitView.element.querySelector(".win-splitview-pane").focus(); + } + function handleResize() { if (window.innerWidth > 768) { splitView.closedDisplayMode = WinJS.UI.SplitView.ClosedDisplayMode.none; @@ -102,4 +109,4 @@ window.onerror = function (E) { debugger; -} \ No newline at end of file +}