cs381/as5/as5.cpp

197 lines
5.3 KiB
C++

#include "AudioDevice.hpp"
#include "Color.hpp"
#include "Keyboard.hpp"
#include "Matrix.hpp"
#include "Mesh.hpp"
#include "Model.hpp"
#include "RadiansDegrees.hpp"
#include "Vector3.hpp"
#include "raylib.h"
#include <concepts>
#include <functional>
#include <memory>
#include <optional>
#include <raylib-cpp.hpp>
#include <vector>
#define SKYBOX_IMPLEMENTATION
#include "skybox.hpp"
void DrawBoundedModel(raylib::Model &model, auto transformer) {
// store the original transform to apply a different transform to the
// model without affecting the next time we draw
raylib::Matrix oldTransform = model.GetTransform();
// apply the transform that we get from whatever the transformer callback
// gives us
raylib::Matrix transform = transformer(model.GetTransform());
// apply the transform that we got from the transformer to the model
model.SetTransform(transform);
// draw the model, passing the origin and default scale as arguments since
// the transform is already applied to the model
model.Draw({ 0, 0, 0 }, 1.0f, raylib::Color::White());
// get the bounding box of the model after applying the transform
auto box = model.GetTransformedBoundingBox();
// draw the bounding box of the model using raylib's built in function
DrawBoundingBox(box, raylib::Color::White());
// restore the model's transform to its original state so that the next time we
// draw the model, it doesn't have the previous transform applied to it
model.SetTransform(oldTransform);
}
class Component {
public:
struct Entity *entity;
virtual void Setup() = 0;
virtual void Update(float dt) = 0;
virtual void Cleanup() = 0;
};
struct Entity {
std::vector<std::shared_ptr<Component>> components;
template<std::derived_from<Component> T>
T &AddComponent() {
std::shared_ptr<Component> out = components.emplace_back(std::make_shared<T>());
out->entity = this;
return (T &)*out;
}
template<std::derived_from<Component> T>
std::optional<std::reference_wrapper<T>> GetComponent() const {
for (auto &c : components) {
T *cast = dynamic_cast<T *>(c.get());
if (cast) {
return *cast;
}
}
return { };
}
};
struct TransformComponent : public Component {
raylib::Vector3 position = { 0, 0, 0 };
raylib::Quaternion rotation = raylib::Quaternion::Identity();
void Setup() override { }
void Update(float dt) override { }
void Cleanup() override { }
};
struct DrawModelComponent : public Component {
raylib::Model *model;
void Setup() override { }
void Update(float dt) override {
DrawBoundedModel(*model, [this](raylib::Transform old) {
auto t = entity->GetComponent<TransformComponent>();
if (t) {
return old
.Translate(t->get().position)
.Rotate(t->get().rotation);
}
return old;
});
}
void Cleanup() override { }
};
template<typename T>
struct Delegate { };
template<typename TReturn, typename... TArgs>
struct Delegate<TReturn(TArgs...)> {
std::vector<std::function<void(int)>> functions;
void connect(const std::function<TReturn(TArgs ...)> &func) {
functions.push_back(func);
}
void operator+=(const std::function<TReturn(TArgs ...)> &func) {
connect(func);
}
void operator()(int arg) {
static_assert(
std::is_same_v<TReturn, void>,
"EC HW: Delegate only supports void return type");
for (const auto &func : functions) {
f(std::forward<TArgs>(arg)...);
}
}
};
raylib::Degree angle_normalize(raylib::Degree angle) {
float decimal = float(angle) - int(angle);
int normalized = (int(angle) % 360 + 360) % 360;
return raylib::Degree(normalized + decimal);
}
int main() {
raylib::Window window(800, 600, "CS381 - Assignment 5");
window.SetState(FLAG_WINDOW_RESIZABLE);
raylib::AudioDevice audio;
raylib::Model penguin("models/penguin.glb");
raylib::Transform penguinTransform = raylib::Transform::Identity()
.Scale(40, 40, 40);
penguin.SetTransform(penguinTransform);
raylib::Camera3D camera(
{ 0, 400, -40 },
{ 0, -0.25f, 1 },
{ 0, 1, 0 },
45.0f);
raylib::Model ground = raylib::Mesh::Plane(10000, 10000, 50, 50, 25);
raylib::Texture snowTexture("textures/snow.jpg");
ground.GetMaterials()[0].maps[MATERIAL_MAP_DIFFUSE].texture = snowTexture;
cs381::SkyBox skybox("textures/skybox.png");
std::vector<Entity> entities;
Entity &e = entities.emplace_back();
e.AddComponent<TransformComponent>();
e.AddComponent<DrawModelComponent>();
e.GetComponent<DrawModelComponent>()->get().model = &penguin;
window.SetTargetFPS(60); // save cpu cycles
while (!window.ShouldClose()) {
window.BeginDrawing();
window.ClearBackground(raylib::Color::Gray());
float dt = window.GetFrameTime();
camera.BeginMode();
skybox.Draw();
ground.Draw({ 0, 0, 0 }, 1.0f, raylib::Color::White());
for (const Entity &e : entities) {
for (const std::shared_ptr<Component> &c : e.components) {
c->Update(dt);
}
}
camera.EndMode();
window.EndDrawing();
}
return 0;
}