This commit is contained in:
unknown 2018-05-17 20:10:47 +01:00
Родитель 71f56c331c
Коммит 0890d2a9b5
224 изменённых файлов: 12235 добавлений и 61 удалений

60
.gitignore поставляемый
Просмотреть файл

@ -8,6 +8,7 @@
*.user
*.userosscache
*.sln.docstates
*.diagsession
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
@ -23,15 +24,13 @@ bld/
[Bb]in/
[Oo]bj/
[Ll]og/
[Gg]enerated*Files/
# Visual Studio 2015/2017 cache/options directory
# Visual Studio 2015 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# Visual Studio 2017 auto generated files
Generated\ Files/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
@ -45,29 +44,20 @@ TestResult.xml
[Rr]eleasePS/
dlldata.c
# Benchmark Results
BenchmarkDotNet.Artifacts/
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
**/Properties/launchSettings.json
# StyleCop
StyleCopReport.xml
# Files built by Visual Studio
*_i.c
*_p.c
*_i.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
@ -105,9 +95,6 @@ ipch/
*.vspx
*.sap
# Visual Studio Trace Files
*.e2e
# TFS 2012 Local Workspace
$tf/
@ -128,10 +115,6 @@ _TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json
# Visual Studio code coverage results
*.coverage
*.coveragexml
@ -167,7 +150,7 @@ publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# TODO: Comment the next line if you want to checkin your web deploy settings
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
@ -180,11 +163,11 @@ PublishScripts/
# NuGet Packages
*.nupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
**/packages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
!**/packages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
#!**/packages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
@ -202,7 +185,6 @@ AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
# Visual Studio cache files
# files ending in .cache can be ignored
@ -221,10 +203,6 @@ ClientBin/
*.publishsettings
orleans.codegen.cs
# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
@ -239,8 +217,6 @@ _UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak
# SQL Server files
*.mdf
@ -251,7 +227,6 @@ ServiceFabricBackup/
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
# Microsoft Fakes
FakesAssemblies/
@ -263,6 +238,9 @@ FakesAssemblies/
.ntvs_analysis.dat
node_modules/
# Typescript v1 declaration files
typings/
# Visual Studio 6 build log
*.plg
@ -302,9 +280,6 @@ __pycache__/
# tools/**
# !tools/packages.config
# Tabs Studio
*.tss
# Telerik's JustMock configuration file
*.jmconfig
@ -313,18 +288,3 @@ __pycache__/
*.btm.cs
*.odx.cs
*.xsd.cs
# OpenCover UI analysis results
OpenCover/
# Azure Stream Analytics local run output
ASALocalRun/
# MSBuild Binary and Structured Log
*.binlog
# NVidia Nsight GPU debugger configuration file
*.nvuser
# MFractors (Xamarin productivity tool) working folder
.mfractor/

Просмотреть файл

@ -0,0 +1,33 @@
#pragma once
#include "pch.h"
#include "IntegerToIndentationConverter.h"
using namespace Platform;
using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Interop;
namespace TreeViewControl {
IntegerToIndentationConverter::IntegerToIndentationConverter()
{
//default
indentMultiplier = 20;
}
Object^ IntegerToIndentationConverter::Convert(Object^ value, TypeName targetType, Object^ parameter, String^ language)
{
Thickness indent(0);
if (value != nullptr)
{
indent.Left = (int)value * indentMultiplier;
return indent;
}
return indent;
}
Object^ IntegerToIndentationConverter::ConvertBack(Object^ value, TypeName targetType, Object^ parameter, String^ language)
{
throw ref new NotImplementedException();
}
}

Просмотреть файл

@ -0,0 +1,23 @@
#pragma once
namespace TreeViewControl {
[Windows::Foundation::Metadata::WebHostHidden]
public ref class IntegerToIndentationConverter sealed : Windows::UI::Xaml::Data::IValueConverter
{
public:
property int IndentMultiplier
{
int get() { return indentMultiplier; };
void set(int i) { indentMultiplier = i; };
}
IntegerToIndentationConverter();
virtual Platform::Object^ Convert(Object^ value, Windows::UI::Xaml::Interop::TypeName targetType, Platform::Object^ parameter, Platform::String^ language);
virtual Platform::Object^ ConvertBack(Object^ value, Windows::UI::Xaml::Interop::TypeName targetType, Platform::Object^ parameter, Platform::String^ language);
private:
int indentMultiplier;
};
}

208
Control/TreeNode.cpp Normal file
Просмотреть файл

@ -0,0 +1,208 @@
#pragma once
#include "pch.h"
#include "TreeNode.h"
using namespace Platform;
using namespace Platform::Collections;
using namespace Windows::UI::Xaml::Data;
using namespace Windows::UI::Xaml::Interop;
using namespace Windows::Foundation;
using namespace Windows::Foundation::Collections;
namespace TreeViewControl {
TreeNode::TreeNode()
{
childrenVector->VectorChanged += ref new VectorChangedEventHandler<TreeNode ^>(this, &TreeNode::ChildrenVectorChanged);
}
void TreeNode::Append(Object^ value)
{
int count = childrenVector->Size;
TreeNode^ targetNode = (TreeNode^)value;
targetNode->ParentNode = this;
childrenVector->Append(targetNode);
//If the count was 0 before we appended, then the HasItems property needs to change.
if (count == 0)
{
this->PropertyChanged(this, ref new Windows::UI::Xaml::Data::PropertyChangedEventArgs("HasItems"));
}
this->PropertyChanged(this, ref new Windows::UI::Xaml::Data::PropertyChangedEventArgs("Size"));
}
void TreeNode::Clear()
{
int count = childrenVector->Size;
TreeNode^ childNode;
for (int i = 0; i < (int)Size; i++)
{
childNode = (TreeNode^)GetAt(i);
childNode->ParentNode = nullptr;
}
childrenVector->Clear();
//If the count was not 0 before we cleared, then the HasItems property needs to change.
if (count != 0)
{
this->PropertyChanged(this, ref new Windows::UI::Xaml::Data::PropertyChangedEventArgs("HasItems"));
}
this->PropertyChanged(this, ref new Windows::UI::Xaml::Data::PropertyChangedEventArgs("Size"));
}
IBindableIterator^ TreeNode::First()
{
return dynamic_cast<IBindableIterator^>(childrenVector->First());
}
Object^ TreeNode::GetAt(unsigned int index)
{
if ((int)index > -1 && index < childrenVector->Size)
{
return childrenVector->GetAt(index);
}
return nullptr;
}
IBindableVectorView^ TreeNode::GetView()
{
return safe_cast<IBindableVectorView^>(childrenVector->GetView());
}
bool TreeNode::IndexOf(Object^ value, unsigned int* index)
{
return childrenVector->IndexOf((TreeNode^)value, index);
}
void TreeNode::InsertAt(unsigned int index, Object^ value)
{
if ((int)index > -1 && index <= childrenVector->Size)
{
int count = childrenVector->Size;
TreeNode^ targetNode = (TreeNode^)value;
targetNode->ParentNode = this;
return childrenVector->InsertAt(index, (TreeNode^)value);
//If the count was 0 before we insert, then the HasItems property needs to change.
if (count == 0)
{
this->PropertyChanged(this, ref new Windows::UI::Xaml::Data::PropertyChangedEventArgs("HasItems"));
}
this->PropertyChanged(this, ref new Windows::UI::Xaml::Data::PropertyChangedEventArgs("Size"));
}
}
void TreeNode::RemoveAt(unsigned int index)
{
if ((int)index > -1 && index < childrenVector->Size)
{
int count = childrenVector->Size;
TreeNode^ targetNode = childrenVector->GetAt(index);
targetNode->ParentNode = nullptr;
childrenVector->RemoveAt(index);
//If the count was 1 before we remove, then the HasItems property needs to change.
if (count == 1)
{
this->PropertyChanged(this, ref new Windows::UI::Xaml::Data::PropertyChangedEventArgs("HasItems"));
}
this->PropertyChanged(this, ref new Windows::UI::Xaml::Data::PropertyChangedEventArgs("Size"));
}
}
void TreeNode::RemoveAtEnd()
{
int count = childrenVector->Size;
TreeNode^ targetNode = childrenVector->GetAt(childrenVector->Size - 1);
targetNode->ParentNode = nullptr;
childrenVector->RemoveAtEnd();
//If the count was 1 before we remove, then the HasItems property needs to change.
if (count == 1)
{
this->PropertyChanged(this, ref new Windows::UI::Xaml::Data::PropertyChangedEventArgs("HasItems"));
}
this->PropertyChanged(this, ref new Windows::UI::Xaml::Data::PropertyChangedEventArgs("Size"));
}
void TreeNode::SetAt(unsigned int index, Object^ value)
{
if ((int)index > -1 && index <= childrenVector->Size)
{
childrenVector->GetAt(index)->ParentNode = nullptr;
TreeNode^ targetNode = (TreeNode^)value;
targetNode->ParentNode = this;
return childrenVector->SetAt(index, targetNode);
}
}
void TreeNode::ChildrenVectorChanged(IObservableVector<TreeNode^>^ sender, IVectorChangedEventArgs^ e)
{
VectorChanged(this, e);
}
unsigned int TreeNode::Size::get()
{
return childrenVector->Size;
}
Object^ TreeNode::Data::get()
{
return data;
}
void TreeNode::Data::set(Object^ value)
{
data = value;
this->PropertyChanged(this, ref new Windows::UI::Xaml::Data::PropertyChangedEventArgs("Data"));
}
TreeNode^ TreeNode::ParentNode::get()
{
return parentNode;
}
void TreeNode::ParentNode::set(TreeNode^ value)
{
parentNode = value;
this->PropertyChanged(this, ref new Windows::UI::Xaml::Data::PropertyChangedEventArgs("ParentNode"));
this->PropertyChanged(this, ref new Windows::UI::Xaml::Data::PropertyChangedEventArgs("Depth"));
}
bool TreeNode::IsExpanded::get()
{
return isExpanded;
}
void TreeNode::IsExpanded::set(bool value)
{
isExpanded = value;
this->PropertyChanged(this, ref new Windows::UI::Xaml::Data::PropertyChangedEventArgs("IsExpanded"));
}
bool TreeNode::HasItems::get()
{
return (Size != 0);
}
int TreeNode::Depth::get()
{
TreeNode^ ancestorNode = this;
int depth = -1;
while ((ancestorNode->ParentNode) != nullptr)
{
depth++;
ancestorNode = ancestorNode->ParentNode;
}
return depth;
}
}

100
Control/TreeNode.h Normal file
Просмотреть файл

