From 6bdfe4569f41eed3d210171e2817e779459fcaa8 Mon Sep 17 00:00:00 2001 From: iDunnoDev Date: Wed, 23 Feb 2022 12:07:57 +0000 Subject: [PATCH] Initial Upload --- Graphics2.sln | 31 ++++ Graphics2/Core.h | 7 + Graphics2/DirectXCore.h | 11 ++ Graphics2/DirectXFramework.cpp | 230 +++++++++++++++++++++++++++ Graphics2/DirectXFramework.h | 63 ++++++++ Graphics2/Framework.cpp | 233 ++++++++++++++++++++++++++++ Graphics2/Framework.h | 55 +++++++ Graphics2/Graphics2.cpp | 18 +++ Graphics2/Graphics2.h | 11 ++ Graphics2/Graphics2.ico | Bin 0 -> 46227 bytes Graphics2/Graphics2.rc | Bin 0 -> 3952 bytes Graphics2/Graphics2.vcxproj | 172 ++++++++++++++++++++ Graphics2/Graphics2.vcxproj.filters | 73 +++++++++ Graphics2/HelperFunctions.h | 13 ++ Graphics2/SceneGraph.h | 26 ++++ Graphics2/SceneNode.h | 39 +++++ Graphics2/resource.h | 27 ++++ Graphics2/small.ico | Bin 0 -> 46227 bytes Graphics2/targetver.h | 8 + 19 files changed, 1017 insertions(+) create mode 100644 Graphics2.sln create mode 100644 Graphics2/Core.h create mode 100644 Graphics2/DirectXCore.h create mode 100644 Graphics2/DirectXFramework.cpp create mode 100644 Graphics2/DirectXFramework.h create mode 100644 Graphics2/Framework.cpp create mode 100644 Graphics2/Framework.h create mode 100644 Graphics2/Graphics2.cpp create mode 100644 Graphics2/Graphics2.h create mode 100644 Graphics2/Graphics2.ico create mode 100644 Graphics2/Graphics2.rc create mode 100644 Graphics2/Graphics2.vcxproj create mode 100644 Graphics2/Graphics2.vcxproj.filters create mode 100644 Graphics2/HelperFunctions.h create mode 100644 Graphics2/SceneGraph.h create mode 100644 Graphics2/SceneNode.h create mode 100644 Graphics2/resource.h create mode 100644 Graphics2/small.ico create mode 100644 Graphics2/targetver.h diff --git a/Graphics2.sln b/Graphics2.sln new file mode 100644 index 0000000..6d0a2cc --- /dev/null +++ b/Graphics2.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.27004.2009 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Graphics2", "Graphics2\Graphics2.vcxproj", "{E4F72E0B-F014-43F1-BC2A-EA26230158F9}" +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 + {E4F72E0B-F014-43F1-BC2A-EA26230158F9}.Debug|x64.ActiveCfg = Debug|x64 + {E4F72E0B-F014-43F1-BC2A-EA26230158F9}.Debug|x64.Build.0 = Debug|x64 + {E4F72E0B-F014-43F1-BC2A-EA26230158F9}.Debug|x86.ActiveCfg = Debug|Win32 + {E4F72E0B-F014-43F1-BC2A-EA26230158F9}.Debug|x86.Build.0 = Debug|Win32 + {E4F72E0B-F014-43F1-BC2A-EA26230158F9}.Release|x64.ActiveCfg = Release|x64 + {E4F72E0B-F014-43F1-BC2A-EA26230158F9}.Release|x64.Build.0 = Release|x64 + {E4F72E0B-F014-43F1-BC2A-EA26230158F9}.Release|x86.ActiveCfg = Release|Win32 + {E4F72E0B-F014-43F1-BC2A-EA26230158F9}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {EF90D084-277F-4434-9B4A-DA8B2C2E8FD6} + EndGlobalSection +EndGlobal diff --git a/Graphics2/Core.h b/Graphics2/Core.h new file mode 100644 index 0000000..96fd36d --- /dev/null +++ b/Graphics2/Core.h @@ -0,0 +1,7 @@ +#pragma once +#include +#include "Resource.h" +#include +#include +#include +#include "HelperFunctions.h" diff --git a/Graphics2/DirectXCore.h b/Graphics2/DirectXCore.h new file mode 100644 index 0000000..43cf3da --- /dev/null +++ b/Graphics2/DirectXCore.h @@ -0,0 +1,11 @@ +#pragma once +#include +#include +#include +#include +#include + +using namespace DirectX; + +using Microsoft::WRL::ComPtr; + diff --git a/Graphics2/DirectXFramework.cpp b/Graphics2/DirectXFramework.cpp new file mode 100644 index 0000000..c6a753e --- /dev/null +++ b/Graphics2/DirectXFramework.cpp @@ -0,0 +1,230 @@ +#include "DirectXFramework.h" + +// DirectX libraries that are needed +#pragma comment(lib, "d3d11.lib") +#pragma comment(lib, "d3dcompiler.lib") + +DirectXFramework * _dxFramework = nullptr; + +DirectXFramework::DirectXFramework() : DirectXFramework(800, 600) +{ +} + +DirectXFramework::DirectXFramework(unsigned int width, unsigned int height) : Framework(width, height) +{ + _dxFramework = this; + + // Set default background colour + _backgroundColour[0] = 0.0f; + _backgroundColour[1] = 0.0f; + _backgroundColour[2] = 0.0f; + _backgroundColour[3] = 0.0f; + + // Initialise vectors used to create camera. We will move these + // to a separate Camera class later + _eyePosition = XMFLOAT4(0.0f, 1.0f, -15.0f, 0.0f); + _focalPointPosition = XMFLOAT4(0.0f, 0.0f, 0.0f, 0.0f); + _upVector = XMFLOAT4(0.0f, 1.0f, 0.0f, 0.0f); +} + +DirectXFramework * DirectXFramework::GetDXFramework() +{ + return _dxFramework; +} + +XMMATRIX DirectXFramework::GetViewTransformation() +{ + return XMLoadFloat4x4(&_viewTransformation); +} + +XMMATRIX DirectXFramework::GetProjectionTransformation() +{ + return XMLoadFloat4x4(&_projectionTransformation); +} + +void DirectXFramework::SetBackgroundColour(XMFLOAT4 backgroundColour) +{ + _backgroundColour[0] = backgroundColour.x; + _backgroundColour[1] = backgroundColour.y; + _backgroundColour[2] = backgroundColour.z; + _backgroundColour[3] = backgroundColour.w; +} + +void DirectXFramework::CreateSceneGraph() +{ +} + +void DirectXFramework::UpdateSceneGraph() +{ +} + +bool DirectXFramework::Initialise() +{ + // The call to CoInitializeEx is needed if we are using + // textures since the WIC library used requires it, so we + // take care of initialising it here + if FAILED(CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED)) + { + return false; + } + if (!GetDeviceAndSwapChain()) + { + return false; + } + OnResize(SIZE_RESTORED); + + // Create camera and projection matrices (we will look at how the + // camera matrix is created from vectors later) + XMStoreFloat4x4(&_projectionTransformation, XMMatrixPerspectiveFovLH(XM_PIDIV4, (float)GetWindowWidth() / GetWindowHeight(), 1.0f, 10000.0f)); + _sceneGraph = make_shared(); + CreateSceneGraph(); + return _sceneGraph->Initialise(); +} + +void DirectXFramework::Shutdown() +{ + // Required because we called CoInitialize above + _sceneGraph->Shutdown(); + CoUninitialize(); +} + +void DirectXFramework::Update() +{ + // Do any updates to the scene graph nodes + UpdateSceneGraph(); + // Now apply any updates that have been made to world transformations + // to all the nodes + _sceneGraph->Update(XMMatrixIdentity()); +} + +void DirectXFramework::Render() +{ + // Clear the render target and the depth stencil view + _deviceContext->ClearRenderTargetView(_renderTargetView.Get(), _backgroundColour); + _deviceContext->ClearDepthStencilView(_depthStencilView.Get(), D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0); + // Now recurse through the scene graph, rendering each object + _sceneGraph->Render(); + // Now display the scene + ThrowIfFailed(_swapChain->Present(0, 0)); +} + +void DirectXFramework::OnResize(WPARAM wParam) +{ + // Update view and projection matrices to allow for the window size change + XMStoreFloat4x4(&_viewTransformation, XMMatrixLookAtLH(XMLoadFloat4(&_eyePosition), XMLoadFloat4(&_focalPointPosition), XMLoadFloat4(&_upVector))); + XMStoreFloat4x4(&_projectionTransformation, XMMatrixPerspectiveFovLH(XM_PIDIV4, (float)GetWindowWidth() / GetWindowHeight(), 1.0f, 10000.0f)); + + // This will free any existing render and depth views (which + // would be the case if the window was being resized) + _renderTargetView = nullptr; + _depthStencilView = nullptr; + _depthStencilBuffer = nullptr; + + ThrowIfFailed(_swapChain->ResizeBuffers(1, GetWindowWidth(), GetWindowHeight(), DXGI_FORMAT_R8G8B8A8_UNORM, 0)); + + // Create a drawing surface for DirectX to render to + ComPtr backBuffer; + ThrowIfFailed(_swapChain->GetBuffer(0, IID_PPV_ARGS(&backBuffer))); + ThrowIfFailed(_device->CreateRenderTargetView(backBuffer.Get(), NULL, _renderTargetView.GetAddressOf())); + + // The depth buffer is used by DirectX to ensure + // that pixels of closer objects are drawn over pixels of more + // distant objects. + + // First, we need to create a texture (bitmap) for the depth buffer + D3D11_TEXTURE2D_DESC depthBufferTexture = { 0 }; + depthBufferTexture.Width = GetWindowWidth(); + depthBufferTexture.Height = GetWindowHeight(); + depthBufferTexture.ArraySize = 1; + depthBufferTexture.MipLevels = 1; + depthBufferTexture.SampleDesc.Count = 4; + depthBufferTexture.Format = DXGI_FORMAT_D32_FLOAT; + depthBufferTexture.Usage = D3D11_USAGE_DEFAULT; + depthBufferTexture.BindFlags = D3D11_BIND_DEPTH_STENCIL; + + // Create the depth buffer. + ComPtr depthBuffer; + ThrowIfFailed(_device->CreateTexture2D(&depthBufferTexture, NULL, depthBuffer.GetAddressOf())); + ThrowIfFailed(_device->CreateDepthStencilView(depthBuffer.Get(), 0, _depthStencilView.GetAddressOf())); + + // Bind the render target view buffer and the depth stencil view buffer to the output-merger stage + // of the pipeline. + _deviceContext->OMSetRenderTargets(1, _renderTargetView.GetAddressOf(), _depthStencilView.Get()); + + // Specify a viewport of the required size + D3D11_VIEWPORT viewPort; + viewPort.Width = static_cast(GetWindowWidth()); + viewPort.Height = static_cast(GetWindowHeight()); + viewPort.MinDepth = 0.0f; + viewPort.MaxDepth = 1.0f; + viewPort.TopLeftX = 0; + viewPort.TopLeftY = 0; + _deviceContext->RSSetViewports(1, &viewPort); +} + +bool DirectXFramework::GetDeviceAndSwapChain() +{ + UINT createDeviceFlags = 0; + + // We are going to only accept a hardware driver or a WARP + // driver + D3D_DRIVER_TYPE driverTypes[] = + { + D3D_DRIVER_TYPE_HARDWARE, + D3D_DRIVER_TYPE_WARP + }; + unsigned int totalDriverTypes = ARRAYSIZE(driverTypes); + + D3D_FEATURE_LEVEL featureLevels[] = + { + D3D_FEATURE_LEVEL_11_0 + }; + unsigned int totalFeatureLevels = ARRAYSIZE(featureLevels); + + DXGI_SWAP_CHAIN_DESC swapChainDesc = { 0 }; + swapChainDesc.BufferCount = 1; + swapChainDesc.BufferDesc.Width = GetWindowWidth(); + swapChainDesc.BufferDesc.Height = GetWindowHeight(); + swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + // Set the refresh rate to 0 and let DXGI determine the best option (refer to DXGI best practices) + swapChainDesc.BufferDesc.RefreshRate.Numerator = 0; + swapChainDesc.BufferDesc.RefreshRate.Denominator = 0; + swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; + swapChainDesc.OutputWindow = GetHWnd(); + // Start out windowed + swapChainDesc.Windowed = true; + // Enable multi-sampling to give smoother lines (set to 1 if performance becomes an issue) + swapChainDesc.SampleDesc.Count = 4; + swapChainDesc.SampleDesc.Quality = 0; + + // Loop through the driver types to determine which one is available to us + D3D_DRIVER_TYPE driverType = D3D_DRIVER_TYPE_UNKNOWN; + + for (unsigned int driver = 0; driver < totalDriverTypes && driverType == D3D_DRIVER_TYPE_UNKNOWN; driver++) + { + if (SUCCEEDED(D3D11CreateDeviceAndSwapChain(0, + driverTypes[driver], + 0, + createDeviceFlags, + featureLevels, + totalFeatureLevels, + D3D11_SDK_VERSION, + &swapChainDesc, + _swapChain.GetAddressOf(), + _device.GetAddressOf(), + 0, + _deviceContext.GetAddressOf() + ))) + + { + driverType = driverTypes[driver]; + } + } + if (driverType == D3D_DRIVER_TYPE_UNKNOWN) + { + // Unable to find a suitable device driver + return false; + } + return true; +} + diff --git a/Graphics2/DirectXFramework.h b/Graphics2/DirectXFramework.h new file mode 100644 index 0000000..86512f4 --- /dev/null +++ b/Graphics2/DirectXFramework.h @@ -0,0 +1,63 @@ +#pragma once +#include +#include "Framework.h" +#include "DirectXCore.h" +#include "SceneGraph.h" + +class DirectXFramework : public Framework +{ +public: + DirectXFramework(); + DirectXFramework(unsigned int width, unsigned int height); + + virtual void CreateSceneGraph(); + virtual void UpdateSceneGraph(); + + bool Initialise(); + void Update(); + void Render(); + void OnResize(WPARAM wParam); + void Shutdown(); + + static DirectXFramework * GetDXFramework(); + + inline SceneGraphPointer GetSceneGraph() { return _sceneGraph; } + inline ComPtr GetDevice() { return _device; } + inline ComPtr GetDeviceContext() { return _deviceContext; } + + XMMATRIX GetViewTransformation(); + XMMATRIX GetProjectionTransformation(); + + void SetBackgroundColour(XMFLOAT4 backgroundColour); + +private: + ComPtr _device; + ComPtr _deviceContext; + ComPtr _swapChain; + ComPtr _depthStencilBuffer; + ComPtr _renderTargetView; + ComPtr _depthStencilView; + + D3D11_VIEWPORT _screenViewport; + + // Our vectors and matrices. Note that we cannot use + // XMVECTOR and XMMATRIX for class variables since they need + // to be aligned on 16-byte boundaries and the compiler cannot + // guarantee this for class variables + + // For now, we are storing our camera vectors and matrix here. + // We will move it to a separate Camera class later + XMFLOAT4 _eyePosition; + XMFLOAT4 _focalPointPosition; + XMFLOAT4 _upVector; + + XMFLOAT4X4 _viewTransformation; + XMFLOAT4X4 _projectionTransformation; + + SceneGraphPointer _sceneGraph; + + float _backgroundColour[4]; + + bool GetDeviceAndSwapChain(); +}; + diff --git a/Graphics2/Framework.cpp b/Graphics2/Framework.cpp new file mode 100644 index 0000000..64edcec --- /dev/null +++ b/Graphics2/Framework.cpp @@ -0,0 +1,233 @@ +#include "Framework.h" + +#define DEFAULT_FRAMERATE 60 +#define DEFAULT_WIDTH 800 +#define DEFAULT_HEIGHT 600 + +// Reference to ourselves - primarily used to access the message handler correctly +// This is initialised in the constructor +Framework * _thisFramework = NULL; + +// Forward declaration of our window procedure +LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); + +int APIENTRY wWinMain(_In_ HINSTANCE hInstance, + _In_opt_ HINSTANCE hPrevInstance, + _In_ LPWSTR lpCmdLine, + _In_ int nCmdShow) +{ + UNREFERENCED_PARAMETER(hPrevInstance); + UNREFERENCED_PARAMETER(lpCmdLine); + + // We can only run if an instance of a class that inherits from Framework + // has been created + if (_thisFramework) + { + return _thisFramework->Run(hInstance, nCmdShow); + } + return -1; +} + +Framework::Framework() : Framework(DEFAULT_WIDTH, DEFAULT_HEIGHT) +{ +} + +Framework::Framework(unsigned int width, unsigned int height) +{ + _thisFramework = this; + _width = width; + _height = height; +} + +Framework::~Framework() +{ +} + +int Framework::Run(HINSTANCE hInstance, int nCmdShow) +{ + int returnValue; + + _hInstance = hInstance; + if (!InitialiseMainWindow(nCmdShow)) + { + return -1; + } + returnValue = MainLoop(); + Shutdown(); + return returnValue; +} + +// Main program loop. + +int Framework::MainLoop() +{ + MSG msg; + HACCEL hAccelTable = LoadAccelerators(_hInstance, MAKEINTRESOURCE(IDC_GRAPHICS2)); + LARGE_INTEGER counterFrequency; + LARGE_INTEGER nextTime; + LARGE_INTEGER currentTime; + LARGE_INTEGER lastTime; + bool updateFlag = true; + + // Initialise timer + QueryPerformanceFrequency(&counterFrequency); + DWORD msPerFrame = (DWORD)(counterFrequency.QuadPart / DEFAULT_FRAMERATE); + double timeFactor = 1.0 / counterFrequency.QuadPart; + QueryPerformanceCounter(&nextTime); + lastTime = nextTime; + + // Main message loop: + msg.message = WM_NULL; + while (msg.message != WM_QUIT) + { + if (updateFlag) + { + QueryPerformanceCounter(¤tTime); + _timeSpan = (currentTime.QuadPart - lastTime.QuadPart) * timeFactor; + lastTime = currentTime; + Update(); + updateFlag = false; + } + QueryPerformanceCounter(¤tTime); + // Is it time to render the frame? + if (currentTime.QuadPart > nextTime.QuadPart) + { + Render(); + // Set time for next frame + nextTime.QuadPart += msPerFrame; + // If we get more than a frame ahead, allow one to be dropped + // Otherwise, we will never catch up if we let the error accumulate + // and message handling will suffer + if (nextTime.QuadPart < currentTime.QuadPart) + { + nextTime.QuadPart = currentTime.QuadPart + msPerFrame; + } + updateFlag = true; + } + else + { + if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) + { + if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + } + } + return (int)msg.wParam; +} + +// Register the window class, create the window and +// create the bitmap that we will use for rendering + +bool Framework::InitialiseMainWindow(int nCmdShow) +{ + #define MAX_LOADSTRING 100 + + WCHAR windowTitle[MAX_LOADSTRING]; + WCHAR windowClass[MAX_LOADSTRING]; + + LoadStringW(_hInstance, IDS_APP_TITLE, windowTitle, MAX_LOADSTRING); + LoadStringW(_hInstance, IDC_GRAPHICS2, windowClass, MAX_LOADSTRING); + + WNDCLASSEXW wcex; + wcex.cbSize = sizeof(WNDCLASSEX); + wcex.style = CS_HREDRAW | CS_VREDRAW; + wcex.lpfnWndProc = WndProc; + wcex.cbClsExtra = 0; + wcex.cbWndExtra = 0; + wcex.hInstance = _hInstance; + wcex.hIcon = LoadIcon(_hInstance, MAKEINTRESOURCE(IDI_GRAPHICS2)); + wcex.hCursor = LoadCursor(nullptr, IDC_ARROW); + wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); + wcex.lpszMenuName = nullptr; + wcex.lpszClassName = windowClass; + wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL)); + if (!RegisterClassExW(&wcex)) + { + MessageBox(0, L"Unable to register window class", 0, 0); + return false; + } + + // Now work out how large the window needs to be for our required client window size + RECT windowRect = { 0, 0, static_cast(_width), static_cast(_height) }; + AdjustWindowRect(&windowRect, WS_OVERLAPPEDWINDOW, FALSE); + _width = windowRect.right - windowRect.left; + _height = windowRect.bottom - windowRect.top; + + _hWnd = CreateWindowW(windowClass, + windowTitle, + WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, CW_USEDEFAULT, _width, _height, + nullptr, nullptr, _hInstance, nullptr); + if (!_hWnd) + { + MessageBox(0, L"Unable to create window", 0, 0); + return false; + } + if (!Initialise()) + { + return false; + } + ShowWindow(_hWnd, nCmdShow); + UpdateWindow(_hWnd); + return true; +} + +// The WndProc for the current window. This cannot be a method, but we can +// redirect all messages to a method. + +LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + if (_thisFramework != NULL) + { + // If framework is started, then we can call our own message proc + return _thisFramework->MsgProc(hWnd, message, wParam, lParam); + } + else + { + // otherwise, we just pass control to the default message proc + return DefWindowProc(hWnd, message, wParam, lParam); + } +} + +// Our main WndProc + +LRESULT Framework::MsgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) + { + case WM_PAINT: + break; + + case WM_KEYDOWN: + OnKeyDown(wParam); + return 0; + + case WM_KEYUP: + OnKeyUp(wParam); + return 0; + + case WM_DESTROY: + PostQuitMessage(0); + break; + + case WM_MOVE: + Render(); + break; + + case WM_SIZE: + _width = LOWORD(lParam); + _height = HIWORD(lParam); + OnResize(wParam); + Render(); + break; + + default: + return DefWindowProc(hWnd, message, wParam, lParam); + } + return 0; +} + diff --git a/Graphics2/Framework.h b/Graphics2/Framework.h new file mode 100644 index 0000000..a044850 --- /dev/null +++ b/Graphics2/Framework.h @@ -0,0 +1,55 @@ +#pragma once +#include "Core.h" + +using namespace std; + +class Framework +{ +public: + Framework(); + Framework(unsigned int width, unsigned int height); + virtual ~Framework(); + + int Run(HINSTANCE hInstance, int nCmdShow); + + LRESULT MsgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); + + inline unsigned int GetWindowWidth() { return _width; } + inline unsigned int GetWindowHeight() { return _height; } + inline HWND GetHWnd() { return _hWnd; } + + // Initialise the application. Called after the window and bitmap has been + // created, but before the main loop starts + // + // Return false if the application cannot be initialised. + virtual bool Initialise() { return true; } + + // Perform any updates to the structures that will be used + // to render the window (i.e. transformation matrices, etc). + virtual void Update() {} + + // Render the contents of the window. + virtual void Render() {}; + + // Perform any application shutdown or cleanup that is needed + virtual void Shutdown() {} + + // Handlers for Windows messages. If you need more, add them + // here and call them from MsgProc. + virtual void OnKeyDown(WPARAM wParam) {} + virtual void OnKeyUp(WPARAM wParam) {} + virtual void OnResize(WPARAM wParam) {} + +private: + HINSTANCE _hInstance; + HWND _hWnd; + unsigned int _width; + unsigned int _height; + + // Used in timing loop + double _timeSpan; + + bool InitialiseMainWindow(int nCmdShow); + int MainLoop(); +}; + diff --git a/Graphics2/Graphics2.cpp b/Graphics2/Graphics2.cpp new file mode 100644 index 0000000..18cc4c3 --- /dev/null +++ b/Graphics2/Graphics2.cpp @@ -0,0 +1,18 @@ +#include "Graphics2.h" + +Graphics2 app; + +void Graphics2::CreateSceneGraph() +{ + SceneGraphPointer sceneGraph = GetSceneGraph(); + + // This is where you add nodes to the scene graph +} + +void Graphics2::UpdateSceneGraph() +{ + SceneGraphPointer sceneGraph = GetSceneGraph(); + + // This is where you make any changes to the local world transformations to nodes + // in the scene graph +} diff --git a/Graphics2/Graphics2.h b/Graphics2/Graphics2.h new file mode 100644 index 0000000..cb2d36f --- /dev/null +++ b/Graphics2/Graphics2.h @@ -0,0 +1,11 @@ +#pragma once +#include "DirectXFramework.h" + +class Graphics2 : public DirectXFramework +{ +public: + void CreateSceneGraph(); + void UpdateSceneGraph(); + +}; + diff --git a/Graphics2/Graphics2.ico b/Graphics2/Graphics2.ico new file mode 100644 index 0000000000000000000000000000000000000000..b3ec03bd617f32e58128fa977fd6ac9605124f4b GIT binary patch literal 46227 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 + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 15.0 + {E4F72E0B-F014-43F1-BC2A-EA26230158F9} + Win32Proj + Graphics2 + 10.0 + + + + Application + true + v142 + Unicode + + + Application + false + v142 + true + Unicode + + + Application + true + v142 + Unicode + + + Application + false + v142 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + + + true + + + false + + + false + + + + NotUsing + Level3 + Disabled + true + WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + + + Windows + true + + + + + NotUsing + Level3 + Disabled + true + _DEBUG;_WINDOWS;%(PreprocessorDefinitions) + + + Windows + true + + + + + Use + Level3 + MaxSpeed + true + true + true + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + + + Windows + true + true + true + + + + + Use + Level3 + MaxSpeed + true + true + true + NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + + + Windows + true + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Graphics2/Graphics2.vcxproj.filters b/Graphics2/Graphics2.vcxproj.filters new file mode 100644 index 0000000..fb173ac --- /dev/null +++ b/Graphics2/Graphics2.vcxproj.filters @@ -0,0 +1,73 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Resource Files + + + + + Resource Files + + + Resource Files + + + + + Source Files + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/Graphics2/HelperFunctions.h b/Graphics2/HelperFunctions.h new file mode 100644 index 0000000..9fc04c6 --- /dev/null +++ b/Graphics2/HelperFunctions.h @@ -0,0 +1,13 @@ +#pragma once + +// Various helper functions + +using namespace std; + +inline void ThrowIfFailed(HRESULT hr) +{ + if (FAILED(hr)) + { + throw exception(); + } +} diff --git a/Graphics2/SceneGraph.h b/Graphics2/SceneGraph.h new file mode 100644 index 0000000..9359151 --- /dev/null +++ b/Graphics2/SceneGraph.h @@ -0,0 +1,26 @@ +#pragma once +#include "SceneNode.h" + +class SceneGraph : public SceneNode +{ +public: + SceneGraph() : SceneNode(L"Root") {}; + SceneGraph(wstring name) : SceneNode(name) {}; + ~SceneGraph(void) {}; + + virtual bool Initialise(void); + virtual void Update(FXMMATRIX& currentWorldTransformation); + virtual void Render(void); + virtual void Shutdown(void); + + void Add(SceneNodePointer node); + void Remove(SceneNodePointer node); + SceneNodePointer Find(wstring name); + +//private: + + // Here you need to add whatever collection you are going to + // use to store the children of this scene graph +}; + +typedef shared_ptr SceneGraphPointer; diff --git a/Graphics2/SceneNode.h b/Graphics2/SceneNode.h new file mode 100644 index 0000000..fc0e8c8 --- /dev/null +++ b/Graphics2/SceneNode.h @@ -0,0 +1,39 @@ +#pragma once +#include "core.h" +#include "DirectXCore.h" + +using namespace std; + +// Abstract base class for all nodes of the scene graph. +// This scene graph implements the Composite Design Pattern + +class SceneNode; + +typedef shared_ptr SceneNodePointer; + +class SceneNode : public enable_shared_from_this +{ +public: + SceneNode(wstring name) {_name = name; XMStoreFloat4x4(&_worldTransformation, XMMatrixIdentity()); }; + ~SceneNode(void) {}; + + // Core methods + virtual bool Initialise() = 0; + virtual void Update(FXMMATRIX& currentWorldTransformation) { XMStoreFloat4x4(&_combinedWorldTransformation, XMLoadFloat4x4(&_worldTransformation) * currentWorldTransformation); } + virtual void Render() = 0; + virtual void Shutdown() = 0; + + void SetWorldTransform(FXMMATRIX& worldTransformation) { XMStoreFloat4x4(&_worldTransformation, worldTransformation); } + + // Although only required in the composite class, these are provided + // in order to simplify the code base. + virtual void Add(SceneNodePointer node) {} + virtual void Remove(SceneNodePointer node) {}; + virtual SceneNodePointer Find(wstring name) { return (_name == name) ? shared_from_this() : nullptr; } + +protected: + XMFLOAT4X4 _worldTransformation; + XMFLOAT4X4 _combinedWorldTransformation; + wstring _name; +}; + diff --git a/Graphics2/resource.h b/Graphics2/resource.h new file mode 100644 index 0000000..95c1ddb --- /dev/null +++ b/Graphics2/resource.h @@ -0,0 +1,27 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by WindowsApp.rc +// + +#define IDS_APP_TITLE 103 + +#define IDR_MAINFRAME 128 +#define IDI_GRAPHICS2 107 +#define IDI_SMALL 108 +#define IDC_GRAPHICS2 109 +#define IDC_MYICON 2 +#ifndef IDC_STATIC +#define IDC_STATIC -1 +#endif +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS + +#define _APS_NO_MFC 130 +#define _APS_NEXT_RESOURCE_VALUE 129 +#define _APS_NEXT_COMMAND_VALUE 32771 +#define _APS_NEXT_CONTROL_VALUE 1000 +#define _APS_NEXT_SYMED_VALUE 110 +#endif +#endif diff --git a/Graphics2/small.ico b/Graphics2/small.ico new file mode 100644 index 0000000000000000000000000000000000000000..b3ec03bd617f32e58128fa977fd6ac9605124f4b GIT binary patch literal 46227 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