diff --git a/NFPackCreator/AssetBuild/CubeTest/cubemaps/test_cmback.png b/NFPackCreator/AssetBuild/CubeTest/cubemaps/test_cmback.png deleted file mode 100644 index c23a742..0000000 Binary files a/NFPackCreator/AssetBuild/CubeTest/cubemaps/test_cmback.png and /dev/null differ diff --git a/NFPackCreator/AssetBuild/CubeTest/cubemaps/test_cmbottom.png b/NFPackCreator/AssetBuild/CubeTest/cubemaps/test_cmbottom.png deleted file mode 100644 index 67eda80..0000000 Binary files a/NFPackCreator/AssetBuild/CubeTest/cubemaps/test_cmbottom.png and /dev/null differ diff --git a/NFPackCreator/AssetBuild/CubeTest/cubemaps/test_cmfront.png b/NFPackCreator/AssetBuild/CubeTest/cubemaps/test_cmfront.png deleted file mode 100644 index b1000fc..0000000 Binary files a/NFPackCreator/AssetBuild/CubeTest/cubemaps/test_cmfront.png and /dev/null differ diff --git a/NFPackCreator/AssetBuild/CubeTest/cubemaps/test_cmleft.png b/NFPackCreator/AssetBuild/CubeTest/cubemaps/test_cmleft.png deleted file mode 100644 index 61537b0..0000000 Binary files a/NFPackCreator/AssetBuild/CubeTest/cubemaps/test_cmleft.png and /dev/null differ diff --git a/NFPackCreator/AssetBuild/CubeTest/cubemaps/test_cmright.png b/NFPackCreator/AssetBuild/CubeTest/cubemaps/test_cmright.png deleted file mode 100644 index 6337433..0000000 Binary files a/NFPackCreator/AssetBuild/CubeTest/cubemaps/test_cmright.png and /dev/null differ diff --git a/NFPackCreator/AssetBuild/CubeTest/cubemaps/test_cmtop.png b/NFPackCreator/AssetBuild/CubeTest/cubemaps/test_cmtop.png deleted file mode 100644 index 45d70ed..0000000 Binary files a/NFPackCreator/AssetBuild/CubeTest/cubemaps/test_cmtop.png and /dev/null differ diff --git a/NFPackCreator/AssetBuild/base/buttons/default_buttonhover.png b/NFPackCreator/AssetBuild/base/buttons/default_buttonhover.png new file mode 100644 index 0000000..87cb4c6 Binary files /dev/null and b/NFPackCreator/AssetBuild/base/buttons/default_buttonhover.png differ diff --git a/NFPackCreator/AssetBuild/base/buttons/default_buttonidle.png b/NFPackCreator/AssetBuild/base/buttons/default_buttonidle.png new file mode 100644 index 0000000..7b11422 Binary files /dev/null and b/NFPackCreator/AssetBuild/base/buttons/default_buttonidle.png differ diff --git a/NFPackCreator/AssetBuild/base/buttons/default_buttonpressed.png b/NFPackCreator/AssetBuild/base/buttons/default_buttonpressed.png new file mode 100644 index 0000000..3b2a59c Binary files /dev/null and b/NFPackCreator/AssetBuild/base/buttons/default_buttonpressed.png differ diff --git a/NFPackCreator/AssetBuild/base/cubemaps/default_cmback.jpg b/NFPackCreator/AssetBuild/base/cubemaps/default_cmback.jpg new file mode 100644 index 0000000..470a679 Binary files /dev/null and b/NFPackCreator/AssetBuild/base/cubemaps/default_cmback.jpg differ diff --git a/NFPackCreator/AssetBuild/base/cubemaps/default_cmbottom.jpg b/NFPackCreator/AssetBuild/base/cubemaps/default_cmbottom.jpg new file mode 100644 index 0000000..893f394 Binary files /dev/null and b/NFPackCreator/AssetBuild/base/cubemaps/default_cmbottom.jpg differ diff --git a/NFPackCreator/AssetBuild/base/cubemaps/default_cmfront.jpg b/NFPackCreator/AssetBuild/base/cubemaps/default_cmfront.jpg new file mode 100644 index 0000000..4e17b77 Binary files /dev/null and b/NFPackCreator/AssetBuild/base/cubemaps/default_cmfront.jpg differ diff --git a/NFPackCreator/AssetBuild/base/cubemaps/default_cmleft.jpg b/NFPackCreator/AssetBuild/base/cubemaps/default_cmleft.jpg new file mode 100644 index 0000000..5750b91 Binary files /dev/null and b/NFPackCreator/AssetBuild/base/cubemaps/default_cmleft.jpg differ diff --git a/NFPackCreator/AssetBuild/base/cubemaps/default_cmright.jpg b/NFPackCreator/AssetBuild/base/cubemaps/default_cmright.jpg new file mode 100644 index 0000000..8963037 Binary files /dev/null and b/NFPackCreator/AssetBuild/base/cubemaps/default_cmright.jpg differ diff --git a/NFPackCreator/AssetBuild/base/cubemaps/default_cmtop.jpg b/NFPackCreator/AssetBuild/base/cubemaps/default_cmtop.jpg new file mode 100644 index 0000000..4db3c2a Binary files /dev/null and b/NFPackCreator/AssetBuild/base/cubemaps/default_cmtop.jpg differ diff --git a/NFPackCreator/AssetBuild/base/shaders/cubemapFragment.shader b/NFPackCreator/AssetBuild/base/shaders/cubemapFragment.shader index ca2d0ee..3f51c14 100644 --- a/NFPackCreator/AssetBuild/base/shaders/cubemapFragment.shader +++ b/NFPackCreator/AssetBuild/base/shaders/cubemapFragment.shader @@ -9,7 +9,7 @@ out vec4 color; void main() { vec3 tc; tc = vec3(-texCoord.x, texCoord.y, texCoord.z); - if (texCoord.y > 0.99 || texCoord.y < -0.99) { + if (texCoord.y > 0.999999 || texCoord.y < -0.999999) { tc = vec3(texCoord.x, texCoord.y, texCoord.z); } color = texture(cm, tc); diff --git a/NFPackCreator/src/main.cpp b/NFPackCreator/src/main.cpp index cf4411b..e651488 100644 --- a/NFPackCreator/src/main.cpp +++ b/NFPackCreator/src/main.cpp @@ -91,7 +91,7 @@ int main(int argc, char* argv[]) { } std::set extensions; - extensions.insert({ "obj", "png", "shader", "ttf" }); + extensions.insert({ "obj", "png", "jpg", "shader", "ttf" }); unsigned int dirCount = 0; const std::filesystem::path workingDir = std::filesystem::current_path(); diff --git a/NothinFancy/NothinFancy.vcxproj b/NothinFancy/NothinFancy.vcxproj index 57d2fde..051b066 100644 --- a/NothinFancy/NothinFancy.vcxproj +++ b/NothinFancy/NothinFancy.vcxproj @@ -200,6 +200,7 @@ + @@ -218,6 +219,7 @@ + diff --git a/NothinFancy/NothinFancy.vcxproj.filters b/NothinFancy/NothinFancy.vcxproj.filters index 79a654f..d7f7da5 100644 --- a/NothinFancy/NothinFancy.vcxproj.filters +++ b/NothinFancy/NothinFancy.vcxproj.filters @@ -75,6 +75,9 @@ Source Files + + Source Files + @@ -149,6 +152,9 @@ Header Files + + Header Files + diff --git a/NothinFancy/src/Application.cpp b/NothinFancy/src/Application.cpp index c6d9255..d1aa2b2 100644 --- a/NothinFancy/src/Application.cpp +++ b/NothinFancy/src/Application.cpp @@ -138,22 +138,27 @@ namespace nf { } bool Application::isKeyHeld(unsigned int code) { - if (code < 164) { - return m_keys[code].first; - } + if (code > 7 && code < 164) + return GetKeyState(code) & 0x8000; return false; } bool Application::isKeyPressed(unsigned int code) { - if (code < 164) { - if (m_keys[code].second) { - m_keys[code].second = false; + if (code > 7 && code < 164) { + if (m_keysPressed[code]) { + m_keysPressed[code] = false; return true; } } return false; } + bool Application::isMouse(unsigned int code) { + if (code < 7) + return GetKeyState(code) & 0x8000; + return false; + } + void Application::trackMouse(bool track) { m_trackingMouse = track; if (m_trackingMouse == true) @@ -167,6 +172,10 @@ namespace nf { m_mouseDiffY = 0; } + Vec2 Application::getMousePos() { + return Vec2(m_mouseX, m_mouseY); + } + Application* Application::getApp() { return currentApp; } @@ -284,10 +293,12 @@ namespace nf { m_fpsDuration = m_fpsClock2 - m_fpsClock1; if (m_fpsDuration.count() >= 0.2) { m_FPS = (int)std::round(1.0 / m_deltaTime); +#ifdef _DEBUG static int i = 0; i++; if (i % 5 == 0) Log("FPS: " + std::to_string(m_FPS)); +#endif m_fpsClock1 = std::chrono::steady_clock::now(); } } @@ -347,14 +358,12 @@ namespace nf { } case WM_KEYDOWN: { if (wParam < 164 && !(lParam & (1 << 30))) - app->m_keys[wParam].first = app->m_keys[wParam].second = true; - + app->m_keysPressed[wParam] = true; return 0; } case WM_KEYUP: { if (wParam < 164) - app->m_keys[wParam].first = app->m_keys[wParam].second = false; - + app->m_keysPressed[wParam] = false; return 0; } case WM_SETCURSOR: { diff --git a/NothinFancy/src/Assets.cpp b/NothinFancy/src/Assets.cpp index 52fcee1..df1f81a 100644 --- a/NothinFancy/src/Assets.cpp +++ b/NothinFancy/src/Assets.cpp @@ -28,11 +28,15 @@ namespace nf { delete[] rightData; } - AShader::~AShader() { + AFont::~AFont() { } - AFont::~AFont() { + AButton::~AButton() { + + } + + AShader::~AShader() { } @@ -45,7 +49,9 @@ namespace nf { std::string packContents = readFile(path); std::string packContentsOBJ = packContents; std::unordered_map cubemaps; + std::unordered_map buttons; unsigned int cubemapCount = 0; + unsigned int buttonCount = 0; while (packContents.size()) { unsigned int startingPos = packContents.find_first_of("#NFASSET ") + 9; packContents = packContents.substr(9); @@ -68,13 +74,12 @@ namespace nf { if (extension == "obj") continue; - if (extension == "png") { + if (extension == "png" || extension == "jpg") { if (assetName.find("_cmfront") != std::string::npos || assetName.find("_cmback") != std::string::npos || assetName.find("_cmtop") != std::string::npos || assetName.find("_cmbottom") != std::string::npos || assetName.find("_cmleft") != std::string::npos || assetName.find("_cmright") != std::string::npos) { std::string cmName = assetName.substr(0, assetName.find('_')); ACubemap* curr; if (cubemaps.find(cmName) == cubemaps.end()) { cubemaps[cmName] = new ACubemap; - cubemaps[cmName]->numImages = 0; } curr = cubemaps[cmName]; if (curr->numImages == 6) @@ -111,13 +116,45 @@ namespace nf { } curr->numImages++; - if (curr->numImages == 6) { + if (curr->numImages == 6) m_assets[cmName + (std::string)".cm"] = curr; - } cubemapCount++; continue; } + else if (assetName.find("_buttonidle") != std::string::npos || assetName.find("_buttonhover") != std::string::npos || assetName.find("_buttonpressed") != std::string::npos) { + std::string buttonName = assetName.substr(0, assetName.find('_')); + AButton* curr; + if (buttons.find(buttonName) == buttons.end()) { + buttons[buttonName] = new AButton; + buttons[buttonName]->numImages = 0; + } + curr = buttons[buttonName]; + if (curr->numImages == 3) + Error("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); + curr->idleTex.size = assetSize; + } + if (assetName.find("_buttonhover") != std::string::npos) { + curr->hoverTex.data = new char[assetSize]; + std::memcpy(curr->hoverTex.data, &assetContents[0], assetSize); + curr->hoverTex.size = assetSize; + } + if (assetName.find("_buttonpressed") != std::string::npos) { + curr->pressedTex.data = new char[assetSize]; + std::memcpy(curr->pressedTex.data, &assetContents[0], assetSize); + curr->pressedTex.size = assetSize; + } + curr->numImages++; + + if (curr->numImages == 3) + m_assets[buttonName + (std::string)".button"] = curr; + + buttonCount++; + continue; + } ATexture* texture = new ATexture; texture->data = new char[assetSize]; std::memcpy(texture->data, &assetContents[0], assetSize); @@ -149,6 +186,8 @@ namespace nf { } if (cubemapCount % 6 != 0) Error("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)"\"!"); while (packContentsOBJ.size()) { unsigned int startingPos = packContentsOBJ.find_first_of("#NFASSET ") + 9; @@ -229,5 +268,9 @@ namespace nf { ATexture* BaseAssets::logo; - AFont* BaseAssets::defaultFont; + ACubemap* BaseAssets::cubemap; + + AFont* BaseAssets::font; + + AButton* BaseAssets::button; } \ No newline at end of file diff --git a/NothinFancy/src/Renderer/Camera.cpp b/NothinFancy/src/Renderer/Camera.cpp index 6e2e542..e1cf0f6 100644 --- a/NothinFancy/src/Renderer/Camera.cpp +++ b/NothinFancy/src/Renderer/Camera.cpp @@ -76,7 +76,7 @@ namespace nf { switch (m_type) { case Type::UI: { - view = glm::mat4(1.0); + break; } case Type::FIRST_PERSON: { @@ -91,15 +91,6 @@ namespace nf { m_pitch = 89.0f; if (m_pitch < -89.0f) m_pitch = -89.0f; - glm::vec3 rotation; - rotation.x = std::cos(glm::radians(m_yaw)) * std::cos(glm::radians(m_pitch)); - rotation.y = std::sin(glm::radians(m_pitch)); - rotation.z = std::sin(glm::radians(m_yaw)) * std::cos(glm::radians(m_pitch)); - rotation = glm::normalize(rotation); - m_front = { rotation.x, rotation.y, rotation.z }; - glm::vec3 position(m_position.x, m_position.y, m_position.z); - glm::vec3 up(0.0, 1.0, 0.0); - view = glm::lookAt(position, position + rotation, up); break; } case Type::ORBIT: { @@ -113,6 +104,16 @@ namespace nf { } glm::vec3 pos(m_position.x, m_position.y, m_position.z); entityShader->setUniform("camera.pos", pos); + + glm::vec3 rotation; + rotation.x = std::cos(glm::radians(m_yaw)) * std::cos(glm::radians(m_pitch)); + rotation.y = std::sin(glm::radians(m_pitch)); + rotation.z = std::sin(glm::radians(m_yaw)) * std::cos(glm::radians(m_pitch)); + rotation = glm::normalize(rotation); + m_front = { rotation.x, rotation.y, rotation.z }; + glm::vec3 position(m_position.x, m_position.y, m_position.z); + glm::vec3 up(0.0, 1.0, 0.0); + view = glm::lookAt(position, position + rotation, up); entityShader->setUniform("view", view); glm::mat4 cubemapView = glm::mat4(glm::mat3(view)); diff --git a/NothinFancy/src/Renderer/Drawable/Button.cpp b/NothinFancy/src/Renderer/Drawable/Button.cpp new file mode 100644 index 0000000..529033c --- /dev/null +++ b/NothinFancy/src/Renderer/Drawable/Button.cpp @@ -0,0 +1,136 @@ +#include "Button.h" + +#include "GL/glew.h" + +#include "Application.h" +#include "Input.h" +#include "Texture.h" +#include "Shader.h" + +namespace nf { + Button::Button() : + m_idleTexture(nullptr), + m_hoverTexture(nullptr), + m_pressedTexture(nullptr), + m_currentTexture(nullptr), + m_scale(1.0f), + m_opacity(1.0f), + m_clicked(false), + m_triggered(false) + { + + } + + void Button::create(const Vec2& position, std::string string, Asset* buttonAsset, double scale, double opacity) { + m_constructed = true; + m_position = position; + m_string = string; + if (m_string.size()) { + m_text.create(m_string, Vec2(0.0, 0.0)); + m_text.centered(true); + } + m_scale = (float)scale * 0.3f; + m_opacity = (float)opacity; + m_text.setOpacity(m_opacity); + AButton* button; + if ((button = dynamic_cast(buttonAsset)) == nullptr) + Error("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!"); + } + float tc[3][4] = { + 0.0, 1.0, + 0.0, 0.0, + 1.0, 0.0, + 0.0, 1.0, + 1.0, 0.0, + 1.0, 1.0 + }; + m_vao = new VertexArray; + m_vao->addBuffer(nullptr, 0); + m_vao->push(2); + m_vao->finishBufferLayout(); + m_vao->addBuffer(tc, sizeof(tc)); + m_vao->push(2); + m_vao->finishBufferLayout(); + + Application::getApp()->getCurrentState()->m_nfObjects.push_back(this); + } + + const char* Button::identity() { + return "button"; + } + + void Button::render(Shader* shader, unsigned int windowWidth, unsigned int windowHeight, Application* app, Shader* textShader) { + float posX = (float)m_position.x * windowWidth, posY = (float)m_position.y * windowHeight; + float scale = windowWidth / 5.0f; + + Vec2 texDim = m_idleTexture->getDimensions(); + float height = scale * m_scale; + float width = ((float)texDim.x / (float)texDim.y) * scale * m_scale; + if (m_centeredX) + posX = ((float)windowWidth - width) / 2; + if (m_centeredY) + posY = ((float)windowHeight - height) / 2; + + m_currentTexture = m_idleTexture; + Vec2 mousePos = app->getMousePos(); + m_triggered = false; + if (mousePos.x >= posX && mousePos.x <= posX + width && mousePos.y <= windowHeight - posY && mousePos.y >= (windowHeight - posY) - height) { + m_currentTexture = m_hoverTexture; + if (app->isMouse(NFI_LEFTMOUSE)) + m_clicked = true; + else if (m_clicked) { + m_triggered = true; + m_clicked = false; + } + } + else m_clicked = false; + + if (m_clicked) + m_currentTexture = m_pressedTexture; + float vb[] = { + posX, posY + height, + posX, posY, + posX + width, posY, + posX, posY + height, + posX + width, posY, + posX + width, posY + height + }; + + m_currentTexture->bind(); + m_vao->setBufferData(0, vb, sizeof(vb)); + shader->setUniform("opacity", m_opacity); + glDrawArrays(GL_TRIANGLES, 0, 6); + + if (m_string.size()) { + Vec2 pos = Vec2(posX, posY); + m_text.render(textShader, windowWidth, windowHeight, true, width, height, pos); + } + } + + bool Button::isClicked() { + return m_triggered; + } + + void Button::destroy() { + m_constructed = false; + m_clicked = false; + m_position = Vec2(0.0); + m_centeredX = m_centeredY = false; + if (!m_idleTexture->isBaseAsset()) + delete m_idleTexture; + if (!m_hoverTexture->isBaseAsset()) + delete m_hoverTexture; + if (!m_pressedTexture->isBaseAsset()) + delete m_pressedTexture; + delete m_vao; + } + + Button::~Button() { + + } +} \ No newline at end of file diff --git a/NothinFancy/src/Renderer/Drawable/Cubemap.cpp b/NothinFancy/src/Renderer/Drawable/Cubemap.cpp index ab354d6..3c25c6a 100644 --- a/NothinFancy/src/Renderer/Drawable/Cubemap.cpp +++ b/NothinFancy/src/Renderer/Drawable/Cubemap.cpp @@ -5,6 +5,7 @@ #include "stb_image.h" #include "Application.h" +#include "Shader.h" #include "Assets.h" namespace nf { @@ -19,6 +20,7 @@ namespace nf { m_constructed = true; ACubemap& cm = *(ACubemap*)cubemapAsset; glGenTextures(1, &m_id); + glActiveTexture(GL_TEXTURE12); glBindTexture(GL_TEXTURE_CUBE_MAP, m_id); struct CMFace { CMFace(unsigned char* d, unsigned int w, unsigned int h, unsigned int nc) : @@ -61,6 +63,8 @@ namespace nf { glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + glBindTexture(GL_TEXTURE_CUBE_MAP, 0); + glActiveTexture(GL_TEXTURE0); float vb[] = { -1.0f, 1.0f, -1.0f, @@ -117,8 +121,10 @@ namespace nf { return m_constructed; } - void Cubemap::render() { + void Cubemap::render(Shader* shader) { m_vao->bind(); + glActiveTexture(GL_TEXTURE12); + shader->setUniform("cm", 12); glBindTexture(GL_TEXTURE_CUBE_MAP, m_id); glDepthFunc(GL_LEQUAL); glDrawArrays(GL_TRIANGLES, 0, 36); diff --git a/NothinFancy/src/Renderer/Drawable/Entity.cpp b/NothinFancy/src/Renderer/Drawable/Entity.cpp index fdb6028..0a222a6 100644 --- a/NothinFancy/src/Renderer/Drawable/Entity.cpp +++ b/NothinFancy/src/Renderer/Drawable/Entity.cpp @@ -19,16 +19,18 @@ namespace nf { void Entity::create(Asset* modelAsset) { m_constructed = true; - AModel& model = *(AModel*)modelAsset; - if (model.alreadyLoaded) { - m_model = model.loadedModel; + AModel* model; + if ((model = dynamic_cast(modelAsset)) == nullptr) + Error("Non-model asset passed to Entity::create!"); + if (model->alreadyLoaded) { + m_model = model->loadedModel; } else { - m_model = new Model(&model); - model.alreadyLoaded = true; - model.loadedModel = m_model; + m_model = new Model(model); + model->alreadyLoaded = true; + model->loadedModel = m_model; } - m_model->setBaseAsset(model.isBaseAsset); + Application::getApp()->getCurrentState()->m_nfObjects.push_back(this); } diff --git a/NothinFancy/src/Renderer/Drawable/Model.cpp b/NothinFancy/src/Renderer/Drawable/Model.cpp index 34b4681..7249189 100644 --- a/NothinFancy/src/Renderer/Drawable/Model.cpp +++ b/NothinFancy/src/Renderer/Drawable/Model.cpp @@ -24,12 +24,18 @@ namespace nf { m_ib = new IndexBuffer(ib, ibCount); if (diffTex) { m_hasDiffuse = true; - m_diffuseTexture = new Texture(diffTex); + if (diffTex->alreadyLoaded) + m_diffuseTexture = diffTex->loadedTexture; + else + m_diffuseTexture = new Texture(diffTex); } m_diffColor = diffColor; if (specTex) { m_hasSpecular = true; - m_specularTexture = new Texture(specTex); + if (specTex->alreadyLoaded) + m_specularTexture = specTex->loadedTexture; + else + m_specularTexture = new Texture(specTex); } m_shininess = shininess; } @@ -63,7 +69,7 @@ namespace nf { } Model::Model(AModel* model) : - m_base(false) + m_base(model->isBaseAsset) { std::string obj = model->data; unsigned int startMtlPos = obj.find("newmtl"); @@ -281,10 +287,6 @@ namespace nf { } } - void Model::setBaseAsset(bool isBase) { - m_base = isBase; - } - bool Model::isBaseAsset() { return m_base; } diff --git a/NothinFancy/src/Renderer/Drawable/Text.cpp b/NothinFancy/src/Renderer/Drawable/Text.cpp index 779a9a6..8ae9fa4 100644 --- a/NothinFancy/src/Renderer/Drawable/Text.cpp +++ b/NothinFancy/src/Renderer/Drawable/Text.cpp @@ -92,11 +92,12 @@ namespace nf { return "text"; } - void Text::render(Shader* shader, unsigned int windowWidth, unsigned int windowHeight) { + void Text::render(Shader* shader, unsigned int windowWidth, unsigned int windowHeight, bool onButton, float buttonWidth, float buttonHeight, const Vec2& buttonPos) { float scale = windowWidth / 4000.0f; - m_vao->bind(); - std::string::const_iterator si; + if (onButton) + scale *= buttonHeight / 100.0f; float currX = (float)m_position.x * windowWidth, currY = (float)m_position.y * windowHeight; + std::string::const_iterator si; if (m_centeredX || m_centeredY) { float textWidth = 0.0f; float textHeight = 0.0f; @@ -110,7 +111,23 @@ namespace nf { currX = ((float)windowWidth - textWidth) / 2; if (m_centeredY) currY = ((float)windowHeight - textHeight) / 2; + + if (onButton) { + while (textWidth > buttonWidth - 20) { + scale -= 0.01f; + textHeight = textWidth = 0.0f; + for (si = m_string.begin(); si != m_string.end(); si++) { + Character& c = m_font->m_characters[*si]; + textWidth += (c.advance >> 6) * scale * m_scale; + if (c.size.y >= textHeight) + textHeight = (float)c.size.y * scale * m_scale; + } + } + currX = (((float)buttonWidth - textWidth) / 2) + (float)buttonPos.x; + currY = (((float)buttonHeight - textHeight) / 2) + (float)buttonPos.y; + } } + glm::vec3 color = { m_color.x, m_color.y, m_color.z }; shader->setUniform("textColor", color); shader->setUniform("opacity", m_opacity); @@ -120,7 +137,7 @@ namespace nf { float y = currY - float(c.size.y - c.bearing.y) * scale * m_scale; float w = (float)c.size.x * scale * m_scale; float h = (float)c.size.y * scale * m_scale; - float vb[3][4] = { + float vb[] = { x, y + h, x, y, x + w, y, @@ -128,7 +145,7 @@ namespace nf { x + w, y, x + w, y + h }; - float tc[3][4] = { + float tc[] = { 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, @@ -138,6 +155,7 @@ namespace nf { }; glActiveTexture(GL_TEXTURE10); glBindTexture(GL_TEXTURE_2D, c.texID); + m_vao->bind(); m_vao->setBufferData(0, vb, sizeof(vb)); m_vao->setBufferData(1, tc, sizeof(tc)); shader->setUniform("text", 10); diff --git a/NothinFancy/src/Renderer/Drawable/UIElement.cpp b/NothinFancy/src/Renderer/Drawable/UIElement.cpp index c94a49d..77d7862 100644 --- a/NothinFancy/src/Renderer/Drawable/UIElement.cpp +++ b/NothinFancy/src/Renderer/Drawable/UIElement.cpp @@ -13,7 +13,7 @@ namespace nf { return "none"; } - void UIElement::setPosition(float x, float y) { + void UIElement::setPosition(double x, double y) { m_position = Vec2(x, y); } void UIElement::setPosition(const Vec2& position) { diff --git a/NothinFancy/src/Renderer/Drawable/UITexture.cpp b/NothinFancy/src/Renderer/Drawable/UITexture.cpp index 372bb5e..e148b1e 100644 --- a/NothinFancy/src/Renderer/Drawable/UITexture.cpp +++ b/NothinFancy/src/Renderer/Drawable/UITexture.cpp @@ -2,6 +2,7 @@ #include "GL/glew.h" +#include "Application.h" #include "Assets.h" #include "Texture.h" #include "Shader.h" @@ -17,7 +18,9 @@ namespace nf { void UITexture::create(Asset* textureAsset, const Vec2& position, double scale, double opacity) { m_constructed = true; - ATexture* tex = (ATexture*)textureAsset; + ATexture* tex; + if ((tex = dynamic_cast(textureAsset)) == nullptr) + Error("Non-texture asset passed to UITexture::create!"); m_position = position; m_scale = (float)scale; m_opacity = (float)opacity; @@ -28,13 +31,23 @@ namespace nf { m_texture = new Texture(tex); } + float tc[] = { + 0.0, 1.0, + 0.0, 0.0, + 1.0, 0.0, + 0.0, 1.0, + 1.0, 0.0, + 1.0, 1.0 + }; m_vao = new VertexArray; m_vao->addBuffer(nullptr, 0); m_vao->push(2); m_vao->finishBufferLayout(); - m_vao->addBuffer(nullptr, 0); + m_vao->addBuffer(tc, sizeof(tc)); m_vao->push(2); m_vao->finishBufferLayout(); + + Application::getApp()->getCurrentState()->m_nfObjects.push_back(this); } const char* UITexture::identity() { @@ -68,17 +81,9 @@ namespace nf { posX + width, posY, posX + width, posY + height }; - float tc[3][4] = { - 0.0, 1.0, - 0.0, 0.0, - 1.0, 0.0, - 0.0, 1.0, - 1.0, 0.0, - 1.0, 1.0 - }; + m_texture->bind(); m_vao->setBufferData(0, vb, sizeof(vb)); - m_vao->setBufferData(1, tc, sizeof(tc)); shader->setUniform("opacity", m_opacity); glDrawArrays(GL_TRIANGLES, 0, 6); } diff --git a/NothinFancy/src/Renderer/Renderer.cpp b/NothinFancy/src/Renderer/Renderer.cpp index 147e017..23b6de5 100644 --- a/NothinFancy/src/Renderer/Renderer.cpp +++ b/NothinFancy/src/Renderer/Renderer.cpp @@ -8,9 +8,9 @@ #include "Shader.h" #include "Light.h" #include "Entity.h" -#include "Model.h" #include "Cubemap.h" #include "UIElement.h" +#include "Button.h" #include "Camera.h" #include "Utility.h" @@ -67,31 +67,7 @@ namespace nf { glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glClearColor(0.0f, 0.0f, 0.0f, 1.0f); - m_baseAP.load("base.nfpack"); - const char* entityVertex = m_baseAP["entityVertex.shader"]->data; - const char* entityFragment = m_baseAP["entityFragment.shader"]->data; - m_entityShader = new Shader(entityVertex, entityFragment); - const char* textVertex = m_baseAP["textVertex.shader"]->data; - const char* textFragment = m_baseAP["textFragment.shader"]->data; - m_textShader = new Shader(textVertex, textFragment); - const char* uiTextureVertex = m_baseAP["uiTextureVertex.shader"]->data; - const char* uiTextureFragment = m_baseAP["uiTextureFragment.shader"]->data; - m_uiTextureShader = new Shader(uiTextureVertex, uiTextureFragment); - const char* cubemapVertex = m_baseAP["cubemapVertex.shader"]->data; - const char* cubemapFragment = m_baseAP["cubemapFragment.shader"]->data; - m_cubemapShader = new Shader(cubemapVertex, cubemapFragment); - const char* fadeVertex = m_baseAP["fadeVertex.shader"]->data; - const char* fadeFragment = m_baseAP["fadeFragment.shader"]->data; - m_fadeShader = new Shader(fadeVertex, fadeFragment); - - BaseAssets::cube = (AModel*)m_baseAP["cube.obj"]; - BaseAssets::plane = (AModel*)m_baseAP["plane.obj"]; - BaseAssets::sphere = (AModel*)m_baseAP["sphere.obj"]; - BaseAssets::cone = (AModel*)m_baseAP["cone.obj"]; - BaseAssets::cylinder = (AModel*)m_baseAP["cylinder.obj"]; - BaseAssets::torus = (AModel*)m_baseAP["torus.obj"]; - BaseAssets::logo = (ATexture*)m_baseAP["logo.png"]; - BaseAssets::defaultFont = (AFont*)m_baseAP["default.ttf"]; + loadBaseAssets(); float fadeVB[] = { -1.0, -1.0, @@ -168,7 +144,7 @@ namespace nf { //Draw cubemap where there isn't anything else if (m_cubemap != nullptr) { m_cubemapShader->setUniform("proj", proj); - m_cubemap->render(); + m_cubemap->render(m_cubemapShader); } m_cubemap = nullptr; @@ -179,13 +155,19 @@ namespace nf { UIElement& curr = *draw; if (curr.identity() == "text") { m_textShader->setUniform("proj", proj); - curr.render(m_textShader, m_app->getConfig().width, m_app->getConfig().height); + Text& text = *(Text*)draw; + text.render(m_textShader, m_app->getConfig().width, m_app->getConfig().height); continue; } - if (curr.identity() == "texture") { + else if (curr.identity() == "texture") { m_uiTextureShader->setUniform("proj", proj); curr.render(m_uiTextureShader, m_app->getConfig().width, m_app->getConfig().height); } + else if (curr.identity() == "button") { + m_uiTextureShader->setUniform("proj", proj); + Button& button = *(Button*)draw; + button.render(m_uiTextureShader, m_app->getConfig().width, m_app->getConfig().height, m_app, m_textShader); + } } m_lUI.clear(); @@ -236,6 +218,36 @@ namespace nf { Error("OpenGL error " + std::to_string(err)); } + void Renderer::loadBaseAssets() { + m_baseAP.load("base.nfpack"); + const char* entityVertex = m_baseAP["entityVertex.shader"]->data; + const char* entityFragment = m_baseAP["entityFragment.shader"]->data; + m_entityShader = new Shader(entityVertex, entityFragment); + const char* textVertex = m_baseAP["textVertex.shader"]->data; + const char* textFragment = m_baseAP["textFragment.shader"]->data; + m_textShader = new Shader(textVertex, textFragment); + const char* uiTextureVertex = m_baseAP["uiTextureVertex.shader"]->data; + const char* uiTextureFragment = m_baseAP["uiTextureFragment.shader"]->data; + m_uiTextureShader = new Shader(uiTextureVertex, uiTextureFragment); + const char* cubemapVertex = m_baseAP["cubemapVertex.shader"]->data; + const char* cubemapFragment = m_baseAP["cubemapFragment.shader"]->data; + m_cubemapShader = new Shader(cubemapVertex, cubemapFragment); + const char* fadeVertex = m_baseAP["fadeVertex.shader"]->data; + const char* fadeFragment = m_baseAP["fadeFragment.shader"]->data; + m_fadeShader = new Shader(fadeVertex, fadeFragment); + + BaseAssets::cube = (AModel*)m_baseAP["cube.obj"]; + BaseAssets::plane = (AModel*)m_baseAP["plane.obj"]; + BaseAssets::sphere = (AModel*)m_baseAP["sphere.obj"]; + BaseAssets::cone = (AModel*)m_baseAP["cone.obj"]; + BaseAssets::cylinder = (AModel*)m_baseAP["cylinder.obj"]; + BaseAssets::torus = (AModel*)m_baseAP["torus.obj"]; + BaseAssets::logo = (ATexture*)m_baseAP["logo.png"]; + BaseAssets::cubemap = (ACubemap*)m_baseAP["default.cm"]; + BaseAssets::font = (AFont*)m_baseAP["default.ttf"]; + BaseAssets::button = (AButton*)m_baseAP["default.button"]; + } + Renderer::~Renderer() { delete m_entityShader; delete m_textShader; diff --git a/NothinFancy/src/include/Application.h b/NothinFancy/src/include/Application.h index e884ddc..1f0ccb4 100644 --- a/NothinFancy/src/include/Application.h +++ b/NothinFancy/src/include/Application.h @@ -32,8 +32,10 @@ namespace nf { int getFPS() const; bool isKeyHeld(unsigned int code); bool isKeyPressed(unsigned int code); + bool isMouse(unsigned int code); void trackMouse(bool track); void getMouseDiff(int& x, int& y); + Vec2 getMousePos(); static Application* getApp(); void quit(); @@ -79,7 +81,7 @@ namespace nf { std::string m_nextState; //Array of booleans that represent keyboard and mouse input minus the scrollwheel - std::array, 164> m_keys; + std::array m_keysPressed; unsigned int m_mouseX, m_mouseY; bool m_trackingMouse; bool m_mouseTrackFirst; diff --git a/NothinFancy/src/include/Assets.h b/NothinFancy/src/include/Assets.h index bdf1d3c..86458ba 100644 --- a/NothinFancy/src/include/Assets.h +++ b/NothinFancy/src/include/Assets.h @@ -49,10 +49,6 @@ namespace nf { ~ACubemap(); }; - struct AShader : Asset { - ~AShader() override; - }; - struct AFont : Asset { size_t size = 0; Font* loadedFont = nullptr; @@ -60,6 +56,20 @@ namespace nf { ~AFont() override; }; + struct AButton : Asset { + ATexture idleTex; + ATexture hoverTex; + ATexture pressedTex; + + unsigned int numImages = 0; + + ~AButton() override; + }; + + struct AShader : Asset { + ~AShader() override; + }; + class AssetPack : public NFObject { public: AssetPack(); @@ -85,7 +95,10 @@ namespace nf { static ATexture* logo; - static AFont* defaultFont; + static ACubemap* cubemap; + static AFont* font; + + static AButton* button; }; } \ No newline at end of file diff --git a/NothinFancy/src/include/Button.h b/NothinFancy/src/include/Button.h new file mode 100644 index 0000000..e763e39 --- /dev/null +++ b/NothinFancy/src/include/Button.h @@ -0,0 +1,36 @@ +#pragma once +#include + +#include "UIElement.h" +#include "NFObject.h" +#include "Text.h" + +namespace nf { + class Application; + class Texture; + struct Asset; + + class Button : public UIElement, public NFObject { + public: + Button(); + + void create(const Vec2& position, std::string string = "", Asset* buttonAsset = nf::BaseAssets::button, double scale = 1.0, double opacity = 1.0); + const char* identity() override; + void render(Shader* shader, unsigned int windowWidth, unsigned int windowHeight, Application* app, Shader* textShader); + bool isClicked(); + + void destroy() override; + ~Button(); + private: + Texture* m_idleTexture; + Texture* m_hoverTexture; + Texture* m_pressedTexture; + Texture* m_currentTexture; + std::string m_string; + Text m_text; + float m_scale; + float m_opacity; + bool m_clicked; + bool m_triggered; + }; +} \ No newline at end of file diff --git a/NothinFancy/src/include/Cubemap.h b/NothinFancy/src/include/Cubemap.h index 44089ff..aa5ad02 100644 --- a/NothinFancy/src/include/Cubemap.h +++ b/NothinFancy/src/include/Cubemap.h @@ -4,6 +4,7 @@ namespace nf { struct Asset; + class Shader; class Cubemap : public Drawable, public NFObject { public: @@ -11,7 +12,7 @@ namespace nf { void create(Asset* cubemapAsset); bool isConstructed(); - void render(); + void render(Shader* shader); void destroy() override; ~Cubemap(); diff --git a/NothinFancy/src/include/Model.h b/NothinFancy/src/include/Model.h index 4254909..a12ef23 100644 --- a/NothinFancy/src/include/Model.h +++ b/NothinFancy/src/include/Model.h @@ -30,7 +30,6 @@ namespace nf { void render(Shader* shader); - void setBaseAsset(bool isBase); bool isBaseAsset(); ~Model(); diff --git a/NothinFancy/src/include/NothinFancy.h b/NothinFancy/src/include/NothinFancy.h index ad752bd..83d41cb 100644 --- a/NothinFancy/src/include/NothinFancy.h +++ b/NothinFancy/src/include/NothinFancy.h @@ -15,6 +15,7 @@ #include "Cubemap.h" #include "Text.h" #include "UITexture.h" +#include "Button.h" #include "Input.h" namespace nf { @@ -85,8 +86,10 @@ namespace nf { int getFPS() const; bool isKeyHeld(unsigned int code); bool isKeyPressed(unsigned int code); + bool isMouse(unsigned int code); void trackMouse(bool track); void getMouseDiff(int& x, int& y); + Vec2 getMousePos(); static Application* getApp(); void quit(); @@ -132,7 +135,7 @@ namespace nf { std::string m_nextState; //Array of booleans that represent keyboard and mouse input minus the scrollwheel - std::array, 164> m_keys; + std::array m_keysPressed; unsigned int m_mouseX, m_mouseY; bool m_trackingMouse; bool m_mouseTrackFirst; diff --git a/NothinFancy/src/include/Renderer.h b/NothinFancy/src/include/Renderer.h index 3f646ac..db96c61 100644 --- a/NothinFancy/src/include/Renderer.h +++ b/NothinFancy/src/include/Renderer.h @@ -32,6 +32,8 @@ namespace nf { ~Renderer(); private: + void loadBaseAssets(); + Application* m_app; HDC m_hdc; diff --git a/NothinFancy/src/include/Text.h b/NothinFancy/src/include/Text.h index 3cd5169..89b5f6c 100644 --- a/NothinFancy/src/include/Text.h +++ b/NothinFancy/src/include/Text.h @@ -23,13 +23,13 @@ namespace nf { public: Text(); - void create(const std::string& string, const Vec2& position, const Vec3& color = {1.0, 1.0, 1.0}, double opacity = 1.0, double scale = 1.0, Asset* font = BaseAssets::defaultFont); + void create(const std::string& string, const Vec2& position, const Vec3& color = {1.0, 1.0, 1.0}, double opacity = 1.0, double scale = 1.0, Asset* font = BaseAssets::font); const char* identity() override; void setText(const std::string& string); void setColor(const Vec3& color); void setScale(double scale); void setOpacity(double opacity); - void render(Shader* shader, unsigned int windowWidth, unsigned int windowHeight) 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()); void destroy() override; ~Text(); diff --git a/NothinFancy/src/include/UIElement.h b/NothinFancy/src/include/UIElement.h index f76b25a..af15152 100644 --- a/NothinFancy/src/include/UIElement.h +++ b/NothinFancy/src/include/UIElement.h @@ -11,7 +11,7 @@ namespace nf { UIElement(); virtual const char* identity(); - void setPosition(float x, float y); + void setPosition(double x, double y); void setPosition(const Vec2& position); void centered(bool x, bool y = false); bool isConstructed(); diff --git a/NothinFancy/src/include/UITexture.h b/NothinFancy/src/include/UITexture.h index f8cba4e..05f3a6b 100644 --- a/NothinFancy/src/include/UITexture.h +++ b/NothinFancy/src/include/UITexture.h @@ -11,7 +11,7 @@ namespace nf { public: UITexture(); - void create(Asset* textureAsset, const Vec2& position, double scale = 1.0, double opacity = 1.0 ); + void create(Asset* textureAsset, const Vec2& position, double scale = 1.0, double opacity = 1.0); const char* identity() override; void setScale(double scale); void setOpacity(double opacity); diff --git a/NothinFancy/src/include/Utility.h b/NothinFancy/src/include/Utility.h index 8b6792d..fa5241a 100644 --- a/NothinFancy/src/include/Utility.h +++ b/NothinFancy/src/include/Utility.h @@ -15,7 +15,7 @@ namespace nf { #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 +//Prints error message and breaks the debugger in debug mode #define Error(x) {nf::Debug::ErrorImp(x,__FILENAME__, __LINE__);\ __debugbreak();} @@ -34,6 +34,7 @@ __debugbreak();} #else #define DEBUGINIT #define Log(x) +//Shows error dialog with specified message then exits #define Error(x) {MessageBox(FindWindow(L"NFClass", NULL), toWide(x), L"NF Engine Error", MB_OK | MB_ICONERROR);\ std::exit(-1);} #endif @@ -54,6 +55,9 @@ std::exit(-1);} this->y -= rhs.y; return *this; } + bool operator==(const Vec2& rhs) { + return this->x == rhs.x && this->y == rhs.y; + } double x, y; }; struct Vec3 { @@ -75,6 +79,9 @@ std::exit(-1);} this->z -= rhs.z; return *this; } + bool operator==(const Vec3& rhs) { + return this->x == rhs.x && this->y == rhs.y && this->z == rhs.z ; + } double x, y, z; };