@ -0,0 +1,100 @@
#pragma once
namespace TreeViewControl {
/// <summary>
/// The TreeNode class implements the hierarchical layout for the TreeView.
/// It also holds the data that will be bound to in the item template.
/// </summary>
[Windows::UI::Xaml::Data::Bindable]
[Windows::Foundation::Metadata::WebHostHidden]
public ref class TreeNode sealed : Windows::UI::Xaml::Interop::IBindableObservableVector, Windows::UI::Xaml::Data::INotifyPropertyChanged
{
public:
TreeNode();
virtual void Append(Object^ value);
virtual void Clear();
virtual Windows::UI::Xaml::Interop::IBindableIterator^ First();
virtual Object^ GetAt(unsigned int index);
virtual Windows::UI::Xaml::Interop::IBindableVectorView^ GetView();
virtual bool IndexOf(Object^ value, unsigned int* index);
virtual void InsertAt(unsigned int index, Object^ value);
virtual void RemoveAt(unsigned int index);
virtual void RemoveAtEnd();
virtual void SetAt(unsigned int index, Object^ value);
virtual event Windows::UI::Xaml::Interop::BindableVectorChangedEventHandler^ VectorChanged
{
virtual Windows::Foundation::EventRegistrationToken add(Windows::UI::Xaml::Interop::BindableVectorChangedEventHandler^ e)
{
return TreeNodeChanged += e;
}
virtual void remove(Windows::Foundation::EventRegistrationToken t)
{
TreeNodeChanged -= t;
}
internal: virtual void raise(Windows::UI::Xaml::Interop::IBindableObservableVector^ vector, Platform::Object^ e)
{
TreeNodeChanged(vector, e);
}
}
virtual event Windows::UI::Xaml::Data::PropertyChangedEventHandler^ PropertyChanged;
virtual property unsigned int Size
{
unsigned int get();
}
property Object^ Data
{
Object^ get();
void set(Object^ value);
}
property TreeNode^ ParentNode
{
TreeNode^ get();
void set(TreeNode^ value);
}
property bool IsExpanded
{
bool get();
void set(bool value);
}
property bool HasItems
{
bool get();
}
//A lone TreeNode will have a depth of -1, this is to show that it is not appended
//under the TreeView's invisible root node. Once added into the TreeView via
//that method, the depth of the node will be calculated appropriately.
property int Depth
{
int get();
}
event Windows::UI::Xaml::Interop::BindableVectorChangedEventHandler^ TreeNodeChanged;
private:
TreeNode^ parentNode = nullptr;
Object^ data = nullptr;
bool isExpanded = false;
Platform::Collections::Vector<TreeNode^>^ childrenVector = ref new Platform::Collections::Vector<TreeNode^>();
void ChildrenVectorChanged(Windows::Foundation::Collections::IObservableVector<TreeNode^>^ sender, Windows::Foundation::Collections::IVectorChangedEventArgs^ e);
};
}

189
Control/TreeView.cpp Normal file
Просмотреть файл

@ -0,0 +1,189 @@
#pragma once
#include "pch.h"
#include "TreeView.h"
using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Interop;
using namespace Windows::UI::Xaml::Controls;
namespace TreeViewControl {
TreeView::TreeView()
{
flatViewModel = ref new ViewModel;
rootNode = ref new TreeNode();
flatViewModel->ExpandNode(rootNode);
CanReorderItems = true;
AllowDrop = true;
CanDragItems = true;
rootNode->VectorChanged += ref new BindableVectorChangedEventHandler(flatViewModel, &ViewModel::TreeNodeVectorChanged);
ItemClick += ref new Windows::UI::Xaml::Controls::ItemClickEventHandler(this, &TreeView::TreeView_OnItemClick);
DragItemsStarting += ref new Windows::UI::Xaml::Controls::DragItemsStartingEventHandler(this, &TreeView::TreeView_DragItemsStarting);
DragItemsCompleted += ref new Windows::Foundation::TypedEventHandler<Windows::UI::Xaml::Controls::ListViewBase ^, Windows::UI::Xaml::Controls::DragItemsCompletedEventArgs ^>(this, &TreeView::TreeView_DragItemsCompleted);
ItemsSource = flatViewModel;
}
void TreeView::TreeView_OnItemClick(Platform::Object^ sender, Windows::UI::Xaml::Controls::ItemClickEventArgs^ args)
{
TreeViewItemClickEventArgs^ treeViewArgs = ref new TreeViewItemClickEventArgs();
treeViewArgs->ClickedItem = args->ClickedItem;
TreeViewItemClick(this, treeViewArgs);
if (!treeViewArgs->IsHandled)
{
TreeNode^ targetNode = (TreeNode^)args->ClickedItem;
if (targetNode->IsExpanded)
{
flatViewModel->CollapseNode(targetNode);
}
else
{
flatViewModel->ExpandNode(targetNode);
}
}
}
void TreeView::TreeView_DragItemsStarting(Platform::Object^ sender, Windows::UI::Xaml::Controls::DragItemsStartingEventArgs^ e)
{
draggedTreeViewItem = (TreeViewItem^)this->ContainerFromItem(e->Items->GetAt(0));
}
void TreeView::TreeView_DragItemsCompleted(Windows::UI::Xaml::Controls::ListViewBase^ sender, Windows::UI::Xaml::Controls::DragItemsCompletedEventArgs^ args)
{
draggedTreeViewItem = nullptr;
}
void TreeView::OnDrop(Windows::UI::Xaml::DragEventArgs^ e)
{
if (e->AcceptedOperation == Windows::ApplicationModel::DataTransfer::DataPackageOperation::Move)
{
Panel^ panel = this->ItemsPanelRoot;
Windows::Foundation::Point point = e->GetPosition(panel);
int aboveIndex = -1;
int belowIndex = -1;
unsigned int relativeIndex;
IInsertionPanel^ insertionPanel = (IInsertionPanel^)panel;
if (insertionPanel != nullptr)
{
insertionPanel->GetInsertionIndexes(point, &aboveIndex, &belowIndex);
TreeNode^ aboveNode = (TreeNode^)flatViewModel->GetAt(aboveIndex);
TreeNode^ belowNode = (TreeNode^)flatViewModel->GetAt(belowIndex);
TreeNode^ targetNode = (TreeNode^)this->ItemFromContainer(draggedTreeViewItem);
//Between two items
if (aboveNode && belowNode)
{
targetNode->ParentNode->IndexOf(targetNode, &relativeIndex);
targetNode->ParentNode->RemoveAt(relativeIndex);
if (belowNode->ParentNode == aboveNode)
{
aboveNode->InsertAt(0, targetNode);
}
else
{
aboveNode->ParentNode->IndexOf(aboveNode, &relativeIndex);
aboveNode->ParentNode->InsertAt(relativeIndex + 1, targetNode);
}
}
//Bottom of the list
else if (aboveNode && !belowNode)
{
targetNode->ParentNode->IndexOf(targetNode, &relativeIndex);
targetNode->ParentNode->RemoveAt(relativeIndex);
aboveNode->ParentNode->IndexOf(aboveNode, &relativeIndex);
aboveNode->ParentNode->InsertAt(relativeIndex + 1, targetNode);
}
//Top of the list
else if (!aboveNode && belowNode)
{
targetNode->ParentNode->IndexOf(targetNode, &relativeIndex);
targetNode->ParentNode->RemoveAt(relativeIndex);
rootNode->InsertAt(0, targetNode);
}
}
}
e->Handled = true;
ListViewBase::OnDrop(e);
}
void TreeView::OnDragOver(Windows::UI::Xaml::DragEventArgs^ e)
{
Windows::ApplicationModel::DataTransfer::DataPackageOperation savedOperation = Windows::ApplicationModel::DataTransfer::DataPackageOperation::None;
e->AcceptedOperation = Windows::ApplicationModel::DataTransfer::DataPackageOperation::None;
Panel^ panel = this->ItemsPanelRoot;
Windows::Foundation::Point point = e->GetPosition(panel);
int aboveIndex = -1;
int belowIndex = -1;
IInsertionPanel^ insertionPanel = (IInsertionPanel^)panel;
if (insertionPanel != nullptr)
{
insertionPanel->GetInsertionIndexes(point, &aboveIndex, &belowIndex);
if (aboveIndex > -1)
{
TreeNode^ aboveNode = (TreeNode^)flatViewModel->GetAt(aboveIndex);
TreeNode^ targetNode = (TreeNode^)this->ItemFromContainer(draggedTreeViewItem);
TreeNode^ ancestorNode = aboveNode;
while (ancestorNode != nullptr && ancestorNode != targetNode)
{
ancestorNode = ancestorNode->ParentNode;
}
if (ancestorNode == nullptr)
{
savedOperation = Windows::ApplicationModel::DataTransfer::DataPackageOperation::Move;
e->AcceptedOperation = Windows::ApplicationModel::DataTransfer::DataPackageOperation::Move;
}
}
else
{
savedOperation = Windows::ApplicationModel::DataTransfer::DataPackageOperation::Move;
e->AcceptedOperation = Windows::ApplicationModel::DataTransfer::DataPackageOperation::Move;
}
}
ListViewBase::OnDragOver(e);
e->AcceptedOperation = savedOperation;
}
void TreeView::ExpandNode(TreeNode^ targetNode)
{
flatViewModel->ExpandNode(targetNode);
}
void TreeView::CollapseNode(TreeNode^ targetNode)
{
flatViewModel->CollapseNode(targetNode);
}
void TreeView::PrepareContainerForItemOverride(DependencyObject^ element, Object^ item)
{
((UIElement^)element)->AllowDrop = true;
ListView::PrepareContainerForItemOverride(element, item);
}
DependencyObject^ TreeView::GetContainerForItemOverride()
{
TreeViewItem^ targetItem = ref new TreeViewItem();
return (DependencyObject^)targetItem;
}
}

75
Control/TreeView.h Normal file
Просмотреть файл

@ -0,0 +1,75 @@
#pragma once
#include "TreeNode.h"
#include "ViewModel.h"
#include "TreeViewItem.h"
namespace TreeViewControl {
public ref class TreeViewItemClickEventArgs sealed
{
public:
TreeViewItemClickEventArgs() {}
property Object^ ClickedItem
{
Object^ get() { return clickedItem; };
void set(Object^ value) { clickedItem = value; };
}
property bool IsHandled
{
bool get() { return isHandled; };
void set(bool value) { isHandled = value; };
}
private:
Object^ clickedItem = nullptr;
bool isHandled = false;
};
ref class TreeView;
[Windows::Foundation::Metadata::WebHostHidden]
public delegate void TreeViewItemClickHandler(TreeView^ sender, TreeViewItemClickEventArgs^ args);
[Windows::Foundation::Metadata::WebHostHidden]
public ref class TreeView sealed : Windows::UI::Xaml::Controls::ListView
{
public:
TreeView();
//This event is used to expose an alternative to itemclick to developers.
event TreeViewItemClickHandler^ TreeViewItemClick;
//This RootNode property is used by the TreeView to handle additions into the TreeView and
//accurate VectorChange with multiple 'root level nodes'. This node will not be placed
//in the flatViewModel, but has it's vectorchanged event hooked up to flatViewModel's
//handler.
property TreeNode^ RootNode
{
TreeNode^ get() { return rootNode; };
}
void TreeView_OnItemClick(Platform::Object^ sender, Windows::UI::Xaml::Controls::ItemClickEventArgs^ args);
void TreeView_DragItemsStarting(Platform::Object^ sender, Windows::UI::Xaml::Controls::DragItemsStartingEventArgs^ e);
void TreeView_DragItemsCompleted(Windows::UI::Xaml::Controls::ListViewBase^ sender, Windows::UI::Xaml::Controls::DragItemsCompletedEventArgs^ args);
void ExpandNode(TreeNode^ targetNode);
void CollapseNode(TreeNode^ targetNode);
protected:
void PrepareContainerForItemOverride(DependencyObject^ element, Object^ item) override;
Windows::UI::Xaml::DependencyObject^ GetContainerForItemOverride() override;
void OnDrop(Windows::UI::Xaml::DragEventArgs^ e) override;
void OnDragOver(Windows::UI::Xaml::DragEventArgs^ e) override;
private:
TreeNode^ rootNode;
ViewModel^ flatViewModel;
internal:
TreeViewItem^ draggedTreeViewItem;
};
}

