Commit 7c1cc096 authored by Administrator's avatar Administrator
Browse files

initial version including code to draw a triangle

parents
# Exclude .vs folder
.vs/
# Exclude x64 folder
x64/
# Exclude cso files
*.cso

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.4.33122.133
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PracticeDx", "PracticeDx\PracticeDx.vcxproj", "{A2C8534C-9AE3-4497-BF42-582D461455DA}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{A2C8534C-9AE3-4497-BF42-582D461455DA}.Debug|x64.ActiveCfg = Debug|x64
{A2C8534C-9AE3-4497-BF42-582D461455DA}.Debug|x64.Build.0 = Debug|x64
{A2C8534C-9AE3-4497-BF42-582D461455DA}.Debug|x86.ActiveCfg = Debug|Win32
{A2C8534C-9AE3-4497-BF42-582D461455DA}.Debug|x86.Build.0 = Debug|Win32
{A2C8534C-9AE3-4497-BF42-582D461455DA}.Release|x64.ActiveCfg = Release|x64
{A2C8534C-9AE3-4497-BF42-582D461455DA}.Release|x64.Build.0 = Release|x64
{A2C8534C-9AE3-4497-BF42-582D461455DA}.Release|x86.ActiveCfg = Release|Win32
{A2C8534C-9AE3-4497-BF42-582D461455DA}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {F4D0EEF3-25D3-4579-86DD-668FD620BBD5}
EndGlobalSection
EndGlobal
float4 main() : SV_TARGET
{
return float4(1.0f, 1.0f, 1.0f, 1.0f);
}
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" 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>16.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{a2c8534c-9ae3-4497-bf42-582d461455da}</ProjectGuid>
<RootNamespace>PracticeDx</RootNamespace>
<WindowsTargetPlatformVersion>10.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>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</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" />
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="WinMain.cpp" />
</ItemGroup>
<ItemGroup>
<FxCompile Include="PixelShader.hlsl">
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Pixel</ShaderType>
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Pixel</ShaderType>
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Pixel</ShaderType>
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Pixel</ShaderType>
<ObjectFileOutput Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(ProjectDir)%(Filename).cso</ObjectFileOutput>
<ObjectFileOutput Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(ProjectDir)%(Filename).cso</ObjectFileOutput>
</FxCompile>
<FxCompile Include="VertexShader.hlsl">
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Vertex</ShaderType>
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Vertex</ShaderType>
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Vertex</ShaderType>
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Vertex</ShaderType>
<ObjectFileOutput Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(ProjectDir)%(Filename).cso</ObjectFileOutput>
<ObjectFileOutput Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(ProjectDir)%(Filename).cso</ObjectFileOutput>
</FxCompile>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
\ No newline at end of file
<?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;c++;cppm;ixx;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;h++;hm;inl;inc;ipp;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>
<Filter Include="Shaders">
<UniqueIdentifier>{8305ae76-37a2-484d-a157-5d9c921795ea}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="WinMain.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<FxCompile Include="PixelShader.hlsl">
<Filter>Shaders</Filter>
</FxCompile>
<FxCompile Include="VertexShader.hlsl">
<Filter>Shaders</Filter>
</FxCompile>
</ItemGroup>
</Project>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup />
</Project>
\ No newline at end of file
float4 main(float2 pos : POSITION) : SV_POSITION
{
return float4(pos.x, pos.y, 0.0f, 1.0f);
}
\ No newline at end of file
// include the basic windows header file
#include <windows.h>
#include <windowsx.h>
#include <d3d11.h>
#pragma comment (lib, "d3d11.lib")
#include <d3dcompiler.h>
#pragma comment (lib, "d3dcompiler.lib")
#include <wrl.h>
// global declarations
Microsoft::WRL::ComPtr<IDXGISwapChain> swapchain; // the pointer to the swap chain interface
Microsoft::WRL::ComPtr<ID3D11Device> dev; // the pointer to our Direct3D device interface
Microsoft::WRL::ComPtr<ID3D11DeviceContext> devcon; // the pointer to our Direct3D device context
// 定义Targe View
Microsoft::WRL::ComPtr<ID3D11RenderTargetView> targetView;
// Define Shader
Microsoft::WRL::ComPtr<ID3D11PixelShader> pPixelShader;
Microsoft::WRL::ComPtr<ID3DBlob> pCompiledPixelBlob;
Microsoft::WRL::ComPtr<ID3D11VertexShader> pVertexShader;
Microsoft::WRL::ComPtr<ID3DBlob> pCompiledVertexBlob;
// Define vertex buffer
Microsoft::WRL::ComPtr<ID3D11Buffer> pVertexBuffer;
// Create buffer description
struct Vertex
{
float x;
float y;
};
// create vertex buffer (1 2d triangle at center of screen)
const Vertex vertices[] =
{
{ -0.0f,0.5f },
{ 0.5f,-0.5f },
{ -0.5f,-0.5f },
};
// Define input layout
ID3D11InputLayout* pInputLayout;
void DefineShader()
{
// Load vertex shader file into BLOB, and create COM object of pixel shader
D3DReadFileToBlob(L"PixelShader.cso", &pCompiledPixelBlob);
dev->CreatePixelShader(pCompiledPixelBlob->GetBufferPointer(), pCompiledPixelBlob->GetBufferSize(), nullptr, &pPixelShader);
// Load pixel shader file into BLOB, and create COM object of vertex shader
D3DReadFileToBlob(L"VertexShader.cso", &pCompiledVertexBlob);
dev->CreateVertexShader(pCompiledVertexBlob->GetBufferPointer(), pCompiledVertexBlob->GetBufferSize(), nullptr, &pVertexShader);
// bind pixel shader
devcon->PSSetShader(pPixelShader.Get(), nullptr, 0u);
// bind vertex shader
devcon->VSSetShader(pVertexShader.Get(), nullptr, 0u);
}
void DefineVertexBuffer()
{
D3D11_BUFFER_DESC bd = {};
bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
bd.Usage = D3D11_USAGE_DEFAULT;
bd.CPUAccessFlags = 0u;
bd.MiscFlags = 0u;
bd.ByteWidth = sizeof(vertices);
bd.StructureByteStride = sizeof(Vertex);
D3D11_SUBRESOURCE_DATA sd = {};
sd.pSysMem = vertices;
// Create vertex buffer
dev->CreateBuffer(&bd, &sd, &pVertexBuffer);
}
void DefineInputLayout()
{
// Create input elements description, choosing whatever need to send to GPU
const D3D11_INPUT_ELEMENT_DESC ied[] =
{
{ "Position",0,DXGI_FORMAT_R32G32_FLOAT,0,0,D3D11_INPUT_PER_VERTEX_DATA,0 },
};
// Create input layout, using the description Defined above
dev->CreateInputLayout
(
ied, 1, //(UINT)std::size(ied),
pCompiledVertexBlob->GetBufferPointer(),
pCompiledVertexBlob->GetBufferSize(),
&pInputLayout
);
// Bind layout to pipeline
// bind vertex layout
devcon->IASetInputLayout(pInputLayout);
// bind render target
devcon->OMSetRenderTargets(1u, targetView.GetAddressOf(), nullptr);
}
void DrawPrimitive()
{
// Set the vertex buffer to use. Pick up the vertex buffer created in previous step.
// Bind vertex buffer to pipeline
const UINT stride = sizeof(Vertex);
const UINT offset = 0u;
devcon->IASetVertexBuffers(0u, 1u, pVertexBuffer.GetAddressOf(), &stride, &offset);
// Set the primitive type to use
// Set primitive topology to triangle list (groups of 3 vertices)
devcon->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
// Draw the triangle.
devcon->Draw((UINT)sizeof(vertices), 0u);
}
void drawTriangle()
{
DefineShader();
DefineVertexBuffer();
DefineInputLayout();
DrawPrimitive();
}
// this function initializes and prepares Direct3D for use
void InitD3D(HWND hWnd)
{
// create a struct to hold information about the swap chain
DXGI_SWAP_CHAIN_DESC scd;
// clear out the struct for use
ZeroMemory(&scd, sizeof(DXGI_SWAP_CHAIN_DESC));
// fill the swap chain description struct
scd.BufferCount = 1; // one back buffer
scd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; // use 32-bit color
scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; // how swap chain is to be used
scd.OutputWindow = hWnd; // the window to be used
scd.SampleDesc.Count = 4; // how many multisamples
scd.Windowed = TRUE; // windowed/full-screen mode
// create a device, device context and swap chain using the information in the scd struct
D3D11CreateDeviceAndSwapChain(NULL, // IDXGIAdapter *pAdapter - Let DXGI take care of what adapter to use (default adapter)
D3D_DRIVER_TYPE_HARDWARE, // D3D_DRIVER_TYPE DriverType - hardware or software, or others
NULL, // HMODULE Software
NULL, // UINT Flags
NULL, // D3D_FEATURE_LEVEL *pFeatureLevels
NULL, // UINT FeatureLevels
D3D11_SDK_VERSION, // UINT SDKVersion
&scd, // DXGI_SWAP_CHAIN_DESC *pSwapChainDesc
&swapchain, // IDXGISwapChain **ppSwapChain
&dev, // ID3D11Device **ppDevice
NULL, // D3D_FEATURE_LEVEL *FeatureLevel
&devcon); // ID3D11DeviceContext **ppImmediateContext
// 从SwapChain中取得back buffer
Microsoft::WRL::ComPtr<ID3D11Texture2D> pBackBuffer;
swapchain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBuffer);
// 根据back buffer,创建新的View Target
dev->CreateRenderTargetView(pBackBuffer.Get(), NULL, &targetView);
// 将渲染目标设置成我们新创建的View Target
devcon->OMSetRenderTargets(1, targetView.GetAddressOf(), NULL);
// 指定View Port
D3D11_VIEWPORT viewport;
ZeroMemory(&viewport, sizeof(D3D11_VIEWPORT));
// 控制View port的位置
viewport.TopLeftX = 0;
viewport.TopLeftY = 0;
viewport.Width = 800;
viewport.Height = 600;
devcon->RSSetViewports(1, &viewport);
}
// this is the function used to render a single frame
void RenderFrame(void)
{
// clear the back buffer to a deep blue
const float color[] = { 0.0f, 0.2f, 0.4f, 1.0f };
devcon->ClearRenderTargetView(targetView.Get(), color);
// do 3D rendering on the back buffer here
drawTriangle();
// switch the back buffer and the front buffer
// 切换显示,将back buffer的内容交换到front buffer
swapchain->Present(0, 0);
}
// this is the function that cleans up Direct3D and COM
void CleanD3D()
{
// close and release all existing COM objects
// changed to use smart pointer, do NOT need to manually release
// pPixelShader->Release();
// pCompiledPixelBlob->Release();
// pVertexShader->Release();
// pCompiledVertexBlob->Release();
// pVertexBuffer->Release();
// pInputLayout->Release();
// swapchain->Release();
// targetView->Release();
// dev->Release();
// devcon->Release();
}
// the WindowProc function prototype
LRESULT CALLBACK WindowProc(HWND hWnd,
UINT message,
WPARAM wParam,
LPARAM lParam);
// the entry point for any Windows program
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
// the handle for the window, filled by a function
HWND hWnd;
// this struct holds information for the window class
WNDCLASSEX wc;
// clear out the window class for use
ZeroMemory(&wc, sizeof(WNDCLASSEX));
// fill in the struct with the needed information
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
wc.lpszClassName = "WindowClass";
// register the window class
RegisterClassEx(&wc);
// create rectangle for client area
RECT wr = { 0, 0, 800, 600 }; // set the size only, but not the position
AdjustWindowRect(&wr, WS_OVERLAPPEDWINDOW, FALSE); // adjust the size
// create the window and use the result as the handle
hWnd = CreateWindowEx(NULL,
"WindowClass", // name of the window class
"Our First Windowed Program", // title of the window
WS_OVERLAPPEDWINDOW, // window style
300, // x-position of the window
200, // y-position of the window
800, // width of the window
600, // height of the window
NULL, // we have no parent window, NULL
NULL, // we aren't using menus, NULL
hInstance, // application handle
NULL); // used with multiple windows, NULL
// display the window on the screen
ShowWindow(hWnd, nCmdShow);
// set up and initialize Direct3D
InitD3D(hWnd);
// enter the main loop:
// this struct holds Windows event messages
MSG msg;
// wait for the next message in the queue, store the result in 'msg'
while (true)
{
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
// translate keystroke messages into the right format
TranslateMessage(&msg);
// send the message to the WindowProc function
DispatchMessage(&msg);
// check if message to quit
if (msg.message == WM_QUIT)
{
break;
}
}
else
{
RenderFrame();
}
}
// clean up DirectX and COM
CleanD3D();
// return this part of the WM_QUIT message to Windows
return msg.wParam;
}
// this is the main message handler for the program
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
// sort through and find what code to run for the message given
switch (message)
{
// this message is read when the window is closed
case WM_DESTROY:
{
// close the application entirely
PostQuitMessage(0);
return 0;
}
break;
}
// Handle any messages the switch statement didn't
return DefWindowProc(hWnd, message, wParam, lParam);
}
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment