From 7fda04e9bfa20c796e53c8b9e03f80259e1672d3 Mon Sep 17 00:00:00 2001
From: bobarna <barnabas.borcsok@gmail.com>
Date: Thu, 13 May 2021 18:24:55 +0200
Subject: [PATCH] =?UTF-8?q?dead=20end=C3=81?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 CMakeLists.txt                                |  28 ++-
 src/application.cpp                           |   7 +-
 src/application.h                             |   6 +-
 src/main.cpp                                  |  28 +--
 src/rendering/Drawable.h                      |  19 --
 src/rendering/camera.cpp                      |  35 +++-
 src/rendering/camera.h                        |  10 +-
 src/rendering/{Drawable.cpp => geometry.cpp}  |  11 +-
 src/rendering/geometry.h                      |  25 +++
 src/rendering/lights/light.cpp                |   6 +
 src/rendering/lights/light.h                  |  18 ++
 src/rendering/materials/material.h            |  12 ++
 src/rendering/objects/object.cpp              |  44 +++++
 src/rendering/objects/object.h                |  38 ++++
 src/rendering/objects/simulation_object.cpp   |  20 ++
 src/rendering/objects/simulation_object.h     |  19 ++
 src/rendering/render_state.h                  |  20 ++
 src/rendering/shaders/basic_shader.cpp        |  10 +
 src/rendering/shaders/basic_shader.h          |  38 ++++
 src/rendering/shaders/gpu_program.cpp         |   1 +
 src/rendering/shaders/gpu_program.h           | 175 ++++++++++++++++++
 src/rendering/shaders/shader.cpp              |  14 ++
 src/rendering/shaders/shader.h                |  19 ++
 src/rendering/textures/texture.cpp            |   5 +
 src/rendering/textures/texture.h              |  80 ++++++++
 .../textures/texture_uniform_color.h          |  17 ++
 src/rendering/vertex_data.cpp                 |   8 +
 src/rendering/vertex_data.h                   |  17 ++
 src/scene.cpp                                 |  26 ++-
 src/scene.h                                   |  11 +-
 src/simulation/pbd/pbd_simulation.cpp         | 102 +++++-----
 src/simulation/pbd/pbd_simulation.h           |  22 +--
 src/simulation/simulation.h                   |  19 ++
 src/simulation/sph/sph_simulation.cpp         |   7 +-
 src/simulation/sph/sph_simulation.h           |   7 +-
 src/utility/custom_math.h                     |  69 +++++++
 .../{InputHandler.cpp => input_handler.cpp}   |   2 +-
 .../{InputHandler.h => input_handler.h}       |   6 +-
 38 files changed, 845 insertions(+), 156 deletions(-)
 delete mode 100644 src/rendering/Drawable.h
 rename src/rendering/{Drawable.cpp => geometry.cpp} (68%)
 create mode 100644 src/rendering/geometry.h
 create mode 100644 src/rendering/lights/light.cpp
 create mode 100644 src/rendering/lights/light.h
 create mode 100644 src/rendering/materials/material.h
 create mode 100644 src/rendering/objects/object.cpp
 create mode 100644 src/rendering/objects/object.h
 create mode 100644 src/rendering/objects/simulation_object.cpp
 create mode 100644 src/rendering/objects/simulation_object.h
 create mode 100644 src/rendering/render_state.h
 create mode 100644 src/rendering/shaders/basic_shader.cpp
 create mode 100644 src/rendering/shaders/basic_shader.h
 create mode 100644 src/rendering/shaders/gpu_program.cpp
 create mode 100644 src/rendering/shaders/gpu_program.h
 create mode 100644 src/rendering/shaders/shader.cpp
 create mode 100644 src/rendering/shaders/shader.h
 create mode 100644 src/rendering/textures/texture.cpp
 create mode 100644 src/rendering/textures/texture.h
 create mode 100644 src/rendering/textures/texture_uniform_color.h
 create mode 100644 src/rendering/vertex_data.cpp
 create mode 100644 src/rendering/vertex_data.h
 create mode 100644 src/simulation/simulation.h
 create mode 100644 src/utility/custom_math.h
 rename src/utility/{InputHandler.cpp => input_handler.cpp} (97%)
 rename src/utility/{InputHandler.h => input_handler.h} (93%)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2546307..26be728 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,9 +1,10 @@
-cmake_minimum_required(VERSION 3.16)
+cmake_minimum_required(VERSION 3.1)
 project(madid)
 
 set(CMAKE_CXX_STANDARD 17)
 #set(CMAKE_CXX_FLAGS "-Wall -Wextra -Werror -pedantic")
 set(CMAKE_CXX_FLAGS "-Wall -Wextra -pedantic -Wunused-parameter")
