From 42e03ddc3b28c41b81fb5410feb72750530ffa13 Mon Sep 17 00:00:00 2001
From: Frederico Linhares <fred@linhares.blue>
Date: Mon, 22 Aug 2022 17:26:43 -0300
Subject: feat Make camera and model instance more abstract

* src/camera.cpp src/camera.hpp: Remove the camera as Vector3D and
Rotation3D are going to replace it.
* src/model.cpp: Add draw command as instances do not exist anymore.
* src/model/instance.cpp src/model/instance.hpp: Remove the instance as
Vector3D and Rotation3D are going to replace it.
---
 src/camera.cpp               | 143 -----------------------------------
 src/camera.hpp               |  25 ------
 src/candy_gear.cpp           |  33 ++++++++
 src/main.cpp                 |   8 +-
 src/model.cpp                |  25 ++++++
 src/model/instance.cpp       |  98 ------------------------
 src/model/instance.hpp       |  25 ------
 src/rotation3d.cpp           | 113 +++++++++++++++++++++++++++
 src/rotation3d.hpp           |  27 +++++++
 src/vector3d.cpp             | 176 +++++++++++++++++++++++++++++++++++++++++++
 src/vector3d.hpp             |  34 +++++++++
 src/vk/camera.hpp            |  33 --------
 src/vk/graphics_pipeline.cpp |  30 ++++----
 src/vk/graphics_pipeline.hpp |   4 +-
 14 files changed, 428 insertions(+), 346 deletions(-)
 delete mode 100644 src/camera.cpp
 delete mode 100644 src/camera.hpp
 delete mode 100644 src/model/instance.cpp
 delete mode 100644 src/model/instance.hpp
 create mode 100644 src/rotation3d.cpp
 create mode 100644 src/rotation3d.hpp
 create mode 100644 src/vector3d.cpp
 create mode 100644 src/vector3d.hpp
 delete mode 100644 src/vk/camera.hpp

(limited to 'src')

