temp
/libmspgame.a
/libmspgame.so
+/libmspgameview.a
+/libmspgameview.so
/mspgame.pc
require "mspcore";
require "mspdatafile";
require "mspmath";
+ require "mspgui";
+ require "mspgl";
+ require "sigc++-2.0";
build_info
{
map "source" "include/msp";
};
};
+
+ library "mspgameview"
+ {
+ source "source/gameview";
+ use "mspgame";
+ install true;
+ install_map
+ {
+ map "source" "include/msp";
+ };
+ };
};
--- /dev/null
+#include "camera.h"
+
+using namespace std;
+
+namespace Msp::Game {
+
+Camera::Camera(Handle<Entity> e, const CameraSetup &s):
+ Component(e),
+ setup(s),
+ fov_y(setup.field_of_view_y),
+ size(setup.size),
+ near_clip(setup.near_clip),
+ far_clip(setup.far_clip)
+{
+ if(!is_orthographic())
+ size = { get_aspect(), 1.0f };
+}
+
+void Camera::set_field_of_view(Geometry::Angle<float> f, float a)
+{
+ if(is_orthographic())
+ throw logic_error("Camera is not perspective");
+
+ fov_y = f;
+ size = { a, 1.0f };
+}
+
+void Camera::set_size(const LinAl::Vector<float, 2> &s)
+{
+ if(!is_orthographic())
+ throw logic_error("Camera is not orthographic");
+
+ size = s;
+}
+
+} // namespace Msp::Game
--- /dev/null
+#ifndef MSP_GAME_CAMERA_H_
+#define MSP_GAME_CAMERA_H_
+
+#include <msp/geometry/angle.h>
+#include <msp/linal/vector.h>
+#include "component.h"
+
+namespace Msp::Game {
+
+enum class CameraScaling
+{
+ ORIGINAL_SIZE,
+ SCALE_TO_FIT,
+ SCALE_TO_COVER,
+ STRETCH_TO_FIT
+};
+
+struct CameraSetup
+{
+ Geometry::Angle<float> field_of_view_y = Geometry::Angle<float>::from_degrees(60);
+ LinAl::Vector<float, 2> size = { 16.0f/9.0f, 1.0f };
+ float near_clip = 0.1f;
+ float far_clip = 100.0f;
+ CameraScaling scaling = CameraScaling::SCALE_TO_FIT;
+ std::string sequence_name;
+};
+
+class Camera: public Component
+{
+public:
+ using Setup = CameraSetup;
+
+private:
+ const Setup &setup;
+ Geometry::Angle<float> fov_y;
+ LinAl::Vector<float, 2> size;
+ float height;
+ float near_clip;
+ float far_clip;
+
+public:
+ Camera(Handle<Entity>, const Setup &);
+
+ void set_field_of_view(Geometry::Angle<float>, float);
+ void set_size(const LinAl::Vector<float, 2> &);
+ bool is_orthographic() const { return fov_y==Geometry::Angle<float>::zero(); }
+ Geometry::Angle<float> get_fov_vertical() const { return fov_y; }
+ Geometry::Angle<float> get_fov_horizontal() const { return Geometry::atan(tan(fov_y/2.0f)*get_aspect())*2.0f; }
+ const LinAl::Vector<float, 2> &get_size() const { return size; }
+ float get_aspect() const { return size.x/size.y; }
+ float get_near_clip() const { return near_clip; }
+ float get_far_clip() const { return far_clip; }
+ CameraScaling get_scaling() const { return setup.scaling; }
+ const std::string &get_sequence_name() const { return setup.sequence_name; }
+};
+
+} // namespace Msp::Game
+
+#endif
namespace Msp::Game {
+class Camera;
class Component;
class Entity;
class Stage;
Stage &stage;
};
+struct CameraChanged
+{
+ Handle<Camera> camera;
+};
+
} // namespace Events
} // namespace Msp::Game
#include "stage.h"
+#include "camera.h"
#include "root.h"
#include "system.h"
+using namespace std;
+
namespace Msp::Game {
Stage::Stage(DataFile::Collection &r):
resources(r),
event_source(event_bus),
+ event_observer(event_bus),
root(std::make_unique<Root>(*this))
-{ }
+{
+ event_observer.observe<Events::ComponentCreated>([this](auto &e){
+ if(!active_camera)
+ if(Handle<Camera> camera = dynamic_handle_cast<Camera>(e.component))
+ set_active_camera(camera);
+ });
+}
// Hide unique_ptr destructors from the header
Stage::~Stage()
erase_if(systems, [&s](auto &p){ return p.get()==&s; });
}
+void Stage::set_active_camera(Handle<Camera> c)
+{
+ active_camera = c;
+ event_source.emit<Events::CameraChanged>(active_camera);
+}
+
void Stage::tick(Time::TimeDelta dt)
{
for(const auto &s: systems)
namespace Msp::Game {
+class Camera;
class Root;
class System;
{
public:
using EventSource = Game::EventSource<Events::EntityCreated, Events::EntityDestroyed,
- Events::ComponentCreated, Events::ComponentDestroyed>;
+ Events::ComponentCreated, Events::ComponentDestroyed, Events::CameraChanged>;
private:
DataFile::Collection &resources;
PoolPool pools;
EventBus event_bus;
EventSource event_source;
+ EventObserver event_observer;
/* Use unique_ptr because there's only one root per stage so it's pointless
to put it in a pool. */
std::unique_ptr<Root> root;
std::vector<std::unique_ptr<System>> systems;
+ Handle<Camera> active_camera;
public:
Stage(DataFile::Collection &);
template<typename T>
T *get_system() const;
+ void set_active_camera(Handle<Camera>);
+ Handle<Camera> get_active_camera() const { return active_camera; }
+
void tick(Time::TimeDelta);
};
--- /dev/null
+#ifndef MSP_GAMEVIEW_APPLICATION_H_
+#define MSP_GAMEVIEW_APPLICATION_H_
+
+#include <msp/core/application.h>
+#include <msp/game/director.h>
+#include <msp/gl/device.h>
+#include <msp/gl/windowview.h>
+#include <msp/graphics/display.h>
+#include <msp/graphics/window.h>
+#include "presenter.h"
+
+namespace Msp::GameView {
+
+template<typename T, typename R>
+class Application: public Msp::RegisteredApplication<T>
+{
+public:
+ using ResourcesType = R;
+
+protected:
+ Msp::Graphics::Display display;
+ Msp::Graphics::Window window;
+ GL::Device gl_device;
+ ResourcesType resources;
+ Msp::Game::Director director;
+ GL::WindowView gl_view;
+ Presenter presenter;
+
+public:
+ Application();
+
+ int main() override;
+protected:
+ void tick() override;
+};
+
+template<typename T, typename R>
+Application<T, R>::Application():
+ window(display, 1920, 1080),
+ gl_device(window),
+ director(resources),
+ gl_view(window),
+ presenter(director, gl_view)
+{
+ window.signal_close.connect(sigc::bind(sigc::mem_fun(this, &Application::exit), 0));
+}
+
+template<typename T, typename R>
+int Application<T, R>::main()
+{
+ window.show();
+ return Msp::Application::main();
+}
+
+template<typename T, typename R>
+void Application<T, R>::tick()
+{
+ display.tick();
+ director.tick();
+}
+
+} // namespace Msp::GameView
+
+#endif
--- /dev/null
+#include "presenter.h"
+#include <functional>
+#include <msp/game/events.h>
+#include <msp/game/stage.h>
+#include "renderer.h"
+
+using namespace std;
+
+namespace Msp::GameView {
+
+Presenter::Presenter(Game::Director &d, GL::View &v):
+ director(d),
+ gl_view(v),
+ resources(director.get_resources()),
+ event_observer(director.get_event_bus())
+{
+ event_observer.observe<Game::Events::StageActivated>([this](auto &e){ stage_activated(e); });
+
+ if(Game::Stage *active_stage = director.get_active_stage())
+ stage_activated({ *active_stage });
+}
+
+Presenter::~Presenter()
+{
+ for(Renderer *r: renderers)
+ r->get_stage().remove_system(*r);
+}
+
+void Presenter::stage_activated(const Game::Events::StageActivated &event)
+{
+ if(!event.stage.get_system<Renderer>())
+ renderers.push_back(&event.stage.add_system<Renderer>(ref(gl_view)));
+}
+
+} // namespace Msp::GameView
--- /dev/null
+#ifndef MSP_GAMEVIEW_PRESENTER_H_
+#define MSP_GAMEVIEW_PRESENTER_H_
+
+#include <msp/datafile/collection.h>
+#include <msp/game/director.h>
+#include <msp/game/eventobserver.h>
+#include <msp/gl/view.h>
+
+namespace Msp::GameView {
+
+class Renderer;
+
+class Presenter
+{
+private:
+ Game::Director &director;
+ GL::View &gl_view;
+ DataFile::Collection &resources;
+ Game::EventObserver event_observer;
+ std::vector<Renderer *> renderers;
+
+public:
+ Presenter(Game::Director &, GL::View &);
+ ~Presenter();
+
+private:
+ void stage_activated(const Game::Events::StageActivated &);
+};
+
+} // namespace Msp::GameView
+
+#endif
--- /dev/null
+#include "renderer.h"
+#include <msp/game/entity.h>
+#include <msp/game/stage.h>
+#include <msp/game/transform.h>
+#include <msp/gl/sequencebuilder.h>
+
+using namespace std;
+
+namespace Msp::GameView {
+
+Renderer::Renderer(Game::Stage &s, GL::View &v):
+ System(s),
+ view(v),
+ event_observer(s.get_event_bus())
+{
+ event_observer.observe<Game::Events::CameraChanged>([this](auto &e){ camera_changed(e); });
+
+ if(Game::Handle<Game::Camera> ac = stage.get_active_camera())
+ camera_changed({ ac });
+
+ view.set_camera(&gl_camera);
+}
+
+Renderer::~Renderer()
+{ }
+
+void Renderer::camera_changed(const Game::Events::CameraChanged &event)
+{
+ active_camera = event.camera;
+ if(event.camera)
+ {
+ const string &seq_name = event.camera->get_sequence_name();
+ if(seq_name!=current_seq_name)
+ {
+ current_seq_name = seq_name;
+ GL::SequenceBuilder bld(stage.get_resources().get<GL::SequenceTemplate>(seq_name));
+ bld.set_renderable("content", scene);
+ sequence.reset(bld.build(view));
+ view.set_content(sequence.get());
+ }
+ }
+}
+
+void Renderer::tick(Time::TimeDelta)
+{
+ if(active_camera)
+ {
+ Game::Handle<Game::Transform> transform = active_camera->get_entity()->get_transform();
+ if(transform)
+ gl_camera.set_object_matrix(transform->get_world_matrix());
+ else
+ gl_camera.set_object_matrix(GL::Matrix());
+ if(active_camera->is_orthographic())
+ {
+ const LinAl::Vector<float, 2> &size = active_camera->get_size();
+ gl_camera.set_orthographic(size.x, size.y);
+ }
+ else
+ gl_camera.set_field_of_view(active_camera->get_fov_vertical());
+ gl_camera.set_depth_clip(active_camera->get_near_clip(), active_camera->get_far_clip());
+ }
+ view.render();
+}
+
+} // namespace Msp::GameView
--- /dev/null
+#ifndef MSP_GAMEVIEW_RENDERER_H_
+#define MSP_GAMEVIEW_RENDERER_H_
+
+#include <msp/game/camera.h>
+#include <msp/game/eventobserver.h>
+#include <msp/game/events.h>
+#include <msp/game/owned.h>
+#include <msp/game/system.h>
+#include <msp/gl/camera.h>
+#include <msp/gl/sequence.h>
+#include <msp/gl/simplescene.h>
+#include <msp/gl/view.h>
+
+namespace Msp::GameView {
+
+class Renderer: public Game::System
+{
+private:
+ GL::View &view;
+ Game::EventObserver event_observer;
+ GL::SimpleScene scene;
+ Game::Handle<Game::Camera> active_camera;
+ GL::Camera gl_camera;
+ std::string current_seq_name;
+ std::unique_ptr<GL::Sequence> sequence;
+
+public:
+ Renderer(Game::Stage &, GL::View &);
+ ~Renderer();
+
+private:
+ void camera_changed(const Game::Events::CameraChanged &);
+
+public:
+ void tick(Time::TimeDelta) override;
+};
+
+} // namespace Msp::GameView
+
+#endif