Added Drawable, rewrote changing states, and organized class definitions and macros

This commit is contained in:
Grayson Riffe (Laptop) 2021-08-24 12:31:15 -05:00
parent 1f6bb4630c
commit 2f4e0ebfac
12 changed files with 141 additions and 109 deletions

View File

@ -193,6 +193,7 @@
<ItemGroup>
<ClCompile Include="src\Application.cpp" />
<ClCompile Include="src\IntroGamestate.cpp" />
<ClCompile Include="src\Renderer\Drawable.cpp" />
<ClCompile Include="src\Renderer\IndexBuffer.cpp" />
<ClCompile Include="src\Renderer\Renderer.cpp" />
<ClCompile Include="src\Renderer\Shader.cpp" />
@ -203,6 +204,7 @@
<ItemGroup>
<ClInclude Include="src\include\Application.h" />
<ClInclude Include="src\include\Config.h" />
<ClInclude Include="src\include\Drawable.h" />
<ClInclude Include="src\include\IGamestate.h" />
<ClInclude Include="src\include\IndexBuffer.h" />
<ClInclude Include="src\include\IntroGamestate.h" />

View File

@ -39,6 +39,9 @@
<ClCompile Include="src\Renderer\Shader.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\Renderer\Drawable.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="src\include\Config.h">
@ -77,6 +80,9 @@
<ClInclude Include="src\include\Shader.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\include\Drawable.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Natvis Include="NatvisFile.natvis" />

View File