diff --git a/src/camera.cpp b/src/camera.cpp
deleted file mode 100644
index 27805ac..0000000
--- a/src/camera.cpp
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Copyright 2022 Frederico de Oliveira Linhares
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "camera.hpp"
-
-#include "vk/camera.hpp"
-
-void
-cg_free_camera(mrb_state *mrb, void* obj)
-{
-  auto ptr = static_cast<std::shared_ptr<VK::Camera>*>(obj);
-
-  ptr->~shared_ptr();
-  mrb_free(mrb, ptr);
-}
-
-const struct mrb_data_type cg_camera_type = {"CG_Camera", cg_free_camera};
-
-static mrb_value
-cg_cCamera_initialize(mrb_state *mrb, mrb_value self)
-{
-  mrb_float position_x, position_y, position_z,
-    rotation_x, rotation_y, rotation_z;
-  std::shared_ptr<VK::Camera> *ptr;
-
-  mrb_get_args(
-    mrb, "ffffff",
-    &position_x, &position_y, &position_z,
-    &rotation_x, &rotation_y, &rotation_z);
-  ptr = (std::shared_ptr<VK::Camera>*)DATA_PTR(self);
-  if(ptr) mrb_free(mrb, ptr);
-  ptr = (std::shared_ptr<VK::Camera>*)mrb_malloc(
-    mrb, sizeof(std::shared_ptr<VK::Camera>));
-  
-  new(ptr)std::shared_ptr<VK::Camera>(std::make_shared<VK::Camera>());
-  (*ptr)->position = glm::vec3(position_x, position_y, position_z);
-  (*ptr)->rotation = glm::vec3(rotation_x, rotation_y, rotation_z);
-
-  mrb_data_init(self, ptr, &cg_camera_type);
-  return self;
-}
-
-static mrb_value
-cg_cCamera_use(mrb_state *mrb, mrb_value self)
-{
-  std::shared_ptr<VK::Camera> *ptr;
-
-  ptr = (std::shared_ptr<VK::Camera>*)DATA_PTR(self);
-  cg_core.vk_graphics_pipeline->camera = (*ptr);
-
-  return self;
-}
-
-static mrb_value
-cg_cCamera_rotate(mrb_state *mrb, mrb_value self)
-{
-  mrb_float x, y, z;
-  std::shared_ptr<VK::Camera> *ptr;
-
-  mrb_get_args(mrb, "fff", &x, &y, &z);
-  ptr = (std::shared_ptr<VK::Camera>*)DATA_PTR(self);
-
-  (*ptr)->rotation.x += x;
-  (*ptr)->rotation.y += y;
-  (*ptr)->rotation.z += z;
-
-  return self;
-}
-
-static mrb_value
-cg_cCamera_translate(mrb_state *mrb, mrb_value self)
-{
-  mrb_float x, y, z;
-  std::shared_ptr<VK::Camera> *ptr;
-
-  mrb_get_args(mrb, "fff", &x, &y, &z);
-  ptr = (std::shared_ptr<VK::Camera>*)DATA_PTR(self);
-
-  (*ptr)->position.x += x;
-  (*ptr)->position.y += y;
-  (*ptr)->position.z += z;
-
-  return self;
-}
-
-static mrb_value
-cg_cCamera_translate_by_rotation(mrb_state *mrb, mrb_value self)
-{
-  mrb_float x, y, z;
-  std::shared_ptr<VK::Camera> *ptr;
-
-  mrb_get_args(mrb, "fff", &x, &y, &z);
-  ptr = (std::shared_ptr<VK::Camera>*)DATA_PTR(self);
-
-  glm::mat4 matrix{1.0f};
-  matrix = glm::rotate(
-    matrix, (*ptr)->rotation.x, glm::vec3{1.0f, 0.0f, 0.0f});
-  matrix = glm::rotate(
-    matrix, (*ptr)->rotation.y, glm::vec3{0.0f, 1.0f, 0.0f});
-  matrix = glm::rotate(
-    matrix, (*ptr)->rotation.z, glm::vec3{0.0f, 0.0f, 1.0f});
-
-  glm::vec4 rotated_vector{matrix * glm::vec4{x, y, z, 1.0}};
-
-  (*ptr)->position.x += rotated_vector.x;
-  (*ptr)->position.y += rotated_vector.y;
-  (*ptr)->position.z += rotated_vector.z;
-
-  return self;
-}
-
-void
-cg_camera_init(mrb_state *mrb)
-{
-  struct RClass *cg_m, *cg_cCamera;
-
-  cg_m = mrb_module_get(mrb, "CandyGear");
-  cg_cCamera = mrb_define_class_under(mrb, cg_m, "Camera", mrb->object_class);
-  MRB_SET_INSTANCE_TT(cg_cCamera, MRB_TT_DATA);
-  mrb_define_method(
-    mrb, cg_cCamera, "initialize", cg_cCamera_initialize, MRB_ARGS_REQ(6));
-  mrb_define_method(mrb, cg_cCamera, "use", cg_cCamera_use, MRB_ARGS_NONE());
-  mrb_define_method(
-    mrb, cg_cCamera, "rotate", cg_cCamera_rotate, MRB_ARGS_REQ(3));
-  mrb_define_method(
-    mrb, cg_cCamera, "translate", cg_cCamera_translate, MRB_ARGS_REQ(3));
-  mrb_define_method(
-    mrb, cg_cCamera, "translate_by_rotation",
-    cg_cCamera_translate_by_rotation, MRB_ARGS_REQ(3));
-}
diff --git a/src/camera.hpp b/src/camera.hpp
deleted file mode 100644
index a3d9d1b..0000000
--- a/src/camera.hpp
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright 2022 Frederico de Oliveira Linhares
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef CANDY_GEAR_CAMERA_H
-#define CANDY_GEAR_CAMERA_H 1
-
-#include "core.hpp"
-
-void
-cg_camera_init(mrb_state *mrb);
-
-#endif /* CANDY_GEAR_CAMERA_H */
diff --git a/src/candy_gear.cpp b/src/candy_gear.cpp
index 2575e83..d0922c6 100644
--- a/src/candy_gear.cpp
+++ b/src/candy_gear.cpp
@@ -22,6 +22,9 @@
 
 #include <yaml-cpp/yaml.h>
 
+#include "rotation3d.hpp"
+#include "vector3d.hpp"
+
 static mrb_value
 parse_node(mrb_state *mrb, const YAML::Node &node)
 {
@@ -56,6 +59,28 @@ parse_node(mrb_state *mrb, const YAML::Node &node)
   }
 }
 