Просмотреть файл

@ -0,0 +1,237 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|ARM">
<Configuration>Debug</Configuration>
<Platform>ARM</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|ARM">
<Configuration>Release</Configuration>
<Platform>ARM</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{bdc228d2-7929-5a98-b7ba-5e28bd1adbcf}</ProjectGuid>
<Keyword>WindowsRuntimeComponent</Keyword>
<ProjectName>TreeViewControl</ProjectName>
<RootNamespace>TreeViewControl</RootNamespace>
<DefaultLanguage>en-US</DefaultLanguage>
<MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>
<AppContainerApplication>true</AppContainerApplication>
<ApplicationType>Windows Store</ApplicationType>
<WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformMinVersion>10.0.16299.0</WindowsTargetPlatformMinVersion>
<ApplicationTypeRevision>10.0</ApplicationTypeRevision>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<GenerateManifest>false</GenerateManifest>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<GenerateManifest>false</GenerateManifest>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">
<GenerateManifest>false</GenerateManifest>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">
<GenerateManifest>false</GenerateManifest>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<GenerateManifest>false</GenerateManifest>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<GenerateManifest>false</GenerateManifest>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<PreprocessorDefinitions>_WINRT_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<PrecompiledHeaderOutputFile>$(IntDir)pch.pch</PrecompiledHeaderOutputFile>
<AdditionalUsingDirectories>$(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories)</AdditionalUsingDirectories>
<AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>
<DisableSpecificWarnings>28204</DisableSpecificWarnings>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<PreprocessorDefinitions>_WINRT_DLL;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<PrecompiledHeaderOutputFile>$(IntDir)pch.pch</PrecompiledHeaderOutputFile>
<AdditionalUsingDirectories>$(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories)</AdditionalUsingDirectories>
<AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>
<DisableSpecificWarnings>28204</DisableSpecificWarnings>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<PreprocessorDefinitions>_WINRT_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<PrecompiledHeaderOutputFile>$(IntDir)pch.pch</PrecompiledHeaderOutputFile>
<AdditionalUsingDirectories>$(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories)</AdditionalUsingDirectories>
<AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>
<DisableSpecificWarnings>28204</DisableSpecificWarnings>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<PreprocessorDefinitions>_WINRT_DLL;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<PrecompiledHeaderOutputFile>$(IntDir)pch.pch</PrecompiledHeaderOutputFile>
<AdditionalUsingDirectories>$(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories)</AdditionalUsingDirectories>
<AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>
<DisableSpecificWarnings>28204</DisableSpecificWarnings>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<PreprocessorDefinitions>_WINRT_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<PrecompiledHeaderOutputFile>$(IntDir)pch.pch</PrecompiledHeaderOutputFile>
<AdditionalUsingDirectories>$(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories)</AdditionalUsingDirectories>
<AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>
<DisableSpecificWarnings>28204</DisableSpecificWarnings>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<PreprocessorDefinitions>_WINRT_DLL;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<PrecompiledHeaderOutputFile>$(IntDir)pch.pch</PrecompiledHeaderOutputFile>
<AdditionalUsingDirectories>$(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories)</AdditionalUsingDirectories>
<AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>
<DisableSpecificWarnings>28204</DisableSpecificWarnings>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="IntegerToIndentationConverter.h" />
<ClInclude Include="pch.h" />
<ClInclude Include="TreeNode.h" />
<ClInclude Include="TreeView.h" />
<ClInclude Include="TreeViewItem.h" />
<ClInclude Include="TreeViewItemAutomationPeer.h" />
<ClInclude Include="ViewModel.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="IntegerToIndentationConverter.cpp" />
<ClCompile Include="pch.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="TreeNode.cpp" />
<ClCompile Include="TreeView.cpp" />
<ClCompile Include="TreeViewItem.cpp" />
<ClCompile Include="TreeViewItemAutomationPeer.cpp" />
<ClCompile Include="ViewModel.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

Просмотреть файл

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Resources">
<UniqueIdentifier>96c875b2-800f-42e2-aba6-ef897e02ec12</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tga;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="pch.cpp" />
<ClCompile Include="TreeNode.cpp" />
<ClCompile Include="TreeView.cpp" />
<ClCompile Include="TreeViewItem.cpp" />
<ClCompile Include="TreeViewItemAutomationPeer.cpp" />
<ClCompile Include="ViewModel.cpp" />
<ClCompile Include="IntegerToIndentationConverter.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="pch.h" />
<ClInclude Include="TreeNode.h" />
<ClInclude Include="TreeView.h" />
<ClInclude Include="TreeViewItem.h" />
<ClInclude Include="TreeViewItemAutomationPeer.h" />
<ClInclude Include="ViewModel.h" />
<ClInclude Include="IntegerToIndentationConverter.h" />
</ItemGroup>
</Project>

127
Control/TreeViewItem.cpp Normal file
Просмотреть файл

@ -0,0 +1,127 @@
#pragma once
#include "pch.h"
#include "TreeViewItem.h"
#include "TreeViewItemAutomationPeer.h"
using namespace Windows::UI::Xaml;
using namespace Platform;
namespace TreeViewControl {
TreeViewItem::TreeViewItem()
{
}
TreeViewItem::~TreeViewItem()
{
}
Windows::UI::Xaml::Controls::ListView^ TreeViewItem::GetAncestorListView(TreeViewItem^ targetItem)
{
DependencyObject^ TreeViewItemAncestor = (DependencyObject^)this;
Windows::UI::Xaml::Controls::ListView^ ancestorListView = nullptr;
while (TreeViewItemAncestor != nullptr && ancestorListView == nullptr)
{
TreeViewItemAncestor = Windows::UI::Xaml::Media::VisualTreeHelper::GetParent(TreeViewItemAncestor);
ancestorListView = dynamic_cast<Windows::UI::Xaml::Controls::ListView^>(TreeViewItemAncestor);
}
return ancestorListView;
}
void TreeViewItem::OnDrop(Windows::UI::Xaml::DragEventArgs^ e)
{
if (e->AcceptedOperation == Windows::ApplicationModel::DataTransfer::DataPackageOperation::Move)
{
TreeViewItem^ droppedOnItem = (TreeViewItem^)this;
Windows::UI::Xaml::Controls::ListView^ ancestorListView = GetAncestorListView(droppedOnItem);
if (ancestorListView)
{
TreeView^ ancestorTreeView = (TreeView^)ancestorListView;
TreeViewItem^ droppedItem = ancestorTreeView->draggedTreeViewItem;
TreeNode^ droppedNode = (TreeNode^)ancestorTreeView->ItemFromContainer(droppedItem);
TreeNode^ droppedOnNode = (TreeNode^)ancestorTreeView->ItemFromContainer(droppedOnItem);
//Remove the item that was dragged
unsigned int removeIndex;
droppedNode->ParentNode->IndexOf(droppedNode, &removeIndex);
if (droppedNode != droppedOnNode)
{
droppedNode->ParentNode->RemoveAt(removeIndex);
//Append the dragged dropped item as a child of the node it was dropped onto
droppedOnNode->Append(droppedNode);
//If not set to true then the Reorder code of listview wil override what is being done here.
e->Handled = true;
}
else
{
e->AcceptedOperation = Windows::ApplicationModel::DataTransfer::DataPackageOperation::None;
}
}
}
}
void TreeViewItem::OnDragEnter(Windows::UI::Xaml::DragEventArgs^ e)
{
TreeViewItem^ draggedOverItem = (TreeViewItem^)this;
e->AcceptedOperation = Windows::ApplicationModel::DataTransfer::DataPackageOperation::None;
Windows::UI::Xaml::Controls::ListView^ ancestorListView = GetAncestorListView(draggedOverItem);
if (ancestorListView)
{
TreeView^ ancestorTreeView = (TreeView^)ancestorListView;
TreeViewItem^ draggedTreeViewItem = ancestorTreeView->draggedTreeViewItem;
TreeNode^ draggedNode = (TreeNode^)ancestorTreeView->ItemFromContainer(draggedTreeViewItem);
TreeNode^ draggedOverNode = (TreeNode^)ancestorTreeView->ItemFromContainer(draggedOverItem);
TreeNode^ walkNode = draggedOverNode->ParentNode;
while (walkNode != nullptr && walkNode != draggedNode)
{
walkNode = walkNode->ParentNode;
}
if (walkNode != draggedNode && draggedNode != draggedOverNode)
{
e->AcceptedOperation = Windows::ApplicationModel::DataTransfer::DataPackageOperation::Move;
}
}
}
void TreeViewItem::OnDragOver(Windows::UI::Xaml::DragEventArgs^ e)
{
e->DragUIOverride->IsGlyphVisible = true;
e->AcceptedOperation = Windows::ApplicationModel::DataTransfer::DataPackageOperation::None;
TreeViewItem^ draggedOverItem = (TreeViewItem^)this;
Windows::UI::Xaml::Controls::ListView^ ancestorListView = GetAncestorListView(draggedOverItem);
if (ancestorListView)
{
TreeView^ ancestorTreeView = (TreeView^)ancestorListView;
TreeViewItem^ draggedTreeViewItem = ancestorTreeView->draggedTreeViewItem;
TreeNode^ draggedNode = (TreeNode^)ancestorTreeView->ItemFromContainer(draggedTreeViewItem);
TreeNode^ draggedOverNode = (TreeNode^)ancestorTreeView->ItemFromContainer(draggedOverItem);
TreeNode^ walkNode = draggedOverNode->ParentNode;
while (walkNode != nullptr && walkNode != draggedNode)
{
walkNode = walkNode->ParentNode;
}
if (walkNode != draggedNode && draggedNode != draggedOverNode)
{
e->AcceptedOperation = Windows::ApplicationModel::DataTransfer::DataPackageOperation::Move;
}
}
}
Windows::UI::Xaml::Automation::Peers::AutomationPeer^ TreeViewItem::OnCreateAutomationPeer()
{
return ref new TreeViewItemAutomationPeer(this);
}
}

22
Control/TreeViewItem.h Normal file
Просмотреть файл