+set(OpenGL_GL_PREFERENCE "LEGACY")
 
 add_executable(${PROJECT_NAME}
         src/main.cpp
@@ -15,8 +16,8 @@ add_executable(${PROJECT_NAME}
         src/scene.h
         src/rendering/camera.cpp
         src/rendering/camera.h
-        src/utility/InputHandler.h
-        src/utility/InputHandler.cpp
+        src/utility/input_handler.h
+        src/utility/input_handler.cpp
 
         src/simulation/particle.cpp
         src/simulation/particle.h
@@ -25,25 +26,22 @@ add_executable(${PROJECT_NAME}
         src/simulation/sph/sph_simulation.cpp
         src/simulation/sph/sph_simulation.h
 
-        src/rendering/Drawable.cpp src/rendering/Drawable.h)
+        src/rendering/geometry.cpp src/rendering/geometry.h
+        src/rendering/vertex_data.cpp src/rendering/vertex_data.h
+        src/rendering/objects/object.cpp src/rendering/objects/object.h src/rendering/objects/simulation_object.cpp src/rendering/objects/simulation_object.h src/simulation/simulation.h src/utility/custom_math.h src/rendering/render_state.h src/rendering/textures/texture.cpp src/rendering/textures/texture.h src/rendering/shaders/shader.cpp src/rendering/shaders/shader.h src/rendering/shaders/gpu_program.cpp src/rendering/shaders/gpu_program.h src/rendering/textures/texture_uniform_color.h src/rendering/materials/material.h src/rendering/lights/light.cpp src/rendering/lights/light.h src/rendering/shaders/basic_shader.cpp src/rendering/shaders/basic_shader.h)
 
 
 # opengl
 find_package(OpenGL REQUIRED)
-include_directories(${OPENGL_INCLUDE_DIRS})
 
-# glfw
-find_package(glfw3 REQUIRED)
-include_directories(${GLFW_INCLUDE_DIRS})
-link_libraries(${GLFW_LIBRARY_DIRS})
-
-# glew
-find_package(GLEW REQUIRED)
-include_directories(${GLEW_INCLUDE_DIRS})
+link_directories(${GTKMM_LIBRARY_DIRS})
+include_directories(${GTKMM_INCLUDE_DIRS})
 
 target_link_libraries(
         ${PROJECT_NAME}
+        GL
+        GLU
         glfw
-        ${OPENGL_LIBRARIES}
-        ${GLEW_LIBRARIES}
+        GLEW
 )
+
diff --git a/src/application.cpp b/src/application.cpp
index 1b1e60a..e1dad28 100644
--- a/src/application.cpp
+++ b/src/application.cpp
@@ -9,6 +9,7 @@ Application::Application() {
 
 Application::~Application() {
     glfwDestroyWindow(window);
+    glfwTerminate();
 }
 
 GLFWwindow *Application::get_window() {
@@ -24,8 +25,6 @@ void Application::init() {
     glDepthMask(GL_TRUE);
     glLoadIdentity();
     glClearColor(255.0f / 255.0f, 25.0f / 255.0f, 25.0f / 255.0f, 1.0f);
-
-    camera->glSetupCamera();
 }
 
 void Application::error_callback(int error, const char *description) {
@@ -112,13 +111,13 @@ void Application::run() {
     // TODO think about rendering only in 24 FPS
     // TODO guarantee delta_time to be infinitesimal
     scene->update(delta_time);
-    camera->control(delta_time);
+
 
     //clear color and depth buffer
     glClearColor(0, 0, 0, 1);
     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
     glLoadIdentity(); //load identity matrix
-    camera->glSetupCamera();
+
     scene->render();
 }
 
diff --git a/src/application.h b/src/application.h
index 97aa239..fcb60d0 100644
--- a/src/application.h
+++ b/src/application.h
@@ -11,12 +11,10 @@
 #include "constants.h"
 #include "scene.h"
 #include "rendering/camera.h"
-#include "utility/InputHandler.h"
+#include "utility/input_handler.h"
 
 // TODO make this class a singleton
 class Application {
-
-
     int width = WIDTH;
     int height = HEIGHT;
 
@@ -43,8 +41,6 @@ class Application {
 
     double time_since_last_frame;
 
-    std::shared_ptr<Camera> camera = std::make_shared<Camera>();
-
     // TODO
     //boolean flag, indicates whether a screen capture event should be performed
     //on the next display event.
diff --git a/src/main.cpp b/src/main.cpp
index 26176b7..dc3a544 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1,3 +1,4 @@
+#define GLFW_INCLUDE_NONE
 #include <GL/glew.h>
 #include <GLFW/glfw3.h>
 
@@ -8,29 +9,16 @@
 
 
 int main(int argc, char **argv) {
-    // start GLEW extension handler
-    glewExperimental = GL_TRUE;
-    glewInit();
-
-    // get version info
-    const GLubyte *renderer = glGetString(GL_RENDERER); // get renderer string
-    const GLubyte *version = glGetString(GL_VERSION); // version as a string
-    std::cerr << "Renderer: " << renderer << std::endl;
-    std::cerr << "OpenGL version supported: " << version << std::endl;
-
     // start GL context and O/S window using the GLFW helper library
     if (!glfwInit()) {
         std::cerr << "ERROR: could not start GLFW3" << std::endl;
         return 1;
     }
 
-    glfwInit();
-
     /* Creating a GLFW application */
     /* Application creates its GLFW window too */
     std::shared_ptr<Application> application = std::make_shared<Application>();
 
-
     if (!application->window) {
         std::cerr << "ERROR: could not open window with GLFW3" << std::endl;
         glfwTerminate();
@@ -38,6 +26,20 @@ int main(int argc, char **argv) {
     }
 
     glfwMakeContextCurrent(application->get_window());
+
+    // start GLEW extension handler
+    if(glewInit() != GLEW_NO_ERROR) {
+        std::cerr << "Failed to initialize GLEW" << std::endl;
+        return -1;
+    }
+    glewExperimental = GL_TRUE;
+
+    // get version info
+    const GLubyte *renderer = glGetString(GL_RENDERER); // get renderer string
+    const GLubyte *version = glGetString(GL_VERSION); // version as a string/home/bobarna/codes/madid
+    std::cerr << "Renderer: " << renderer << std::endl;
+    std::cerr << "OpenGL version supported: " << version << std::endl;
+
     application->init();
     application->start();
 
diff --git a/src/rendering/Drawable.h b/src/rendering/Drawable.h
deleted file mode 100644
index b7e14e9..0000000
--- a/src/rendering/Drawable.h
+++ /dev/null
@@ -1,19 +0,0 @@
-#ifndef MADID_DRAWABLE_H
-#define MADID_DRAWABLE_H
-
-#include "../utility/gl.h"
-
-class Drawable {
-protected:
-    GLuint vao, vbo;
-
-public:
-    Drawable();
-
-    virtual void Draw() = 0;
-
-    ~Drawable();
-};
-
-
-#endif //MADID_DRAWABLE_H
diff --git a/src/rendering/camera.cpp b/src/rendering/camera.cpp
index 8b860f8..2ae75b6 100644
--- a/src/rendering/camera.cpp
+++ b/src/rendering/camera.cpp
@@ -1,5 +1,6 @@
 #include <iostream>
 #include "camera.h"
+#include "../utility/custom_math.h"
 
 Camera::Camera() :
         aspect_ratio(1),
@@ -19,7 +20,6 @@ void Camera::control(float delta_time) {
     if (InputHandler::IsPressed(GLFW_KEY_W))
         pos += forward * speed * delta_time;
 
-
     if (InputHandler::IsPressed(GLFW_KEY_S))
         pos -= forward * speed * delta_time;
 
@@ -66,3 +66,36 @@ void Camera::glSetupCamera() const {
             0.0f, 1.0f, 0.0f);
 }
 
+glm::mat4 Camera::V() const {
+    glm::vec3 w = normalize(forward);
+    glm::vec3 u = normalize(right);
+    glm::vec3 v = cross(w, u);
+    return translate_matrix(-pos) * glm::mat4(
+            u.x, v.x, w.x, 0,
+            u.y, v.y, w.y, 0,
+            u.z, v.z, w.z, 0,
+            0, 0, 0, 1
+    );
+}
+
+glm::mat4 Camera::P() const {
+    float fov = 1.38f;
+    float asp = aspect_ratio;
+    float fp = 0.2f;
+    float bp = 10;
+
+    return mat4(1.0f / (tanf(fov / 2) * asp), 0, 0, 0,
+                0, 1.0f / tanf(fov / 2), 0, 0,
+                0, 0, -(fp + bp) / (bp - fp), -1,
+                0, 0, -2 * fp * bp / (bp - fp), 0);
+}
+
+RenderState Camera::getState() {
+    RenderState state;
+    state.wEye = pos;
+    state.V = V();
+    state.P = P();
+
+    return state;
+}
+
diff --git a/src/rendering/camera.h b/src/rendering/camera.h
index d2d189e..4db6e79 100644
--- a/src/rendering/camera.h
+++ b/src/rendering/camera.h
@@ -3,7 +3,8 @@
 
 #include <glm/glm.hpp>
 #include "../utility/gl.h"
-#include "../utility/InputHandler.h"
+#include "../utility/input_handler.h"
+#include "render_state.h"
 
 class Camera {
     float aspect_ratio;
@@ -32,6 +33,13 @@ public:
 
     ~Camera();
 
+    // View Matrix: translates the center to the origin
+    glm::mat4 V() const;
+
+    // Projection Matrix
+    glm::mat4 P() const;
+
+    RenderState getState();
 };
 
 #endif
diff --git a/src/rendering/Drawable.cpp b/src/rendering/geometry.cpp
similarity index 68%
rename from src/rendering/Drawable.cpp
rename to src/rendering/geometry.cpp
index 0bdbd11..eaf6ee8 100644
--- a/src/rendering/Drawable.cpp
+++ b/src/rendering/geometry.cpp
@@ -1,14 +1,13 @@
-#include <cstdio>
-#include "Drawable.h"
+#include "geometry.h"
 
-Drawable::Drawable() {
+Geometry::Geometry() {
     glGenVertexArrays(1, &vao);
     glBindVertexArray(vao);
     glGenBuffers(1, &vbo);
     glBindBuffer(GL_ARRAY_BUFFER, vbo);
-}
+};
 
-Drawable::~Drawable() {
+Geometry::~Geometry() {
     glDeleteBuffers(1, &vbo);
     glDeleteVertexArrays(1, &vao);
-}
+};
\ No newline at end of file
diff --git a/src/rendering/geometry.h b/src/rendering/geometry.h
new file mode 100644
index 0000000..5915f15
--- /dev/null
+++ b/src/rendering/geometry.h
@@ -0,0 +1,25 @@
+#ifndef MADID_GEOMETRY_H
+#define MADID_GEOMETRY_H
+
+#include <glm/glm.hpp>
+
+#include <GL/glew.h>
+#include <vector>
+#include "vertex_data.h"
+
+class Geometry {
+protected:
+    GLuint vao, vbo;
+
+public:
+    std::vector<VertexData> vtxData;    // vertices on the CPU
+
+    Geometry();
+
+    virtual void render() = 0;
+
+    ~Geometry();
+};
+
+
+#endif //MADID_GEOMETRY_H
diff --git a/src/rendering/lights/light.cpp b/src/rendering/lights/light.cpp
new file mode 100644
index 0000000..1b6d9f6
--- /dev/null
+++ b/src/rendering/lights/light.cpp
@@ -0,0 +1,6 @@
+#include "light.h"
+
+
+void Light::Animate(float t) {
+    // stay in place
+}
diff --git a/src/rendering/lights/light.h b/src/rendering/lights/light.h
new file mode 100644
index 0000000..9c4fda6
--- /dev/null
+++ b/src/rendering/lights/light.h
@@ -0,0 +1,18 @@
+#ifndef MADID_LIGHT_H
+#define MADID_LIGHT_H
+
+#include <glm/glm.hpp>
+
+class Light {
+    // homogenous coordinates, can be at ideal point
+
+    void Animate(float t);
+
+public:
+    glm::vec3 La;
+    glm::vec3 Le;
+    glm::vec4 wLightPos;
+};
+
+
+#endif //MADID_LIGHT_H
diff --git a/src/rendering/materials/material.h b/src/rendering/materials/material.h
new file mode 100644
index 0000000..ab82179
--- /dev/null
+++ b/src/rendering/materials/material.h
@@ -0,0 +1,12 @@
+#ifndef MADID_MATERIAL_H
+#define MADID_MATERIAL_H
+
+#include <glm/glm.hpp>
+
+struct Material {
+    glm::vec3 kd, ks, ka;
+    float shininess;
+};
+
+
+#endif //MADID_MATERIAL_H
diff --git a/src/rendering/objects/object.cpp b/src/rendering/objects/object.cpp
new file mode 100644
index 0000000..8fe05cd
--- /dev/null
+++ b/src/rendering/objects/object.cpp
@@ -0,0 +1,44 @@
+#include "object.h"
+
+Object::Object(Shader *_shader, Geometry *_geometry, Material *_material, Texture *_texture) :
+        scale(vec3(1, 1, 1)), translation(vec3(0, 0, 0)), rotationAxis(0, 0, 1), rotationAngle(0) {
+    shader = _shader;
+    geometry = _geometry;
+    material = _material;
+    texture = _texture;
+}
+
+void Object::SetModelingTransform(mat4 &M, mat4 &Minv) {
+    M = scale_matrix(scale) * rotation_matrix(rotationAngle, rotationAxis) * translate_matrix(translation);
+    Minv = translate_matrix(-translation) * rotation_matrix(-rotationAngle, rotationAxis) *
+           scale_matrix(vec3(1 / scale.x, 1 / scale.y, 1 / scale.z));
+}
+
+void Object::render(RenderState state) {
+    mat4 M, Minv;
+    SetModelingTransform(M, Minv);
+    state.M = M;
+    state.Minv = Minv;
+    state.MVP = state.M * state.V * state.P;
+    state.material = material;
+    state.texture = texture;
+    shader->Bind(state);
+    geometry->render();
+}
+
+void Object::update(float delta_t) {
+}
+
+
+void Object::Scale(vec3 s) {
+    scale *= s;
+}
+
+void Object::Translate(vec3 t) {
+    translation += t;
+}
+
+void Object::Rotate(vec3 axis, float angle) {
+    rotationAxis = axis;
+    rotationAngle = angle;
+}
\ No newline at end of file
diff --git a/src/rendering/objects/object.h b/src/rendering/objects/object.h
new file mode 100644
index 0000000..1eef817
--- /dev/null
+++ b/src/rendering/objects/object.h
@@ -0,0 +1,38 @@
+#ifndef MADID_OBJECT_H
+#define MADID_OBJECT_H
+
+#include <glm/glm.hpp>
+#include "../../utility/custom_math.h"
+#include "../geometry.h"
+#include "../shaders/shader.h"
+#include "../materials/material.h"
+
+using namespace glm;
+
+class Object {
+protected:
+    vec3 scale, translation, rotationAxis;
+    float rotationAngle;
+
+    Geometry *geometry;
+    Shader *shader;
+    Material *material;
+    Texture *texture;
+public:
+    Object(Shader *_shader, Geometry *_sim, Material *_material = nullptr, Texture *_texture = nullptr);
+
+    virtual void SetModelingTransform(mat4 &M, mat4 &Minv);
+
+    void render(RenderState state);
+
+    virtual void update(float delta_t);
+
+    void Scale(vec3 s);
+
+    void Translate(vec3 t);
+
+    void Rotate(vec3 axis, float angle);
+};
+
+
+#endif //MADID_OBJECT_H
diff --git a/src/rendering/objects/simulation_object.cpp b/src/rendering/objects/simulation_object.cpp
new file mode 100644
index 0000000..1cb3769
--- /dev/null
+++ b/src/rendering/objects/simulation_object.cpp
@@ -0,0 +1,20 @@
+#include "simulation_object.h"
+
+SimulationObject::SimulationObject(Shader *_shader, PBDSimulation *_sim):
+    Object(_shader, _sim) {
+
+}
+
+void SimulationObject::ResetExternalForces() {
+
+}
+
+void SimulationObject::AddForce(glm::vec3 f) {
+    reinterpret_cast<Simulation *>(geometry)->addForce(f);
+}
+
+void SimulationObject::update(float delta_t) {
+    reinterpret_cast<Simulation *>(geometry)->update(delta_t);
+}
+
+
diff --git a/src/rendering/objects/simulation_object.h b/src/rendering/objects/simulation_object.h
new file mode 100644
index 0000000..fe1489c
--- /dev/null
+++ b/src/rendering/objects/simulation_object.h
@@ -0,0 +1,19 @@
+#ifndef MADID_SIMULATION_OBJECT_H
+#define MADID_SIMULATION_OBJECT_H
+
+#include "object.h"
+#include "../../simulation/pbd/pbd_simulation.h"
+
+class SimulationObject : public Object {
+public:
+    SimulationObject(Shader *_shader, PBDSimulation *_sim);
+
+    void ResetExternalForces();
+
+    void AddForce(glm::vec3 f);
+
+    void update(float delta_t) override;
+};
+
+
+#endif //MADID_SIMULATION_OBJECT_H
diff --git a/src/rendering/render_state.h b/src/rendering/render_state.h
new file mode 100644
index 0000000..4a4649a
--- /dev/null
+++ b/src/rendering/render_state.h
@@ -0,0 +1,20 @@
+#ifndef MADID_RENDER_STATE_H
+#define MADID_RENDER_STATE_H
+
+#include "materials/material.h"
+#include "lights/light.h"
+#include "textures/texture.h"
+
+using namespace glm;
+
+struct RenderState {
+    mat4 MVP, M, Minv, V, P;
+    vec3 wEye;
+    Texture *texture;
+    Material *material;
+
+    std::vector<Light> lights;
+};
+
+
+#endif //MADID_RENDER_STATE_H
diff --git a/src/rendering/shaders/basic_shader.cpp b/src/rendering/shaders/basic_shader.cpp
new file mode 100644
index 0000000..505178b
--- /dev/null
+++ b/src/rendering/shaders/basic_shader.cpp
@@ -0,0 +1,10 @@
+#include "basic_shader.h"
+
+BasicShader::BasicShader() {
+    create(vertexCode, fragmentCode, "fragmentColor");
+}
+
+void BasicShader::Bind(RenderState state) {
+    Use(); //make this program run
+    setUniform(state.MVP, "MVP");
+}
\ No newline at end of file
diff --git a/src/rendering/shaders/basic_shader.h b/src/rendering/shaders/basic_shader.h
new file mode 100644
index 0000000..959ab86
--- /dev/null
+++ b/src/rendering/shaders/basic_shader.h
@@ -0,0 +1,38 @@
+#ifndef MADID_BASIC_SHADER_H
+#define MADID_BASIC_SHADER_H
+
+#include "shader.h"
+
+class BasicShader : public Shader {
+    const char *vertexCode = R"(#version 330 core
+
+                                 uniform mat4 MVP;
+
+                                 layout (location = 0) in vec3 aPos;
+                                 layout (location = 1) in vec3 aColor;
+
+                                 out vec3 ourColor;
+
+                                 void main()
+                                 {
+                                     gl_Position = vec4(aPos, 1.0) * MVP;
+                                     ourColor = aColor;
+                                 })";
+
+    const char *fragmentCode = R"(#version 330 core
+                                   out vec4 FragColor;
+
+                                   in vec3 ourColor;
+
+                                   void main()
+                                   {
+                                       gl_FragColor = vec4(ourColor, 1.0f);
+                                   })";
+public:
+    BasicShader();
+
+    void Bind(RenderState state) override;
+};
+
+
+#endif //MADID_BASIC_SHADER_H
diff --git a/src/rendering/shaders/gpu_program.cpp b/src/rendering/shaders/gpu_program.cpp
new file mode 100644
index 0000000..9eaff0f
--- /dev/null
+++ b/src/rendering/shaders/gpu_program.cpp
@@ -0,0 +1 @@
+#include "gpu_program.h"
diff --git a/src/rendering/shaders/gpu_program.h b/src/rendering/shaders/gpu_program.h
new file mode 100644
index 0000000..d341e91
--- /dev/null
+++ b/src/rendering/shaders/gpu_program.h
@@ -0,0 +1,175 @@
+#ifndef MADID_GPU_PROGRAM_H
+#define MADID_GPU_PROGRAM_H
+
+#include <glm/gtc/type_ptr.hpp>
+#include "../../utility/gl.h"
+#include "../../utility/custom_math.h"
+#include "../textures/texture.h"
+
+class GPUProgram {
+    unsigned int shaderProgramId = 0;
+    unsigned int vertexShader = 0, geometryShader = 0, fragmentShader = 0;
+    bool waitError = true;
+
+    void getErrorInfo(unsigned int handle) { // shader error report
+        int logLen, written;
+        glGetShaderiv(handle, GL_INFO_LOG_LENGTH, &logLen);
+        if (logLen > 0) {
+            std::string log(logLen, '\0');
+            glGetShaderInfoLog(handle, logLen, &written, &log[0]);
+            printf("Shader log:\n%s", log.c_str());
+            if (waitError) getchar();
+        }
+    }
+
+    bool checkShader(unsigned int shader, std::string message) { // check if shader could be compiled
+        int OK;
+        glGetShaderiv(shader, GL_COMPILE_STATUS, &OK);
+        if (!OK) {
+            printf("%s!\n", message.c_str());
+            getErrorInfo(shader);
+            return false;
+        }
+        return true;
+    }
+
+    bool checkLinking(unsigned int program) {    // check if shader could be linked
+        int OK;
+        glGetProgramiv(program, GL_LINK_STATUS, &OK);
+        if (!OK) {
+            printf("Failed to link shader program!\n");
+            getErrorInfo(program);
+            return false;
+        }
+        return true;
+    }
+
+    int getLocation(const std::string &name) {    // get the address of a GPU uniform variable
+        int location = glGetUniformLocation(shaderProgramId, name.c_str());
+        if (location < 0) printf("uniform %s cannot be set\n", name.c_str());
+        return location;
+    }
+
+public:
+    GPUProgram(bool _waitError = true) {
+        shaderProgramId = 0;
+        waitError = _waitError;
+    }
+
+    GPUProgram(const GPUProgram &program) {
+        if (program.shaderProgramId > 0) printf("\nError: GPU program is not copied on GPU!!!\n");
+    }
+
+    void operator=(const GPUProgram &program) {
+        if (program.shaderProgramId > 0) printf("\nError: GPU program is not copied on GPU!!!\n");
+    }
+
+    unsigned int getId() { return shaderProgramId; }
+
+    bool create(const char *const vertexShaderSource,
+                const char *const fragmentShaderSource, const char *const fragmentShaderOutputName,
+                const char *const geometryShaderSource = nullptr) {
+        // Create vertex shader from string
+        if (vertexShader == 0) vertexShader = glCreateShader(GL_VERTEX_SHADER);
+        if (!vertexShader) {
+            printf("Error in vertex shader creation\n");
+            exit(1);
+        }
+        glShaderSource(vertexShader, 1, (const GLchar **) &vertexShaderSource, NULL);
+        glCompileShader(vertexShader);
+        if (!checkShader(vertexShader, "Vertex shader error")) return false;
+
+        // Create geometry shader from string if given
+        if (geometryShaderSource != nullptr) {
+            if (geometryShader == 0) geometryShader = glCreateShader(GL_GEOMETRY_SHADER);
+            if (!geometryShader) {
+                printf("Error in geometry shader creation\n");
+                exit(1);
+            }
+            glShaderSource(geometryShader, 1, (const GLchar **) &geometryShaderSource, NULL);
+            glCompileShader(geometryShader);
+            if (!checkShader(geometryShader, "Geometry shader error")) return false;
+        }
+
+        // Create fragment shader from string
+        if (fragmentShader == 0) fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
+        if (!fragmentShader) {
+            printf("Error in fragment shader creation\n");
+            exit(1);
+        }
+
+        glShaderSource(fragmentShader, 1, (const GLchar **) &fragmentShaderSource, NULL);
+        glCompileShader(fragmentShader);
+        if (!checkShader(fragmentShader, "Fragment shader error")) return false;
+
+        shaderProgramId = glCreateProgram();
+        if (!shaderProgramId) {
+            printf("Error in shader program creation\n");
+            exit(1);
+        }
+        glAttachShader(shaderProgramId, vertexShader);
+        glAttachShader(shaderProgramId, fragmentShader);
+        if (geometryShader > 0) glAttachShader(shaderProgramId, geometryShader);
+
+        // Connect the fragmentColor to the frame buffer memory
+        glBindFragDataLocation(shaderProgramId, 0,
+                               fragmentShaderOutputName);    // this output goes to the frame buffer memory
+
+        // program packaging
+        glLinkProgram(shaderProgramId);
+        if (!checkLinking(shaderProgramId)) return false;
+
+        // make this program run
+        glUseProgram(shaderProgramId);
+        return true;
+    }
+
+    void Use() {        // make this program run
+        glUseProgram(shaderProgramId);
+    }
+
+    void setUniform(int i, const std::string &name) {
+        int location = getLocation(name);
+        if (location >= 0) glUniform1i(location, i);
+    }
+
+    void setUniform(float f, const std::string &name) {
+        int location = getLocation(name);
+        if (location >= 0) glUniform1f(location, f);
+    }
+
+    void setUniform(const vec2 &v, const std::string &name) {
+        int location = getLocation(name);
+        if (location >= 0) glUniform2fv(location, 1, &v.x);
+    }
+
+    void setUniform(const vec3 &v, const std::string &name) {
+        int location = getLocation(name);
+        if (location >= 0) glUniform3fv(location, 1, &v.x);
+    }
+
+    void setUniform(const vec4 &v, const std::string &name) {
+        int location = getLocation(name);
+        if (location >= 0) glUniform4fv(location, 1, &v.x);
+    }
+
+    void setUniform(const mat4 &mat, const std::string &name) {
+        int location = getLocation(name);
+        if (location >= 0) glUniformMatrix4fv(location, 1, GL_TRUE, glm::value_ptr(mat));
+    }
+
+    void setUniform(const Texture &texture, const std::string &samplerName, unsigned int textureUnit = 0) {
+
+        int location = getLocation(samplerName);
+        if (location >= 0) {
+            glUniform1i(location, textureUnit);
+            glActiveTexture(GL_TEXTURE0 + textureUnit);
+            glBindTexture(GL_TEXTURE_2D, texture.textureId);
+        }
+    }
+
+    ~GPUProgram() { if (shaderProgramId > 0) glDeleteProgram(shaderProgramId); }
+};
+
+
+#endif //MADID_GPU_PROGRAM_H
diff --git a/src/rendering/shaders/shader.cpp b/src/rendering/shaders/shader.cpp
new file mode 100644
index 0000000..fe56cda
--- /dev/null
+++ b/src/rendering/shaders/shader.cpp
@@ -0,0 +1,14 @@
+#include "shader.h"
+
+void Shader::setUniformMaterial(Material &material, const std::string &name) {
+    setUniform(material.kd, name + ".kd");
+    setUniform(material.ks, name + ".ks");
+    setUniform(material.ka, name + ".ka");
+    setUniform(material.shininess, name + ".shininess");
+}
+
+void Shader::setUniformLight(const Light &light, const std::string &name) {
+    setUniform(light.La, name + ".La");
+    setUniform(light.Le, name + ".Le");
+    setUniform(light.wLightPos, name + ".wLightPos");
+}
diff --git a/src/rendering/shaders/shader.h b/src/rendering/shaders/shader.h
new file mode 100644
index 0000000..2cc8c83
--- /dev/null
+++ b/src/rendering/shaders/shader.h
@@ -0,0 +1,19 @@
+#ifndef MADID_SHADER_H
+#define MADID_SHADER_H
+
+#include "gpu_program.h"
+#include "../render_state.h"
+#include "../materials/material.h"
+#include "../lights/light.h"
+
+class Shader : public GPUProgram {
+public:
+    virtual void Bind(RenderState state) = 0;
+
+    void setUniformMaterial(Material &material, const std::string &name);
+
+    void setUniformLight(const Light &light, const std::string &name);
+};
+
+
+#endif //MADID_SHADER_H
diff --git a/src/rendering/textures/texture.cpp b/src/rendering/textures/texture.cpp
new file mode 100644
index 0000000..ca7d364
--- /dev/null
+++ b/src/rendering/textures/texture.cpp
@@ -0,0 +1,5 @@
+//
+// Created by bobarna on 2021. 05. 13..
+//
+
+#include "texture.h"
diff --git a/src/rendering/textures/texture.h b/src/rendering/textures/texture.h
new file mode 100644
index 0000000..465584f
--- /dev/null
+++ b/src/rendering/textures/texture.h
@@ -0,0 +1,80 @@
+#ifndef MADID_TEXTURE_H
+#define MADID_TEXTURE_H
+
+#include "../../utility/custom_math.h"
+#include <iostream>
+#include "../../utility/gl.h"
+
+class Texture {
+    std::vector<vec4> load(std::string pathname, bool transparent, int &width, int &height) {
+        FILE *file = fopen(pathname.c_str(), "r");
+        if (!file) {
+            printf("%s does not exist\n", pathname.c_str());
+            width = height = 0;
+            return std::vector<vec4>();
+        }
+        unsigned short bitmapFileHeader[27];                    // bitmap header
+        fread(&bitmapFileHeader, 27, 2, file);
+        if (bitmapFileHeader[0] != 0x4D42) printf("Not bmp file\n");
+        if (bitmapFileHeader[14] != 24) printf("Only true color bmp files are supported\n");
+        width = bitmapFileHeader[9];
+        height = bitmapFileHeader[11];
+        unsigned int size = (unsigned long) bitmapFileHeader[17] + (unsigned long) bitmapFileHeader[18] * 65536;
+        fseek(file, 54, SEEK_SET);
+        std::vector<unsigned char> bImage(size);
+        fread(&bImage[0], 1, size, file);    // read the pixels
+        fclose(file);
+        std::vector<vec4> image(width * height);
+        int i = 0;
+        for (unsigned int idx = 0; idx < size; idx += 3) { // Swap R and B since in BMP, the order is BGR
+            float alpha = (transparent) ? (bImage[idx] + bImage[idx + 1] + bImage[idx + 2]) / 3.0f / 256.0f : 1.0f;
+            image[i++] = vec4(bImage[idx + 2] / 256.0f, bImage[idx + 1] / 256.0f, bImage[idx] / 256.0f, alpha);
+        }
+        return image;
+    }
+
+public:
+    unsigned int textureId = 0;
+
+    Texture() { textureId = 0; }
+
+    Texture(std::string pathname, bool transparent = false) {
+        textureId = 0;
+        create(pathname, transparent);
+    }
+
+    Texture(int width, int height, const std::vector<vec4> &image, int sampling = GL_LINEAR) {
+        textureId = 0;
+        create(width, height, image, sampling);
+    }
+
+    Texture(const Texture &texture) {
+        printf("\nError: Texture resource is not copied on GPU!!!\n");
+    }
+
+    void operator=(const Texture &texture) {
+        printf("\nError: Texture resource is not copied on GPU!!!\n");
+    }
+
+    void create(std::string pathname, bool transparent = false) {
+        int width, height;
+        std::vector<vec4> image = load(pathname, transparent, width, height);
+        if (image.size() > 0) create(width, height, image);
+    }
+
+    void create(int width, int height, const std::vector<vec4> &image, int sampling = GL_LINEAR) {
+        if (textureId == 0) glGenTextures(1, &textureId);                // id generation
+        glBindTexture(GL_TEXTURE_2D, textureId);    // binding
+
+        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_FLOAT, &image[0]); // To GPU
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, sampling); // sampling
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, sampling);
+    }
+
+    ~Texture() {
+        if (textureId > 0) glDeleteTextures(1, &textureId);
+    }
+};
+
+
+#endif //MADID_TEXTURE_H
diff --git a/src/rendering/textures/texture_uniform_color.h b/src/rendering/textures/texture_uniform_color.h
new file mode 100644
index 0000000..9705c11
--- /dev/null
+++ b/src/rendering/textures/texture_uniform_color.h
@@ -0,0 +1,17 @@
+#ifndef MADID_TEXTURE_UNIFORM_COLOR_H
+#define MADID_TEXTURE_UNIFORM_COLOR_H
+
+#include "texture.h"
+
+class UniformColorTexture : public Texture {
+public:
+    UniformColorTexture(float r = 1, float g = 1, float b = 0, float a = 1) : Texture() {
+        std::vector<vec4> color;
+        color.emplace_back(r, g, b, a);
+
+        create(1, 1, color, GL_NEAREST);
+    }
+};
+
+
+#endif //MADID_TEXTURE_UNIFORM_COLOR_H
diff --git a/src/rendering/vertex_data.cpp b/src/rendering/vertex_data.cpp
new file mode 100644
index 0000000..3a43a49
--- /dev/null
+++ b/src/rendering/vertex_data.cpp
@@ -0,0 +1,8 @@
+#include "vertex_data.h"
+
+VertexData::VertexData(glm::vec3 p, glm::vec3 n, glm::vec2 uv) :
+        position(p), normal(n), texcoord(uv) {
+}
+
+VertexData::VertexData() {
+}
\ No newline at end of file
diff --git a/src/rendering/vertex_data.h b/src/rendering/vertex_data.h
new file mode 100644
index 0000000..a90397b
--- /dev/null
+++ b/src/rendering/vertex_data.h
@@ -0,0 +1,17 @@
+
+#ifndef MADID_VERTEX_DATA_H
+#define MADID_VERTEX_DATA_H
+
+#include <glm/glm.hpp>
+
+struct VertexData {
+    // needed for GetVertexByUV function
+    bool valid = true;
+    glm::vec3 position, normal;
+    glm::vec2 texcoord;
+    VertexData();
+    VertexData(glm::vec3 p, glm::vec3 n, glm::vec2 uv);
+    explicit VertexData(bool valid, glm::vec3 p = {0,0,0}, glm::vec3 n = {0,0,0}, glm::vec2 uv = {0,0}){};
+};
+
+#endif //MADID_VERTEX_DATA_H
diff --git a/src/scene.cpp b/src/scene.cpp
index 52d36e4..d59df65 100644
--- a/src/scene.cpp
+++ b/src/scene.cpp
@@ -1,17 +1,35 @@
 #include "scene.h"
+#include "rendering/shaders/basic_shader.h"
 
 Scene::Scene() {
-    std::cout << "Scene built successfully" << std::endl;
+    camera->glSetupCamera();
+
+    size_t nrSims = 100;
+    size_t nrSegments = 50;
+    float lSeg = 0.003f;
+
+    auto pbd_sim = new PBDSimulation(nrSims, nrSegments, lSeg);
+
+    Shader *basicShader = new BasicShader();
+
+    auto pbd_sim_object = std::make_shared<SimulationObject>(basicShader, pbd_sim);
+
+    simulations.push_back(pbd_sim_object);
+
+    std::cout << "Scene built successfully." << std::endl;
 }
 
 Scene::~Scene() {
-    std::cout << "Scene destroyed" << std::endl;
+    std::cout << "Scene destroyed." << std::endl;
 }
 
 void Scene::update(double dt) {
-    sph_system->update((float) dt);
+    camera->control(dt);
+
+    for (auto &s: simulations) s->update(dt);
 }
 
 void Scene::render() {
-    sph_system->render();
+    camera->glSetupCamera();
+    for (auto &s: simulations) s->render(camera->getState());
 }
diff --git a/src/scene.h b/src/scene.h
index e19b830..6ed4e1a 100644
--- a/src/scene.h
+++ b/src/scene.h
@@ -4,8 +4,9 @@
 #include <iostream>
 #include <memory>
 
-#include "simulation/sph/sph_simulation.h"
-#include "simulation/pbd/pbd_simulation.h"
+#include "rendering/objects/object.h"
+#include "rendering/objects/simulation_object.h"
+#include "rendering/camera.h"
 
 class Scene {
     bool draw_normals;
@@ -13,10 +14,10 @@ class Scene {
     bool draw_velocity;
     bool use_emitter;
 
-    std::shared_ptr<SPHSimulation> sph_system = std::make_shared<SPHSimulation>();
+    std::shared_ptr<Camera> camera = std::make_shared<Camera>();
 
-    // TODO set parameters here
-    std::shared_ptr<PBDSimulation> pbd_system = std::make_shared<PBDSimulation>();
+    // TODO shared_ptr
+    std::vector<std::shared_ptr<SimulationObject>> simulations;
 
 public:
     Scene();
diff --git a/src/simulation/pbd/pbd_simulation.cpp b/src/simulation/pbd/pbd_simulation.cpp
index 369b77d..af51ec3 100644
--- a/src/simulation/pbd/pbd_simulation.cpp
+++ b/src/simulation/pbd/pbd_simulation.cpp
@@ -4,52 +4,20 @@ void PBDSimulation::addForce(vec3 force) {
     externalForces += force;
 }
 
-PBDSimulation::PBDSimulation() {
-    numberOfParticlesOnASide = 10;
-    nrSegments = 10;
-    lSeg = 0.08f;
-    initParticles();
-}
-
 PBDSimulation::PBDSimulation(size_t _nr_sims, size_t _nr_segments, float _l_seg) :
-        numberOfParticlesOnASide(_nr_sims),
+        nrStrands(_nr_sims),
         nrSegments(_nr_segments),
         lSeg(_l_seg),
         externalForces(.0f, .0f, .0f) {
 
-    // placing hair on the head
-    initParticles();
-
-    /* collisionTriangles.emplace_back(0.15, -1, 1); */
-    /* collisionTriangles.emplace_back(0.15, 1, 0); */
-    /* collisionTriangles.emplace_back(0.15, -1, -1); */
-}
-
-void PBDSimulation::initParticles() {
-
-    vec3 startPos = vec3(-1, 0, -1);
+    // placing the fibers of the cloth
+    for (size_t i = 0; i < nrStrands; i++) {
+        vec3 currPos(-.5f, 0.f, lSeg * (float)i);
 
-    for (size_t i = 0; i < numberOfParticlesOnASide; i++) {
-        vec3 color = vec3(222.0f, 101.0f, 32.0f);
-        std::vector<Particle *> currentStrand;
-
-        for (size_t j = 0; j < numberOfParticlesOnASide; j++) {
-            // mass of the current particle
-            float m = .25f;
-            vec3 currPos = startPos + vec3((float) i * lSeg, 0, (float) j * lSeg);
-
-            // infinite mass on the corners
-            if ((i == 0 && j == 0) ||
-                (i == 0 && j == numberOfParticlesOnASide - 1) ||
-                (i == numberOfParticlesOnASide - 1 && j == 0) ||
-                (i == numberOfParticlesOnASide - 1 && j == numberOfParticlesOnASide - 1)
-                    ) {
-                currentStrand.push_back(new Particle(currPos, 0, color));
-            } else currentStrand.push_back(new Particle(currPos, 1 / m, color));
-        }
-
-        strands.emplace_back(currentStrand);
+        vec3 color = vec3(0.9f, 0.3f, 0.3f);
+        strands.emplace_back(CreateFiber(nrSegments, lSeg, currPos * vec3(1, -1, 1), color));
     }
+
 }
 
 void PBDSimulation::update(float dt) {
@@ -58,7 +26,6 @@ void PBDSimulation::update(float dt) {
         for (auto &p : strand) {
             p->v = p->v + dt * (p->w) * externalForces;
             // damp velocities
-            // TODO better damping technique: (3.5) https://matthias-research.github.io/pages/publications/posBasedDyn.pdf
             p->v *= .99f;
 
             // calculating temporal positions
@@ -70,18 +37,26 @@ void PBDSimulation::update(float dt) {
     // solve constraints
     size_t num_iter = 10;
     for (size_t iter = 0; iter < num_iter; iter++) {
-        for (auto &strand: strands) {
-            //keep first particle in place
+        for (size_t s = 0; s < strands.size(); s++) {
+            std::vector<Particle*>& strand = strands.at(s);
+
             // TODO position constraint
+            //keep first particle in place
             strand.at(0)->tmp_pos = strand.at(0)->pos;
-            //distance between subsequent particles should be l
+            // keep the last one fixed as well
+            strand.at(strand.size()-1)->tmp_pos = strand.at(strand.size()-1)->pos;
+
+            //distance between other particles should be l
             for (size_t i = 1; i < strand.size(); i++) {
                 solve_distance_constraint(strand[i - 1], strand[i], lSeg);
-                if (i < strand.size() - 1) solve_bending_constraint(strand[i - 1], strand[i + 1], lSeg * 0.9f);
-                if (i < strand.size() - 2 && i > 1)
-                    solve_bending_constraint(strand[i - 2], strand[i + 2], lSeg * 1.9f);
-                /* solve_collision_constraint(strand[i], */
-                /*                            collisionTriangles[0], collisionTriangles[1], collisionTriangles[2]); */
+            }
+
+            // distance constraint for neighboring strands
+            if(s != 0 && s != strands.size() - 1) {
+                std::vector<Particle*>& next_strand = strands.at(s+1);
+                // TODO refactor distance into constant
+                for (size_t i = 1; i < strand.size()-1; i++)
+                    solve_distance_constraint(strand[i], next_strand[i], lSeg);
             }
         }
     }
@@ -105,8 +80,8 @@ void PBDSimulation::solve_distance_constraint(Particle *p1, Particle *p2, float
                 (length(p1->tmp_pos - p2->tmp_pos) - dist) *
                 (p1->tmp_pos - p2->tmp_pos) / length(p1->tmp_pos - p2->tmp_pos);
 
-    p1->tmp_pos += d_p1;
-    p2->tmp_pos += d_p2;
+    p1->tmp_pos += 0.8f*d_p1;
+    p2->tmp_pos += 0.8f*d_p2;
 }
 
 void PBDSimulation::solve_bending_constraint(Particle *p1, Particle *p2, float dist) {
@@ -117,10 +92,8 @@ void PBDSimulation::solve_bending_constraint(Particle *p1, Particle *p2, float d
                 (length(p1->tmp_pos - p2->tmp_pos) - dist) *
                 (p1->tmp_pos - p2->tmp_pos) / length(p1->tmp_pos - p2->tmp_pos);
 
-    // TODO define *(float, vec3) operator...
-    float damping = 0.6f;
-    p1->tmp_pos += vec3(d_p1.x * damping, d_p1.y * damping, d_p1.z * damping);
-    p2->tmp_pos += vec3(d_p2.x * damping, d_p2.y * damping, d_p2.z * damping);
+    p1->tmp_pos += 0.6f*d_p1;
+    p2->tmp_pos += 0.6f*d_p2;
 }
 
 void PBDSimulation::solve_collision_constraint(Particle *p, vec3 &q1, vec3 &q2, vec3 &q3) {
@@ -133,7 +106,7 @@ void PBDSimulation::solve_collision_constraint(Particle *p, vec3 &q1, vec3 &q2,
     p->tmp_pos += d_p;
 }
 
-void PBDSimulation::Draw() {
+void PBDSimulation::render() {
     std::vector<float> particlePosAndColor;
     for (auto &strand : strands)
         for (size_t i = 0; i < strand.size() - 1; ++i) {
@@ -171,8 +144,23 @@ void PBDSimulation::Draw() {
     glDrawArrays(GL_LINES, 0, particlePosAndColor.size() / 6);
 }
 
-vec3 PBDSimulation::getExternalForces() const {
-    return externalForces;
+std::vector<Particle *> PBDSimulation::CreateFiber(size_t n, float l, vec3 startPos, vec3 color) {
+    vec3 currPos = startPos;
+    std::vector<Particle *> currentStrand;
+
+    for (size_t i = 0; i < n; i++) {
+        // slightly random mass for better visual results
+        float m = (float) rand() / RAND_MAX * .35f + .15f;
+
+        // first and last particle's position is infinite
+        if (i == 0 || i == n-1) currentStrand.push_back(new Particle(currPos, 0, color));
+        else currentStrand.push_back(new Particle(currPos, 1 / m, color));
+
+        // propagate particles horizontally
+        currPos.x += l;
+    }
+
+    return currentStrand;
 }
 
 void PBDSimulation::resetExternalForces() {
diff --git a/src/simulation/pbd/pbd_simulation.h b/src/simulation/pbd/pbd_simulation.h
index e23b4a1..90766cc 100644
--- a/src/simulation/pbd/pbd_simulation.h
+++ b/src/simulation/pbd/pbd_simulation.h
@@ -6,13 +6,13 @@
 #include <glm/glm.hpp>
 
 #include "../../utility/gl.h"
-
 #include "../particle.h"
-#include "../../rendering/Drawable.h"
+#include "../../rendering/geometry.h"
+#include "../simulation.h"
 
 typedef glm::vec3 vec3;
 
-class PBDSimulation : Drawable {
+class PBDSimulation : public Geometry {
     void solve_distance_constraint(Particle *p1, Particle *p2, float dist);
 
     void solve_bending_constraint(Particle *p1, Particle *p2, float dist);
@@ -20,10 +20,10 @@ class PBDSimulation : Drawable {
     void solve_collision_constraint(Particle *p, vec3 &q1, vec3 &q2, vec3 &q3);
 
 public:
-    //// numberOfParticlesOnASide X numberOfParticlesOnASide sized cloth will be generated
-    size_t numberOfParticlesOnASide;
+    //// number of hair strands to be placed on the head
+    size_t nrStrands;
 
-    //// how many segments one side of the cloth will be subdivided into
+    //// how many segments a strand will be sub-divided into
     size_t nrSegments;
 
     //// length of a segment
@@ -40,19 +40,15 @@ public:
 
     void addForce(vec3 force);
 
-    PBDSimulation();
-
     PBDSimulation(size_t _nr_sims, size_t _nr_segments, float _l_seg);
 
-    void initParticles();
-
     void update(float dt);
 
-    void Draw();
-
-    vec3 getExternalForces() const;
+    void render() override;
 
     void resetExternalForces();
+
+    std::vector<Particle *> CreateFiber(size_t n, float l, vec3 startPos, vec3 color);
 };
 
 
diff --git a/src/simulation/simulation.h b/src/simulation/simulation.h
new file mode 100644
index 0000000..9310268
--- /dev/null
+++ b/src/simulation/simulation.h
@@ -0,0 +1,19 @@
+#ifndef MADID_SIMULATION_H
+#define MADID_SIMULATION_H
+
+
+#include "../rendering/geometry.h"
+
+class Simulation : public Geometry {
+public:
+    virtual void addForce(glm::vec3 force) = 0;
+    Simulation(): Geometry() { };
+
+    virtual void update(float dt) = 0;
+    virtual void render() = 0;
+
+    virtual void resetExternalForces() = 0;
+};
+
+
+#endif //MADID_SIMULATION_H
diff --git a/src/simulation/sph/sph_simulation.cpp b/src/simulation/sph/sph_simulation.cpp
index 75fb769..0d6a8e1 100644
--- a/src/simulation/sph/sph_simulation.cpp
+++ b/src/simulation/sph/sph_simulation.cpp
@@ -8,9 +8,6 @@ SPHSimulation::SPHSimulation() {
         for (float z = 0; z < 2; z += 0.2f)
             for (float x = 0; x < 2; x += 0.2f)
                 if (particles.size() < sph::N) {
-
-                    float x_off = glm::linearRand(.0f, 1.f);
-//                        particles.emplace_back(new Particle(x + x_off, y, z));
                     particles.emplace_back(
                             new Particle(
                                     glm::linearRand(1.f, 1.1f),
@@ -25,9 +22,7 @@ SPHSimulation::SPHSimulation() {
 }
 
 SPHSimulation::~SPHSimulation() {
-    for (auto &particle : particles)
-        delete particle;
-
+    for (auto &particle : particles) { delete particle; }
 }
 
 void SPHSimulation::compute_density_and_pressure() {
diff --git a/src/simulation/sph/sph_simulation.h b/src/simulation/sph/sph_simulation.h
index 30deb8c..4b3c30c 100644
--- a/src/simulation/sph/sph_simulation.h
+++ b/src/simulation/sph/sph_simulation.h
@@ -11,6 +11,7 @@
 
 #include "../particle.h"
 #include "../../constants.h"
+#include "../simulation.h"
 
 namespace sph {
     // external (gravitational force)
@@ -50,7 +51,7 @@ namespace sph {
 }
 
 
-class SPHSimulation {
+class SPHSimulation : Simulation {
 
     std::vector<Particle *> particles;
 
@@ -66,9 +67,9 @@ public:
     ~SPHSimulation();
 
     // step the system by t time
-    void update(float t);
+    void update(float t) override;
 
-    void render();
+    void render() override;
 };
 
 #endif
diff --git a/src/utility/custom_math.h b/src/utility/custom_math.h
new file mode 100644
index 0000000..31dbf91
--- /dev/null
+++ b/src/utility/custom_math.h
@@ -0,0 +1,69 @@
+#ifndef MADID_CUSTOM_MATH_H
+#define MADID_CUSTOM_MATH_H
+
+#include <glm/glm.hpp>
+#include <cmath>
+#include <vector>
+
+using namespace glm;
+
+inline mat4 translate_matrix(vec3 t) {
+    return mat4(vec4(1, 0, 0, 0),
+                vec4(0, 1, 0, 0),
+                vec4(0, 0, 1, 0),
+                vec4(t.x, t.y, t.z, 1));
+}
+
+inline mat4 scale_matrix(vec3 s) {
+    return mat4(vec4(s.x, 0, 0, 0),
+                vec4(0, s.y, 0, 0),
+                vec4(0, 0, s.z, 0),
+                vec4(0, 0, 0, 1));
+}
+
+inline mat4 rotation_matrix(float angle, vec3 w) {
+    float c = cosf(angle), s = sinf(angle);
+    w = normalize(w);
+    return mat4(vec4(c * (1 - w.x * w.x) + w.x * w.x, w.x * w.y * (1 - c) + w.z * s, w.x * w.z * (1 - c) - w.y * s, 0),
+                vec4(w.x * w.y * (1 - c) - w.z * s, c * (1 - w.y * w.y) + w.y * w.y, w.y * w.z * (1 - c) + w.x * s, 0),
+                vec4(w.x * w.z * (1 - c) + w.y * s, w.y * w.z * (1 - c) - w.x * s, c * (1 - w.z * w.z) + w.z * w.z, 0),
+                vec4(0, 0, 0, 1));
+}
+
+inline mat4 x_rotation_matrix(float angle) {
+    float s = sinf(angle);
+    float c = cosf(angle);
+    return mat4(
+            1.f, 0.f, 0.f, 0.f,
+            0.f, c, s, 0.f,
+            0.f, -s, c, 0.f,
+            0.f, 0.f, 0.f, 1.f
+    );
+}
+
+inline mat4 y_rotation_matrix(float angle) {
+    float s = sinf(angle);
+    float c = cosf(angle);
+    return mat4(
+            c, 0.f, -s, 0.f,
+            0.f, 1.f, 0.f, 0.f,
+            s, 0.f, c, 0.f,
+            0.f, 0.f, 0.f, 1.f
+    );
+}
+
+inline mat4 z_rotation_matrix(float angle) {
+    float s = sinf(angle);
+    float c = cosf(angle);
+    return mat4(
+            c, s, 0.f, 0.f,
+            -s, c, 0.f, 0.f,
+            0.f, 0.f, 1.f, 0.f,
+            0.f, 0.f, 0.f, 1.f
+    );
+}
+
+// automatic mat4 printing
+//std::ostream &operator<<(std::ostream &out, const mat4 &v);
+
+#endif //MADID_CUSTOM_MATH_H
diff --git a/src/utility/InputHandler.cpp b/src/utility/input_handler.cpp
similarity index 97%
rename from src/utility/InputHandler.cpp
rename to src/utility/input_handler.cpp
index 9566f56..d16f357 100644
--- a/src/utility/InputHandler.cpp
+++ b/src/utility/input_handler.cpp
@@ -1,4 +1,4 @@
-#include "InputHandler.h"
+#include "input_handler.h"
 
 InputHandler *InputHandler::singleton_ = nullptr;
 bool InputHandler::keyPressed[348];
diff --git a/src/utility/InputHandler.h b/src/utility/input_handler.h
similarity index 93%
rename from src/utility/InputHandler.h
rename to src/utility/input_handler.h
index 50780de..b3c7493 100644
--- a/src/utility/InputHandler.h
+++ b/src/utility/input_handler.h
@@ -1,5 +1,5 @@
-#ifndef MADID_INPUTHANDLER_H
-#define MADID_INPUTHANDLER_H
+#ifndef MADID_INPUT_HANDLER_H
+#define MADID_INPUT_HANDLER_H
 
 #include "gl.h"
 
@@ -64,4 +64,4 @@ public:
 
 };
 
-#endif //MADID_INPUTHANDLER_H
+#endif //MADID_INPUT_HANDLER_H
-- 
GitLab