Improved logger, added a debug timer, other small stuff, and wrote more user guide

This commit is contained in:
grayson committed 2021-12-04 02:17:33 -06:00
1 parent f66c3fb4e0
commit 21764d3f98
25 files changed
+326 -121

No files matched your search

+2
View File
@@ -62,6 +62,7 @@
<AdditionalIncludeDirectories>$(ProjectDir)src\include\;$(ProjectDir)dep\include\</AdditionalIncludeDirectories>
<ObjectFileName>$(IntDir)obj\</ObjectFileName>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<TreatWarningAsError>true</TreatWarningAsError>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@@ -94,6 +95,7 @@
<AdditionalIncludeDirectories>$(ProjectDir)src\include\;$(ProjectDir)dep\include\</AdditionalIncludeDirectories>
<ObjectFileName>$(IntDir)obj\</ObjectFileName>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<TreatWarningAsError>true</TreatWarningAsError>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
+11 -12
View File
@@ -16,8 +16,8 @@ namespace nf {
m_stateChange(false),
m_stateChangeStarted(false)
{
NFLog("Creating NF application");
NFLog("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);
NFLog("Constructing application");
NFLog("Width: " + std::to_string(m_currentConfig.width) + ", Height: " + std::to_string(m_currentConfig.height) + ", Fullscreen: " + (m_currentConfig.fullscreen ? "true" : "false") + ", Title: " + m_currentConfig.title);
if (getApp(true) != nullptr)
NFError("Cannot create two NF Application objects!");
@@ -78,7 +78,9 @@ namespace nf {
}
void Application::run() {
NFLog("Running application...");
#ifdef _DEBUG
Debug::startTimer();
SetThreadDescription(GetCurrentThread(), L"Input Thread");
#endif
if (m_defaultState.empty())
@@ -111,6 +113,9 @@ namespace nf {
std::this_thread::sleep_for(std::chrono::milliseconds(5));
}
mainThread.join();
#ifdef _DEBUG
Debug::stopTimer();
#endif
}
bool Application::hasCustomWindowIcon() {
@@ -118,10 +123,12 @@ namespace nf {
}
void Application::changeState(const std::string& stateName) {
if (m_stateChange) return;
if (m_states.find(stateName) == m_states.end())
NFError("State \"" + (std::string)stateName + (std::string)"\" doesn't exist!");
m_stateChange = true;
m_nextState = m_states[stateName];
NFLog("Changing to state \"" + stateName + (std::string)"\"");
}
Gamestate* Application::getCurrentState() {
@@ -300,7 +307,6 @@ namespace nf {
void Application::quit() {
m_quit = true;
NFLog("Exiting NF application");
}
void Application::runMainGameThread() {
@@ -343,12 +349,11 @@ namespace nf {
}
}
}
m_audio->stopAllSounds();
m_currentState->stop();
delete sIntro;
delete m_physics;
delete m_audio;
delete m_renderer;
delete sIntro;
}
void Application::doStateChange() {
@@ -445,6 +450,7 @@ namespace nf {
break;
}
case WM_CLOSE: {
NFLog("Exiting NF application");
DestroyWindow(hWnd);
return 0;
}
@@ -456,12 +462,5 @@ namespace nf {
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
Application::~Application() {
for (std::pair<std::string, Gamestate*> state : m_states) {
Gamestate* curr = state.second;
delete curr;
}
}
Application* Application::currentApp = nullptr;
}
+1 -3
View File
@@ -59,7 +59,6 @@ namespace nf {
unsigned int cubemapCount = 0;
unsigned int buttonCount = 0;
while (packContents.size()) {
size_t startingPos = packContents.find_first_of("#NFASSET ") + 9;
packContents = packContents.substr(9);
size_t endAssetNamePos = packContents.find_first_of('\n');
std::string assetName = packContents.substr(0, endAssetNamePos);
@@ -206,7 +205,6 @@ namespace nf {
NFError("Could not find full button set in pack \"" + (std::string)packName + (std::string)"\"!");
while (packContentsOBJ.size()) {
size_t startingPos = packContentsOBJ.find_first_of("#NFASSET ") + 9;
packContentsOBJ = packContentsOBJ.substr(9);
size_t endAssetNamePos = packContentsOBJ.find_first_of('\n');
std::string assetName = packContentsOBJ.substr(0, endAssetNamePos);
@@ -223,7 +221,6 @@ namespace nf {
assetContents = packContentsOBJ;
packContentsOBJ = "";
}
size_t assetSize = assetContents.size();
if (extension == "obj") {
AModel* model = new AModel;
@@ -236,6 +233,7 @@ namespace nf {
}
}
assetContents = assetContents.substr(assetContents.find("\n") + 1);
size_t assetSize = assetContents.size();
model->data = new char[assetSize];
std::memcpy(model->data, &assetContents[0], assetSize);
model->size = assetSize;
+14 -5
View File
@@ -17,7 +17,7 @@ namespace nf {
NFError("Could not initialize COM!");
hr = XAudio2Create(&m_engine);
if (FAILED(hr))
NFError("Could not initialize the audio engine!");
NFError("Could not initialize audio engine!");
#ifdef _DEBUG
XAUDIO2_DEBUG_CONFIGURATION debug = { 0 };
debug.TraceMask = XAUDIO2_LOG_ERRORS | XAUDIO2_LOG_WARNINGS;
@@ -25,12 +25,16 @@ namespace nf {
m_engine->SetDebugConfiguration(&debug, 0);
#endif
hr = m_engine->CreateMasteringVoice(&m_masterVoice);
if (hr == HRESULT_FROM_WIN32(ERROR_NOT_FOUND))
if (hr == HRESULT_FROM_WIN32(ERROR_NOT_FOUND)) {
m_isActive = false;
else if (SUCCEEDED(hr))
NFLog("Audio engine not initialized since no audio devices found");
}
else if (SUCCEEDED(hr)) {
m_isActive = true;
NFLog("Initialized audio engine");
}
else
NFError("Could not initialize the audio engine!");
NFError("Could not initialize audio engine!");
m_threadRunning = true;
m_thread = std::thread(&AudioEngine::runAudioThread, this);
}
@@ -42,10 +46,11 @@ namespace nf {
return false;
else if (hr == S_OK) {
m_isActive = true;
NFLog("Initialized audio engine");
return true;
}
else {
NFError("Could not initialize audio!");
NFError("Could not initialize audio engine!");
return false;
}
}
@@ -62,6 +67,9 @@ namespace nf {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
if (!m_isActive)
return;
DWORD cm;
m_masterVoice->GetChannelMask(&cm);
X3DAUDIO_HANDLE x3d;
@@ -192,6 +200,7 @@ namespace nf {
}
AudioEngine::~AudioEngine() {
stopAllSounds();
m_threadRunning = false;
m_thread.join();
m_engine->Release();
+1
View File
@@ -24,6 +24,7 @@ namespace nf {
if (physics)
app->getPhysicsEngine()->newScene();
NFTimerLoad;
onEnter();
m_loading = false;
+2 -1
View File
@@ -22,10 +22,11 @@ namespace nf {
m_member = true;
}
void Entity::create(Asset* modelAsset, Type type) {
void Entity::create(Asset* modelAsset, const Vec3& position, Type type) {
if (m_constructed)
NFError("Entity already created!");
m_constructed = true;
setPosition(position);
m_type = type;
AModel* model;
if ((model = dynamic_cast<AModel*>(modelAsset)) == nullptr)
+1 -2
View File
@@ -140,7 +140,7 @@ namespace nf {
callbacks.close_func = v_close;
callbacks.tell_func = v_tell;
int open = ov_open_callbacks(&memFile, &file, nullptr, 0, callbacks);
ov_open_callbacks(&memFile, &file, nullptr, 0, callbacks);
char* buff = new char[65536 * 1000];
int stream = 0;
@@ -164,7 +164,6 @@ namespace nf {
}
size_t Sound::loadWAV(std::string& data) {
unsigned int fileSize = *(unsigned int*)&data[4];
size_t fmtPos;
if ((fmtPos = data.find("fmt")) == std::string::npos)
NFError("WAV not of correct format!");
+3
View File
@@ -30,6 +30,7 @@ namespace nf {
m_stepSize(1.0f / 60.0f),
m_accumulator(0.0)
{
NFLog("Initializing physics engine...");
m_err = new PhysicsErrorCallback;
m_foundation = PxCreateFoundation(PX_PHYSICS_VERSION, m_alloc, *m_err);
if (!m_foundation)
@@ -54,6 +55,8 @@ namespace nf {
m_dispacher = PxDefaultCpuDispatcherCreate(threads);
m_defaultMat = m_phy->createMaterial(0.5f, 0.5f, 0.0f);
NFLog("Initialized physics engine");
}
void PhysicsEngine::newScene() {
+49 -46
View File
@@ -34,6 +34,7 @@ namespace nf {
m_fadeText(true),
m_fadeOutComplete(false)
{
NFLog("Initializing renderer...");
m_hdc = GetDC(m_app->getWindow());
PIXELFORMATDESCRIPTOR pfd = {
sizeof(PIXELFORMATDESCRIPTOR),
@@ -123,6 +124,8 @@ namespace nf {
m_quadVAO->finishBufferLayout();
m_quadIB = new IndexBuffer(quadIB, 6);
m_loadingText.create("NFLoadingText", Vec2(0.025f, 0.044f), Vec3(0.7f));
NFLog("Initialized renderer");
}
void Renderer::setFade(bool in, bool out, bool text) {
@@ -165,59 +168,57 @@ namespace nf {
glm::mat4 proj = glm::perspective(glm::radians(45.0f), (float)m_app->getConfig().width / (float)m_app->getConfig().height, 0.1f, 1000.0f);
camera->update(m_gBufferShader, m_lightingShader, m_cubemapShader);
//First, fill the gBuffer with entities
m_gBufferShader->setUniform("proj", proj);
m_gBuffer->render(m_lGame, m_gBufferShader);
if (m_lGame.size()) {
//First, fill the gBuffer with entities
m_gBufferShader->setUniform("proj", proj);
m_gBuffer->render(m_lGame, m_gBufferShader);
//Light entities using the gBuffer
size_t lightsRemaining = m_lights.size();
if (!lightsRemaining) {
m_quadVAO->bind();
m_quadIB->bind();
m_lightingShader->bind();
m_gBuffer->bindTextures(m_lightingShader);
glDrawElements(GL_TRIANGLES, m_quadIB->getCount(), GL_UNSIGNED_INT, nullptr);
//Light entities using the gBuffer
size_t lightsRemaining = m_lights.size();
unsigned int drawCount = 0;
do {
size_t currLightsDrawn;
if (lightsRemaining > m_texSlots)
currLightsDrawn = m_texSlots;
else
currLightsDrawn = lightsRemaining;
lightsRemaining -= currLightsDrawn;
m_lightingShader->setUniform("numberOfLights", (int)currLightsDrawn);
if (drawCount == 0)
m_lightingShader->setUniform("isContinued", false);
else {
m_lightingShader->setUniform("isContinued", true);
glBlendFunc(GL_ONE, GL_ONE);
glDepthFunc(GL_LEQUAL);
}
for (unsigned int i = 0; i < currLightsDrawn; i++)
m_lights[i]->bind(m_lightingShader, i);
renderShadowMaps(currLightsDrawn);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glViewport(0, 0, m_app->getConfig().width, m_app->getConfig().height);
m_quadVAO->bind();
m_quadIB->bind();
m_lightingShader->bind();
m_gBuffer->bindTextures(m_lightingShader);
#ifdef _DEBUG
m_lightingShader->validate();
#endif
glDrawElements(GL_TRIANGLES, m_quadIB->getCount(), GL_UNSIGNED_INT, nullptr);
m_lights.erase(m_lights.begin(), m_lights.begin() + currLightsDrawn);
drawCount++;
} while (lightsRemaining > 0);
m_lGame.clear();
m_lights.clear();
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDepthFunc(GL_LESS);
}
unsigned int drawCount = 0;
while (lightsRemaining > 0) {
size_t currLightsDrawn;
if (lightsRemaining > m_texSlots)
currLightsDrawn = m_texSlots;
else
currLightsDrawn = lightsRemaining;
lightsRemaining -= currLightsDrawn;
m_lightingShader->setUniform("numberOfLights", (int)currLightsDrawn);
if(drawCount == 0)
m_lightingShader->setUniform("isContinued", false);
else {
m_lightingShader->setUniform("isContinued", true);
glBlendFunc(GL_ONE, GL_ONE);
glDepthFunc(GL_LEQUAL);
}
for (unsigned int i = 0; i < currLightsDrawn; i++)
m_lights[i]->bind(m_lightingShader, i);
renderShadowMaps(currLightsDrawn);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glViewport(0, 0, m_app->getConfig().width, m_app->getConfig().height);
m_quadVAO->bind();
m_quadIB->bind();
m_lightingShader->bind();
m_gBuffer->bindTextures(m_lightingShader);
glDrawElements(GL_TRIANGLES, m_quadIB->getCount(), GL_UNSIGNED_INT, nullptr);
m_lights.erase(m_lights.begin(), m_lights.begin() + currLightsDrawn);
drawCount++;
}
m_lGame.clear();
m_lights.clear();
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDepthFunc(GL_LESS);
//Draw the cubemap if one is currently set
if (m_cubemap != nullptr) {
m_cubemapShader->setUniform("proj", proj);
m_cubemap->render(m_cubemapShader);
m_cubemap = nullptr;
}
m_cubemap = nullptr;
//Draw UI elements
glDisable(GL_DEPTH_TEST);
@@ -297,6 +298,7 @@ namespace nf {
}
void Renderer::loadBaseAssets() {
NFLog("Loading base assets...");
m_baseAP.load("base.nfpack");
const char* gBufferVertex = m_baseAP.get("gBufferVertex.shader")->data;
const char* gBufferFragment = m_baseAP.get("gBufferFragment.shader")->data;
@@ -334,6 +336,8 @@ namespace nf {
BaseAssets::cubemap = (ACubemap*)m_baseAP.get("default.cm");
BaseAssets::font = (AFont*)m_baseAP.get("default.ttf");
BaseAssets::button = (AButton*)m_baseAP.get("default.button");
NFLog("Base assets loaded");
}
void Renderer::createShadowMaps() {
@@ -371,7 +375,6 @@ namespace nf {
glm::mat4 lightView;
glm::mat4 lightSpaceMat;
bool directionalRendered = false;
unsigned int directionalSlot = 0; //TODO: Test this
glBindFramebuffer(GL_FRAMEBUFFER, m_shadowMapFBO);
for (unsigned int i = 0; i < count; i++) {
Light::Type type = m_lights[i]->getType();
+46 -14
View File
@@ -19,47 +19,79 @@ namespace nf {
#ifdef _DEBUG
NFDEBUGINIT;
void Debug::startTimer() {
m_timerStarted = true;
m_initTime = std::chrono::steady_clock::now();
}
void Debug::stopTimer() {
m_timerStarted = false;
}
void Debug::LogImp(const char* in) {
std::chrono::duration<float> time = getCurrentTime();
std::printf("[%.4f] NF Log: %s\n", time.count(), in);
if(m_timerStarted)
printCurrentTime();
std::printf("NF Log: %s\n", in);
}
void Debug::LogImp(const std::string& in) {
std::chrono::duration<float> time = getCurrentTime();
std::printf("[%.4f] NF Log: ", time.count());
if (m_timerStarted)
printCurrentTime();
std::printf("NF Log: ");
std::cout << in << "\n";
}
void Debug::LogImp(int in) {
std::chrono::duration<float> time = getCurrentTime();
std::printf("[%.4f] NF Log: %i\n", time.count(), in);
if (m_timerStarted)
printCurrentTime();
std::printf("NF Log: %i\n", in);
}
void Debug::LogImp(float in) {
std::chrono::duration<float> time = getCurrentTime();
std::printf("[%.4f] NF Log: %.4f\n", time.count(), in);
if (m_timerStarted)
printCurrentTime();
std::printf("NF Log: %.4f\n", in);
}
//TODO: Test every Error in release mode
void Debug::ErrorImp(const char* in, const char* filename, int line) {
std::chrono::duration<float> time = getCurrentTime();
if (m_timerStarted)
printCurrentTime();
static HANDLE cmd = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(cmd, FOREGROUND_RED);
std::printf("[%.4f] NF Error (%s, %i): %s\n", time.count(), filename, line, in);
std::printf("NF Error (%s, %i): %s\n", filename, line, in);
SetConsoleTextAttribute(cmd, 7);
}
void Debug::ErrorImp(const std::string& in, const char* filename, int line) {
std::chrono::duration<float> time = getCurrentTime();
if (m_timerStarted)
printCurrentTime();
static HANDLE cmd = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(cmd, FOREGROUND_RED);
std::printf("[%.4f] NF Error (%s, %i): ", time.count(), filename, line);
std::printf("NF Error (%s, %i): ", filename, line);
std::cout << in << "\n";
SetConsoleTextAttribute(cmd, 7);
}
std::chrono::duration<float> Debug::getCurrentTime() {
void Debug::printCurrentTime() {
std::chrono::steady_clock::time_point now = std::chrono::high_resolution_clock::now();
return now - m_initTime;
std::chrono::duration<float> dur = now - m_initTime;
std::printf("[%.4f] ", dur.count());
}
Timer::Timer(const std::string& function, bool onEnter) {
m_funcName = function;
m_initTime = std::chrono::steady_clock::now();
m_loading = onEnter;
if (!m_loading)
NFLog("Started timing \"" + m_funcName + (std::string)"\"");
}
Timer::~Timer() {
std::chrono::duration<float> dur = std::chrono::steady_clock::now() - m_initTime;
if (!m_loading)
NFLog("\"" + m_funcName + (std::string)"\" took " + std::to_string(dur.count()) + (std::string)" seconds.");
else
NFLog("Loading took " + std::to_string(dur.count()) + (std::string)" seconds.");
}
#endif
+2 -5
View File
@@ -1,11 +1,8 @@
//This is the main header for the entire engine.
#pragma once
//TODO: Rework this file to only contain functions the frontend will need to access
//Maybe a implementation define here?
//TODO: Prevent including other headers other than this one
#ifndef NFIMPL
#define NFIMPL 1
#define NFIMPL
#endif
#include "nf/Config.h"
-1
View File
@@ -177,7 +177,6 @@ namespace nf {
void getMouseDiff(int& x, int& y);
static Application* getApp(bool first = false);
#endif
~Application();
private:
void registerWindowClass();
RECT getWindowRect() const;
+2 -1
View File
@@ -53,6 +53,7 @@ namespace nf {
/**
* @brief Creates an entity
* @param modelAsset A model Asset pointer
* @param position Initial position vector
* @param type Type of entity; Defaults to Type::STATIC
*
* This function will initialize an entity by loading its associated model from
@@ -61,7 +62,7 @@ namespace nf {
* @warning Calling this function twice before the state exits will result in an
* error. See @ref isConstructed.
*/
void create(Asset* modelAsset, Type type = Type::STATIC);
void create(Asset* modelAsset, const Vec3& position, Type type = Type::STATIC);
/**
* @brief Queries whether or not the entity has been created
* @return If the entity has been created
+3 -3
View File
@@ -14,10 +14,10 @@ namespace nf {
class Texture;
/**
* @brief A state NF can be in that includes a collection of objects and user-defined
* @brief An engine state that includes a world, objects, and user-defined
* behavior
*
* Every user-defined state inherits from this class.
* Every state inherits from this class.
*/
class Gamestate {
public:
@@ -37,7 +37,7 @@ namespace nf {
* @brief Update function
* @param deltaTime Amount of time the previous frame took to produce in seconds
*
* This function is called every frame. It is called before render.
* This function is called every frame. It is called before @ref render.
*
* The deltaTime parameter's purpose is to create non-frame-dependant gameplay. This
* number should be multiplied with user numbers likes velocities. Doing this will
+52 -7
View File
@@ -7,7 +7,7 @@
/**
* @brief Nothin' Fancy namespace
*
* Every class and struct lives inside of this namespace
* Every class and struct lives inside of this namespace.
*
* It could be useful to `using` this namespace:
*
@@ -20,7 +20,15 @@ namespace nf {
//Strips __FILE__ down to only the name of the file
#define __FILENAME__ strrchr(__FILE__, '\\') + 1
//Initializes static variables needed for debugging
#define NFDEBUGINIT std::chrono::steady_clock::time_point Debug::m_initTime = std::chrono::high_resolution_clock::now();
#define NFDEBUGINIT std::chrono::steady_clock::time_point Debug::m_initTime = std::chrono::high_resolution_clock::now(); \
bool Debug::m_timerStarted = false
/**
* @defgroup macros Macros
*
* Macros to aid in debugging and developing with NF
*
* @{
*/
/**
* Pauses the engine for a set amount of seconds
*/
@@ -43,11 +51,33 @@ namespace nf {
*/
#define NFError(x) {nf::Debug::ErrorImp(x,__FILENAME__, __LINE__);\
__debugbreak();}
/**
* @brief Handles NFLog and NFError calls
*/
/**
* A timer useful for timing functions
*
* To time a function, place this macro at the beginning of it:
*
* ~~~
* void myFunc() {
* NFTimer;
* //Rest of function to be timed...
* } //Prints here
* ~~~
*
* The result will be logged when the scope it's declared in ends.
*/
#define NFTimer nf::Timer _nfTimer(__func__)
/**
* @}
*/
#ifndef NFIMPL
#define NFTimerLoad nf::Timer _nfTimer(__func__, true);
#endif
class Debug {
public:
static void startTimer();
static void stopTimer();
static void LogImp(const char* in);
static void LogImp(const std::string& in);
static void LogImp(int in);
@@ -57,8 +87,20 @@ __debugbreak();}
[[noreturn]]
static void ErrorImp(const std::string& in, const char* filename, int line);
private:
static void printCurrentTime();
static std::chrono::steady_clock::time_point m_initTime;
static std::chrono::duration<float> getCurrentTime();
static bool m_timerStarted;
};
class Timer {
public:
Timer(const std::string& function, bool onEnter = false);
~Timer();
private:
std::chrono::steady_clock::time_point m_initTime;
bool m_loading;
std::string m_funcName;
};
#else
#define NFDEBUGINIT
@@ -67,6 +109,8 @@ __debugbreak();}
#define NFLog(x)
#define NFError(x) {MessageBox(FindWindow(L"NFClass", NULL), toWide(x).data(), L"NF Engine Error", MB_OK | MB_ICONERROR);\
std::exit(-1);}
#define NFTimer
#define NFTimerLoad
#endif
/**
@@ -364,10 +408,11 @@ std::exit(-1);}
float w;
};
#ifndef NFIMPL
const std::wstring toWide(const char* in);
const std::wstring toWide(const std::string& in);
Vec4 degToQuat(const Vec3& in);
#endif
/**
* @brief Writes a stream of bytes as as std::string into a file in a specified location