@ -0,0 +1,22 @@
#pragma once
namespace TreeViewControl {
[Windows::Foundation::Metadata::WebHostHidden]
[Windows::UI::Xaml::Data::Bindable]
public ref class TreeViewItem sealed : Windows::UI::Xaml::Controls::ListViewItem
{
public:
TreeViewItem();
virtual ~TreeViewItem();
private:
Windows::UI::Xaml::Controls::ListView^ GetAncestorListView(TreeViewItem^ targetItem);
protected:
void OnDrop(Windows::UI::Xaml::DragEventArgs^ e) override;
void OnDragEnter(Windows::UI::Xaml::DragEventArgs^ e) override;
void OnDragOver(Windows::UI::Xaml::DragEventArgs^ e) override;
Windows::UI::Xaml::Automation::Peers::AutomationPeer^ OnCreateAutomationPeer() override;
};
}

Просмотреть файл

@ -0,0 +1,178 @@
#pragma once
#include "pch.h"
#include "TreeViewItemAutomationPeer.h"
#include "TreeNode.h"
using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Automation;
using namespace Windows::UI::Xaml::Controls;
using namespace Windows::UI::Xaml::Data;
namespace TreeViewControl {
//IExpandCollapseProvider
Windows::UI::Xaml::Automation::ExpandCollapseState TreeViewItemAutomationPeer::ExpandCollapseState::get()
{
Windows::UI::Xaml::Automation::ExpandCollapseState currentState = Windows::UI::Xaml::Automation::ExpandCollapseState::Collapsed;
Windows::UI::Xaml::Controls::ListView^ ancestorListView = GetParentListView((DependencyObject^)Owner);
TreeNode^ targetNode;
TreeNode^ targetParentNode;
if (ancestorListView)
{
TreeView^ ancestorTreeView = (TreeView^)ancestorListView;
targetNode = (TreeNode^)ancestorTreeView->ItemFromContainer((TreeViewItem^)Owner);
if (Owner->AllowDrop)
{
if (targetNode->IsExpanded)
{
currentState = Windows::UI::Xaml::Automation::ExpandCollapseState::Expanded;
}
else
{
currentState = Windows::UI::Xaml::Automation::ExpandCollapseState::Collapsed;
}
}
else
{
currentState = Windows::UI::Xaml::Automation::ExpandCollapseState::LeafNode;
}
}
return currentState;
}
void TreeViewItemAutomationPeer::Collapse()
{
Windows::UI::Xaml::Controls::ListView^ ancestorListView = GetParentListView((DependencyObject^)Owner);
if (ancestorListView)
{
TreeView^ ancestorTreeView = (TreeView^)ancestorListView;
TreeNode^ targetNode = (TreeNode^)ancestorTreeView->ItemFromContainer((TreeViewItem^)Owner);
ancestorTreeView->CollapseNode(targetNode);
RaiseExpandCollapseAutomationEvent(Windows::UI::Xaml::Automation::ExpandCollapseState::Collapsed);
}
}
void TreeViewItemAutomationPeer::Expand()
{
Windows::UI::Xaml::Controls::ListView^ ancestorListView = GetParentListView((DependencyObject^)Owner);
if (ancestorListView)
{
TreeView^ ancestorTreeView = (TreeView^)ancestorListView;
TreeNode^ targetNode = (TreeNode^)ancestorTreeView->ItemFromContainer((TreeViewItem^)Owner);
ancestorTreeView->ExpandNode(targetNode);
RaiseExpandCollapseAutomationEvent(Windows::UI::Xaml::Automation::ExpandCollapseState::Expanded);
}
}
void TreeViewItemAutomationPeer::RaiseExpandCollapseAutomationEvent(Windows::UI::Xaml::Automation::ExpandCollapseState newState)
{
Windows::UI::Xaml::Automation::ExpandCollapseState oldState;
if (newState == Windows::UI::Xaml::Automation::ExpandCollapseState::Expanded)
{
oldState = Windows::UI::Xaml::Automation::ExpandCollapseState::Collapsed;
}
else
{
oldState = Windows::UI::Xaml::Automation::ExpandCollapseState::Expanded;
}
RaisePropertyChangedEvent(ExpandCollapsePatternIdentifiers::ExpandCollapseStateProperty, oldState, newState);
}
//Position override
//These methods are being overridden so that the TreeView under narrator reads out
//the position of an item as compared to it's children, not it's overall position
//in the listview. I've included an override for level as well, to give context on
//how deep in the tree an item is.
int TreeViewItemAutomationPeer::GetSizeOfSetCore()
{
Windows::UI::Xaml::Controls::ListView^ ancestorListView = GetParentListView((DependencyObject^)Owner);
TreeNode^ targetNode;
TreeNode^ targetParentNode;
int setSize = 0;
if (ancestorListView)
{
TreeView^ ancestorTreeView = (TreeView^)ancestorListView;
targetNode = (TreeNode^)ancestorTreeView->ItemFromContainer((TreeViewItem^)Owner);
targetParentNode = targetNode->ParentNode;
setSize = targetParentNode->Size;
}
return setSize;
}
int TreeViewItemAutomationPeer::GetPositionInSetCore()
{
Windows::UI::Xaml::Controls::ListView^ ancestorListView = GetParentListView((DependencyObject^)Owner);
TreeNode^ targetNode;
TreeNode^ targetParentNode;
int positionInSet = 0;
if (ancestorListView)
{
TreeView^ ancestorTreeView = (TreeView^)ancestorListView;
targetNode = (TreeNode^)ancestorTreeView->ItemFromContainer((TreeViewItem^)Owner);
unsigned int positionInt;
targetParentNode = targetNode->ParentNode;
targetParentNode->IndexOf(targetNode, &positionInt);
positionInSet = (int)positionInt + 1;
}
return positionInSet;
}
int TreeViewItemAutomationPeer::GetLevelCore()
{
Windows::UI::Xaml::Controls::ListView^ ancestorListView = GetParentListView((DependencyObject^)Owner);
TreeNode^ targetNode;
TreeNode^ targetParentNode;
int levelValue = 0;
if (ancestorListView)
{
TreeView^ ancestorTreeView = (TreeView^)ancestorListView;
targetNode = (TreeNode^)ancestorTreeView->ItemFromContainer((TreeViewItem^)Owner);
levelValue = targetNode->Depth + 1;
}
return levelValue;
}
Platform::Object^ TreeViewItemAutomationPeer::GetPatternCore(Windows::UI::Xaml::Automation::Peers::PatternInterface patternInterface)
{
if (patternInterface == Windows::UI::Xaml::Automation::Peers::PatternInterface::ExpandCollapse)
{
return this;
}
return ListViewItemAutomationPeer::GetPatternCore(patternInterface);
}
Windows::UI::Xaml::Controls::ListView^ TreeViewItemAutomationPeer::GetParentListView(DependencyObject^ Owner)
{
DependencyObject^ treeViewItemAncestor = Owner;
Windows::UI::Xaml::Controls::ListView^ ancestorListView = nullptr;
while (treeViewItemAncestor != nullptr && ancestorListView == nullptr)
{
treeViewItemAncestor = Windows::UI::Xaml::Media::VisualTreeHelper::GetParent(treeViewItemAncestor);
ancestorListView = dynamic_cast<Windows::UI::Xaml::Controls::ListView^>(treeViewItemAncestor);
}
return ancestorListView;
}
}

Просмотреть файл

@ -0,0 +1,39 @@
#pragma once
#include "TreeViewItem.h"
#include "TreeView.h"
namespace TreeViewControl {
[Windows::Foundation::Metadata::WebHostHidden]
public ref class TreeViewItemAutomationPeer : Windows::UI::Xaml::Automation::Peers::ListViewItemAutomationPeer, Windows::UI::Xaml::Automation::Provider::IExpandCollapseProvider
{
internal:
TreeViewItemAutomationPeer(TreeViewItem^ owner) :Windows::UI::Xaml::Automation::Peers::ListViewItemAutomationPeer(owner) {};
public:
//IExpandCollapseProvider
virtual void Collapse();
virtual void Expand();
property Windows::UI::Xaml::Automation::ExpandCollapseState ExpandCollapseState
{
virtual Windows::UI::Xaml::Automation::ExpandCollapseState get();
}
void RaiseExpandCollapseAutomationEvent(Windows::UI::Xaml::Automation::ExpandCollapseState newState);
//Position override
int GetSizeOfSetCore() override;
int GetPositionInSetCore() override;
int GetLevelCore() override;
protected:
Platform::Object^ GetPatternCore(Windows::UI::Xaml::Automation::Peers::PatternInterface patternInterface) override;
private:
Windows::UI::Xaml::Controls::ListView^ GetParentListView(DependencyObject^ Owner);
};
}

450
Control/ViewModel.cpp Normal file
Просмотреть файл

