diff --git a/engine b/engine index 0bc85f8..ab5cef7 160000 --- a/engine +++ b/engine @@ -1 +1 @@ -Subproject commit 0bc85f8c8e70056c1efbb378df8dfd64e1391215 +Subproject commit ab5cef765e0f458928c6c3f6d8b09ea06f636786 diff --git a/main.cpp b/main.cpp index 2dc44a9..55024dd 100644 --- a/main.cpp +++ b/main.cpp @@ -1,53 +1,189 @@ +#include +#include + #include "engine.hpp" static int SCR_HEIGHT = 600; static int SCR_WIDTH = 800; -const char *cubeSource = "/cube2.obj"; -const char *catSource = "/cat.obj"; -const char *benchSource = "/bench.obj"; - const char *vertexShaderSource = "/vertex/standart.vshader"; const char *fragmentShaderSource = "/fragment/standart.fshader"; +const char *cubeSource = "/cube.obj"; + +class MovingBall : public Object { + private: + float MIN_VELOCITY = 0.001; + public: + Vec3 velocity; + float bounciness = 1; + float friction = 0; + + void Update(float dt) override { + transform->Translate(velocity * dt); + // transform->Rotate(length(velocity) * dt / transform->GetScale().x / 2, direction); + velocity *= pow(1 - friction, dt); + if (length(velocity) < MIN_VELOCITY) { + velocity = Vec3(0, 0, 0); + } + } + + MovingBall(Vec3 position, ShaderProgram * shaderProgram, + std::string diffuseSource, std::string specularSource = "") { + this->renderData = new RenderData(); + this->renderData->model = Model::GetSphere(); + this->renderData->model->shader = shaderProgram; + + auto images = std::vector(); + images.push_back(diffuseSource); + if (specularSource != "") { + images.push_back(specularSource); + } + this->renderData->material = { + 4.f, + Texture(images), + }; + + bindRenderData(this->renderData); -Object* initModel(); + this->collider = new Collider{Sphere{ + Vec3(0.0), + 1.0f, + }}; + + transform = new Transform(position, Vec3(1., 1., 1.), Mat4(1.0)); + } +}; + +class GameManager : public Object { + public: + std::vector balls; + float minX = -7, maxX = 7, minZ = -7, maxZ = 7; + + void Update(float dt) override { + for (int i = 0; i < balls.size(); ++i) { + auto ball = balls[i]; + Vec3 pos = ball->transform->GetTranslation(); + if (pos.x < minX) { + ball->transform->Translate((1 + ball->bounciness) * Vec3(minX - pos.x, 0, 0)); + ball->velocity = Vec3(- ball->velocity.x, 0, ball->velocity.z) * ball->bounciness; + } + if (pos.x > maxX) { + ball->transform->Translate((1 + ball->bounciness) * Vec3(maxX - pos.x, 0, 0)); + ball->velocity = Vec3(- ball->velocity.x, 0, ball->velocity.z) * ball->bounciness; + } + if (pos.z < minZ) { + ball->transform->Translate((1 + ball->bounciness) * Vec3(0, 0, minZ - pos.z)); + ball->velocity = Vec3(ball->velocity.x, 0, - ball->velocity.z) * ball->bounciness; + } + if (pos.z > maxZ) { + ball->transform->Translate((1 + ball->bounciness) * Vec3(0, 0, maxZ - pos.z)); + ball->velocity = Vec3(ball->velocity.x, 0, - ball->velocity.z) * ball->bounciness; + } + for (int j = i + 1; j < balls.size(); ++j) { + auto ball2 = balls[j]; + if (ball->collider->Collide(*ball->transform, ball2->collider, *ball2->transform)) { + // collision + Vec3 pos2 = ball2->transform->GetTranslation(); + Vec3 center = (pos + pos2) * 0.5f; // collision point + Vec3 speed = ball->velocity - ball2->velocity; // approach speed of 2 balls + Vec3 v = pos - center; // vector towards center of collision + float dotProduct = speed.x * v.x + speed.z * v.z; + float proj = dotProduct / length(v); // projection of speed vector on collision line + Vec3 impulseChange = normalize(v) * proj * (1 + ball->bounciness * ball2->bounciness); + ball->velocity -= impulseChange * 0.5f; + ball2->velocity += impulseChange * 0.5f; + ball->transform->Translate(v * (ball->transform->GetScale().x / length(v) - 1)); + ball2->transform->Translate(v * (1 - ball2->transform->GetScale().x / length(v))); + } + } + } + } + explicit GameManager(std::vector balls) { + this->balls = balls; + } +}; + +MovingBall *newBall(Vec3 position, Vec3 velocity, + ShaderProgram *sp, std::string diffuseSource, std::string specularSource); + +void initLight(Engine& engine); int main() { auto engine = Engine(SCR_WIDTH, SCR_HEIGHT); - Object* testObj = initModel(); - engine.AddObject<>(testObj); - engine.Run(SCR_WIDTH, SCR_HEIGHT); -} -Object* initModel() { - // build and compile our shader program ------------------------------------ Shader vShader = Shader(VertexShader, vertexShaderSource); Shader fShader = Shader(FragmentShader, fragmentShaderSource); + ShaderProgram *shaderProgram = new ShaderProgram(vShader, fShader); + + initLight(engine); + + std::vector balls; + int ballsCount = 5; + + for (int i = 0; i < ballsCount; ++i) { + MovingBall *sphere = newBall(Vec3(i * 2 - 5, -12, -i), Vec3(3, 0, 1 + i), + shaderProgram, "/wall.png", "/wallspecular.png"); + balls.push_back(sphere); + engine.AddObject<>(sphere); + } + + GameManager *gameManager = new GameManager(balls); + + engine.AddObject(gameManager); + + engine.Run(SCR_WIDTH, SCR_HEIGHT); +} + +MovingBall *newBall(Vec3 position, Vec3 velocity, + ShaderProgram *sp, std::string diffuseSource, std::string specularSource) { + MovingBall* ball = new MovingBall(position, sp, diffuseSource, specularSource); + ball->velocity = velocity; + return ball; +} + - // init a model - Model * model = Model::loadFromFile(catSource); +void initLight(Engine& engine) { + // init light objects + Object* pointLight1 = new Object(); + pointLight1->light = new PointLight( + Vec3(0.2f, 0.2f, 0.2f), Vec3(0.5f, 0.5f, 0.5f), + Vec3(1.0f, 1.0f, 1.0f), Vec3(-0.2, -0.5, -1.2), + 1, 0.09f, 0.032f); + auto pointLight = std::get(pointLight1->light); + engine.AddObject<>(pointLight1); - auto obj = new Object(); - obj->renderData = new RenderData(); - obj->renderData->model = model; - obj->renderData->model->shader = new ShaderProgram(vShader, fShader); + Object* pointLight2 = new Object(); + pointLight2->light = new PointLight( + Vec3(0.2f, 0.2f, 0.2f), Vec3(0.5f, 0.5f, 0.5f), + Vec3(1.0f, 1.0f, 1.0f), Vec3(2.3f, -3.3f, -4.0f), + 1, 0.09f, 0.032f); + pointLight = std::get(pointLight2->light); + engine.AddObject<>(pointLight2); - obj->transform = new Transform(glm::vec3(0.f, -3.f, -8.f), glm::vec3(.1f, .1f, .1f), glm::mat4(1.0)); - obj->transform->Rotate(1.67f, glm::vec3(-1.f, 0.f, 0.f)); - auto render_data = obj->renderData; + Object* pointLight3 = new Object(); + pointLight3->light = new PointLight( + Vec3(0.2f, 0.2f, 0.2f), Vec3(0.5f, 0.5f, 0.5f), + Vec3(1.0f, 1.0f, 1.0f), Vec3(0.0f, 0.0f, -3.0f), + 1, 0.09f, 0.032f); + pointLight = std::get(pointLight3->light); + engine.AddObject<>(pointLight3); - bindRenderData(render_data); + Object* dirLight = new Object(); + dirLight->light = new DirLight( + Vec3(0.05f, 0.05f, 0.05f), Vec3(0.4f, 0.4f, 0.4f), + Vec3(0.5f, 0.5f, 0.5f), Vec3(-0.2f, -1.0f, -0.3f)); - // Maybe this can be less clunky? - // Perhaps variadic functions? - auto images = std::vector(); - images.push_back("/Cat_diffuse.png"); - images.push_back("/Cat_specular.png"); - obj->renderData->material = { - 4.f, - Texture(images), - }; + auto directionLight = std::get(dirLight->light); + engine.AddObject<>(dirLight); - return obj; + Object* spotLight = new Object(); + spotLight->light = new SpotLight( + Vec3(0.0f, 0.0f, 0.0f), Vec3(1.0f, 1.0f, 1.0f), + Vec3(1.0f, 1.0f, 1.0f), Vec3(1.0f, 1.0f, 1.0f), + 1.0f, 0.09f, 0.032f, Vec3(0), + glm::cos(glm::radians(12.5f)), + glm::cos(glm::radians(15.0f))); + auto sptLight = std::get(spotLight->light); + engine.AddObject<>(spotLight); }