diff options
Diffstat (limited to 'samples/DX_APIUsage/GfeSDKWrapper.cpp')
| -rw-r--r-- | samples/DX_APIUsage/GfeSDKWrapper.cpp | 383 |
1 files changed, 383 insertions, 0 deletions
diff --git a/samples/DX_APIUsage/GfeSDKWrapper.cpp b/samples/DX_APIUsage/GfeSDKWrapper.cpp new file mode 100644 index 0000000..33a4a63 --- /dev/null +++ b/samples/DX_APIUsage/GfeSDKWrapper.cpp @@ -0,0 +1,383 @@ +/* Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved. +* +* NVIDIA CORPORATION and its licensors retain all intellectual property +* and proprietary rights in and to this software, related documentation +* and any modifications thereto. Any use, reproduction, disclosure or +* distribution of this software and related documentation without an express +* license agreement from NVIDIA CORPORATION is strictly prohibited. +*/ +/*! +* \file +* Shows example usage of the GfeSDK C++ API by a directX application. +*/ + +#include <Windows.h> + +#include "GfeSDKWrapper.hpp" + +#include <json/json.h> + +char g_logBuffer[512]; +void dbgprint(const char *fmt, ...) { + va_list args; + va_start(args, fmt); + vsprintf_s(g_logBuffer, sizeof(g_logBuffer) / sizeof(g_logBuffer[0]), fmt, args); + printf(g_logBuffer); + printf("\n"); + OutputDebugStringA(g_logBuffer); + OutputDebugStringA("\n"); + va_end(args); +} +#define LOG(fmt, ...) dbgprint(fmt, __VA_ARGS__) + +static std::wstring permissionToStringW(GfeSDK::NVGSDK_Permission p) +{ + switch (p) + { + case GfeSDK::NVGSDK_PERMISSION_MUST_ASK: return L"Must Ask"; + case GfeSDK::NVGSDK_PERMISSION_GRANTED: return L"Granted"; + case GfeSDK::NVGSDK_PERMISSION_DENIED: return L"Denied"; + default: + return L"UNKNOWN"; + } +} + +GfeSdkWrapper::GfeSdkWrapper() : + m_currentPermission(permissionToStringW(GfeSDK::NVGSDK_PERMISSION_MUST_ASK)) +{ +} + +void GfeSdkWrapper::Init(char const* gameName, char const* defaultLocale, GfeSDK::NVGSDK_Highlight* highlights, size_t numHighlights) +{ + using namespace std::placeholders; + + //! [Creation CPP] + GfeSDK::CreateInputParams createParams; + createParams.appName = "gfesdk_dx_sample"; // appName will only be used/visible if GFE cannot identify your game + createParams.pollForCallbacks = true; // We will poll for callbacks in order to execute callbacks from game loop + createParams.requiredScopes = { + GfeSDK::NVGSDK_SCOPE_HIGHLIGHTS, + GfeSDK::NVGSDK_SCOPE_HIGHLIGHTS_VIDEO, + GfeSDK::NVGSDK_SCOPE_HIGHLIGHTS_SCREENSHOT + }; + createParams.notificationCallback = std::bind(&GfeSdkWrapper::OnNotification, this, _1, _2); + + GfeSDK::CreateResponse response; + GfeSDK::Core* gfesdkCore = GfeSDK::Core::Create(createParams, response); + if (GfeSDK::NVGSDK_SUCCEEDED(response.returnCode)) + { + // Valid handle has been returned + LOG("Success: %s", GfeSDK::NVGSDK_RetCodeToString(response.returnCode)); + LOG("PC is running GFE version %s", response.nvidiaGfeVersion.c_str()); + LOG("PC is running GfeSDK version %d.%d", response.versionMajor, response.versionMinor); + switch (response.returnCode) + { + case GfeSDK::NVGSDK_SUCCESS_VERSION_OLD_GFE: + LOG("Compatible, but the user should update to the latest version of GFE."); + break; + case GfeSDK::NVGSDK_SUCCESS_VERSION_OLD_SDK: + LOG("Compatible, but this application should update to a more recent GfeSDK to get latest features/bugfixes"); + break; + } + } + else + { + // No valid handle + LOG("Failure: %s", GfeSDK::NVGSDK_RetCodeToString(response.returnCode)); + switch (response.returnCode) + { + case GfeSDK::NVGSDK_ERR_SDK_VERSION: + LOG("This version of the SDK is too old to communicate with the user's SDK. We're never planning on this happening."); + LOG("PC is running GFE version %s", response.nvidiaGfeVersion.c_str()); + LOG("PC is running GfeSDK version %d.%d", response.versionMajor, response.versionMinor); + break; + case GfeSDK::NVGSDK_SUCCESS_VERSION_OLD_SDK: + LOG("The installed version of GFE is too old to continue. User must upgrade."); + LOG("PC is running GFE version %s", response.nvidiaGfeVersion.c_str()); + LOG("PC is running GfeSDK version %d.%d", response.versionMajor, response.versionMinor); + break; + } + return; + } + //! [Creation CPP] + + m_gfesdk.reset(gfesdkCore); + UpdateLastResultString(response.returnCode); + + if (response.scopePermissions.find(GfeSDK::NVGSDK_SCOPE_HIGHLIGHTS_VIDEO) != response.scopePermissions.end()) + { + m_currentPermission = permissionToStringW(response.scopePermissions[GfeSDK::NVGSDK_SCOPE_HIGHLIGHTS_VIDEO]); + } + + //! [Permissions CPP] + // Request Permissions if user hasn't decided yet + GfeSDK::RequestPermissionsParams requestPermissionsParams; + + // 'response' came from create call. It tells us which permissions we requested during Create, + // but the user hasn't yet made a decision on + for (auto&& entry : response.scopePermissions) + { + if (entry.second == GfeSDK::NVGSDK_PERMISSION_MUST_ASK) + { + requestPermissionsParams.scopes.push_back(entry.first); + } + } + + if (!requestPermissionsParams.scopes.empty()) + { + // If the user hasn't given permission for recording yet, ask them to do so now via overlay + m_gfesdk->RequestPermissionsAsync(requestPermissionsParams, [this, defaultLocale, highlights, numHighlights](GfeSDK::NVGSDK_RetCode rc, void* cbContext) { + UpdateLastResultString(rc); + if (GfeSDK::NVGSDK_SUCCEEDED(rc)) + { + ConfigureHighlights(defaultLocale, highlights, numHighlights); + } + }); + } + else + { + // Otherwise, go ahead and set up now + ConfigureHighlights(defaultLocale, highlights, numHighlights); + } + //! [Permissions CPP] +} + +void GfeSdkWrapper::DeInit() +{ + // Releasing from smart pointer just to document how to delete handle + GfeSDK::Core* gfesdkCore = m_gfesdk.release(); + + //! [Release CPP] + delete gfesdkCore; + //! [Release CPP] +} + +void GfeSdkWrapper::OnTick(void) +{ + if (!m_gfesdk) return; + + // Poll for callbacks in order to execute these callbacks from the game update thread, + // not a third party thead owned by GfeSDK. This lets us update game state from the callbacks + // without causing a threading problem + m_gfesdk->Poll(); +} + +void GfeSdkWrapper::OnNotification(GfeSDK::NVGSDK_NotificationType type, GfeSDK::NotificationBase const& notification) +{ + switch (type) + { + case GfeSDK::NVGSDK_NOTIFICATION_PERMISSIONS_CHANGED: + { + GfeSDK::PermissionsChangedNotification const& n = static_cast<GfeSDK::PermissionsChangedNotification const&>(notification); + + auto hlPermission = n.scopePermissions.find(GfeSDK::NVGSDK_SCOPE_HIGHLIGHTS_VIDEO); + if (hlPermission != n.scopePermissions.end()) + { + m_currentPermission = permissionToStringW(hlPermission->second); + } + break; + } + case GfeSDK::NVGSDK_NOTIFICATION_OVERLAY_STATE_CHANGED: + { + GfeSDK::OverlayStateChangedNotification const& n = static_cast<GfeSDK::OverlayStateChangedNotification const&>(notification); + + m_lastOverlayEvent.clear(); + switch (n.state) + { + case GfeSDK::NVGSDK_OVERLAY_STATE_MAIN: m_lastOverlayEvent += L"Main Overlay Window"; break; + case GfeSDK::NVGSDK_OVERLAY_STATE_PERMISSION: m_lastOverlayEvent += L"Permission Overlay Window"; break; + case GfeSDK::NVGSDK_OVERLAY_STATE_HIGHLIGHTS_SUMMARY: m_lastOverlayEvent += L"Highlights Summary Overlay Window"; break; + default: + m_lastOverlayEvent += L"UNKNOWNWindow"; + } + m_lastOverlayEvent += (n.open ? L" OPEN" : L" CLOSE"); + break; + } + } +} + +void GfeSdkWrapper::OnOpenGroup(std::string const& id) +{ + if (!m_highlights) return; + + //! [OpenGroup CPP] + GfeSDK::HighlightOpenGroupParams params; + params.groupId = id; + params.groupDescriptionLocaleTable["en-US"] = id; + m_highlights->OpenGroupAsync(params, [this](GfeSDK::NVGSDK_RetCode rc, void*) { + UpdateLastResultString(rc); + }); + //! [OpenGroup CPP] +} + +void GfeSdkWrapper::OnCloseGroup(std::string const& id, bool destroy) +{ + if (!m_highlights) return; + + //! [CloseGroup CPP] + GfeSDK::HighlightCloseGroupParams params; + params.groupId = id; + params.destroyHighlights = destroy; + m_highlights->CloseGroupAsync(params, [this](GfeSDK::NVGSDK_RetCode rc, void*) { + UpdateLastResultString(rc); + }); + //! [CloseGroup CPP] + +#ifdef DOXYGEN + //! [Async Call No Callback] + // If the caller doesn't care about the return value, no need to pass callbacks + GfeSDK::HighlightCloseGroupParams params = { "GROUP_1" }; + m_highlights->CloseGroupAsync(params); + //! [Async Call No Callback] +#endif +} + +void GfeSdkWrapper::OnSaveScreenshot(std::string const& highlightId, std::string const& groupId) +{ + GfeSDK::ScreenshotHighlightParams params; + params.groupId = groupId; + params.highlightId = highlightId; + m_highlights->SetScreenshotHighlightAsync(params, [this](GfeSDK::NVGSDK_RetCode rc, void*) { + UpdateLastResultString(rc); + }); +} + +void GfeSdkWrapper::OnSaveVideo(std::string const& highlightId, std::string const& groupId, int startDelta, int endDelta) +{ + //! [SaveVideo CPP] + GfeSDK::VideoHighlightParams params; + params.startDelta = startDelta; + params.endDelta = endDelta; + params.groupId = groupId; + params.highlightId = highlightId; + m_highlights->SetVideoHighlightAsync(params, [this](GfeSDK::NVGSDK_RetCode rc, void*) { + UpdateLastResultString(rc); + }); + //! [SaveVideo CPP] +} + +void GfeSdkWrapper::OnGetNumHighlights(std::string const& groupId, GfeSDK::NVGSDK_HighlightSignificance sigFilter, GfeSDK::NVGSDK_HighlightType tagFilter) +{ + GfeSDK::GroupView v; + v.groupId = groupId; + v.significanceFilter = sigFilter; + v.tagsFilter = tagFilter; + + m_highlights->GetNumberOfHighlightsAsync(v, [this](GfeSDK::NVGSDK_RetCode rc, GfeSDK::GetNumberOfHighlightsResponse const* response, void*) { + UpdateLastResultString(rc); + if (GfeSDK::NVGSDK_SUCCEEDED(rc)) + { + m_lastQueryResult = std::to_wstring(response->numHighlights); + } + }); +} + +void GfeSdkWrapper::OnOpenSummary(char const* groupIds[], size_t numGroups, GfeSDK::NVGSDK_HighlightSignificance sigFilter, GfeSDK::NVGSDK_HighlightType tagFilter) +{ + //! [OpenSummary CPP] + GfeSDK::SummaryParams params; + + // Can show more than one group at a time, each with their own filters if desired + for (size_t i = 0; i < numGroups; ++i) + { + GfeSDK::GroupView v; + v.groupId = groupIds[i]; + v.significanceFilter = sigFilter; + v.tagsFilter = tagFilter; + params.groupViews.push_back(v); + } + + m_highlights->OpenSummaryAsync(params, [this](GfeSDK::NVGSDK_RetCode rc, void*) { + UpdateLastResultString(rc); + }); + //! [OpenSummary CPP] +} + +void GfeSdkWrapper::OnRequestLanguage(void) +{ + //! [Asynchonous Call] + // We are passing two arguments to this function, the function lambda, and a user context. In this case, we're passing + // the 'this' pointer as the user context. This gets passed through unmodified for use in the callback function. + m_gfesdk->GetUILanguageAsync([this](GfeSDK::NVGSDK_RetCode rc, GfeSDK::GetUILanguageResponse const* response, void* context) { + // Passed this pointer through as context + GfeSdkWrapper* thiz = reinterpret_cast<GfeSdkWrapper*>(context); + + UpdateLastResultString(rc); + if (GfeSDK::NVGSDK_SUCCEEDED(rc)) + { + m_lastQueryResult = m_converter.from_bytes(response->cultureCode); + } + }, this); + //! [Asynchonous Call] +} + +void GfeSdkWrapper::OnRequestUserSettings(void) +{ + m_highlights->GetUserSettingsAsync([this](GfeSDK::NVGSDK_RetCode rc, GfeSDK::GetUserSettingsResponse const* response, void*) { + UpdateLastResultString(rc); + m_lastQueryResult = L""; + if (GfeSDK::NVGSDK_SUCCEEDED(rc)) + { + for (auto it = response->highlightSettings.begin(); it != response->highlightSettings.end(); ++it) + { + m_lastQueryResult += L"\n" + m_converter.from_bytes(it->highlightId) + (it->enabled ? L": ON" : L": OFF"); + } + } + }); +} + +wchar_t const* GfeSdkWrapper::GetCurrentPermissionStr(void) +{ + return m_currentPermission.c_str(); +} + +wchar_t const* GfeSdkWrapper::GetLastOverlayEvent(void) +{ + return m_lastOverlayEvent.c_str(); +} + +wchar_t const* GfeSdkWrapper::GetLastResult(void) +{ + return m_lastResult.c_str(); +} + +wchar_t const* GfeSdkWrapper::GetLastQueryResult(void) +{ + return m_lastQueryResult.c_str(); +} + +void GfeSdkWrapper::ConfigureHighlights(char const* defaultLocale, GfeSDK::NVGSDK_Highlight* highlights, size_t numHighlights) +{ + //! [ConfigureHighlights CPP] + // Create handle to highlights module + m_highlights.reset(GfeSDK::Highlights::Create(m_gfesdk.get())); + + GfeSDK::HighlightConfigParams configParams; + configParams.defaultLocale = defaultLocale; + + // Set up highlight definition table + for (size_t i = 0; i < numHighlights; ++i) + { + GfeSDK::HighlightDefinition highlightDef; + highlightDef.id = highlights[i].id; + highlightDef.userDefaultInterest = highlights[i].userInterest; + highlightDef.significance = highlights[i].significance; + highlightDef.highlightTags = highlights[i].highlightTags; + for (size_t j = 0; j < highlights[i].nameTableSize; ++j) + { + highlightDef.nameLocaleTable[highlights[i].nameTable[j].localeCode] = highlights[i].nameTable[j].localizedString; + } + + configParams.highlightDefinitions.push_back(highlightDef); + } + + m_highlights->ConfigureAsync(configParams, [this](GfeSDK::NVGSDK_RetCode rc, void*) { + UpdateLastResultString(rc); + }); + //! [ConfigureHighlights CPP] +} + +void GfeSdkWrapper::UpdateLastResultString(GfeSDK::NVGSDK_RetCode rc) +{ + m_lastResult = m_converter.from_bytes(GfeSDK::RetCodeToString(rc)); +} |