Numero speciale del 2015 su Windows 10
Volume 30 Numero 11
Il presente articolo è stato tradotto automaticamente.
Elementi grafici e animazione - Composizione Windows e Windows 10
Da Kenny Kerr | Windows 2015
Il motore della composizione Windows, noto anche come la gestione (Finestre), ottiene una nuova API per Windows 10. DirectComposition è l'interfaccia principale per la composizione, ma, come un'API COM classico, non era accessibile principalmente allo sviluppatore di app medio. La nuova API di composizione Windows si basa su Windows Runtime (WinRT) e fornisce le basi per il rendering ad alte prestazioni da fusione del mondo di grafica in modalità immediata offerti da Direct2D e Direct3D con una struttura visiva mantenuta che propone ora l'animazione notevolmente migliorato e le funzionalità di effetti.
Ho scritto prima sulla gestione finestre desktop nel 2006 quando Windows Vista è stato in versione beta (goo.gl/19jCyR). È consentito di controllo dell'estensione dell'effetto di sfocatura per una determinata finestra e di creare un colore personalizzato che combinati correttamente con il desktop. Figura 1 illustra l'altezza di tale risultato in Windows 7. È stato possibile generare rendering con accelerazione hardware con Direct3D e Direct2D per creare elementi visivi di grande impatto per l'applicazione (goo.gl/IufcN1). È anche possibile fondere il mondo precedente di GDI e USER controlli con Gestione finestre desktop (goo.gl/9ITISE). Tuttavia, qualsiasi observer acuta dicessi che Gestione finestre desktop ha altro da offrire, molte altre. La funzionalità Windows Flip 3D in Windows 7 è stata convincere la prova.
Figura 1 Windows Aero
Windows 8 ha introdotto una nuova API per la gestione finestre desktop chiamato DirectComposition, il relativo nome fornendo tribute della famiglia DirectX di APIs COM classico ispirato la progettazione. DirectComposition ha iniziato a offrire agli sviluppatori un'immagine più chiara di ciò che era in grado di eseguire Gestione finestre desktop. Offriva inoltre migliorata la terminologia. Gestione finestre desktop è realmente il motore della composizione Windows è stato in grado di generare gli effetti in Windows Vista e Windows 7 perché è cambiato radicalmente il modo in cui il rendering di desktop windows. Per impostazione predefinita, il motore di composizione creata un'area di reindirizzamento per ogni finestra di primo livello. Questo descritto in dettaglio nel mio articolo di giugno 2014 (goo.gl/oMlVa4). Queste superfici di reindirizzamento formano parte di un struttura ad albero visuale e DirectComposition consentito App per avvalersi di questa stessa tecnologia per fornire una semplice API in modalità retain per immagini ad alte prestazioni. DirectComposition offerto una struttura ad albero visuale e la gestione della superficie consentiti app ripartire la produzione di effetti e animazioni al motore di composizione. Queste funzionalità descritto nel mio agosto (goo.gl/CNwnWR) e le colonne di settembre 2014 (goo.gl/y7ZMLL). Ho anche prodotto un corso sul rendering ad alte prestazioni con DirectComposition di formazione per Pluralsight (goo.gl/fgg0XN).
Windows 8 apparsi con DirectComposition, con miglioramenti al resto della famiglia DirectX di API, ma anche appartiene a una nuova era per l'API di Windows che potrebbero modificare per sempre il modo in cui gli sviluppatori di analizzare il sistema operativo. L'introduzione di Windows Runtime eclissato tutto il resto. Microsoft promesso un nuovo modo aggiornato per compilare applicazioni e accedere ai servizi del sistema operativo che è stato digitato il ritiro finale della cosiddetta API Win32 che fosse stata lungo il modo principale per compilare applicazioni e di interagire con il sistema operativo. Windows 8 rivelato Rocciose, avvio, ma Windows 8.1 fisso molti dei problemi e 10 Windows ora fornisce un'API molto più completa che consente di eliminare molti sviluppatori più interessati a creare app di prima classe, nay, gravi applicazioni per Windows.
Windows 10 fornito in luglio 2015 con un'anteprima della composizione nuova API non ancora pronto per la produzione. È stata ancora soggetta a modifiche e pertanto non può essere utilizzato in applicazioni Windows universali inviate al Windows Store. È altrettanto bene perché la composizione di API che è ora disponibile per la produzione è stato modificato sostanzialmente e di migliorare. Questo aggiornamento per Windows 10 è anche la prima volta che la stessa composizione API è disponibile in tutti i fattori di forma, che fornisce ulteriori credence per la parte della piattaforma Windows universale universale. Composizione funziona allo stesso modo indipendentemente dal fatto di destinazione il potente sistema desktop a multi-display o piccolo smartphone in tasca.
Naturalmente, l'aspetto di che tutti gli utenti mi piace sul Runtime di Windows è che infine offre la promessa di common language runtime per Windows. Se si preferisce codice in c#, è possibile utilizzare il Runtime di Windows direttamente tramite il supporto incorporato in Microsoft .NET Framework. Se, come me, preferibile utilizzare C++, è possibile utilizzare il Runtime di Windows con alcun astrazioni intermedie o costose. Windows Runtime è basato su COM anziché .NET e di conseguenza è adatto per l'utilizzo di C++. Verrà utilizzato per Windows Runtime C++ moderno (moderncpp.com), la proiezione di linguaggio C++ standard, ma è possibile proseguire nella lingua preferita come l'API è lo stesso, indipendentemente dal fatto che. Sarà offre anche alcuni esempi in c# per illustrare la facilità con cui Windows Runtime può supportare lingue diverse.
La composizione di Windows API distanze stesso dalle sue radici di DirectX. Mentre DirectComposition fornito un oggetto dispositivo, modellato dispositivi Direct3D e Direct2D, la nuova API di composizione Windows inizia con un filtro compositor. Tuttavia, svolge la stessa funzione, che funge da factory per le risorse di composizione. Inoltre, è molto simile a DirectComposition composizione di Windows. Esiste una destinazione di composizione che rappresenta la relazione tra una finestra e struttura ad albero visiva. Le differenze diventano più palese man mano che si esamina più da vicino gli oggetti visivi. Un visual DirectComposition era una proprietà di contenuto che ha fornito una bitmap di qualche tipo. La bitmap è stata una delle tre operazioni: una superficie di composizione, una catena di scambio DXGI o la superficie di reindirizzamento di un'altra finestra. Una tipica applicazione DirectComposition è costituito da elementi visivi e superfici, con le superfici che agisce come il contenuto o bitmap per gli oggetti visivi diversi. Come illustrato nella Figura 2, un struttura ad albero visuale di composizione è una potenza leggermente diverso. Nuovo oggetto visivo non dispone di alcuna proprietà di contenuto e viene invece eseguito il rendering con un pennello di composizione. Ciò risulta per essere un'astrazione più flessibile. Mentre il pennello può solo eseguire il rendering di una bitmap come prima, è possibile creare in modo efficiente i pennelli di colore a tinta unita semplice e pennelli più elaborati possono essere definite almeno concettualmente, in modo simile a come Direct2D fornisce gli effetti che possono essere considerati come immagini. L'astrazione destra rende essenziale.
Figura 2, la struttura visiva di composizione Windows
Passiamo a esaminare alcuni esempi pratici per illustrare il funzionamento di tutto questo e offrono informazioni di ciò che è possibile. Anche in questo caso, è possibile selezionare la proiezione di linguaggio WinRT Preferiti. È possibile creare un filtro compositor con C++ moderno, come indicato di seguito:
using namespace Windows::UI::Composition;
Compositor compositor;
Analogamente, è possibile eseguire la stessa operazione con c#:
using Windows.UI.Composition;
Compositor compositor = new Compositor();
È anche possibile utilizzare la sintassi più flamboyant offerta da C + + CX:
using namespace Windows::UI::Composition;
Compositor ^ compositor = ref new Compositor();
Questi sono equivalenti dal punto di vista dell'API e semplicemente riflettono le differenze nella proiezione della lingua. Esistono essenzialmente due i modi in cui è possibile scrivere un'app Windows universali oggi. Probabilmente l'approccio più comune consiste nell'utilizzare lo spazio dei nomi Windows.UI.Xaml del sistema operativo. Se XAML non è importante che l'applicazione, è possibile utilizzare anche il modello dell'applicazione sottostante direttamente con alcuna dipendenza in XAML. Il modello di applicazione WinRT descritto nel mio articolo dell'agosto 2013 (goo.gl/GI3OKP). Questo approccio, è sufficiente una semplice implementazione delle interfacce IFrameworkView e IFrameworkViewSource e sei pronto per iniziare. Figura 3 fornisce una struttura di base in c# che è possibile utilizzare per iniziare. Composizione di Windows offre inoltre una stretta integrazione con XAML, ma si inizia con una semplice applicazione prive di XAML in quanto forniscono un ambiente particelle più semplice in cui per informazioni sulla composizione. Otterrà in XAML un po' più avanti in questo articolo.
Figura 3 modello applicativo di Windows Runtime in c#
using Windows.ApplicationModel.Core;
using Windows.UI.Core;
class View : IFrameworkView, IFrameworkViewSource
{
static void Main()
{
CoreApplication.Run(new View());
}
public IFrameworkView CreateView()
{
return this;
}
public void SetWindow(CoreWindow window)
{
// Prepare composition resources here...
}
public void Run()
{
CoreWindow window = CoreWindow.GetForCurrentThread();
window.Activate();
window.Dispatcher.ProcessEvents(CoreProcessEventsOption.ProcessUntilQuit);
}
public void Initialize(CoreApplicationView applicationView) { }
public void Load(string entryPoint) { }
public void Uninitialize() { }
}
Si trova all'interno di metodo SetWindow dell'applicazione (vedere Figura 3) che deve essere costruito il compositor. In effetti, questo è il primo punto nel ciclo di vita dell'applicazione che ciò può verificarsi perché il compositor dipende dal dispatcher della finestra e questo è il punto in cui sia finestra dispatcher sono infine esistenti. È quindi possibile stabilire la relazione tra il compositor e la visualizzazione dell'applicazione mediante la creazione di una destinazione di composizione:
CompositionTarget m_target = nullptr;
// ...
m_target = compositor.CreateTargetForCurrentView();
È fondamentale che l'applicazione keep-alive della destinazione di composizione, prestare attenzione affinché sia una variabile membro di implementazione IFrameworkView. Come indicato in precedenza, la destinazione di composizione rappresenta la relazione tra la finestra o visualizzazione e la struttura ad albero visuale. È possibile semplicemente con una destinazione di composizione è impostato visual radice. In genere, si tratterà di un contenitore visual:
ContainerVisual root = compositor.CreateContainerVisual();
m_target.Root(root);
Qui utilizzo C++, che non dispone del supporto linguistico per le proprietà, in modo che la proprietà radice viene proiettata come metodi di accesso. C# è molto simile con l'aggiunta della sintassi proprietà:
ContainerVisual root = compositor.CreateContainerVisual();
m_target.Root = root;
DirectComposition fornito un solo tipo di visual, supportati diversi tipi di superfici per rappresentare il contenuto bitmap. Composizione di Windows offre gerarchie di classi di piccole dimensioni che rappresentano diversi tipi di elementi visivi, pennelli e animazioni, ma esiste un solo tipo di area e può essere creato solo utilizzando C++ perché fa parte dell'API di interoperabilità composizione Windows deve essere utilizzato dal framework come XAML e gli sviluppatori di applicazioni più sofisticati.
Viene illustrata la gerarchia di classe visual Figura 4. Un CompositionObject è una risorsa supportata dal compositor. Tutti gli oggetti di composizione potrebbero avere le relative proprietà animate. Un oggetto visivo offre una gamma di proprietà per controllare molti aspetti dell'oggetto visivo posizione relativa, aspetto, ritaglio e opzioni di rendering. Include una proprietà di matrice di trasformazione, nonché i tasti di scelta rapida per la scala e rotazione. Si tratta di una classe di base potente. Al contrario, ContainerVisual è una classe relativamente semplice che semplicemente aggiunge una proprietà di elementi figlio. Sebbene sia possibile creare direttamente elementi visivi di contenitore, un SpriteVisual aggiunge la possibilità di associare un pennello in modo che l'oggetto visivo può eseguire il rendering di pixel di un proprio.
Figura 4 elementi visivi di composizione
Dato un oggetto visivo contenitore radice, è possibile creare un numero qualsiasi di figlio degli elementi visivi:
VisualCollection children = root.Children();
Possono inoltre essere elementi visivi di contenitore, ma più probabilmente saranno elementi visivi sprite. Potrei aggiungere tre oggetti visivi come elementi figlio della radice visual utilizzando un ciclo for loop in C++:
using namespace Windows::Foundation::Numerics;
for (unsigned i = 0; i != 3; ++i)
{
SpriteVisual visual = compositor.CreateSpriteVisual();
visual.Size(Vector2{ 300.0f, 200.0f });
visual.Offset(Vector3{ 50 + 20.0f * i, 50 + 20.0f * i });
children.InsertAtTop(visual);
}
Si può facilmente immaginare finestra dell'app in Figura 5, e ancora non si osserva questo codice in un elemento viene eseguito il rendering perché non esiste nessun pennello associato a questi elementi visivi. Viene illustrata la gerarchia di classe pennello Figura 6. Un CompositionBrush è semplicemente una classe base per i pennelli e non fornisce alcuna funzionalità proprie. Un CompositionColorBrush è il tipo più semplice, che offrono solo una proprietà di colore per il rendering di elementi visivi di colore a tinta unita. Questo potrebbe non sembrare molto interessante, ma non dimenticare che è possibile connettersi animazioni a tale proprietà color. Le classi CompositionEffectBrush e CompositionSurfaceBrush sono correlate, ma sono più complessi pennelli perché si è supportati da altre risorse. Verrà eseguito il rendering di una superficie di composizione per tutti gli oggetti visivi collegati un CompositionSurfaceBrush. Include una serie di proprietà bitmap tale controllo, ad esempio interpolazione, l'allineamento e stretch, per non parlare la superficie di disegno. Un CompositionEffectBrush accetta un numero di superficie pennelli per produrre effetti diversi.
Figura 5 oggetti visivi figlio in una finestra
Figura 6 composizione pennelli
Creazione e applicazione di un pennello di colore è semplice. Di seguito è riportato un esempio in c#:
using Windows.UI;
CompositionColorBrush brush = compositor.CreateColorBrush();
brush.Color = Color.FromArgb(0xDC, 0x5B, 0x9B, 0xD5);
visual.Brush = brush;
La struttura Color viene fornito da Windows lo spazio dei nomi e sport alfa, rosso, verde e blu come valori di colore a 8 bit, deroga la preferenza DirectComposition e Direct2D per valori di colore a virgola mobile. Una funzionalità interessante di questo approccio per gli oggetti visivi e pennelli è che la proprietà del colore può essere modificata in qualsiasi momento e tutti gli elementi visivi che fa riferimento per lo stesso pennello verranno aggiornati automaticamente. In effetti, come ho accennavo alla prima, la proprietà color può anche essere animata. Come funziona? Questo ci porta per le classi di animazione.
La gerarchia di classi di animazione viene visualizzata Figura 7. La classe di base CompositionAnimation offre la possibilità di archiviare valori denominati per l'utilizzo con le espressioni. Più avanti parlerò sulle espressioni in un momento. Un KeyFrameAnimation fornisce le proprietà di animazioni basate su fotogramma chiave tipico come comportamento di durata, iterazione e stop. Le varie classi di animazione fotogramma chiave offrono metodi specifici del tipo per l'inserimento di fotogrammi chiave, nonché le proprietà dell'animazione specifici del tipo. Ad esempio, ColorKeyFrameAnimation consente di inserire i fotogrammi chiave con valori di colore e una proprietà per controllare lo spazio colore per interpolazione tra fotogrammi chiave.
Figura 7 composizione animazioni
Creazione di un oggetto di animazione e l'applicazione che l'animazione a un oggetto particolare composizione è sorprendentemente facile. Si supponga che si desidera animare l'opacità di un oggetto visivo. Potrei imposto opacità dell'oggetto visivo al 50% direttamente con un valore scalare in C++, come indicato di seguito:
visual.Opacity(0.5f);
In alternativa, è possibile creare un oggetto di scalare animazione con fotogrammi chiave per produrre una variabile di animazione compreso tra 0.0 e 1.0, che rappresenta 0% e 100 percento di opacità:
ScalarKeyFrameAnimation animation =
compositor.CreateScalarKeyFrameAnimation();
animation.InsertKeyFrame(0.0f, 0.0f); // Optional
animation.InsertKeyFrame(1.0f, 1.0f);
Il primo parametro InsertKeyFrame è relativo offset dall'inizio dell'animazione (0,0) alla fine dell'animazione (1.0). Il secondo parametro è il valore della variabile di animazione a quel punto nella sequenza temporale dell'animazione. Questa animazione verrà pertanto transizione graduale valore compreso tra 0,0 e 1,0 per tutta la durata dell'animazione. È quindi possibile impostare la durata complessiva di questa animazione, come indicato di seguito:
using namespace Windows::Foundation;
animation.Duration(TimeSpan::FromSeconds(1));
Con l'animazione pronta all'uso, è sufficiente collegarlo all'oggetto di composizione e alla proprietà di my scelta:
visual.StartAnimation(L"Opacity", animation);
Il metodo StartAnimation effettivamente viene ereditato dalla classe di base CompositionObject, vale a dire che è possibile animare le proprietà di una varietà di classi diverse. Si tratta di un altro punto di svolta rispetto DirectComposition, dove ogni possibile animare proprietà forniti overload per i valori scalari, come gli oggetti di animazione. Composizione di Windows offre un molto più completo sistema di proprietà che apre la strada ad alcune funzionalità molto interessante. In particolare, supporta la possibilità di scrivere espressioni testuali che consente di ridurre la quantità di codice che deve essere scritto per più interessanti di animazioni ed effetti. Queste espressioni vengono analizzate in fase di esecuzione compilato ed eseguito in modo efficiente dal motore della composizione Windows.
Immagina di che voler ruotare un oggetto visivo lungo l'asse Y e assegnargli l'aspetto di profondità. Proprietà RotationAngle dell'oggetto visivo, espresso in radianti, non è sufficiente poiché che non produce una trasformazione che include una prospettiva. Come ruota l'oggetto visivo, il bordo più vicino a occhio risulterà più grande, mentre il bordo opposto risulterà più piccolo. Figura 8 Mostra un numero di elementi visivi di rotazione che illustrano questo comportamento.
Figura 8 rotazione degli elementi visivi
Come viene eseguita tale effetto animato? Bene, cominciamo con un'animazione fotogramma chiave scalare per l'angolo di rotazione:
ScalarKeyFrameAnimation animation = compositor.CreateScalarKeyFrameAnimation();
animation.InsertKeyFrame(1.0f, 2.0f * Math::Pi,
compositor.CreateLinearEasingFunction());
animation.Duration(TimeSpan::FromSeconds(2));
animation.IterationBehavior(AnimationIterationBehavior::Forever);
La funzione di interpolazione lineare sostituisce la funzione di accelerazione/decelerazione predefinita per produrre un movimento di rotazione continuo. È quindi necessario definire un oggetto personalizzato con una proprietà che è possibile fare riferimento a dall'interno di un'espressione. Il filtro compositor fornisce una set di proprietà per solo a questo scopo:
CompositionPropertySet rotation = compositor.CreatePropertySet();
rotation.InsertScalar(L"Angle", 0.0f);
Un set di proprietà è anche un oggetto di composizione, pertanto è possibile utilizzare il metodo StartAnimation per animare la proprietà personalizzata in modo altrettanto semplice come qualsiasi proprietà predefinite:
rotation.StartAnimation(L"Angle", animation);
Ora è disponibile un oggetto la cui proprietà Angle è in continua evoluzione. È necessario definire una matrice di trasformazione per produrre l'effetto desiderato in fase di delega per questa proprietà per l'angolo di rotazione animata. Immettere espressioni:
ExpressionAnimation expression =
compositor.CreateExpressionAnimation(
L"pre * Matrix4x4.CreateFromAxisAngle(axis, rotation.Angle) * post");
Un'animazione di espressione non è un oggetto di animazione fotogramma chiave, pertanto non esiste alcun offset relativo fotogramma chiave animazione potrebbero modificare le variabili (in base a una funzione di interpolazione). Al contrario, le espressioni semplicemente riferiscono ai parametri che possono essere animati stessi nel senso più tradizionale. Tuttavia, spetta a me per definire quali "pre" sono "asse", "rotazione" e "post". Iniziamo con il parametro asse:
expression.SetVector3Parameter(L"axis", Vector3{ 0.0f, 1.0f, 0.0f });
Il metodo CreateFromAxisAngle all'interno dell'espressione è previsto un asse di rotazione intorno e definisce l'asse attorno all'asse Y. Prevede inoltre un angolo di rotazione e che è possibile rinviare a rotazione impostando la proprietà con la proprietà "Angolo" animata:
expression.SetReferenceParameter(L"rotation", rotation);
Per assicurarsi che la rotazione verrà eseguita tramite il centro dell'oggetto visivo, piuttosto che il bordo sinistro, è necessario pre-moltiplicare la matrice di rotazione creata da CreateFromAxisAngle con una traduzione che passa in modo logico l'asse per il punto di rotazione:
expression.SetMatrix4x4Parameter(
L"pre", Matrix4x4::Translation(-width / 2.0f, -height / 2.0f, 0.0f));
Tenere presente che la moltiplicazione non è commutativa, pertanto le matrici di pre e post sono davvero tutto ciò. Infine, dopo la matrice di rotazione, è possibile aggiungere nuove prospettive e quindi ripristinare l'oggetto visivo nella posizione originale:
expression.SetMatrix4x4Parameter(
L"post", Matrix4x4::PerspectiveProjection(width * 2.0f) *
Matrix4x4::Translation(width / 2.0f, height / 2.0f, 0.0f));
Questo soddisfa tutti i parametri a cui fa riferimento l'espressione e semplicemente ora è possibile utilizzare l'animazione di espressione per animare l'oggetto visivo utilizzando la relativa proprietà TransformMatrix:
visual.StartAnimation(L"TransformMatrix", expression);
Quindi ho studiato vari modi per creare, compilare e animare oggetti visivi, ma cosa accade se è necessario eseguire il rendering degli elementi visivi direttamente? DirectComposition offerto preassegnate superfici sia scarsamente allocata bitmap chiamata superfici virtuali che sono state allocate su richiesta e inoltre ridimensionabile. Composizione di Windows non fornisce apparentemente alcuna possibilità di creare superfici. Esiste una classe CompositionDrawingSurface, ma non è possibile crearlo senza supporto esterno. La risposta proviene dall'API di interoperabilità di composizione di Windows. Le classi WinRT potrebbero implementare ulteriori interfacce COM non direttamente visibili se si dispone di metadati di Windows di un componente. In base alla conoscenza di queste interfacce mascherate, è facile eseguire query per tali in C++. Naturalmente, questo sarà un po' più difficoltoso in quanto è l'esecuzione di istruzioni di fuori di astrazioni brillante fornite agli sviluppatori tradizionali per la composizione di Windows API. La prima cosa da fare è creare un dispositivo di rendering e si utilizzerà Direct3D 11 poiché composizione Windows non supporta ancora Direct3D 12:
ComPtr<ID3D11Device> direct3dDevice;
Verrà quindi preparare il dispositivo di flag di creazione:
unsigned flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT |
D3D11_CREATE_DEVICE_SINGLETHREADED;
#ifdef _DEBUG
flags |= D3D11_CREATE_DEVICE_DEBUG;
#endif
Il supporto BGRA mi consente di utilizzare l'API Direct2D più accessibile per il rendering con questo dispositivo e quindi la funzione D3D11CreateDevice crea il dispositivo hardware stesso:
check(D3D11CreateDevice(nullptr, // Adapter
D3D_DRIVER_TYPE_HARDWARE,
nullptr, // Module
flags,
nullptr, 0, // Highest available feature level
D3D11_SDK_VERSION,
set(direct3dDevice),
nullptr, // Actual feature level
nullptr)); // Device context
Quindi è necessario eseguire una query per l'interfaccia DXGI del dispositivo, perché questo è ciò che è necessario creare un dispositivo Direct2D:
ComPtr<IDXGIDevice3> dxgiDevice = direct3dDevice.As<IDXGIDevice3>();
Ora è necessario creare il dispositivo Direct2D stesso:
ComPtr<ID2D1Device> direct2dDevice;
In questo caso, anche in questo caso, consegna a livello di debug per la diagnostica aggiuntivo:
D2D1_CREATION_PROPERTIES properties = {};
#ifdef _DEBUG
properties.debugLevel = D2D1_DEBUG_LEVEL_INFORMATION;
#endif
Potrei creare innanzitutto una factory di Direct2D per creare il dispositivo. Sarebbe utile se è necessario creare tutte le risorse indipendenti dal dispositivo. Qui utilizzerò il collegamento fornito dalla funzione D2D1CreateDevice:
check(D2D1CreateDevice(get(dxgiDevice), properties, set(direct2dDevice)));
Il dispositivo di rendering è pronto. Ho un dispositivo Direct2D che posso utilizzare per eseguire il rendering di qualsiasi posso immaginare. È necessario indicare il motore della composizione Windows sul dispositivo per il rendering. Si tratta in quelli mascherati interfacce sono disponibili. Dato il compositor che ho utilizzato in tutto, è possibile eseguire una query per l'interfaccia ICompositorInterop:
namespace abi = ABI::Windows::UI::Composition;
ComPtr<abi::ICompositorInterop> compositorInterop;
check(compositor->QueryInterface(set(compositorInterop)));
ICompositorInterop fornisce metodi per la creazione di una superficie di composizione da una superficie DXGI, sarebbe utile se si desidera includere una catena di scambio esistente in un struttura ad albero visuale di composizione, ma fornisce un altro elemento che è molto più interessante. Il metodo CreateGraphicsDevice verrà creato un oggetto CompositionGraphicsDevice ha un dispositivo di rendering. La classe CompositionGraphicsDevice è una classe normale della composizione Windows API, anziché un'interfaccia mascherata, ma non fornisce un costruttore pertanto è necessario utilizzare C++ e l'interfaccia ICompositorInterop per crearla:
CompositionGraphicsDevice device = nullptr;
check(compositorInterop->CreateGraphicsDevice(get(direct2dDevice), set(device)));
Poiché CompositionGraphicsDevice è un tipo di WinRT, è possibile utilizzare nuovamente C++ moderno, piuttosto che i puntatori e la gestione degli errori manuali. Ed è CompositionGraphicsDevice che infine mi consente di creare una superficie di composizione:
using namespace Windows::Graphics::DirectX;
CompositionDrawingSurface surface =
compositionDevice.CreateDrawingSurface(Size{ 100, 100 },
DirectXPixelFormat::B8G8R8A8UIntNormalized,
CompositionAlphaMode::Premultiplied);
Di seguito sto creando una superficie 100 x 100 pixel di composizione di dimensioni. Si noti che rappresenta il pixel fisici anziché l'operatore logico e coordina compatibile con DPI presuppone e fornito dal resto della composizione Windows. La superficie fornisce anche a 32 bit con fusione alfa per il rendering supportato da Direct2D. Naturalmente, Direct3D e Direct2D non sono ancora disponibili tramite il Runtime di Windows, pertanto è tornata a interfacce mascherate per disegnare effettivamente a questa area:
ComPtr<abi::ICompositionDrawingSurfaceInterop> surfaceInterop;
check(surface->QueryInterface(set(surfaceInterop)));
Come DirectComposition prima, composizione Windows fornisce molto BeginDraw ed EndDraw metodi sull'interfaccia ICompositionDrawingSurfaceInterop di classificare e al posto delle chiamate tipiche per le chiamate del metodo Direct2D che seguono gli stessi nomi:
ComPtr<ID2D1DeviceContext> dc;
POINT offset = {};
check(surfaceInterop->BeginDraw(nullptr, // Update rect
__uuidof(dc),
reinterpret_cast<void **>(set(dc)),
&offset));
Composizione di Windows richiede il dispositivo di rendering originale fornito al momento il dispositivo di composizione è stato creato e viene utilizzato per creare un contesto di dispositivo o di destinazione di rendering. Sia possibile fornire facoltativamente un rettangolo di ridimensionamento in pixel fisici, ma qui sono appena scelta per l'accesso illimitato all'area di rendering. BeginDraw restituisce anche un offset nuovamente in pixel fisici, che indica l'origine dell'area di disegno desiderato. Questo non è necessariamente l'angolo superiore sinistro della destinazione di rendering e prestare attenzione per modificare o trasformare i comandi di disegno da gestire correttamente l'offset. Nuovamente, non chiamare BeginDraw sulla destinazione di rendering come composizione Windows ha già eseguito questa operazione automaticamente. Questa destinazione di rendering è di proprietà in modo logico la composizione di API e prestare attenzione per non conservare che segue la chiamata a EndDraw. La destinazione di rendering è ora pronta all'uso, ma non riconosce i DPI effettivo o logico per la visualizzazione. È possibile utilizzare lo spazio dei nomi Windows::Graphics::Display per ottenere DPI logico per la visualizzazione corrente e imposta il DPI che verrà utilizzato da Direct2D per il rendering:
using namespace Windows::Graphics::Display;
DisplayInformation display = DisplayInformation::GetForCurrentView();
float const dpi = display.LogicalDpi();
dc->SetDpi(dpi, dpi);
Il passaggio finale prima di procedere per il rendering di è gestire l'offset di composizione in qualche modo. Una soluzione semplice è utilizzare l'offset per produrre una matrice di trasformazione. È importante ricordare che Direct2D tondo in pixel logici, è necessario utilizzare non solo l'offset, ma il valore DPI appena stabilito:
dc->SetTransform(D2D1::Matrix3x2F::Translation(offset.x * 96.0f / dpi,
offset.y * 96.0f / dpi));
A questo punto, è possibile disegnare piacere prima di chiamare il metodo EndDraw sull'interfaccia di interoperabilità della superficie per garantire che qualsiasi Direct2D batch vengono elaborati i comandi di disegno e nell'area vengono riflesse nella struttura visiva composizione:
check(surfaceInterop->EndDraw());
Naturalmente, non ho ancora associato un oggetto visivo di area di e, come ho accennato, forniscono una proprietà di contenuto non è più elementi visivi e devono essere eseguito il rendering utilizzando un pennello. Fortunatamente, il filtro compositor verrà creato un pennello per rappresentare una superficie esistente:
CompositionSurfaceBrush brush = compositor.CreateSurfaceBrush(surface);
È possibile quindi creare un pennello sprite normale e utilizza il pennello per portare l'oggetto visivo chiaro:
SpriteVisual visual = compositor.CreateSpriteVisual();
visual.Brush(brush);
visual.Size(Vector2{ ... });
Se non è sufficiente l'interoperabilità per l'utente, è possibile anche richiedere un elemento XAML e recuperare l'oggetto visivo composizione sottostante. Di seguito è riportato un esempio in c#:
using Windows.UI.Xaml.Hosting;
Visual visual = ElementCompositionPreview.GetElementVisual(button);
Nonostante lo stato temporaneo apparentemente ElementCompositionPreview in realtà è pronto per la produzione e può essere utilizzato da applicazioni inviate al Windows Store. Dato un elemento dell'interfaccia utente, il metodo statico GetElementVisual restituirà l'oggetto visivo la struttura visiva di composizione sottostante. Si noti che restituisce un oggetto visivo anziché un ContainerVisual o SpriteVisual, direttamente non è possibile lavorare con elementi figlio visivi o applicare un pennello, ma è possibile modificare le proprietà visive molti offerte dalla composizione di Windows. La classe helper ElementCompositionPreview fornisce alcuni metodi statici aggiuntive per l'aggiunta di oggetti visivi figlio in modo controllato. È possibile modificare l'offset dell'oggetto visivo e operazioni quali l'interfaccia utente hit testing verrà continuano a funzionare a livello di codice XAML. È anche possibile applicare un'animazione direttamente con composizione Windows senza interrompere l'infrastruttura di XAML di base. Creiamo una semplice animazione scalare per il pulsante di rotazione. È necessario recuperare il compositor da visual, quindi creando un oggetto di animazione funziona come prima:
Compositor compositor = visual.Compositor;
ScalarKeyFrameAnimation animation = compositor.CreateScalarKeyFrameAnimation();
È opportuno creare una semplice animazione per ruotare lentamente sul pulsante per sempre con una funzione di interpolazione lineare:
animation.InsertKeyFrame(1.0f, (float) (2 * Math.PI),
compositor.CreateLinearEasingFunction());
Quindi è possibile indicare che una singola rotazione di 3 secondi e continuare all'infinito:
animation.Duration = TimeSpan.FromSeconds(3);
animation.IterationBehavior = AnimationIterationBehavior.Forever;
Infine, la connessione semplicemente l'animazione all'oggetto visivo fornito da XAML, richiedendo al motore di composizione di animare la relativa proprietà RotationAngle:
visual.StartAnimation("RotationAngle", animation);
Anche se potrebbe essere possibile ottenuto questo risultato con XAML da solo, il motore della composizione Windows fornisce molto più potente e flessibile, dato che si trova in un livello di astrazione molto inferiore e indubbiamente può offrire prestazioni migliori. Se ad esempio composizione Windows fornisce le animazioni quaternion attualmente non supportate da XAML.
È molto più a parlare per quanto riguarda il motore della composizione Windows. Il mio modesto parere si tratta dell'API WinRT più innovativo per Data. La quantità di energia a disposizione è impressionante e, ancora, a differenza di così tante altre grandi dell'interfaccia utente e API grafiche, non introduce un impatto negativo sulle prestazioni o anche una curva di apprendimento proibitiva. In molti modi, la composizione di Windows è rappresentativo del tutto ciò che è buona e interessanti sulla piattaforma Windows.
È possibile trovare il team di composizione di Windows su Twitter: @WinComposition.
Kenny Kerrè un programmatore di computer basato su in Canada, nonché un autore per Pluralsight e Microsoft MVP. Partecipa al blog kennykerr.ca e seguirlo su Twitter: @kennykerr.
Grazie ai seguenti esperti tecnici Microsoft per la revisione di questo articolo: Mark Aldham, James Clarke, John Serna, Jeffrey stallo e Nick Waggoner