@ -0,0 +1,450 @@
#pragma once
#include "pch.h"
#include "ViewModel.h"
using namespace Platform;
using namespace Windows::Foundation::Collections;
using namespace Windows::UI::Xaml::Interop;
using namespace Windows::UI::Xaml::Data;
namespace TreeViewControl {
ViewModel::ViewModel()
{
flatVectorRealizedItems->VectorChanged += ref new VectorChangedEventHandler<TreeNode ^>(this, &ViewModel::UpdateTreeView);
}
void ViewModel::Append(Object^ value)
{
TreeNode^ targetNode = (TreeNode^)value;
flatVectorRealizedItems->Append(targetNode);
collectionChangedEventTokenVector.push_back(targetNode->VectorChanged += ref new BindableVectorChangedEventHandler(this, &ViewModel::TreeNodeVectorChanged));
propertyChangedEventTokenVector.push_back(targetNode->PropertyChanged += ref new Windows::UI::Xaml::Data::PropertyChangedEventHandler(this, &ViewModel::TreeNodePropertyChanged));
}
void ViewModel::Clear()
{
while (flatVectorRealizedItems->Size != 0)
{
RemoveAtEnd();
}
}
IBindableIterator^ ViewModel::First()
{
return dynamic_cast<IBindableIterator^>(flatVectorRealizedItems->First());
}
Object^ ViewModel::GetAt(unsigned int index)
{
if ((int)index > -1 && (int)index < flatVectorRealizedItems->Size)
{
return flatVectorRealizedItems->GetAt(index);
}
return nullptr;
}
IBindableVectorView^ ViewModel::GetView()
{
return safe_cast<IBindableVectorView^>(flatVectorRealizedItems->GetView());
}
bool ViewModel::IndexOf(Object^ value, unsigned int* index)
{
return flatVectorRealizedItems->IndexOf((TreeNode^)value, index);
}
void ViewModel::InsertAt(unsigned int index, Object^ value)
{
if ((int)index > -1 && (int)index <= flatVectorRealizedItems->Size)
{
TreeNode^ targetNode = (TreeNode^)value;
flatVectorRealizedItems->InsertAt(index, targetNode);
auto eventIndex = collectionChangedEventTokenVector.begin() + index;
collectionChangedEventTokenVector.insert(eventIndex, targetNode->VectorChanged += ref new BindableVectorChangedEventHandler(this, &ViewModel::TreeNodeVectorChanged));
eventIndex = propertyChangedEventTokenVector.begin() + index;
propertyChangedEventTokenVector.insert(eventIndex,targetNode->PropertyChanged += ref new Windows::UI::Xaml::Data::PropertyChangedEventHandler(this, &ViewModel::TreeNodePropertyChanged));
}
}
void ViewModel::RemoveAt(unsigned int index)
{
if ((int)index > -1 && (int)index < flatVectorRealizedItems->Size)
{
TreeNode^ targetNode = flatVectorRealizedItems->GetAt(index);
flatVectorRealizedItems->RemoveAt(index);
auto eventIndex = collectionChangedEventTokenVector.begin() + index;
targetNode->VectorChanged -= collectionChangedEventTokenVector[index];
collectionChangedEventTokenVector.erase(eventIndex);
eventIndex = propertyChangedEventTokenVector.begin() + index;
targetNode->PropertyChanged -= propertyChangedEventTokenVector[index];
propertyChangedEventTokenVector.erase(eventIndex);
}
}
void ViewModel::RemoveAtEnd()
{
int index = flatVectorRealizedItems->Size - 1;
if (index >= 0)
{
TreeNode^ targetNode = flatVectorRealizedItems->GetAt(index);
flatVectorRealizedItems->RemoveAt(index);
auto eventIndex = collectionChangedEventTokenVector.begin() + index;
targetNode->VectorChanged -= collectionChangedEventTokenVector[index];
collectionChangedEventTokenVector.erase(eventIndex);
eventIndex = propertyChangedEventTokenVector.begin() + index;
targetNode->PropertyChanged -= propertyChangedEventTokenVector[index];
propertyChangedEventTokenVector.erase(eventIndex);
}
}
void ViewModel::SetAt(unsigned int index, Object^ value)
{
if ((int)index > -1 && (int)index < flatVectorRealizedItems->Size)
{
TreeNode^ targetNode = (TreeNode^)value;
TreeNode^ removeNode = flatVectorRealizedItems->GetAt(index);
flatVectorRealizedItems->SetAt(index, targetNode);
auto eventIndex = collectionChangedEventTokenVector.begin() + index;
removeNode->VectorChanged -= collectionChangedEventTokenVector[index];
collectionChangedEventTokenVector.erase(eventIndex);
collectionChangedEventTokenVector.insert(eventIndex, targetNode->VectorChanged += ref new BindableVectorChangedEventHandler(this, &ViewModel::TreeNodeVectorChanged));
eventIndex = propertyChangedEventTokenVector.begin() + index;
targetNode->PropertyChanged -= propertyChangedEventTokenVector[index];
propertyChangedEventTokenVector.erase(eventIndex);
propertyChangedEventTokenVector.insert(eventIndex, targetNode->PropertyChanged += ref new Windows::UI::Xaml::Data::PropertyChangedEventHandler(this, &ViewModel::TreeNodePropertyChanged));
}
}
void ViewModel::ExpandNode(TreeNode^ targetNode)
{
if (!targetNode->IsExpanded)
{
targetNode->IsExpanded = true;
}
}
void ViewModel::CollapseNode(TreeNode^ targetNode)
{
if (targetNode->IsExpanded)
{
targetNode->IsExpanded = false;
}
}
void ViewModel::AddNodeToView(TreeNode^ targetNode, int index)
{
InsertAt(index, targetNode);
}
int ViewModel::AddNodeDescendantsToView(TreeNode^ targetNode, int index, int offset)
{
if (targetNode->IsExpanded)
{
TreeNode^ childNode;
for (int i = 0; i < (int)targetNode->Size; i++)
{
childNode = (TreeNode^)targetNode->GetAt(i);
offset++;
AddNodeToView(childNode, index + offset);
offset = AddNodeDescendantsToView(childNode, index, offset);
}
return offset;
}
return offset;
}
void ViewModel::RemoveNodeAndDescendantsFromView(TreeNode^ targetNode)
{
if (targetNode->IsExpanded)
{
TreeNode^ childNode;
for (int i = 0; i < (int)targetNode->Size; i++)
{
childNode = (TreeNode^)targetNode->GetAt(i);
RemoveNodeAndDescendantsFromView(childNode);
}
}
int index = IndexOf(targetNode);
RemoveAt(index);
}
int ViewModel::CountDescendants(TreeNode^ targetNode)
{
int descendantCount = 0;
TreeNode^ childNode;
for (int i = 0; i < (int)targetNode->Size; i++)
{
childNode = (TreeNode^)targetNode->GetAt(i);
descendantCount++;
if (childNode->IsExpanded)
{
descendantCount = descendantCount + CountDescendants(childNode);
}
}
return descendantCount;
}
int ViewModel::IndexOf(TreeNode^ targetNode)
{
unsigned int index;
bool isIndexed = IndexOf(targetNode, &index);
if (isIndexed)
{
return (int)index;
}
else
{
return -1;
}
}
void ViewModel::UpdateTreeView(IObservableVector<TreeNode^>^ sender, IVectorChangedEventArgs^ e)
{
VectorChanged(this, e);
}
void ViewModel::TreeNodeVectorChanged(IBindableObservableVector^ sender, Platform::Object^ e)
{
CollectionChange CC = ((IVectorChangedEventArgs^)e)->CollectionChange;
switch (CC)
{
//Reset case, commonly seen when a TreeNode is cleared.
//removes all nodes that need removing then
//toggles a collapse / expand to ensure order.
case (CollectionChange::Reset) :
{
TreeNode^ resetNode = (TreeNode^)sender;
int resetIndex = IndexOf(resetNode);
if (resetIndex != Size - 1 && resetNode->IsExpanded)
{
TreeNode^ childNode = resetNode;
TreeNode^ parentNode = resetNode->ParentNode;
int stopIndex;
bool isLastRelativeChild = true;
while (parentNode != nullptr && isLastRelativeChild)
{
unsigned int relativeIndex;
parentNode->IndexOf(childNode, &relativeIndex);
if (parentNode->Size - 1 != relativeIndex)
{
isLastRelativeChild = false;
}
else
{
childNode = parentNode;
parentNode = parentNode->ParentNode;
}
}
if (parentNode != nullptr)
{
unsigned int siblingIndex;
parentNode->IndexOf(childNode, &siblingIndex);
TreeNode^ siblingNode = (TreeNode^)parentNode->GetAt(siblingIndex + 1);
stopIndex = IndexOf(siblingNode);
}
else
{
stopIndex = Size;
}
for (int i = stopIndex - 1; i > resetIndex; i--)
{
if ((flatVectorRealizedItems->GetAt(i))->ParentNode == nullptr)
{
RemoveNodeAndDescendantsFromView(flatVectorRealizedItems->GetAt(i));
}
}
if (resetNode->IsExpanded)
{
CollapseNode(resetNode);
ExpandNode(resetNode);
}
}
break;
}
//Inserts the TreeNode into the correct index of the ViewModel
case (CollectionChange::ItemInserted) :
{
//We will find the correct index of insertion by first checking if the
//node we are inserting into is expanded. If it is we will start walking
//down the tree and counting the open items. This is to ensure we place
//the inserted item in the correct index. If along the way we bump into
//the item being inserted, we insert there then return, because we don't
//need to do anything further.
unsigned int index = ((IVectorChangedEventArgs^)e)->Index;
TreeNode^ targetNode = (TreeNode^)sender->GetAt(index);
TreeNode^ parentNode = targetNode->ParentNode;
TreeNode^ childNode;
int parentIndex = IndexOf(parentNode);
int allOpenedDescendantsCount = 0;
if (parentNode->IsExpanded)
{
for (int i = 0; i < (int)parentNode->Size; i++)
{
childNode = (TreeNode^)parentNode->GetAt(i);
if (childNode == targetNode)
{
AddNodeToView(targetNode, (parentIndex + i + 1 + allOpenedDescendantsCount));
if (targetNode->IsExpanded)
{
AddNodeDescendantsToView(targetNode, parentIndex + i + 1, allOpenedDescendantsCount);
}
return;
}
if (childNode->IsExpanded)
{
allOpenedDescendantsCount += CountDescendants(childNode);
}
}
AddNodeToView(targetNode, (parentIndex + parentNode->Size + allOpenedDescendantsCount));
if (targetNode->IsExpanded)
{
AddNodeDescendantsToView(targetNode, parentIndex + parentNode->Size, allOpenedDescendantsCount);
}
}
break;
}
//Removes a node from the ViewModel when a TreeNode
//removes a child.
case (CollectionChange::ItemRemoved) :
{
TreeNode^ removeNode = (TreeNode^)sender;
int removeIndex = IndexOf(removeNode);
if (removeIndex != Size - 1 && removeNode->IsExpanded)
{
TreeNode^ childNode = removeNode;
TreeNode^ parentNode = removeNode->ParentNode;
int stopIndex;
bool isLastRelativeChild = true;
while (parentNode != nullptr && isLastRelativeChild)
{
unsigned int relativeIndex;
parentNode->IndexOf(childNode, &relativeIndex);
if (parentNode->Size - 1 != relativeIndex)
{
isLastRelativeChild = false;
}
else
{
childNode = parentNode;
parentNode = parentNode->ParentNode;
}
}
if (parentNode != nullptr)
{
unsigned int siblingIndex;
parentNode->IndexOf(childNode, &siblingIndex);
TreeNode^ siblingNode = (TreeNode^)parentNode->GetAt(siblingIndex + 1);
stopIndex = IndexOf(siblingNode);
}
else
{
stopIndex = Size;
}
for (int i = stopIndex - 1; i > removeIndex; i--)
{
if ((flatVectorRealizedItems->GetAt(i))->ParentNode == nullptr)
{
RemoveNodeAndDescendantsFromView(flatVectorRealizedItems->GetAt(i));
}
}
}
break;
}
//Triggered by a replace such as SetAt.
//Updates the TreeNode that changed in the ViewModel.
case (CollectionChange::ItemChanged) :
{
unsigned int index = ((IVectorChangedEventArgs^)e)->Index;
TreeNode^ targetNode = (TreeNode^)sender->GetAt(index);
TreeNode^ parentNode = targetNode->ParentNode;
TreeNode^ childNode;
int allOpenedDescendantsCount = 0;
int parentIndex = IndexOf(parentNode);
for (int i = 0; i < (int)parentNode->Size; i++)
{
childNode = (TreeNode^)parentNode->GetAt(i);
if (childNode->IsExpanded)
{
allOpenedDescendantsCount += CountDescendants(childNode);
}
}
TreeNode^ removeNode = (TreeNode^)GetAt(parentIndex + index + allOpenedDescendantsCount + 1);
if (removeNode->IsExpanded)
{
CollapseNode(removeNode);
}
RemoveAt(parentIndex + index + allOpenedDescendantsCount + 1);
InsertAt(parentIndex + index + allOpenedDescendantsCount + 1, targetNode);
break;
}
}
}
void ViewModel::TreeNodePropertyChanged(Object^ sender, PropertyChangedEventArgs^ e)
{
if (e->PropertyName == "IsExpanded")
{
TreeNode^ targetNode = (TreeNode^)sender;
if (targetNode->IsExpanded)
{
if (targetNode->Size != 0)
{
int openedDescendantOffset = 0;
int index = IndexOf(targetNode);
index = index + 1;
TreeNode^ childNode;
for (int i = 0; i < (int)targetNode->Size; i++)
{
childNode = (TreeNode^)targetNode->GetAt(i);
AddNodeToView(childNode, ((int)index + i + openedDescendantOffset));
openedDescendantOffset = AddNodeDescendantsToView(childNode, (index + i), openedDescendantOffset);
}
}
}
else
{
TreeNode^ childNode;
for (int i = 0; i < (int)targetNode->Size; i++)
{
childNode = (TreeNode^)targetNode->GetAt(i);
RemoveNodeAndDescendantsFromView(childNode);
}
}
}
}
}

105
Control/ViewModel.h Normal file
Просмотреть файл

@ -0,0 +1,105 @@
#pragma once
#include "TreeNode.h"
namespace TreeViewControl {
/// <summary>
/// The ViewModel is responsible for flattening the heirarchical data into a flat list.
/// It also tracks changes to the underlying data and updates the flat list accordingly.
/// </summary>
[Windows::Foundation::Metadata::WebHostHidden]
ref class ViewModel sealed : Windows::UI::Xaml::Interop::IBindableObservableVector
{
internal:
ViewModel();
public:
/// <summary>
/// Add root to the view model. In other cases the app should not
/// use this api.
/// </summary>
virtual void Append(Object^ value);
virtual void Clear();
virtual Windows::UI::Xaml::Interop::IBindableIterator^ First();
virtual Object^ GetAt(unsigned int index);
virtual Windows::UI::Xaml::Interop::IBindableVectorView^ GetView();
virtual bool IndexOf(Object^ value, unsigned int* index);
virtual void InsertAt(unsigned int index, Object^ value);
virtual void RemoveAt(unsigned int index);
virtual void RemoveAtEnd();
virtual void SetAt(unsigned int index, Object^ value);
virtual property unsigned int Size
{
unsigned int get() { return flatVectorRealizedItems->Size; };
};
virtual event Windows::UI::Xaml::Interop::BindableVectorChangedEventHandler^ VectorChanged
{
virtual Windows::Foundation::EventRegistrationToken add(Windows::UI::Xaml::Interop::BindableVectorChangedEventHandler^ args)
{
return ViewModelChanged += args;
}
virtual void remove(Windows::Foundation::EventRegistrationToken token)
{
return ViewModelChanged -= token;
}
virtual void raise(Windows::UI::Xaml::Interop::IBindableObservableVector^ vector, Platform::Object^ e)
{
ViewModelChanged(vector, e);
}
}
/// <summary>
/// ExpandNode adds the children and all open descendants of the targetNode
/// to the ViewModel in their correct flattened index.
/// </summary>
void ExpandNode(TreeNode^ targetNode);
/// <summary>
/// Collapse node removes all the descendants of the targetNode from the ViewModel.
/// </summary>
void CollapseNode(TreeNode^ targetNode);
/// <summary>
/// This is the collection changed handler for individual TreeNodes. The collection changes
/// from the hierarchical TreeNodes need to be flattened so that we can keep our current
/// flat list in sync.
/// </summary>
/// <param name="sender">TreeNode that has already been changed</param>
void TreeNodeVectorChanged(Windows::UI::Xaml::Interop::IBindableObservableVector^ sender, Platform::Object^ e);
void TreeNodePropertyChanged(Object^ sender, Windows::UI::Xaml::Data::PropertyChangedEventArgs^ e);
private:
event Windows::UI::Xaml::Interop::BindableVectorChangedEventHandler^ ViewModelChanged;
Platform::Collections::Vector<TreeNode^>^ flatVectorRealizedItems = ref new Platform::Collections::Vector<TreeNode^>();
std::vector<Windows::Foundation::EventRegistrationToken> collectionChangedEventTokenVector;
std::vector<Windows::Foundation::EventRegistrationToken> propertyChangedEventTokenVector;
void AddNodeToView(TreeNode^ targetNode, int index);
int AddNodeDescendantsToView(TreeNode^ targetNode, int start, int offset);
void RemoveNodeAndDescendantsFromView(TreeNode^ targetNode);
int CountDescendants(TreeNode^ targetNode);
int IndexOf(TreeNode^ targetNode);
void UpdateTreeView(Windows::Foundation::Collections::IObservableVector<TreeNode^>^ sender, Windows::Foundation::Collections::IVectorChangedEventArgs^ e);
};
}

1
Control/pch.cpp Normal file
Просмотреть файл

@ -0,0 +1 @@
#include "pch.h"

10
Control/pch.h Normal file
Просмотреть файл

@ -0,0 +1,10 @@
#pragma once
#include <collection.h>
#include <ppltasks.h>
#include <TreeNode.h>
#include <ViewModel.h>
#include <TreeViewItem.h>
#include <TreeView.h>
#include <TreeViewItemAutomationPeer.h>
#include <IntegerToIndentationConverter.h>

Двоичные данные
GLBGLTFConverter/GLBGLTFConverter.cpp Normal file

Двоичный файл не отображается.

Просмотреть файл

@ -0,0 +1,166 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>15.0</VCProjectVersion>
<ProjectGuid>{F6FAFE3C-92C0-43E7-A64B-B38DFC793EB2}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>GLBGLTFConverter</RootNamespace>
<WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="stdafx.h" />
<ClInclude Include="targetver.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="GLBGLTFConverter.cpp" />
<ClCompile Include="stdafx.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\gltfparser\gltfparser.vcxproj">
<Project>{d3b2132d-132e-4b58-a828-b20ef9962a83}</Project>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

Просмотреть файл

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="stdafx.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="targetver.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="stdafx.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="GLBGLTFConverter.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

Двоичные данные
GLBGLTFConverter/stdafx.cpp Normal file

Двоичный файл не отображается.

Двоичные данные
GLBGLTFConverter/stdafx.h Normal file

Двоичный файл не отображается.

Двоичные данные
GLBGLTFConverter/targetver.h Normal file

Двоичный файл не отображается.

8
ModelViewer/App.xaml Normal file
Просмотреть файл

@ -0,0 +1,8 @@
<Application
x:Class="ModelViewer.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:ModelViewer"
RequestedTheme="Dark">
</Application>

155
ModelViewer/App.xaml.cpp Normal file
Просмотреть файл

@ -0,0 +1,155 @@
//
// App.xaml.cpp
// Implementation of the App class.
//
#include "pch.h"
#include "RootPage.xaml.h"
#include "DirectXPage.xaml.h"
using namespace ModelViewer;
using namespace Platform;
using namespace Windows::ApplicationModel;
using namespace Windows::ApplicationModel::Activation;
using namespace Windows::Foundation;
using namespace Windows::Foundation::Collections;
using namespace Windows::Storage;
using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Controls;
using namespace Windows::UI::Xaml::Controls::Primitives;
using namespace Windows::UI::Xaml::Data;
using namespace Windows::UI::Xaml::Input;
using namespace Windows::UI::Xaml::Interop;
using namespace Windows::UI::Xaml::Media;
using namespace Windows::UI::Xaml::Navigation;
/// <summary>
/// Initializes the singleton application object. This is the first line of authored code
/// executed, and as such is the logical equivalent of main() or WinMain().
/// </summary>
App::App()
{
InitializeComponent();
//builder.registerType<>
Suspending += ref new SuspendingEventHandler(this, &App::OnSuspending);
Resuming += ref new EventHandler<Object^>(this, &App::OnResuming);
}
void App::ExtendAcrylicIntoTitleBar()
{
Windows::ApplicationModel::Core::CoreApplication::GetCurrentView()->TitleBar->ExtendViewIntoTitleBar = true;
auto titleBar = Windows::ApplicationModel::Core::CoreApplication::GetCurrentView()->TitleBar;
// These properties don't exist...
//titleBar->ButtonBackgroundColor = Colors.Transparent;
//titleBar->ButtonInactiveBackgroundColor = Colors.Transparent;
}
/// <summary>
/// Invoked when the application is launched normally by the end user. Other entry points
/// will be used when the application is launched to open a specific file, to display
/// search results, and so forth.
/// </summary>
/// <param name="e">Details about the launch request and process.</param>
void App::OnLaunched(Windows::ApplicationModel::Activation::LaunchActivatedEventArgs^ e)
{
#if _DEBUG
if (IsDebuggerPresent())
{
DebugSettings->EnableFrameRateCounter = true;
}
#endif
if (m_rootPage == nullptr)
{
m_rootPage = ref new ModelViewer::RootPage();
}
if (e->PreviousExecutionState == ApplicationExecutionState::Terminated)
{
m_rootPage->LoadInternalState(ApplicationData::Current->LocalSettings->Values);
}
auto rootFrame = dynamic_cast<Frame^>(Window::Current->Content);
// Do not repeat app initialization when the Window already has content,
// just ensure that the window is active
if (rootFrame == nullptr)
{
// Create a Frame to act as the navigation context and associate it with
// a SuspensionManager key
rootFrame = ref new Frame();
rootFrame->NavigationFailed += ref new Windows::UI::Xaml::Navigation::NavigationFailedEventHandler(this, &App::OnNavigationFailed);
if (rootFrame->Content == nullptr)
{
// When the navigation stack isn't restored navigate to the first page,
// configuring the new page by passing required information as a navigation
// parameter
rootFrame->Navigate(TypeName(RootPage::typeid), e->Arguments);
}
// Place the frame in the current Window
Window::Current->Content = rootFrame;
// Ensure the current window is active
Window::Current->Activate();
}
else
{
if (rootFrame->Content == nullptr)
{
// When the navigation stack isn't restored navigate to the first page,
// configuring the new page by passing required information as a navigation
// parameter
rootFrame->Navigate(TypeName(RootPage::typeid), e->Arguments);
}
// Ensure the current window is active
Window::Current->Activate();
ExtendAcrylicIntoTitleBar();
}
//m_rootPage->GetContentFrame()->Content = ref new DirectXPage();
}
/// <summary>
/// Invoked when application execution is being suspended. Application state is saved
/// without knowing whether the application will be terminated or resumed with the contents
/// of memory still intact.
/// </summary>
/// <param name="sender">The source of the suspend request.</param>
/// <param name="e">Details about the suspend request.</param>
void App::OnSuspending(Object^ sender, SuspendingEventArgs^ e)
{
(void) sender; // Unused parameter
(void) e; // Unused parameter
m_rootPage->SaveInternalState(ApplicationData::Current->LocalSettings->Values);
}
/// <summary>
/// Invoked when application execution is being resumed.
/// </summary>
/// <param name="sender">The source of the resume request.</param>
/// <param name="args">Details about the resume request.</param>
void App::OnResuming(Object ^sender, Object ^args)
{
(void) sender; // Unused parameter
(void) args; // Unused parameter
m_rootPage->LoadInternalState(ApplicationData::Current->LocalSettings->Values);
}
/// <summary>
/// Invoked when Navigation to a certain page fails
/// </summary>
/// <param name="sender">The Frame which failed navigation</param>
/// <param name="e">Details about the navigation failure</param>
void App::OnNavigationFailed(Platform::Object ^sender, Windows::UI::Xaml::Navigation::NavigationFailedEventArgs ^e)
{
throw ref new FailureException("Failed to load Page " + e->SourcePageType.Name);
}

30
ModelViewer/App.xaml.h Normal file
Просмотреть файл

