Skip to content

Instantly share code, notes, and snippets.

@usagi
Last active August 29, 2015 13:59
Show Gist options
  • Select an option

  • Save usagi/10658860 to your computer and use it in GitHub Desktop.

Select an option

Save usagi/10658860 to your computer and use it in GitHub Desktop.
#pragma once
// TODO: impl
#pragma once
#include <forward_list>
#include <unordered_map>
#include <GLFW/glfw3.h>
#include "subsystem_base.hxx"
namespace
{
using window_owner_dictionary_t = std::unordered_map
< GLFWwindow*
, std::weak_ptr<wonder_rabbit_project::wonderland::subsystem::subsystem_base_t>
>;
window_owner_dictionary_t window_owner_dictionary;
}
namespace wonder_rabbit_project
{
namespace wonderland
{
namespace subsystem
{
struct glfw3_runtime_error_t
: subsystem_runtime_error_t
{
glfw3_runtime_error_t(const std::string& what)
: subsystem_runtime_error_t(what)
{ }
};
class GLFW3_t
: public subsystem_base_t
{
using dtor_hook_t = std::function<void()>;
using dtor_hooks_t = std::forward_list<dtor_hook_t>;
dtor_hooks_t _dtor_hooks;
GLFWwindow* _window;
public:
static constexpr const char* initialize_param_key_width = "width";
static constexpr const char* initialize_param_key_height = "height";
static constexpr const char* initialize_param_key_title = "title";
static constexpr const char* initialize_param_key_monitor = "monitor";
static constexpr const char* initialize_param_key_window = "window";
static constexpr int initialize_param_default_width = 320;
static constexpr int initialize_param_default_height = 240;
static constexpr const char* initialize_param_default_title = "some other wonderland with GLFW3";
static constexpr GLFWmonitor* initialize_param_default_monitor = nullptr;
static constexpr GLFWwindow* initialize_param_default_window = nullptr;
~GLFW3_t()
{
while( not _dtor_hooks.empty() )
{
_dtor_hooks.front()();
_dtor_hooks.pop_front();
}
}
auto default_initialize_params() const
-> initialize_params_t
{
return
{ { initialize_param_key_width , initialize_param_default_width }
, { initialize_param_key_height , initialize_param_default_height }
, { initialize_param_key_title , initialize_param_default_title }
, { initialize_param_key_monitor, initialize_param_default_monitor }
, { initialize_param_key_window , initialize_param_default_window }
};
}
auto initialize( initialize_params_t&& ps )
-> void override
{
ps = fill_initialize_params( std::move(ps) );
{
const auto r = glfwInit();
if ( not r )
throw glfw3_runtime_error_t( std::string("glfwInit failed. return value: ") + std::to_string(r) );
}
_dtor_hooks.emplace_front( []{ glfwTerminate(); } );
glfwSetErrorCallback
( [](int error, const char* description)
{ throw glfw3_runtime_error_t
( std::string("glfw error: error = ") + std::to_string(error)
+ std::string(" , description = ") + std::string(description)
);
}
);
const auto window = _window
= glfwCreateWindow
( boost::any_cast< int >( ps[initialize_param_key_width ] )
, boost::any_cast< int >( ps[initialize_param_key_height ] )
, boost::any_cast< const char* >( ps[initialize_param_key_title ] )
, boost::any_cast< GLFWmonitor* >( ps[initialize_param_key_monitor] )
, boost::any_cast< GLFWwindow* >( ps[initialize_param_key_window ] )
);
if ( not window )
throw glfw3_runtime_error_t
( "glfwCreateWindow failed. window is nullptr." );
::window_owner_dictionary.emplace( window, shared_from_this() );
_dtor_hooks.emplace_front( [window]
{
::window_owner_dictionary.erase( window );
glfwDestroyWindow( window );
});
glfwMakeContextCurrent( window );
glfwSetKeyCallback
( window
, [] ( GLFWwindow* window, int key, int scancode, int action, int mods )
{
::window_owner_dictionary
.at(window)
.lock()
-> keyboard_state(unsigned(key), bool(action));
}
);
glfwSetFramebufferSizeCallback
( window
, [](GLFWwindow* window, int width, int height)
{ glViewport(0, 0, width, height); }
);
}
auto after_render()
-> void override
{
glfwSwapBuffers( _window );
glfwPollEvents();
}
auto to_continue() const
-> bool override
{ return not glfwWindowShouldClose( _window ); }
auto to_continue(const bool b)
-> void override
{ glfwSetWindowShouldClose( _window, int( not b ) ); }
auto version() const
-> version_t override
{ return { GLFW_VERSION_MAJOR , GLFW_VERSION_MINOR , GLFW_VERSION_REVISION }; }
auto name() const
-> std::string override
{ return "GLFW3"; }
};
constexpr const char* GLFW3_t::initialize_param_key_width;
constexpr const char* GLFW3_t::initialize_param_key_height;
constexpr const char* GLFW3_t::initialize_param_key_title;
constexpr const char* GLFW3_t::initialize_param_key_monitor;
constexpr const char* GLFW3_t::initialize_param_key_window;
constexpr int GLFW3_t::initialize_param_default_width;
constexpr int GLFW3_t::initialize_param_default_height;
constexpr const char* GLFW3_t::initialize_param_default_title;
constexpr GLFWmonitor* GLFW3_t::initialize_param_default_monitor;
constexpr GLFWwindow* GLFW3_t::initialize_param_default_window;
#ifndef WRP_WONDERLAND_SUBSYSTEM_T
#define WRP_WONDERLAND_SUBSYSTEM_T
using subsystem_t = GLFW3_t;
#endif
}
}
}
#ifdef EMSCRIPTEN
#include <emscripten/emscripten.h>
#endif
// define this CPP-macro if need GLFW3 before include subsystem.hxx
#define WRP_WONDERLAND_SUBSYSTEM_GLFW3
// include subsystem
#include "subsystem.hxx"
namespace
{
// not need but it's demo.
template<class T>
auto print_initialize_params(T ips) -> void
{
std::cout << "\ninitialize params:\n";
for ( const auto& ip : ips )
{
std::cout << " { " << ip.first << " , ";
if ( ip.second.type() == typeid(int) )
std::cout << boost::any_cast<int>(ip.second);
else if ( ip.second.type() == typeid(const char*) )
std::cout << boost::any_cast<const char*>(ip.second);
else if ( ip.second.type() == typeid(GLFWmonitor*) )
std::cout << boost::any_cast<GLFWmonitor*>(ip.second);
else if ( ip.second.type() == typeid(GLFWwindow*) )
std::cout << boost::any_cast<GLFWwindow*>(ip.second);
else
throw std::logic_error("unexpectedly type.");
std::cout << " }\n";
}
}
}
int main()
{
// using
using wonder_rabbit_project::wonderland::subsystem::subsystem_t;
// generate the subsystem
auto subsystem = std::make_shared<subsystem_t>();
// get initialize params ( not need if initilize with default settings )
auto ips = subsystem -> default_initialize_params();
print_initialize_params(ips);
// change title
auto title
= std::string("hello, subsystem ") + subsystem->name()
+ " version " + subsystem->version().to_string()
;
ips[subsystem_t::initialize_param_key_title] = title.data();
print_initialize_params(ips);
// initialize the subsystem
subsystem -> initialize( std::move(ips) );
// invoke world pattern 1: consign main-loop to subsystem
// set your world update code
subsystem -> update_functors.emplace_front( [&subsystem]
{
/* do update your world */
if ( subsystem -> keyboard_state< GLFW_KEY_ESCAPE >() )
subsystem -> to_continue( false );
} );
// set your world render code
subsystem -> render_functors.emplace_front( []{ /* do render your world */ } );
// invoke your world
subsystem -> invoke();
// invoke world pattern 2: original main-loop system with use subsystem
/*
#ifdef EMSCRIPTEN
emscripten_set_main_loop( []
#else
do
#endif
{
subsystem -> before_update();
// do update world
{ }
subsystem -> after_update();
subsystem -> before_render();
// do render with GL(glXxx)
{ }
subsystem -> after_render();
}
#ifdef EMSCRIPTEN
, 0, 1);
#else
while ( subsystem -> to_continue );
#endif
*/
}
#include <boost/scope_exit.hpp>
#include "subsystem_base.hxx"
#ifdef WRP_WONDERLAND_SUBSYSTEM_GLFW3
#include "glfw3.hxx"
#elif defined(WRP_WONDERLAND_SUBSYSTEM_GLFW2)
#include "glfw2.hxx"
#endif
#pragma once
#include <cstdint>
#include <stdexcept>
#include <string>
#include <memory>
#include <unordered_map>
#include <forward_list>
#include <boost/any.hpp>
namespace wonder_rabbit_project
{
namespace wonderland
{
namespace subsystem
{
struct subsystem_runtime_error_t
: std::runtime_error
{
subsystem_runtime_error_t(const std::string& what)
: std::runtime_error(what)
{ }
};
struct version_t
{
std::uint16_t major, minor, revision;
auto to_string() -> std::string
{
return std::to_string(major) + "."
+ std::to_string(minor) + "."
+ std::to_string(revision)
;
}
};
class subsystem_base_t
: public std::enable_shared_from_this<subsystem_base_t>
{
public:
using initialize_param_key_t
= std::string;
using initialize_param_value_t
= boost::any;
using initialize_params_t
= std::unordered_map
< initialize_param_key_t
, initialize_param_value_t
>;
using update_functors_t
= std::forward_list
< std::function<void()>
>;
using render_functors_t
= update_functors_t;
using keyboard_states_t
= std::vector<bool>;
// by USB HID Usage code of the "MENU" key is 348.
static constexpr unsigned max_keycode = 348;
protected:
keyboard_states_t _keyboard_states;
bool _to_continue;
public:
update_functors_t update_functors;
render_functors_t render_functors;
subsystem_base_t()
{
_keyboard_states.resize( max_keycode );
}
virtual ~subsystem_base_t() { }
virtual auto default_initialize_params() const
-> initialize_params_t
{ return initialize_params_t(); }
virtual auto fill_initialize_params(initialize_params_t&& ps) const
-> initialize_params_t
{
for ( const auto& default_param : default_initialize_params() )
{
const auto& key = default_param.first;
const auto& default_value = default_param.second;
if
( ps.find(key) == std::end(ps)
or default_value.type() not_eq ps[key].type()
)
ps[key] = default_value;
}
return ps;
}
virtual auto initialize(initialize_params_t&&) -> void { }
virtual auto before_update() -> void { }
virtual auto after_update() -> void { }
virtual auto before_render() -> void { }
virtual auto after_render() -> void { }
virtual auto version() const -> version_t = 0;
virtual auto name() const -> std::string = 0;
virtual auto update() -> void
{
for ( const auto& f : update_functors )
f();
}
virtual auto render() -> void
{
for ( const auto& f : render_functors )
f();
}
virtual auto to_continue() const
-> bool
{ return _to_continue; }
virtual auto to_continue(const bool b)
-> void
{ _to_continue = b; }
template<unsigned keycode>
inline auto keyboard_state() const
-> bool
{ return _keyboard_states[keycode]; }
virtual auto keyboard_state(unsigned keycode) const
-> bool
{ return _keyboard_states[keycode]; }
virtual auto keyboard_state(unsigned keycode, bool action)
-> void
{ _keyboard_states[keycode] = action; }
virtual auto keyboard_states() const
-> const keyboard_states_t&
{ return _keyboard_states; }
virtual auto invoke()
-> void
{
_to_continue = true;
#ifdef EMSCRIPTEN
emscripten_set_main_loop( []
#else
do
#endif
{
before_update();
update();
after_update();
before_render();
render();
after_render();
}
#ifdef EMSCRIPTEN
, 0, 1);
#else
while ( to_continue() );
#endif
}
};
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment