Added clickable buttons; Custom button textures can be specified; Added default cubemap
Before Width: | Height: | Size: 27 KiB |
Before Width: | Height: | Size: 27 KiB |
Before Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 29 KiB |
Before Width: | Height: | Size: 19 KiB |
BIN
NFPackCreator/AssetBuild/base/buttons/default_buttonhover.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
NFPackCreator/AssetBuild/base/buttons/default_buttonidle.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
NFPackCreator/AssetBuild/base/buttons/default_buttonpressed.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
NFPackCreator/AssetBuild/base/cubemaps/default_cmback.jpg
Normal file
After Width: | Height: | Size: 723 KiB |
BIN
NFPackCreator/AssetBuild/base/cubemaps/default_cmbottom.jpg
Normal file
After Width: | Height: | Size: 274 KiB |
BIN
NFPackCreator/AssetBuild/base/cubemaps/default_cmfront.jpg
Normal file
After Width: | Height: | Size: 462 KiB |
BIN
NFPackCreator/AssetBuild/base/cubemaps/default_cmleft.jpg
Normal file
After Width: | Height: | Size: 588 KiB |
BIN
NFPackCreator/AssetBuild/base/cubemaps/default_cmright.jpg
Normal file
After Width: | Height: | Size: 525 KiB |
BIN
NFPackCreator/AssetBuild/base/cubemaps/default_cmtop.jpg
Normal file
After Width: | Height: | Size: 338 KiB |
@ -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);
|
||||
|
@ -91,7 +91,7 @@ int main(int argc, char* argv[]) {
|
||||
}
|
||||
|
||||
std::set<std::string> 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();
|
||||
|
@ -200,6 +200,7 @@
|
||||
<ClCompile Include="src\Gamestate.cpp" />
|
||||
<ClCompile Include="src\IntroGamestate.cpp" />
|
||||
<ClCompile Include="src\Renderer\Camera.cpp" />
|
||||
<ClCompile Include="src\Renderer\Drawable\Button.cpp" />
|
||||
<ClCompile Include="src\Renderer\Drawable\Cubemap.cpp" />
|
||||
<ClCompile Include="src\Renderer\Drawable\Drawable.cpp" />
|
||||
<ClCompile Include="src\Renderer\Drawable\Entity.cpp" />
|
||||
@ -218,6 +219,7 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="src\include\Assets.h" />
|
||||
<ClInclude Include="src\include\Button.h" />
|
||||
<ClInclude Include="src\include\Camera.h" />
|
||||
<ClInclude Include="src\include\Cubemap.h" />
|
||||
<ClInclude Include="src\include\Entity.h" />
|
||||
|
@ -75,6 +75,9 @@
|
||||
<ClCompile Include="src\Renderer\Drawable\Cubemap.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\Renderer\Drawable\Button.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="src\include\Config.h">
|
||||
@ -149,6 +152,9 @@
|
||||
<ClInclude Include="src\include\NFObject.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\include\Button.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Natvis Include="NatvisFile.natvis" />
|
||||
|
@ -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: {
|
||||
|
@ -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<std::string, ACubemap*> cubemaps;
|
||||
std::unordered_map<std::string, AButton*> 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;
|
||||
}
|
@ -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));
|
||||
|
136
NothinFancy/src/Renderer/Drawable/Button.cpp
Normal file
@ -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<AButton*>(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<float>(2);
|
||||
m_vao->finishBufferLayout();
|
||||
m_vao->addBuffer(tc, sizeof(tc));
|
||||
m_vao->push<float>(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() {
|
||||
|
||||
}
|
||||
}
|
@ -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);
|
||||
|
@ -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<AModel*>(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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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<ATexture*>(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<float>(2);
|
||||
m_vao->finishBufferLayout();
|
||||
m_vao->addBuffer(nullptr, 0);
|
||||
m_vao->addBuffer(tc, sizeof(tc));
|
||||
m_vao->push<float>(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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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<std::pair<bool, bool>, 164> m_keys;
|
||||
std::array<bool, 164> m_keysPressed;
|
||||
unsigned int m_mouseX, m_mouseY;
|
||||
bool m_trackingMouse;
|
||||
bool m_mouseTrackFirst;
|
||||
|
@ -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;
|
||||
};
|
||||
}
|
36
NothinFancy/src/include/Button.h
Normal file
@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
|
||||
#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;
|
||||
};
|
||||
}
|
@ -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();
|
||||
|
@ -30,7 +30,6 @@ namespace nf {
|
||||
|
||||
void render(Shader* shader);
|
||||
|
||||
void setBaseAsset(bool isBase);
|
||||
bool isBaseAsset();
|
||||
|
||||
~Model();
|
||||
|
@ -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<std::pair<bool, bool>, 164> m_keys;
|
||||
std::array<bool, 164> m_keysPressed;
|
||||
unsigned int m_mouseX, m_mouseY;
|
||||
bool m_trackingMouse;
|
||||
bool m_mouseTrackFirst;
|
||||
|
@ -32,6 +32,8 @@ namespace nf {
|
||||
|
||||
~Renderer();
|
||||
private:
|
||||
void loadBaseAssets();
|
||||
|
||||
Application* m_app;
|
||||
|
||||
HDC m_hdc;
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|