Physics meshes are now cooked during runtime; Code cleanup

This commit is contained in:
Grayson Riffe (Laptop) 2021-10-29 13:39:42 -05:00
parent b4c704f5ec
commit aa58238162
35 changed files with 371 additions and 234 deletions

View File

@ -2,10 +2,11 @@
void MainState::onEnter() { void MainState::onEnter() {
Log("MainState onEnter!"); Log("MainState onEnter!");
camera->setType(nf::Camera::Type::FIRST_PERSON); currCamType = nf::Camera::Type::FIRST_PERSON;
camera->setType(currCamType);
ap.load("example.nfpack"); ap.load("example.nfpack");
test.create(ap["2mats.obj"]); test.create(ap["2mats.obj"], nf::Entity::Type::DYNAMIC);
test.setPosition(0.0, 0.05, -5.0); test.setPosition(nf::Vec3(0.0, 1.5, -5.0));
plane.create(nf::BaseAssets::plane); plane.create(nf::BaseAssets::plane);
plane.setScale(20.0); plane.setScale(20.0);
text.create("This is a test text.", nf::Vec2(0.1, 0.025), nf::Vec3(0.8)); text.create("This is a test text.", nf::Vec2(0.1, 0.025), nf::Vec3(0.8));
@ -28,20 +29,23 @@ void MainState::onEnter() {
for (int y = 0; y < 5; y++) { for (int y = 0; y < 5; y++) {
for (int z = 0; z < 5; z++) { for (int z = 0; z < 5; z++) {
entities.push_back(new nf::Entity); entities.push_back(new nf::Entity);
entities.back()->create(ap["2mats.obj"], nf::Entity::Type::DYNAMIC); entities.back()->create(nf::BaseAssets::sphere, nf::Entity::Type::DYNAMIC);
entities.back()->setPosition(5.0 + x * 2.1, 1.0 + y * 2.1, -5.0 + z * 2.1); entities.back()->setPosition(nf::Vec3(5.0 + x * 2.05, 1.0 + y * 2.05, -5.0 + z * 2.05));
} }
} }
} }
camera->setPosition(-20.0, 5.0, 0.0);
camera->setRotation(85.0, 0.0);
} }
void MainState::update(double deltaTime) { void MainState::update(float deltaTime) {
if (app->isKeyPressed(NFI_U)) if (app->isKeyPressed(NFI_E)) {
camera->setType(nf::Camera::Type::UI); currCamType = currCamType == nf::Camera::Type::FIRST_PERSON ? nf::Camera::Type::UI : nf::Camera::Type::FIRST_PERSON;
if (app->isKeyPressed(NFI_P)) camera->setType(currCamType);
camera->setType(nf::Camera::Type::FIRST_PERSON); }
double speed = 5.0; float speed = 5.0;
if (camera->getType() == nf::Camera::Type::FIRST_PERSON) { if (camera->getType() == nf::Camera::Type::FIRST_PERSON) {
if (app->isKeyHeld(NFI_SHIFT)) if (app->isKeyHeld(NFI_SHIFT))
speed = 20.0; speed = 20.0;
@ -57,19 +61,12 @@ void MainState::update(double deltaTime) {
camera->moveLeft(speed * deltaTime); camera->moveLeft(speed * deltaTime);
} }
static double offset = 0.0; //test.setPosition(nf::Vec3(std::sin(circle) * 10.0, 5.0, std::cos(circle) * 10.0));
if (app->isKeyHeld(NFI_UP)) circle += 1.5f * deltaTime;
offset += 2.0 * deltaTime;
if (app->isKeyHeld(NFI_DOWN))
offset -= 2.0 * deltaTime;
test.setRotation(0.0, 0.0, -offset * 20.0);
test.setPosition(nf::Vec3(std::sin(circle) * 10.0, 5.0, std::cos(circle) * 10.0));
circle += 2.0 * deltaTime;
text.setText("FPS: " + std::to_string(app->getFPS())); text.setText("FPS: " + std::to_string(app->getFPS()));
if (button.isClicked()) if (button.isClicked() || app->isKeyPressed(NFI_R))
app->changeState("Main State"); app->changeState("Main State");
if (button2.isClicked() || app->isKeyPressed(NFI_SPACE)) if (button2.isClicked() || app->isKeyPressed(NFI_SPACE))
@ -87,7 +84,7 @@ void MainState::update(double deltaTime) {
} }
void MainState::render(nf::Renderer& renderer) { void MainState::render(nf::Renderer& renderer) {
//renderer.render(test); renderer.render(test);
renderer.render(plane); renderer.render(plane);
renderer.render(light); renderer.render(light);
renderer.render(light2); renderer.render(light2);
@ -104,7 +101,7 @@ void MainState::render(nf::Renderer& renderer) {
void MainState::onExit() { void MainState::onExit() {
Log("MainState onExit!"); Log("MainState onExit!");
circle = 0.0;
circle = 0.0f;
entities.clear(); entities.clear();
} }

View File

@ -5,11 +5,13 @@ class MainState : public nf::Gamestate {
public: public:
void onEnter() override; void onEnter() override;
void update(double deltaTime) override; void update(float deltaTime) override;
void render(nf::Renderer& renderer) override; void render(nf::Renderer& renderer) override;
void onExit() override; void onExit() override;
private: private:
nf::Camera::Type currCamType;
nf::AssetPack ap; nf::AssetPack ap;
nf::Entity test; nf::Entity test;
nf::Entity plane; nf::Entity plane;
@ -25,7 +27,7 @@ private:
nf::Sound sound; nf::Sound sound;
nf::Sound sound2; nf::Sound sound2;
double circle; float circle;
std::vector<nf::Entity*> entities; std::vector<nf::Entity*> entities;
}; };

Binary file not shown.

View File

@ -15,7 +15,8 @@ namespace nf {
m_altWidth(1280), m_altWidth(1280),
m_altHeight(720), m_altHeight(720),
m_defaultStateAdded(false), m_defaultStateAdded(false),
m_stateChange(false) m_stateChange(false),
m_stateChangeStarted(false)
{ {
Log("Creating NF application"); 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); 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);
@ -168,7 +169,7 @@ namespace nf {
} }
bool Application::isMouse(unsigned int code) { bool Application::isMouse(unsigned int code) {
if (code < 7) if (code < 7 && GetForegroundWindow() == m_window)
return GetKeyState(code) & 0x8000; return GetKeyState(code) & 0x8000;
return false; return false;
} }
@ -187,7 +188,7 @@ namespace nf {
} }
Vec2 Application::getMousePos() { Vec2 Application::getMousePos() {
return Vec2(m_mouseX, m_mouseY); return Vec2((float)m_mouseX, (float)m_mouseY);
} }
Application* Application::getApp(bool first) { Application* Application::getApp(bool first) {
@ -284,6 +285,7 @@ namespace nf {
void Application::quit() { void Application::quit() {
m_quit = true; m_quit = true;
Log("Exiting NF application");
} }
void Application::runMainGameThread() { void Application::runMainGameThread() {
@ -295,22 +297,24 @@ namespace nf {
m_physics = new PhysicsEngine(this); m_physics = new PhysicsEngine(this);
Gamestate* sIntro = new IntroGamestate; Gamestate* sIntro = new IntroGamestate;
m_currentState = sIntro; m_currentState = sIntro;
m_currentState->run(this); m_currentState->run(this, false);
m_renderer->setFade(true, false, true); m_renderer->setFade(true, false, true);
std::chrono::steady_clock::time_point currentFrame = std::chrono::steady_clock::now(); std::chrono::steady_clock::time_point startOfCurrentFrame = std::chrono::steady_clock::now();
std::chrono::steady_clock::time_point lastFrame = std::chrono::steady_clock::now(); std::chrono::steady_clock::time_point startOfLastFrame = std::chrono::steady_clock::now();
while (m_running) { while (m_running) {
currentFrame = std::chrono::steady_clock::now(); startOfCurrentFrame = std::chrono::steady_clock::now();
m_deltaTime = std::chrono::duration<double>(currentFrame - lastFrame).count(); m_deltaTime = std::chrono::duration<float>(startOfCurrentFrame - startOfLastFrame).count();
if (m_deltaTime >= m_minFrametime) { if (m_deltaTime >= m_minFrametime) {
lastFrame = std::chrono::steady_clock::now(); //Don't count loading times into delta time
if (m_stateChange)
doStateChange();
startOfLastFrame = std::chrono::steady_clock::now();
//Should the physics update before user code? //Should the physics update before user code?
m_physics->update(m_deltaTime); m_physics->update(m_deltaTime);
m_currentState->update(m_deltaTime); m_currentState->update(m_deltaTime);
m_currentState->render(*m_renderer); m_currentState->render(*m_renderer);
m_renderer->doFrame(m_currentState->getCamera(), m_deltaTime); m_renderer->doFrame(m_currentState->getCamera(), m_deltaTime);
if (m_stateChange)
doStateChange();
m_fpsClock2 = std::chrono::steady_clock::now(); m_fpsClock2 = std::chrono::steady_clock::now();
m_fpsDuration = m_fpsClock2 - m_fpsClock1; m_fpsDuration = m_fpsClock2 - m_fpsClock1;
if (m_fpsDuration.count() >= 0.2) { if (m_fpsDuration.count() >= 0.2) {
@ -334,10 +338,9 @@ namespace nf {
} }
void Application::doStateChange() { void Application::doStateChange() {
static bool once = true; if (!m_stateChangeStarted) {
if (once) {
m_renderer->setFade(false, true, false); m_renderer->setFade(false, true, false);
once = false; m_stateChangeStarted = true;
} }
if (m_renderer->isFadeOutComplete()) { if (m_renderer->isFadeOutComplete()) {
@ -347,7 +350,7 @@ namespace nf {
m_currentState->run(this); m_currentState->run(this);
m_renderer->setFade(true, false, false); m_renderer->setFade(true, false, false);
m_stateChange = false; m_stateChange = false;
once = true; m_stateChangeStarted = false;
} }
} }
@ -412,8 +415,6 @@ namespace nf {
} }
Application::~Application() { Application::~Application() {
Log("Exiting NF application");
for (std::pair<std::string, Gamestate*> state : m_states) { for (std::pair<std::string, Gamestate*> state : m_states) {
Gamestate* curr = state.second; Gamestate* curr = state.second;
delete curr; delete curr;

View File

@ -256,9 +256,7 @@ namespace nf {
return m_assets[in]; return m_assets[in];
} }
Asset* AssetPack::operator[](std::string& in) { Asset* AssetPack::operator[](std::string& in) {
if (m_assets.find(in) == m_assets.end()) return operator[](in.c_str());
Error("Could not find asset \"" + in + (std::string)"\" in asset pack!");
return m_assets[in];
} }
void AssetPack::destroy() { void AssetPack::destroy() {

View File

@ -92,9 +92,9 @@ namespace nf {
if (m_isActive && Application::getApp()->getCurrentState() && Application::getApp()->getCurrentState()->isRunning()) { if (m_isActive && Application::getApp()->getCurrentState() && Application::getApp()->getCurrentState()->isRunning()) {
//Update listener position //Update listener position
temp = Application::getApp()->getCurrentState()->getCamera()->getPosition(); temp = Application::getApp()->getCurrentState()->getCamera()->getPosition();
listener.Position = X3DAUDIO_VECTOR((float)temp.x, (float)temp.y, (float)-temp.z); listener.Position = X3DAUDIO_VECTOR(temp.x, temp.y, -temp.z);
temp = Application::getApp()->getCurrentState()->getCamera()->getRotation(); temp = Application::getApp()->getCurrentState()->getCamera()->getRotation();
listener.OrientFront = X3DAUDIO_VECTOR((float)temp.x, 0.0f, (float)-temp.z); listener.OrientFront = X3DAUDIO_VECTOR(temp.x, 0.0f, -temp.z);
//Stop all sounds if requested //Stop all sounds if requested
if (m_clear) if (m_clear)
@ -138,7 +138,7 @@ namespace nf {
int ch = curr.format->Format.nChannels; int ch = curr.format->Format.nChannels;
emitter.ChannelCount = ch; emitter.ChannelCount = ch;
x3dSettings.SrcChannelCount = ch; x3dSettings.SrcChannelCount = ch;
emitter.Position = X3DAUDIO_VECTOR((float)temp.x, (float)temp.y, (float)-temp.z); emitter.Position = X3DAUDIO_VECTOR(temp.x, temp.y, -temp.z);
X3DAudioCalculate(x3d, &listener, &emitter, X3DAUDIO_CALCULATE_MATRIX | X3DAUDIO_CALCULATE_DOPPLER | X3DAUDIO_CALCULATE_LPF_DIRECT | X3DAUDIO_CALCULATE_REVERB, &x3dSettings); X3DAudioCalculate(x3d, &listener, &emitter, X3DAUDIO_CALCULATE_MATRIX | X3DAUDIO_CALCULATE_DOPPLER | X3DAUDIO_CALCULATE_LPF_DIRECT | X3DAUDIO_CALCULATE_REVERB, &x3dSettings);
float temp2 = matrix[1]; float temp2 = matrix[1];
matrix[1] = matrix[2]; matrix[1] = matrix[2];

View File

@ -2,6 +2,7 @@
#include "Application.h" #include "Application.h"
#include "PhysicsEngine.h" #include "PhysicsEngine.h"
#include "Entity.h"
#include "Model.h" #include "Model.h"
#include "Texture.h" #include "Texture.h"
#include "Utility.h" #include "Utility.h"
@ -10,18 +11,22 @@ namespace nf {
Gamestate::Gamestate() : Gamestate::Gamestate() :
app(nullptr), app(nullptr),
camera(nullptr), camera(nullptr),
m_loading(false),
m_running(false) m_running(false)
{ {
} }
void Gamestate::run(Application* app) { void Gamestate::run(Application* app, bool physics) {
m_loading = true;
this->app = app; this->app = app;
camera = new Camera(this->app); camera = new Camera(this->app);
app->getPhysicsEngine()->newScene(); if (physics)
app->getPhysicsEngine()->newScene();
onEnter(); onEnter();
m_loading = false;
m_running = true; m_running = true;
} }
@ -33,7 +38,11 @@ namespace nf {
return m_running; return m_running;
} }
void Gamestate::update(double deltaTime) { bool Gamestate::isLoading() {
return m_loading;
}
void Gamestate::update(float deltaTime) {
} }
@ -57,6 +66,10 @@ namespace nf {
curr->destroy(); curr->destroy();
m_nfObjects.clear(); m_nfObjects.clear();
for (Entity* curr : m_entsToDelete)
delete curr;
m_entsToDelete.clear();
for (Model* curr : m_modelsToDelete) for (Model* curr : m_modelsToDelete)
if (!curr->isBaseAsset()) if (!curr->isBaseAsset())
delete curr; delete curr;

View File

@ -7,26 +7,26 @@
namespace nf { namespace nf {
void IntroGamestate::onEnter() { void IntroGamestate::onEnter() {
Log("Intro onEnter!"); Log("Intro onEnter!");
m_frame = 0;
m_scale = 2.0;
m_logoTex.create(BaseAssets::logo, Vec2(0.0, 0.0)); m_logoTex.create(BaseAssets::logo, Vec2(0.0, 0.0));
m_logoTex.centered(true, true); m_logoTex.centered(true, true);
m_text.create("(c) Grayson Riffe 2021", Vec2(0.01, 0.025), Vec3(0.8)); m_text.create("(c) Grayson Riffe 2021", Vec2(0.01f, 0.025f), Vec3(0.8f));
m_text.setScale(0.6); m_text.setScale(0.6f);
} }
void IntroGamestate::update(double deltaTime) { void IntroGamestate::update(float deltaTime) {
static unsigned int frame = 0; m_frame++;
frame++; if (m_frame < 5) return;
if (frame < 5) return; if (m_frame == 5)
if (frame == 5)
m_start = std::chrono::steady_clock::now(); m_start = std::chrono::steady_clock::now();
std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now(); std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now();
std::chrono::duration<double, std::ratio<1i64>> dur = now - m_start; std::chrono::duration<float, std::ratio<1i64>> dur = now - m_start;
static double scale = 2.0; m_logoTex.setScale(m_scale);
m_logoTex.setScale(scale);
if (dur.count() > 0.2) { if (dur.count() > 0.2) {
scale += 0.12 * deltaTime; m_scale += 0.12f * deltaTime;
} }
if (dur.count() > 3.5 || app->isKeyPressed(NFI_SPACE)) { if (dur.count() > 3.5 || app->isKeyPressed(NFI_SPACE)) {

View File

@ -21,7 +21,7 @@ namespace nf {
} }
void Button::create(const Vec2& position, std::string string, Asset* buttonAsset, double scale, double opacity) { void Button::create(const Vec2& position, std::string string, Asset* buttonAsset, float scale, float opacity) {
if (m_constructed) if (m_constructed)
Error("Button already created!"); Error("Button already created!");
m_constructed = true; m_constructed = true;
@ -31,8 +31,8 @@ namespace nf {
m_text.create(m_string, Vec2(0.0, 0.0)); m_text.create(m_string, Vec2(0.0, 0.0));
m_text.centered(true); m_text.centered(true);
} }
m_scale = (float)scale * 0.3f; m_scale = scale * 0.3f;
m_opacity = (float)opacity; m_opacity = opacity;
m_text.setOpacity(m_opacity); m_text.setOpacity(m_opacity);
AButton* button; AButton* button;
if ((button = dynamic_cast<AButton*>(buttonAsset)) == nullptr) if ((button = dynamic_cast<AButton*>(buttonAsset)) == nullptr)
@ -68,12 +68,12 @@ namespace nf {
} }
void Button::render(Shader* shader, unsigned int windowWidth, unsigned int windowHeight, Application* app, Shader* textShader) { 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 posX = m_position.x * windowWidth, posY = m_position.y * windowHeight;
float scale = windowWidth / 5.0f; float scale = windowWidth / 5.0f;
Vec2 texDim = m_idleTexture->getDimensions(); Vec2 texDim = m_idleTexture->getDimensions();
float height = scale * m_scale; float height = scale * m_scale;
float width = ((float)texDim.x / (float)texDim.y) * scale * m_scale; float width = (texDim.x / texDim.y) * scale * m_scale;
if (m_centeredX) if (m_centeredX)
posX = ((float)windowWidth - width) / 2; posX = ((float)windowWidth - width) / 2;
if (m_centeredY) if (m_centeredY)

View File

@ -10,6 +10,7 @@
namespace nf { namespace nf {
Entity::Entity() : Entity::Entity() :
m_constructed(false), m_constructed(false),
m_createdAtLoad(false),
m_type(Type::STATIC), m_type(Type::STATIC),
m_model(nullptr), m_model(nullptr),
m_position(0.0), m_position(0.0),
@ -17,7 +18,9 @@ namespace nf {
m_scale(1.0), m_scale(1.0),
m_update(false) m_update(false)
{ {
if (Application::getApp() && Application::getApp()->getCurrentState())
if (Application::getApp()->getCurrentState()->isLoading())
m_createdAtLoad = true;
} }
void Entity::create(Asset* modelAsset, Type type) { void Entity::create(Asset* modelAsset, Type type) {
@ -32,15 +35,21 @@ namespace nf {
m_model = model->loadedModel; m_model = model->loadedModel;
} }
else { else {
m_model = new Model(model); //Build convex mesh for every model once and store them somehow bool physics = false;
if (m_type != Entity::Type::DETAIL)
physics = true;
m_model = new Model(model, physics);
model->alreadyLoaded = true; model->alreadyLoaded = true;
model->loadedModel = m_model; model->loadedModel = m_model;
} }
if (type != Type::STATIC) if (type != Type::DETAIL)
Application::getApp()->getPhysicsEngine()->addActor(this); Application::getApp()->getPhysicsEngine()->addActor(this);
if (!Application::getApp()->getCurrentState()->isRunning()) if (!Application::getApp()->getCurrentState()->isRunning())
if (m_createdAtLoad)
Application::getApp()->getCurrentState()->m_entsToDelete.push_back(this);
else
Application::getApp()->getCurrentState()->m_nfObjects.push_back(this); Application::getApp()->getCurrentState()->m_nfObjects.push_back(this);
} }
@ -48,15 +57,11 @@ namespace nf {
return m_constructed; return m_constructed;
} }
void Entity::setType(Entity::Type type) {
//TODO: This function
}
Entity::Type Entity::getType() { Entity::Type Entity::getType() {
return m_type; return m_type;
} }
void Entity::setPosition(double x, double y, double z) { void Entity::setPosition(float x, float y, float z) {
m_position = { x, y, z }; m_position = { x, y, z };
m_update = true; m_update = true;
} }
@ -70,7 +75,7 @@ namespace nf {
m_position = position; m_position = position;
} }
void Entity::setRotation(double x, double y, double z) { void Entity::setRotation(float x, float y, float z) {
m_rotation = degToQuat({ x, y, z }); m_rotation = degToQuat({ x, y, z });
m_update = true; m_update = true;
} }
@ -84,12 +89,12 @@ namespace nf {
m_rotation = rotation; m_rotation = rotation;
} }
void Entity::setScale(double x) { void Entity::setScale(float x) {
m_scale = { x, x, x }; m_scale = { x, x, x };
m_update = true; m_update = true;
} }
void Entity::setScale(double x, double y, double z) { void Entity::setScale(float x, float y, float z) {
m_scale = { x, y, z }; m_scale = { x, y, z };
m_update = true; m_update = true;
} }
@ -115,6 +120,10 @@ namespace nf {
return m_rotation; return m_rotation;
} }
const Vec3& Entity::getScale() {
return m_scale;
}
void Entity::render(Shader* shader, bool onlyDepth) { void Entity::render(Shader* shader, bool onlyDepth) {
shader->bind(); shader->bind();
glm::mat4 model = getModelMatrix(); glm::mat4 model = getModelMatrix();
@ -146,7 +155,7 @@ namespace nf {
m_constructed = false; m_constructed = false;
m_type = Type::STATIC; m_type = Type::STATIC;
m_position = Vec3(0.0); m_position = Vec3(0.0);
m_rotation = Vec4(0.0); m_rotation = degToQuat({ 0.0 });
m_scale = Vec3(1.0); m_scale = Vec3(1.0);
} }

View File

@ -12,14 +12,14 @@ namespace nf {
} }
void Light::create(const Vec3& position, const Vec3& color, double strength, Type type) { void Light::create(const Vec3& position, const Vec3& color, float strength, Type type) {
if (m_constructed) if (m_constructed)
Error("Light already created!"); Error("Light already created!");
m_constructed = true; m_constructed = true;
m_position = position; m_position = position;
m_color = color; m_color = color;
m_type = type; m_type = type;
m_strength = (float)strength; m_strength = strength;
if (!Application::getApp()->getCurrentState()->isRunning()) if (!Application::getApp()->getCurrentState()->isRunning())
Application::getApp()->getCurrentState()->m_nfObjects.push_back(this); Application::getApp()->getCurrentState()->m_nfObjects.push_back(this);
@ -37,8 +37,8 @@ namespace nf {
m_color = color; m_color = color;
} }
void Light::setStrength(double strength) { void Light::setStrength(float strength) {
m_strength = (float)strength; m_strength = strength;
} }
void Light::bind(Shader* shader, unsigned int lightNumber) { void Light::bind(Shader* shader, unsigned int lightNumber) {

View File

@ -179,8 +179,8 @@ namespace nf {
return dataSize; return dataSize;
} }
void Sound::setVolume(double volume) { void Sound::setVolume(float volume) {
m_volume = (float)volume; m_volume = volume;
} }
void Sound::setEntity(Entity& entity) { void Sound::setEntity(Entity& entity) {

View File

@ -17,18 +17,20 @@ namespace nf {
} }
void Text::create(const std::string& string, const Vec2& position, const Vec3& color, double opacity, double scale, Asset* font) { void Text::create(const std::string& string, const Vec2& position, const Vec3& color, float opacity, float scale, Asset* fontAsset) {
if (m_constructed) if (m_constructed)
Error("Text already created!"); Error("Text already created!");
m_constructed = true; m_constructed = true;
m_string = string; m_string = string;
m_position = position; m_position = position;
m_color = color; m_color = color;
m_scale = (float)scale; m_scale = scale;
m_opacity = (float)opacity; m_opacity = opacity;
AFont& newFont = *(AFont*)font; AFont* font;
if (newFont.alreadyLoaded) { if ((font = dynamic_cast<AFont*>(fontAsset)) == nullptr)
m_font = newFont.loadedFont; Error("Non-font asset passed to Text::create!");
if (font->alreadyLoaded) {
m_font = font->loadedFont;
} }
else { else {
m_font = new Font; m_font = new Font;
@ -36,7 +38,7 @@ namespace nf {
if (FT_Init_FreeType(&ft)) if (FT_Init_FreeType(&ft))
Error("Could not initialize FreeType!"); Error("Could not initialize FreeType!");
FT_Face face; FT_Face face;
if (FT_New_Memory_Face(ft, (const unsigned char*)newFont.data, (unsigned int)newFont.size, 0, &face)) if (FT_New_Memory_Face(ft, (const unsigned char*)font->data, (unsigned int)font->size, 0, &face))
Error("Could not load font!"); Error("Could not load font!");
FT_Set_Pixel_Sizes(face, 0, 160); FT_Set_Pixel_Sizes(face, 0, 160);
for (unsigned char c = 0; c < 128; c++) { for (unsigned char c = 0; c < 128; c++) {
@ -49,14 +51,14 @@ namespace nf {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
Character ch = { tex, Vec2((float)face->glyph->bitmap.width, (float)face->glyph->bitmap.rows), Vec2(face->glyph->bitmap_left, face->glyph->bitmap_top), (unsigned int)face->glyph->advance.x }; Character ch = { tex, Vec2((float)face->glyph->bitmap.width, (float)face->glyph->bitmap.rows), Vec2((float)face->glyph->bitmap_left, (float)face->glyph->bitmap_top), (unsigned int)face->glyph->advance.x };
m_font->m_characters[c] = ch; m_font->m_characters[c] = ch;
} }
FT_Done_Face(face); FT_Done_Face(face);
FT_Done_FreeType(ft); FT_Done_FreeType(ft);
newFont.alreadyLoaded = true; font->alreadyLoaded = true;
newFont.loadedFont = m_font; font->loadedFont = m_font;
m_font->isBase = newFont.isBaseAsset; m_font->isBase = font->isBaseAsset;
} }
m_vao = new VertexArray; m_vao = new VertexArray;
m_vao->addBuffer(nullptr, 0); m_vao->addBuffer(nullptr, 0);
@ -83,12 +85,12 @@ namespace nf {
m_color = color; m_color = color;
} }
void Text::setScale(double scale) { void Text::setScale(float scale) {
m_scale = (float)scale; m_scale = scale;
} }
void Text::setOpacity(double opacity) { void Text::setOpacity(float opacity) {
m_opacity = (float)opacity; m_opacity = opacity;
} }
const char* Text::identity() { const char* Text::identity() {
@ -99,7 +101,7 @@ namespace nf {
float scale = windowWidth / 4000.0f; float scale = windowWidth / 4000.0f;
if (onButton) if (onButton)
scale *= buttonWidth / 400.0f; scale *= buttonWidth / 400.0f;
float currX = (float)m_position.x * windowWidth, currY = (float)m_position.y * windowHeight; float currX = m_position.x * windowWidth, currY = m_position.y * windowHeight;
std::string::const_iterator si; std::string::const_iterator si;
if (m_centeredX || m_centeredY) { if (m_centeredX || m_centeredY) {
float textWidth = 0.0f; float textWidth = 0.0f;
@ -108,7 +110,7 @@ namespace nf {
Character& c = m_font->m_characters[*si]; Character& c = m_font->m_characters[*si];
textWidth += (c.advance >> 6) * scale * m_scale; textWidth += (c.advance >> 6) * scale * m_scale;
if (c.size.y >= textHeight) if (c.size.y >= textHeight)
textHeight = (float)c.size.y * scale * m_scale; textHeight = c.size.y * scale * m_scale;
} }
if (m_centeredX) if (m_centeredX)
currX = ((float)windowWidth - textWidth) / 2; currX = ((float)windowWidth - textWidth) / 2;
@ -123,11 +125,11 @@ namespace nf {
Character& c = m_font->m_characters[*si]; Character& c = m_font->m_characters[*si];
textWidth += (c.advance >> 6) * scale * m_scale; textWidth += (c.advance >> 6) * scale * m_scale;
if (c.size.y >= textHeight) if (c.size.y >= textHeight)
textHeight = (float)c.size.y * scale * m_scale; textHeight = c.size.y * scale * m_scale;
} }
} }
currX = (((float)buttonWidth - textWidth) / 2) + (float)buttonPos.x; currX = (((float)buttonWidth - textWidth) / 2) + buttonPos.x;
currY = (((float)buttonHeight - textHeight) / 2) + (float)buttonPos.y; currY = (((float)buttonHeight - textHeight) / 2) + buttonPos.y;
} }
} }
@ -136,10 +138,10 @@ namespace nf {
shader->setUniform("opacity", m_opacity); shader->setUniform("opacity", m_opacity);
for (si = m_string.begin(); si != m_string.end(); si++) { for (si = m_string.begin(); si != m_string.end(); si++) {
Character& c = m_font->m_characters[*si]; Character& c = m_font->m_characters[*si];
float x = currX + (float)c.bearing.x * scale * m_scale; float x = currX + c.bearing.x * scale * m_scale;
float y = currY - float(c.size.y - c.bearing.y) * scale * m_scale; float y = currY - float(c.size.y - c.bearing.y) * scale * m_scale;
float w = (float)c.size.x * scale * m_scale; float w = c.size.x * scale * m_scale;
float h = (float)c.size.y * scale * m_scale; float h = c.size.y * scale * m_scale;
float vb[] = { float vb[] = {
x, y + h, x, y + h,
x, y, x, y,

View File

@ -16,7 +16,7 @@ namespace nf {
} }
void UITexture::create(Asset* textureAsset, const Vec2& position, double scale, double opacity) { void UITexture::create(Asset* textureAsset, const Vec2& position, float scale, float opacity) {
if (m_constructed) if (m_constructed)
Error("UITexture already created!"); Error("UITexture already created!");
m_constructed = true; m_constructed = true;
@ -24,8 +24,8 @@ namespace nf {
if ((tex = dynamic_cast<ATexture*>(textureAsset)) == nullptr) if ((tex = dynamic_cast<ATexture*>(textureAsset)) == nullptr)
Error("Non-texture asset passed to UITexture::create!"); Error("Non-texture asset passed to UITexture::create!");
m_position = position; m_position = position;
m_scale = (float)scale; m_scale = scale;
m_opacity = (float)opacity; m_opacity = opacity;
if (tex->alreadyLoaded) { if (tex->alreadyLoaded) {
m_texture = tex->loadedTexture; m_texture = tex->loadedTexture;
} }
@ -57,21 +57,21 @@ namespace nf {
return "texture"; return "texture";
} }
void UITexture::setScale(double scale) { void UITexture::setScale(float scale) {
m_scale = (float)scale; m_scale = scale;
} }
void UITexture::setOpacity(double opacity) { void UITexture::setOpacity(float opacity) {
m_opacity = (float)opacity; m_opacity = opacity;
} }
void UITexture::render(Shader* shader, unsigned int windowWidth, unsigned int windowHeight) { void UITexture::render(Shader* shader, unsigned int windowWidth, unsigned int windowHeight) {
float posX = (float)m_position.x * windowWidth, posY = (float)m_position.y * windowHeight; float posX = m_position.x * windowWidth, posY = m_position.y * windowHeight;
float scale = windowWidth / 5.0f; float scale = windowWidth / 5.0f;
Vec2 texDim = m_texture->getDimensions(); Vec2 texDim = m_texture->getDimensions();
float height = scale * m_scale; float height = scale * m_scale;
float width = ((float)texDim.x / (float)texDim.y) * scale * m_scale; float width = (texDim.x / texDim.y) * scale * m_scale;
if (m_centeredX) if (m_centeredX)
posX = ((float)windowWidth - width) / 2; posX = ((float)windowWidth - width) / 2;
if (m_centeredY) if (m_centeredY)

View File

@ -2,6 +2,7 @@
#include "Application.h" #include "Application.h"
#include "Entity.h" #include "Entity.h"
#include "Model.h"
#include "Utility.h" #include "Utility.h"
//Remove this //Remove this
@ -21,14 +22,15 @@ namespace nf {
PhysicsEngine::PhysicsEngine(Application* app) : PhysicsEngine::PhysicsEngine(Application* app) :
m_app(app), m_app(app),
m_err(nullptr),
m_foundation(nullptr), m_foundation(nullptr),
m_pvd(nullptr), m_pvd(nullptr),
m_phy(nullptr), m_phy(nullptr),
m_cooking(nullptr), m_cooking(nullptr),
m_dispacher(nullptr), m_dispacher(nullptr),
m_defaultMat(nullptr),
m_scene(nullptr), m_scene(nullptr),
m_err(nullptr), m_stepSize(1.0f / 60.0f),
m_stepSize(1.0 / 60.0),
m_accumulator(0.0) m_accumulator(0.0)
{ {
m_err = new PhysicsErrorCallback; m_err = new PhysicsErrorCallback;
@ -50,7 +52,11 @@ namespace nf {
if (!m_cooking) if (!m_cooking)
Error("Could not initialize physics engine!"); Error("Could not initialize physics engine!");
m_dispacher = PxDefaultCpuDispatcherCreate(2); unsigned int threads = std::thread::hardware_concurrency() - 1;
if (threads < 0) threads = 0;
m_dispacher = PxDefaultCpuDispatcherCreate(threads);
m_defaultMat = m_phy->createMaterial(0.5f, 0.5f, 0.0f);
} }
void PhysicsEngine::newScene() { void PhysicsEngine::newScene() {
@ -68,47 +74,52 @@ namespace nf {
cli->setScenePvdFlag(PxPvdSceneFlag::eTRANSMIT_SCENEQUERIES, true); cli->setScenePvdFlag(PxPvdSceneFlag::eTRANSMIT_SCENEQUERIES, true);
} }
//TODO: Delete this //Ground plane at the very bottom (Is this a good position?)
PxMaterial* mat = m_phy->createMaterial(0.5f, 0.5f, 0.6f); PxRigidStatic* ground = PxCreatePlane(*m_phy, PxPlane(0, 1, 0, 200), *m_defaultMat);
PxRigidStatic* ground = PxCreatePlane(*m_phy, PxPlane(0, 1, 0, 0), *mat);
m_scene->addActor(*ground); m_scene->addActor(*ground);
} }
void PhysicsEngine::update(double dt) { void PhysicsEngine::update(float dt) {
//TODO: Remove this if (!m_scene || !m_scene->getNbActors(PxActorTypeFlag::eRIGID_DYNAMIC | PxActorTypeFlag::eRIGID_STATIC)) return;
static bool start = false;
if (m_app->isKeyPressed(NFI_ENTER))
start = true;
if (!start) return;
if (!m_scene->getNbActors(PxActorTypeFlag::eRIGID_DYNAMIC | PxActorTypeFlag::eRIGID_STATIC)) return; unsigned int count = m_scene->getNbActors(PxActorTypeFlag::eRIGID_DYNAMIC | PxActorTypeFlag::eRIGID_STATIC);
PxActor** actors = new PxActor*[count];
m_scene->getActors(PxActorTypeFlag::eRIGID_DYNAMIC | PxActorTypeFlag::eRIGID_STATIC, actors, count);
unsigned int count = m_scene->getNbActors(PxActorTypeFlag::eRIGID_DYNAMIC); if (m_app->isMouse(NFI_LEFTMOUSE)) {
PxActor** actors = new PxActor * [count];
m_scene->getActors(PxActorTypeFlag::eRIGID_DYNAMIC, actors, count);
//TODO: Add static actors here
if (m_app->isKeyPressed(NFI_F)) {
Vec3 pos = m_app->getCurrentState()->getCamera()->getPosition(); Vec3 pos = m_app->getCurrentState()->getCamera()->getPosition();
PxVec3 camPos((float)pos.x, (float)pos.y, (float)pos.z); PxVec3 camPos(pos.x, pos.y, pos.z);
PxQuat q(PxIdentity); PxQuat q(PxIdentity);
((PxRigidDynamic*)actors[0])->setGlobalPose(PxTransform(camPos, q)); ((PxRigidDynamic*)actors[1])->setGlobalPose(PxTransform(camPos, q));
Vec3 camDir = m_app->getCurrentState()->getCamera()->getRotation(); Vec3 camDir = m_app->getCurrentState()->getCamera()->getRotation();
float speed = 100.0f; float speed = 100.0f;
PxRigidBodyExt::updateMassAndInertia(*(PxRigidDynamic*)actors[0], 1000.0); PxRigidBodyExt::updateMassAndInertia(*(PxRigidDynamic*)actors[1], 1000.0);
((PxRigidDynamic*)actors[0])->setLinearVelocity(PxVec3((float)camDir.x * speed, (float)camDir.y* speed, (float)camDir.z * speed)); ((PxRigidDynamic*)actors[1])->setAngularVelocity(PxVec3(0.0));
((PxRigidDynamic*)actors[1])->setLinearVelocity(PxVec3(camDir.x * speed, camDir.y * speed, camDir.z * speed));
} }
for (unsigned int i = 0; i < count; i++) { //TODO: CHANGE THIS 1 TO A 0!!!!
for (unsigned int i = 1; i < count; i++) {
Entity* currEnt = (Entity*)actors[i]->userData; Entity* currEnt = (Entity*)actors[i]->userData;
if (!currEnt->needsPhysicsUpdate()) continue; if (!currEnt->needsPhysicsUpdate()) continue;
Vec3 pos = currEnt->getPosition(); Vec3 posTemp = currEnt->getPosition();
PxVec3 pos2((float)pos.x, (float)pos.y, (float)pos.z); PxVec3 pos(posTemp.x, posTemp.y, posTemp.z);
Vec4 quat = currEnt->getRotation(); Vec4 rotTemp = currEnt->getRotation();
PxQuat quat2(quat.x, quat.y, quat.z, quat.w); PxQuat rot(rotTemp.x, rotTemp.y, rotTemp.z, rotTemp.w);
((PxRigidDynamic*)actors[i])->setGlobalPose(PxTransform(pos2, quat2)); PxTransform t(pos, rot);
Vec3 scaleTemp = currEnt->getScale();
PxVec3 scaleTemp2(scaleTemp.x, scaleTemp.y, scaleTemp.z);
PxMeshScale scale(scaleTemp2);
if (currEnt->getType() == Entity::Type::DYNAMIC) {
updateEnt<PxRigidDynamic>(actors[i], t, scale);
}
else if (currEnt->getType() == Entity::Type::STATIC) {
updateEnt<PxRigidStatic>(actors[i], t, scale);
}
} }
delete[] actors; delete[] actors;
@ -116,12 +127,11 @@ namespace nf {
unsigned int stepCount = (unsigned int)(m_accumulator / m_stepSize); unsigned int stepCount = (unsigned int)(m_accumulator / m_stepSize);
m_accumulator -= stepCount * m_stepSize; m_accumulator -= stepCount * m_stepSize;
for (unsigned int i = 0; i < stepCount; i++) { for (unsigned int i = 0; i < stepCount; i++) {
m_scene->simulate((float)m_stepSize); m_scene->simulate(m_stepSize);
m_scene->fetchResults(true); m_scene->fetchResults(true);
} }
PxActor** actives = m_scene->getActiveActors(count); PxActor** actives = m_scene->getActiveActors(count);
//TODO: Kinematic actors?
for (unsigned int i = 0; i < count; i++) { for (unsigned int i = 0; i < count; i++) {
Entity& ent = *(Entity*)actives[i]->userData; Entity& ent = *(Entity*)actives[i]->userData;
PxTransform transform = ((PxRigidActor*)actives[i])->getGlobalPose(); PxTransform transform = ((PxRigidActor*)actives[i])->getGlobalPose();
@ -130,23 +140,79 @@ namespace nf {
} }
} }
void PhysicsEngine::addMesh(Model* model, std::vector<float>& vertices) {
PxConvexMeshDesc desc;
desc.points.count = (unsigned int)vertices.size() / 3;
desc.points.stride = 3 * sizeof(float);
desc.points.data = &vertices[0];
desc.flags = PxConvexFlag::eCOMPUTE_CONVEX;
PxDefaultMemoryOutputStream buf;
if (!m_cooking->cookConvexMesh(desc, buf))
Error("Could not create convex mesh!");
PxDefaultMemoryInputData in(buf.getData(), buf.getSize());
PxConvexMesh* mesh = m_phy->createConvexMesh(in);
m_meshes[model] = mesh;
}
void PhysicsEngine::addActor(Entity* entity) { void PhysicsEngine::addActor(Entity* entity) {
Entity::Type type = entity->getType(); Entity::Type type = entity->getType();
Vec3 pos = entity->getPosition(); //TODO: Materials system for physics; Default material if none provided
PxMaterial* mat = m_phy->createMaterial(0.5f, 0.5f, 0.0f); PxMaterial* mat;
PxRigidDynamic* act = PxCreateDynamic(*m_phy, PxTransform(PxVec3((float)pos.x, (float)pos.y, (float)pos.z)), PxBoxGeometry(1.0, 1.0, 1.0), *mat, 100.0f); mat = m_defaultMat;
//act->setRigidBodyFlag(PxRigidBodyFlag::eKINEMATIC, true); float density = 100.0f;
act->userData = entity;
m_scene->addActor(*act); //Get mesh
if (m_meshes.find(entity->getModel()) == m_meshes.end())
Error("No physics mesh found for this entity!");
PxConvexMesh* mesh = m_meshes[entity->getModel()];
//Dynamic or static
if (type == Entity::Type::DYNAMIC) {
PxRigidDynamic* act = PxCreateDynamic(*m_phy, PxTransform(PxIdentity), PxConvexMeshGeometry(mesh), *mat, density);
act->userData = entity;
m_scene->addActor(*act);
}
else if (type == Entity::Type::STATIC) {
PxRigidStatic* act = PxCreateStatic(*m_phy, PxTransform(PxIdentity), PxConvexMeshGeometry(mesh), *mat);
act->userData = entity;
m_scene->addActor(*act);
}
} }
void PhysicsEngine::closeScene() { void PhysicsEngine::closeScene() {
m_scene->release(); if (m_scene) {
m_scene = nullptr; //Does this actually release all of them? Only if the respective shapes have been released?
for (auto it = m_meshes.begin(); it != m_meshes.end();) {
if (!it->first->isBaseAsset()) {
it->second->release();
it = m_meshes.erase(it);
}
else
it++;
}
m_scene->release();
m_scene = nullptr;
}
}
template<typename ActorType>
void PhysicsEngine::updateEnt(PxActor* act, PxTransform& transform, PxMeshScale& scale) {
((ActorType*)act)->setGlobalPose(transform);
PxShape** shape = new PxShape*;
((ActorType*)act)->getShapes(shape, sizeof(shape));
PxGeometryHolder holder = shape[0]->getGeometry();
holder.convexMesh().scale = scale;
shape[0]->setGeometry(holder.convexMesh());
delete shape;
} }
PhysicsEngine::~PhysicsEngine() { PhysicsEngine::~PhysicsEngine() {
closeScene();
m_dispacher->release();
m_cooking->release(); m_cooking->release();
m_phy->release(); m_phy->release();
if (m_pvd) { if (m_pvd) {

View File

@ -31,31 +31,31 @@ namespace nf {
return m_type; return m_type;
} }
void Camera::moveForward(double speed) { void Camera::moveForward(float speed) {
Vec3 temp = m_front * speed; Vec3 temp = m_front * speed;
m_position += temp; m_position += temp;
} }
void Camera::moveBackward(double speed) { void Camera::moveBackward(float speed) {
Vec3 temp = m_front * speed; Vec3 temp = m_front * speed;
m_position -= temp; m_position -= temp;
} }
void Camera::moveRight(double speed) { void Camera::moveRight(float speed) {
glm::vec3 front = { m_front.x, m_front.y, m_front.z }; 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))) * (float)speed; 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 }; Vec3 move = { temp.x, temp.y, temp.z };
m_position += move; m_position += move;
} }
void Camera::moveLeft(double speed) { void Camera::moveLeft(float speed) {
glm::vec3 front = { m_front.x, m_front.y, m_front.z }; 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))) * (float)speed; 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 }; Vec3 move = { temp.x, temp.y, temp.z };
m_position -= move; m_position -= move;
} }
void Camera::setPosition(double x, double y, double z) { void Camera::setPosition(float x, float y, float z) {
m_position = { x, y, z }; m_position = { x, y, z };
} }
@ -67,6 +67,16 @@ namespace nf {
return m_position; return m_position;
} }
void Camera::setRotation(float x, float y) {
m_yaw = x - 90.0f;
m_pitch = y;
}
void Camera::setRotation(const Vec2& rotation) {
m_yaw = rotation.x - 90.0f;
m_pitch = rotation.y;
}
const Vec3& Camera::getRotation() { const Vec3& Camera::getRotation() {
return m_front; return m_front;
} }
@ -83,7 +93,7 @@ namespace nf {
int mouseDiffx = 0; int mouseDiffx = 0;
int mouseDiffy = 0; int mouseDiffy = 0;
m_app->getMouseDiff(mouseDiffx, mouseDiffy); m_app->getMouseDiff(mouseDiffx, mouseDiffy);
float mouseX = (float)mouseDiffx * 0.1f; //TODO: Mouse sensitivity float mouseX = (float)mouseDiffx * 0.1f; //TODO: Custom mouse sensitivity
float mouseY = (float)mouseDiffy * 0.1f; float mouseY = (float)mouseDiffy * 0.1f;
m_yaw += mouseX; m_yaw += mouseX;
m_pitch += mouseY; m_pitch += mouseY;

View File

@ -12,7 +12,7 @@
#include "Utility.h" #include "Utility.h"
namespace nf { namespace nf {
Model::Model(AModel* model) : Model::Model(AModel* model, bool physicsExport) :
m_base(model->isBaseAsset) m_base(model->isBaseAsset)
{ {
if (model->neededTextures.size() > 32) if (model->neededTextures.size() > 32)
@ -143,7 +143,7 @@ namespace nf {
} }
size_t pos = file.find(line) + strlen(line) + remove; size_t pos = file.find(line) + strlen(line) + remove;
file = file.substr(pos); file.erase(0, pos);
} }
if (!tcPresent) if (!tcPresent)
@ -276,7 +276,7 @@ namespace nf {
normA = model->neededTextures[curr2.normalTextureName]; normA = model->neededTextures[curr2.normalTextureName];
norm = new Texture(normA, true); norm = new Texture(normA, true);
} }
m_materials.push_back(std::make_tuple(diff, spec, norm, (float)curr2.diffuseColor.x, (float)curr2.diffuseColor.y, (float)curr2.diffuseColor.z, curr2.shininess)); m_materials.push_back(std::make_tuple(diff, spec, norm, curr2.diffuseColor.x, curr2.diffuseColor.y, curr2.diffuseColor.z, curr2.shininess));
size_t offset = vboPositions.size() / 3; size_t offset = vboPositions.size() / 3;
vboPositions.insert(vboPositions.end(), curr2.outVB.begin(), curr2.outVB.end()); vboPositions.insert(vboPositions.end(), curr2.outVB.begin(), curr2.outVB.end());
vboTexCoords.insert(vboTexCoords.end(), curr2.outTC.begin(), curr2.outTC.end()); vboTexCoords.insert(vboTexCoords.end(), curr2.outTC.begin(), curr2.outTC.end());
@ -308,6 +308,9 @@ namespace nf {
m_vao->pushInt(1); m_vao->pushInt(1);
m_vao->finishBufferLayout(); m_vao->finishBufferLayout();
m_ib = new IndexBuffer(&vboIndices[0], vboIndices.size()); m_ib = new IndexBuffer(&vboIndices[0], vboIndices.size());
if (physicsExport)
Application::getApp()->getPhysicsEngine()->addMesh(this, vboPositions);
} }
void Model::render(Shader* shader, bool onlyDepth, unsigned int count) { void Model::render(Shader* shader, bool onlyDepth, unsigned int count) {

View File

@ -117,7 +117,7 @@ namespace nf {
m_quadVAO->pushFloat(2); m_quadVAO->pushFloat(2);
m_quadVAO->finishBufferLayout(); m_quadVAO->finishBufferLayout();
m_quadIB = new IndexBuffer(quadIB, 6); m_quadIB = new IndexBuffer(quadIB, 6);
m_loadingText.create("NFLoadingText", Vec2(0.025, 0.044), Vec3(0.7, 0.7, 0.7)); m_loadingText.create("NFLoadingText", Vec2(0.025f, 0.044f), Vec3(0.7f));
} }
void Renderer::setFade(bool in, bool out, bool noText) { void Renderer::setFade(bool in, bool out, bool noText) {
@ -152,7 +152,7 @@ namespace nf {
m_cubemap = &in; m_cubemap = &in;
} }
void Renderer::doFrame(Camera* camera, double dT) { void Renderer::doFrame(Camera* camera, float dT) {
//Begin frame //Begin frame
glBindFramebuffer(GL_FRAMEBUFFER, 0); glBindFramebuffer(GL_FRAMEBUFFER, 0);
glViewport(0, 0, m_app->getConfig().width, m_app->getConfig().height); glViewport(0, 0, m_app->getConfig().width, m_app->getConfig().height);
@ -239,8 +239,8 @@ namespace nf {
//Fade over everything when states change //Fade over everything when states change
if (m_fadeIn) { if (m_fadeIn) {
static double opacity = 1.0; static float opacity = 1.0f;
m_fadeShader->setUniform("opacity", (float)opacity); m_fadeShader->setUniform("opacity", opacity);
m_quadVAO->bind(); m_quadVAO->bind();
m_quadIB->bind(); m_quadIB->bind();
glDrawElements(GL_TRIANGLES, m_quadIB->getCount(), GL_UNSIGNED_INT, nullptr); glDrawElements(GL_TRIANGLES, m_quadIB->getCount(), GL_UNSIGNED_INT, nullptr);
@ -249,9 +249,9 @@ namespace nf {
m_loadingText.setOpacity(opacity); m_loadingText.setOpacity(opacity);
m_loadingText.render(m_textShader, m_app->getConfig().width, m_app->getConfig().height); m_loadingText.render(m_textShader, m_app->getConfig().width, m_app->getConfig().height);
} }
if (dT > 1.0 / 60.0) if (dT > 1.0f / 60.0f)
dT = 1.0 / 60.0; dT = 1.0f / 60.0f;
opacity -= 2.5 * dT; opacity -= 2.5f * dT;
if (opacity <= 0.0) { if (opacity <= 0.0) {
m_fadeIn = false; m_fadeIn = false;
opacity = 1.0; opacity = 1.0;
@ -259,8 +259,8 @@ namespace nf {
} }
} }
else if (m_fadeOut) { else if (m_fadeOut) {
static double opacity = 0.0; static float opacity = 0.0f;
m_fadeShader->setUniform("opacity", (float)opacity); m_fadeShader->setUniform("opacity", opacity);
m_quadVAO->bind(); m_quadVAO->bind();
m_quadIB->bind(); m_quadIB->bind();
glDrawElements(GL_TRIANGLES, m_quadIB->getCount(), GL_UNSIGNED_INT, nullptr); glDrawElements(GL_TRIANGLES, m_quadIB->getCount(), GL_UNSIGNED_INT, nullptr);
@ -269,7 +269,7 @@ namespace nf {
m_loadingText.setOpacity(opacity); m_loadingText.setOpacity(opacity);
m_loadingText.render(m_textShader, m_app->getConfig().width, m_app->getConfig().height); m_loadingText.render(m_textShader, m_app->getConfig().width, m_app->getConfig().height);
} }
opacity += 3.0 * dT; opacity += 3.0f * dT;
if (opacity >= 1.0) { if (opacity >= 1.0) {
m_fadeIn = false; m_fadeIn = false;
opacity = 0.0; opacity = 0.0;
@ -444,6 +444,7 @@ namespace nf {
delete m_cubemapShader; delete m_cubemapShader;
delete m_fadeShader; delete m_fadeShader;
delete m_directionalShadowShader; delete m_directionalShadowShader;
delete m_pointShadowShader;
delete m_gBuffer; delete m_gBuffer;
delete m_quadVAO; delete m_quadVAO;
delete m_quadIB; delete m_quadIB;

View File

@ -13,7 +13,7 @@ namespace nf {
return "none"; return "none";
} }
void UIElement::setPosition(double x, double y) { void UIElement::setPosition(float x, float y) {
m_position = Vec2(x, y); m_position = Vec2(x, y);
} }
void UIElement::setPosition(const Vec2& position) { void UIElement::setPosition(const Vec2& position) {

View File

@ -13,7 +13,7 @@
namespace nf { namespace nf {
static DECOMPRESSOR_HANDLE s_dHandle; static DECOMPRESSOR_HANDLE s_dHandle;
static const double deg2rad = M_PI / 180.0f; static const float deg2rad = (float)M_PI / 180.0f;
#ifdef _DEBUG #ifdef _DEBUG
void Debug::LogImp(const char* in) { void Debug::LogImp(const char* in) {
@ -32,7 +32,7 @@ namespace nf {
std::printf("[%.4f] Debug: %i\n", time.count(), in); std::printf("[%.4f] Debug: %i\n", time.count(), in);
} }
void Debug::LogImp(double in) { void Debug::LogImp(float in) {
std::chrono::duration<float> time = getCurrentTime(); std::chrono::duration<float> time = getCurrentTime();
std::printf("[%.4f] Debug: %.4f\n", time.count(), in); std::printf("[%.4f] Debug: %.4f\n", time.count(), in);
} }
@ -83,19 +83,19 @@ namespace nf {
Vec4 degToQuat(const Vec3& in) { Vec4 degToQuat(const Vec3& in) {
float outX, outY, outZ, outW; float outX, outY, outZ, outW;
float cy = (float)std::cos(in.z * deg2rad * 0.5); float cy = std::cosf(in.z * deg2rad / 2);
float sy = (float)std::sin(in.z * deg2rad * 0.5); float sy = std::sinf(in.z * deg2rad / 2);
float cp = (float)std::cos(in.y * deg2rad * 0.5); float cp = std::cosf(in.y * deg2rad / 2);
float sp = (float)std::sin(in.y * deg2rad * 0.5); float sp = std::sinf(in.y * deg2rad / 2);
float cr = (float)std::cos(in.x * deg2rad * 0.5); float cr = std::cosf(in.x * deg2rad / 2);
float sr = (float)std::sin(in.x * deg2rad * 0.5); float sr = std::sinf(in.x * deg2rad / 2);
outW = cr * cp * cy + sr * sp * sy; outW = cr * cp * cy + sr * sp * sy;
outX = sr * cp * cy - cr * sp * sy; outX = sr * cp * cy - cr * sp * sy;
outY = cr * sp * cy + sr * cp * sy; outY = cr * sp * cy + sr * cp * sy;
outZ = cr * cp * sy - sr * sp * cy; outZ = cr * cp * sy - sr * sp * cy;
return {outX, outY, outZ, outW}; return { outX, outY, outZ, outW };
} }
void writeFile(const std::string& filename, const std::string& in, bool encrypted) { void writeFile(const std::string& filename, const std::string& in, bool encrypted) {

View File

@ -71,12 +71,12 @@ namespace nf {
LONG m_defaultWindowStyle; LONG m_defaultWindowStyle;
unsigned int m_altWidth, m_altHeight; unsigned int m_altWidth, m_altHeight;
std::chrono::duration<double> m_fpsDuration; std::chrono::duration<float> m_fpsDuration;
double m_deltaTime; float m_deltaTime;
std::chrono::steady_clock::time_point m_fpsClock1 = std::chrono::steady_clock::now(); std::chrono::steady_clock::time_point m_fpsClock1 = std::chrono::steady_clock::now();
std::chrono::steady_clock::time_point m_fpsClock2 = m_fpsClock1; std::chrono::steady_clock::time_point m_fpsClock2 = m_fpsClock1;
const int m_targetFPS = 60; const int m_targetFPS = 60;
const double m_minFrametime = 1.0 / m_targetFPS; const float m_minFrametime = 1.0f / m_targetFPS;
int m_FPS; int m_FPS;
//Inactive states to potentially be active during the Application's lifetime //Inactive states to potentially be active during the Application's lifetime
@ -87,6 +87,7 @@ namespace nf {
Gamestate* m_currentState; Gamestate* m_currentState;
bool m_stateChange; bool m_stateChange;
std::string m_nextState; std::string m_nextState;
bool m_stateChangeStarted;
//Array of booleans that represent keyboard and mouse input minus the scrollwheel //Array of booleans that represent keyboard and mouse input minus the scrollwheel
std::array<bool, 164> m_keysPressed; std::array<bool, 164> m_keysPressed;

View File

@ -14,7 +14,7 @@ namespace nf {
public: public:
Button(); Button();
void create(const Vec2& position, std::string string = "", Asset* buttonAsset = nf::BaseAssets::button, double scale = 1.0, double opacity = 1.0); void create(const Vec2& position, std::string string = "", Asset* buttonAsset = nf::BaseAssets::button, float scale = 1.0f, float opacity = 1.0f);
const char* identity() override; const char* identity() override;
void render(Shader* shader, unsigned int windowWidth, unsigned int windowHeight, Application* app, Shader* textShader); void render(Shader* shader, unsigned int windowWidth, unsigned int windowHeight, Application* app, Shader* textShader);
bool isClicked(); bool isClicked();

View File

@ -18,13 +18,15 @@ namespace nf {
void setType(Type cameraType); void setType(Type cameraType);
Type getType() const; Type getType() const;
void moveForward(double speed); void moveForward(float speed);
void moveBackward(double speed); void moveBackward(float speed);
void moveRight(double speed); void moveRight(float speed);
void moveLeft(double speed); void moveLeft(float speed);
void setPosition(double x, double y, double z); void setPosition(float x, float y, float z);
void setPosition(const Vec3& position); void setPosition(const Vec3& position);
const Vec3& getPosition(); const Vec3& getPosition();
void setRotation(float x, float y);
void setRotation(const Vec2& rotation);
const Vec3& getRotation(); const Vec3& getRotation();
void bind(Shader* gBufferShader, Shader* lightingShader, Shader* cubemapShader); void bind(Shader* gBufferShader, Shader* lightingShader, Shader* cubemapShader);

View File

@ -17,28 +17,29 @@ namespace nf {
DYNAMIC, DYNAMIC,
DETAIL DETAIL
}; };
Entity(); Entity();
void create(Asset* modelAsset, Type type = Type::STATIC); void create(Asset* modelAsset, Type type = Type::STATIC);
bool isConstructed(); bool isConstructed();
void setType(Type type);
Type getType(); Type getType();
void setPosition(double x, double y, double z); void setPosition(float x, float y, float z);
void setPosition(const Vec3& position); void setPosition(const Vec3& position);
void setPositionPhysics(const Vec3& position); void setPositionPhysics(const Vec3& position);
void setRotation(double x, double y, double z); void setRotation(float x, float y, float z);
void setRotation(const Vec3& rotation); void setRotation(const Vec3& rotation);
void setRotationPhysics(const Vec4& rotation); void setRotationPhysics(const Vec4& rotation);
void setScale(double x); void setScale(float x);
void setScale(double x, double y, double z); void setScale(float x, float y, float z);
void setScale(const Vec3& scale); void setScale(const Vec3& scale);
bool needsPhysicsUpdate(); bool needsPhysicsUpdate();
const Vec3& getPosition(); const Vec3& getPosition();
const Vec4& getRotation(); const Vec4& getRotation();
const Vec3& getScale();
void render(Shader* shader, bool onlyDepth); void render(Shader* shader, bool onlyDepth);
Model* getModel() const; Model* getModel() const;
#ifdef NFENGINE #ifdef NFENGINE
@ -48,6 +49,7 @@ namespace nf {
~Entity(); ~Entity();
private: private:
bool m_constructed; bool m_constructed;
bool m_createdAtLoad;
Type m_type; Type m_type;
Model* m_model; Model* m_model;

View File

@ -9,6 +9,7 @@ namespace nf {
class Application; class Application;
class Renderer; class Renderer;
class Camera; class Camera;
class Entity;
class Model; class Model;
class Texture; class Texture;
@ -20,9 +21,10 @@ namespace nf {
virtual void onEnter(); virtual void onEnter();
bool isRunning(); bool isRunning();
void run(Application* app); bool isLoading();
void run(Application* app, bool physics = true);
virtual void update(double deltaTime); virtual void update(float deltaTime);
Camera* getCamera(); Camera* getCamera();
virtual void render(Renderer& renderer); virtual void render(Renderer& renderer);
@ -30,11 +32,13 @@ namespace nf {
void stop(); void stop();
std::vector<NFObject*> m_nfObjects; std::vector<NFObject*> m_nfObjects;
std::vector<Entity*> m_entsToDelete;
std::unordered_set<Model*> m_modelsToDelete; std::unordered_set<Model*> m_modelsToDelete;
std::unordered_set<Texture*> m_texturesToDelete; std::unordered_set<Texture*> m_texturesToDelete;
protected: protected:
Application* app; Application* app;
Camera* camera; Camera* camera;
bool m_loading;
bool m_running; bool m_running;
}; };
} }

View File

@ -9,12 +9,14 @@ namespace nf {
public: public:
void onEnter() override; void onEnter() override;
void update(double deltaTime) override; void update(float deltaTime) override;
void render(Renderer& renderer) override; void render(Renderer& renderer) override;
void onExit() override; void onExit() override;
private: private:
std::chrono::steady_clock::time_point m_start; std::chrono::steady_clock::time_point m_start;
unsigned int m_frame;
float m_scale;
UITexture m_logoTex; UITexture m_logoTex;
Text m_text; Text m_text;
}; };

View File

@ -13,11 +13,11 @@ namespace nf {
}; };
Light(); Light();
void create(const Vec3& position, const Vec3& color, double strength = 1.0, Type type = Type::POINT); void create(const Vec3& position, const Vec3& color, float strength = 1.0f, Type type = Type::POINT);
bool isConstructed(); bool isConstructed();
void setPosition(const Vec3& position); void setPosition(const Vec3& position);
void setColor(const Vec3& color); void setColor(const Vec3& color);
void setStrength(double strength); void setStrength(float strength);
void bind(Shader* shader, unsigned int lightNumber); void bind(Shader* shader, unsigned int lightNumber);

View File

@ -6,10 +6,11 @@
namespace nf { namespace nf {
class Texture; class Texture;
class Shader; class Shader;
struct TempMaterial;
class Model : public Drawable { class Model : public Drawable {
public: public:
Model(AModel* model); Model(AModel* model, bool physicsExport);
void render(Shader* shader, bool onlyDepth, unsigned int count); void render(Shader* shader, bool onlyDepth, unsigned int count);
void bindMaterials(Shader* shader); void bindMaterials(Shader* shader);
@ -18,6 +19,8 @@ namespace nf {
~Model(); ~Model();
private: private:
void parseMaterials(std::unordered_map<std::string, TempMaterial*>& mats, std::string& mtl);
bool m_base; bool m_base;
std::vector<std::tuple<Texture*, Texture*, Texture*, float, float, float, float>> m_materials; std::vector<std::tuple<Texture*, Texture*, Texture*, float, float, float, float>> m_materials;
const std::string m_hasDiffString = "hasDiffuseTex["; const std::string m_hasDiffString = "hasDiffuseTex[";

View File

@ -1,4 +1,5 @@
#pragma once #pragma once
#include <unordered_map>
#include <PxConfig.h> #include <PxConfig.h>
#include <PxPhysicsAPI.h> #include <PxPhysicsAPI.h>
@ -7,32 +8,37 @@ using namespace physx;
namespace nf { namespace nf {
class Application; class Application;
class Entity; class Entity;
class Model;
class PhysicsEngine { class PhysicsEngine {
public: public:
PhysicsEngine(Application* app); PhysicsEngine(Application* app);
void newScene(); void newScene();
void update(double dt); void update(float dt);
void addMesh(Model* model, std::vector<float>& vertices);
void addActor(Entity* entity); void addActor(Entity* entity);
void closeScene(); void closeScene();
~PhysicsEngine(); ~PhysicsEngine();
private: private:
template<typename ActorType>
void updateEnt(PxActor* act, PxTransform& transform, PxMeshScale& scale);
Application* m_app; Application* m_app;
PxDefaultAllocator m_alloc;
PxErrorCallback* m_err;
PxFoundation* m_foundation; PxFoundation* m_foundation;
PxPvd* m_pvd; PxPvd* m_pvd;
PxPvdTransport* m_transport; PxPvdTransport* m_transport;
PxPhysics* m_phy; PxPhysics* m_phy;
PxCooking* m_cooking; PxCooking* m_cooking;
PxCpuDispatcher* m_dispacher; PxDefaultCpuDispatcher* m_dispacher;
PxMaterial* m_defaultMat;
PxScene* m_scene; PxScene* m_scene;
std::unordered_map<Model*, PxConvexMesh*> m_meshes;
PxDefaultAllocator m_alloc; const float m_stepSize;
PxErrorCallback* m_err; float m_accumulator;
const double m_stepSize;
double m_accumulator;
}; };
} }

View File

@ -29,7 +29,7 @@ namespace nf {
void render(Light& in); void render(Light& in);
void render(Cubemap& in); void render(Cubemap& in);
void doFrame(Camera* camera, double dT); void doFrame(Camera* camera, float dT);
~Renderer(); ~Renderer();
private: private:

View File

@ -12,7 +12,7 @@ namespace nf {
Sound(); Sound();
void create(Asset* soundAsset); void create(Asset* soundAsset);
void setVolume(double volume); void setVolume(float volume);
void setEntity(Entity& entity); void setEntity(Entity& entity);
void setPosition(const Vec3& position); void setPosition(const Vec3& position);
void play(bool loop = false); void play(bool loop = false);

View File

@ -23,12 +23,12 @@ namespace nf {
public: public:
Text(); 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::font); 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; const char* identity() override;
void setText(const std::string& string); void setText(const std::string& string);
void setColor(const Vec3& color); void setColor(const Vec3& color);
void setScale(double scale); void setScale(float scale);
void setOpacity(double opacity); void setOpacity(float opacity);
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 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; void destroy() override;

View File

@ -11,7 +11,7 @@ namespace nf {
UIElement(); UIElement();
virtual const char* identity(); virtual const char* identity();
void setPosition(double x, double y); void setPosition(float x, float y);
void setPosition(const Vec2& position); void setPosition(const Vec2& position);
void centered(bool x, bool y = false); void centered(bool x, bool y = false);
bool isConstructed(); bool isConstructed();

View File

@ -11,10 +11,10 @@ namespace nf {
public: public:
UITexture(); UITexture();
void create(Asset* textureAsset, const Vec2& position, double scale = 1.0, double opacity = 1.0); void create(Asset* textureAsset, const Vec2& position, float scale = 1.0f, float opacity = 1.0f);
const char* identity() override; const char* identity() override;
void setScale(double scale); void setScale(float scale);
void setOpacity(double opacity); void setOpacity(float opacity);
void render(Shader* shader, unsigned int windowWidth, unsigned int windowHeight) override; void render(Shader* shader, unsigned int windowWidth, unsigned int windowHeight) override;
void destroy() override; void destroy() override;

View File

@ -28,7 +28,7 @@ __debugbreak();}
static void LogImp(const char* in); static void LogImp(const char* in);
static void LogImp(const std::string& in); static void LogImp(const std::string& in);
static void LogImp(int in); static void LogImp(int in);
static void LogImp(double in); static void LogImp(float in);
static void ErrorImp(const char* in, const char* filename, int line); static void ErrorImp(const char* in, const char* filename, int line);
static void ErrorImp(const std::string& in, const char* filename, int line); static void ErrorImp(const std::string& in, const char* filename, int line);
}; };
@ -41,9 +41,14 @@ std::exit(-1);}
#endif #endif
struct Vec2 { struct Vec2 {
Vec2() : x(0.0), y(0.0) {} Vec2() : x(0.0), y(0.0) {}
Vec2(double x1) : x(x1), y(x1) {} Vec2(float x1) : x(x1), y(x1) {}
Vec2(double x1, double y1) : x(x1), y(y1) {} Vec2(float x1, float y1) : x(x1), y(y1) {}
Vec2 operator*(const double scalar) { Vec2(double x1) : x((float)x1), y((float)x1) {}
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 float scalar) const {
return Vec2(x * scalar, y * scalar); return Vec2(x * scalar, y * scalar);
} }
Vec2& operator+=(const Vec2& rhs) { Vec2& operator+=(const Vec2& rhs) {
@ -59,13 +64,18 @@ std::exit(-1);}
bool operator==(const Vec2& rhs) { bool operator==(const Vec2& rhs) {
return this->x == rhs.x && this->y == rhs.y; return this->x == rhs.x && this->y == rhs.y;
} }
double x, y; float x, y;
}; };
struct Vec3 { struct Vec3 {
Vec3() : x(0.0), y(0.0), z(0.0) {} Vec3() : x(0.0), y(0.0), z(0.0) {}
Vec3(double x1) : x(x1), y(x1), z(x1) {} Vec3(float x1) : x(x1), y(x1), z(x1) {}
Vec3(double x1, double y1, double z1) : x(x1), y(y1), z(z1) {} Vec3(float x1, float y1, float z1) : x(x1), y(y1), z(z1) {}
Vec3 operator*(const double scalar) { Vec3(double x1) : x((float)x1), y((float)x1), z((float)x1) {}
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 float scalar) const {
return Vec3(x * scalar, y * scalar, z * scalar); return Vec3(x * scalar, y * scalar, z * scalar);
} }
Vec3& operator+=(const Vec3& rhs) { Vec3& operator+=(const Vec3& rhs) {
@ -83,13 +93,18 @@ std::exit(-1);}
bool operator==(const Vec3& rhs) { bool operator==(const Vec3& rhs) {
return this->x == rhs.x && this->y == rhs.y && this->z == rhs.z ; return this->x == rhs.x && this->y == rhs.y && this->z == rhs.z ;
} }
double x, y, z; float x, y, z;
}; };
struct Vec4 { struct Vec4 {
Vec4() : x(0.0), y(0.0), z(0.0), w(0.0) {} Vec4() : x(0.0), y(0.0), z(0.0), w(0.0) {}
Vec4(float x1) : x(x1), y(x1), z(x1), w(x1) {} Vec4(float x1) : x(x1), y(x1), z(x1), w(x1) {}
Vec4(float x1, float y1, float z1, float w1) : x(x1), y(y1), z(z1), w(w1) {} Vec4(float x1, float y1, float z1, float w1) : x(x1), y(y1), z(z1), w(w1) {}
Vec4 operator*(const float scalar) { Vec4(double x1) : x((float)x1), y((float)x1), z((float)x1), w((float)x1) {}
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 float scalar) const {
return Vec4(x * scalar, y * scalar, z * scalar, w * scalar); return Vec4(x * scalar, y * scalar, z * scalar, w * scalar);
} }
Vec4& operator+=(const Vec4& rhs) { Vec4& operator+=(const Vec4& rhs) {