C++ OpenGL ES Viewer i C# (4 / 8 steg)
Steg 4: Skapa Windows plattform (ar) stöd lager
Vi måste nu lägga till Microsofts OpenGLES hjälpklass i delade C++ bridge projektet. Så Lägg bara till en klass som heter OpenGLES detta projekt.
Huvudet ska innehålla:
#pragma en gång
#include < EGL/egl.h >
klass OpenGLES
{
offentlig:
OpenGLES();
~ OpenGLES();
EGLSurface CreateSurface(Windows::UI::Xaml::Controls::SwapChainPanel^ panel, const Windows::Foundation::Size* renderSurfaceSize);
void DestroySurface (const EGLSurface yta);
void MakeCurrent (const EGLSurface yta);
EGLBoolean SwapBuffers(const EGLSurface surface);
void Reset();
privat:
void Initialize();
void Cleanup();
privat:
EGLDisplay mEglDisplay;
EGLContext mEglContext;
EGLConfig mEglConfig;
};
Och cpp-filen ska innehålla:
#include "OpenGLES.h"
#include < concrt.h >
#include < EGL/egl.h >
#include < EGL/eglext.h >
#include < EGL/eglplatform.h >
#include < angle_windowsstore.h >
med hjälp av namnområdet plattform;
med hjälp av namnområdet Windows::UI::Xaml::Controls;
med hjälp av namnområdet Windows::Foundation;
med hjälp av namnområdet Windows::Foundation::Collections;
OpenGLES::OpenGLES():
mEglConfig(nullptr),
mEglDisplay(EGL_NO_DISPLAY),
mEglContext(EGL_NO_CONTEXT)
{
Initialize();
}
OpenGLES::~OpenGLES()
{
CleanUp();
}
void OpenGLES::Initialize()
{
CONST EGLint configAttributes [] =
{
EGL_RED_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_BLUE_SIZE, 8,
EGL_ALPHA_SIZE, 8,
EGL_DEPTH_SIZE, 8,
EGL_STENCIL_SIZE, 8,
EGL_NONE
};
CONST EGLint contextAttributes [] =
{
EGL_CONTEXT_CLIENT_VERSION, 2,
EGL_NONE
};
CONST EGLint defaultDisplayAttributes [] =
{
Detta är display standardattributen, används för att begära VINKELNS D3D11 renderer.
eglInitialize kommer bara att lyckas med dessa attribut om maskinvaran stöder D3D11 funktionen nivå 10_0 +.
EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE,
EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER är en optimering som kan ha stora prestandafördelar på mobila enheter.
Dess syntax kan ändras, dock. Vänligen uppdatera din Visual Studio mallar om du får sammanställning problem med den.
EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER, EGL_TRUE,
EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE är ett alternativ som gör att vinkeln att automatiskt ringa
metoden IDXGIDevice3::Trim för programmet när det blir tillfälligt.
Ringa IDXGIDevice3::Trim när ett program avbryts är ett Windows Store ansökan certifiering krav.
EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE, EGL_TRUE,
EGL_NONE,
};
CONST EGLint fl9_3DisplayAttributes [] =
{
Dessa kan användas för att begära VINKELNS D3D11 renderer, med D3D11 funktionen nivå 9_3.
Dessa attribut används om anropet till eglInitialize misslyckas med display standardattributen.
EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE,
EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE, 9,
EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE, 3,
EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER, EGL_TRUE,
EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE, EGL_TRUE,
EGL_NONE,
};
CONST EGLint warpDisplayAttributes [] =
{
Dessa attribut kan användas för att begära D3D11 WARP.
De används om eglInitialize misslyckas med både standard display attribut och 9_3 display attribut.
EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE,
EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE,
EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER, EGL_TRUE,
EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE, EGL_TRUE,
EGL_NONE,
};
EGLConfig config = NULL;
eglGetPlatformDisplayEXT är ett alternativ till eglGetDisplay. Det tillåter oss att passera i display attribut används för att konfigurera D3D11.
PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT = reinterpret_cast
(eglGetProcAddress("eglGetPlatformDisplayEXT"));
om (! eglGetPlatformDisplayEXT)
{
kasta Exception::CreateException (E_FAIL, L "Kunde inte få funktion eglGetPlatformDisplayEXT");
}
//
För att initiera displayen, gör vi tre uppsättningar av samtal till eglGetPlatformDisplayEXT och eglInitialize, med varierande
parametrar som skickas till eglGetPlatformDisplayEXT:
1) de första samtal använder "defaultDisplayAttributes" som en parameter. Detta motsvarar D3D11 funktionen nivå 10_0 +.
2) om eglInitialize misslyckas för steg 1 (t.ex. eftersom 10_0 + inte stöds som standard GPU), då vi försöka igen
med "fl9_3DisplayAttributes". Detta motsvarar D3D11 funktionen nivå 9_3.
3) om eglInitialize misslyckas för steg 2 (t.ex. eftersom 9_3 + inte stöds som standard GPU), då vi försöka igen
med "warpDisplayAttributes". Detta motsvarar D3D11 funktionen nivå 11_0 i varp, en D3D11 programvara rasterizer.
//
Obs: På Windows Phone, vi #ifdef ut den första uppsättningen av samtal till eglPlatformDisplayEXT och eglInitialize.
Windows-telefoner enheter stöder endast D3D11 funktionen nivå 9_3, men Windows Phone emulator stöder 11_0 +.
Vi använder denna #ifdef för att begränsa telefonen emulator till funktionen nivå 9_3, vilket gör det beter sig mer liknande
verkliga Windows Phone-enheter.
Om du vill testa funktionen nivå 10_0 + i Windows Phone emulator bör du ta bort denna #ifdef.
//
#if (WINAPI_FAMILY! = WINAPI_FAMILY_PHONE_APP)
Detta försöker initiera EGL till D3D11 funktionen nivå 10_0 +. Se ovan kommentar för detaljer.
mEglDisplay = eglGetPlatformDisplayEXT (EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, defaultDisplayAttributes);
om (mEglDisplay == EGL_NO_DISPLAY)
{
kasta Exception::CreateException (E_FAIL, L "Misslyckades med att få EGL display");
}
om (eglInitialize (mEglDisplay, NULL, NULL) == EGL_FALSE)
#endif
{
Detta försöker initiera EGL till D3D11 funktionen nivå 9_3, om 10_0 + är tillgänglig (t.ex. om Windows Phone eller vissa Windows tabletter).
mEglDisplay = eglGetPlatformDisplayEXT (EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, fl9_3DisplayAttributes);
om (mEglDisplay == EGL_NO_DISPLAY)
{
kasta Exception::CreateException (E_FAIL, L "Misslyckades med att få EGL display");
}
om (eglInitialize (mEglDisplay, NULL, NULL) == EGL_FALSE)
{
Detta initierar EGL till D3D11 funktionen nivå 11_0 i varp, om 9_3 + är tillgängligt på standard GPU (t.ex. på Surface RT).
mEglDisplay = eglGetPlatformDisplayEXT (EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, warpDisplayAttributes);
om (mEglDisplay == EGL_NO_DISPLAY)
{
kasta Exception::CreateException (E_FAIL, L "Misslyckades med att få EGL display");
}
om (eglInitialize (mEglDisplay, NULL, NULL) == EGL_FALSE)
{
Om alla samtal till eglInitialize returneras EGL_FALSE har sedan ett fel uppstått.
kasta Exception::CreateException (E_FAIL, L "Gick inte att initiera EGL");
}
}
}
EGLint numConfigs = 0;
om ((eglChooseConfig (mEglDisplay, configAttributes, & mEglConfig, 1 & numConfigs) == EGL_FALSE) || (numConfigs == 0))
{
kasta Exception::CreateException (E_FAIL, L "Kunde inte välja första EGLConfig");
}
mEglContext = eglCreateContext (mEglDisplay, mEglConfig, EGL_NO_CONTEXT, contextAttributes);
om (mEglContext == EGL_NO_CONTEXT)
{
kasta Exception::CreateException (E_FAIL, L "Kunde inte skapa EGL sammanhang");
}
}
void OpenGLES::Cleanup()
{
om (mEglDisplay! = EGL_NO_DISPLAY & & mEglContext! = EGL_NO_CONTEXT)
{
eglDestroyContext (mEglDisplay, mEglContext);
mEglContext = EGL_NO_CONTEXT;
}
om (mEglDisplay! = EGL_NO_DISPLAY)
{
eglTerminate(mEglDisplay);
mEglDisplay = EGL_NO_DISPLAY;
}
}
void OpenGLES::Reset()
{
CleanUp();
Initialize();
}
EGLSurface OpenGLES::CreateSurface(SwapChainPanel^ panel, const Size* renderSurfaceSize)
{
om (! panel)
{
kasta Exception::CreateException (E_INVALIDARG, L "SwapChainPanel parametern är ogiltig");
}
EGLSurface yta = EGL_NO_SURFACE;
CONST EGLint surfaceAttributes [] =
{
EGL_ANGLE_SURFACE_RENDER_TO_BACK_BUFFER är en del av samma optimering som EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER (se ovan).
Om du har sammanställning problem med det så snälla uppdatera mallarna Visual Studio.
EGL_ANGLE_SURFACE_RENDER_TO_BACK_BUFFER, EGL_TRUE,
EGL_NONE
};
Skapa en PropertySet och initiera med EGLNativeWindowType.
PropertySet ^ surfaceCreationProperties = ref nya PropertySet();
surfaceCreationProperties -> Infoga (ref nya String(EGLNativeWindowTypeProperty), panel);
Om en render ytans storlek anges, lägga till yta skapas egenskaperna
om (renderSurfaceSize! = nullptr)
{
surfaceCreationProperties -> Infoga (ref nya String(EGLRenderSurfaceSizeProperty), PropertyValue::CreateSize(*renderSurfaceSize));
}
yta = eglCreateWindowSurface (mEglDisplay, mEglConfig, reinterpret_cast(surfaceCreationProperties), surfaceAttributes);
om (ytan == EGL_NO_SURFACE)
{
kasta Exception::CreateException (E_FAIL, L "Kunde inte skapa EGL yta");
}
returnera ytan.
}
void OpenGLES::DestroySurface (const EGLSurface yta)
{
om (mEglDisplay! = EGL_NO_DISPLAY & & ytan! = EGL_NO_SURFACE)
{
eglDestroySurface (mEglDisplay, yta);
}
}
void OpenGLES::MakeCurrent (const EGLSurface yta)
{
om (eglMakeCurrent (mEglDisplay, yta, yta, mEglContext) == EGL_FALSE)
{
kasta Exception::CreateException (E_FAIL, L "Misslyckades med att göra EGLSurface nuvarande");
}
}
EGLBoolean OpenGLES::SwapBuffers(const EGLSurface surface)
{
Return (eglSwapBuffers (mEglDisplay, ytbehandlar));
}
Återigen, detta är hämtade från mallen vinkel och den har fungerande behöver förmodligen inte berör dig. Försök igen att se om du fortfarande kan kompilera.
OK så nu för CX (Microsofts runtime C++ extensions version av C ++ eller vad det heter) / (version av C++ med mycket rolig syntax) omslag som kommer att ge oss en sömlös C#-gränssnitt. För nu kommer vi att använda en modifierad version av huvudsidan koden finns på mallen vinkel. Denna sida är nu faktiskt ett C#-objekt, får vi route händelserna från C# till C++. Resten av koden kan hållas som i C++ att hålla det enkelt.
Så nu skapa en klass i klassen delade bro och kallar det GLESSurface. Klassen kommer att behöva vara i ett namnområde med samma namn som projektet eftersom annars får du fel när du försöker kompilera C# programmet. Problemet är att här namnområdet är olika för projekt som Windows Store och Windows Phone. För att åtgärda detta måste vi lägga till några förprocessordirektiv. För butiken projektet jag lagt "WIN_STORE" och för WP en "WIN_PHONE". Kanske finns det redan vissa standard som skulle fungera men jag kunde inte hitta dem och gick bara med dessa. Med dessa kunde jag sedan använda följande i sidhuvudfilen för att definiera namnområdet behövs:
#if WIN_STORE
#define MAINNAMESPACE CppGLESBridge_Win
#else om WIN_PHONE
#define MAINNAMESPACE CppGLESBridge_WP
#endif
Du kommer att behöva ändra de till vad dina projekt kallas. Min heter "CppGLESBridge.Win" och "CppGLESBride.WP". Du bör ha kunnat se vad namnområde som du behövs i standardfilerna för klass 1. Du kan också använda något sånt här överallt i C++-kod där du måste göra något lite annorlunda för WP och Win butik.
Nu försök sammanställa för att se om allt fungerar. Detta är också nödvändigt eftersom komponenten Runtime måste kompileras innan Intellisense kan börja registrera den när vi byter till C#.
Om allt gick bra så här långt då du kommer att vara mycket nära ser något nu men vi är inte där ännu. Vi får bara till Xamarin.Forms i slutet av handledningen. För nu vill vi bara se en färgad snurrande kub på alla plattformar. Så gå till din MainPage.xaml filer för både vinst och WP och lägga till en SwapChainPanel som heter något i stil med "swapPanel" som kan ses i skärmdumpar.
Nu måste du öppna MainPage.xaml.cs för varje projekt. Lägg till följande med-uttryck:
använder Windows.UI.Core;
använder CppGLESBridge_Win;
CppGLESBridge_Win är för Win butik för WP bör du använda CppGLESBridge_WP. Om du åkte med några andra namn sedan bara anpassa sig dessa på lämpligt sätt. Därefter skapa ett privat GLESSurface objekt i båda projekten. Vi kommer att routning händelserna till detta objekt. Du måste sedan skapa objektet och ansluta de nödvändiga händelserna som C# till C++ hanterarna. Du din MainPage() metod att så småningom innehålla följande utöver vad redan var där:
GS = nya GLESSurface(swapPanel);
CoreWindow fönster = Window.Current.CoreWindow;
fönstret. VisibilityChanged += (CoreWindow avsändare, VisibilityChangedEventArgs args) = > {gs. OnVisibilityChanged (avsändare, args); };
swapPanel.SizeChanged += (objekt avsändare, SizeChangedEventArgs e) = > {gs. OnSwapChainPanelSizeChanged (avsändare, e); };
Detta. Lastade += (objekt avsändare, RoutedEventArgs e) = > {gs. OnPageLoaded (avsändare, e); };
Det finns skärmdumpar för både färdiga Windows Phone och Windows Store filer.
Om du bygga och driva dina projekt bör nu du se en snurrande kub.