@ -0,0 +1,30 @@
//
// App.xaml.h
// Declaration of the App class.
//
#pragma once
#include "App.g.h"
#include "RootPage.xaml.h"
namespace ModelViewer
{
/// <summary>
/// Provides application-specific behavior to supplement the default Application class.
/// </summary>
ref class App sealed
{
public:
App();
virtual void OnLaunched(Windows::ApplicationModel::Activation::LaunchActivatedEventArgs^ e) override;
private:
void ExtendAcrylicIntoTitleBar();
void OnSuspending(Platform::Object^ sender, Windows::ApplicationModel::SuspendingEventArgs^ e);
void OnResuming(Platform::Object ^sender, Platform::Object ^args);
void OnNavigationFailed(Platform::Object ^sender, Windows::UI::Xaml::Navigation::NavigationFailedEventArgs ^e);
RootPage^ m_rootPage;
};
}

Двоичные данные
ModelViewer/Assets/LockScreenLogo.scale-200.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.4 KiB

Просмотреть файл

@ -0,0 +1,359 @@
//
// This fragment shader defines a reference implementation for Physically Based Shading of
// a microfacet surface material defined by a glTF model.
//
// References:
// [1] Real Shading in Unreal Engine 4
// http://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_notes_v2.pdf
// [2] Physically Based Shading at Disney
// http://blog.selfshadow.com/publications/s2012-shading-course/burley/s2012_pbs_disney_brdf_notes_v3.pdf
// [3] README.md - Environment Maps
// https://github.com/KhronosGroup/glTF-WebGL-PBR/#environment-maps
// [4] "An Inexpensive BRDF Model for Physically based Rendering" by Christophe Schlick
// https://www.cs.virginia.edu/~jdl/bib/appearance/analytic%20models/schlick94b.pdf
#define NORMALS
#define UV
#define HAS_NORMALS
#define USE_IBL
#define USE_TEX_LOD
Texture2D baseColourTexture : register(t0);
SamplerState baseColourSampler : register(s0);
Texture2D normalTexture : register(t1);
SamplerState normalSampler : register(s1);
Texture2D emissionTexture : register(t2);
SamplerState emissionSampler : register(s2);
Texture2D occlusionTexture : register(t3);
SamplerState occlusionSampler : register(s3);
Texture2D metallicRoughnessTexture : register(t4);
SamplerState metallicRoughnessSampler : register(s4);
TextureCube envDiffuseTexture : register(t8);
SamplerState envDiffuseSampler : register(s8);
Texture2D brdfLutTexture : register(t9);
SamplerState brdfLutSampler : register(s9);
TextureCube envSpecularTexture : register(t10);
SamplerState envSpecularSampler : register(s10);
struct Light
{
float3 dir;
float padding1;
float3 colour;
float padding2;
};
cbuffer cbPerFrame : register(b0)
{
Light light;
};
cbuffer cbPerObject : register(b1)
{
float normalScale;
float3 emissiveFactor;
float occlusionStrength;
float2 metallicRoughnessValues;
float padding1;
float4 baseColorFactor;
float3 camera;
float padding2;
// debugging flags used for shader output of intermediate PBR variables
float4 scaleDiffBaseMR;
float4 scaleFGDSpec;
float4 scaleIBLAmbient;
};
// Per-pixel color data passed through the pixel shader.
struct PixelShaderInput
{
float4 position : SV_POSITION;
float3 poswithoutw : POSITION;
#ifdef NORMALS
float3 normal : NORMAL;
#endif
#ifdef UV
float2 texcoord : TEXCOORD0;
#endif
};
#ifdef HAS_NORMALS
#ifdef HAS_TANGENTS
varying mat3 v_TBN;
#else
#endif
#endif
// Encapsulate the various inputs used by the various functions in the shading equation
// We store values in this struct to simplify the integration of alternative implementations
// of the shading terms, outlined in the Readme.MD Appendix.
struct PBRInfo
{
float NdotL; // cos angle between normal and light direction
float NdotV; // cos angle between normal and view direction
float NdotH; // cos angle between normal and half vector
float LdotH; // cos angle between light direction and half vector
float VdotH; // cos angle between view direction and half vector
float perceptualRoughness; // roughness value, as authored by the model creator (input to shader)
float metalness; // metallic value at the surface
float3 reflectance0; // full reflectance color (normal incidence angle)
float3 reflectance90; // reflectance color at grazing angle
float alphaRoughness; // roughness mapped to a more linear change in the roughness (proposed by [2])
float3 diffuseColor; // color contribution from diffuse lighting
float3 specularColor; // color contribution from specular lighting
};
static const float M_PI = 3.141592653589793;
static const float c_MinRoughness = 0.04;
float4 SRGBtoLINEAR(float4 srgbIn)
{
#ifdef MANUAL_SRGB
#ifdef SRGB_FAST_APPROXIMATION
float3 linOut = pow(srgbIn.xyz,float3(2.2, 2.2, 2.2));
#else //SRGB_FAST_APPROXIMATION
float3 bLess = step(float3(0.04045, 0.04045, 0.04045), srgbIn.xyz);
float3 linOut = lerp(srgbIn.xyz / float3(12.92, 12.92, 12.92), pow((srgbIn.xyz + float3(0.055, 0.055, 0.055)) / float3(1.055, 1.055, 1.055), float3(2.4, 2.4, 2.4)), bLess);
#endif //SRGB_FAST_APPROXIMATION
return float4(linOut,srgbIn.w);;
#else //MANUAL_SRGB
return srgbIn;
#endif //MANUAL_SRGB
}
// Find the normal for this fragment, pulling either from a predefined normal map
// or from the interpolated mesh normal and tangent attributes.
float3 getNormal(float3 position, float3 normal, float2 uv)
{
// Retrieve the tangent space matrix
#ifndef HAS_TANGENTS
float3 pos_dx = ddx(position);
float3 pos_dy = ddy(position);
float3 tex_dx = ddx(float3(uv, 0.0));
float3 tex_dy = ddy(float3(uv, 0.0));
float3 t = (tex_dy.y * pos_dx - tex_dx.y * pos_dy) / (tex_dx.x * tex_dy.y - tex_dy.x * tex_dx.y);
#ifdef HAS_NORMALS
float3 ng = normalize(normal);
#else
float3 ng = cross(pos_dx, pos_dy);
#endif
t = normalize(t - ng * dot(ng, t));
float3 b = normalize(cross(ng, t));
row_major float3x3 tbn = float3x3(t, b, ng);
#else // HAS_TANGENTS
mat3 tbn = v_TBN;
#endif
#ifdef HAS_NORMALMAP
float3 n = normalTexture.Sample(normalSampler, uv).rgb;
// Need to check the multiplication is equivalent..
n = normalize(mul(((2.0 * n - 1.0) * float3(normalScale, normalScale, 1.0)), tbn));
#else
float3 n = tbn[2].xyz;
#endif
return n;
}
#ifdef USE_IBL
// Calculation of the lighting contribution from an optional Image Based Light source.
// Precomputed Environment Maps are required uniform inputs and are computed as outlined in [1].
// See our README.md on Environment Maps [3] for additional discussion.
float3 getIBLContribution(PBRInfo pbrInputs, float3 n, float3 reflection)
{
float mipCount = 9.0; // resolution of 512x512
float lod = (pbrInputs.perceptualRoughness * mipCount);
// retrieve a scale and bias to F0. See [1], Figure 3
float2 val = float2(pbrInputs.NdotV, 1.0 - pbrInputs.perceptualRoughness);
float3 brdf = SRGBtoLINEAR(brdfLutTexture.Sample(brdfLutSampler, val)).rgb;
float3 diffuseLight = SRGBtoLINEAR(envDiffuseTexture.Sample(envDiffuseSampler, n)).rgb;
#ifdef USE_TEX_LOD
float3 specularLight = SRGBtoLINEAR(envSpecularTexture.SampleLevel(envSpecularSampler, reflection, 0)).rgb;
#else
float3 specularLight = SRGBtoLINEAR(envSpecularTexture.Sample(envSpecularSampler, reflection)).rgb;
#endif
float3 diffuse = diffuseLight * pbrInputs.diffuseColor;
float3 specular = specularLight * (pbrInputs.specularColor * brdf.x + brdf.y);
// For presentation, this allows us to disable IBL terms
diffuse *= scaleIBLAmbient.x;
specular *= scaleIBLAmbient.y;
return diffuse + specular;
}
#endif
// Basic Lambertian diffuse
// Implementation from Lambert's Photometria https://archive.org/details/lambertsphotome00lambgoog
// See also [1], Equation 1
float3 diffuse(PBRInfo pbrInputs)
{
return pbrInputs.diffuseColor / M_PI;
}
// The following equation models the Fresnel reflectance term of the spec equation (aka F())
// Implementation of fresnel from [4], Equation 15
float3 specularReflection(PBRInfo pbrInputs)
{
return pbrInputs.reflectance0 + (pbrInputs.reflectance90 - pbrInputs.reflectance0) * pow(clamp(1.0 - pbrInputs.VdotH, 0.0, 1.0), 5.0);
}
// This calculates the specular geometric attenuation (aka G()),
// where rougher material will reflect less light back to the viewer.
// This implementation is based on [1] Equation 4, and we adopt their modifications to
// alphaRoughness as input as originally proposed in [2].
float geometricOcclusion(PBRInfo pbrInputs)
{
float NdotL = pbrInputs.NdotL;
float NdotV = pbrInputs.NdotV;
float r = pbrInputs.alphaRoughness;
float attenuationL = 2.0 * NdotL / (NdotL + sqrt(r * r + (1.0 - r * r) * (NdotL * NdotL)));
float attenuationV = 2.0 * NdotV / (NdotV + sqrt(r * r + (1.0 - r * r) * (NdotV * NdotV)));
return attenuationL * attenuationV;
}
// The following equation(s) model the distribution of microfacet normals across the area being drawn (aka D())
// Implementation from "Average Irregularity Representation of a Roughened Surface for Ray Reflection" by T. S. Trowbridge, and K. P. Reitz
// Follows the distribution function recommended in the SIGGRAPH 2013 course notes from EPIC Games [1], Equation 3.
float microfacetDistribution(PBRInfo pbrInputs)
{
float roughnessSq = pbrInputs.alphaRoughness * pbrInputs.alphaRoughness;
float f = (pbrInputs.NdotH * roughnessSq - pbrInputs.NdotH) * pbrInputs.NdotH + 1.0;
return roughnessSq / (M_PI * f * f);
}
float4 main(PixelShaderInput input) : SV_TARGET
{
// Metallic and Roughness material properties are packed together
// In glTF, these factors can be specified by fixed scalar values
// or from a metallic-roughness map
float perceptualRoughness = metallicRoughnessValues.y;
float metallic = metallicRoughnessValues.x;
#ifdef HAS_METALROUGHNESSMAP
// Roughness is stored in the 'g' channel, metallic is stored in the 'b' channel.
// This layout intentionally reserves the 'r' channel for (optional) occlusion map data
float4 mrSample = metallicRoughnessTexture.Sample(metallicRoughnessSampler, input.texcoord);
// Had to reverse the order of the channels here - TODO: investigate..
perceptualRoughness = mrSample.g * perceptualRoughness;
metallic = mrSample.b * metallic;
#endif
perceptualRoughness = clamp(perceptualRoughness, c_MinRoughness, 1.0);
metallic = clamp(metallic, 0.0, 1.0);
// Roughness is authored as perceptual roughness; as is convention,
// convert to material roughness by squaring the perceptual roughness [2].
float alphaRoughness = perceptualRoughness * perceptualRoughness;
// The albedo may be defined from a base texture or a flat color
#ifdef HAS_BASECOLORMAP
float4 baseColor = SRGBtoLINEAR(baseColourTexture.Sample(baseColourSampler, input.texcoord)) * baseColorFactor;
#else
float4 baseColor = baseColorFactor;
#endif
float3 f0 = float3(0.04, 0.04, 0.04);
float3 diffuseColor = baseColor.rgb * (float3(1.0, 1.0, 1.0) - f0);
diffuseColor *= 1.0 - metallic;
float3 specularColor = lerp(f0, baseColor.rgb, metallic);
// Compute reflectance.
float reflectance = max(max(specularColor.r, specularColor.g), specularColor.b);
// For typical incident reflectance range (between 4% to 100%) set the grazing reflectance to 100% for typical fresnel effect.
// For very low reflectance range on highly diffuse objects (below 4%), incrementally reduce grazing reflecance to 0%.
float reflectance90 = clamp(reflectance * 25.0, 0.0, 1.0);
float3 specularEnvironmentR0 = specularColor.rgb;
float3 specularEnvironmentR90 = float3(1.0, 1.0, 1.0) * reflectance90;
float3 n = getNormal(input.poswithoutw, input.normal, input.texcoord); // normal at surface point
float3 v = normalize(camera - input.poswithoutw); // Vector from surface point to camera
float3 l = normalize(light.dir); // Vector from surface point to light
float3 h = normalize(l + v); // Half vector between both l and v
float3 reflection = -normalize(reflect(v, n));
float NdotL = clamp(dot(n, l), 0.001, 1.0);
float NdotV = abs(dot(n, v)) + 0.001;
float NdotH = clamp(dot(n, h), 0.0, 1.0);
float LdotH = clamp(dot(l, h), 0.0, 1.0);
float VdotH = clamp(dot(v, h), 0.0, 1.0);
PBRInfo pbrInputs;
pbrInputs.NdotL = NdotL;
pbrInputs.NdotV = NdotV;
pbrInputs.NdotH = NdotH;
pbrInputs.LdotH = LdotH;
pbrInputs.VdotH = VdotH;
pbrInputs.perceptualRoughness = perceptualRoughness;
pbrInputs.metalness = metallic;
pbrInputs.reflectance0 = specularEnvironmentR0;
pbrInputs.reflectance90 = specularEnvironmentR90;
pbrInputs.alphaRoughness = alphaRoughness;
pbrInputs.diffuseColor = diffuseColor;
pbrInputs.specularColor = specularColor;
// Calculate the shading terms for the microfacet specular shading model
float3 F = specularReflection(pbrInputs);
float G = geometricOcclusion(pbrInputs);
float D = microfacetDistribution(pbrInputs);
// Calculation of analytical lighting contribution
float3 diffuseContrib = (1.0 - F) * diffuse(pbrInputs);
float3 specContrib = F * G * D / (4.0 * NdotL * NdotV);
float3 color = NdotL * light.colour * (diffuseContrib + specContrib);
// Calculate lighting contribution from image based lighting source (IBL)
#ifdef USE_IBL
color += getIBLContribution(pbrInputs, n, reflection);
#endif
// Apply optional PBR terms for additional (optional) shading
#ifdef HAS_OCCLUSIONMAP
float ao = occlusionTexture.Sample(occlusionSampler, input.texcoord).r;
color = lerp(color, color * ao, occlusionStrength);
#endif
#ifdef HAS_EMISSIVEMAP
float3 emissive = SRGBtoLINEAR(emissionTexture.Sample(emissionSampler, input.texcoord)).rgb * emissiveFactor;
color += emissive;
#endif
// This section uses lerp to override final color for reference app visualization
// of various parameters in the lighting equation.
color = lerp(color, F, scaleFGDSpec.x);
color = lerp(color, float3(G, G, G), scaleFGDSpec.y);
color = lerp(color, float3(D, D, D), scaleFGDSpec.z);
color = lerp(color, specContrib, scaleFGDSpec.w);
color = lerp(color, diffuseContrib, scaleDiffBaseMR.x);
color = lerp(color, baseColor.rgb, scaleDiffBaseMR.y);
color = lerp(color, float3(metallic, metallic, metallic), scaleDiffBaseMR.z);
color = lerp(color, float3(perceptualRoughness, perceptualRoughness, perceptualRoughness), scaleDiffBaseMR.w);
return float4(color, 1.0);
}