+static mrb_value
+cg_mCandyGear_set_camera_position(mrb_state *mrb, mrb_value self)
+{
+  std::shared_ptr<glm::vec3> *camera_position;
+
+  mrb_get_args(mrb, "d", &camera_position, &cg_vector3d_type);
+  cg_core.vk_graphics_pipeline->camera_position = (*camera_position);
+
+  return self;
+}
+
+static mrb_value
+cg_mCandyGear_set_camera_rotation(mrb_state *mrb, mrb_value self)
+{
+  std::shared_ptr<glm::vec3> *camera_rotation;
+
+  mrb_get_args(mrb, "d", &camera_rotation, &cg_rotation3d_type);
+  cg_core.vk_graphics_pipeline->camera_rotation = (*camera_rotation);
+
+  return self;
+}
+
 static mrb_value
 cg_mCandyGear_load_yaml(mrb_state *mrb, mrb_value self)
 {
@@ -109,6 +134,14 @@ cg_candy_gear_init(mrb_state *mrb)
   struct RClass *cg_m;
 
   cg_m = mrb_module_get(mrb, "CandyGear");
+
+  mrb_define_class_method(
+    mrb, cg_m, "camera_position=", cg_mCandyGear_set_camera_position,
+    MRB_ARGS_REQ(1));
+  mrb_define_class_method(
+    mrb, cg_m, "camera_rotation=", cg_mCandyGear_set_camera_rotation,
+    MRB_ARGS_REQ(1));
+
   mrb_define_class_method(
     mrb, cg_m, "load_yaml", cg_mCandyGear_load_yaml, MRB_ARGS_REQ(1));
   mrb_define_class_method(
diff --git a/src/main.cpp b/src/main.cpp
index 5155f60..61f7967 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -17,14 +17,14 @@
 #include <chrono>
 #include <thread>
 
-#include "camera.hpp"
 #include "candy_gear.hpp"
 #include "core.hpp"
 #include "key.hpp"
 #include "model.hpp"
-#include "model/instance.hpp"
+#include "rotation3d.hpp"
 #include "sound.hpp"
 #include "texture.hpp"
+#include "vector3d.hpp"
 
 cg_sCore cg_core;
 
@@ -58,13 +58,13 @@ int main(int argc, char *argv[])
   }
 
   mrb_define_module(cg_core.mrb, "CandyGear");
-  cg_camera_init(cg_core.mrb);
   cg_candy_gear_init(cg_core.mrb);
   cg_key_init(cg_core.mrb);
   cg_model_init(cg_core.mrb);
-  cg_model_instance_init(cg_core.mrb);
+  cg_rotation3d_init(cg_core.mrb);
   cg_sound_init(cg_core.mrb);
   cg_texture_init(cg_core.mrb);
+  cg_vector3d_init(cg_core.mrb);
 
   main_obj = mrb_obj_iv_inspect(cg_core.mrb, cg_core.mrb->top_self);
   sym_init = mrb_intern_cstr(cg_core.mrb, "init");
diff --git a/src/model.cpp b/src/model.cpp
index 1a97c9b..06ddf65 100644
--- a/src/model.cpp
+++ b/src/model.cpp
@@ -16,7 +16,10 @@
 
 #include "model.hpp"
 
+#include "rotation3d.hpp"
 #include "texture.hpp"
+#include "vector3d.hpp"
+#include "vk/model_instance.hpp"
 
 void
 cg_free_model(mrb_state *mrb, void* obj)
@@ -54,6 +57,27 @@ cg_cModel_initialize(mrb_state *mrb, mrb_value self)
   return self;
 }
 
+static mrb_value
+cg_cModel_draw(mrb_state *mrb, mrb_value self)
+{
+  auto *ptr = (std::shared_ptr<VK::Model>*)DATA_PTR(self);
+  VK::ModelInstance instance;
+  std::shared_ptr<glm::vec3> *position;
+  std::shared_ptr<glm::vec3> *rotation;
+
+  mrb_get_args(
+    mrb, "dd", &position, &cg_vector3d_type, &rotation, &cg_rotation3d_type);
+  instance.position = **position;
+  instance.rotation = **rotation;
+
+  auto &instances =
+    cg_core.vk_graphics_pipeline->models_to_draw[
+      cg_core.vk_graphics_pipeline->current_frame][*ptr];
+  instances.push_back(instance);
+
+  return self;
+}
+
 void
 cg_model_init(mrb_state *mrb)
 {
@@ -64,4 +88,5 @@ cg_model_init(mrb_state *mrb)
   MRB_SET_INSTANCE_TT(cg_cModel, MRB_TT_DATA);
   mrb_define_method(
     mrb, cg_cModel, "initialize", cg_cModel_initialize, MRB_ARGS_REQ(2));
+  mrb_define_method(mrb, cg_cModel, "draw", cg_cModel_draw, MRB_ARGS_REQ(2));
 }
