diff --git a/.gitignore b/.gitignore index c65061d..35c0d89 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ .vs/ bin/ int/ +manual/ *.aps *.res *.nfpack \ No newline at end of file diff --git a/Game/Game.vcxproj b/Game/Game.vcxproj index 7afd107..38f21e6 100644 --- a/Game/Game.vcxproj +++ b/Game/Game.vcxproj @@ -98,8 +98,8 @@ if exist "base.nfpack" (copy "base.nfpack" "$(OutDir)assets\") true mainCRTStartup libcmt.lib - /ignore:4099 %(AdditionalOptions) true + /ignore:4099 %(AdditionalOptions) cd assets diff --git a/Game/src/MainState.cpp b/Game/src/MainState.cpp index b705e1f..2fe1092 100644 --- a/Game/src/MainState.cpp +++ b/Game/src/MainState.cpp @@ -1,7 +1,7 @@ #include "MainState.h" void MainState::onEnter() { - Log("MainState onEnter!"); + NFLog("MainState onEnter!"); currCamType = nf::Camera::Type::FIRST_PERSON; camera->setType(currCamType); ap.load("example.nfpack"); @@ -31,7 +31,7 @@ void MainState::onEnter() { for (int y = 0; y < 3; y++) { for (int z = 0; z < 3; z++) { entities.push_back(new nf::Entity); - entities.back()->create(ap.get("2mats.obj"), nf::Entity::Type::DYNAMIC); + entities.back()->create(nf::BaseAssets::cone, nf::Entity::Type::DYNAMIC); entities.back()->setPosition(nf::Vec3(5.0 + x * 2.05, 1.0 + y * 2.05, -5.0 + z * 2.05)); } } @@ -52,20 +52,21 @@ void MainState::update(float deltaTime) { camera->setType(currCamType); } - float speed = 5.0; + float speed; if (camera->getType() == nf::Camera::Type::FIRST_PERSON) { if (app->isKeyHeld(NFI_SHIFT)) - speed = 20.0; + speed = 20.0f; else - speed = 5.0; + speed = 5.0f; + speed *= deltaTime; if (app->isKeyHeld(NFI_W)) - camera->moveForward(speed * deltaTime); + camera->moveZ(speed); if (app->isKeyHeld(NFI_S)) - camera->moveBackward(speed * deltaTime); + camera->moveZ(-speed); if (app->isKeyHeld(NFI_D)) - camera->moveRight(speed * deltaTime); + camera->moveX(speed); if (app->isKeyHeld(NFI_A)) - camera->moveLeft(speed * deltaTime); + camera->moveX(-speed); } text.setText("FPS: " + std::to_string(app->getFPS())); @@ -134,7 +135,7 @@ void MainState::render(nf::Renderer& renderer) { } void MainState::onExit() { - Log("MainState onExit!"); + NFLog("MainState onExit!"); entities.clear(); } \ No newline at end of file diff --git a/NothinFancy/NothinFancy.vcxproj b/NothinFancy/NothinFancy.vcxproj index 79a9f59..5b6efa4 100644 --- a/NothinFancy/NothinFancy.vcxproj +++ b/NothinFancy/NothinFancy.vcxproj @@ -57,7 +57,7 @@ Level3 true - NFENGINE; GLEW_STATIC;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + GLEW_STATIC;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) true $(ProjectDir)src\include\;$(ProjectDir)dep\include\ $(IntDir)obj\ @@ -89,7 +89,7 @@ true true true - NFENGINE; GLEW_STATIC;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + GLEW_STATIC;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true $(ProjectDir)src\include\;$(ProjectDir)dep\include\ $(IntDir)obj\ diff --git a/NothinFancy/src/Application.cpp b/NothinFancy/src/Application.cpp index 1ef5342..67b72c0 100644 --- a/NothinFancy/src/Application.cpp +++ b/NothinFancy/src/Application.cpp @@ -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(); } diff --git a/NothinFancy/src/Assets.cpp b/NothinFancy/src/Assets.cpp index f6467a6..5a89bff 100644 --- a/NothinFancy/src/Assets.cpp +++ b/NothinFancy/src/Assets.cpp @@ -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() { diff --git a/NothinFancy/src/AudioEngine.cpp b/NothinFancy/src/AudioEngine.cpp index 6d62ceb..a620940 100644 --- a/NothinFancy/src/AudioEngine.cpp +++ b/NothinFancy/src/AudioEngine.cpp @@ -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); diff --git a/NothinFancy/src/Gamestate.cpp b/NothinFancy/src/Gamestate.cpp index 630a9fb..fe46e70 100644 --- a/NothinFancy/src/Gamestate.cpp +++ b/NothinFancy/src/Gamestate.cpp @@ -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() { diff --git a/NothinFancy/src/IntroGamestate.cpp b/NothinFancy/src/IntroGamestate.cpp index dfbd436..27416fc 100644 --- a/NothinFancy/src/IntroGamestate.cpp +++ b/NothinFancy/src/IntroGamestate.cpp @@ -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!"); } } \ No newline at end of file diff --git a/NothinFancy/src/NFObject/Button.cpp b/NothinFancy/src/NFObject/Button.cpp index e5ec3d3..9feef4b 100644 --- a/NothinFancy/src/NFObject/Button.cpp +++ b/NothinFancy/src/NFObject/Button.cpp @@ -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(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, diff --git a/NothinFancy/src/NFObject/Cubemap.cpp b/NothinFancy/src/NFObject/Cubemap.cpp index c72e0ea..3ac2aee 100644 --- a/NothinFancy/src/NFObject/Cubemap.cpp +++ b/NothinFancy/src/NFObject/Cubemap.cpp @@ -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); diff --git a/NothinFancy/src/NFObject/Entity.cpp b/NothinFancy/src/NFObject/Entity.cpp index fb674bd..92080dc 100644 --- a/NothinFancy/src/NFObject/Entity.cpp +++ b/NothinFancy/src/NFObject/Entity.cpp @@ -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(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; } diff --git a/NothinFancy/src/NFObject/Light.cpp b/NothinFancy/src/NFObject/Light.cpp index 327ed04..57587bb 100644 --- a/NothinFancy/src/NFObject/Light.cpp +++ b/NothinFancy/src/NFObject/Light.cpp @@ -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; diff --git a/NothinFancy/src/NFObject/Sound.cpp b/NothinFancy/src/NFObject/Sound.cpp index 142c912..ee8cd4a 100644 --- a/NothinFancy/src/NFObject/Sound.cpp +++ b/NothinFancy/src/NFObject/Sound.cpp @@ -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(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); diff --git a/NothinFancy/src/NFObject/Text.cpp b/NothinFancy/src/NFObject/Text.cpp index 68d5bd3..bf41e1d 100644 --- a/NothinFancy/src/NFObject/Text.cpp +++ b/NothinFancy/src/NFObject/Text.cpp @@ -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(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); diff --git a/NothinFancy/src/NFObject/UITexture.cpp b/NothinFancy/src/NFObject/UITexture.cpp index 0944ef5..34c078d 100644 --- a/NothinFancy/src/NFObject/UITexture.cpp +++ b/NothinFancy/src/NFObject/UITexture.cpp @@ -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(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; diff --git a/NothinFancy/src/PhysicsEngine.cpp b/NothinFancy/src/PhysicsEngine.cpp index 4dac779..5049744 100644 --- a/NothinFancy/src/PhysicsEngine.cpp +++ b/NothinFancy/src/PhysicsEngine.cpp @@ -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) { diff --git a/NothinFancy/src/Renderer/Camera.cpp b/NothinFancy/src/Renderer/Camera.cpp index 2d1d678..d96bbae 100644 --- a/NothinFancy/src/Renderer/Camera.cpp +++ b/NothinFancy/src/Renderer/Camera.cpp @@ -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: { diff --git a/NothinFancy/src/Renderer/Drawable.cpp b/NothinFancy/src/Renderer/Drawable.cpp index b2dbd1d..026992b 100644 --- a/NothinFancy/src/Renderer/Drawable.cpp +++ b/NothinFancy/src/Renderer/Drawable.cpp @@ -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() { diff --git a/NothinFancy/src/Renderer/Model.cpp b/NothinFancy/src/Renderer/Model.cpp index 1f62fc6..6818e9f 100644 --- a/NothinFancy/src/Renderer/Model.cpp +++ b/NothinFancy/src/Renderer/Model.cpp @@ -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 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 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); diff --git a/NothinFancy/src/Renderer/Renderer.cpp b/NothinFancy/src/Renderer/Renderer.cpp index 6893349..bcecb94 100644 --- a/NothinFancy/src/Renderer/Renderer.cpp +++ b/NothinFancy/src/Renderer/Renderer.cpp @@ -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 = ∈ } @@ -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); } diff --git a/NothinFancy/src/Renderer/Shader.cpp b/NothinFancy/src/Renderer/Shader.cpp index 1b95b80..d863d2b 100644 --- a/NothinFancy/src/Renderer/Shader.cpp +++ b/NothinFancy/src/Renderer/Shader.cpp @@ -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; } diff --git a/NothinFancy/src/Renderer/Texture.cpp b/NothinFancy/src/Renderer/Texture.cpp index 930e87f..5d41d94 100644 --- a/NothinFancy/src/Renderer/Texture.cpp +++ b/NothinFancy/src/Renderer/Texture.cpp @@ -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); diff --git a/NothinFancy/src/Renderer/VertexArray.cpp b/NothinFancy/src/Renderer/VertexArray.cpp index a3fc77a..c73efe9 100644 --- a/NothinFancy/src/Renderer/VertexArray.cpp +++ b/NothinFancy/src/Renderer/VertexArray.cpp @@ -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); } diff --git a/NothinFancy/src/Utility.cpp b/NothinFancy/src/Utility.cpp index d1ed958..fe5eac2 100644 --- a/NothinFancy/src/Utility.cpp +++ b/NothinFancy/src/Utility.cpp @@ -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()); diff --git a/NothinFancy/src/include/Application.h b/NothinFancy/src/include/Application.h index 3a20ef1..0abf0fb 100644 --- a/NothinFancy/src/include/Application.h +++ b/NothinFancy/src/include/Application.h @@ -2,53 +2,183 @@ #include #include #include +#define WIN32_LEAN_AND_MEAN #include #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; }; } \ No newline at end of file diff --git a/NothinFancy/src/include/Assets.h b/NothinFancy/src/include/Assets.h index ae13ebe..4b631b1 100644 --- a/NothinFancy/src/include/Assets.h +++ b/NothinFancy/src/include/Assets.h @@ -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 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; }; } \ No newline at end of file diff --git a/NothinFancy/src/include/Button.h b/NothinFancy/src/include/Button.h index 9ab6979..e980013 100644 --- a/NothinFancy/src/include/Button.h +++ b/NothinFancy/src/include/Button.h @@ -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: diff --git a/NothinFancy/src/include/Camera.h b/NothinFancy/src/include/Camera.h index d2a6edf..68f9ae1 100644 --- a/NothinFancy/src/include/Camera.h +++ b/NothinFancy/src/include/Camera.h @@ -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; diff --git a/NothinFancy/src/include/Config.h b/NothinFancy/src/include/Config.h index ada3a8e..86c4eef 100644 --- a/NothinFancy/src/include/Config.h +++ b/NothinFancy/src/include/Config.h @@ -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; }; } \ No newline at end of file diff --git a/NothinFancy/src/include/Cubemap.h b/NothinFancy/src/include/Cubemap.h index aa5ad02..2dd2ef3 100644 --- a/NothinFancy/src/include/Cubemap.h +++ b/NothinFancy/src/include/Cubemap.h @@ -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: diff --git a/NothinFancy/src/include/Entity.h b/NothinFancy/src/include/Entity.h index 9f28108..51854dd 100644 --- a/NothinFancy/src/include/Entity.h +++ b/NothinFancy/src/include/Entity.h @@ -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; diff --git a/NothinFancy/src/include/Gamestate.h b/NothinFancy/src/include/Gamestate.h index 191a7b0..1d8f11d 100644 --- a/NothinFancy/src/include/Gamestate.h +++ b/NothinFancy/src/include/Gamestate.h @@ -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 m_nfObjects; std::vector m_entsToDelete; std::unordered_set m_modelsToDelete; diff --git a/NothinFancy/src/include/Light.h b/NothinFancy/src/include/Light.h index e599d33..1b68f86 100644 --- a/NothinFancy/src/include/Light.h +++ b/NothinFancy/src/include/Light.h @@ -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: diff --git a/NothinFancy/src/include/NothinFancy.h b/NothinFancy/src/include/NothinFancy.h index 2ce3098..1b20ac9 100644 --- a/NothinFancy/src/include/NothinFancy.h +++ b/NothinFancy/src/include/NothinFancy.h @@ -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 -#include -#include -#include +#ifndef NFIMPL +#define NFIMPL 1 +#endif #include "Config.h" #include "Application.h" diff --git a/NothinFancy/src/include/Renderer.h b/NothinFancy/src/include/Renderer.h index 30268b7..831dfe5 100644 --- a/NothinFancy/src/include/Renderer.h +++ b/NothinFancy/src/include/Renderer.h @@ -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(); diff --git a/NothinFancy/src/include/Sound.h b/NothinFancy/src/include/Sound.h index d6ac4d3..4e80f15 100644 --- a/NothinFancy/src/include/Sound.h +++ b/NothinFancy/src/include/Sound.h @@ -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; diff --git a/NothinFancy/src/include/Text.h b/NothinFancy/src/include/Text.h index 49c4d06..9cb3ca6 100644 --- a/NothinFancy/src/include/Text.h +++ b/NothinFancy/src/include/Text.h @@ -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: diff --git a/NothinFancy/src/include/UITexture.h b/NothinFancy/src/include/UITexture.h index 84f0755..736f2f1 100644 --- a/NothinFancy/src/include/UITexture.h +++ b/NothinFancy/src/include/UITexture.h @@ -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: diff --git a/NothinFancy/src/include/Utility.h b/NothinFancy/src/include/Utility.h index 331d646..beb1db5 100644 --- a/NothinFancy/src/include/Utility.h +++ b/NothinFancy/src/include/Utility.h @@ -4,22 +4,48 @@ #include #include +/** + * @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); } \ No newline at end of file diff --git a/docs/Doxyfile b/docs/Doxyfile new file mode 100644 index 0000000..f51d8ee --- /dev/null +++ b/docs/Doxyfile @@ -0,0 +1,346 @@ +# Doxyfile 1.9.2 + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- +DOXYFILE_ENCODING = UTF-8 +PROJECT_NAME = "Nothin' Fancy" +PROJECT_NUMBER = 0.1 +PROJECT_BRIEF = "C++ 3D Game Engine" +PROJECT_LOGO = images/logo.png +OUTPUT_DIRECTORY = . +CREATE_SUBDIRS = NO +ALLOW_UNICODE_NAMES = NO +OUTPUT_LANGUAGE = English +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the +ALWAYS_DETAILED_SEC = NO +INLINE_INHERITED_MEMB = NO +FULL_PATH_NAMES = NO +STRIP_FROM_PATH = +STRIP_FROM_INC_PATH = +SHORT_NAMES = NO +JAVADOC_AUTOBRIEF = NO +JAVADOC_BANNER = NO +QT_AUTOBRIEF = NO +MULTILINE_CPP_IS_BRIEF = NO +PYTHON_DOCSTRING = YES +INHERIT_DOCS = YES +SEPARATE_MEMBER_PAGES = NO +TAB_SIZE = 4 +ALIASES = +OPTIMIZE_OUTPUT_FOR_C = NO +OPTIMIZE_OUTPUT_JAVA = NO +OPTIMIZE_FOR_FORTRAN = NO +OPTIMIZE_OUTPUT_VHDL = NO +OPTIMIZE_OUTPUT_SLICE = NO +EXTENSION_MAPPING = +MARKDOWN_SUPPORT = YES +TOC_INCLUDE_HEADINGS = 5 +AUTOLINK_SUPPORT = YES +BUILTIN_STL_SUPPORT = NO +CPP_CLI_SUPPORT = NO +SIP_SUPPORT = NO +IDL_PROPERTY_SUPPORT = YES +DISTRIBUTE_GROUP_DOC = NO +GROUP_NESTED_COMPOUNDS = NO +SUBGROUPING = YES +INLINE_GROUPED_CLASSES = NO +INLINE_SIMPLE_STRUCTS = NO +TYPEDEF_HIDES_STRUCT = NO +LOOKUP_CACHE_SIZE = 0 +NUM_PROC_THREADS = 1 +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- +EXTRACT_ALL = NO +EXTRACT_PRIVATE = NO +EXTRACT_PRIV_VIRTUAL = NO +EXTRACT_PACKAGE = NO +EXTRACT_STATIC = NO +EXTRACT_LOCAL_CLASSES = NO +EXTRACT_LOCAL_METHODS = NO +EXTRACT_ANON_NSPACES = NO +RESOLVE_UNNAMED_PARAMS = YES +HIDE_UNDOC_MEMBERS = YES +HIDE_UNDOC_CLASSES = YES +HIDE_FRIEND_COMPOUNDS = NO +HIDE_IN_BODY_DOCS = NO +INTERNAL_DOCS = NO +CASE_SENSE_NAMES = NO +HIDE_SCOPE_NAMES = NO +HIDE_COMPOUND_REFERENCE= NO +SHOW_HEADERFILE = YES +SHOW_INCLUDE_FILES = NO +SHOW_GROUPED_MEMB_INC = NO +FORCE_LOCAL_INCLUDES = NO +INLINE_INFO = YES +SORT_MEMBER_DOCS = NO +SORT_BRIEF_DOCS = NO +SORT_MEMBERS_CTORS_1ST = NO +SORT_GROUP_NAMES = NO +SORT_BY_SCOPE_NAME = NO +STRICT_PROTO_MATCHING = NO +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +GENERATE_DEPRECATEDLIST= YES +ENABLED_SECTIONS = +MAX_INITIALIZER_LINES = 30 +SHOW_USED_FILES = YES +SHOW_FILES = YES +SHOW_NAMESPACES = YES +FILE_VERSION_FILTER = +LAYOUT_FILE = layout.xml +CITE_BIB_FILES = +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- +QUIET = NO +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_IF_DOC_ERROR = YES +WARN_IF_INCOMPLETE_DOC = YES +WARN_NO_PARAMDOC = NO +WARN_AS_ERROR = NO +WARN_FORMAT = "$file:$line: $text" +WARN_LOGFILE = +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- +INPUT = pages \ + ../NothinFancy/src/include +INPUT_ENCODING = UTF-8 +FILE_PATTERNS = *.h \ + *.md +RECURSIVE = YES +EXCLUDE = ../NothinFancy/src/include/IntroGamestate.h +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = +EXCLUDE_SYMBOLS = +EXAMPLE_PATH = examples +EXAMPLE_PATTERNS = * +EXAMPLE_RECURSIVE = NO +IMAGE_PATH = images +INPUT_FILTER = +FILTER_PATTERNS = +FILTER_SOURCE_FILES = NO +FILTER_SOURCE_PATTERNS = +USE_MDFILE_AS_MAINPAGE = main.md +#--------------------------------------------------------------------------- +# Configuration options related to source browsing +#--------------------------------------------------------------------------- +SOURCE_BROWSER = NO +INLINE_SOURCES = NO +STRIP_CODE_COMMENTS = YES +REFERENCED_BY_RELATION = NO +REFERENCES_RELATION = NO +REFERENCES_LINK_SOURCE = YES +SOURCE_TOOLTIPS = YES +USE_HTAGS = NO +VERBATIM_HEADERS = NO +CLANG_ASSISTED_PARSING = NO +CLANG_ADD_INC_PATHS = YES +CLANG_OPTIONS = +CLANG_DATABASE_PATH = +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- +ALPHABETICAL_INDEX = NO +IGNORE_PREFIX = +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- +GENERATE_HTML = YES +HTML_OUTPUT = manual +HTML_FILE_EXTENSION = .html +HTML_HEADER = header.html +HTML_FOOTER = +HTML_STYLESHEET = +HTML_EXTRA_STYLESHEET = theme.css +HTML_EXTRA_FILES = favicon.png +HTML_COLORSTYLE_HUE = 30 +HTML_COLORSTYLE_SAT = 100 +HTML_COLORSTYLE_GAMMA = 80 +HTML_TIMESTAMP = NO +HTML_DYNAMIC_MENUS = YES +HTML_DYNAMIC_SECTIONS = NO +HTML_INDEX_NUM_ENTRIES = 100 +GENERATE_DOCSET = NO +DOCSET_FEEDNAME = "Doxygen generated docs" +DOCSET_BUNDLE_ID = org.doxygen.Project +DOCSET_PUBLISHER_ID = org.doxygen.Publisher +DOCSET_PUBLISHER_NAME = Publisher +GENERATE_HTMLHELP = NO +CHM_FILE = +HHC_LOCATION = +GENERATE_CHI = NO +CHM_INDEX_ENCODING = +BINARY_TOC = NO +TOC_EXPAND = NO +GENERATE_QHP = NO +QCH_FILE = +QHP_NAMESPACE = org.doxygen.Project +QHP_VIRTUAL_FOLDER = doc +QHP_CUST_FILTER_NAME = +QHP_CUST_FILTER_ATTRS = +QHP_SECT_FILTER_ATTRS = +QHG_LOCATION = +GENERATE_ECLIPSEHELP = NO +ECLIPSE_DOC_ID = org.doxygen.Project +DISABLE_INDEX = NO +GENERATE_TREEVIEW = YES +FULL_SIDEBAR = NO +ENUM_VALUES_PER_LINE = 4 +TREEVIEW_WIDTH = 250 +EXT_LINKS_IN_WINDOW = NO +HTML_FORMULA_FORMAT = png +FORMULA_FONTSIZE = 10 +FORMULA_TRANSPARENT = YES +FORMULA_MACROFILE = +USE_MATHJAX = NO +MATHJAX_VERSION = MathJax_2 +MATHJAX_FORMAT = HTML-CSS +MATHJAX_RELPATH = +MATHJAX_EXTENSIONS = +MATHJAX_CODEFILE = +SEARCHENGINE = YES +SERVER_BASED_SEARCH = NO +EXTERNAL_SEARCH = NO +SEARCHENGINE_URL = +SEARCHDATA_FILE = searchdata.xml +EXTERNAL_SEARCH_ID = +EXTRA_SEARCH_MAPPINGS = +#--------------------------------------------------------------------------- +# Configuration options related to the LaTeX output +#--------------------------------------------------------------------------- +GENERATE_LATEX = NO +LATEX_OUTPUT = latex +LATEX_CMD_NAME = +MAKEINDEX_CMD_NAME = makeindex +LATEX_MAKEINDEX_CMD = makeindex +COMPACT_LATEX = NO +PAPER_TYPE = a4 +EXTRA_PACKAGES = +LATEX_HEADER = +LATEX_FOOTER = +LATEX_EXTRA_STYLESHEET = +LATEX_EXTRA_FILES = +PDF_HYPERLINKS = YES +USE_PDFLATEX = YES +LATEX_BATCHMODE = NO +LATEX_HIDE_INDICES = NO +LATEX_BIB_STYLE = plain +LATEX_TIMESTAMP = NO +LATEX_EMOJI_DIRECTORY = +#--------------------------------------------------------------------------- +# Configuration options related to the RTF output +#--------------------------------------------------------------------------- +GENERATE_RTF = NO +RTF_OUTPUT = rtf +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = +#--------------------------------------------------------------------------- +# Configuration options related to the man page output +#--------------------------------------------------------------------------- +GENERATE_MAN = NO +MAN_OUTPUT = man +MAN_EXTENSION = .3 +MAN_SUBDIR = +MAN_LINKS = NO +#--------------------------------------------------------------------------- +# Configuration options related to the XML output +#--------------------------------------------------------------------------- +GENERATE_XML = NO +XML_OUTPUT = xml +XML_PROGRAMLISTING = YES +XML_NS_MEMB_FILE_SCOPE = NO +#--------------------------------------------------------------------------- +# Configuration options related to the DOCBOOK output +#--------------------------------------------------------------------------- +GENERATE_DOCBOOK = NO +DOCBOOK_OUTPUT = docbook +#--------------------------------------------------------------------------- +# Configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- +GENERATE_AUTOGEN_DEF = NO +#--------------------------------------------------------------------------- +# Configuration options related to the Perl module output +#--------------------------------------------------------------------------- +GENERATE_PERLMOD = NO +PERLMOD_LATEX = NO +PERLMOD_PRETTY = YES +PERLMOD_MAKEVAR_PREFIX = +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = NO +EXPAND_ONLY_PREDEF = NO +SEARCH_INCLUDES = YES +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = doxygen +EXPAND_AS_DEFINED = +SKIP_FUNCTION_MACROS = YES +#--------------------------------------------------------------------------- +# Configuration options related to external references +#--------------------------------------------------------------------------- +TAGFILES = +GENERATE_TAGFILE = +ALLEXTERNALS = NO +EXTERNAL_GROUPS = YES +EXTERNAL_PAGES = YES +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- +CLASS_DIAGRAMS = YES +DIA_PATH = +HIDE_UNDOC_RELATIONS = YES +HAVE_DOT = NO +DOT_NUM_THREADS = 0 +DOT_FONTNAME = Helvetica +DOT_FONTSIZE = 10 +DOT_FONTPATH = +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +GROUP_GRAPHS = YES +UML_LOOK = NO +UML_LIMIT_NUM_FIELDS = 10 +DOT_UML_DETAILS = NO +DOT_WRAP_THRESHOLD = 17 +TEMPLATE_RELATIONS = NO +INCLUDE_GRAPH = YES +INCLUDED_BY_GRAPH = YES +CALL_GRAPH = NO +CALLER_GRAPH = NO +GRAPHICAL_HIERARCHY = YES +DIRECTORY_GRAPH = YES +DOT_IMAGE_FORMAT = png +INTERACTIVE_SVG = NO +DOT_PATH = +DOTFILE_DIRS = +MSCFILE_DIRS = +DIAFILE_DIRS = +PLANTUML_JAR_PATH = +PLANTUML_CFG_FILE = +PLANTUML_INCLUDE_PATH = +DOT_GRAPH_MAX_NODES = 50 +MAX_DOT_GRAPH_DEPTH = 0 +DOT_TRANSPARENT = NO +DOT_MULTI_TARGETS = NO +GENERATE_LEGEND = YES +DOT_CLEANUP = YES diff --git a/docs/favicon.png b/docs/favicon.png new file mode 100644 index 0000000..5691d1b Binary files /dev/null and b/docs/favicon.png differ diff --git a/docs/header.html b/docs/header.html new file mode 100644 index 0000000..ca161b1 --- /dev/null +++ b/docs/header.html @@ -0,0 +1,74 @@ + + + + + + + + + +$projectname: $title +$title + + + + + + + + +$treeview +$search +$mathjax + +$extrastylesheet + + + + +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
$projectname $projectnumber +
+
$projectbrief
+
+
$projectbrief
+
$searchbox
$searchbox
+
+ + diff --git a/docs/images/logo.png b/docs/images/logo.png new file mode 100644 index 0000000..160fb5b Binary files /dev/null and b/docs/images/logo.png differ diff --git a/docs/images/logofull.png b/docs/images/logofull.png new file mode 100644 index 0000000..765225e Binary files /dev/null and b/docs/images/logofull.png differ diff --git a/docs/layout.xml b/docs/layout.xml new file mode 100644 index 0000000..bcd20ef --- /dev/null +++ b/docs/layout.xml @@ -0,0 +1,240 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/pages/1_install.md b/docs/pages/1_install.md new file mode 100644 index 0000000..058f273 --- /dev/null +++ b/docs/pages/1_install.md @@ -0,0 +1,19 @@ +@page install Installation +@tableofcontents + +This page details how to install NF in a MSVC project. + +@section prereq Prerequisites + +In order to create an NF application, you must first have the following: + +- Visual Studio 2022 or later (MSVC v143 or later) +- A 64 bit computer as NF is 64 bit only +- A compatible graphics card (See @ref issues) +- Apt C++ knowledge +- The engine itself +@todo Link download here? + +@section projSetup Step One: Project Setup + +@note kdlsjfldksjf \ No newline at end of file diff --git a/docs/pages/2_tutorial.md b/docs/pages/2_tutorial.md new file mode 100644 index 0000000..5cdcf44 --- /dev/null +++ b/docs/pages/2_tutorial.md @@ -0,0 +1,21 @@ +@page tutorial Tutorial +@tableofcontents + +This tutorial aims to teach the basics of the engine and how to use it. + +First, follow the steps on the @ref install page. Once NF has been installed into a new +MSVC project in Visual Studio, you can begin here. + +@section createConfig Creating a Config + +@todo The tutorial page + +@section createUI Creating a UI + +@section createCubemap Adding a Cubemap (Skybox) + +@todo Lighting page? + +@image html logofull.png "NF Logo" width=200px + +Really cool \ No newline at end of file diff --git a/docs/pages/3_gamestates.md b/docs/pages/3_gamestates.md new file mode 100644 index 0000000..ab4466a --- /dev/null +++ b/docs/pages/3_gamestates.md @@ -0,0 +1,8 @@ +@page gamestates Gamestate System +@tableofcontents + +@todo The gamestates page + +@section enterAndExit onEnter and onExit + +@section obLifetime Object Lifetime \ No newline at end of file diff --git a/docs/pages/4_assets.md b/docs/pages/4_assets.md new file mode 100644 index 0000000..9bf043c --- /dev/null +++ b/docs/pages/4_assets.md @@ -0,0 +1,13 @@ +@page assets Asset System + +This page details NF's asset system and custom pack format. + +@section buildAssets How to Build Your Assets + +@todo Asset system page + +@section customFonts Custom Font Assets + +@section customButtons Custom Button Assets + +@section customCubemap Custom Cubemap Assets \ No newline at end of file diff --git a/docs/pages/5_issues.md b/docs/pages/5_issues.md new file mode 100644 index 0000000..1aa5c35 --- /dev/null +++ b/docs/pages/5_issues.md @@ -0,0 +1,6 @@ +@page issues Known Issues + +This page includes the known issues of the engine in order of importance. + +1. Shader compilation errors + - This issue is caused by differences in graphics drivers and what exact OpenGL shader code they will compile. **This issue will be attended to soon.** \ No newline at end of file diff --git a/docs/pages/main.md b/docs/pages/main.md new file mode 100644 index 0000000..ab2eef8 --- /dev/null +++ b/docs/pages/main.md @@ -0,0 +1,35 @@ +@tableofcontents + +Nothin' Fancy (abbreviated as NF) is an experimental 3D game engine written in C++ +for Windows. It was created by Grayson Riffe in 2021. This manual aims to aid the end-user +with using this engine to create games and visualizations. It contains a user guide and +the API reference. + +@image html logofull.png "Engine Logo" width=200px + +Features +=== + +In its current form, NF is always changing and evolving, so some of these features could change +at any time. + +- @ref gamestates +- @ref assets +- Easy-to-use input +- Deffered renderer +- Materials system + - Color, specular, and normal texture support +- Cubemap support +- 3D sound support +- Rigid body physics +- Customizable UI + - Text + - Textures + - Buttons also with customizable textures + +Example App +=== + +You can download the source or build for the example game that includes all of the +aforementioned features. +@todo Example App download \ No newline at end of file diff --git a/docs/theme.css b/docs/theme.css new file mode 100644 index 0000000..8e3f174 --- /dev/null +++ b/docs/theme.css @@ -0,0 +1,1827 @@ +/* The standard CSS for doxygen 1.9.2 */ + +body, table, div, p, dl { + font: 400 14px/22px Roboto,sans-serif; +} + +p.reference, p.definition { + font: 400 14px/22px Roboto,sans-serif; +} + +/* @group Heading Levels */ + +h1.groupheader { + font-size: 150%; +} + +.title { + font: 400 14px/28px Roboto,sans-serif; + font-size: 150%; + font-weight: bold; + margin: 10px 2px; +} + +h2.groupheader { + border-bottom: 1px solid #CBA987; + color: #7B5835; + font-size: 150%; + font-weight: normal; + margin-top: 1.75em; + padding-top: 8px; + padding-bottom: 4px; + width: 100%; +} + +h3.groupheader { + font-size: 100%; +} + +h1, h2, h3, h4, h5, h6 { + -webkit-transition: text-shadow 0.5s linear; + -moz-transition: text-shadow 0.5s linear; + -ms-transition: text-shadow 0.5s linear; + -o-transition: text-shadow 0.5s linear; + transition: text-shadow 0.5s linear; + margin-right: 15px; +} + +h1.glow, h2.glow, h3.glow, h4.glow, h5.glow, h6.glow { + text-shadow: 0 0 15px cyan; +} + +dt { + font-weight: bold; +} + +ul.multicol { + -moz-column-gap: 1em; + -webkit-column-gap: 1em; + column-gap: 1em; + -moz-column-count: 3; + -webkit-column-count: 3; + column-count: 3; +} + +p.startli, p.startdd { + margin-top: 2px; +} + +th p.starttd, th p.intertd, th p.endtd { + font-size: 100%; + font-weight: 700; +} + +p.starttd { + margin-top: 0px; +} + +p.endli { + margin-bottom: 0px; +} + +p.enddd { + margin-bottom: 4px; +} + +p.endtd { + margin-bottom: 2px; +} + +p.interli { +} + +p.interdd { +} + +p.intertd { +} + +/* @end */ + +caption { + font-weight: bold; +} + +span.legend { + font-size: 70%; + text-align: center; +} + +h3.version { + font-size: 90%; + text-align: center; +} + +div.navtab { + border-right: 1px solid #D7BDA3; + padding-right: 15px; + text-align: right; + line-height: 110%; +} + +div.navtab table { + border-spacing: 0; +} + +td.navtab { + padding-right: 6px; + padding-left: 6px; +} +td.navtabHL { + background-image: url('tab_a.png'); + background-repeat:repeat-x; + padding-right: 6px; + padding-left: 6px; +} + +td.navtabHL a, td.navtabHL a:visited { + color: #fff; + text-shadow: 0px 1px 1px rgba(0, 0, 0, 1.0); +} + +a.navtab { + font-weight: bold; +} + +div.qindex{ + text-align: center; + width: 100%; + line-height: 140%; + font-size: 130%; + color: #A0A0A0; +} + +dt.alphachar{ + font-size: 180%; + font-weight: bold; +} + +.alphachar a{ + color: black; +} + +.alphachar a:hover, .alphachar a:visited{ + text-decoration: none; +} + +.classindex dl { + padding: 25px; + column-count:1 +} + +.classindex dd { + display:inline-block; + margin-left: 50px; + width: 90%; + line-height: 1.15em; +} + +.classindex dl.odd { + background-color: #FCFAF8; +} + +@media(min-width: 1120px) { + .classindex dl { + column-count:2 + } +} + +@media(min-width: 1320px) { + .classindex dl { + column-count:3 + } +} + + +/* @group Link Styling */ + +a { + color: #8C643D; + font-weight: normal; + text-decoration: none; +} + +.contents a:visited { + color: #A27446; +} + +a:hover { + text-decoration: underline; +} + +.contents a.qindexHL:visited { + color: #FFFFFF; +} + +a.el { + font-weight: bold; +} + +a.elRef { +} + +a.code, a.code:visited, a.line, a.line:visited { + color: #A27446; +} + +a.codeRef, a.codeRef:visited, a.lineRef, a.lineRef:visited { + color: #A27446; +} + +a.code.hl_class { /* style for links to class names in code snippets */ } +a.code.hl_struct { /* style for links to struct names in code snippets */ } +a.code.hl_union { /* style for links to union names in code snippets */ } +a.code.hl_interface { /* style for links to interface names in code snippets */ } +a.code.hl_protocol { /* style for links to protocol names in code snippets */ } +a.code.hl_category { /* style for links to category names in code snippets */ } +a.code.hl_exception { /* style for links to exception names in code snippets */ } +a.code.hl_service { /* style for links to service names in code snippets */ } +a.code.hl_singleton { /* style for links to singleton names in code snippets */ } +a.code.hl_concept { /* style for links to concept names in code snippets */ } +a.code.hl_namespace { /* style for links to namespace names in code snippets */ } +a.code.hl_package { /* style for links to package names in code snippets */ } +a.code.hl_define { /* style for links to macro names in code snippets */ } +a.code.hl_function { /* style for links to function names in code snippets */ } +a.code.hl_variable { /* style for links to variable names in code snippets */ } +a.code.hl_typedef { /* style for links to typedef names in code snippets */ } +a.code.hl_enumvalue { /* style for links to enum value names in code snippets */ } +a.code.hl_enumeration { /* style for links to enumeration names in code snippets */ } +a.code.hl_signal { /* style for links to Qt signal names in code snippets */ } +a.code.hl_slot { /* style for links to Qt slot names in code snippets */ } +a.code.hl_friend { /* style for links to friend names in code snippets */ } +a.code.hl_dcop { /* style for links to KDE3 DCOP names in code snippets */ } +a.code.hl_property { /* style for links to property names in code snippets */ } +a.code.hl_event { /* style for links to event names in code snippets */ } +a.code.hl_sequence { /* style for links to sequence names in code snippets */ } +a.code.hl_dictionary { /* style for links to dictionary names in code snippets */ } + +/* @end */ + +dl.el { + margin-left: -1cm; +} + +ul { + overflow: hidden; /*Fixed: list item bullets overlap floating elements*/ +} + +#side-nav ul { + overflow: visible; /* reset ul rule for scroll bar in GENERATE_TREEVIEW window */ +} + +#main-nav ul { + overflow: visible; /* reset ul rule for the navigation bar drop down lists */ +} + +.fragment { + text-align: left; + direction: ltr; + overflow-x: auto; /*Fixed: fragment lines overlap floating elements*/ + overflow-y: hidden; +} + +pre.fragment { + border: 1px solid #E5D5C4; + background-color: #FDFCFB; + padding: 4px 6px; + margin: 4px 8px 4px 2px; + overflow: auto; + word-wrap: break-word; + font-size: 9pt; + line-height: 125%; + font-family: monospace, fixed; + font-size: 105%; +} + +div.fragment { + padding: 0 0 1px 0; /*Fixed: last line underline overlap border*/ + margin: 4px 8px 4px 2px; + background-color: #FDFCFB; + border: 1px solid #E5D5C4; +} + +div.line { + font-family: monospace, fixed; + font-size: 13px; + min-height: 13px; + line-height: 1.0; + text-wrap: unrestricted; + white-space: -moz-pre-wrap; /* Moz */ + white-space: -pre-wrap; /* Opera 4-6 */ + white-space: -o-pre-wrap; /* Opera 7 */ + white-space: pre-wrap; /* CSS3 */ + word-wrap: break-word; /* IE 5.5+ */ + text-indent: -53px; + padding-left: 53px; + padding-bottom: 0px; + margin: 0px; + -webkit-transition-property: background-color, box-shadow; + -webkit-transition-duration: 0.5s; + -moz-transition-property: background-color, box-shadow; + -moz-transition-duration: 0.5s; + -ms-transition-property: background-color, box-shadow; + -ms-transition-duration: 0.5s; + -o-transition-property: background-color, box-shadow; + -o-transition-duration: 0.5s; + transition-property: background-color, box-shadow; + transition-duration: 0.5s; +} + +div.line:after { + content:"\000A"; + white-space: pre; +} + +div.line.glow { + background-color: cyan; + box-shadow: 0 0 10px cyan; +} + + +span.lineno { + padding-right: 4px; + margin-right: 9px; + text-align: right; + border-right: 2px solid #0F0; + background-color: #E8E8E8; + white-space: pre; +} +span.lineno a { + background-color: #D8D8D8; +} + +span.lineno a:hover { + background-color: #C8C8C8; +} + +.lineno { + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +div.ah, span.ah { + background-color: black; + font-weight: bold; + color: #FFFFFF; + margin-bottom: 3px; + margin-top: 3px; + padding: 0.2em; + border: solid thin #333; + border-radius: 0.5em; + -webkit-border-radius: .5em; + -moz-border-radius: .5em; + box-shadow: 2px 2px 3px #999; + -webkit-box-shadow: 2px 2px 3px #999; + -moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px; + background-image: -webkit-gradient(linear, left top, left bottom, from(#eee), to(#000),color-stop(0.3, #444)); + background-image: -moz-linear-gradient(center top, #eee 0%, #444 40%, #000 110%); +} + +div.classindex ul { + list-style: none; + padding-left: 0; +} + +div.classindex span.ai { + display: inline-block; +} + +div.groupHeader { + margin-left: 16px; + margin-top: 12px; + font-weight: bold; +} + +div.groupText { + margin-left: 16px; + font-style: italic; +} + +body { + background-color: white; + color: black; + margin: 0; +} + +div.contents { + margin-top: 10px; + margin-left: 12px; + margin-right: 8px; +} + +td.indexkey { + background-color: #F6F1EB; + font-weight: bold; + border: 1px solid #E5D5C4; + margin: 2px 0px 2px 0; + padding: 2px 10px; + white-space: nowrap; + vertical-align: top; +} + +td.indexvalue { + background-color: #F6F1EB; + border: 1px solid #E5D5C4; + padding: 2px 10px; + margin: 2px 0px; +} + +tr.memlist { + background-color: #F7F2EE; +} + +p.formulaDsp { + text-align: center; +} + +img.formulaDsp { + +} + +img.formulaInl, img.inline { + vertical-align: middle; +} + +div.center { + text-align: center; + margin-top: 0px; + margin-bottom: 0px; + padding: 0px; +} + +div.center img { + border: 0px; +} + +address.footer { + text-align: right; + padding-right: 12px; +} + +img.footer { + border: 0px; + vertical-align: middle; +} + +.compoundTemplParams { + color: #A27446; + font-size: 80%; + line-height: 120%; +} + +/* @group Code Colorization */ + +span.keyword { + color: #008000 +} + +span.keywordtype { + color: #604020 +} + +span.keywordflow { + color: #e08000 +} + +span.comment { + color: #800000 +} + +span.preprocessor { + color: #806020 +} + +span.stringliteral { + color: #002080 +} + +span.charliteral { + color: #008080 +} + +span.vhdldigit { + color: #ff00ff +} + +span.vhdlchar { + color: #000000 +} + +span.vhdlkeyword { + color: #700070 +} + +span.vhdllogic { + color: #ff0000 +} + +blockquote { + background-color: #FBF9F7; + border-left: 2px solid #D4B89C; + margin: 0 24px 0 4px; + padding: 0 12px 0 16px; +} + +blockquote.DocNodeRTL { + border-left: 0; + border-right: 2px solid #D4B89C; + margin: 0 4px 0 24px; + padding: 0 16px 0 12px; +} + +/* @end */ + +/* +.search { + color: #003399; + font-weight: bold; +} + +form.search { + margin-bottom: 0px; + margin-top: 0px; +} + +input.search { + font-size: 75%; + color: #000080; + font-weight: normal; + background-color: #e8eef2; +} +*/ + +td.tiny { + font-size: 75%; +} + +.dirtab { + padding: 4px; + border-collapse: collapse; + border: 1px solid #D7BDA3; +} + +th.dirtab { + background: #F6F1EB; + font-weight: bold; +} + +hr { + height: 0px; + border: none; + border-top: 1px solid #AA7A4A; +} + +hr.footer { + height: 1px; +} + +/* @group Member Descriptions */ + +table.memberdecls { + border-spacing: 0px; + padding: 0px; +} + +.memberdecls td, .fieldtable tr { + -webkit-transition-property: background-color, box-shadow; + -webkit-transition-duration: 0.5s; + -moz-transition-property: background-color, box-shadow; + -moz-transition-duration: 0.5s; + -ms-transition-property: background-color, box-shadow; + -ms-transition-duration: 0.5s; + -o-transition-property: background-color, box-shadow; + -o-transition-duration: 0.5s; + transition-property: background-color, box-shadow; + transition-duration: 0.5s; +} + +.memberdecls td.glow, .fieldtable tr.glow { + background-color: cyan; + box-shadow: 0 0 15px cyan; +} + +.mdescLeft, .mdescRight, +.memItemLeft, .memItemRight, +.memTemplItemLeft, .memTemplItemRight, .memTemplParams { + background-color: #FCFAF9; + border: none; + margin: 4px; + padding: 1px 0 0 8px; +} + +.mdescLeft, .mdescRight { + padding: 0px 8px 4px 8px; + color: #555; +} + +.memSeparator { + border-bottom: 1px solid #F0E7DE; + line-height: 1px; + margin: 0px; + padding: 0px; +} + +.memItemLeft, .memTemplItemLeft { + white-space: nowrap; +} + +.memItemRight, .memTemplItemRight { + width: 100%; +} + +.memTemplParams { + color: #A27446; + white-space: nowrap; + font-size: 80%; +} + +/* @end */ + +/* @group Member Details */ + +/* Styles for detailed member documentation */ + +.memtitle { + padding: 8px; + border-top: 1px solid #D9C0A8; + border-left: 1px solid #D9C0A8; + border-right: 1px solid #D9C0A8; + border-top-right-radius: 4px; + border-top-left-radius: 4px; + margin-bottom: -1px; + background-image: url('nav_f.png'); + background-repeat: repeat-x; + background-color: #F2EAE2; + line-height: 1.25; + font-weight: 300; + float:left; +} + +.permalink +{ + font-size: 65%; + display: inline-block; + vertical-align: middle; +} + +.memtemplate { + font-size: 80%; + color: #A27446; + font-weight: normal; + margin-left: 9px; +} + +.memnav { + background-color: #F6F1EB; + border: 1px solid #D7BDA3; + text-align: center; + margin: 2px; + margin-right: 15px; + padding: 2px; +} + +.mempage { + width: 100%; +} + +.memitem { + padding: 0; + margin-bottom: 10px; + margin-right: 5px; + -webkit-transition: box-shadow 0.5s linear; + -moz-transition: box-shadow 0.5s linear; + -ms-transition: box-shadow 0.5s linear; + -o-transition: box-shadow 0.5s linear; + transition: box-shadow 0.5s linear; + display: table !important; + width: 100%; +} + +.memitem.glow { + box-shadow: 0 0 15px cyan; +} + +.memname { + font-weight: 400; + margin-left: 6px; +} + +.memname td { + vertical-align: bottom; +} + +.memproto, dl.reflist dt { + border-top: 1px solid #D9C0A8; + border-left: 1px solid #D9C0A8; + border-right: 1px solid #D9C0A8; + padding: 6px 0px 6px 0px; + color: #553D25; + font-weight: bold; + text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.9); + background-color: #F1E8DF; + /* opera specific markup */ + box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + border-top-right-radius: 4px; + /* firefox specific markup */ + -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px; + -moz-border-radius-topright: 4px; + /* webkit specific markup */ + -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + -webkit-border-top-right-radius: 4px; + +} + +.overload { + font-family: "courier new",courier,monospace; + font-size: 65%; +} + +.memdoc, dl.reflist dd { + border-bottom: 1px solid #D9C0A8; + border-left: 1px solid #D9C0A8; + border-right: 1px solid #D9C0A8; + padding: 6px 10px 2px 10px; + background-color: #FDFCFB; + border-top-width: 0; + background-image:url('nav_g.png'); + background-repeat:repeat-x; + background-color: #FFFFFF; + /* opera specific markup */ + border-bottom-left-radius: 4px; + border-bottom-right-radius: 4px; + box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + /* firefox specific markup */ + -moz-border-radius-bottomleft: 4px; + -moz-border-radius-bottomright: 4px; + -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px; + /* webkit specific markup */ + -webkit-border-bottom-left-radius: 4px; + -webkit-border-bottom-right-radius: 4px; + -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); +} + +dl.reflist dt { + padding: 5px; +} + +dl.reflist dd { + margin: 0px 0px 10px 0px; + padding: 5px; +} + +.paramkey { + text-align: right; +} + +.paramtype { + white-space: nowrap; +} + +.paramname { + color: #602020; + white-space: nowrap; +} +.paramname em { + font-style: normal; +} +.paramname code { + line-height: 14px; +} + +.params, .retval, .exception, .tparams { + margin-left: 0px; + padding-left: 0px; +} + +.params .paramname, .retval .paramname, .tparams .paramname, .exception .paramname { + font-weight: bold; + vertical-align: top; +} + +.params .paramtype, .tparams .paramtype { + font-style: italic; + vertical-align: top; +} + +.params .paramdir, .tparams .paramdir { + font-family: "courier new",courier,monospace; + vertical-align: top; +} + +table.mlabels { + border-spacing: 0px; +} + +td.mlabels-left { + width: 100%; + padding: 0px; +} + +td.mlabels-right { + vertical-align: bottom; + padding: 0px; + white-space: nowrap; +} + +span.mlabels { + margin-left: 8px; +} + +span.mlabel { + background-color: #C19A72; + border-top:1px solid #B48453; + border-left:1px solid #B48453; + border-right:1px solid #E5D5C4; + border-bottom:1px solid #E5D5C4; + text-shadow: none; + color: white; + margin-right: 4px; + padding: 2px 3px; + border-radius: 3px; + font-size: 7pt; + white-space: nowrap; + vertical-align: middle; +} + + + +/* @end */ + +/* these are for tree view inside a (index) page */ + +div.directory { + margin: 10px 0px; + border-top: 1px solid #D4B89C; + border-bottom: 1px solid #D4B89C; + width: 100%; +} + +.directory table { + border-collapse:collapse; +} + +.directory td { + margin: 0px; + padding: 0px; + vertical-align: top; +} + +.directory td.entry { + white-space: nowrap; + padding-right: 6px; + padding-top: 3px; +} + +.directory td.entry a { + outline:none; +} + +.directory td.entry a img { + border: none; +} + +.directory td.desc { + width: 100%; + padding-left: 6px; + padding-right: 6px; + padding-top: 3px; + border-left: 1px solid rgba(0,0,0,0.05); +} + +.directory tr.even { + padding-left: 6px; + background-color: #FBF9F7; +} + +.directory img { + vertical-align: -30%; +} + +.directory .levels { + white-space: nowrap; + width: 100%; + text-align: right; + font-size: 9pt; +} + +.directory .levels span { + cursor: pointer; + padding-left: 2px; + padding-right: 2px; + color: #8C643D; +} + +.arrow { + color: #D4B89C; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + cursor: pointer; + font-size: 80%; + display: inline-block; + width: 16px; + height: 22px; +} + +.icon { + font-family: Arial, Helvetica; + font-weight: bold; + font-size: 12px; + height: 14px; + width: 16px; + display: inline-block; + background-color: #C19A72; + color: white; + text-align: center; + border-radius: 4px; + margin-left: 2px; + margin-right: 2px; +} + +.icona { + width: 24px; + height: 22px; + display: inline-block; +} + +.iconfopen { + width: 24px; + height: 18px; + margin-bottom: 4px; + background-image:url('folderopen.png'); + background-position: 0px -4px; + background-repeat: repeat-y; + vertical-align:top; + display: inline-block; +} + +.iconfclosed { + width: 24px; + height: 18px; + margin-bottom: 4px; + background-image:url('folderclosed.png'); + background-position: 0px -4px; + background-repeat: repeat-y; + vertical-align:top; + display: inline-block; +} + +.icondoc { + width: 24px; + height: 18px; + margin-bottom: 4px; + background-image:url('doc.png'); + background-position: 0px -4px; + background-repeat: repeat-y; + vertical-align:top; + display: inline-block; +} + +table.directory { + font: 400 14px Roboto,sans-serif; +} + +/* @end */ + +div.dynheader { + margin-top: 8px; + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +address { + font-style: normal; + color: #61462A; +} + +table.doxtable caption { + caption-side: top; +} + +table.doxtable { + border-collapse:collapse; + margin-top: 4px; + margin-bottom: 4px; +} + +table.doxtable td, table.doxtable th { + border: 1px solid #684A2D; + padding: 3px 7px 2px; +} + +table.doxtable th { + background-color: #7F5B37; + color: #FFFFFF; + font-size: 110%; + padding-bottom: 4px; + padding-top: 5px; +} + +table.fieldtable { + /*width: 100%;*/ + margin-bottom: 10px; + border: 1px solid #D9C0A8; + border-spacing: 0px; + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + border-radius: 4px; + -moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px; + -webkit-box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.15); + box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.15); +} + +.fieldtable td, .fieldtable th { + padding: 3px 7px 2px; +} + +.fieldtable td.fieldtype, .fieldtable td.fieldname { + white-space: nowrap; + border-right: 1px solid #D9C0A8; + border-bottom: 1px solid #D9C0A8; + vertical-align: top; +} + +.fieldtable td.fieldname { + padding-top: 3px; +} + +.fieldtable td.fielddoc { + border-bottom: 1px solid #D9C0A8; + /*width: 100%;*/ +} + +.fieldtable td.fielddoc p:first-child { + margin-top: 0px; +} + +.fieldtable td.fielddoc p:last-child { + margin-bottom: 2px; +} + +.fieldtable tr:last-child td { + border-bottom: none; +} + +.fieldtable th { + background-image:url('nav_f.png'); + background-repeat:repeat-x; + background-color: #F2EAE2; + font-size: 90%; + color: #553D25; + padding-bottom: 4px; + padding-top: 5px; + text-align:left; + font-weight: 400; + -moz-border-radius-topleft: 4px; + -moz-border-radius-topright: 4px; + -webkit-border-top-left-radius: 4px; + -webkit-border-top-right-radius: 4px; + border-top-left-radius: 4px; + border-top-right-radius: 4px; + border-bottom: 1px solid #D9C0A8; +} + + +.tabsearch { + top: 0px; + left: 10px; + height: 36px; + background-image: url('tab_b.png'); + z-index: 101; + overflow: hidden; + font-size: 13px; +} + +.navpath ul +{ + font-size: 11px; + background-image:url('tab_b.png'); + background-repeat:repeat-x; + background-position: 0 -5px; + height:30px; + line-height:30px; + color:#CCAB8A; + border:solid 1px #E4D3C2; + overflow:hidden; + margin:0px; + padding:0px; +} + +.navpath li +{ + list-style-type:none; + float:left; + padding-left:10px; + padding-right:15px; + background-image:url('bc_s.png'); + background-repeat:no-repeat; + background-position:right; + color:#7C5936; +} + +.navpath li.navelem a +{ + height:32px; + display:block; + text-decoration: none; + outline: none; + color: #5D4328; + font-family: 'Lucida Grande',Geneva,Helvetica,Arial,sans-serif; + text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.9); + text-decoration: none; +} + +.navpath li.navelem a:hover +{ + color:#BD9268; +} + +.navpath li.footer +{ + list-style-type:none; + float:right; + padding-left:10px; + padding-right:15px; + background-image:none; + background-repeat:no-repeat; + background-position:right; + color:#7C5936; + font-size: 8pt; +} + + +div.summary +{ + float: right; + font-size: 8pt; + padding-right: 5px; + width: 50%; + text-align: right; +} + +div.summary a +{ + white-space: nowrap; +} + +table.classindex +{ + margin: 10px; + white-space: nowrap; + margin-left: 3%; + margin-right: 3%; + width: 94%; + border: 0; + border-spacing: 0; + padding: 0; +} + +div.ingroups +{ + font-size: 8pt; + width: 50%; + text-align: left; +} + +div.ingroups a +{ + white-space: nowrap; +} + +div.header +{ + background-image:url('nav_h.png'); + background-repeat:repeat-x; + background-color: #FCFAF9; + margin: 0px; + border-bottom: 1px solid #E5D5C4; +} + +div.headertitle +{ + padding: 5px 5px 5px 10px; +} + +.PageDocRTL-title div.headertitle { + text-align: right; + direction: rtl; +} + +dl { + padding: 0 0 0 0; +} + +/* dl.note, dl.warning, dl.attention, dl.pre, dl.post, dl.invariant, dl.deprecated, dl.todo, dl.test, dl.bug, dl.examples */ +dl.section { + margin-left: 0px; + padding-left: 0px; +} + +dl.section.DocNodeRTL { + margin-right: 0px; + padding-right: 0px; +} + +dl.note { + margin-left: -7px; + padding-left: 3px; + border-left: 4px solid; + border-color: #D0C000; +} + +dl.note.DocNodeRTL { + margin-left: 0; + padding-left: 0; + border-left: 0; + margin-right: -7px; + padding-right: 3px; + border-right: 4px solid; + border-color: #D0C000; +} + +dl.warning, dl.attention { + margin-left: -7px; + padding-left: 3px; + border-left: 4px solid; + border-color: #FF0000; +} + +dl.warning.DocNodeRTL, dl.attention.DocNodeRTL { + margin-left: 0; + padding-left: 0; + border-left: 0; + margin-right: -7px; + padding-right: 3px; + border-right: 4px solid; + border-color: #FF0000; +} + +dl.pre, dl.post, dl.invariant { + margin-left: -7px; + padding-left: 3px; + border-left: 4px solid; + border-color: #00D000; +} + +dl.pre.DocNodeRTL, dl.post.DocNodeRTL, dl.invariant.DocNodeRTL { + margin-left: 0; + padding-left: 0; + border-left: 0; + margin-right: -7px; + padding-right: 3px; + border-right: 4px solid; + border-color: #00D000; +} + +dl.deprecated { + margin-left: -7px; + padding-left: 3px; + border-left: 4px solid; + border-color: #505050; +} + +dl.deprecated.DocNodeRTL { + margin-left: 0; + padding-left: 0; + border-left: 0; + margin-right: -7px; + padding-right: 3px; + border-right: 4px solid; + border-color: #505050; +} + +dl.todo { + margin-left: -7px; + padding-left: 3px; + border-left: 4px solid; + border-color: #00C0E0; +} + +dl.todo.DocNodeRTL { + margin-left: 0; + padding-left: 0; + border-left: 0; + margin-right: -7px; + padding-right: 3px; + border-right: 4px solid; + border-color: #00C0E0; +} + +dl.test { + margin-left: -7px; + padding-left: 3px; + border-left: 4px solid; + border-color: #3030E0; +} + +dl.test.DocNodeRTL { + margin-left: 0; + padding-left: 0; + border-left: 0; + margin-right: -7px; + padding-right: 3px; + border-right: 4px solid; + border-color: #3030E0; +} + +dl.bug { + margin-left: -7px; + padding-left: 3px; + border-left: 4px solid; + border-color: #C08050; +} + +dl.bug.DocNodeRTL { + margin-left: 0; + padding-left: 0; + border-left: 0; + margin-right: -7px; + padding-right: 3px; + border-right: 4px solid; + border-color: #C08050; +} + +dl.section dd { + margin-bottom: 6px; +} + + +#projectlogo +{ + text-align: center; + vertical-align: bottom; + border-collapse: separate; +} + +#projectlogo img +{ + border: 0px none; +} + +#projectalign +{ + vertical-align: middle; +} + +#projectname +{ + font: 200% Tahoma, Arial,sans-serif; + margin: 0px; + padding: 2px 0px; +} + +#projectbrief +{ + font: 90% Tahoma, Arial,sans-serif; + margin: 0px; + padding: 0px; +} + +#projectnumber +{ + font: 50% Tahoma, Arial,sans-serif; + margin: 0px; + padding: 0px; +} + +#titlearea +{ + padding: 0px; + margin: 0px; + width: 100%; + border-bottom: 1px solid #B48453; +} + +.image +{ + text-align: left; +} + +.dotgraph +{ + text-align: center; +} + +.mscgraph +{ + text-align: center; +} + +.plantumlgraph +{ + text-align: center; +} + +.diagraph +{ + text-align: center; +} + +.caption +{ + font-weight: bold; +} + +div.zoom +{ + border: 1px solid #CEAF90; +} + +dl.citelist { + margin-bottom:50px; +} + +dl.citelist dt { + color:#755433; + float:left; + font-weight:bold; + margin-right:10px; + padding:5px; + text-align:right; + width:52px; +} + +dl.citelist dd { + margin:2px 0 2px 72px; + padding:5px 0; +} + +div.toc { + padding: 14px 25px; + background-color: #FAF7F4; + border: 1px solid #EEE3D8; + border-radius: 7px 7px 7px 7px; + float: right; + height: auto; + margin: 0 8px 10px 10px; + width: 200px; +} + +.PageDocRTL-title div.toc { + float: left !important; + text-align: right; +} + +div.toc li { + background: url("bdwn.png") no-repeat scroll 0 5px transparent; + font: 10px/1.2 Verdana,DejaVu Sans,Geneva,sans-serif; + margin-top: 5px; + padding-left: 10px; + padding-top: 2px; +} + +.PageDocRTL-title div.toc li { + background-position-x: right !important; + padding-left: 0 !important; + padding-right: 10px; +} + +div.toc h3 { + font: bold 12px/1.2 Arial,FreeSans,sans-serif; + color: #A27446; + border-bottom: 0 none; + margin: 0; +} + +div.toc ul { + list-style: none outside none; + border: medium none; + padding: 0px; +} + +div.toc li.level1 { + margin-left: 0px; +} + +div.toc li.level2 { + margin-left: 15px; +} + +div.toc li.level3 { + margin-left: 30px; +} + +div.toc li.level4 { + margin-left: 45px; +} + +span.emoji { + /* font family used at the site: https://unicode.org/emoji/charts/full-emoji-list.html + * font-family: "Noto Color Emoji", "Apple Color Emoji", "Segoe UI Emoji", Times, Symbola, Aegyptus, Code2000, Code2001, Code2002, Musica, serif, LastResort; + */ +} + +.PageDocRTL-title div.toc li.level1 { + margin-left: 0 !important; + margin-right: 0; +} + +.PageDocRTL-title div.toc li.level2 { + margin-left: 0 !important; + margin-right: 15px; +} + +.PageDocRTL-title div.toc li.level3 { + margin-left: 0 !important; + margin-right: 30px; +} + +.PageDocRTL-title div.toc li.level4 { + margin-left: 0 !important; + margin-right: 45px; +} + +.inherit_header { + font-weight: bold; + color: gray; + cursor: pointer; + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.inherit_header td { + padding: 6px 0px 2px 5px; +} + +.inherit { + display: none; +} + +tr.heading h2 { + margin-top: 12px; + margin-bottom: 4px; +} + +/* tooltip related style info */ + +.ttc { + position: absolute; + display: none; +} + +#powerTip { + cursor: default; + white-space: nowrap; + background-color: white; + border: 1px solid gray; + border-radius: 4px 4px 4px 4px; + box-shadow: 1px 1px 7px gray; + display: none; + font-size: smaller; + max-width: 80%; + opacity: 0.9; + padding: 1ex 1em 1em; + position: absolute; + z-index: 2147483647; +} + +#powerTip div.ttdoc { + color: grey; + font-style: italic; +} + +#powerTip div.ttname a { + font-weight: bold; +} + +#powerTip div.ttname { + font-weight: bold; +} + +#powerTip div.ttdeci { + color: #006318; +} + +#powerTip div { + margin: 0px; + padding: 0px; + font: 12px/16px Roboto,sans-serif; +} + +#powerTip:before, #powerTip:after { + content: ""; + position: absolute; + margin: 0px; +} + +#powerTip.n:after, #powerTip.n:before, +#powerTip.s:after, #powerTip.s:before, +#powerTip.w:after, #powerTip.w:before, +#powerTip.e:after, #powerTip.e:before, +#powerTip.ne:after, #powerTip.ne:before, +#powerTip.se:after, #powerTip.se:before, +#powerTip.nw:after, #powerTip.nw:before, +#powerTip.sw:after, #powerTip.sw:before { + border: solid transparent; + content: " "; + height: 0; + width: 0; + position: absolute; +} + +#powerTip.n:after, #powerTip.s:after, +#powerTip.w:after, #powerTip.e:after, +#powerTip.nw:after, #powerTip.ne:after, +#powerTip.sw:after, #powerTip.se:after { + border-color: rgba(255, 255, 255, 0); +} + +#powerTip.n:before, #powerTip.s:before, +#powerTip.w:before, #powerTip.e:before, +#powerTip.nw:before, #powerTip.ne:before, +#powerTip.sw:before, #powerTip.se:before { + border-color: rgba(128, 128, 128, 0); +} + +#powerTip.n:after, #powerTip.n:before, +#powerTip.ne:after, #powerTip.ne:before, +#powerTip.nw:after, #powerTip.nw:before { + top: 100%; +} + +#powerTip.n:after, #powerTip.ne:after, #powerTip.nw:after { + border-top-color: #FFFFFF; + border-width: 10px; + margin: 0px -10px; +} +#powerTip.n:before { + border-top-color: #808080; + border-width: 11px; + margin: 0px -11px; +} +#powerTip.n:after, #powerTip.n:before { + left: 50%; +} + +#powerTip.nw:after, #powerTip.nw:before { + right: 14px; +} + +#powerTip.ne:after, #powerTip.ne:before { + left: 14px; +} + +#powerTip.s:after, #powerTip.s:before, +#powerTip.se:after, #powerTip.se:before, +#powerTip.sw:after, #powerTip.sw:before { + bottom: 100%; +} + +#powerTip.s:after, #powerTip.se:after, #powerTip.sw:after { + border-bottom-color: #FFFFFF; + border-width: 10px; + margin: 0px -10px; +} + +#powerTip.s:before, #powerTip.se:before, #powerTip.sw:before { + border-bottom-color: #808080; + border-width: 11px; + margin: 0px -11px; +} + +#powerTip.s:after, #powerTip.s:before { + left: 50%; +} + +#powerTip.sw:after, #powerTip.sw:before { + right: 14px; +} + +#powerTip.se:after, #powerTip.se:before { + left: 14px; +} + +#powerTip.e:after, #powerTip.e:before { + left: 100%; +} +#powerTip.e:after { + border-left-color: #FFFFFF; + border-width: 10px; + top: 50%; + margin-top: -10px; +} +#powerTip.e:before { + border-left-color: #808080; + border-width: 11px; + top: 50%; + margin-top: -11px; +} + +#powerTip.w:after, #powerTip.w:before { + right: 100%; +} +#powerTip.w:after { + border-right-color: #FFFFFF; + border-width: 10px; + top: 50%; + margin-top: -10px; +} +#powerTip.w:before { + border-right-color: #808080; + border-width: 11px; + top: 50%; + margin-top: -11px; +} + +@media print +{ + #top { display: none; } + #side-nav { display: none; } + #nav-path { display: none; } + body { overflow:visible; } + h1, h2, h3, h4, h5, h6 { page-break-after: avoid; } + .summary { display: none; } + .memitem { page-break-inside: avoid; } + #doc-content + { + margin-left:0 !important; + height:auto !important; + width:auto !important; + overflow:inherit; + display:inline; + } +} + +/* @group Markdown */ + +table.markdownTable { + border-collapse:collapse; + margin-top: 4px; + margin-bottom: 4px; +} + +table.markdownTable td, table.markdownTable th { + border: 1px solid #684A2D; + padding: 3px 7px 2px; +} + +table.markdownTable tr { +} + +th.markdownTableHeadLeft, th.markdownTableHeadRight, th.markdownTableHeadCenter, th.markdownTableHeadNone { + background-color: #7F5B37; + color: #FFFFFF; + font-size: 110%; + padding-bottom: 4px; + padding-top: 5px; +} + +th.markdownTableHeadLeft, td.markdownTableBodyLeft { + text-align: left +} + +th.markdownTableHeadRight, td.markdownTableBodyRight { + text-align: right +} + +th.markdownTableHeadCenter, td.markdownTableBodyCenter { + text-align: center +} + +.DocNodeRTL { + text-align: right; + direction: rtl; +} + +.DocNodeLTR { + text-align: left; + direction: ltr; +} + +table.DocNodeRTL { + width: auto; + margin-right: 0; + margin-left: auto; +} + +table.DocNodeLTR { + width: auto; + margin-right: auto; + margin-left: 0; +} + +tt, code, kbd, samp +{ + display: inline-block; + direction:ltr; +} +/* @end */ + +u { + text-decoration: underline; +} +