Started writing a manual; Lots of changes

This commit is contained in:
grayson committed 2021-11-25 14:01:20 -06:00
1 parent f884847513
commit 3b5b608ae9
53 files changed
+3851 -241

No files matched your search

+2 -2
View File
@@ -57,7 +57,7 @@
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NFENGINE; GLEW_STATIC;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>GLEW_STATIC;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>$(ProjectDir)src\include\;$(ProjectDir)dep\include\</AdditionalIncludeDirectories>
<ObjectFileName>$(IntDir)obj\</ObjectFileName>
@@ -89,7 +89,7 @@
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NFENGINE; GLEW_STATIC;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>GLEW_STATIC;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>$(ProjectDir)src\include\;$(ProjectDir)dep\include\</AdditionalIncludeDirectories>
<ObjectFileName>$(IntDir)obj\</ObjectFileName>
+24 -24
View File
@@ -5,7 +5,7 @@
#include "Utility.h"
namespace nf {
DEBUGINIT;
NFDEBUGINIT;
Application::Application(Config& config) :
m_currentConfig(config),
@@ -18,21 +18,12 @@ namespace nf {
m_stateChange(false),
m_stateChangeStarted(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);
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);
if (getApp(true) != nullptr)
Error("Cannot create two NF Application objects!");
NFError("Cannot create two NF Application objects!");
setApp(this);
m_hInst = GetModuleHandle(NULL);
registerWindowClass();
RECT windowSize = getWindowRect();
int x = 0;
int y = 0;
calculateNewWindowPos(x, y);
m_window = CreateWindowEx(NULL, m_wclassName, toWide(m_currentConfig.title).data(), WS_OVERLAPPED | WS_SYSMENU | WS_MINIMIZEBOX, x, y, windowSize.right, windowSize.bottom, NULL, NULL, m_hInst, NULL);
SetProp(m_window, L"App", this);
if (m_currentConfig.fullscreen) toggleFullscreen();
}
void Application::setWindowIcon(HICON hIcon) {
@@ -47,19 +38,19 @@ namespace nf {
Renderer* Application::getRenderer() const {
if (!m_renderer)
Error("Application not running yet!");
NFError("Application not running yet!");
return m_renderer;
}
AudioEngine* Application::getAudioEngine() const {
if(!m_audio)
Error("Application not running yet!");
NFError("Application not running yet!");
return m_audio;
}
PhysicsEngine* Application::getPhysicsEngine() const {
if (!m_physics)
Error("Application not running yet!");
NFError("Application not running yet!");
return m_physics;
}
@@ -68,7 +59,7 @@ namespace nf {
m_states[stateName] = state;
}
else
Error("State \"" + (std::string)stateName + (std::string)"\" already exists!");
NFError("State \"" + (std::string)stateName + (std::string)"\" already exists!");
}
void Application::setDefaultState(const std::string& stateName) {
@@ -78,10 +69,10 @@ namespace nf {
m_defaultStateAdded = true;
}
else
Error("State \"" + (std::string)stateName + (std::string)"\" doesn't exist!");
NFError("State \"" + (std::string)stateName + (std::string)"\" doesn't exist!");
}
else
Error("More than one default state defined!");
NFError("More than one default state defined!");
}
const std::string& Application::getDefaultState() {
@@ -92,6 +83,15 @@ namespace nf {
#ifdef _DEBUG
SetThreadDescription(GetCurrentThread(), L"Input Thread");
#endif
m_hInst = GetModuleHandle(NULL);
registerWindowClass();
RECT windowSize = getWindowRect();
int x = 0;
int y = 0;
calculateNewWindowPos(x, y);
m_window = CreateWindowEx(NULL, m_wclassName, toWide(m_currentConfig.title).data(), WS_OVERLAPPED | WS_SYSMENU | WS_MINIMIZEBOX, x, y, windowSize.right, windowSize.bottom, NULL, NULL, m_hInst, NULL);
SetProp(m_window, L"App", this);
if (m_currentConfig.fullscreen) toggleFullscreen();
showWindow(true);
m_running = true;
MSG msg = { };
@@ -119,7 +119,7 @@ namespace nf {
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!");
NFError("State \"" + (std::string)stateName + (std::string)"\" doesn't exist!");
m_stateChange = true;
m_nextState = m_states[stateName];
}
@@ -210,7 +210,7 @@ namespace nf {
Application* Application::getApp(bool first) {
if (!currentApp && !first)
Error("No Application has been created yet!");
NFError("No Application has been created yet!");
return currentApp;
}
@@ -226,7 +226,7 @@ namespace nf {
RegisterClass(&wclass);
}
else
Error("Cannot run multiple NF applications concurrently!");
NFError("Cannot run multiple NF applications concurrently!");
}
RECT Application::getWindowRect() const {
@@ -303,7 +303,7 @@ namespace nf {
void Application::quit() {
m_quit = true;
Log("Exiting NF application");
NFLog("Exiting NF application");
}
void Application::runMainGameThread() {
@@ -340,7 +340,7 @@ namespace nf {
static int i = 0;
i++;
if (i % 5 == 0)
Log("FPS: " + std::to_string(m_FPS));
NFLog("FPS: " + std::to_string(m_FPS));
#endif
m_fpsClock1 = std::chrono::steady_clock::now();
}
+20 -7
View File
@@ -44,7 +44,9 @@ namespace nf {
}
AssetPack::AssetPack() {
AssetPack::AssetPack() :
m_loaded(false)
{
}
@@ -87,7 +89,7 @@ namespace nf {
}
curr = cubemaps[cmName];
if (curr->numImages == 6)
Error("Duplicate cubemap images in pack \"" + (std::string)packName + (std::string)"\"!");
NFError("Duplicate cubemap images in pack \"" + (std::string)packName + (std::string)"\"!");
if (assetName.find("_cmfront") != std::string::npos) {
curr->frontData = new char[assetSize];
std::memcpy(curr->frontData, &assetContents[0], assetSize);
@@ -135,7 +137,7 @@ namespace nf {
}
curr = buttons[buttonName];
if (curr->numImages == 3)
Error("Duplicate button images in pack \"" + (std::string)packName + (std::string)"\"!");
NFError("Duplicate button images in pack \"" + (std::string)packName + (std::string)"\"!");
if (assetName.find("_buttonidle") != std::string::npos) {
curr->idleTex.data = new char[assetSize];
std::memcpy(curr->idleTex.data, &assetContents[0], assetSize);
@@ -196,12 +198,12 @@ namespace nf {
m_assets[assetName] = sound;
continue;
}
Error("Invalid asset extention in pack \"" + (std::string)packName + (std::string)"\"!");
NFError("Invalid asset extention in pack \"" + (std::string)packName + (std::string)"\"!");
}
if (cubemapCount % 6 != 0)
Error("Could not find full cubemap in pack \"" + (std::string)packName + (std::string)"\"!");
NFError("Could not find full cubemap in pack \"" + (std::string)packName + (std::string)"\"!");
if (buttonCount % 3 != 0)
Error("Could not find full button set in pack \"" + (std::string)packName + (std::string)"\"!");
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;
@@ -244,26 +246,35 @@ namespace nf {
}
}
m_loaded = true;
if (packName != "base.nfpack") {
if (!Application::getApp()->getCurrentState()->isRunning())
Application::getApp()->getCurrentState()->m_nfObjects.push_back(this);
}
}
bool AssetPack::isLoaded() {
return m_loaded;
}
Asset* AssetPack::get(const char* in) {
if (!m_loaded) NFError("AssetPack has not been loaded yet!");
if (m_assets.find(in) == m_assets.end())
Error("Could not find asset \"" + (std::string)in + (std::string)"\" in asset pack!");
NFError("Could not find asset \"" + (std::string)in + (std::string)"\" in asset pack!");
return m_assets[in];
}
Asset* AssetPack::get(std::string& in) {
if (!m_loaded) NFError("AssetPack has not been loaded yet!");
return get(in.c_str());
}
Asset* AssetPack::operator[](const char* in) {
if (!m_loaded) NFError("AssetPack has not been loaded yet!");
return get(in);
}
Asset* AssetPack::operator[](std::string& in) {
if (!m_loaded) NFError("AssetPack has not been loaded yet!");
return get(in.c_str());
}
@@ -275,6 +286,8 @@ namespace nf {
for (auto curr : m_assets)
delete curr.second;
m_assets.clear();
m_loaded = false;
}
AssetPack::~AssetPack() {
+5 -5
View File
@@ -14,10 +14,10 @@ namespace nf {
{
HRESULT hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
if (FAILED(hr))
Error("Could not initialize COM!");
NFError("Could not initialize COM!");
hr = XAudio2Create(&m_engine);
if (FAILED(hr))
Error("Could not initialize the audio engine!");
NFError("Could not initialize the audio engine!");
#ifdef _DEBUG
XAUDIO2_DEBUG_CONFIGURATION debug = { 0 };
debug.TraceMask = XAUDIO2_LOG_ERRORS | XAUDIO2_LOG_WARNINGS;
@@ -30,7 +30,7 @@ namespace nf {
else if (SUCCEEDED(hr))
m_isActive = true;
else
Error("Could not initialize the audio engine!");
NFError("Could not initialize the audio engine!");
m_threadRunning = true;
m_thread = std::thread(&AudioEngine::runAudioThread, this);
}
@@ -45,7 +45,7 @@ namespace nf {
return true;
}
else {
Error("Could not initialize audio!");
NFError("Could not initialize audio!");
return false;
}
}
@@ -115,7 +115,7 @@ namespace nf {
break;
}
else if (!SUCCEEDED(hr))
Error("Could not play sound!");
NFError("Could not play sound!");
curr.voice = source;
curr.voice->SubmitSourceBuffer(curr.buffer);
curr.voice->SetVolume(curr.volume);
+4 -4
View File
@@ -39,15 +39,15 @@ namespace nf {
}
void Gamestate::onEnter() {
Error("Gamestate has no overridden onEnter function!");
NFError("Gamestate has no overridden onEnter function!");
}
void Gamestate::update(float deltaTime) {
Error("Gamestate has no overridden update function!");
NFError("Gamestate has no overridden update function!");
}
void Gamestate::render(Renderer& renderer) {
Error("Gamestate has no overridden render function!");
NFError("Gamestate has no overridden render function!");
}
Camera* Gamestate::getCamera() {
@@ -67,7 +67,7 @@ namespace nf {
}
void Gamestate::onExit() {
Error("Gamestate has no overridden onExit function!");
NFError("Gamestate has no overridden onExit function!");
}
void Gamestate::stop() {
+2 -2
View File
@@ -6,7 +6,7 @@
namespace nf {
void IntroGamestate::onEnter() {
Log("Intro onEnter!");
NFLog("Intro onEnter!");
m_scale = 2.0;
m_logoTex.create(BaseAssets::logo, Vec2(0.0, 0.0));
m_logoTex.centered(true, true);
@@ -37,6 +37,6 @@ namespace nf {
}
void IntroGamestate::onExit() {
Log("Intro onExit!");
NFLog("Intro onExit!");
}
}
+3 -3
View File
@@ -23,7 +23,7 @@ namespace nf {
void Button::create(const Vec2& position, std::string string, Asset* buttonAsset, float scale, float opacity) {
if (m_constructed)
Error("Button already created!");
NFError("Button already created!");
m_constructed = true;
m_position = position;
m_string = string;
@@ -36,12 +36,12 @@ namespace nf {
m_text.setOpacity(m_opacity);
AButton* button;
if ((button = dynamic_cast<AButton*>(buttonAsset)) == nullptr)
Error("Non-button asset passed to Button::create!");
NFError("Non-button asset passed to Button::create!");
m_idleTexture = new Texture(&button->idleTex);
m_hoverTexture = new Texture(&button->hoverTex);
m_pressedTexture = new Texture(&button->pressedTex);
if (!((m_idleTexture->getDimensions() == m_hoverTexture->getDimensions()) && (m_idleTexture->getDimensions() == m_pressedTexture->getDimensions()))) {
Error("Button images are not the same size!");
NFError("Button images are not the same size!");
}
float tc[3][4] = {
0.0, 1.0,
+1 -1
View File
@@ -18,7 +18,7 @@ namespace nf {
void Cubemap::create(Asset* cubemapAsset) {
if (m_constructed)
Error("Cubemap already created!");
NFError("Cubemap already created!");
m_constructed = true;
ACubemap& cm = *(ACubemap*)cubemapAsset;
glGenTextures(1, &m_id);
+2 -2
View File
@@ -24,12 +24,12 @@ namespace nf {
void Entity::create(Asset* modelAsset, Type type) {
if (m_constructed)
Error("Entity already created!");
NFError("Entity already created!");
m_constructed = true;
m_type = type;
AModel* model;
if ((model = dynamic_cast<AModel*>(modelAsset)) == nullptr)
Error("Non-model asset passed to Entity::create!");
NFError("Non-model asset passed to Entity::create!");
if (model->alreadyLoaded) {
m_model = model->loadedModel;
}
+1 -1
View File
@@ -14,7 +14,7 @@ namespace nf {
void Light::create(const Vec3& position, const Vec3& color, float strength, Type type) {
if (m_constructed)
Error("Light already created!");
NFError("Light already created!");
m_constructed = true;
m_position = position;
m_color = color;
+5 -5
View File
@@ -94,11 +94,11 @@ namespace nf {
void Sound::create(Asset* soundAsset) {
if (m_constructed)
Error("Sound already created!");
NFError("Sound already created!");
m_constructed = true;
ASound* sound;
if ((sound = dynamic_cast<ASound*>(soundAsset)) == nullptr)
Error("Non-sound asset passed to Sound::create!");
NFError("Non-sound asset passed to Sound::create!");
std::string data(sound->data, sound->size);
size_t dataSize;
@@ -107,7 +107,7 @@ namespace nf {
else if (data.find("RIFF") == 0)
dataSize = loadWAV(data);
else
Error("Sound asset not of correct format!");
NFError("Sound asset not of correct format!");
m_xBuffer.pAudioData = (unsigned char*)m_buffer;
m_xBuffer.AudioBytes = (unsigned int)dataSize;
@@ -167,11 +167,11 @@ namespace nf {
unsigned int fileSize = *(unsigned int*)&data[4];
size_t fmtPos;
if ((fmtPos = data.find("fmt")) == std::string::npos)
Error("WAV not of correct format!");
NFError("WAV not of correct format!");
std::memcpy(&m_format, &data[fmtPos + 8], 16);
size_t dataPos;
if ((dataPos = data.find("data")) == std::string::npos)
Error("WAV not of correct m_format!");
NFError("WAV not of correct m_format!");
unsigned int dataSize = *(unsigned int*)&data[dataPos + 4];
m_buffer = new char[dataSize];
std::memcpy(m_buffer, &data[dataPos + 8], dataSize);
+4 -4
View File
@@ -19,7 +19,7 @@ namespace nf {
void Text::create(const std::string& string, const Vec2& position, const Vec3& color, float opacity, float scale, Asset* fontAsset) {
if (m_constructed)
Error("Text already created!");
NFError("Text already created!");
m_constructed = true;
m_string = string;
m_position = position;
@@ -28,7 +28,7 @@ namespace nf {
m_opacity = opacity;
AFont* font;
if ((font = dynamic_cast<AFont*>(fontAsset)) == nullptr)
Error("Non-font asset passed to Text::create!");
NFError("Non-font asset passed to Text::create!");
if (font->alreadyLoaded) {
m_font = font->loadedFont;
}
@@ -36,10 +36,10 @@ namespace nf {
m_font = new Font;
FT_Library ft;
if (FT_Init_FreeType(&ft))
Error("Could not initialize FreeType!");
NFError("Could not initialize FreeType!");
FT_Face face;
if (FT_New_Memory_Face(ft, (const unsigned char*)font->data, (unsigned int)font->size, 0, &face))
Error("Could not load font!");
NFError("Could not load font!");
FT_Set_Pixel_Sizes(face, 0, 160);
for (unsigned char c = 0; c < 128; c++) {
FT_Load_Char(face, c, FT_LOAD_RENDER);
+2 -2
View File
@@ -18,11 +18,11 @@ namespace nf {
void UITexture::create(Asset* textureAsset, const Vec2& position, float scale, float opacity) {
if (m_constructed)
Error("UITexture already created!");
NFError("UITexture already created!");
m_constructed = true;
ATexture* tex;
if ((tex = dynamic_cast<ATexture*>(textureAsset)) == nullptr)
Error("Non-texture asset passed to UITexture::create!");
NFError("Non-texture asset passed to UITexture::create!");
m_position = position;
m_scale = scale;
m_opacity = opacity;
+7 -7
View File
@@ -11,7 +11,7 @@ namespace nf {
Debug::ErrorImp(message, file, line);
__debugbreak();
#else
Error(message);
NFError(message);
#endif
}
};
@@ -33,7 +33,7 @@ namespace nf {
m_err = new PhysicsErrorCallback;
m_foundation = PxCreateFoundation(PX_PHYSICS_VERSION, m_alloc, *m_err);
if (!m_foundation)
Error("Could not initialize physics engine!");
NFError("Could not initialize physics engine!");
#ifdef _DEBUG
m_pvd = PxCreatePvd(*m_foundation);
@@ -43,11 +43,11 @@ namespace nf {
m_phy = PxCreatePhysics(PX_PHYSICS_VERSION, *m_foundation, PxTolerancesScale(), false, m_pvd);
if (!m_phy)
Error("Could not initialize physics engine!");
NFError("Could not initialize physics engine!");
m_cooking = PxCreateCooking(PX_PHYSICS_VERSION, *m_foundation, PxCookingParams(PxTolerancesScale()));
if (!m_cooking)
Error("Could not initialize physics engine!");
NFError("Could not initialize physics engine!");
unsigned int threads = std::thread::hardware_concurrency() - 1;
if (threads < 0) threads = 0;
@@ -177,7 +177,7 @@ namespace nf {
PxDefaultMemoryOutputStream buf;
if (!m_cooking->cookConvexMesh(desc, buf))
Error("Could not create convex mesh!");
NFError("Could not create convex mesh!");
PxDefaultMemoryInputData in(buf.getData(), buf.getSize());
PxConvexMesh* mesh = m_phy->createConvexMesh(in);
@@ -195,7 +195,7 @@ namespace nf {
PxDefaultMemoryOutputStream buf;
if (!m_cooking->cookTriangleMesh(desc, buf))
Error("Could not create triangle mesh!");
NFError("Could not create triangle mesh!");
PxDefaultMemoryInputData in(buf.getData(), buf.getSize());
PxTriangleMesh* mesh = m_phy->createTriangleMesh(in);
@@ -218,7 +218,7 @@ namespace nf {
else if (m_triangleMeshes.find(entity->getModel()) != m_triangleMeshes.end())
triangleMesh = m_triangleMeshes[entity->getModel()];
else
Error("No physics mesh found for this entity!");
NFError("No physics mesh found for this entity!");
//Dynamic or static
if (type == Entity::Type::DYNAMIC) {
+11 -18
View File
@@ -31,30 +31,23 @@ namespace nf {
return m_type;
}
void Camera::moveForward(float speed) {
Vec3 temp = m_front * speed;
void Camera::move(const Vec2& offset) {
moveX(offset.x);
moveZ(offset.y);
}
void Camera::moveZ(float offset) {
Vec3 temp = m_front * offset;
m_position += temp;
}
void Camera::moveBackward(float speed) {
Vec3 temp = m_front * speed;
m_position -= temp;
}
void Camera::moveRight(float speed) {
void Camera::moveX(float offset) {
glm::vec3 front = { m_front.x, m_front.y, m_front.z };
glm::vec3 temp = glm::normalize(glm::cross(front, glm::vec3(0.0, 1.0, 0.0))) * speed;
glm::vec3 temp = glm::normalize(glm::cross(front, glm::vec3(0.0, 1.0, 0.0))) * offset;
Vec3 move = { temp.x, temp.y, temp.z };
m_position += move;
}
void Camera::moveLeft(float speed) {
glm::vec3 front = { m_front.x, m_front.y, m_front.z };
glm::vec3 temp = glm::normalize(glm::cross(front, glm::vec3(0.0, 1.0, 0.0))) * speed;
Vec3 move = { temp.x, temp.y, temp.z };
m_position -= move;
}
void Camera::setPosition(float x, float y, float z) {
m_position = { x, y, z };
}
@@ -81,7 +74,7 @@ namespace nf {
return m_front;
}
void Camera::bind(Shader* gBufferShader, Shader* lightingShader, Shader* cubemapShader) {
void Camera::update(Shader* gBufferShader, Shader* lightingShader, Shader* cubemapShader) {
glm::mat4 view;
switch (m_type) {
@@ -104,7 +97,7 @@ namespace nf {
break;
}
case Type::ORBIT: {
//TODO: Camera orbit mode
break;
}
case Type::FIXED: {
+1 -1
View File
@@ -11,7 +11,7 @@ namespace nf {
}
void Drawable::bind() {
Error("Tried to bind an invalid object!");
NFError("Tried to bind an invalid object!");
}
unsigned int Drawable::getIndexCount() {
+5 -5
View File
@@ -19,7 +19,7 @@ namespace nf {
m_newLine("\n")
{
if (model->neededTextures.size() > 32)
Error("Model exceedes 32 texture limit!");
NFError("Model exceedes 32 texture limit!");
std::vector<char> file(model->data, model->data + model->size);
size_t mtlPos = std::search(file.begin(), file.end(), m_newMtl, m_newMtl + std::strlen(m_newMtl)) - file.begin();
std::vector<char> mtl(&file[mtlPos], &file[0] + file.size());
@@ -72,15 +72,15 @@ namespace nf {
}
else if (std::strcmp(&firstWord[0], "f") == 0) {
if (!tcPresent)
Error("No texture coordinates found in model!");
NFError("No texture coordinates found in model!");
if (!vnPresent)
Error("No normals found in model!");
NFError("No normals found in model!");
unsigned int vertexIndex[3], uvIndex[3], vnIndex[3];
char temp;
ss >> vertexIndex[0] >> temp >> uvIndex[0] >> temp >> vnIndex[0] >> vertexIndex[1] >> temp >> uvIndex[1] >> temp >> vnIndex[1] >> vertexIndex[2] >> temp >> uvIndex[2] >> temp >> vnIndex[2];
if (ss.rdbuf()->in_avail() > 1)
Error("Model has non-triangle faces!");
NFError("Model has non-triangle faces!");
mats[usingMat]->vbIndices.push_back(vertexIndex[0]);
mats[usingMat]->vbIndices.push_back(vertexIndex[1]);
mats[usingMat]->vbIndices.push_back(vertexIndex[2]);
@@ -232,7 +232,7 @@ namespace nf {
matCount++;
}
if (m_materials.size() > 32)
Error("Model exceedes 32 material limit!");
NFError("Model exceedes 32 material limit!");
m_vao = new VertexArray;
m_vao->addBuffer(&vboPositions[0], vboPositions.size() * sizeof(float));
m_vao->pushFloat(3);
+9 -9
View File
@@ -59,7 +59,7 @@ namespace nf {
wglMakeCurrent(m_hdc, m_hglrc);
glewExperimental = GL_TRUE;
if (glewInit() != GLEW_OK)
Error("Could not initialize GLEW!");
NFError("Could not initialize GLEW!");
const int attrib[] = {
WGL_CONTEXT_MAJOR_VERSION_ARB, 3,
WGL_CONTEXT_MINOR_VERSION_ARB, 3,
@@ -71,7 +71,7 @@ namespace nf {
wglMakeCurrent(m_hdc, m_hglrc);
//TODO: Configure V-Sync with a custom max FPS
wglSwapIntervalEXT(0);
Log("OpenGL version: " + std::string((char*)glGetString(GL_VERSION)));
NFLog("OpenGL version: " + std::string((char*)glGetString(GL_VERSION)));
glDepthFunc(GL_LESS);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
@@ -137,23 +137,23 @@ namespace nf {
void Renderer::render(Entity& in) {
if (in.isConstructed() == false)
Error("Tried to render Entity before being created!");
NFError("Tried to render Entity before being created!");
m_lGame.push_back(&in);
//TODO: Sort transparent objects by distance; Farthest first
}
void Renderer::render(UIElement& in) {
if (in.isConstructed() == false)
Error("Tried to render a UI element before being created!");
NFError("Tried to render a UI element before being created!");
m_lUI.push_back(&in);
}
void Renderer::render(Light& in) {
if (in.isConstructed() == false)
Error("Tried to render a light before being created!");
NFError("Tried to render a light before being created!");
m_lights.push_back(&in);
}
void Renderer::render(Cubemap& in) {
if (in.isConstructed() == false)
Error("Tried to render a cubemap before being created!");
NFError("Tried to render a cubemap before being created!");
m_cubemap = &in;
}
@@ -163,7 +163,7 @@ namespace nf {
glViewport(0, 0, m_app->getConfig().width, m_app->getConfig().height);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glm::mat4 proj = glm::perspective(glm::radians(45.0f), (float)m_app->getConfig().width / (float)m_app->getConfig().height, 0.1f, 1000.0f);
camera->bind(m_gBufferShader, m_lightingShader, m_cubemapShader);
camera->update(m_gBufferShader, m_lightingShader, m_cubemapShader);
//First, fill the gBuffer with entities
m_gBufferShader->setUniform("proj", proj);
@@ -284,7 +284,7 @@ namespace nf {
//Check for OpenGL errors
GLenum err = glGetError();
if (err != GL_NO_ERROR)
Error("OpenGL error " + std::to_string(err));
NFError("OpenGL error " + std::to_string(err));
//Show completed frame
SwapBuffers(m_hdc);
@@ -292,7 +292,7 @@ namespace nf {
void Renderer::setAmbient(float am) {
if (am < 0.0f)
Error("Cannot have a negative ambient light strength!");
NFError("Cannot have a negative ambient light strength!");
m_lightingShader->setUniform("ambientStrength", am);
}
+4 -4
View File
@@ -37,7 +37,7 @@ namespace nf {
char* message = new char[length];
glGetShaderInfoLog(curr, length, &length, message);
message[length - 2] = 0;
Error("OpenGL Error: " + (std::string)message);
NFError("OpenGL Error: " + (std::string)message);
}
}
glAttachShader(m_id, vs);
@@ -51,7 +51,7 @@ namespace nf {
glGetProgramiv(m_id, GL_INFO_LOG_LENGTH, &length);
char* message = new char[length];
glGetProgramInfoLog(m_id, length, &length, message);
Error("OpenGL Error: " + (std::string)message);
NFError("OpenGL Error: " + (std::string)message);
}
glDetachShader(m_id, vs);
glDetachShader(m_id, fs);
@@ -72,7 +72,7 @@ namespace nf {
glGetProgramiv(m_id, GL_INFO_LOG_LENGTH, &length);
char* message = new char[length];
glGetProgramInfoLog(m_id, length, &length, message);
Error("OpenGL Error: " + (std::string)message);
NFError("OpenGL Error: " + (std::string)message);
}
}
@@ -108,7 +108,7 @@ namespace nf {
void Shader::getUniformLocation(const std::string& uniformName) {
unsigned int loc = glGetUniformLocation(m_id, uniformName.c_str());
if (loc == -1)
Error("Uniform \"" + (std::string)uniformName + "\" does not exist!");
NFError("Uniform \"" + (std::string)uniformName + "\" does not exist!");
m_uniformLocations[uniformName] = loc;
}
+1 -1
View File
@@ -18,7 +18,7 @@ namespace nf {
stbi_set_flip_vertically_on_load(true);
unsigned char* texture = stbi_load_from_memory((unsigned char*)tex->data, (unsigned int)tex->size, &m_x, &m_y, &nChannels, 0);
if (!texture)
Error("Texture failed to load from memory!");
NFError("Texture failed to load from memory!");
glGenTextures(1, &m_id);
glBindTexture(GL_TEXTURE_2D, m_id);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+5 -5
View File
@@ -15,7 +15,7 @@ namespace nf {
void VertexArray::addBuffer(const void* data, const size_t size) {
if (!m_lastBufferHasLayout)
Error("Buffer added to vertex array has no layout!");
NFError("Buffer added to vertex array has no layout!");
m_buffers.push_back(new VertexBuffer(data, size));
m_buffers.back()->bind();
m_lastBufferHasLayout = false;
@@ -24,14 +24,14 @@ namespace nf {
void VertexArray::pushFloat(unsigned int count) {
if (m_lastBufferHasLayout)
Error("Tried to modify a vertex array's buffer after the layout was final!");
NFError("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);
}
void VertexArray::pushInt(unsigned int count) {
if (m_lastBufferHasLayout)
Error("Tried to modify a vertex array's buffer after the layout was final!");
NFError("Tried to modify a vertex array's buffer after the layout was final!");
m_lastBufferLayout.push_back({ GL_INT, count, GL_FALSE });
m_lastStride += count * sizeof(GL_INT);
}
@@ -53,9 +53,9 @@ namespace nf {
void VertexArray::bind() {
if (m_buffers.empty())
Error("No buffers and layouts added to vertex array before being bound!");
NFError("No buffers and layouts added to vertex array before being bound!");
if (!m_lastBufferHasLayout)
Error("Buffer added to vertex array has no layout!");
NFError("Buffer added to vertex array has no layout!");
glBindVertexArray(m_id);
}
+2 -2
View File
@@ -114,7 +114,7 @@ namespace nf {
std::ofstream out;
out.open(filename, std::ios::binary);
if (!out)
Error("File \"" + (std::string)filename + (std::string)"\" could not be written!");
NFError("File \"" + (std::string)filename + (std::string)"\" could not be written!");
std::string write(in);
if (encrypted) {
for (unsigned int i = 0; i < write.size(); i++)
@@ -132,7 +132,7 @@ namespace nf {
std::ifstream in;
in.open(filename, std::ios::binary);
if (!in)
Error("File \"" + (std::string)filename + (std::string)"\" could not be read!");
NFError("File \"" + (std::string)filename + (std::string)"\" could not be read!");
std::stringstream ss;
ss << in.rdbuf();
std::string read(ss.str());
+153 -21
View File
@@ -2,53 +2,183 @@
#include <chrono>
#include <unordered_map>
#include <array>
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include "Config.h"
#include "IntroGamestate.h"
#include "Renderer.h"
#include "Gamestate.h"
#ifndef NFIMPL
#include "IntroGamestate.h"
#include "AudioEngine.h"
#ifdef NFENGINE
#include "PhysicsEngine.h"
#endif
//TODO: Document ALL frontend functions in new include files for the frontend only
namespace nf {
class AudioEngine;
class PhysicsEngine;
/**
* @brief Main class
*
* This class handles low-level Windows APIs and provides a window.
* Every NF applicaiton will create one.
*/
class Application {
public:
Application(Config& conf);
Application() = delete;
Application(Application& other) = delete;
/**
* @brief Main constructor
* @param conf Configuration to be applied to the app as default. Must be provided.
*/
Application(Config& conf);
/**
* @brief Sets the app's window icon
* @param hIcon Valid HICON loaded with a Windows API funciton like LoadIcon
*
* This also sets the window's taskbar icon.
*/
void setWindowIcon(HICON hIcon);
/**
* @brief Sets the app's cursor
* @param hCursor Valid HCURSOR loaded with a Windows API funciton like LoadCursor
*/
void setWindowCursor(HCURSOR hCursor);
/**
* @brief Adds a Gamestate to the app's available gamestates
* @param state Pointer to the Gamestate instance
* @param stateName Name of the state to be used later
*
* Gamestates can only be accessed in an app if this funciton has been called.
* The stateName is added to the app's list of states that can be switched to later.
*/
void addState(Gamestate* state, const std::string& stateName);
/**
* @brief Sets the state the app should switch to after the logo gamestate
* @param stateName Name of a priviously-added state
*
* @note The gamestate must have already been added to the app by calling addState.
*/
void setDefaultState(const std::string& stateName);
/**
* @brief Queries the name of the current gamestate
* @return Name of current gamestate
*/
const std::string& getDefaultState();
/**
* @brief Runs the application
*
* This funciton initializes and runs the main loop on the calling thread.
*
* @note This function will not return untill the engine exits.
*/
void run();
/**
* @brief Change to a different gamestate
* @param stateName name of the gamestate to switch to
*
* This function starts the process of unloading the current gamestate and loading
* a new one.
*
* @note The actual gamestate switching does not happen immediately before the next
* frame, but instead after a short amount of time for the engine to fade to a
* loading screen.
*/
void changeState(const std::string& stateName);
/**
* @brief Sets the visibility of the main window
* @param show Show the window?
*
* This function can be called at any time, regardless of the state of the application.
*/
void showWindow(bool show);
/**
* @brief Changes the app's config
* @param in The configuration to replace the current one
*
* This function reads in the new Config and sets up the engine to reflect it.
*
* @sa Config
*/
void changeConfig(const Config& in);
/**
* @brief Queries the current configuration
* @return A const reference to the current configuration of the app
*
* @sa Config
*/
const Config& getConfig() const;
/**
* @brief Queries the current FPS
* @return The current FPS
*
* @todo Start averaging the FPS instead of calculating it every frame.
*/
int getFPS() const;
/**
* @brief Queries if a certain key is currently down
* @param code An NFI code representing a keyboard key
* @return If the key is down
*
* This function returns true for every frame that a key is held down for. This is
* perfect for continuous movement or really anything that involves holding keys.
*/
bool isKeyHeld(unsigned int code);
/**
* @brief Queries if a certain key has been pressed
* @param code An NFI code representing a keyboard key
* @return If the key has been pressed
*
* This function returns true for only one frame that a key is held down for.
* This is perfect for toggling menus, actions, etc.
*/
bool isKeyPressed(unsigned int code);
/**
* @brief Queries if a certain mouse button is currently down
* @param code An NFI code representing a mouse button
* @return If the mouse button is down
*
* This function returns true for every frame that a mouse button is held down for.
* This is perfect for automatic weapons, dragging objects, etc.
*/
bool isMouseHeld(unsigned int code);
/**
* @brief Queries if a certain mouse button has been pressed
* @param code An NFI code representing a mouse button
* @return If the mouse button has been pressed
*
* This function returns true for only one frame that a mouse button is held down for.
* This is perfect for semi-automatic weapons, actions, etc.
*/
bool isMouseClicked(unsigned int code);
/**
* @brief Queries the cursor's current position in the window
* @return The coordinates of the cursor in window space
*
* A return value of (0, 0) represents the top-left corner of the window while
* a return value of (window width, window height) represents the bottom-right
* corner of the window.
*/
Vec2 getMousePos();
/**
* @brief Exits the main loop and cleans up the engine
*
* @todo Free up the possibility for an implementation to create another app
* before it exits.
*/
void quit();
#ifndef NFIMPL
Renderer* getRenderer() const;
AudioEngine* getAudioEngine() const;
PhysicsEngine* getPhysicsEngine() const;
void addState(Gamestate* state, const std::string& stateName);
void setDefaultState(const std::string& stateName);
const std::string& getDefaultState();
void run();
bool hasCustomWindowIcon();
void changeState(const std::string& stateName);
Gamestate* getCurrentState();
void showWindow(bool show);
const HWND& getWindow();
void changeConfig(const Config& in);
const Config& getConfig() const;
int getFPS() const;
bool isKeyHeld(unsigned int code);
bool isKeyPressed(unsigned int code);
bool isMouseClicked(unsigned int code);
bool isMouseHeld(unsigned int code);
void trackMouse(bool track);
void getMouseDiff(int& x, int& y);
Vec2 getMousePos();
static Application* getApp(bool first = false);
void quit();
#endif
~Application();
private:
void registerWindowClass();
@@ -101,8 +231,10 @@ namespace nf {
//Renderer object to use OpenGL to render the current state
Renderer* m_renderer;
//Handles nf::Sound objects and calculates 3D sounds
AudioEngine* m_audio;
//Calculates physics
PhysicsEngine* m_physics;
};
}
+106 -7
View File
@@ -72,37 +72,136 @@ namespace nf {
~ASound() override;
};
/**
* @brief A representation of a nfpack file
*
* With this class, you can access your custom assets with the get functions.
*/
class AssetPack : public NFObject {
public:
AssetPack(const AssetPack& other) = delete;
/**
* @brief Constructor
*
* See @ref obLifetime
*/
AssetPack();
/**
* @brief Loads a specified nfpack into memory
* @param packName name of pack to load relative to the `assets` directory
*
* After calling this function, future calls to @ref get will return an Asset pointer.
*
* @warning Because this function could take a considerable amount of time when
* dealing with very large packs, it is not recomended to call this function
* in a Gamestate::update or Gamestate::render function.
*/
void load(const char* packName);
/**
* @brief Queries whether or not a pack has been loaded
* @return If a pack is loaded
*/
bool isLoaded();
/**
* @brief Gets a specified Asset pointer from a string literal
* @param in name of asset file to retrieve
* @return An Asset pointer
*/
Asset* get(const char* in);
/**
* @brief Gets a specified Asset pointer from an std::string
* @param in name of asset file to retrieve
* @return An Asset pointer
*/
Asset* get(std::string& in);
/**
* @brief Gets a specified Asset pointer from a string literal
* @param in name of asset file to retrieve
* @return An Asset pointer
*
* This function allows you to get assets like this:
*
* ~~~
* Asset* model = assetPack["model.obj"];
* ~~~
*/
Asset* operator[](const char* in);
/**
* @brief Gets a specified Asset pointer from an std::string
* @param in name of asset file to retrieve
* @return An Asset pointer
*
* This function allows you to get assets like this:
*
* ~~~
* std::string str = "model.obj";
* Asset* model = assetPack[str];
* ~~~
*/
Asset* operator[](std::string& in);
void destroy() override;
/**
* @brief Unloads the pack from memory
*
* This function can be useful if you have an AssetPack object as a member of
* a Gamestate and want to unload it at a specific time.
*/
void unload();
void destroy() override;
~AssetPack();
private:
bool m_loaded;
std::unordered_map<std::string, Asset*> m_assets;
};
/**
* @brief A collection of a few defualt assets included in `base.nfpack`
*
* All models have a default, grey material.
*/
struct BaseAssets {
/**
* @brief A cube
*/
static AModel* cube;
/**
* @brief A flattened cube
*/
static AModel* plane;
/**
* @brief A sphere
*/
static AModel* sphere;
/**
* @brief A cone
*/
static AModel* cone;
/**
* @brief A cylinder
*/
static AModel* cylinder;
/**
* @brief A torus
*/
static AModel* torus;
/**
* @brief NF logo
*/
static ATexture* logo;
/**
* @brief Default cubemap
*/
static ACubemap* cubemap;
/**
* @brief Default font
*
* The default font is Segoe UI Light.
*/
static AFont* font;
/**
* @brief Default button textures
*
* @sa @ref customButtons
*/
static AButton* button;
};
}
+33 -3
View File
@@ -10,15 +10,45 @@ namespace nf {
class Texture;
struct Asset;
/**
* @brief A UI button
*
* Buttons can be customized to use three different textures: an idle, hover, and pressed
* texture.
*
* @sa @ref customButtons
* @ref createUI
*/
class Button : public UIElement, public NFObject {
public:
Button(const Button& other) = delete;
/**
* @brief Constructor
*
* See @ref obLifetime
*/
Button();
/**
* @brief Creates a UI button
* @param position Position vector in screen space
* @param string Text to show on the button; Can be an empty string; Optional
* @param buttonAsset A custom button asset; Optional
* @param scale Scale of the button; Optional
* @param opacity Opacity of the button; Optional
*/
void create(const Vec2& position, std::string string = "", Asset* buttonAsset = nf::BaseAssets::button, float scale = 1.0f, float opacity = 1.0f);
/**
* @brief Queries whether or not the button has been clicked
* @return If the button has been clicked
*
* @note This function returns true for only one frame when the mouse button
* is released on top of the button.
*/
bool isClicked();
#ifndef NFIMPL
const char* identity() override;
void render(Shader* shader, unsigned int windowWidth, unsigned int windowHeight, Application* app, Shader* textShader);
bool isClicked();
#endif
void destroy() override;
~Button();
private:
+88 -10
View File
@@ -5,32 +5,110 @@ namespace nf {
class Application;
class Shader;
//TODO: Make sure there are always newlines here;
/**
* @brief The viewpoint for the engine
*/
class Camera {
public:
/**
* @brief Dictates the behavior of a camera's movement
*/
enum class Type {
/**
* @brief No mouse capture
*
* Perfect for selecting menus with the mouse
*/
UI,
/**
* @brief First-person mouse-look movement
*/
FIRST_PERSON,
/**
* @brief Orbit movement around either a position or Entity
*/
ORBIT,
/**
* @brief Fixed to either a position or Entity
*/
FIXED
};
#ifndef NFIMPL
Camera(Application* app);
#else
Camera() = delete;
Camera(const Camera& other) = delete;
#endif
/**
* @brief Sets the camera's type
* @param cameraType the @ref Type to change to
*/
void setType(Type cameraType);
/**
* @brief Queries the current @ref Type of the camera
* @return The current Type of the camera
*/
Type getType() const;
void moveForward(float speed);
void moveBackward(float speed);
void moveRight(float speed);
void moveLeft(float speed);
/**
* @brief Moves the camera given an offset
* @param offset Offset vector
*
* The x component of the offset is added to the x coordinate of the camera
* while the y component is added to the z coordinate.
*/
void move(const Vec2& offset);
/**
* @brief Moves the camera forwards and backwards
* @param offset The amount to move the camera in the Z direction
*/
void moveZ(float offset);
/**
* @brief Moves the camera left and right
* @param offset The amount to move the camera in the X direction
*/
void moveX(float offset);
/**
* @brief Sets the position of the camera with three floats
* @param x X component
* @param y Y component
* @param z Z component
*/
void setPosition(float x, float y, float z);
/**
* @brief Sets the position of the camera with a Vec3
* @param position Position vector
*/
void setPosition(const Vec3& position);
/**
* @brief Queries the position of the camera
* @return The position of the camera
*/
const Vec3& getPosition();
void setRotation(float x, float y);
/**
* @brief Sets the rotation of the camera given a pitch and yaw
* @param yaw Left and right rotation in degrees
* @param pitch Up and down rotation in degrees
*/
void setRotation(float yaw, float pitch);
/**
* @brief Sets the rotation of the camera given a Vec2
* @param rotation Rotation vector
*
* The x component of the rotation represents yaw (left and right rotation)
* while the y component represents pitch (up and down rotation).
* Both are in degrees.
*/
void setRotation(const Vec2& rotation);
/**
* @brief Gets the rotation of the camera
* @return The rotation of the camera
*/
const Vec3& getRotation();
void bind(Shader* gBufferShader, Shader* lightingShader, Shader* cubemapShader);
#ifndef NFIMPL
void update(Shader* gBufferShader, Shader* lightingShader, Shader* cubemapShader);
#endif
~Camera();
private:
Application* m_app;
+22
View File
@@ -1,11 +1,33 @@
#pragma once
namespace nf {
/**
* @brief Configuration for NF
*
* This struct contains basic information about the engine's window.
*
* @todo Add more things here such as mouse sensativity and FPS target?
*/
struct Config {
public:
/**
* @brief Width of the engine window (should fullscreen be false)
*/
unsigned int width;
/**
* @brief Height of the engine window (should fullscreen be false)
*/
unsigned int height;
/**
* @brief Sets fullscreen
*
* If fullscreen, the engine will be displayed at the current monitor's
* resolution.
*/
bool fullscreen;
/**
* @brief Title of the engine's window
*/
const char* title;
};
}
+26 -2
View File
@@ -6,14 +6,38 @@ namespace nf {
struct Asset;
class Shader;
/**
* @brief A skybox in the background of a gamestate's world
*
* A cubemap is a cube with a texture on each one of its 6 sides.
*
* @sa @ref createCubemap @ref customCubemap
*/
class Cubemap : public Drawable, public NFObject {
public:
/**
* @brief Constructor
*
* See @ref obLifetime
*/
Cubemap();
/**
* @brief Creates a cubemap
* @param cubemapAsset A cubemap asset retrieved from an AssetPack
*
* This function will prepare the cubemap to be rendered.
*
* @warning Trying to render a cubemap before creating it will result in an error.
*/
void create(Asset* cubemapAsset);
/**
* @brief Queries whether or not the cubemap has been created
* @return If the cubemap has been created
*/
bool isConstructed();
#ifndef NFIMPL
void render(Shader* shader);
#endif
void destroy() override;
~Cubemap();
private:
+113 -9
View File
@@ -2,7 +2,7 @@
#include "Assets.h"
#include "NFObject.h"
#include "Utility.h"
#ifdef NFENGINE
#ifndef NFIMPL
#include "glm/glm.hpp"
#endif
@@ -10,45 +10,149 @@ namespace nf {
class Shader;
class Model;
/**
* @brief Represents a 3D object in the world
*
* Every entity has a position, rotation, and scale with respect to the world.
* Every entity also has an associated Model it was created with.
*/
class Entity : public NFObject {
public:
/**
* @brief Dictates the behavior of an entity in the physics simulation
*/
enum class Type {
/**
* @brief Will not move, but will participate in the simulation
*/
STATIC,
/**
* @brief Will move and participate in the simulation
*/
DYNAMIC,
/**
* @brief Will not move, but will participate in the simulation;
* This type allows concave meshes. This type is meant for environmental
* meshes such as landscapes and the insides of buildings or similar.
*/
MAP,
/**
* @brief Will not participate in the simulation; This is perfect for debris
* on the ground like trash or books.
*/
DETAIL
};
Entity(const Entity& other) = delete;
/**
* @brief Constructor
*
* See @ref obLifetime
*/
Entity();
/**
* @brief Creates an entity
* @param modelAsset A model Asset pointer
* @param type @ref Type of entity; Defaults to Type::STATIC
*
* This function will initialize an entity by loading its associated model from
* the modelAsset parameter.
*
* @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);
/**
* @brief Queries whether or not the entity has been created
* @return If the entity has been created
*/
bool isConstructed();
/**
* @brief Queries the type of the entity
* @return The type of the entity
*/
Type getType();
/**
* @brief Sets the position of the origin of the entity with three floats
* @param x X component
* @param y Y component
* @param z Z component
*/
void setPosition(float x, float y, float z);
/**
* @brief Sets the position of the origin of the entity with a Vec3
* @param position The position vector
*/
void setPosition(const Vec3& position);
/**
* @brief Sets the rotation of the origin of the entity with three floats in degrees
* @param x X component
* @param y Y component
* @param z Z component
*/
void setRotation(float x, float y, float z);
/**
* @brief Sets the rotation of the origin of the entity with a Vec3
* @param rotation The rotation vector in degrees
*/
void setRotation(const Vec3& rotation);
/**
* @brief Sets the scale of the entity with three floats
* @param x X component
* @param y Y component
* @param z Z component
*/
void setScale(float x, float y, float z);
/**
* @brief Sets the scale of the entity with a Vec3
* @param scale The scale vector
*/
void setScale(const Vec3& scale);
/**
* @brief Sets the scale of the entity with a single scalar
* @param x The single scalar for all three axes
*/
void setScale(float x);
/**
* @brief Sets the linear velocy of the entity with three floats
* @param x X component
* @param y Y component
* @param z Z component
*/
void setVelocity(float x, float y, float z);
/**
* @brief Sets the linear velocy of the entity with a Vec3
* @param velocity The velocity vector
*/
void setVelocity(const Vec3& velocity);
/**
* @brief Sets the mass of the entity
* @param mass The mass
*
* Experiment with different values to get an idea of the scale of masses.
*/
void setMass(float mass);
/**
* @brief Queries the current position of the entity
* @return The entity's current position
*/
const Vec3& getPosition();
/**
* @brief Queries the current rotation of the entity
* @return The entity's current rotation as a quaternion
*/
const Vec4& getRotation();
/**
* @brief Queries the current scale of the entity
* @return The entity's current scale
*/
const Vec3& getScale();
#ifndef NFIMPL
void setPositionPhysics(const Vec3& position);
void setRotationPhysics(const Vec4& rotation);
bool needsPhysicsUpdate();
void render(Shader* shader, bool onlyDepth);
Model* getModel() const;
#ifdef NFENGINE
const glm::mat4 getModelMatrix();
#endif
void destroy() override;
+84 -17
View File
@@ -13,31 +13,98 @@ namespace nf {
class Model;
class Texture;
/**
* @brief A state NF can be in that includes a collection of objects and user-defined
* behavior
*
* Every user-defined state inherits from this class.
*/
class Gamestate {
public:
Gamestate();
//TODO: Add this to other objects
Gamestate(const Gamestate& other) = delete;
/**
* @brief Default constructor; Must be used
*/
Gamestate();
/**
* @brief The state's 'constructor'
*
* This function runs when the state is started.
*/
virtual void onEnter();
/**
* @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.
*
* 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
* produce output that will look the same on higher and lower framerates.
*/
virtual void update(float deltaTime);
/**
* @brief Render function
* @param renderer A reference to the Renderer object
*
* This function will contain calls to Renderer::render to decide what will be drawn
* on the next frame.
*
* @sa Renderer
*/
virtual void render(Renderer& renderer);
/**
* @brief The state's 'destructor'
*
* This function runs when the state is exited.
*
* It is imperitive that the class members are 'reset' back to their default values
* here. This does not include members of the Gamestate that are NF objects
* such as entites and UIElements.
*
* For more information see the @ref gamestates.
*/
virtual void onExit();
/**
* @brief Returns the state's Camera
* @return The state's camera
*/
Camera* getCamera();
/**
* @brief Sets the state's ambient light level
* @param stength Light level multiplier; Defaults to 0.1f
*
* An ambient light level of 0.0f is perfect for pitch dark rooms where no light means
* completely black while a level of 1.0f means full-bright.
*/
void setAmbientLight(float stength);
/**
* @brief Sets the state's gravity in a certain direction
* @param gravity A vector representing a direction the force of gravity should act in
* In units of Earth gravity
*
* The default gravity of a state is:
*
* ~~~
* Vec3(0.0, -1.0, 0.0);
* ~~~
*/
void setGravity(const Vec3& gravity);
/**
* @brief Sets the state's gravity downward
* @param strength A multiplier in units of Earth gravity
*
* The default is 1.0f;
*/
void setGravity(float strength);
#ifndef NFIMPL
void run(Application* app, bool physics = true);
bool isRunning();
bool isLoading();
virtual void onEnter();
virtual void update(float deltaTime);
virtual void render(Renderer& renderer);
Camera* getCamera();
//Defaults to 0.1f
void setAmbientLight(float stength);
//In units of Earth gravity (9.81 m/s^2)
void setGravity(const Vec3& gravity);
void setGravity(float strength);
virtual void onExit();
void stop();
#endif
//TODO: Probably change these to private members?
std::vector<NFObject*> m_nfObjects;
std::vector<Entity*> m_entsToDelete;
std::unordered_set<Model*> m_modelsToDelete;
+69 -7
View File
@@ -5,27 +5,89 @@
namespace nf {
class Shader;
/**
* @brief A light in a gamestate's world
*
* Lights are completely dynamic and can have different colors and strengths. They
* are also movable.
*/
class Light : public NFObject {
public:
/**
* @brief Dictates the behavior of a light
*/
enum class Type {
DIRECTIONAL,
POINT
/**
* @brief A light that has a position in the world and casts light in every
* direction
*/
POINT,
/**
* @brief A light that has no position, but only a direction; Perfect for
* sunlight
*/
DIRECTIONAL
};
/**
* @brief Constructor
*
* See @ref obLifetime
*/
Light();
/**
* @brief Creates a light
* @param position Starting position vector of the light
* @param color Color vector in (red, green, blue) order from 0.0f to 1.0f
* @param strength Strength of the light; Optional
* @param type Type of the light; Optional
*/
void create(const Vec3& position, const Vec3& color, float strength = 1.0f, Type type = Type::POINT);
/**
* @brief Queries whether or not the light has been created
* @return If the light has been created
*/
bool isConstructed();
/**
* @brief Sets the position of the light with a Vec3
* @param position The position vector
*
* For directional lights, this will change the direction instead of the position.
*/
void setPosition(const Vec3& position);
/**
* @brief Sets the color of the light
* @param color The color vector in (red, green, blue) order from 0.0f to 1.0f
*/
void setColor(const Vec3& color);
/**
* @brief Sets the strength of the light
* @param strength The strength
*/
void setStrength(float strength);
void bind(Shader* shader, unsigned int lightNumber);
/**
* @brief Queries the type of the light
* @return The type of the light
*/
Type getType();
/**
* @brief Gets the position of the light
* @return The position of the light
*/
const Vec3& getPosition();
/**
* @brief Gets the color of the light
* @return The color vector
*/
const Vec3& getColor();
/**
* @brief Gets the strength of the light
* @return The strength
*/
const float getStrength();
#ifndef NFIMPL
void bind(Shader* shader, unsigned int lightNumber);
#endif
void destroy() override;
~Light();
private:
+4 -4
View File
@@ -2,11 +2,11 @@
//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
#include <chrono>
#include <unordered_map>
#include <array>
#include <Windows.h>
#ifndef NFIMPL
#define NFIMPL 1
#endif
#include "Config.h"
#include "Application.h"
+45 -8
View File
@@ -17,22 +17,59 @@ namespace nf {
class VertexArray;
class IndexBuffer;
/**
* @brief Handles rendering user objects
*
* This should only be accessed in a gamestate's render function.
*
* @todo Maybe move to something like rendering everything automatically and adding a
* show function to entities and UI stuff?
*/
class Renderer {
public:
Renderer(Application* app);
/**
* @brief Renders an Entity
* @param in Entity to render
*
* This function adds an Entity to the list of entites to render in the next frame.
*
* @note An entity will participate in the physics simulation if it is setup to
* do so regardless of if it is rendered or not.
*/
void render(Entity& in);
/**
* @brief Renders a UIElement
* @param in UIElement to render
*
* This function adds a UIElement to the list UIElements to render in the next frame.
*/
void render(UIElement& in);
/**
* @brief Renders a Light
* @param in Light to render
*
* This function adds a Light to the list of lights to render in the next frame.
*/
void render(Light& in);
/**
* @brief Renders a Cubemap
* @param in Cubemap to render
*
* This function sets the next frame's Cubemap.
*
* @note Because only one Cubemap can be rendered in a frame, only the last call to
* this function before a frame is produced will take effect.
*/
void render(Cubemap& in);
#ifndef NFIMPL
void setFade(bool in, bool out, bool text = true);
bool isFadeOutComplete();
void render(Entity& in);
void render(UIElement& in);
void render(Light& in);
void render(Cubemap& in);
void doFrame(Camera* camera, float dT);
void setAmbient(float am);
Renderer(Application* app);
~Renderer();
#endif
private:
void loadBaseAssets();
void createShadowMaps();
+44 -1
View File
@@ -7,15 +7,58 @@ namespace nf {
struct Asset;
class Entity;
/**
* @brief A stream of audio; Could be a sound effect or music
*
* NF currently supports WAV and Ogg Vorbis files.
*/
class Sound : public NFObject {
public:
/**
* @brief Constructor
*
* See @ref obLifetime
*/
Sound();
/**
* @brief Creates a sound
* @param soundAsset A sound asset retrieved from an AssetPack
*
* The referenced sound can be of any format. This function will take care of
* figuring that out and loading it accordingly.
*/
void create(Asset* soundAsset);
/**
* @brief Sets the volume of the sound
* @param volume Volume; Can be higher than 1.0f
*/
void setVolume(float volume);
/**
* @brief Sets the target Entity of the sound
* @param entity The target entity
*
* This function will bind the sound to a specific entity. When it is played,
* it will sound like the sound is coming from the target entity.
*/
void setEntity(Entity& entity);
/**
* @brief Sets the static location the sound should play at
* @param position A position vector
*/
void setPosition(const Vec3& position);
/**
* @brief Plays the sound
* @param loop If the sound should forever loop when it completes playing
*
* This function can be called multiple times to play multiple instances of the
* sound.
*/
void play(bool loop = false);
/**
* @brief Stops the sound
*
* This function will stop all instances of the sound if multiple are playing
*/
void stop();
void destroy() override;
+38 -3
View File
@@ -19,18 +19,53 @@ namespace nf {
bool isBase = false;
};
/**
* @brief A UI string
*
* Custom fonts are supported. See @ref customFonts
*/
class Text : public UIElement, public NFObject {
public:
/**
* @brief Constructor
*
* See @ref obLifetime
*/
Text();
/**
* @brief Creates UI text
* @param string The text itself
* @param position Position vector in screen space
* @param color Color vector; Optional
* @param opacity Opacity of the text; Optional
* @param scale Scale of the text; Optional
* @param fontAsset Custom font asset; Optional
*/
void create(const std::string& string, const Vec2& position, const Vec3& color = {1.0, 1.0, 1.0}, float opacity = 1.0f, float scale = 1.0f, Asset* fontAsset = BaseAssets::font);
const char* identity() override;
/**
* @brief Sets the displayed text
* @param string The new text to display
*/
void setText(const std::string& string);
/**
* @brief Sets the text's color
* @param color The new color vector
*/
void setColor(const Vec3& color);
/**
* @brief Sets the text's scale
* @param scale The new scale
*/
void setScale(float scale);
/**
* @brief Sets the text's opacity
* @param opacity The new opacity
*/
void setOpacity(float opacity);
#ifndef NFIMPL
const char* identity() override;
void render(Shader* shader, unsigned int windowWidth, unsigned int windowHeight, bool onButton = false, float buttonWidth = 0.0f, float buttonHeight = 0.0f, const Vec2& buttonPos = Vec2());
#endif
void destroy() override;
~Text();
private:
+28 -3
View File
@@ -7,16 +7,41 @@ namespace nf {
class Texture;
struct Asset;
/**
* @brief A UI image
*
* This class represents a texture that can be added to the UI.
*/
class UITexture : public UIElement, public NFObject {
public:
/**
* @brief Constructor
*
* See @ref obLifetime
*/
UITexture();
/**
* @brief Creates a UI texture
* @param textureAsset Texture asset retrieved from an AssetPack
* @param position Position vector in screen space
* @param scale Scale of the texture
* @param opacity Opacity of the texture
*/
void create(Asset* textureAsset, const Vec2& position, float scale = 1.0f, float opacity = 1.0f);
const char* identity() override;
/**
* @brief Sets the texture's scale
* @param scale The new scale
*/
void setScale(float scale);
/**
* @brief Sets the texture's opacity
* @param opacity The new opacity
*/
void setOpacity(float opacity);
#ifndef NFIMPL
const char* identity() override;
void render(Shader* shader, unsigned int windowWidth, unsigned int windowHeight) override;
#endif
void destroy() override;
~UITexture();
private:
+276 -21
View File
@@ -4,22 +4,48 @@
#include <string>
#include <Windows.h>
/**
* @brief Nothin' Fancy namespace
*
* Every class and struct lives inside of this namespace
*
* It could be useful to `using` this namespace:
*
* ~~~
* using namespace nf;
* ~~~
*/
namespace nf {
#ifdef _DEBUG
#if defined(_DEBUG) || defined(doxygen)
//Strips __FILE__ down to only the name of the file
#define __FILENAME__ strrchr(__FILE__, '\\') + 1
//Initializes static variables needed for debugging
#define DEBUGINIT std::chrono::steady_clock::time_point Debug::m_initTime = std::chrono::high_resolution_clock::now();
//Sleep for an amount of seconds
#define SleepS(x) std::this_thread::sleep_for(std::chrono::seconds(x))
//Sleep for an amount of milliseconds
#define SleepMS(x) std::this_thread::sleep_for(std::chrono::milliseconds(x))
//Prints a nicely-formatted message complete with a timestamp
#define Log(x) nf::Debug::LogImp(x)
//Prints error message and breaks the debugger in debug mode
#define Error(x) {nf::Debug::ErrorImp(x,__FILENAME__, __LINE__);\
#define NFDEBUGINIT std::chrono::steady_clock::time_point Debug::m_initTime = std::chrono::high_resolution_clock::now();
/**
* Pauses the engine for a set amount of seconds
*/
#define NFSleepS(x) std::this_thread::sleep_for(std::chrono::seconds(x))
/**
* Pauses the engine for a set amount of milliseconds
*/
#define NFSleepMS(x) std::this_thread::sleep_for(std::chrono::milliseconds(x))
/**
* In debug mode, this prints a nicely-formatted message complete with a timestamp.
*
* In release mode, this does nothing.
*/
#define NFLog(x) nf::Debug::LogImp(x)
/**
* In debug mode, the error message is printed to the console and the debugger is broken.
*
* In release mode, the error message is shown in a message box and the application
* closes when the message box is closed.
*/
#define NFError(x) {nf::Debug::ErrorImp(x,__FILENAME__, __LINE__);\
__debugbreak();}
/**
* @brief Handles NFLog and NFError calls
*/
class Debug {
private:
static std::chrono::steady_clock::time_point m_initTime;
@@ -33,24 +59,70 @@ __debugbreak();}
static void ErrorImp(const std::string& in, const char* filename, int line);
};
#else
#define DEBUGINIT
#define Log(x)
//Shows error dialog with specified message then exits
#define Error(x) {MessageBox(FindWindow(L"NFClass", NULL), toWide(x).data(), L"NF Engine Error", MB_OK | MB_ICONERROR);\
#define NFDEBUGINIT
#define NFSleepS(x)
#define NFSleepMS(x)
#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);}
#endif
/**
* @brief Two component vector
*
* Similar to Vec3 and Vec4.
*
* Supports operators + - * / += -= *= /= ==
*/
struct Vec2 {
Vec2() : x(0.0), y(0.0) {}
/**
* @brief Default constructor
*
* Initializes all components to 0.0f
*/
Vec2() : x(0.0f), y(0.0f) {}
/**
* @brief Single constructor
* @param x1
*
* Sets all components to x1
*/
Vec2(float x1) : x(x1), y(x1) {}
/**
* @brief Double constructor
* @param x1
* @param y1
*
* Initializes the vector with the specified values
*/
Vec2(float x1, float y1) : x(x1), y(y1) {}
/**
* @brief Single constructor (double version)
* @param x1
*
* Double compatibility
*/
Vec2(double x1) : x((float)x1), y((float)x1) {}
/**
* @brief Double constructor (double version)
* @param x1
* @param y1
*
* Double compatibility
*/
Vec2(double x1, double y1) : x((float)x1), y((float)y1) {}
Vec2 operator+(const Vec2& rhs) const {
return Vec2(x + rhs.x, y + rhs.y);
}
Vec2 operator-(const Vec2& rhs) const {
return Vec2(x - rhs.x, y - rhs.y);
}
Vec2 operator*(const float scalar) const {
return Vec2(x * scalar, y * scalar);
}
Vec2 operator/(const Vec2& rhs) const {
return Vec2(x / rhs.x, y / rhs.y);
}
Vec2& operator+=(const Vec2& rhs) {
this->x += rhs.x;
this->y += rhs.y;
@@ -61,23 +133,86 @@ std::exit(-1);}
this->y -= rhs.y;
return *this;
}
Vec2& operator*=(const Vec2& rhs) {
this->x *= rhs.x;
this->y *= rhs.y;
return *this;
}
Vec2& operator/=(const Vec2& rhs) {
this->x /= rhs.x;
this->y /= rhs.y;
return *this;
}
bool operator==(const Vec2& rhs) {
return this->x == rhs.x && this->y == rhs.y;
}
float x, y;
/**
* @brief X component
*/
float x;
/**
* @brief Y components
*/
float y;
};
/**
* @brief Three component vector
*
* Similar to Vec2 and Vec4
*
* Supports operators + - * / += -= *= /= ==
*/
struct Vec3 {
Vec3() : x(0.0), y(0.0), z(0.0) {}
/**
* @brief Default constructor
*
* Initializes all components to 0.0f
*/
Vec3() : x(0.0f), y(0.0f), z(0.0f) {}
/**
* @brief Single constructor
* @param x1
*
* Sets all components to x1
*/
Vec3(float x1) : x(x1), y(x1), z(x1) {}
/**
* @brief Triple constructor
* @param x1
* @param y1
* @param z1
*
* Initializes the vector with the specified values
*/
Vec3(float x1, float y1, float z1) : x(x1), y(y1), z(z1) {}
/**
* @brief Single constructor (double version)
* @param x1
*
* Double compatibility
*/
Vec3(double x1) : x((float)x1), y((float)x1), z((float)x1) {}
/**
* @brief Triple constructor (double version)
* @param x1
* @param y1
* @param z1
*
* Double compatibility
*/
Vec3(double x1, double y1, double z1) : x((float)x1), y((float)y1), z((float)z1) {}
Vec3 operator+(const Vec3& rhs) const {
return Vec3(x + rhs.x, y + rhs.y, z + rhs.z);
}
Vec3 operator-(const Vec3& rhs) const {
return Vec3(x - rhs.x, y - rhs.y, z - rhs.z);
}
Vec3 operator*(const float scalar) const {
return Vec3(x * scalar, y * scalar, z * scalar);
}
Vec3 operator/(const Vec3& rhs) const {
return Vec3(x / rhs.x, y / rhs.y, z / rhs.z);
}
Vec3& operator+=(const Vec3& rhs) {
this->x += rhs.x;
this->y += rhs.y;
@@ -90,23 +225,94 @@ std::exit(-1);}
this->z -= rhs.z;
return *this;
}
Vec3& operator*=(const Vec3& rhs) {
this->x *= rhs.x;
this->y *= rhs.y;
this->z *= rhs.z;
return *this;
}
Vec3& operator/=(const Vec3& rhs) {
this->x /= rhs.x;
this->y /= rhs.y;
this->z /= rhs.z;
return *this;
}
bool operator==(const Vec3& rhs) {
return this->x == rhs.x && this->y == rhs.y && this->z == rhs.z ;
}
float x, y, z;
/**
* @brief X component
*/
float x;
/**
* @brief Y component
*/
float y;
/**
* @brief Z component
*/
float z;
};
/**
* @brief Four component vector
*
* Similar to Vec2 and Vec3
*
* Supports operators + - * / += -= *= /= ==
*/
struct Vec4 {
Vec4() : x(0.0), y(0.0), z(0.0), w(0.0) {}
/**
* @brief Default constructor
*
* Initializes all components to 0.0f
*/
Vec4() : x(0.0f), y(0.0f), z(0.0f), w(0.0f) {}
/**
* @brief Single constructor
* @param x1
*
* Sets all components to x1
*/
Vec4(float x1) : x(x1), y(x1), z(x1), w(x1) {}
/**
* @brief Quadruple constructor
* @param x1
* @param y1
* @param z1
* @param w1
*
* Initializes the vector with the specified values
*/
Vec4(float x1, float y1, float z1, float w1) : x(x1), y(y1), z(z1), w(w1) {}
/**
* @brief Single constructor (double version)
* @param x1
*
* Double compatibility
*/
Vec4(double x1) : x((float)x1), y((float)x1), z((float)x1), w((float)x1) {}
/**
* @brief Quadruple constructor (double version)
* @param x1
* @param y1
* @param z1
* @param w1
*
* Double compatibility
*/
Vec4(double x1, double y1, double z1, double w1) : x((float)x1), y((float)y1), z((float)z1), w((float)w1) {}
Vec4 operator+(const Vec4& rhs) const {
return Vec4(x + rhs.x, y + rhs.y, z + rhs.z, w + rhs.w);
}
Vec4 operator-(const Vec4& rhs) const {
return Vec4(x - rhs.x, y - rhs.y, z - rhs.z, w - rhs.w);
}
Vec4 operator*(const float scalar) const {
return Vec4(x * scalar, y * scalar, z * scalar, w * scalar);
}
Vec4 operator/(const Vec4& rhs) const {
return Vec4(x / rhs.x, y / rhs.y, z / rhs.z, w / rhs.w);
}
Vec4& operator+=(const Vec4& rhs) {
this->x += rhs.x;
this->y += rhs.y;
@@ -121,10 +327,39 @@ std::exit(-1);}
this->w -= rhs.w;
return *this;
}
Vec4& operator*=(const Vec4& rhs) {
this->x *= rhs.x;
this->y *= rhs.y;
this->z *= rhs.z;
this->w *= rhs.w;
return *this;
}
Vec4& operator/=(const Vec4& rhs) {
this->x /= rhs.x;
this->y /= rhs.y;
this->z /= rhs.z;
this->w /= rhs.w;
return *this;
}
bool operator==(const Vec4& rhs) {
return this->x == rhs.x && this->y == rhs.y && this->z == rhs.z && this->w == rhs.w;
}
float x, y, z, w;
/**
* @brief X component
*/
float x;
/**
* @brief Y component
*/
float y;
/**
* @brief Z component
*/
float z;
/**
* @brief W component
*/
float w;
};
const std::wstring toWide(const char* in);
@@ -132,6 +367,26 @@ std::exit(-1);}
Vec4 degToQuat(const Vec3& in);
/**
* @brief Writes a stream of bytes as as std::string into a file in a specified location
* @param filename Path and name of file to be written, including extensions; Relative or absolute
* @param in Input std::string to be written
* @param encrypted Write the file encrypted?
*
* This function, as well as readFile, supports a basic and unsecure form of encryption.
* This is meant to discourage players from easily modifying stats, saves, etc.
*/
void writeFile(const std::string& filename, const std::string& in, bool encrypted = false);
/**
* @brief Reads a file's bytes into an std::string
* @param filename Path and name of file to be read, including extensions; Relative or absolute
* @param compressed Internal use only as of now
* @return An std::string containing the specified file's bytes
*
* This function automatically detects whether or not the target file is encrypted
* and decrypts it if it is.
*
* @todo If files aren't found, the engine errors. Change this.
*/
std::string readFile(const std::string& filename, bool compressed = false);
}