diff --git a/.gitattributes b/.gitattributes index d21f1dda0..d3f7280e2 100644 --- a/.gitattributes +++ b/.gitattributes @@ -12,6 +12,8 @@ configure crlf=input *.dsp -crlf *.dsptemplate -crlf *.dsw -crlf +*.pfx -crlf +*.png -crlf *.sln -crlf *.vcproj -crlf diff --git a/Help/manual/cmake-properties.7.rst b/Help/manual/cmake-properties.7.rst index 5b0673ac0..d28229a3a 100644 --- a/Help/manual/cmake-properties.7.rst +++ b/Help/manual/cmake-properties.7.rst @@ -235,6 +235,7 @@ Properties on Targets /prop_tgt/VS_SCC_LOCALPATH /prop_tgt/VS_SCC_PROJECTNAME /prop_tgt/VS_SCC_PROVIDER + /prop_tgt/VS_WINRT_COMPONENT /prop_tgt/VS_WINRT_EXTENSIONS /prop_tgt/VS_WINRT_REFERENCES /prop_tgt/WIN32_EXECUTABLE diff --git a/Help/prop_tgt/VS_WINRT_COMPONENT.rst b/Help/prop_tgt/VS_WINRT_COMPONENT.rst new file mode 100644 index 000000000..e160bd64b --- /dev/null +++ b/Help/prop_tgt/VS_WINRT_COMPONENT.rst @@ -0,0 +1,11 @@ +VS_WINRT_COMPONENT +------------------ + +Mark a target as a Windows Runtime component for the Visual Studio generator. +Compile the target with ``C++/CX`` language extensions for Windows Runtime. +For ``SHARED`` and ``MODULE`` libraries, this also defines the +``_WINRT_DLL`` preprocessor macro. + +.. note:: + Currently this is implemented only by Visual Studio generators. + Support may be added to other generators in the future. diff --git a/Help/prop_tgt/VS_WINRT_EXTENSIONS.rst b/Help/prop_tgt/VS_WINRT_EXTENSIONS.rst index cc6fb16b0..d1cba3471 100644 --- a/Help/prop_tgt/VS_WINRT_EXTENSIONS.rst +++ b/Help/prop_tgt/VS_WINRT_EXTENSIONS.rst @@ -1,6 +1,5 @@ VS_WINRT_EXTENSIONS ------------------- -Visual Studio project C++/CX language extensions for Windows Runtime - -Can be set to enable C++/CX language extensions. +Deprecated. Use :prop_tgt:`VS_WINRT_COMPONENT` instead. +This property was an experimental partial implementation of that one. diff --git a/Help/release/dev/vs-windows-apps.rst b/Help/release/dev/vs-windows-apps.rst new file mode 100644 index 000000000..63dae2812 --- /dev/null +++ b/Help/release/dev/vs-windows-apps.rst @@ -0,0 +1,6 @@ +vs-windows-apps +--------------- + +* The :prop_tgt:`VS_WINRT_COMPONENT` target property was created to + tell Visual Studio generators to compile a shared library as a + Windows Runtime (WinRT) component. diff --git a/Modules/CMakeDetermineCompilerABI.cmake b/Modules/CMakeDetermineCompilerABI.cmake index 8595b976f..4b7ec301f 100644 --- a/Modules/CMakeDetermineCompilerABI.cmake +++ b/Modules/CMakeDetermineCompilerABI.cmake @@ -28,13 +28,15 @@ function(CMAKE_DETERMINE_COMPILER_ABI lang src) if(DEFINED CMAKE_${lang}_VERBOSE_FLAG) set(CMAKE_FLAGS "-DCMAKE_EXE_LINKER_FLAGS=${CMAKE_${lang}_VERBOSE_FLAG}") endif() + if(NOT "x${CMAKE_${lang}_COMPILER_ID}" STREQUAL "xMSVC") + # Avoid adding our own platform standard libraries for compilers + # from which we might detect implicit link libraries. + list(APPEND CMAKE_FLAGS "-DCMAKE_${lang}_STANDARD_LIBRARIES=") + endif() try_compile(CMAKE_${lang}_ABI_COMPILED ${CMAKE_BINARY_DIR} ${src} - CMAKE_FLAGS "${CMAKE_FLAGS}" - "-DCMAKE_${lang}_STANDARD_LIBRARIES=" - # We need ignore these warnings because some platforms need - # CMAKE_${lang}_STANDARD_LIBRARIES to link properly and we - # don't care when we are just determining the ABI. + CMAKE_FLAGS ${CMAKE_FLAGS} + # Ignore unused flags when we are just determining the ABI. "--no-warn-unused-cli" OUTPUT_VARIABLE OUTPUT COPY_FILE "${BIN}" diff --git a/Modules/Platform/Windows-MSVC.cmake b/Modules/Platform/Windows-MSVC.cmake index 0c2e21b39..a72f9469e 100644 --- a/Modules/Platform/Windows-MSVC.cmake +++ b/Modules/Platform/Windows-MSVC.cmake @@ -163,6 +163,7 @@ if(WINCE) set(CMAKE_C_STANDARD_LIBRARIES_INIT "${CMAKE_C_STANDARD_LIBRARIES_INIT} corelibc.lib") endif () elseif(WINDOWS_PHONE OR WINDOWS_STORE) + set(_PLATFORM_DEFINES "/DWIN32") set(_FLAGS_C " /DUNICODE /D_UNICODE") set(_FLAGS_CXX " /DUNICODE /D_UNICODE /GR /EHsc") if(WINDOWS_PHONE) diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index f9b68d47b..9a42ca2ed 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -53,6 +53,8 @@ struct ExternalObjectsTag {}; struct IDLSourcesTag {}; struct ResxTag {}; struct ModuleDefinitionFileTag {}; +struct AppManifestTag{}; +struct CertificatesTag{}; #if !defined(_MSC_VER) || _MSC_VER >= 1310 template @@ -195,6 +197,14 @@ struct TagVisitor { DoAccept::Result>::Do(this->Data, sf); } + else if (ext == "appxmanifest") + { + DoAccept::Result>::Do(this->Data, sf); + } + else if (ext == "pfx") + { + DoAccept::Result>::Do(this->Data, sf); + } else if(this->Header.find(sf->GetFullPath().c_str())) { DoAccept::Result>::Do(this->Data, sf); @@ -428,6 +438,24 @@ void cmGeneratorTarget srcs = data.ResxSources; } +//---------------------------------------------------------------------------- +void +cmGeneratorTarget +::GetAppManifest(std::vector& data, + const std::string& config) const +{ + IMPLEMENT_VISIT(AppManifest); +} + +//---------------------------------------------------------------------------- +void +cmGeneratorTarget +::GetCertificates(std::vector& data, + const std::string& config) const +{ + IMPLEMENT_VISIT(Certificates); +} + //---------------------------------------------------------------------------- bool cmGeneratorTarget::IsSystemIncludeDirectory(const std::string& dir, const std::string& config) const diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h index 29aa4106f..2083b8858 100644 --- a/Source/cmGeneratorTarget.h +++ b/Source/cmGeneratorTarget.h @@ -54,6 +54,10 @@ public: const std::string& config) const; void GetExpectedResxHeaders(std::set&, const std::string& config) const; + void GetAppManifest(std::vector&, + const std::string& config) const; + void GetCertificates(std::vector&, + const std::string& config) const; void ComputeObjectMapping(); diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index 09a9252c2..c525b7ce1 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -181,7 +181,12 @@ cmVisualStudio10TargetGenerator(cmTarget* target, this->GUID = this->GlobalGenerator->GetGUID(this->Name.c_str()); this->Platform = gg->GetPlatformName(); this->MSTools = true; + this->TargetCompileAsWinRT = false; this->BuildFileStream = 0; + this->IsMissingFiles = false; + this->DefaultArtifactDir = + this->Makefile->GetStartOutputDirectory() + std::string("/") + + this->LocalGenerator->GetTargetDirectory(*this->Target); } cmVisualStudio10TargetGenerator::~cmVisualStudio10TargetGenerator() @@ -312,9 +317,10 @@ void cmVisualStudio10TargetGenerator::Generate() this->WriteString("", 2); (*this->BuildFileStream) << "{" << this->GUID << "}\n"; - if(this->MSTools && this->Target->GetType() <= cmTarget::UTILITY) + if(this->MSTools && this->Target->GetType() <= cmTarget::GLOBAL_TARGET) { this->WriteApplicationTypeSettings(); + this->VerifyNecessaryFiles(); } const char* vsProjectTypes = @@ -351,6 +357,11 @@ void cmVisualStudio10TargetGenerator::Generate() } } + if(this->Target->GetPropertyAsBool("VS_WINRT_COMPONENT")) + { + this->WriteString("true\n", 2); + } + const char* vsGlobalKeyword = this->Target->GetProperty("VS_GLOBAL_KEYWORD"); if(!vsGlobalKeyword) @@ -410,6 +421,7 @@ void cmVisualStudio10TargetGenerator::Generate() " Label=\"LocalAppDataPlatform\" />\n", 2); this->WriteString("\n", 1); this->WriteString("\n", 1); + this->WriteWinRTPackageCertificateKeyFile(); this->WritePathAndIncrementalLinkOptions(); this->WriteItemDefinitionGroups(); this->WriteCustomCommands(); @@ -421,6 +433,7 @@ void cmVisualStudio10TargetGenerator::Generate() this->WriteString( "\n", 1); + this->WriteTargetSpecificReferences(); this->WriteString("\n", 1); if (this->GlobalGenerator->IsMasmEnabled()) { @@ -500,6 +513,22 @@ void cmVisualStudio10TargetGenerator::WriteEmbeddedResourceGroup() } } +void cmVisualStudio10TargetGenerator::WriteTargetSpecificReferences() +{ + if(this->MSTools) + { + if(this->GlobalGenerator->TargetsWindowsPhone() && + this->GlobalGenerator->GetSystemVersion() == "8.0") + { + this->WriteString( + "\n", 1); + } + } +} + void cmVisualStudio10TargetGenerator::WriteWinRTReferences() { std::vector references; @@ -508,6 +537,13 @@ void cmVisualStudio10TargetGenerator::WriteWinRTReferences() { cmSystemTools::ExpandListArgument(vsWinRTReferences, references); } + + if(this->GlobalGenerator->TargetsWindowsPhone() && + this->GlobalGenerator->GetSystemVersion() == "8.0" && + references.empty()) + { + references.push_back("platform.winmd"); + } if(!references.empty()) { this->WriteString("\n", 1); @@ -572,9 +608,9 @@ void cmVisualStudio10TargetGenerator::WriteProjectConfigurationValues() configType += "Application"; break; case cmTarget::UTILITY: + case cmTarget::GLOBAL_TARGET: configType += "Utility"; break; - case cmTarget::GLOBAL_TARGET: case cmTarget::UNKNOWN_LIBRARY: case cmTarget::INTERFACE_LIBRARY: break; @@ -616,6 +652,9 @@ void cmVisualStudio10TargetGenerator if((this->Target->GetType() <= cmTarget::OBJECT_LIBRARY && this->ClOptions[config]->UsingUnicode()) || + this->Target->GetPropertyAsBool("VS_WINRT_COMPONENT") || + this->GlobalGenerator->TargetsWindowsPhone() || + this->GlobalGenerator->TargetsWindowsStore() || this->Target->GetPropertyAsBool("VS_WINRT_EXTENSIONS")) { this->WriteString("Unicode\n", 2); @@ -636,7 +675,8 @@ void cmVisualStudio10TargetGenerator pts += "\n"; this->WriteString(pts.c_str(), 2); } - if(this->Target->GetPropertyAsBool("VS_WINRT_EXTENSIONS")) + if(this->Target->GetPropertyAsBool("VS_WINRT_COMPONENT") || + this->Target->GetPropertyAsBool("VS_WINRT_EXTENSIONS")) { this->WriteString("true" "\n", 2); @@ -846,6 +886,49 @@ void cmVisualStudio10TargetGenerator::WriteGroups() this->WriteGroupSources(ti->first.c_str(), ti->second, sourceGroups); } + // Added files are images and the manifest. + if (!this->AddedFiles.empty()) + { + this->WriteString("\n", 1); + for(std::vector::const_iterator + oi = this->AddedFiles.begin(); oi != this->AddedFiles.end(); ++oi) + { + std::string fileName = cmSystemTools::LowerCase( + cmSystemTools::GetFilenameName(*oi)); + if (fileName == "wmappmanifest.xml") + { + this->WriteString("BuildFileStream) << *oi << "\">\n"; + this->WriteString("Resource Files\n", 3); + this->WriteString("\n", 2); + } + else if(cmSystemTools::GetFilenameExtension(fileName) == + ".appxmanifest") + { + this->WriteString("BuildFileStream) << *oi << "\">\n"; + this->WriteString("Resource Files\n", 3); + this->WriteString("\n", 2); + } + else if(cmSystemTools::GetFilenameExtension(fileName) == + ".pfx") + { + this->WriteString("BuildFileStream) << *oi << "\">\n"; + this->WriteString("Resource Files\n", 3); + this->WriteString("\n", 2); + } + else + { + this->WriteString("BuildFileStream) << *oi << "\">\n"; + this->WriteString("Resource Files\n", 3); + this->WriteString("\n", 2); + } + } + this->WriteString("\n", 1); + } + std::vector resxObjs; this->GeneratorTarget->GetResxSources(resxObjs, ""); if(!resxObjs.empty()) @@ -919,7 +1002,7 @@ void cmVisualStudio10TargetGenerator::WriteGroups() this->WriteString("\n", 2); } - if(!resxObjs.empty()) + if(!resxObjs.empty() || !this->AddedFiles.empty()) { this->WriteString("\n", 2); std::string guidName = "SG_Filter_Resource Files"; @@ -1048,11 +1131,7 @@ void cmVisualStudio10TargetGenerator::WriteExtraSource(cmSourceFile const* sf) std::string tool = "None"; std::string shaderType; std::string const& ext = sf->GetExtension(); - if(ext == "appxmanifest") - { - tool = "AppxManifest"; - } - else if(ext == "hlsl") + if(ext == "hlsl") { tool = "FXCompile"; // Figure out the type of shader compiler to use. @@ -1247,6 +1326,10 @@ void cmVisualStudio10TargetGenerator::WriteAllSources() } } + std::vector manifestSources; + this->GeneratorTarget->GetAppManifest(manifestSources, ""); + this->WriteSources("AppxManifest", manifestSources); + std::vector externalObjects; this->GeneratorTarget->GetExternalObjects(externalObjects, ""); for(std::vector::iterator @@ -1302,6 +1385,11 @@ void cmVisualStudio10TargetGenerator::WriteAllSources() (*this->BuildFileStream ) << cmVS10EscapeXML(obj) << "\" />\n"; } + if (this->IsMissingFiles) + { + this->WriteMissingFiles(); + } + this->WriteString("\n", 1); } @@ -1353,6 +1441,7 @@ bool cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags( compileAs = "CompileAsC"; } } + bool noWinRT = this->TargetCompileAsWinRT && lang == "C"; bool hasFlags = false; // for the first time we need a new line if there is something // produced here. @@ -1386,7 +1475,7 @@ bool cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags( } // if we have flags or defines for this config then // use them - if(!flags.empty() || !configDefines.empty() || compileAs) + if(!flags.empty() || !configDefines.empty() || compileAs || noWinRT) { (*this->BuildFileStream ) << firstString; firstString = ""; // only do firstString once @@ -1399,6 +1488,10 @@ bool cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags( { clOptions.AddFlag("CompileAs", compileAs); } + if(noWinRT) + { + clOptions.AddFlag("CompileAsWinRT", "false"); + } clOptions.Parse(flags.c_str()); if(clOptions.HasFlag("AdditionalIncludeDirectories")) { @@ -1634,6 +1727,36 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions( clOptions.AddDefine(exportMacro); } + if (this->MSTools) + { + // If we have the VS_WINRT_COMPONENT set then force Compile as WinRT. + if (this->Target->GetPropertyAsBool("VS_WINRT_COMPONENT")) + { + clOptions.AddFlag("CompileAsWinRT", "true"); + // For WinRT components, add the _WINRT_DLL define to produce a lib + if (this->Target->GetType() == cmTarget::SHARED_LIBRARY || + this->Target->GetType() == cmTarget::MODULE_LIBRARY ) + { + clOptions.AddDefine("_WINRT_DLL"); + } + } + else if (this->GlobalGenerator->TargetsWindowsStore() || + this->GlobalGenerator->TargetsWindowsPhone()) + { + if (!clOptions.IsWinRt()) + { + clOptions.AddFlag("CompileAsWinRT", "false"); + } + } + if(const char* winRT = clOptions.GetFlag("CompileAsWinRT")) + { + if(cmSystemTools::IsOn(winRT)) + { + this->TargetCompileAsWinRT = true; + } + } + } + this->ClOptions[configName] = pOptions.release(); return true; } @@ -1829,6 +1952,18 @@ cmVisualStudio10TargetGenerator::WriteLibOptions(std::string const& config) libOptions.OutputFlagMap(*this->BuildFileStream, " "); this->WriteString("\n", 2); } + + // We cannot generate metadata for static libraries. WindowsPhone + // and WindowsStore tools look at GenerateWindowsMetadata in the + // Link tool options even for static libraries. + if(this->GlobalGenerator->TargetsWindowsPhone() || + this->GlobalGenerator->TargetsWindowsStore()) + { + this->WriteString("\n", 2); + this->WriteString("false" + "\n", 3); + this->WriteString("\n", 2); + } } //---------------------------------------------------------------------------- @@ -2010,6 +2145,28 @@ cmVisualStudio10TargetGenerator::ComputeLinkOptions(std::string const& config) linkOptions.AddFlag("ImportLibrary", imLib.c_str()); linkOptions.AddFlag("ProgramDataBaseFile", pdb.c_str()); + + // A Windows Runtime component uses internal .NET metadata, + // so does not have an import library. + if(this->Target->GetPropertyAsBool("VS_WINRT_COMPONENT")) + { + linkOptions.AddFlag("GenerateWindowsMetadata", "true"); + } + else if (this->GlobalGenerator->TargetsWindowsPhone() || + this->GlobalGenerator->TargetsWindowsStore()) + { + // WindowsPhone and WindowsStore components are in an app container + // and produce WindowsMetadata. If we are not producing a WINRT + // component, then do not generate the metadata here. + linkOptions.AddFlag("GenerateWindowsMetadata", "false"); + } + + if (this->GlobalGenerator->TargetsWindowsPhone() && + this->GlobalGenerator->GetSystemVersion() == "8.0") + { + // WindowsPhone 8.0 does not have ole32. + linkOptions.AppendFlag("IgnoreSpecificDefaultLibraries", "ole32.lib"); + } } linkOptions.Parse(flags.c_str()); @@ -2260,6 +2417,67 @@ void cmVisualStudio10TargetGenerator::WriteProjectReferences() this->WriteString("\n", 1); } +void cmVisualStudio10TargetGenerator::WriteWinRTPackageCertificateKeyFile() +{ + if((this->GlobalGenerator->TargetsWindowsStore() || + this->GlobalGenerator->TargetsWindowsPhone()) + && (cmTarget::EXECUTABLE == this->Target->GetType())) + { + std::string pfxFile; + std::vector certificates; + this->GeneratorTarget->GetCertificates(certificates, ""); + for(std::vector::const_iterator si = + certificates.begin(); si != certificates.end(); ++si) + { + pfxFile = this->ConvertPath((*si)->GetFullPath(), false); + this->ConvertToWindowsSlash(pfxFile); + break; + } + + if(this->IsMissingFiles && + !(this->GlobalGenerator->TargetsWindowsPhone() && + this->GlobalGenerator->GetSystemVersion() == "8.0")) + { + // Move the manifest to a project directory to avoid clashes + std::string artifactDir = + this->LocalGenerator->GetTargetDirectory(*this->Target); + this->ConvertToWindowsSlash(artifactDir); + this->WriteString("\n", 1); + this->WriteString("", 2); + (*this->BuildFileStream) << cmVS10EscapeXML(artifactDir) << + "\\\n"; + this->WriteString("" + "$(TargetDir)resources.pri", 2); + + // If we are missing files and we don't have a certificate and + // aren't targeting WP8.0, add a default certificate + if(pfxFile.empty()) + { + std::string templateFolder = cmSystemTools::GetCMakeRoot() + + "/Templates/Windows"; + pfxFile = this->DefaultArtifactDir + "/Windows_TemporaryKey.pfx"; + cmSystemTools::CopyAFile(templateFolder + "/Windows_TemporaryKey.pfx", + pfxFile, false); + this->ConvertToWindowsSlash(pfxFile); + this->AddedFiles.push_back(pfxFile); + } + + this->WriteString("<", 2); + (*this->BuildFileStream) << "PackageCertificateKeyFile>" + << pfxFile << "\n"; + this->WriteString("\n", 1); + } + else if(!pfxFile.empty()) + { + this->WriteString("\n", 1); + this->WriteString("<", 2); + (*this->BuildFileStream) << "PackageCertificateKeyFile>" + << pfxFile << "\n"; + this->WriteString("\n", 1); + } + } +} + bool cmVisualStudio10TargetGenerator:: IsResxHeader(const std::string& headerFile) { @@ -2273,6 +2491,7 @@ bool cmVisualStudio10TargetGenerator:: void cmVisualStudio10TargetGenerator::WriteApplicationTypeSettings() { + bool isAppContainer = false; bool const isWindowsPhone = this->GlobalGenerator->TargetsWindowsPhone(); bool const isWindowsStore = this->GlobalGenerator->TargetsWindowsStore(); std::string const& v = this->GlobalGenerator->GetSystemVersion(); @@ -2290,17 +2509,439 @@ void cmVisualStudio10TargetGenerator::WriteApplicationTypeSettings() // Visual Studio 12.0 is necessary for building 8.1 apps this->WriteString("12.0" "\n", 2); + + if (this->Target->GetType() < cmTarget::UTILITY) + { + isAppContainer = true; + } } else if (v == "8.0") { // Visual Studio 11.0 is necessary for building 8.0 apps this->WriteString("11.0" "\n", 2); + + if (isWindowsStore && this->Target->GetType() < cmTarget::UTILITY) + { + isAppContainer = true; + } + else if (isWindowsPhone && + this->Target->GetType() == cmTarget::EXECUTABLE) + { + this->WriteString("true\n", 2); + this->WriteString("", 2); + (*this->BuildFileStream) << cmVS10EscapeXML(this->Name.c_str()) << + "_$(Configuration)_$(Platform).xap\n"; + } } } - if (this->Platform == "ARM") + if(isAppContainer) + { + this->WriteString("true" + "", 2); + } + else if (this->Platform == "ARM") { this->WriteString("true" "", 2); } } + +void cmVisualStudio10TargetGenerator::VerifyNecessaryFiles() +{ + // For Windows and Windows Phone executables, we will assume that if a + // manifest is not present that we need to add all the necessary files + if (this->Target->GetType() == cmTarget::EXECUTABLE) + { + std::vector manifestSources; + this->GeneratorTarget->GetAppManifest(manifestSources, ""); + { + std::string const& v = this->GlobalGenerator->GetSystemVersion(); + if(this->GlobalGenerator->TargetsWindowsPhone()) + { + if (v == "8.0") + { + // Look through the sources for WMAppManifest.xml + std::vector extraSources; + this->GeneratorTarget->GetExtraSources(extraSources, ""); + bool foundManifest = false; + for(std::vector::const_iterator si = + extraSources.begin(); si != extraSources.end(); ++si) + { + // Need to do a lowercase comparison on the filename + if("wmappmanifest.xml" == cmSystemTools::LowerCase( + (*si)->GetLocation().GetName())) + { + foundManifest = true; + break; + } + } + if (!foundManifest) + { + this->IsMissingFiles = true; + } + } + else if (v == "8.1") + { + if(manifestSources.empty()) + { + this->IsMissingFiles = true; + } + } + } + else if (this->GlobalGenerator->TargetsWindowsStore()) + { + if (manifestSources.empty()) + { + if (v == "8.0") + { + this->IsMissingFiles = true; + } + else if (v == "8.1") + { + this->IsMissingFiles = true; + } + } + } + } + } +} + +void cmVisualStudio10TargetGenerator::WriteMissingFiles() +{ + std::string const& v = this->GlobalGenerator->GetSystemVersion(); + if(this->GlobalGenerator->TargetsWindowsPhone()) + { + if (v == "8.0") + { + this->WriteMissingFilesWP80(); + } + else if (v == "8.1") + { + this->WriteMissingFilesWP81(); + } + } + else if (this->GlobalGenerator->TargetsWindowsStore()) + { + if (v == "8.0") + { + this->WriteMissingFilesWS80(); + } + else if (v == "8.1") + { + this->WriteMissingFilesWS81(); + } + } +} + +void cmVisualStudio10TargetGenerator::WriteMissingFilesWP80() +{ + std::string templateFolder = cmSystemTools::GetCMakeRoot() + + "/Templates/Windows"; + + // For WP80, the manifest needs to be in the same folder as the project + // this can cause an overwrite problem if projects aren't organized in + // folders + std::string manifestFile = this->Makefile->GetStartOutputDirectory() + + std::string("/WMAppManifest.xml"); + std::string artifactDir = + this->LocalGenerator->GetTargetDirectory(*this->Target); + this->ConvertToWindowsSlash(artifactDir); + std::string artifactDirXML = cmVS10EscapeXML(artifactDir); + std::string targetNameXML = cmVS10EscapeXML(this->Target->GetName()); + + cmGeneratedFileStream fout(manifestFile.c_str()); + fout.SetCopyIfDifferent(true); + + fout << + "\n" + "\n" + "\t\n" + "\tGUID << "}\"" + " Title=\"CMake Test Program\" RuntimeType=\"Modern Native\"" + " Version=\"1.0.0.0\" Genre=\"apps.normal\" Author=\"CMake\"" + " Description=\"Default CMake App\" Publisher=\"CMake\"" + " PublisherID=\"{" << this->GUID << "}\">\n" + "\t\t" + << artifactDirXML << "\\ApplicationIcon.png\n" + "\t\t\n" + "\t\t\n" + "\t\t\t\n" + "\t\t\n" + "\t\t\n" + "\t\t\t\n" + "\t\t\t\t\n" + "\t\t\t\t\t" + << artifactDirXML << "\\SmallLogo.png\n" + "\t\t\t\t\t0\n" + "\t\t\t\t\t" + << artifactDirXML << "\\Logo.png\n" + "\t\t\t\t\n" + "\t\t\t\n" + "\t\t\n" + "\t\t\n" + "\t\t\t\n" + "\t\t\n" + "\t\n" + "\n"; + + std::string sourceFile = this->ConvertPath(manifestFile, false); + this->ConvertToWindowsSlash(sourceFile); + this->WriteString("BuildFileStream) << cmVS10EscapeXML(sourceFile) << "\">\n"; + this->WriteString("Designer\n", 3); + this->WriteString("\n", 2); + this->AddedFiles.push_back(sourceFile); + + std::string smallLogo = this->DefaultArtifactDir + "/SmallLogo.png"; + cmSystemTools::CopyAFile(templateFolder + "/SmallLogo.png", + smallLogo, false); + this->ConvertToWindowsSlash(smallLogo); + this->WriteString("BuildFileStream) << cmVS10EscapeXML(smallLogo) << "\" />\n"; + this->AddedFiles.push_back(smallLogo); + + std::string logo = this->DefaultArtifactDir + "/Logo.png"; + cmSystemTools::CopyAFile(templateFolder + "/Logo.png", + logo, false); + this->ConvertToWindowsSlash(logo); + this->WriteString("BuildFileStream) << cmVS10EscapeXML(logo) << "\" />\n"; + this->AddedFiles.push_back(logo); + + std::string applicationIcon = + this->DefaultArtifactDir + "/ApplicationIcon.png"; + cmSystemTools::CopyAFile(templateFolder + "/ApplicationIcon.png", + applicationIcon, false); + this->ConvertToWindowsSlash(applicationIcon); + this->WriteString("BuildFileStream) << cmVS10EscapeXML(applicationIcon) << "\" />\n"; + this->AddedFiles.push_back(applicationIcon); +} + +void cmVisualStudio10TargetGenerator::WriteMissingFilesWP81() +{ + std::string manifestFile = + this->DefaultArtifactDir + "/package.appxManifest"; + std::string artifactDir = + this->LocalGenerator->GetTargetDirectory(*this->Target); + this->ConvertToWindowsSlash(artifactDir); + std::string artifactDirXML = cmVS10EscapeXML(artifactDir); + std::string targetNameXML = cmVS10EscapeXML(this->Target->GetName()); + + cmGeneratedFileStream fout(manifestFile.c_str()); + fout.SetCopyIfDifferent(true); + + fout << + "\n" + "\n" + "\tGUID << "\" Publisher=\"CN=CMake\"" + " Version=\"1.0.0.0\" />\n" + "\tGUID << "\"" + " PhonePublisherId=\"00000000-0000-0000-0000-000000000000\"/>\n" + "\t\n" + "\t\t" << targetNameXML << "\n" + "\t\tCMake\n" + "\t\t" << artifactDirXML << "\\StoreLogo.png\n" + "\t\n" + "\t\n" + "\t\t6.3.1\n" + "\t\t6.3.1\n" + "\t\n" + "\t\n" + "\t\t\n" + "\t\n" + "\t\n" + "\t\t\n" + "\t\t\t\n" + "\t\t\t\t\n" + "\t\t\t\t\t\n" + "\t\t\t\t\t\t\n" + "\t\t\t\t\t\n" + "\t\t\t\t\n" + "\t\t\t\t\n" + "\t\t\t\n" + "\t\t\n" + "\t\n" + "\n"; + + this->WriteCommonMissingFiles(manifestFile); +} + +void cmVisualStudio10TargetGenerator::WriteMissingFilesWS80() +{ + std::string manifestFile = + this->DefaultArtifactDir + "/package.appxManifest"; + std::string artifactDir = + this->LocalGenerator->GetTargetDirectory(*this->Target); + this->ConvertToWindowsSlash(artifactDir); + std::string artifactDirXML = cmVS10EscapeXML(artifactDir); + std::string targetNameXML = cmVS10EscapeXML(this->Target->GetName()); + + cmGeneratedFileStream fout(manifestFile.c_str()); + fout.SetCopyIfDifferent(true); + + fout << + "\n" + "\n" + "\tGUID << "\" Publisher=\"CN=CMake\"" + " Version=\"1.0.0.0\" />\n" + "\t\n" + "\t\t" << targetNameXML << "\n" + "\t\tCMake\n" + "\t\t" << artifactDirXML << "\\StoreLogo.png\n" + "\t\n" + "\t\n" + "\t\t6.2.1\n" + "\t\t6.2.1\n" + "\t\n" + "\t\n" + "\t\t\n" + "\t\n" + "\t\n" + "\t\t\n" + "\t\t\t\n" + "\t\t\t\t\n" + "\t\t\t\t\n" + "\t\t\t\n" + "\t\t\n" + "\t\n" + "\n"; + + this->WriteCommonMissingFiles(manifestFile); +} + +void cmVisualStudio10TargetGenerator::WriteMissingFilesWS81() +{ + std::string manifestFile = + this->DefaultArtifactDir + "/package.appxManifest"; + std::string artifactDir = + this->LocalGenerator->GetTargetDirectory(*this->Target); + this->ConvertToWindowsSlash(artifactDir); + std::string artifactDirXML = cmVS10EscapeXML(artifactDir); + std::string targetNameXML = cmVS10EscapeXML(this->Target->GetName()); + + cmGeneratedFileStream fout(manifestFile.c_str()); + fout.SetCopyIfDifferent(true); + + fout << + "\n" + "\n" + "\tGUID << "\" Publisher=\"CN=CMake\"" + " Version=\"1.0.0.0\" />\n" + "\t\n" + "\t\t" << targetNameXML << "\n" + "\t\tCMake\n" + "\t\t" << artifactDirXML << "\\StoreLogo.png\n" + "\t\n" + "\t\n" + "\t\t6.3\n" + "\t\t6.3\n" + "\t\n" + "\t\n" + "\t\t\n" + "\t\n" + "\t\n" + "\t\t\n" + "\t\t\t\n" + "\t\t\t\t\n" + "\t\t\t\t\t\n" + "\t\t\t\t\t\t\n" + "\t\t\t\t\t\n" + "\t\t\t\t\n" + "\t\t\t\t\n" + "\t\t\t\n" + "\t\t\n" + "\t\n" + "\n"; + + this->WriteCommonMissingFiles(manifestFile); +} + +void +cmVisualStudio10TargetGenerator +::WriteCommonMissingFiles(const std::string& manifestFile) +{ + std::string templateFolder = cmSystemTools::GetCMakeRoot() + + "/Templates/Windows"; + + std::string sourceFile = this->ConvertPath(manifestFile, false); + this->ConvertToWindowsSlash(sourceFile); + this->WriteString("BuildFileStream) << cmVS10EscapeXML(sourceFile) << "\">\n"; + this->WriteString("Designer\n", 3); + this->WriteString("\n", 2); + this->AddedFiles.push_back(sourceFile); + + std::string smallLogo = this->DefaultArtifactDir + "/SmallLogo.png"; + cmSystemTools::CopyAFile(templateFolder + "/SmallLogo.png", + smallLogo, false); + this->ConvertToWindowsSlash(smallLogo); + this->WriteString("BuildFileStream) << cmVS10EscapeXML(smallLogo) << "\" />\n"; + this->AddedFiles.push_back(smallLogo); + + std::string logo = this->DefaultArtifactDir + "/Logo.png"; + cmSystemTools::CopyAFile(templateFolder + "/Logo.png", + logo, false); + this->ConvertToWindowsSlash(logo); + this->WriteString("BuildFileStream) << cmVS10EscapeXML(logo) << "\" />\n"; + this->AddedFiles.push_back(logo); + + std::string storeLogo = this->DefaultArtifactDir + "/StoreLogo.png"; + cmSystemTools::CopyAFile(templateFolder + "/StoreLogo.png", + storeLogo, false); + this->ConvertToWindowsSlash(storeLogo); + this->WriteString("BuildFileStream) << cmVS10EscapeXML(storeLogo) << "\" />\n"; + this->AddedFiles.push_back(storeLogo); + + std::string splashScreen = this->DefaultArtifactDir + "/SplashScreen.png"; + cmSystemTools::CopyAFile(templateFolder + "/SplashScreen.png", + splashScreen, false); + this->ConvertToWindowsSlash(splashScreen); + this->WriteString("BuildFileStream) << cmVS10EscapeXML(splashScreen) << "\" />\n"; + this->AddedFiles.push_back(splashScreen); + + // This file has already been added to the build so don't copy it + std::string keyFile = this->DefaultArtifactDir + "/Windows_TemporaryKey.pfx"; + this->ConvertToWindowsSlash(keyFile); + this->WriteString("BuildFileStream) << cmVS10EscapeXML(keyFile) << "\" />\n"; +} diff --git a/Source/cmVisualStudio10TargetGenerator.h b/Source/cmVisualStudio10TargetGenerator.h index 93b72f43c..d6db18a2f 100644 --- a/Source/cmVisualStudio10TargetGenerator.h +++ b/Source/cmVisualStudio10TargetGenerator.h @@ -67,8 +67,17 @@ private: void WriteDotNetReferences(); void WriteEmbeddedResourceGroup(); void WriteWinRTReferences(); + void WriteWinRTPackageCertificateKeyFile(); void WritePathAndIncrementalLinkOptions(); void WriteItemDefinitionGroups(); + void VerifyNecessaryFiles(); + void WriteMissingFiles(); + void WriteMissingFilesWP80(); + void WriteMissingFilesWP81(); + void WriteMissingFilesWS80(); + void WriteMissingFilesWS81(); + void WriteCommonMissingFiles(const std::string& manifestFile); + void WriteTargetSpecificReferences(); bool ComputeClOptions(); bool ComputeClOptions(std::string const& configName); @@ -130,10 +139,14 @@ private: std::string GUID; std::string Name; bool MSTools; + bool TargetCompileAsWinRT; cmGlobalVisualStudio10Generator* GlobalGenerator; cmGeneratedFileStream* BuildFileStream; cmLocalVisualStudio7Generator* LocalGenerator; std::set SourcesVisited; + bool IsMissingFiles; + std::vector AddedFiles; + std::string DefaultArtifactDir; typedef std::map ToolSourceMap; ToolSourceMap Tools; diff --git a/Source/cmVisualStudioGeneratorOptions.cxx b/Source/cmVisualStudioGeneratorOptions.cxx index 745961f29..cdc8879a4 100644 --- a/Source/cmVisualStudioGeneratorOptions.cxx +++ b/Source/cmVisualStudioGeneratorOptions.cxx @@ -106,6 +106,12 @@ bool cmVisualStudioGeneratorOptions::IsDebug() const return this->FlagMap.find("DebugInformationFormat") != this->FlagMap.end(); } +//---------------------------------------------------------------------------- +bool cmVisualStudioGeneratorOptions::IsWinRt() const +{ + return this->FlagMap.find("CompileAsWinRT") != this->FlagMap.end(); +} + //---------------------------------------------------------------------------- bool cmVisualStudioGeneratorOptions::UsingUnicode() const { diff --git a/Source/cmVisualStudioGeneratorOptions.h b/Source/cmVisualStudioGeneratorOptions.h index 8de6017f1..9951033bd 100644 --- a/Source/cmVisualStudioGeneratorOptions.h +++ b/Source/cmVisualStudioGeneratorOptions.h @@ -53,6 +53,7 @@ public: bool UsingSBCS() const; bool IsDebug() const; + bool IsWinRt() const; // Write options to output. void OutputPreprocessorDefinitions(std::ostream& fout, const char* prefix, diff --git a/Templates/Windows/ApplicationIcon.png b/Templates/Windows/ApplicationIcon.png new file mode 100644 index 000000000..7d95d4e08 Binary files /dev/null and b/Templates/Windows/ApplicationIcon.png differ diff --git a/Templates/Windows/Logo.png b/Templates/Windows/Logo.png new file mode 100644 index 000000000..e26771cb3 Binary files /dev/null and b/Templates/Windows/Logo.png differ diff --git a/Templates/Windows/SmallLogo.png b/Templates/Windows/SmallLogo.png new file mode 100644 index 000000000..1eb0d9d52 Binary files /dev/null and b/Templates/Windows/SmallLogo.png differ diff --git a/Templates/Windows/SplashScreen.png b/Templates/Windows/SplashScreen.png new file mode 100644 index 000000000..c951e031b Binary files /dev/null and b/Templates/Windows/SplashScreen.png differ diff --git a/Templates/Windows/StoreLogo.png b/Templates/Windows/StoreLogo.png new file mode 100644 index 000000000..dcb672712 Binary files /dev/null and b/Templates/Windows/StoreLogo.png differ diff --git a/Templates/Windows/Windows_TemporaryKey.pfx b/Templates/Windows/Windows_TemporaryKey.pfx new file mode 100644 index 000000000..1cad9993d Binary files /dev/null and b/Templates/Windows/Windows_TemporaryKey.pfx differ diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index f51a93428..a091d407c 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -1764,6 +1764,56 @@ ${CMake_BINARY_DIR}/bin/cmake -DDIR=dev -P ${CMake_SOURCE_DIR}/Utilities/Release endif() endif() + get_filename_component(ntver "[HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Windows NT\\CurrentVersion;CurrentVersion]" NAME) + if(WIN32 AND ntver VERSION_GREATER 6.1) # Windows >= 8.0 + macro(add_test_VSWinStorePhone name generator systemName systemVersion) + add_test(NAME VSWinStorePhone.${name} COMMAND ${CMAKE_CTEST_COMMAND} + --build-and-test + "${CMake_SOURCE_DIR}/Tests/VSWinStorePhone" + "${CMake_BINARY_DIR}/Tests/VSWinStorePhone/${name}" + --build-generator "${generator}" + --build-project VSWinStorePhone + --build-config $ + --build-options -DCMAKE_SYSTEM_NAME=${systemName} + -DCMAKE_SYSTEM_VERSION=${systemVersion} + ) + list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/VSWinStorePhone/${name}") + endmacro() + + set(reg_vs11 "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\11.0;InstallDir]") + set(reg_vs12 "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\12.0;InstallDir]") + set(reg_ws80 "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows\\v8.0;InstallationFolder]") + set(reg_ws81 "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows\\v8.1;InstallationFolder]") + set(reg_wp80 "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\WindowsPhone\\v8.0;InstallationFolder]") + set(reg_wp81 "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\WindowsPhone\\v8.1;InstallationFolder]") + foreach(reg vs11 vs12 ws80 ws81 wp80 wp81) + get_filename_component(r "${reg_${reg}}" ABSOLUTE) + if(IS_DIRECTORY "${r}") + set(${reg} 1) + else() + set(${reg} 0) + endif() + endforeach() + if(vs11 AND ws80) + add_test_VSWinStorePhone(vs11-store80-X86 "Visual Studio 11 2012" WindowsStore 8.0) + add_test_VSWinStorePhone(vs11-store80-ARM "Visual Studio 11 2012 ARM" WindowsStore 8.0) + add_test_VSWinStorePhone(vs11-store80-X64 "Visual Studio 11 2012 Win64" WindowsStore 8.0) + endif() + if(vs12 AND ws81) + add_test_VSWinStorePhone(vs12-store81-X86 "Visual Studio 12 2013" WindowsStore 8.1) + add_test_VSWinStorePhone(vs12-store81-ARM "Visual Studio 12 2013 ARM" WindowsStore 8.1) + add_test_VSWinStorePhone(vs12-store81-X64 "Visual Studio 12 2013 Win64" WindowsStore 8.1) + endif() + if(vs11 AND wp80) + add_test_VSWinStorePhone(vs11-phone80-X86 "Visual Studio 11 2012" WindowsPhone 8.0) + add_test_VSWinStorePhone(vs11-phone80-ARM "Visual Studio 11 2012 ARM" WindowsPhone 8.0) + endif() + if(vs12 AND wp81) + add_test_VSWinStorePhone(vs12-phone81-X86 "Visual Studio 12 2013" WindowsPhone 8.1) + add_test_VSWinStorePhone(vs12-phone81-ARM "Visual Studio 12 2013 ARM" WindowsPhone 8.1) + endif() + endif() + if (APPLE) if (CMAKE_COMPILER_IS_GNUCXX OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") set(BundleTestInstallDir diff --git a/Tests/VSWinStorePhone/CMakeLists.txt b/Tests/VSWinStorePhone/CMakeLists.txt new file mode 100644 index 000000000..0041c7555 --- /dev/null +++ b/Tests/VSWinStorePhone/CMakeLists.txt @@ -0,0 +1,114 @@ +cmake_minimum_required(VERSION 3.0) +project(VSWinStorePhone) + +if(MSVC_VERSION GREATER 1700) + set(COMPILER_VERSION "12") +elseif(MSVC_VERSION GREATER 1600) + set(COMPILER_VERSION "11") +endif() + +set (APP_MANIFEST_NAME Package.appxmanifest) +if("${CMAKE_SYSTEM_NAME}" STREQUAL "WindowsPhone") + set(PLATFORM WP) + add_definitions("-DPHONE") + if("${CMAKE_SYSTEM_VERSION}" STREQUAL "8.0") + set(APP_MANIFEST_NAME WMAppManifest.xml) + set(WINDOWS_PHONE8 1) + endif() +elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "WindowsStore") + set(PLATFORM STORE) +else() + set(PLATFORM DESKTOP) + message(FATAL_ERROR "This app supports Store / Phone only. Please edit the target platform.") +endif() + +set_property(GLOBAL PROPERTY USE_FOLDERS ON) + +set(EXE_NAME Direct3DApp1) +set(SHORT_NAME ${EXE_NAME}) +set(PACKAGE_GUID "6514377e-dfd4-4cdb-80df-4e0366346efc") + +if (NOT "${PLATFORM}" STREQUAL "DESKTOP") + configure_file( + cmake/Package_vc${COMPILER_VERSION}.${PLATFORM}.appxmanifest.in + ${CMAKE_CURRENT_BINARY_DIR}/${APP_MANIFEST_NAME} + @ONLY) +endif() + +set(SOURCE_FILES + Direct3DApp1/CubeRenderer.cpp + Direct3DApp1/Direct3DApp1.cpp + Direct3DApp1/Direct3DBase.cpp + Direct3DApp1/pch.cpp + ) + +set(HEADER_FILES + Direct3DApp1/BasicTimer.h + Direct3DApp1/CubeRenderer.h + Direct3DApp1/Direct3DApp1.h + Direct3DApp1/Direct3DBase.h + Direct3DApp1/DirectXHelper.h + Direct3DApp1/pch.h + ) + +set(PIXELSHADER_FILES + Direct3DApp1/SimplePixelShader.hlsl + ) + +set(VERTEXSHADER_FILES + Direct3DApp1/SimpleVertexShader.hlsl + ) + +set(CONTENT_FILES ${PIXELSHADER_FILES} ${VERTEXSHADER_FILES}) + +if (WINDOWS_PHONE8) + set(CONTENT_FILES ${CONTENT_FILES} + ${CMAKE_CURRENT_BINARY_DIR}/${APP_MANIFEST_NAME} + Direct3DApp1/Assets/Tiles/FlipCycleTileLarge.png + Direct3DApp1/Assets/Tiles/FlipCycleTileMedium.png + Direct3DApp1/Assets/Tiles/FlipCycleTileSmall.png + Direct3DApp1/Assets/Tiles/IconicTileMediumLarge.png + Direct3DApp1/Assets/Tiles/IconicTileSmall.png + Direct3DApp1/Assets/ApplicationIcon.png + ) + # Windows Phone 8.0 needs to copy all the images. + # It doesn't know to use relative paths. + file(COPY + Direct3DApp1/Assets/Tiles/FlipCycleTileLarge.png + Direct3DApp1/Assets/Tiles/FlipCycleTileMedium.png + Direct3DApp1/Assets/Tiles/FlipCycleTileSmall.png + Direct3DApp1/Assets/Tiles/IconicTileMediumLarge.png + Direct3DApp1/Assets/Tiles/IconicTileSmall.png + Direct3DApp1/Assets/ApplicationIcon.png + DESTINATION ${CMAKE_CURRENT_BINARY_DIR} + ) + +elseif (NOT "${PLATFORM}" STREQUAL "DESKTOP") + set(CONTENT_FILES ${CONTENT_FILES} + ${CMAKE_CURRENT_BINARY_DIR}/${APP_MANIFEST_NAME} + Direct3DApp1/Assets/Logo.png + Direct3DApp1/Assets/SmallLogo.png + Direct3DApp1/Assets/SplashScreen.png + Direct3DApp1/Assets/StoreLogo.png + ) +endif() + +set(RESOURCE_FILES + ${CONTENT_FILES} ${DEBUG_CONTENT_FILES} ${RELEASE_CONTENT_FILES} + Direct3DApp1/Direct3DApp1_TemporaryKey.pfx) + +set_property(SOURCE ${CONTENT_FILES} PROPERTY VS_DEPLOYMENT_CONTENT 1) +set_property(SOURCE ${DEBUG_CONTENT_FILES} PROPERTY VS_DEPLOYMENT_CONTENT $) +set_property(SOURCE ${RELEASE_CONTENT_FILES} PROPERTY + VS_DEPLOYMENT_CONTENT $,$,$>) + +set_property(SOURCE ${PIXELSHADER_FILES} PROPERTY VS_SHADER_TYPE Pixel) +set_property(SOURCE ${VERTEXSHADER_FILES} PROPERTY VS_SHADER_TYPE Vertex) + +source_group("Source Files" FILES ${SOURCE_FILES}) +source_group("Header Files" FILES ${HEADER_FILES}) +source_group("Resource Files" FILES ${RESOURCE_FILES}) + +add_executable(${EXE_NAME} WIN32 ${SOURCE_FILES} ${HEADER_FILES} ${RESOURCE_FILES}) +set_property(TARGET ${EXE_NAME} PROPERTY VS_WINRT_COMPONENT TRUE) +target_link_libraries(${EXE_NAME} d3d11) diff --git a/Tests/VSWinStorePhone/Direct3DApp1/Assets/ApplicationIcon.png b/Tests/VSWinStorePhone/Direct3DApp1/Assets/ApplicationIcon.png new file mode 100644 index 000000000..7d95d4e08 Binary files /dev/null and b/Tests/VSWinStorePhone/Direct3DApp1/Assets/ApplicationIcon.png differ diff --git a/Tests/VSWinStorePhone/Direct3DApp1/Assets/Logo.png b/Tests/VSWinStorePhone/Direct3DApp1/Assets/Logo.png new file mode 100644 index 000000000..e26771cb3 Binary files /dev/null and b/Tests/VSWinStorePhone/Direct3DApp1/Assets/Logo.png differ diff --git a/Tests/VSWinStorePhone/Direct3DApp1/Assets/SmallLogo.png b/Tests/VSWinStorePhone/Direct3DApp1/Assets/SmallLogo.png new file mode 100644 index 000000000..1eb0d9d52 Binary files /dev/null and b/Tests/VSWinStorePhone/Direct3DApp1/Assets/SmallLogo.png differ diff --git a/Tests/VSWinStorePhone/Direct3DApp1/Assets/SplashScreen.png b/Tests/VSWinStorePhone/Direct3DApp1/Assets/SplashScreen.png new file mode 100644 index 000000000..c951e031b Binary files /dev/null and b/Tests/VSWinStorePhone/Direct3DApp1/Assets/SplashScreen.png differ diff --git a/Tests/VSWinStorePhone/Direct3DApp1/Assets/StoreLogo.png b/Tests/VSWinStorePhone/Direct3DApp1/Assets/StoreLogo.png new file mode 100644 index 000000000..dcb672712 Binary files /dev/null and b/Tests/VSWinStorePhone/Direct3DApp1/Assets/StoreLogo.png differ diff --git a/Tests/VSWinStorePhone/Direct3DApp1/Assets/Tiles/FlipCycleTileLarge.png b/Tests/VSWinStorePhone/Direct3DApp1/Assets/Tiles/FlipCycleTileLarge.png new file mode 100644 index 000000000..e0c59ac01 Binary files /dev/null and b/Tests/VSWinStorePhone/Direct3DApp1/Assets/Tiles/FlipCycleTileLarge.png differ diff --git a/Tests/VSWinStorePhone/Direct3DApp1/Assets/Tiles/FlipCycleTileMedium.png b/Tests/VSWinStorePhone/Direct3DApp1/Assets/Tiles/FlipCycleTileMedium.png new file mode 100644 index 000000000..e93b89d60 Binary files /dev/null and b/Tests/VSWinStorePhone/Direct3DApp1/Assets/Tiles/FlipCycleTileMedium.png differ diff --git a/Tests/VSWinStorePhone/Direct3DApp1/Assets/Tiles/FlipCycleTileSmall.png b/Tests/VSWinStorePhone/Direct3DApp1/Assets/Tiles/FlipCycleTileSmall.png new file mode 100644 index 000000000..550b1b5e8 Binary files /dev/null and b/Tests/VSWinStorePhone/Direct3DApp1/Assets/Tiles/FlipCycleTileSmall.png differ diff --git a/Tests/VSWinStorePhone/Direct3DApp1/Assets/Tiles/IconicTileMediumLarge.png b/Tests/VSWinStorePhone/Direct3DApp1/Assets/Tiles/IconicTileMediumLarge.png new file mode 100644 index 000000000..686e6b53f Binary files /dev/null and b/Tests/VSWinStorePhone/Direct3DApp1/Assets/Tiles/IconicTileMediumLarge.png differ diff --git a/Tests/VSWinStorePhone/Direct3DApp1/Assets/Tiles/IconicTileSmall.png b/Tests/VSWinStorePhone/Direct3DApp1/Assets/Tiles/IconicTileSmall.png new file mode 100644 index 000000000..d4b5ede1b Binary files /dev/null and b/Tests/VSWinStorePhone/Direct3DApp1/Assets/Tiles/IconicTileSmall.png differ diff --git a/Tests/VSWinStorePhone/Direct3DApp1/BasicTimer.h b/Tests/VSWinStorePhone/Direct3DApp1/BasicTimer.h new file mode 100644 index 000000000..b58c77d38 --- /dev/null +++ b/Tests/VSWinStorePhone/Direct3DApp1/BasicTimer.h @@ -0,0 +1,76 @@ +#pragma once + +#include + +// Helper class for basic timing. +ref class BasicTimer sealed +{ +public: + // Initializes internal timer values. + BasicTimer() + { + if (!QueryPerformanceFrequency(&m_frequency)) + { + throw ref new Platform::FailureException(); + } + Reset(); + } + + // Reset the timer to initial values. + void Reset() + { + Update(); + m_startTime = m_currentTime; + m_total = 0.0f; + m_delta = 1.0f / 60.0f; + } + + // Update the timer's internal values. + void Update() + { + if (!QueryPerformanceCounter(&m_currentTime)) + { + throw ref new Platform::FailureException(); + } + + m_total = static_cast( + static_cast(m_currentTime.QuadPart - m_startTime.QuadPart) / + static_cast(m_frequency.QuadPart) + ); + + if (m_lastTime.QuadPart == m_startTime.QuadPart) + { + // If the timer was just reset, report a time delta equivalent to 60Hz frame time. + m_delta = 1.0f / 60.0f; + } + else + { + m_delta = static_cast( + static_cast(m_currentTime.QuadPart - m_lastTime.QuadPart) / + static_cast(m_frequency.QuadPart) + ); + } + + m_lastTime = m_currentTime; + } + + // Duration in seconds between the last call to Reset() and the last call to Update(). + property float Total + { + float get() { return m_total; } + } + + // Duration in seconds between the previous two calls to Update(). + property float Delta + { + float get() { return m_delta; } + } + +private: + LARGE_INTEGER m_frequency; + LARGE_INTEGER m_currentTime; + LARGE_INTEGER m_startTime; + LARGE_INTEGER m_lastTime; + float m_total; + float m_delta; +}; diff --git a/Tests/VSWinStorePhone/Direct3DApp1/CubeRenderer.cpp b/Tests/VSWinStorePhone/Direct3DApp1/CubeRenderer.cpp new file mode 100644 index 000000000..f4827f2d6 --- /dev/null +++ b/Tests/VSWinStorePhone/Direct3DApp1/CubeRenderer.cpp @@ -0,0 +1,260 @@ +#include "pch.h" +#include "CubeRenderer.h" + +using namespace DirectX; +using namespace Microsoft::WRL; +using namespace Windows::Foundation; +using namespace Windows::UI::Core; + +CubeRenderer::CubeRenderer() : + m_loadingComplete(false), + m_indexCount(0) +{ +} + +void CubeRenderer::CreateDeviceResources() +{ + Direct3DBase::CreateDeviceResources(); + + auto loadVSTask = DX::ReadDataAsync("SimpleVertexShader.cso"); + auto loadPSTask = DX::ReadDataAsync("SimplePixelShader.cso"); + + auto createVSTask = loadVSTask.then([this](Platform::Array^ fileData) { + DX::ThrowIfFailed( + m_d3dDevice->CreateVertexShader( + fileData->Data, + fileData->Length, + nullptr, + &m_vertexShader + ) + ); + + 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, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }, + }; + + DX::ThrowIfFailed( + m_d3dDevice->CreateInputLayout( + vertexDesc, + ARRAYSIZE(vertexDesc), + fileData->Data, + fileData->Length, + &m_inputLayout + ) + ); + }); + + auto createPSTask = loadPSTask.then([this](Platform::Array^ fileData) { + DX::ThrowIfFailed( + m_d3dDevice->CreatePixelShader( + fileData->Data, + fileData->Length, + nullptr, + &m_pixelShader + ) + ); + + CD3D11_BUFFER_DESC constantBufferDesc(sizeof(ModelViewProjectionConstantBuffer), D3D11_BIND_CONSTANT_BUFFER); + DX::ThrowIfFailed( + m_d3dDevice->CreateBuffer( + &constantBufferDesc, + nullptr, + &m_constantBuffer + ) + ); + }); + + auto createCubeTask = (createPSTask && createVSTask).then([this] () { + VertexPositionColor cubeVertices[] = + { + {XMFLOAT3(-0.5f, -0.5f, -0.5f), XMFLOAT3(0.0f, 0.0f, 0.0f)}, + {XMFLOAT3(-0.5f, -0.5f, 0.5f), XMFLOAT3(0.0f, 0.0f, 1.0f)}, + {XMFLOAT3(-0.5f, 0.5f, -0.5f), XMFLOAT3(0.0f, 1.0f, 0.0f)}, + {XMFLOAT3(-0.5f, 0.5f, 0.5f), XMFLOAT3(0.0f, 1.0f, 1.0f)}, + {XMFLOAT3( 0.5f, -0.5f, -0.5f), XMFLOAT3(1.0f, 0.0f, 0.0f)}, + {XMFLOAT3( 0.5f, -0.5f, 0.5f), XMFLOAT3(1.0f, 0.0f, 1.0f)}, + {XMFLOAT3( 0.5f, 0.5f, -0.5f), XMFLOAT3(1.0f, 1.0f, 0.0f)}, + {XMFLOAT3( 0.5f, 0.5f, 0.5f), XMFLOAT3(1.0f, 1.0f, 1.0f)}, + }; + + D3D11_SUBRESOURCE_DATA vertexBufferData = {0}; + vertexBufferData.pSysMem = cubeVertices; + vertexBufferData.SysMemPitch = 0; + vertexBufferData.SysMemSlicePitch = 0; + CD3D11_BUFFER_DESC vertexBufferDesc(sizeof(cubeVertices), D3D11_BIND_VERTEX_BUFFER); + DX::ThrowIfFailed( + m_d3dDevice->CreateBuffer( + &vertexBufferDesc, + &vertexBufferData, + &m_vertexBuffer + ) + ); + + unsigned short cubeIndices[] = + { + 0,2,1, // -x + 1,2,3, + + 4,5,6, // +x + 5,7,6, + + 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; + CD3D11_BUFFER_DESC indexBufferDesc(sizeof(cubeIndices), D3D11_BIND_INDEX_BUFFER); + DX::ThrowIfFailed( + m_d3dDevice->CreateBuffer( + &indexBufferDesc, + &indexBufferData, + &m_indexBuffer + ) + ); + }); + + createCubeTask.then([this] () { + m_loadingComplete = true; + }); +} + +void CubeRenderer::CreateWindowSizeDependentResources() +{ + Direct3DBase::CreateWindowSizeDependentResources(); + + float aspectRatio = m_windowBounds.Width / m_windowBounds.Height; + float fovAngleY = 70.0f * XM_PI / 180.0f; + if (aspectRatio < 1.0f) + { + fovAngleY /= aspectRatio; + } + + // Note that the m_orientationTransform3D matrix is post-multiplied here + // in order to correctly orient the scene to match the display orientation. + // This post-multiplication step is required for any draw calls that are + // made to the swap chain render target. For draw calls to other targets, + // this transform should not be applied. + XMStoreFloat4x4( + &m_constantBufferData.projection, + XMMatrixTranspose( + XMMatrixMultiply( + XMMatrixPerspectiveFovRH( + fovAngleY, + aspectRatio, + 0.01f, + 100.0f + ), + XMLoadFloat4x4(&m_orientationTransform3D) + ) + ) + ); +} + +void CubeRenderer::Update(float timeTotal, float timeDelta) +{ + (void) timeDelta; // Unused parameter. + + XMVECTOR eye = XMVectorSet(0.0f, 0.7f, 1.5f, 0.0f); + XMVECTOR at = XMVectorSet(0.0f, -0.1f, 0.0f, 0.0f); + XMVECTOR up = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f); + + XMStoreFloat4x4(&m_constantBufferData.view, XMMatrixTranspose(XMMatrixLookAtRH(eye, at, up))); + XMStoreFloat4x4(&m_constantBufferData.model, XMMatrixTranspose(XMMatrixRotationY(timeTotal * XM_PIDIV4))); +} + +void CubeRenderer::Render() +{ + const float midnightBlue[] = { 0.098f, 0.098f, 0.439f, 1.000f }; + m_d3dContext->ClearRenderTargetView( + m_renderTargetView.Get(), + midnightBlue + ); + + m_d3dContext->ClearDepthStencilView( + m_depthStencilView.Get(), + D3D11_CLEAR_DEPTH, + 1.0f, + 0 + ); + + // Only draw the cube once it is loaded (loading is asynchronous). + if (!m_loadingComplete) + { + return; + } + + m_d3dContext->OMSetRenderTargets( + 1, + m_renderTargetView.GetAddressOf(), + m_depthStencilView.Get() + ); + + m_d3dContext->UpdateSubresource( + m_constantBuffer.Get(), + 0, + NULL, + &m_constantBufferData, + 0, + 0 + ); + + UINT stride = sizeof(VertexPositionColor); + UINT offset = 0; + m_d3dContext->IASetVertexBuffers( + 0, + 1, + m_vertexBuffer.GetAddressOf(), + &stride, + &offset + ); + + m_d3dContext->IASetIndexBuffer( + m_indexBuffer.Get(), + DXGI_FORMAT_R16_UINT, + 0 + ); + + m_d3dContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + + m_d3dContext->IASetInputLayout(m_inputLayout.Get()); + + m_d3dContext->VSSetShader( + m_vertexShader.Get(), + nullptr, + 0 + ); + + m_d3dContext->VSSetConstantBuffers( + 0, + 1, + m_constantBuffer.GetAddressOf() + ); + + m_d3dContext->PSSetShader( + m_pixelShader.Get(), + nullptr, + 0 + ); + + m_d3dContext->DrawIndexed( + m_indexCount, + 0, + 0 + ); +} diff --git a/Tests/VSWinStorePhone/Direct3DApp1/CubeRenderer.h b/Tests/VSWinStorePhone/Direct3DApp1/CubeRenderer.h new file mode 100644 index 000000000..68cb188d1 --- /dev/null +++ b/Tests/VSWinStorePhone/Direct3DApp1/CubeRenderer.h @@ -0,0 +1,44 @@ +#pragma once + +#include "Direct3DBase.h" + +struct ModelViewProjectionConstantBuffer +{ + DirectX::XMFLOAT4X4 model; + DirectX::XMFLOAT4X4 view; + DirectX::XMFLOAT4X4 projection; +}; + +struct VertexPositionColor +{ + DirectX::XMFLOAT3 pos; + DirectX::XMFLOAT3 color; +}; + +// This class renders a simple spinning cube. +ref class CubeRenderer sealed : public Direct3DBase +{ +public: + CubeRenderer(); + + // Direct3DBase methods. + virtual void CreateDeviceResources() override; + virtual void CreateWindowSizeDependentResources() override; + virtual void Render() override; + + // Method for updating time-dependent objects. + void Update(float timeTotal, float timeDelta); + +private: + bool m_loadingComplete; + + Microsoft::WRL::ComPtr m_inputLayout; + Microsoft::WRL::ComPtr m_vertexBuffer; + Microsoft::WRL::ComPtr m_indexBuffer; + Microsoft::WRL::ComPtr m_vertexShader; + Microsoft::WRL::ComPtr m_pixelShader; + Microsoft::WRL::ComPtr m_constantBuffer; + + uint32 m_indexCount; + ModelViewProjectionConstantBuffer m_constantBufferData; +}; diff --git a/Tests/VSWinStorePhone/Direct3DApp1/Direct3DApp1.cpp b/Tests/VSWinStorePhone/Direct3DApp1/Direct3DApp1.cpp new file mode 100644 index 000000000..3dbb97f10 --- /dev/null +++ b/Tests/VSWinStorePhone/Direct3DApp1/Direct3DApp1.cpp @@ -0,0 +1,153 @@ +#include "pch.h" +#include "Direct3DApp1.h" +#include "BasicTimer.h" + +using namespace Windows::ApplicationModel; +using namespace Windows::ApplicationModel::Core; +using namespace Windows::ApplicationModel::Activation; +using namespace Windows::UI::Core; +using namespace Windows::System; +using namespace Windows::Foundation; +using namespace Windows::Graphics::Display; +using namespace concurrency; + +Direct3DApp1::Direct3DApp1() : + m_windowClosed(false), + m_windowVisible(true) +{ +} + +void Direct3DApp1::Initialize(CoreApplicationView^ applicationView) +{ + applicationView->Activated += + ref new TypedEventHandler(this, &Direct3DApp1::OnActivated); + + CoreApplication::Suspending += + ref new EventHandler(this, &Direct3DApp1::OnSuspending); + + CoreApplication::Resuming += + ref new EventHandler(this, &Direct3DApp1::OnResuming); + + m_renderer = ref new CubeRenderer(); +} + +void Direct3DApp1::SetWindow(CoreWindow^ window) +{ + window->SizeChanged += + ref new TypedEventHandler(this, &Direct3DApp1::OnWindowSizeChanged); + + window->VisibilityChanged += + ref new TypedEventHandler(this, &Direct3DApp1::OnVisibilityChanged); + + window->Closed += + ref new TypedEventHandler(this, &Direct3DApp1::OnWindowClosed); + +#ifndef PHONE + window->PointerCursor = ref new CoreCursor(CoreCursorType::Arrow, 0); +#endif + + window->PointerPressed += + ref new TypedEventHandler(this, &Direct3DApp1::OnPointerPressed); + + window->PointerMoved += + ref new TypedEventHandler(this, &Direct3DApp1::OnPointerMoved); + + m_renderer->Initialize(CoreWindow::GetForCurrentThread()); +} + +void Direct3DApp1::Load(Platform::String^ entryPoint) +{ +} + +void Direct3DApp1::Run() +{ + BasicTimer^ timer = ref new BasicTimer(); + + while (!m_windowClosed) + { + if (m_windowVisible) + { + timer->Update(); + CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessAllIfPresent); + m_renderer->Update(timer->Total, timer->Delta); + m_renderer->Render(); + m_renderer->Present(); // This call is synchronized to the display frame rate. + } + else + { + CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessOneAndAllPending); + } + } +} + +void Direct3DApp1::Uninitialize() +{ +} + +void Direct3DApp1::OnWindowSizeChanged(CoreWindow^ sender, WindowSizeChangedEventArgs^ args) +{ + m_renderer->UpdateForWindowSizeChange(); +} + +void Direct3DApp1::OnVisibilityChanged(CoreWindow^ sender, VisibilityChangedEventArgs^ args) +{ + m_windowVisible = args->Visible; +} + +void Direct3DApp1::OnWindowClosed(CoreWindow^ sender, CoreWindowEventArgs^ args) +{ + m_windowClosed = true; +} + +void Direct3DApp1::OnPointerPressed(CoreWindow^ sender, PointerEventArgs^ args) +{ + // Insert your code here. +} + +void Direct3DApp1::OnPointerMoved(CoreWindow^ sender, PointerEventArgs^ args) +{ + // Insert your code here. +} + +void Direct3DApp1::OnActivated(CoreApplicationView^ applicationView, IActivatedEventArgs^ args) +{ + CoreWindow::GetForCurrentThread()->Activate(); +} + +void Direct3DApp1::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(); + m_renderer->ReleaseResourcesForSuspending(); + + create_task([this, deferral]() + { + // Insert your code here. + + deferral->Complete(); + }); +} + +void Direct3DApp1::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. + m_renderer->CreateWindowSizeDependentResources(); +} + +IFrameworkView^ Direct3DApplicationSource::CreateView() +{ + return ref new Direct3DApp1(); +} + +[Platform::MTAThread] +int main(Platform::Array^) +{ + auto direct3DApplicationSource = ref new Direct3DApplicationSource(); + CoreApplication::Run(direct3DApplicationSource); + return 0; +} diff --git a/Tests/VSWinStorePhone/Direct3DApp1/Direct3DApp1.h b/Tests/VSWinStorePhone/Direct3DApp1/Direct3DApp1.h new file mode 100644 index 000000000..40b69a173 --- /dev/null +++ b/Tests/VSWinStorePhone/Direct3DApp1/Direct3DApp1.h @@ -0,0 +1,40 @@ +#pragma once + +#include "pch.h" +#include "CubeRenderer.h" + +ref class Direct3DApp1 sealed : public Windows::ApplicationModel::Core::IFrameworkView +{ +public: + Direct3DApp1(); + + // 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: + // Event Handlers. + void OnWindowSizeChanged(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::WindowSizeChangedEventArgs^ args); + void OnLogicalDpiChanged(Platform::Object^ sender); + void OnActivated(Windows::ApplicationModel::Core::CoreApplicationView^ applicationView, Windows::ApplicationModel::Activation::IActivatedEventArgs^ args); + void OnSuspending(Platform::Object^ sender, Windows::ApplicationModel::SuspendingEventArgs^ args); + void OnResuming(Platform::Object^ sender, Platform::Object^ args); + void OnWindowClosed(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::CoreWindowEventArgs^ args); + void OnVisibilityChanged(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::VisibilityChangedEventArgs^ args); + void OnPointerPressed(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::PointerEventArgs^ args); + void OnPointerMoved(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::PointerEventArgs^ args); + +private: + CubeRenderer^ m_renderer; + bool m_windowClosed; + bool m_windowVisible; +}; + +ref class Direct3DApplicationSource sealed : Windows::ApplicationModel::Core::IFrameworkViewSource +{ +public: + virtual Windows::ApplicationModel::Core::IFrameworkView^ CreateView(); +}; diff --git a/Tests/VSWinStorePhone/Direct3DApp1/Direct3DApp1_TemporaryKey.pfx b/Tests/VSWinStorePhone/Direct3DApp1/Direct3DApp1_TemporaryKey.pfx new file mode 100644 index 000000000..1cad9993d Binary files /dev/null and b/Tests/VSWinStorePhone/Direct3DApp1/Direct3DApp1_TemporaryKey.pfx differ diff --git a/Tests/VSWinStorePhone/Direct3DApp1/Direct3DBase.cpp b/Tests/VSWinStorePhone/Direct3DApp1/Direct3DBase.cpp new file mode 100644 index 000000000..46727b5ff --- /dev/null +++ b/Tests/VSWinStorePhone/Direct3DApp1/Direct3DBase.cpp @@ -0,0 +1,384 @@ +#include "pch.h" +#include "Direct3DBase.h" + +using namespace DirectX; +using namespace Microsoft::WRL; +using namespace Windows::UI::Core; +using namespace Windows::Foundation; +using namespace Windows::Graphics::Display; + +// Constructor. +Direct3DBase::Direct3DBase() +{ +} + +// Initialize the Direct3D resources required to run. +void Direct3DBase::Initialize(CoreWindow^ window) +{ + m_window = window; + + CreateDeviceResources(); + CreateWindowSizeDependentResources(); +} + +// Recreate all device resources and set them back to the current state. +void Direct3DBase::HandleDeviceLost() +{ + // Reset these member variables to ensure that UpdateForWindowSizeChange recreates all resources. + m_windowBounds.Width = 0; + m_windowBounds.Height = 0; + m_swapChain = nullptr; + + CreateDeviceResources(); + UpdateForWindowSizeChange(); +} + +// These are the resources that depend on the device. +void Direct3DBase::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 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. + // Don't forget to declare your application's minimum required feature level in its + // description. All applications are assumed to support 9.1 unless otherwise stated. + D3D_FEATURE_LEVEL featureLevels[] = + { + D3D_FEATURE_LEVEL_11_1, + D3D_FEATURE_LEVEL_11_0, + D3D_FEATURE_LEVEL_10_1, + D3D_FEATURE_LEVEL_10_0, + D3D_FEATURE_LEVEL_9_3, + D3D_FEATURE_LEVEL_9_2, + D3D_FEATURE_LEVEL_9_1 + }; + + // Create the Direct3D 11 API device object and a corresponding context. + ComPtr device; + ComPtr context; + DX::ThrowIfFailed( + D3D11CreateDevice( + nullptr, // Specify nullptr to use the default adapter. + D3D_DRIVER_TYPE_HARDWARE, + nullptr, + creationFlags, // Set set debug and Direct2D compatibility flags. + featureLevels, // List of feature levels this app can support. + ARRAYSIZE(featureLevels), + D3D11_SDK_VERSION, // Always set this to D3D11_SDK_VERSION for Windows Store apps. + &device, // Returns the Direct3D device created. + &m_featureLevel, // Returns feature level of device created. + &context // Returns the device immediate context. + ) + ); + + // Get the Direct3D 11.1 API device and context interfaces. + DX::ThrowIfFailed( + device.As(&m_d3dDevice) + ); + + DX::ThrowIfFailed( + context.As(&m_d3dContext) + ); +} + +// Allocate all memory resources that change on a window SizeChanged event. +void Direct3DBase::CreateWindowSizeDependentResources() +{ + // Store the window bounds so the next time we get a SizeChanged event we can + // avoid rebuilding everything if the size is identical. + m_windowBounds = m_window->Bounds; + + // Calculate the necessary swap chain and render target size in pixels. + float windowWidth = ConvertDipsToPixels(m_windowBounds.Width); + float windowHeight = ConvertDipsToPixels(m_windowBounds.Height); + + // The width and height of the swap chain must be based on the window's + // landscape-oriented width and height. If the window is in a portrait + // orientation, the dimensions must be reversed. +#if WINVER > 0x0602 + m_orientation = DisplayInformation::GetForCurrentView()->CurrentOrientation; +#else +#if PHONE + // WP8 doesn't support rotations so always make it landscape + m_orientation = DisplayOrientations::Landscape; +#else + m_orientation = DisplayProperties::CurrentOrientation; +#endif +#endif + bool swapDimensions = + m_orientation == DisplayOrientations::Portrait || + m_orientation == DisplayOrientations::PortraitFlipped; + m_renderTargetSize.Width = swapDimensions ? windowHeight : windowWidth; + m_renderTargetSize.Height = swapDimensions ? windowWidth : windowHeight; + + if(m_swapChain != nullptr) + { + // If the swap chain already exists, resize it. + DX::ThrowIfFailed( + m_swapChain->ResizeBuffers( + 2, // Double-buffered swap chain. + static_cast(m_renderTargetSize.Width), + static_cast(m_renderTargetSize.Height), + DXGI_FORMAT_B8G8R8A8_UNORM, + 0 + ) + ); + } + else + { + // Otherwise, create a new one using the same adapter as the existing Direct3D device. + DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {0}; + swapChainDesc.Width = static_cast(m_renderTargetSize.Width); // Match the size of the window. + swapChainDesc.Height = static_cast(m_renderTargetSize.Height); + swapChainDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; // This is the most common swap chain format. + swapChainDesc.Stereo = false; + swapChainDesc.SampleDesc.Count = 1; // Don't use multi-sampling. + swapChainDesc.SampleDesc.Quality = 0; + swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; +#if PHONE && WINVER <= 0x0602 + swapChainDesc.BufferCount = 1; // Use double-buffering to minimize latency. + swapChainDesc.Scaling = DXGI_SCALING_STRETCH; // On phone, only stretch and aspect-ratio stretch scaling are allowed. + swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; // On phone, no swap effects are supported. +#else + swapChainDesc.BufferCount = 2; // Use double-buffering to minimize latency. + swapChainDesc.Scaling = DXGI_SCALING_NONE; + swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; // All Windows Store apps must use this SwapEffect. +#endif + swapChainDesc.Flags = 0; + + ComPtr dxgiDevice; + DX::ThrowIfFailed( + m_d3dDevice.As(&dxgiDevice) + ); + + ComPtr dxgiAdapter; + DX::ThrowIfFailed( + dxgiDevice->GetAdapter(&dxgiAdapter) + ); + + ComPtr dxgiFactory; + DX::ThrowIfFailed( + dxgiAdapter->GetParent( + __uuidof(IDXGIFactory2), + &dxgiFactory + ) + ); + + Windows::UI::Core::CoreWindow^ window = m_window.Get(); + DX::ThrowIfFailed( + dxgiFactory->CreateSwapChainForCoreWindow( + m_d3dDevice.Get(), + reinterpret_cast(window), + &swapChainDesc, + nullptr, // Allow on all displays. + &m_swapChain + ) + ); + + // Ensure that DXGI does not queue more than one frame at a time. This both reduces latency and + // ensures that the application will only render after each VSync, minimizing power consumption. + DX::ThrowIfFailed( + dxgiDevice->SetMaximumFrameLatency(1) + ); + } + + // Set the proper orientation for the swap chain, and generate the + // 3D matrix transformation for rendering to the rotated swap chain. + DXGI_MODE_ROTATION rotation = DXGI_MODE_ROTATION_UNSPECIFIED; + switch (m_orientation) + { + case DisplayOrientations::Landscape: + rotation = DXGI_MODE_ROTATION_IDENTITY; + m_orientationTransform3D = XMFLOAT4X4( // 0-degree Z-rotation + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f + ); + break; + + case DisplayOrientations::Portrait: + rotation = DXGI_MODE_ROTATION_ROTATE270; + m_orientationTransform3D = XMFLOAT4X4( // 90-degree Z-rotation + 0.0f, 1.0f, 0.0f, 0.0f, + -1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f + ); + break; + + case DisplayOrientations::LandscapeFlipped: + rotation = DXGI_MODE_ROTATION_ROTATE180; + m_orientationTransform3D = XMFLOAT4X4( // 180-degree Z-rotation + -1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, -1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f + ); + break; + + case DisplayOrientations::PortraitFlipped: + rotation = DXGI_MODE_ROTATION_ROTATE90; + m_orientationTransform3D = XMFLOAT4X4( // 270-degree Z-rotation + 0.0f, -1.0f, 0.0f, 0.0f, + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f + ); + break; + + default: + throw ref new Platform::FailureException(); + } + +#if !PHONE || WINVER > 0x0602 + DX::ThrowIfFailed( + m_swapChain->SetRotation(rotation) + ); +#endif // !PHONE + + // Create a render target view of the swap chain back buffer. + ComPtr backBuffer; + DX::ThrowIfFailed( + m_swapChain->GetBuffer( + 0, + __uuidof(ID3D11Texture2D), + &backBuffer + ) + ); + + DX::ThrowIfFailed( + m_d3dDevice->CreateRenderTargetView( + backBuffer.Get(), + nullptr, + &m_renderTargetView + ) + ); + + // Create a depth stencil view. + CD3D11_TEXTURE2D_DESC depthStencilDesc( + DXGI_FORMAT_D24_UNORM_S8_UINT, + static_cast(m_renderTargetSize.Width), + static_cast(m_renderTargetSize.Height), + 1, + 1, + D3D11_BIND_DEPTH_STENCIL + ); + + ComPtr depthStencil; + DX::ThrowIfFailed( + m_d3dDevice->CreateTexture2D( + &depthStencilDesc, + nullptr, + &depthStencil + ) + ); + + CD3D11_DEPTH_STENCIL_VIEW_DESC depthStencilViewDesc(D3D11_DSV_DIMENSION_TEXTURE2D); + DX::ThrowIfFailed( + m_d3dDevice->CreateDepthStencilView( + depthStencil.Get(), + &depthStencilViewDesc, + &m_depthStencilView + ) + ); + + // Set the rendering viewport to target the entire window. + CD3D11_VIEWPORT viewport( + 0.0f, + 0.0f, + m_renderTargetSize.Width, + m_renderTargetSize.Height + ); + + m_d3dContext->RSSetViewports(1, &viewport); +} + +// This method is called in the event handler for the SizeChanged event. +void Direct3DBase::UpdateForWindowSizeChange() +{ + if (m_window->Bounds.Width != m_windowBounds.Width || + m_window->Bounds.Height != m_windowBounds.Height || +#if WINVER > 0x0602 + m_orientation != DisplayInformation::GetForCurrentView()->CurrentOrientation) +#else + m_orientation != DisplayProperties::CurrentOrientation) +#endif + { + ID3D11RenderTargetView* nullViews[] = {nullptr}; + m_d3dContext->OMSetRenderTargets(ARRAYSIZE(nullViews), nullViews, nullptr); + m_renderTargetView = nullptr; + m_depthStencilView = nullptr; + m_d3dContext->Flush(); + CreateWindowSizeDependentResources(); + } +} + +void Direct3DBase::ReleaseResourcesForSuspending() +{ + // Phone applications operate in a memory-constrained environment, so when entering + // the background it is a good idea to free memory-intensive objects that will be + // easy to restore upon reactivation. The swapchain and backbuffer are good candidates + // here, as they consume a large amount of memory and can be reinitialized quickly. + m_swapChain = nullptr; + m_renderTargetView = nullptr; + m_depthStencilView = nullptr; +} + +// Method to deliver the final image to the display. +void Direct3DBase::Present() +{ + // The first argument instructs DXGI to block until VSync, putting the application + // to sleep until the next VSync. This ensures we don't waste any cycles rendering + // frames that will never be displayed to the screen. +#if PHONE && WINVER <= 0x0602 + HRESULT hr = m_swapChain->Present(1, 0); +#else + // The application may optionally specify "dirty" or "scroll" + // rects to improve efficiency in certain scenarios. + DXGI_PRESENT_PARAMETERS parameters = { 0 }; + parameters.DirtyRectsCount = 0; + parameters.pDirtyRects = nullptr; + parameters.pScrollRect = nullptr; + parameters.pScrollOffset = nullptr; + + HRESULT hr = m_swapChain->Present1(1, 0 , ¶meters); +#endif + + // 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(m_renderTargetView.Get()); + + // Discard the contents of the depth stencil. + m_d3dContext->DiscardView(m_depthStencilView.Get()); + + // If the device was removed either by a disconnect or a driver upgrade, we + // must recreate all device resources. + if (hr == DXGI_ERROR_DEVICE_REMOVED) + { + HandleDeviceLost(); + } + else + { + DX::ThrowIfFailed(hr); + } +} + +// Method to convert a length in device-independent pixels (DIPs) to a length in physical pixels. +float Direct3DBase::ConvertDipsToPixels(float dips) +{ + static const float dipsPerInch = 96.0f; +#if WINVER > 0x0602 + return floor(dips * DisplayInformation::GetForCurrentView()->LogicalDpi / dipsPerInch + 0.5f); // Round to nearest integer. +#else + return floor(dips * DisplayProperties::LogicalDpi / dipsPerInch + 0.5f); // Round to nearest integer. +#endif +} diff --git a/Tests/VSWinStorePhone/Direct3DApp1/Direct3DBase.h b/Tests/VSWinStorePhone/Direct3DApp1/Direct3DBase.h new file mode 100644 index 000000000..bba9f1697 --- /dev/null +++ b/Tests/VSWinStorePhone/Direct3DApp1/Direct3DBase.h @@ -0,0 +1,39 @@ +#pragma once + +#include "DirectXHelper.h" + +// Helper class that initializes DirectX APIs for 3D rendering. +ref class Direct3DBase abstract +{ +internal: + Direct3DBase(); + +public: + virtual void Initialize(Windows::UI::Core::CoreWindow^ window); + virtual void HandleDeviceLost(); + virtual void CreateDeviceResources(); + virtual void CreateWindowSizeDependentResources(); + virtual void UpdateForWindowSizeChange(); + virtual void ReleaseResourcesForSuspending(); + virtual void Render() = 0; + virtual void Present(); + virtual float ConvertDipsToPixels(float dips); + +protected private: + // Direct3D Objects. + Microsoft::WRL::ComPtr m_d3dDevice; + Microsoft::WRL::ComPtr m_d3dContext; + Microsoft::WRL::ComPtr m_swapChain; + Microsoft::WRL::ComPtr m_renderTargetView; + Microsoft::WRL::ComPtr m_depthStencilView; + + // Cached renderer properties. + D3D_FEATURE_LEVEL m_featureLevel; + Windows::Foundation::Size m_renderTargetSize; + Windows::Foundation::Rect m_windowBounds; + Platform::Agile m_window; + Windows::Graphics::Display::DisplayOrientations m_orientation; + + // Transform used for display orientation. + DirectX::XMFLOAT4X4 m_orientationTransform3D; +}; diff --git a/Tests/VSWinStorePhone/Direct3DApp1/DirectXHelper.h b/Tests/VSWinStorePhone/Direct3DApp1/DirectXHelper.h new file mode 100644 index 000000000..d411a9b81 --- /dev/null +++ b/Tests/VSWinStorePhone/Direct3DApp1/DirectXHelper.h @@ -0,0 +1,45 @@ +#pragma once + +#include +#include +#include + +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(Platform::String^ filename) + { + using namespace Windows::Storage; + using namespace Concurrency; + + auto folder = Windows::ApplicationModel::Package::Current->InstalledLocation; + + return create_task(folder->GetFileAsync(filename)).then([] (StorageFile^ file) + { +#if !PHONE + return FileIO::ReadBufferAsync(file); +#else + return file->OpenReadAsync(); + }).then([](Streams::IRandomAccessStreamWithContentType^ stream) + { + unsigned int bufferSize = static_cast(stream->Size); + auto fileBuffer = ref new Streams::Buffer(bufferSize); + return stream->ReadAsync(fileBuffer, bufferSize, Streams::InputStreamOptions::None); +#endif + }).then([] (Streams::IBuffer^ fileBuffer) -> Platform::Array^ + { + auto fileData = ref new Platform::Array(fileBuffer->Length); + Streams::DataReader::FromBuffer(fileBuffer)->ReadBytes(fileData); + return fileData; + }); + } +} diff --git a/Tests/VSWinStorePhone/Direct3DApp1/SimplePixelShader.cso b/Tests/VSWinStorePhone/Direct3DApp1/SimplePixelShader.cso new file mode 100644 index 000000000..56f9c1756 Binary files /dev/null and b/Tests/VSWinStorePhone/Direct3DApp1/SimplePixelShader.cso differ diff --git a/Tests/VSWinStorePhone/Direct3DApp1/SimplePixelShader.hlsl b/Tests/VSWinStorePhone/Direct3DApp1/SimplePixelShader.hlsl new file mode 100644 index 000000000..d61e2c8f5 --- /dev/null +++ b/Tests/VSWinStorePhone/Direct3DApp1/SimplePixelShader.hlsl @@ -0,0 +1,10 @@ +struct PixelShaderInput +{ + float4 pos : SV_POSITION; + float3 color : COLOR0; +}; + +float4 main(PixelShaderInput input) : SV_TARGET +{ + return float4(input.color,1.0f); +} diff --git a/Tests/VSWinStorePhone/Direct3DApp1/SimpleVertexShader.cso b/Tests/VSWinStorePhone/Direct3DApp1/SimpleVertexShader.cso new file mode 100644 index 000000000..ea8025821 Binary files /dev/null and b/Tests/VSWinStorePhone/Direct3DApp1/SimpleVertexShader.cso differ diff --git a/Tests/VSWinStorePhone/Direct3DApp1/SimpleVertexShader.hlsl b/Tests/VSWinStorePhone/Direct3DApp1/SimpleVertexShader.hlsl new file mode 100644 index 000000000..65d60e5bd --- /dev/null +++ b/Tests/VSWinStorePhone/Direct3DApp1/SimpleVertexShader.hlsl @@ -0,0 +1,35 @@ +cbuffer ModelViewProjectionConstantBuffer : register(b0) +{ + matrix model; + matrix view; + matrix projection; +}; + +struct VertexShaderInput +{ + float3 pos : POSITION; + float3 color : COLOR0; +}; + +struct VertexShaderOutput +{ + float4 pos : SV_POSITION; + float3 color : COLOR0; +}; + +VertexShaderOutput main(VertexShaderInput input) +{ + VertexShaderOutput output; + float4 pos = float4(input.pos, 1.0f); + + // Transform the vertex position into projected space. + pos = mul(pos, model); + pos = mul(pos, view); + pos = mul(pos, projection); + output.pos = pos; + + // Pass through the color without modification. + output.color = input.color; + + return output; +} diff --git a/Tests/VSWinStorePhone/Direct3DApp1/pch.cpp b/Tests/VSWinStorePhone/Direct3DApp1/pch.cpp new file mode 100644 index 000000000..1d9f38c57 --- /dev/null +++ b/Tests/VSWinStorePhone/Direct3DApp1/pch.cpp @@ -0,0 +1 @@ +#include "pch.h" diff --git a/Tests/VSWinStorePhone/Direct3DApp1/pch.h b/Tests/VSWinStorePhone/Direct3DApp1/pch.h new file mode 100644 index 000000000..2302e66ba --- /dev/null +++ b/Tests/VSWinStorePhone/Direct3DApp1/pch.h @@ -0,0 +1,7 @@ +#pragma once + +#include +#include +#include +#include +#include diff --git a/Tests/VSWinStorePhone/cmake/Package_vc11.store.appxmanifest.in b/Tests/VSWinStorePhone/cmake/Package_vc11.store.appxmanifest.in new file mode 100644 index 000000000..d3cb21fb0 --- /dev/null +++ b/Tests/VSWinStorePhone/cmake/Package_vc11.store.appxmanifest.in @@ -0,0 +1,24 @@ + + + + + @SHORT_NAME@ + mgong + StoreLogo.png + + + 6.2.1 + 6.2.1 + + + + + + + + + + + + + diff --git a/Tests/VSWinStorePhone/cmake/Package_vc11.wp.appxmanifest.in b/Tests/VSWinStorePhone/cmake/Package_vc11.wp.appxmanifest.in new file mode 100644 index 000000000..70f3abf79 --- /dev/null +++ b/Tests/VSWinStorePhone/cmake/Package_vc11.wp.appxmanifest.in @@ -0,0 +1,35 @@ + + + + + ApplicationIcon.png + + + + + + + + + + + + FlipCycleTileSmall.png + 0 + FlipCycleTileMedium.png + @SHORT_NAME@ + + + + + + + + + + + + + + + diff --git a/Tests/VSWinStorePhone/cmake/Package_vc12.store.appxmanifest.in b/Tests/VSWinStorePhone/cmake/Package_vc12.store.appxmanifest.in new file mode 100644 index 000000000..495f18ed5 --- /dev/null +++ b/Tests/VSWinStorePhone/cmake/Package_vc12.store.appxmanifest.in @@ -0,0 +1,34 @@ + + + + + @SHORT_NAME@ + mgong + StoreLogo.png + + + 6.3 + 6.3 + + + + + + + + + + + + + + + + + diff --git a/Tests/VSWinStorePhone/cmake/Package_vc12.wp.appxmanifest.in b/Tests/VSWinStorePhone/cmake/Package_vc12.wp.appxmanifest.in new file mode 100644 index 000000000..2d4d389c4 --- /dev/null +++ b/Tests/VSWinStorePhone/cmake/Package_vc12.wp.appxmanifest.in @@ -0,0 +1,36 @@ + + + + + + + @SHORT_NAME@ + mgong + StoreLogo.png + + + 6.3.1 + 6.3.1 + + + + + + + + + + + + + + + + +