diff --git a/src/model/instance.cpp b/src/model/instance.cpp
deleted file mode 100644
index 83a93c2..0000000
--- a/src/model/instance.cpp
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright 2022 Frederico de Oliveira Linhares
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "instance.hpp"
-
-#include "../model.hpp"
-#include "../vk/model_instance.hpp"
-
-// This variable works as a constant
-static mrb_sym id_at_model;
-
-void
-cg_free_model_instance(mrb_state *mrb, void* obj)
-{
-  auto ptr = static_cast<VK::ModelInstance*>(obj);
-
-  mrb_free(mrb, ptr);
-}
-
-const struct mrb_data_type cg_model_instance_type = {
-  "CG_Model_Instance", cg_free_model_instance };
-
-static mrb_value
-cg_cModel_cInstance_initialize(mrb_state *mrb, mrb_value self)
-{
-  mrb_float position_x, position_y, position_z,
-    rotation_x, rotation_y, rotation_z;
-  mrb_value model;
-  VK::ModelInstance *ptr;
-
-  mrb_get_args(
-    mrb, "offffff",
-    &model,
-    &position_x, &position_y, &position_z,
-    &rotation_x, &rotation_y, &rotation_z);
-  ptr = (VK::ModelInstance*)DATA_PTR(self);
-  if(ptr) mrb_free(mrb, ptr);
-  ptr = (VK::ModelInstance*)mrb_malloc(mrb, sizeof(VK::ModelInstance));
-
-  mrb_iv_set(mrb, self, id_at_model, model);
-  ptr->position = glm::vec3(position_x, position_y, position_z);
-  ptr->rotation = glm::vec3(rotation_x, rotation_y, rotation_z);
-
-  mrb_data_init(self, ptr, &cg_model_instance_type);
-  return self;
-}
-
-static mrb_value
-cg_cModel_cInstance_draw(mrb_state *mrb, mrb_value self)
-{
-  mrb_value model_v;
-
-  VK::ModelInstance *ptr;
-  std::shared_ptr<VK::Model> *model_ptr;
-
-  model_v = mrb_iv_get(mrb, self, id_at_model);
-  ptr = (VK::ModelInstance*)DATA_PTR(self);
-  model_ptr = (std::shared_ptr<VK::Model>*) DATA_PTR(model_v);
-
-  auto &instances =
-    cg_core.vk_graphics_pipeline->models_to_draw[
-      cg_core.vk_graphics_pipeline->current_frame][*model_ptr];
-  instances.push_back(*ptr);
-
-  return self;
-}
-
-void
-cg_model_instance_init(mrb_state *mrb)
-{
-  struct RClass *cg_m, *cg_cModel, *cg_cInstance;
-
-  id_at_model = mrb_intern_cstr(mrb, "@model");
-
-  cg_m = mrb_module_get(mrb, "CandyGear");
-  cg_cModel = mrb_class_get_under(mrb, cg_m, "Model");
-  cg_cInstance = mrb_define_class_under(
-    mrb, cg_cModel, "Instance", mrb->object_class);
-  MRB_SET_INSTANCE_TT(cg_cInstance, MRB_TT_DATA);
-  mrb_define_method(
-    mrb, cg_cInstance, "initialize", cg_cModel_cInstance_initialize,
-    MRB_ARGS_REQ(7));
-  mrb_define_method(
-    mrb, cg_cInstance, "draw", cg_cModel_cInstance_draw, MRB_ARGS_NONE());
-}
diff --git a/src/model/instance.hpp b/src/model/instance.hpp
deleted file mode 100644
index f84003c..0000000
--- a/src/model/instance.hpp
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright 2022 Frederico de Oliveira Linhares
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef CANDY_GEAR_MODEL_INSTANCE_H
-#define CANDY_GEAR_MODEL_INSTANCE_H 1
-
-#include "../core.hpp"
-
-void
-cg_model_instance_init(mrb_state *mrb);
-
-#endif /* CANDY_GEAR_MODEL_INSTANCE_H */
diff --git a/src/rotation3d.cpp b/src/rotation3d.cpp
new file mode 100644
index 0000000..d95947b
--- /dev/null
+++ b/src/rotation3d.cpp
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2022 Frederico de Oliveira Linhares
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "rotation3d.hpp"
+
+#include "vector3d.hpp"
+
+namespace
+{
+inline float
+pitch_limit(float pitch)
+{
+  if(pitch > M_PI/2) pitch = M_PI/2;
+  else if (pitch < -(M_PI/2)) pitch = -(M_PI/2);
+
+  return pitch;
+}
+
+}
+
+void
+cg_free_rotation3d(mrb_state *mrb, void* obj)
+{
+  auto ptr = static_cast<std::shared_ptr<glm::vec3>*>(obj);
+
+  ptr->~shared_ptr();
+  mrb_free(mrb, ptr);
+}
+
+const struct mrb_data_type cg_rotation3d_type = {
+  "CG_Rotation3D", cg_free_rotation3d};
+
+static mrb_value
+cg_cRotation3D_initialize(mrb_state *mrb, mrb_value self)
+{
+  mrb_float pitch, yaw, roll;
+  std::shared_ptr<glm::vec3> *ptr;
+
+  mrb_get_args(mrb, "fff", &pitch, &yaw, &roll);
+  ptr = (std::shared_ptr<glm::vec3>*)DATA_PTR(self);
+  if(ptr) mrb_free(mrb, ptr);
+  ptr = (std::shared_ptr<glm::vec3>*)mrb_malloc(
+    mrb, sizeof(std::shared_ptr<glm::vec3>));
+
+  new(ptr)std::shared_ptr<glm::vec3>(
+    std::make_shared<glm::vec3>(pitch_limit(pitch), yaw, roll));
+
+  mrb_data_init(self, ptr, &cg_rotation3d_type);
+  return self;
+}
+
+// Rotation when there is a up direction (ex.: Earth).
+static mrb_value
+cg_cRotation3D_rotate(mrb_state *mrb, mrb_value self)
+{
+  mrb_float pitch, yaw;
+  auto *ptr = (std::shared_ptr<glm::vec3>*)DATA_PTR(self);
+
+  mrb_get_args(mrb, "ff", &pitch, &yaw);
+
+  (*ptr)->x = pitch_limit((*ptr)->x + pitch);
+  (*ptr)->y += yaw;
+
+  return self;
+}
+
+// Rotation when there is a up direction (ex.: space without gravity).
+static mrb_value
+cg_cRotation3D_baseless_rotation(mrb_state *mrb, mrb_value self)
+{
+  mrb_float x, y;
+
+  // TODO
+
+  return self;
+}
+
+void
+cg_rotation3d_init(mrb_state *mrb)
+{
+  struct RClass *cg_m, *cg_cRotation3D;
+
+  cg_m = mrb_module_get(mrb, "CandyGear");
+  cg_cRotation3D = mrb_define_class_under(
+    mrb, cg_m, "Rotation3D", mrb->object_class);
+  MRB_SET_INSTANCE_TT(cg_cRotation3D, MRB_TT_DATA);
+  mrb_define_method(
+    mrb, cg_cRotation3D, "initialize", cg_cRotation3D_initialize,
+    MRB_ARGS_REQ(3));
+
+  mrb_define_method(
+    mrb, cg_cRotation3D, "pitch", cg_cVector3D_get_x, MRB_ARGS_NONE());
+  mrb_define_method(
+    mrb, cg_cRotation3D, "yaw", cg_cVector3D_get_y, MRB_ARGS_NONE());
+  mrb_define_method(
+    mrb, cg_cRotation3D, "roll", cg_cVector3D_get_z, MRB_ARGS_NONE());
+
+  mrb_define_method(
+    mrb, cg_cRotation3D, "rotate", cg_cRotation3D_rotate, MRB_ARGS_REQ(2));
+}
diff --git a/src/rotation3d.hpp b/src/rotation3d.hpp
new file mode 100644
index 0000000..6b94e89
--- /dev/null
+++ b/src/rotation3d.hpp
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2022 Frederico de Oliveira Linhares
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CANDY_GEAR_ROTATION3D_H
+#define CANDY_GEAR_ROTATION3D_H 1
+
+#include "core.hpp"
+
+extern const struct mrb_data_type cg_rotation3d_type;
+
+void
+cg_rotation3d_init(mrb_state *mrb);
+
+#endif /* CANDY_GEAR_ROTATION3D_H */
diff --git a/src/vector3d.cpp b/src/vector3d.cpp
new file mode 100644
index 0000000..a2e0e4c
--- /dev/null
+++ b/src/vector3d.cpp
@@ -0,0 +1,176 @@
+/*
+ * Copyright 2022 Frederico de Oliveira Linhares
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "vector3d.hpp"
+
+#include <memory>
+
+#include <glm/vec3.hpp>
+
+#include "rotation3d.hpp"
+
+void
+cg_free_vector3d(mrb_state *mrb, void* obj)
+{
+  auto ptr = static_cast<std::shared_ptr<glm::vec3>*>(obj);
+
+  ptr->~shared_ptr();
+  mrb_free(mrb, ptr);
+}
+
+const struct mrb_data_type cg_vector3d_type = {
+  "CG_Vector3D", cg_free_vector3d};
+
+static mrb_value
+cg_cVector3D_initialize(mrb_state *mrb, mrb_value self)
+{
+  mrb_float x = 0.0f;
+  mrb_float y = 0.0f;
+  mrb_float z = 0.0f;
+  std::shared_ptr<glm::vec3> *ptr;
+
+  mrb_get_args(mrb, "|fff", &x, &y, &z);
+  ptr = (std::shared_ptr<glm::vec3>*)DATA_PTR(self);
+  if(ptr) mrb_free(mrb, ptr);
+  ptr = (std::shared_ptr<glm::vec3>*)mrb_malloc(
+    mrb, sizeof(std::shared_ptr<glm::vec3>));
+
+  new(ptr)std::shared_ptr<glm::vec3>(std::make_shared<glm::vec3>(x, y, z));
+
+  mrb_data_init(self, ptr, &cg_vector3d_type);
+  return self;
+}
+
+mrb_value
+cg_cVector3D_get_x(mrb_state *mrb, mrb_value self)
+{
+  std::shared_ptr<glm::vec3> *ptr =
+    (std::shared_ptr<glm::vec3>*)DATA_PTR(self);
+
+  return mrb_float_value(mrb, (*ptr)->x);
+}
+
+mrb_value
+cg_cVector3D_get_y(mrb_state *mrb, mrb_value self)
+{
+  std::shared_ptr<glm::vec3> *ptr =
+    (std::shared_ptr<glm::vec3>*)DATA_PTR(self);
+
+  return mrb_float_value(mrb, (*ptr)->y);
+}
+
+mrb_value
+cg_cVector3D_get_z(mrb_state *mrb, mrb_value self)
+{
+  std::shared_ptr<glm::vec3> *ptr =
+    (std::shared_ptr<glm::vec3>*)DATA_PTR(self);
+
+  return mrb_float_value(mrb, (*ptr)->z);
+}
+
+static mrb_value
+cg_cVector3D_set_x(mrb_state *mrb, mrb_value self)
+{
+  mrb_float x;
+  std::shared_ptr<glm::vec3> *ptr =
+    (std::shared_ptr<glm::vec3>*)DATA_PTR(self);
+
+  mrb_get_args(mrb, "f", &x);
+  (*ptr)->x = x;
+
+  return self;
+}
+
+static mrb_value
+cg_cVector3D_set_y(mrb_state *mrb, mrb_value self)
+{
+  mrb_float y;
+  std::shared_ptr<glm::vec3> *ptr =
+    (std::shared_ptr<glm::vec3>*)DATA_PTR(self);
+
+  mrb_get_args(mrb, "f", &y);
+  (*ptr)->y = y;
+
+  return self;
+}
+
+static mrb_value
+cg_cVector3D_set_z(mrb_state *mrb, mrb_value self)
+{
+  mrb_float z;
+  std::shared_ptr<glm::vec3> *ptr =
+    (std::shared_ptr<glm::vec3>*)DATA_PTR(self);
+
+  mrb_get_args(mrb, "f", &z);
+  (*ptr)->z = z;
+
+  return self;
+}
+
+static mrb_value
+cg_cVector3D_translate(mrb_state *mrb, mrb_value self)
+{
+  std::shared_ptr<glm::vec3> *ptr =
+    (std::shared_ptr<glm::vec3>*)DATA_PTR(self);
+  std::shared_ptr<glm::vec3> *direction, *rotation;
+
+  mrb_get_args(
+    mrb, "dd", &direction, &cg_vector3d_type, &rotation, &cg_rotation3d_type);
+
+  glm::mat4 matrix{1.0f};
+  glm::vec4 vec{(**direction), 1.0f};
+  matrix = glm::rotate(matrix, (*rotation)->y, glm::vec3{0.0f, 1.0f, 0.0f});
+  matrix = glm::rotate(matrix, (*rotation)->x, glm::vec3{1.0f, 0.0f, 0.0f});
+  matrix = glm::rotate(matrix, (*rotation)->z, glm::vec3{0.0f, 0.0f, 1.0f});
+  vec = matrix * vec;
+
+  (*ptr)->x += vec.x;
+  (*ptr)->y += vec.y;
+  (*ptr)->z += vec.z;
+
+  return self;
+}
+
+void
+cg_vector3d_init(mrb_state *mrb)
+{
+  struct RClass *cg_m, *cg_cVector3D;
+
+  cg_m = mrb_module_get(mrb, "CandyGear");
+  cg_cVector3D = mrb_define_class_under(
+    mrb, cg_m, "Vector3D", mrb->object_class);
+  MRB_SET_INSTANCE_TT(cg_cVector3D, MRB_TT_DATA);
+  mrb_define_method(
+    mrb, cg_cVector3D, "initialize", cg_cVector3D_initialize,
+    MRB_ARGS_NONE()|MRB_ARGS_OPT(3));
+
+  mrb_define_method(
+    mrb, cg_cVector3D, "x", cg_cVector3D_get_x, MRB_ARGS_NONE());
+  mrb_define_method(
+    mrb, cg_cVector3D, "y", cg_cVector3D_get_y, MRB_ARGS_NONE());
+  mrb_define_method(
+    mrb, cg_cVector3D, "z", cg_cVector3D_get_z, MRB_ARGS_NONE());
+
+  mrb_define_method(
+    mrb, cg_cVector3D, "x=", cg_cVector3D_set_x, MRB_ARGS_REQ(1));
+  mrb_define_method(
+    mrb, cg_cVector3D, "y=", cg_cVector3D_set_y, MRB_ARGS_REQ(1));
+  mrb_define_method(
+    mrb, cg_cVector3D, "z=", cg_cVector3D_set_z, MRB_ARGS_REQ(1));
+
+  mrb_define_method(
+    mrb, cg_cVector3D, "translate", cg_cVector3D_translate, MRB_ARGS_REQ(2));
+}
diff --git a/src/vector3d.hpp b/src/vector3d.hpp
new file mode 100644
index 0000000..2533f4e
--- /dev/null
+++ b/src/vector3d.hpp
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2022 Frederico de Oliveira Linhares
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CANDY_GEAR_VECTOR3D_H
+#define CANDY_GEAR_VECTOR3D_H 1
+
+#include "core.hpp"
+
+extern const struct mrb_data_type cg_vector3d_type;
+
+mrb_value
+cg_cVector3D_get_x(mrb_state *mrb, mrb_value self);
+mrb_value
+cg_cVector3D_get_y(mrb_state *mrb, mrb_value self);
+mrb_value
+cg_cVector3D_get_z(mrb_state *mrb, mrb_value self);
+
+void
+cg_vector3d_init(mrb_state *mrb);
+
+#endif /* CANDY_GEAR_VECTOR3D_H */
diff --git a/src/vk/camera.hpp b/src/vk/camera.hpp
deleted file mode 100644
index 5f09390..0000000
--- a/src/vk/camera.hpp
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright 2022 Frederico de Oliveira Linhares
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef CANDY_GEAR_VK_CAMERA_H
-#define CANDY_GEAR_VK_CAMERA_H 1
-
-#include "core.hpp"
-
-namespace VK
-{
-
-struct Camera
-{
-  glm::vec3 position;
-  glm::vec3 rotation; // Radians
-};
-
-}
-
-#endif /* CANDY_GEAR_VK_CAMERA_H */
diff --git a/src/vk/graphics_pipeline.cpp b/src/vk/graphics_pipeline.cpp
index de08945..3956a99 100644
--- a/src/vk/graphics_pipeline.cpp
+++ b/src/vk/graphics_pipeline.cpp
@@ -845,7 +845,8 @@ namespace VK
 
 GraphicsPipeline::GraphicsPipeline():
   current_frame{0},