@ -12,7 +12,9 @@ namespace nf {
Application::Application(Config& config) :
m_currentConfig(config),
m_wndPlacement{ sizeof(m_wndPlacement) },
m_running(false)
m_running(false),
m_defaultStateAdded(false),
m_stateChange(false)
{
Log("Creating NF application");
Log("Width: " + std::to_string(m_currentConfig.width) + ", Height: " + std::to_string(m_currentConfig.height) + ", Fullscreen: " + std::to_string(m_currentConfig.fullscreen) + ", Title: " + m_currentConfig.title);
@ -38,28 +40,25 @@ namespace nf {
SetClassLongPtr(m_window, GCLP_HCURSOR, (LONG_PTR)hCursor);
}
void Application::addState(IGamestate* state, const char* stateName) {
void Application::addState(IGamestate* state,const std::string& stateName) {
if (m_states.find(stateName) == m_states.end()) {
m_states[stateName] = state;
}
else {
else
Error("State \"" + (std::string)stateName + (std::string)"\" already exists!");
}
}
void Application::addDefaultState(const char* stateName) {
void Application::addDefaultState(const std::string& stateName) {
if (!m_defaultStateAdded) {
if (m_states.find(stateName) != m_states.end()) {
m_DefaultState = m_states[stateName];
m_defaultStateAdded = true;
}
else {
else
Error("State \"" + (std::string)stateName + (std::string)"\" doesn't exist!");
}
}
else {
else
Error("More than one default state defined!");
}
}
void Application::run() {
@ -81,6 +80,13 @@ namespace nf {
mainThread.join();
}
void Application::changeState(const std::string& stateName) {
if (m_states.find(stateName) == m_states.end())
Error("State \"" + (std::string)stateName + (std::string)"\" doesn't exist!");
m_stateChange = true;
m_nextState = stateName;
}
void Application::showWindow(bool show) {
if (show)
ShowWindow(m_window, SW_SHOW);
@ -88,15 +94,8 @@ namespace nf {
ShowWindow(m_window, SW_HIDE);
}
void Application::changeState(const char* stateName) {
if (m_states.find(stateName) != m_states.end()) {
m_currentState->onExit();
m_currentState = m_states[stateName];
m_currentState->onEnter(this);
}
else {
Error("State \"" + (std::string)stateName + (std::string)"\" doesn't exist!");
}
const HWND& Application::getWindow() {
return m_window;
}
void Application::changeConfig(const Config& in) {
@ -113,10 +112,6 @@ namespace nf {
SetWindowPos(m_window, HWND_TOP, x, y, in.width, in.height, SWP_NOOWNERZORDER | SWP_FRAMECHANGED);
}
const HWND& Application::getWindow() {
return m_window;
}
const Config& Application::getConfig() const {
return m_currentConfig;
}
@ -134,41 +129,6 @@ namespace nf {
}
}
void Application::startIntroState() {
m_sIntro = new IntroGamestate;
m_sIntro->onEnter(this);
m_currentState = m_sIntro;
}
void Application::runMainGameThread() {
m_renderer = new Renderer(this);
startIntroState();
std::chrono::steady_clock::time_point start_time = std::chrono::steady_clock::now();
const std::chrono::duration<double> wait_time = std::chrono::nanoseconds(1000000000 / 60);
auto next_time = start_time + wait_time;
while (m_running) {
start_time = std::chrono::steady_clock::now();
m_currentState->update();
m_currentState->render();
m_renderer->doFrame();
m_frames++;
m_fpsClock2 = std::chrono::steady_clock::now();
m_fpsDuration = m_fpsClock2 - m_fpsClock1;
if (m_fpsDuration.count() >= 1.0) {
m_FPS = m_frames;
m_frames = 0;
Log("FPS: " + std::to_string(m_FPS));
m_fpsClock1 = std::chrono::steady_clock::now();
//TODO: Rework calculating FPS
}
std::this_thread::sleep_until(next_time);
m_deltaTime = (double)(std::chrono::steady_clock::now() - start_time).count();
next_time += wait_time;
}
m_currentState->onExit();
delete m_renderer;
}
void Application::registerWindowClass() {
if (!FindWindow(L"NFClass", NULL)) {
m_wclassName = L"NFClass";
@ -180,25 +140,8 @@ namespace nf {
wclass.lpfnWndProc = Application::WindowProc;
RegisterClass(&wclass);
}
else {
else
Error("Cannot run two NF applications at once!");
}
}
//TODO: Test fullscreen graphcis
void Application::toggleFullscreen() {
DWORD wndStyle = GetWindowLong(m_window, GWL_STYLE);
if (wndStyle & WS_OVERLAPPEDWINDOW) {
GetWindowPlacement(m_window, &m_wndPlacement);
MONITORINFO mi = { sizeof(mi) };
GetMonitorInfo(MonitorFromWindow(m_window, MONITOR_DEFAULTTOPRIMARY), &mi);
SetWindowLong(m_window, GWL_STYLE, wndStyle & ~WS_OVERLAPPEDWINDOW);
SetWindowPos(m_window, HWND_TOP, mi.rcMonitor.left, mi.rcMonitor.top, mi.rcMonitor.right - mi.rcMonitor.left, mi.rcMonitor.bottom - mi.rcMonitor.top, SWP_NOOWNERZORDER | SWP_FRAMECHANGED);
}
else {
SetWindowLong(m_window, GWL_STYLE, m_defaultWindowStyle);
SetWindowPlacement(m_window, &m_wndPlacement);
SetWindowPos(m_window, NULL, 0, 0, m_currentConfig.width, m_currentConfig.height, SWP_NOMOVE | SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_FRAMECHANGED);
}
}
RECT Application::getWindowRect() const {
@ -222,6 +165,66 @@ namespace nf {
x = monX - (m_currentConfig.width / 2);
y = monY - (m_currentConfig.height / 2);
}
//TODO: Test fullscreen graphcis
void Application::toggleFullscreen() {
DWORD wndStyle = GetWindowLong(m_window, GWL_STYLE);
if (wndStyle & WS_OVERLAPPEDWINDOW) {
GetWindowPlacement(m_window, &m_wndPlacement);
MONITORINFO mi = { sizeof(mi) };
GetMonitorInfo(MonitorFromWindow(m_window, MONITOR_DEFAULTTOPRIMARY), &mi);
SetWindowLong(m_window, GWL_STYLE, wndStyle & ~WS_OVERLAPPEDWINDOW);
SetWindowPos(m_window, HWND_TOP, mi.rcMonitor.left, mi.rcMonitor.top, mi.rcMonitor.right - mi.rcMonitor.left, mi.rcMonitor.bottom - mi.rcMonitor.top, SWP_NOOWNERZORDER | SWP_FRAMECHANGED);
}
else {
SetWindowLong(m_window, GWL_STYLE, m_defaultWindowStyle);
SetWindowPlacement(m_window, &m_wndPlacement);
SetWindowPos(m_window, NULL, 0, 0, m_currentConfig.width, m_currentConfig.height, SWP_NOMOVE | SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_FRAMECHANGED);
}
}
void Application::runMainGameThread() {
m_renderer = new Renderer(this);
startIntroState();
std::chrono::steady_clock::time_point start_time = std::chrono::steady_clock::now();
const std::chrono::duration<double> wait_time = std::chrono::nanoseconds(1000000000 / 60);
auto next_time = start_time + wait_time;
while (m_running) {
start_time = std::chrono::steady_clock::now();
m_currentState->update();
m_currentState->render();
m_renderer->doFrame();
m_frames++;
if (m_stateChange)
doStateChange();
m_fpsClock2 = std::chrono::steady_clock::now();
m_fpsDuration = m_fpsClock2 - m_fpsClock1;
if (m_fpsDuration.count() >= 1.0) {
m_FPS = m_frames;
m_frames = 0;
Log("FPS: " + std::to_string(m_FPS));
m_fpsClock1 = std::chrono::steady_clock::now();
//TODO: Rework calculating FPS
}
std::this_thread::sleep_until(next_time);
m_deltaTime = (double)(std::chrono::steady_clock::now() - start_time).count();
next_time += wait_time;
}
m_currentState->onExit();
delete m_renderer;
}
void Application::startIntroState() {
m_sIntro = new IntroGamestate;
m_sIntro->onEnter(this);
m_currentState = m_sIntro;
}
void Application::doStateChange() {
m_stateChange = false;
m_currentState->onExit();
m_currentState = m_states[m_nextState];
m_currentState->onEnter(this);
}
LRESULT CALLBACK Application::WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
Application* app = (Application*)GetProp(hWnd, L"App");
@ -294,7 +297,7 @@ namespace nf {
Application::~Application() {
Log("Exiting NF application");
for (std::pair<const char*, IGamestate*> state : m_states) {
for (std::pair<std::string, IGamestate*> state : m_states) {
IGamestate* curr = state.second;
delete curr;
}

View File

@ -0,0 +1,11 @@
#include "Drawable.h"
namespace nf {
Drawable::Drawable() {
}
Drawable::~Drawable() {
}
}

View File

@ -33,9 +33,8 @@ namespace nf {
m_hglrc = wglCreateContext(m_hdc);
wglMakeCurrent(m_hdc, m_hglrc);
glewExperimental = GL_TRUE;
if (glewInit() != GLEW_OK) {
if (glewInit() != GLEW_OK)
Error("Could not initialize GLEW!");
}
const int attrib[] = {
WGL_CONTEXT_MAJOR_VERSION_ARB, 3,
WGL_CONTEXT_MINOR_VERSION_ARB, 3,
@ -57,9 +56,8 @@ namespace nf {
SwapBuffers(m_hdc);
GLenum err = glGetError();
if (err != GL_NO_ERROR) {
if (err != GL_NO_ERROR)
Error("OpenGL error " + std::to_string(err));
}
}
Renderer::~Renderer() {

View File

@ -49,9 +49,8 @@ namespace nf {
//TODO: Create overloaded setUniform function
void Shader::getUniformLocation(const char* uniformName) {
unsigned int loc = glGetUniformLocation(m_id, uniformName);
if (loc == -1) {
if (loc == -1)
Error("Uniform \"" + (std::string)uniformName + "\" does not exist!");
}
m_uniformLocations[uniformName] = loc;
}

View File

@ -14,9 +14,8 @@ namespace nf {
}
void VertexArray::addBuffer(const void* data, const size_t size) {
if (!m_lastBufferHasLayout) {
if (!m_lastBufferHasLayout)
Error("Buffer added to vertex array has no layout!");
}
m_buffers.push_back(new VertexBuffer(data, size));
m_buffers.back()->bind();
m_lastBufferHasLayout = false;
@ -25,9 +24,8 @@ namespace nf {
template<>
void VertexArray::push<float>(unsigned int count) {
if (m_lastBufferHasLayout) {
if (m_lastBufferHasLayout)
Error("Tried to modify a vertex array's buffer after the layout was final!");
}
m_lastBufferLayout.push_back({ GL_FLOAT, count, GL_FALSE });
m_lastStride += count * sizeof(GL_FLOAT);
}
@ -45,12 +43,10 @@ namespace nf {
}
void VertexArray::bind(unsigned int buffer) {
if (m_buffers.empty()) {
if (m_buffers.empty())
Error("No buffers and layouts added to vertex array before being bound!");
}
if (!m_lastBufferHasLayout) {
if (!m_lastBufferHasLayout)
Error("Buffer added to vertex array has no layout!");
}
glBindVertexArray(m_id);
}

View File

@ -84,10 +84,8 @@ namespace nf {
}
std::ofstream out;
out.open(filename);
if (!out) {
if (!out)
Error("File \"" + (std::string)filename + (std::string)"\" could not be written!");
return false;
}
out << in;
out.close();
return true;
@ -96,10 +94,8 @@ namespace nf {
std::string readFile(const char* filename) {
std::ifstream in;
in.open(filename);
if (!in) {
if (!in)
Error("File \"" + (std::string)filename + (std::string)"\" could not be read!");
return NULL;
}
std::stringstream ss;
ss << in.rdbuf();
return ss.str();

View File

@ -17,11 +17,11 @@ namespace nf {
void setWindowIcon(HANDLE hIcon);
void setWindowCursor(HCURSOR hCursor);
void addState(IGamestate* state, const char* stateName);
void addDefaultState(const char* stateName);
void addState(IGamestate* state, const std::string& stateName);
void addDefaultState(const std::string& stateName);
void run();
void changeState(const std::string& stateName);
void showWindow(bool show);
void changeState(const char* stateName);
const HWND& getWindow();
void changeConfig(const Config& in);
const Config& getConfig() const;
@ -30,12 +30,13 @@ namespace nf {
~Application();
private:
void startIntroState();
void runMainGameThread();
void registerWindowClass();
void toggleFullscreen();
RECT getWindowRect() const;
void calculateNewWindowPos(int& x, int& y);
void toggleFullscreen();
void runMainGameThread();
void startIntroState();
void doStateChange();
static LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
@ -56,13 +57,15 @@ namespace nf {
const double m_minFrametime = 1.0 / m_targetFPS;
int m_FPS;
//Inactive states states to potentially be active during the Application's lifetime
//Inactive states to potentially be active during the Application's lifetime
//Mapped to const char* to be referenced later in the frontend
std::unordered_map<const char*, IGamestate*> m_states;
std::unordered_map<std::string, IGamestate*> m_states;
IntroGamestate* m_sIntro;
IGamestate* m_DefaultState;
bool m_defaultStateAdded = false;
bool m_defaultStateAdded;
IGamestate* m_currentState;
bool m_stateChange;
std::string m_nextState;
//Array of booleans that represent keyboard and mouse input minus the scrollwheel
bool m_input[164];

View File

@ -0,0 +1,12 @@
#pragma once
namespace nf {
class Drawable {
public:
Drawable();
~Drawable();
private:
};
}

View File

@ -1,6 +1,9 @@
#pragma once
#include <vector>
#include <Windows.h>
#include "Drawable.h"
namespace nf {
class Application;
@ -16,5 +19,8 @@ namespace nf {
HDC m_hdc;
HGLRC m_hglrc;
std::vector<Drawable*> m_lGame;
std::vector<Drawable*> m_lUI;
};
}

View File

@ -16,8 +16,8 @@ namespace nf {
//Prints a nicely-formatted message complete with a timestamp
#define Log(x) nf::Debug::LogImp(x)
//Prints error message and breaks the debugger
#define Error(x) nf::Debug::ErrorImp(x,__FILENAME__, __LINE__);\
__debugbreak();
#define Error(x) {nf::Debug::ErrorImp(x,__FILENAME__, __LINE__);\
__debugbreak();}
class Debug {
private:
@ -34,8 +34,8 @@ __debugbreak();
#else
#define DEBUGINIT
#define Log(x)
#define Error(x) MessageBox(FindWindow(L"NFClass", NULL), toWide(x), L"NF Engine Error", MB_OK | MB_ICONERROR);\
std::exit(-1)
#define Error(x) {MessageBox(FindWindow(L"NFClass", NULL), toWide(x), L"NF Engine Error", MB_OK | MB_ICONERROR);\
std::exit(-1);}
#endif
const wchar_t* toWide(const char* in);