diff --git a/BaseFramework.sln b/BaseFramework.sln new file mode 100644 index 0000000..755975a --- /dev/null +++ b/BaseFramework.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29326.143 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BaseFramework", "BaseFramework.vcxproj", "{E78A1901-BE1C-4A6F-9C82-3BFC672AFE28}" +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 + {E78A1901-BE1C-4A6F-9C82-3BFC672AFE28}.Debug|x64.ActiveCfg = Debug|x64 + {E78A1901-BE1C-4A6F-9C82-3BFC672AFE28}.Debug|x64.Build.0 = Debug|x64 + {E78A1901-BE1C-4A6F-9C82-3BFC672AFE28}.Debug|x86.ActiveCfg = Debug|Win32 + {E78A1901-BE1C-4A6F-9C82-3BFC672AFE28}.Debug|x86.Build.0 = Debug|Win32 + {E78A1901-BE1C-4A6F-9C82-3BFC672AFE28}.Release|x64.ActiveCfg = Release|x64 + {E78A1901-BE1C-4A6F-9C82-3BFC672AFE28}.Release|x64.Build.0 = Release|x64 + {E78A1901-BE1C-4A6F-9C82-3BFC672AFE28}.Release|x86.ActiveCfg = Release|Win32 + {E78A1901-BE1C-4A6F-9C82-3BFC672AFE28}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {4CC4CC5A-427D-44AF-A956-84094536848C} + EndGlobalSection +EndGlobal diff --git a/BaseFramework.vcxproj b/BaseFramework.vcxproj new file mode 100644 index 0000000..64ce85e --- /dev/null +++ b/BaseFramework.vcxproj @@ -0,0 +1,173 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 16.0 + {E78A1901-BE1C-4A6F-9C82-3BFC672AFE28} + Win32Proj + BaseFramework + 10.0 + + + + Application + true + v142 + Unicode + + + Application + false + v142 + true + Unicode + + + Application + true + v142 + Unicode + + + Application + false + v142 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + + + true + + + false + + + false + + + + Level3 + Disabled + true + WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + true + + + Windows + true + + + + + Level3 + Disabled + true + _DEBUG;_WINDOWS;%(PreprocessorDefinitions) + true + true + + + Windows + true + + + + + Level3 + MaxSpeed + true + true + true + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + true + + + Windows + true + true + true + + + + + Level3 + MaxSpeed + true + true + true + NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + true + true + + + Windows + true + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/BaseFramework.vcxproj.filters b/BaseFramework.vcxproj.filters new file mode 100644 index 0000000..9484823 --- /dev/null +++ b/BaseFramework.vcxproj.filters @@ -0,0 +1,70 @@ + + + + + {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;ipp;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 + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Resource Files + + + Resource Files + + + + + Resource Files + + + \ No newline at end of file diff --git a/Bitmap.cpp b/Bitmap.cpp new file mode 100644 index 0000000..3d1383f --- /dev/null +++ b/Bitmap.cpp @@ -0,0 +1,111 @@ +#include "Bitmap.h" + +Bitmap::Bitmap() +{ +} + +Bitmap::~Bitmap() +{ + // Ensure we clean up any existing bitmap + DeleteBitmap(); +} + +// Create a new bitmap of the specified width and height, deleting any existing bitmap +// +// Returns value of false if bitmap cannot be created. + +bool Bitmap::Create(HWND hWnd, unsigned int width, unsigned int height) +{ + bool status = false; + HDC hDc; + + // Delete any existing bitmap + DeleteBitmap(); + + // Create a device context compatible with the window device context + hDc = ::GetDC(hWnd); + _width = width; + _height = height; + _hMemDC = CreateCompatibleDC(hDc); + if (_hMemDC != 0) + { + // Create a bitmap compatible with the window + _hBitmap = CreateCompatibleBitmap(hDc, _width, _height); + if (_hBitmap != 0) + { + // Select the bitmap into the new device context, saving any old bitmap handle + _hOldBitmap = static_cast(SelectObject(_hMemDC, _hBitmap)); + status = true; + } + } + // Release the device context for the window + ReleaseDC(hWnd, hDc); + return status; +} + +// Return device context of bitmap + +HDC Bitmap::GetDC() const +{ + return _hMemDC; +} + +// Return width of bitmap + +unsigned int Bitmap::GetWidth() const +{ + return _width; +} + +// Return height of bitmap + +unsigned int Bitmap::GetHeight() const +{ + return _height; +} + +// Delete any existing bitmap + +void Bitmap::DeleteBitmap() +{ + // Select any default bitmap that existed for the device context + if (_hOldBitmap != 0 && _hMemDC != 0) + { + SelectObject(_hMemDC, _hOldBitmap); + _hOldBitmap = 0; + } + // Delete any existing bitmap + if (_hBitmap != 0) + { + DeleteObject(_hBitmap); + _hBitmap = 0; + } + // Delete any existing bitmap device context + if (_hMemDC != 0) + { + DeleteDC(_hMemDC); + _hMemDC = 0; + } +} + +// Clear bitmap using the specified brush + +void Bitmap::Clear(HBRUSH hBrush) const +{ + RECT rect; + + rect.left = 0; + rect.right = _width; + rect.top = 0; + rect.bottom = _height; + FillRect(_hMemDC, &rect, hBrush); +} + +// Clear bitmap using the specified colour + +void Bitmap::Clear(COLORREF colour) const +{ + HBRUSH brush = CreateSolidBrush(colour); + Clear(brush); + DeleteObject(brush); +} diff --git a/Bitmap.h b/Bitmap.h new file mode 100644 index 0000000..d663647 --- /dev/null +++ b/Bitmap.h @@ -0,0 +1,26 @@ +#pragma once +#include "windows.h" + +class Bitmap +{ +public: + Bitmap(); + ~Bitmap(); + + bool Create(HWND hWnd, unsigned int width, unsigned int height); + HDC GetDC() const; + unsigned int GetWidth() const; + unsigned int GetHeight() const; + void Clear(HBRUSH hBrush) const; + void Clear(COLORREF colour) const; + +private: + HBITMAP _hBitmap{ 0 }; + HBITMAP _hOldBitmap{ 0 }; + HDC _hMemDC{ 0 }; + unsigned int _width{ 0 }; + unsigned int _height{ 0 }; + + void DeleteBitmap(); +}; + diff --git a/Framework.cpp b/Framework.cpp new file mode 100644 index 0000000..c5c6d21 --- /dev/null +++ b/Framework.cpp @@ -0,0 +1,275 @@ +#include "Framework.h" + +const unsigned int DEFAULT_FRAMERATE = 30; + +// Reference to ourselves - primarily used to access the message handler correctly +// This is initialised in the constructor + +Framework * _thisFramework = NULL; + +// Flag set once the framework has been successfully initialised + +bool isInitialised = false; + +// 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(800, 600) +{ +} + +Framework::Framework(unsigned int width, unsigned int height) + : _hInstance(0), _hWnd(0), _width(width), _height(height) +{ + _thisFramework = this; +} + +Framework::~Framework() +{ +} + +int Framework::Run(HINSTANCE hInstance, int nCmdShow) +{ + int returnValue; + + _hInstance = hInstance; + if (!InitialiseMainWindow(nCmdShow)) + { + return -1; + } + if (!Initialise()) + { + return -1; + } + isInitialised = true; + returnValue = MainLoop(); + Shutdown(); + return returnValue; +} + +// Main program loop. + +int Framework::MainLoop() +{ + MSG msg; + HACCEL hAccelTable = LoadAccelerators(_hInstance, MAKEINTRESOURCE(IDC_RASTERISER)); + LARGE_INTEGER counterFrequency; + LARGE_INTEGER nextTime; + LARGE_INTEGER currentTime; + LARGE_INTEGER lastTime; + bool updateFlag = true; + + // Initialise timer + QueryPerformanceFrequency(&counterFrequency); + DWORD msPerFrame = static_cast(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(_bitmap); + updateFlag = false; + } + QueryPerformanceCounter(¤tTime); + // Is it time to render the frame? + if (currentTime.QuadPart > nextTime.QuadPart) + { + Render(_bitmap); + // Make sure that the window gets repainted + InvalidateRect(_hWnd, NULL, FALSE); + // 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; + } + // Each time we go through this loop, we look to see if there is a Windows message + // that needs to be processed + if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) + { + if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + } + return static_cast(msg.wParam); +} + +// 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. + +bool Framework::Initialise() +{ + return true; +} + +// Perform any updates to the structures that will be used +// to render the window (i.e. transformation matrices, etc). +// +// This should be overridden + +void Framework::Update(const Bitmap &bitmap) +{ + // Default update method does nothing +} + +// Render the window. This should be overridden + +void Framework::Render(const Bitmap &bitmap) +{ + // Default render method just sets the background to the default window colour + bitmap.Clear(reinterpret_cast(COLOR_WINDOW + 1)); +} + +// Perform any application shutdown that is needed + +void Framework::Shutdown() +{ +} + +// 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_RASTERISER, 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_RASTERISER)); + wcex.hCursor = LoadCursor(nullptr, IDC_ARROW); + wcex.hbrBackground = reinterpret_cast(COLOR_WINDOW + 1); + wcex.lpszMenuName = nullptr; + wcex.lpszClassName = windowClass; + wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL)); + if (!RegisterClassExW(&wcex)) + { + 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) + { + return false; + } + ShowWindow(_hWnd, nCmdShow); + UpdateWindow(_hWnd); + + // Create a bitmap of the same size as the client area of the window. This is what we + // will be drawing on + RECT clientArea; + GetClientRect(_hWnd, &clientArea); + _bitmap.Create(_hWnd, clientArea.right - clientArea.left, clientArea.bottom - clientArea.top); + 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: + { + // Copy the contents of the bitmap to the window + PAINTSTRUCT ps; + HDC hdc = BeginPaint(hWnd, &ps); + BitBlt(hdc, 0, 0, _bitmap.GetWidth(), _bitmap.GetHeight(), _bitmap.GetDC(), 0, 0, SRCCOPY); + EndPaint(hWnd, &ps); + } + break; + + case WM_SIZE: + // Delete any existing bitmap and create a new one of the required size. + _bitmap.Create(hWnd, LOWORD(lParam), HIWORD(lParam)); + // Now render to the resized bitmap (but only if we are fully initialised) + if (isInitialised) + { + Update(_bitmap); + Render(_bitmap); + InvalidateRect(hWnd, NULL, FALSE); + } + break; + + case WM_DESTROY: + PostQuitMessage(0); + break; + + default: + return DefWindowProc(hWnd, message, wParam, lParam); + } + return 0; +} + diff --git a/Framework.h b/Framework.h new file mode 100644 index 0000000..87c975b --- /dev/null +++ b/Framework.h @@ -0,0 +1,37 @@ +#pragma once +#include +#include "Resource.h" +#include "Bitmap.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); + + virtual bool Initialise(); + virtual void Update(const Bitmap &bitmap); + virtual void Render(const Bitmap &bitmap); + virtual void Shutdown(); + +private: + HINSTANCE _hInstance; + HWND _hWnd; + Bitmap _bitmap; + unsigned int _width; + unsigned int _height; + + // Used in timing loop + double _timeSpan{ 0 }; + + bool InitialiseMainWindow(int nCmdShow); + int MainLoop(); +}; + diff --git a/Matrix.cpp b/Matrix.cpp new file mode 100644 index 0000000..e5a23ed --- /dev/null +++ b/Matrix.cpp @@ -0,0 +1,137 @@ +#include "Matrix.h" + +Matrix::Matrix() : _matrix{ 0 } +{ +} + +Matrix::Matrix(std::initializer_list inputList) : _matrix{ 0 } +{ + if (inputList.size() != ROWS * COLS) + { + throw "You did not provide enough points to create the matrix"; + } + + auto listContainer = inputList.begin(); + for (int i = 0; i < ROWS; i++) + { + for (int j = 0; j < COLS; j++) + { + _matrix[i][j] = *listContainer++; + } + } +} + +Matrix::Matrix(const float arrayIn[ROWS][COLS]) +{ + for (int i = 0; i < ROWS; i++) + { + for (int j = 0; j < COLS; j++) + { + _matrix[i][j] = arrayIn[i][j]; + } + } +} + +Matrix::Matrix(const Matrix& other) +{ + Copy(other); +} + +Matrix::~Matrix() +{ + +} + +float Matrix::GetM(const int row, const int column) const +{ + return GetMatrixCell(row, column); +} + +float Matrix::GetMatrixCell(const int row, const int column) const +{ + return _matrix[row][column]; +} + +void Matrix::SetM(const int row, const int column, const float value) +{ + SetMatrixCell(row, column, value); +} + +void Matrix::SetMatrixCell(const int row, const int column, const float value) +{ + _matrix[row][column] = value; +} + +void Matrix::FromArray(const float arrayIn[ROWS][COLS]) +{ + for (int i = 0; i < ROWS; i++) + { + for (int j = 0; j < COLS; j++) + { + _matrix[i][j] = arrayIn[i][j]; + } + } +} + +Matrix& Matrix::operator= (const Matrix& rhs) +{ + if (this != &rhs) + { + Copy(rhs); + } + return *this; +} + +bool Matrix::operator== (const Matrix& other) const +{ + for (int i = 0; i < ROWS; i++) + { + for (int j = 0; j < COLS; j++) + { + if (_matrix[i][j] != other.GetMatrixCell(i, j)) + { + return false; + } + } + } + return true; +} + +const Matrix Matrix::operator*(const Matrix& other) const +{ + Matrix result; + for (int i = 0; i < ROWS; i++) + { + for (int j = 0; j < COLS; j++) + { + float resultValue = 0; + for (int k = 0; k < ROWS; k++) + { + resultValue += _matrix[i][k] * other.GetMatrixCell(k, j); + } + result.SetMatrixCell(i, j, resultValue); + } + } + return result; +} + +const Vertex Matrix::operator*(const Vertex& other) const +{ + Vertex newVertex(other); + + newVertex.SetX(_matrix[0][0] * other.GetX() + _matrix[0][1] * other.GetY() + _matrix[0][2] * other.GetW()); + newVertex.SetY(_matrix[1][0] * other.GetX() + _matrix[1][1] * other.GetY() + _matrix[1][2] * other.GetW()); + newVertex.SetW(_matrix[2][0] * other.GetX() + _matrix[2][1] * other.GetY() + _matrix[2][2] * other.GetW()); + return newVertex; +} + +void Matrix::Copy(const Matrix& other) +{ + for (int i = 0; i < ROWS; i++) + { + for (int j = 0; j < COLS; j++) + { + _matrix[i][j] = other.GetMatrixCell(i, j); + } + } +} \ No newline at end of file diff --git a/Matrix.h b/Matrix.h new file mode 100644 index 0000000..334d3e7 --- /dev/null +++ b/Matrix.h @@ -0,0 +1,38 @@ +#pragma once + +#include "Vertex.h" +#include + +// Size of the matrix +const int COLS = 3; +const int ROWS = 3; + +class Matrix +{ +public: + Matrix(); + Matrix(std::initializer_list inputList); + // Take in an array of floats matching the cols and rows + Matrix(const float arrayIn[ROWS][COLS]); + Matrix(const Matrix& other); + + ~Matrix(); + + float GetM(const int row, const int column) const; + float GetMatrixCell(const int row, const int column) const; + + void SetM(const int row, const int column, const float value); + void SetMatrixCell(const int row, const int column, const float value); + void FromArray(const float arrayIn[ROWS][COLS]); + + Matrix& operator= (const Matrix& rhs); + + bool operator==(const Matrix& other) const; + const Matrix operator*(const Matrix& other) const; + const Vertex operator*(const Vertex& other) const; + +private: + float _matrix[ROWS][COLS]; + void Copy(const Matrix& other); +}; + diff --git a/Rasteriser.cpp b/Rasteriser.cpp new file mode 100644 index 0000000..a63fb12 --- /dev/null +++ b/Rasteriser.cpp @@ -0,0 +1,97 @@ +#include "Rasteriser.h" +#include + +using namespace std; + +Rasteriser app; + +bool Rasteriser::Initialise() +{ + //_vertexArray.push_back(Vertex(175, 175, 1)); + //_vertexArray.push_back(Vertex(225, 175, 1)); + //_vertexArray.push_back(Vertex(225, 225, 1)); + //_vertexArray.push_back(Vertex(175, 225, 1)); + + _vertexArray.push_back(Vertex(150, 200, 1)); + _vertexArray.push_back(Vertex(187.5f, 187.5f, 1)); + _vertexArray.push_back(Vertex(200, 150, 1)); + _vertexArray.push_back(Vertex(212.5f, 187.5f, 1)); + _vertexArray.push_back(Vertex(250, 200, 1)); + _vertexArray.push_back(Vertex(212.5f, 212.5f, 1)); + _vertexArray.push_back(Vertex(200, 250, 1)); + _vertexArray.push_back(Vertex(187.5, 212.5f, 1)); + + return true; +} + +void Rasteriser::Update(const Bitmap& bitmap) +{ + for (int i = 0; i < _vertexArray.size(); i++) { + _vertexArray[i] = Translate(_vertexArray[i], 2, 0); + _vertexArray[i] = Rotate(_vertexArray[i], 1); + _vertexArray[i] = Scale(_vertexArray[i], 1.001f, 1.001f); + } + +} + +void Rasteriser::Render(const Bitmap& bitmap) +{ + bitmap.Clear(RGB(255, 255, 255)); + SelectObject(bitmap.GetDC(), GetStockObject(DC_BRUSH)); + //DrawSquare(bitmap.GetDC(), _vertexArray); + DrawShape(bitmap.GetDC(), _vertexArray); +} + +Vertex Rasteriser::Translate(const Vertex vertexIn, const float moveXBy, const float moveYBy) +{ + Matrix translationMatrix = Matrix({ 1, 0, moveXBy, 0, 1, moveYBy, 0, 0, 1 }); + return translationMatrix * vertexIn; +} + +Vertex Rasteriser::Scale(const Vertex vertexIn, const float scaleXBy, const float scaleYBy) +{ + Matrix scaleFactorMatrix = Matrix({ scaleXBy, 0, 0, 0, scaleYBy, 0, 0, 0, 1 }); + return scaleFactorMatrix * vertexIn; +} + +Vertex Rasteriser::Rotate(const Vertex vertexIn, const float rotationDegrees) +{ + float rotationRadian = DegreesToRadians(rotationDegrees); + Matrix rotationFactorMatrix = Matrix({ cos(rotationRadian), -sin(rotationRadian), 0, sin(rotationRadian), cos(rotationRadian), 0, 0, 0, 1}); + return rotationFactorMatrix * vertexIn; +} + +float Rasteriser::DegreesToRadians(const float degrees) +{ + return (degrees * _PI) / 180; +} + +void Rasteriser::DrawSquare(HDC hDc, const vector verticies) +{ + POINT pointArray[4]; + for (int i = 0; i < 4; i++) + { + pointArray[i].x = (long) verticies[i].GetX(); + pointArray[i].y = (long) verticies[i].GetY(); + } + + SetDCBrushColor(hDc, RGB(255, 0, 255)); + SetDCPenColor(hDc, RGB(0, 0, 255)); + Polygon(hDc, pointArray, 4); +} + +void Rasteriser::DrawShape(HDC hDc, const vector verticies) +{ + vector pointArray; + for (int i = 0; i < verticies.size(); i++) + { + POINT newPoint; + newPoint.x = (long)verticies[i].GetX(); + newPoint.y = (long)verticies[i].GetY(); + pointArray.push_back(newPoint); + } + + SetDCBrushColor(hDc, RGB(rand() % 256, rand() % 256, rand() % 256)); + SetDCPenColor(hDc, RGB(rand() % 256, rand() % 256, rand() % 256)); + Polygon(hDc, pointArray.data(), (int) verticies.size()); +} \ No newline at end of file diff --git a/Rasteriser.h b/Rasteriser.h new file mode 100644 index 0000000..9ec46d6 --- /dev/null +++ b/Rasteriser.h @@ -0,0 +1,27 @@ +#pragma once +#include "Framework.h" +#include "Vertex.h" +#include "Matrix.h" +#include + +class Rasteriser : public Framework +{ +public: + bool Initialise(); + void Update(const Bitmap& bitmap); + void Render(const Bitmap& bitmap); + + void DrawSquare(HDC hDc, const vector verticies); + void DrawShape(HDC hDc, const vector verticies); + + Vertex Translate(const Vertex vertexIn, const float moveXBy, const float moveYBy); + Vertex Scale(const Vertex vertexIn, const float scaleXBy, const float scaleYBy); + Vertex Rotate(const Vertex vertexIn, const float rotationDegrees); + + float DegreesToRadians(const float degrees); + +private: + vector _vertexArray; + const float _PI = (float) acos(-1); +}; + diff --git a/Rasteriser.ico b/Rasteriser.ico new file mode 100644 index 0000000..b3ec03b Binary files /dev/null and b/Rasteriser.ico differ diff --git a/Rasteriser.rc b/Rasteriser.rc new file mode 100644 index 0000000..2356eff Binary files /dev/null and b/Rasteriser.rc differ diff --git a/Resource.h b/Resource.h new file mode 100644 index 0000000..c6d266c --- /dev/null +++ b/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_RASTERISER 107 +#define IDI_SMALL 108 +#define IDC_RASTERISER 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/Vertex.cpp b/Vertex.cpp new file mode 100644 index 0000000..e889f49 --- /dev/null +++ b/Vertex.cpp @@ -0,0 +1,84 @@ +#include "Vertex.h" + +Vertex::Vertex() +{ + _x = 0.0f; + _y = 0.0f; + _w = 0.0f; +} + +Vertex::Vertex(float x, float y, float w) +{ + _x = x; + _y = y; + _w = w; +} + +Vertex::Vertex(const Vertex & other) +{ + _x = other.GetX(); + _y = other.GetY(); + _w = other.GetW(); +} + +float Vertex::GetX() const +{ + return _x; +} + +void Vertex::SetX(const float x) +{ + _x = x; +} + +float Vertex::GetY() const +{ + return _y; +} + +void Vertex::SetY(const float y) +{ + _y = y; +} + +float Vertex::GetW() const +{ + return _w; +} + +void Vertex::SetW(const float w) +{ + _w = w; +} + +Vertex& Vertex::operator=(const Vertex& rhs) +{ + // Only do the assignment if we are not assigning + // to ourselves + if (this != &rhs) + { + _x = rhs.GetX(); + _y = rhs.GetY(); + _w = rhs.GetW(); + } + return *this; +} + +// The const at the end of the declaraion for '==" indicates that this operation does not change +// any of the member variables in this class. + +bool Vertex::operator==(const Vertex& rhs) const +{ + return (_x == rhs.GetX() && _y == rhs.GetY() && _w == rhs.GetW()); +} + +// You can see three different uses of 'const' here: +// +// The first const indicates that the method changes the return value, but it is not moved in memory +// The second const indicates that the parameter is passed by reference, but it is not modified +// The third const indicates that the operator does not change any of the memory variables in the class. + +const Vertex Vertex::operator+(const Vertex& rhs) const +{ + return Vertex(_x + rhs.GetX(), _y + rhs.GetY(), _w + rhs.GetW()); +} diff --git a/Vertex.h b/Vertex.h new file mode 100644 index 0000000..e206585 --- /dev/null +++ b/Vertex.h @@ -0,0 +1,29 @@ +#pragma once +class Vertex +{ +public: + Vertex(); + Vertex(float x, float y, float w); + Vertex(const Vertex& other); + + // Accessors + float GetX() const; + void SetX(const float x); + float GetY() const; + void SetY(const float y); + float GetW() const; + void SetW(const float w); + + // Assignment operator + Vertex& operator= (const Vertex& rhs); + + bool operator== (const Vertex& rhs) const; + + const Vertex operator+ (const Vertex& rhs) const; + +private: + float _x; + float _y; + float _w; +}; + diff --git a/small.ico b/small.ico new file mode 100644 index 0000000..b3ec03b Binary files /dev/null and b/small.ico differ diff --git a/targetver.h b/targetver.h new file mode 100644 index 0000000..87c0086 --- /dev/null +++ b/targetver.h @@ -0,0 +1,8 @@ +#pragma once + +// Including SDKDDKVer.h defines the highest available Windows platform. + +// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and +// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. + +#include