-  camera{std::make_shared<VK::Camera>()},
+  camera_position{std::make_shared<glm::vec3>(0.0f, 0.0f, 0.0f)},
+  camera_rotation{std::make_shared<glm::vec3>(0.0f, 0.0f, 0.0f)},
   models_to_draw{cg_core.vk_swapchain->images_count}
 {
   loader.execute(this);
@@ -952,17 +953,14 @@ GraphicsPipeline::draw()
       {
 	// Object matrix.
 	glm::mat4 instance_matrix{1.0f};
+	instance_matrix = glm::translate(
+	  instance_matrix, instances[i].position);
 	instance_matrix = glm::rotate(
-	  instance_matrix, glm::radians(instances[i].rotation.x),
-	  glm::vec3{1.0, 0.0, 0.0});
+	  instance_matrix, instances[i].rotation.x, glm::vec3{1.0, 0.0, 0.0});
 	instance_matrix = glm::rotate(
-	  instance_matrix, glm::radians(instances[i].rotation.y),
-	  glm::vec3{0.0, 1.0, 0.0});
+	  instance_matrix, instances[i].rotation.y, glm::vec3{0.0, 1.0, 0.0});
 	instance_matrix = glm::rotate(
-	  instance_matrix, glm::radians(instances[i].rotation.z),
-	  glm::vec3{0.0, 0.0, 1.0});
-	instance_matrix = glm::translate(
-	  instance_matrix, instances[i].position);
+	  instance_matrix, instances[i].rotation.z, glm::vec3{0.0, 0.0, 1.0});
 
 	ubo_model_instance.model[i] = instance_matrix;
       }
@@ -982,16 +980,16 @@ GraphicsPipeline::draw()
     // View matrix.
     ubo_view_projection.view = glm::mat4{1.0f};
     ubo_view_projection.view = glm::translate(
-        ubo_view_projection.view, this->camera->position);
+        ubo_view_projection.view, *this->camera_position);
     ubo_view_projection.view = glm::rotate(
-        ubo_view_projection.view, this->camera->rotation.x,
-        glm::vec3{1.0, 0.0, 0.0});
+      ubo_view_projection.view, this->camera_rotation->y,
+      glm::vec3{0.0, 1.0, 0.0});
     ubo_view_projection.view = glm::rotate(
-        ubo_view_projection.view, this->camera->rotation.y,
-        glm::vec3{0.0, 1.0, 0.0});
+      ubo_view_projection.view, this->camera_rotation->x,
+      glm::vec3{1.0, 0.0, 0.0});
     ubo_view_projection.view = glm::rotate(
-        ubo_view_projection.view, this->camera->rotation.z,
-        glm::vec3{0.0, 0.0, 1.0});
+      ubo_view_projection.view, this->camera_rotation->z,
+      glm::vec3{0.0, 0.0, 1.0});
     ubo_view_projection.view = glm::inverse(ubo_view_projection.view);
 
     // Projection matrix.
diff --git a/src/vk/graphics_pipeline.hpp b/src/vk/graphics_pipeline.hpp
index dffd6fb..b4a282a 100644
--- a/src/vk/graphics_pipeline.hpp
+++ b/src/vk/graphics_pipeline.hpp
@@ -22,7 +22,6 @@
 
 #include "../command.hpp"
 #include "core.hpp"
-#include "camera.hpp"
 #include "command_pool.hpp"
 #include "model.hpp"
 #include "model_instance.hpp"
@@ -64,7 +63,8 @@ struct GraphicsPipeline
   std::vector<VkSemaphore> render_finished_semaphores;
   std::vector<VkFence> in_flight_fences;
 
-  std::shared_ptr<Camera> camera;
+  std::shared_ptr<glm::vec3> camera_position;
+  std::shared_ptr<glm::vec3> camera_rotation;
   std::vector<std::unordered_map<
     std::shared_ptr<Model>, std::vector<ModelInstance>>>
   models_to_draw;
-- 
cgit v1.2.3