Просмотреть файл

@ -0,0 +1,73 @@
//#define NORMALS
//#define UV
// A constant buffer that stores the three basic column-major matrices for composing geometry.
cbuffer ModelViewProjectionConstantBuffer : register(b0)
{
matrix model;
matrix view;
matrix projection;
};
// Per-vertex data used as input to the vertex shader.
struct VertexShaderInput
{
float4 position : POSITION;
#ifdef NORMALS
float3 normal : NORMAL;
#endif
#ifdef UV
float2 texcoord : TEXCOORD0;
#endif
};
// Per-pixel color data passed through the pixel shader.
struct PixelShaderInput
{
float4 position : SV_POSITION;
float3 poswithoutw : POSITION;
#ifdef NORMALS
float3 normal : NORMAL;
#endif
float2 texcoord : TEXCOORD0;
};
PixelShaderInput main(VertexShaderInput input)
{
PixelShaderInput output;
// Transform the vertex position into projected space.
float4 pos = mul(input.position, model);
output.poswithoutw = float3(pos.xyz) / pos.w;
#ifdef NORMALS
// If we have normals...
output.normal = normalize(mul(float4(input.normal.xyz, 0.0), model));
#endif
#ifdef UV
output.texcoord = input.texcoord;
#else
output.texcoord = float2(0.0f, 0.0f);
#endif
#ifdef HAS_NORMALS
#ifdef HAS_TANGENTS
vec3 normalW = normalize(vec3(u_ModelMatrix * vec4(a_Normal.xyz, 0.0)));
vec3 tangentW = normalize(vec3(u_ModelMatrix * vec4(a_Tangent.xyz, 0.0)));
vec3 bitangentW = cross(normalW, tangentW) * a_Tangent.w;
v_TBN = mat3(tangentW, bitangentW, normalW);
#else // HAS_TANGENTS != 1
v_Normal = normalize(vec3(u_ModelMatrix * vec4(a_Normal.xyz, 0.0)));
#endif
#endif
// Transform the vertex position into projected space.
pos = mul(pos, view);
pos = mul(pos, projection);
output.position = pos;
return output;
}

Двоичные данные
ModelViewer/Assets/SplashScreen.scale-200.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 7.5 KiB

Двоичные данные
ModelViewer/Assets/Square150x150Logo.scale-200.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 2.9 KiB

Двоичные данные
ModelViewer/Assets/Square44x44Logo.scale-200.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.6 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.2 KiB

Двоичные данные
ModelViewer/Assets/StoreLogo.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.4 KiB

Двоичные данные
ModelViewer/Assets/Wide310x150Logo.scale-200.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 3.1 KiB

Двоичные данные
ModelViewer/Assets/textures/brdfLUT.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 16 KiB

Двоичные данные
ModelViewer/Assets/textures/papermill/diffuse/diffuse_back_0.jpg Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 24 KiB

Двоичные данные
ModelViewer/Assets/textures/papermill/diffuse/diffuse_bottom_0.jpg Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 23 KiB

Двоичные данные
ModelViewer/Assets/textures/papermill/diffuse/diffuse_front_0.jpg Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 22 KiB

Двоичные данные
ModelViewer/Assets/textures/papermill/diffuse/diffuse_left_0.jpg Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 24 KiB

Двоичные данные
ModelViewer/Assets/textures/papermill/diffuse/diffuse_right_0.jpg Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 23 KiB

Двоичные данные
ModelViewer/Assets/textures/papermill/diffuse/diffuse_top_0.jpg Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 18 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 140 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 107 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 148 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 126 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 137 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 145 KiB

Двоичные данные
ModelViewer/Assets/textures/papermill/specular/specular_back_0.jpg Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 173 KiB

Двоичные данные
ModelViewer/Assets/textures/papermill/specular/specular_back_1.jpg Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 45 KiB

Двоичные данные
ModelViewer/Assets/textures/papermill/specular/specular_back_2.jpg Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 29 KiB

Двоичные данные
ModelViewer/Assets/textures/papermill/specular/specular_back_3.jpg Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 25 KiB

Двоичные данные
ModelViewer/Assets/textures/papermill/specular/specular_back_4.jpg Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 24 KiB

Двоичные данные
ModelViewer/Assets/textures/papermill/specular/specular_back_5.jpg Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 23 KiB

Двоичные данные
ModelViewer/Assets/textures/papermill/specular/specular_back_6.jpg Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 23 KiB

Двоичные данные
ModelViewer/Assets/textures/papermill/specular/specular_back_7.jpg Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 23 KiB

Двоичные данные
ModelViewer/Assets/textures/papermill/specular/specular_back_8.jpg Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 23 KiB

Двоичные данные
ModelViewer/Assets/textures/papermill/specular/specular_back_9.jpg Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 23 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 119 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 31 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 23 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 20 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 19 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 19 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 19 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 19 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 19 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 19 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 182 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 42 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 25 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 21 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 20 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 19 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 19 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 19 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 19 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 19 KiB

Двоичные данные
ModelViewer/Assets/textures/papermill/specular/specular_left_0.jpg Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 149 KiB

Двоичные данные
ModelViewer/Assets/textures/papermill/specular/specular_left_1.jpg Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 38 KiB

Двоичные данные
ModelViewer/Assets/textures/papermill/specular/specular_left_2.jpg Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 24 KiB

Двоичные данные
ModelViewer/Assets/textures/papermill/specular/specular_left_3.jpg Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 21 KiB

Двоичные данные
ModelViewer/Assets/textures/papermill/specular/specular_left_4.jpg Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 20 KiB

Двоичные данные
ModelViewer/Assets/textures/papermill/specular/specular_left_5.jpg Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 19 KiB

Двоичные данные
ModelViewer/Assets/textures/papermill/specular/specular_left_6.jpg Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 19 KiB

Двоичные данные
ModelViewer/Assets/textures/papermill/specular/specular_left_7.jpg Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 19 KiB

Двоичные данные
ModelViewer/Assets/textures/papermill/specular/specular_left_8.jpg Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 19 KiB

Двоичные данные
ModelViewer/Assets/textures/papermill/specular/specular_left_9.jpg Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 19 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 169 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 39 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 24 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 21 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 20 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 19 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 19 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 19 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 19 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 19 KiB

Двоичные данные
ModelViewer/Assets/textures/papermill/specular/specular_top_0.jpg Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 174 KiB

Двоичные данные
ModelViewer/Assets/textures/papermill/specular/specular_top_1.jpg Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 42 KiB

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше