--- a/bear/bear-engine/core/src/audio/code/sdl_sound.cpp +++ b/bear/bear-engine/core/src/audio/code/sdl_sound.cpp @@ -45,9 +45,15 @@ char* buffer = new char[file_size]; file.read( buffer, file_size ); +#ifdef __EMSCRIPTEN__ + // No threads: the sound loads at once. + m_loader = NULL; + load_sound( buffer, file_size ); +#else m_loader = new boost::thread ( boost::bind( &sdl_sound::load_sound, this, buffer, file_size ) ); +#endif } // sdl_sound::sdl_sound() /*----------------------------------------------------------------------------*/ --- a/bear/bear-engine/core/src/engine/item_brick/item_with_toggle.hpp +++ b/bear/bear-engine/core/src/engine/item_brick/item_with_toggle.hpp @@ -15,6 +15,7 @@ #define __ENGINE_ITEM_WITH_TOGGLE_HPP__ #include "audio/sample.hpp" +#include "engine/base_item.hpp" #include "engine/item_brick/with_toggle.hpp" #include "universe/derived_item_handle.hpp" #include "universe/types.hpp" --- a/bear/bear-engine/core/src/engine/model/code/model_action.cpp +++ b/bear/bear-engine/core/src/engine/model/code/model_action.cpp @@ -380,7 +380,8 @@ bear::engine::model_action::get_snapshot_const_iterator_at ( universe::time_type t ) const { - if ( claw::real_number(t) > get_duration() ) + if ( claw::real_number(t) > + claw::real_number(get_duration()) ) return m_snapshot.end(); else if ( m_snapshot.empty() ) return m_snapshot.end(); --- a/bear/bear-engine/core/src/engine/script/code/script_runner.cpp +++ b/bear/bear-engine/core/src/engine/script/code/script_runner.cpp @@ -93,7 +93,8 @@ bool done(false); while ( !done && (m_current_call != m_sequence.end()) ) - if ( claw::real_number(m_current_call->date) > m_date ) + if ( claw::real_number(m_current_call->date) > + claw::real_number(m_date) ) done = true; else { --- a/bear/bear-engine/core/src/time/code/time_unix.cpp +++ b/bear/bear-engine/core/src/time/code/time_unix.cpp @@ -16,6 +16,10 @@ #include #include +#ifdef __EMSCRIPTEN__ +#include +#endif + /*----------------------------------------------------------------------------*/ /** * \brief Stop the process for a given amount of time. @@ -23,6 +27,11 @@ */ void bear::systime::sleep( milliseconds_type ms ) { +#ifdef __EMSCRIPTEN__ + // Gives the turn back to the browser (ASYNCIFY). + emscripten_sleep( ms > 0 ? (unsigned int)ms : 0 ); + return; +#endif struct timespec time; time.tv_sec = ms / 1000; time.tv_nsec = ( ms % 1000 ) * ( 1000 * 1000 ); --- a/bear/bear-engine/core/src/visual/code/gl_renderer.cpp +++ b/bear/bear-engine/core/src/visual/code/gl_renderer.cpp @@ -676,6 +676,9 @@ */ void bear::visual::gl_renderer::make_current() { +#ifdef __EMSCRIPTEN__ + return; // one thread only: the context stays current +#endif if ( SDL_GL_MakeCurrent( m_window, m_gl_context ) != 0 ) claw::logger << claw::log_error << SDL_GetError() << std::endl; @@ -688,6 +691,9 @@ */ void bear::visual::gl_renderer::release_context() { +#ifdef __EMSCRIPTEN__ + return; +#endif if ( SDL_GL_MakeCurrent( m_window, nullptr ) != 0 ) claw::logger << claw::log_error << SDL_GetError() << std::endl; @@ -740,7 +746,12 @@ Uint32 flags = SDL_WINDOW_OPENGL; +#ifdef __EMSCRIPTEN__ + // The page scales the canvas; the image has the size of the view. + m_window_size = m_view_size; +#else m_window_size = get_best_screen_size(); +#endif if ( m_fullscreen ) flags |= SDL_WINDOW_FULLSCREEN; @@ -978,7 +989,7 @@ { m_mutex.gl_access.lock(); -#ifdef WIN32 +#if defined(WIN32) || defined(__EMSCRIPTEN__) m_render_thread = nullptr; #else m_render_thread = --- a/bear/bear-engine/core/src/visual/code/gl_state.cpp +++ b/bear/bear-engine/core/src/visual/code/gl_state.cpp @@ -282,6 +282,11 @@ VISUAL_GL_ERROR_THROW(); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); VISUAL_GL_ERROR_THROW(); +#ifdef __EMSCRIPTEN__ + // WebGL 1 renders textures of any size black, unless they are clamped. + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); +#endif output.draw( mode, it->vertex_index, it->count ); } --- a/fredygames-compat/boost/filesystem/convenience.hpp +++ b/fredygames-compat/boost/filesystem/convenience.hpp @@ -0,0 +1 @@ +#include --- a/fredygames-compat/boost/filesystem/directory.hpp +++ b/fredygames-compat/boost/filesystem/directory.hpp @@ -0,0 +1 @@ +#include --- a/fredygames-compat/boost/filesystem/operations.hpp +++ b/fredygames-compat/boost/filesystem/operations.hpp @@ -0,0 +1 @@ +#include --- a/fredygames-compat/boost/filesystem/path.hpp +++ b/fredygames-compat/boost/filesystem/path.hpp @@ -0,0 +1 @@ +#include --- a/fredygames-compat/boost/filesystem.hpp +++ b/fredygames-compat/boost/filesystem.hpp @@ -0,0 +1,12 @@ +// FredyGames: Boost.Filesystem substitute (Plee the Bear): the same names, taken from std::filesystem. +#ifndef FREDYGAMES_BOOST_FILESYSTEM_HPP +#define FREDYGAMES_BOOST_FILESYSTEM_HPP + +#include + +namespace boost +{ + namespace filesystem = std::filesystem; +} + +#endif --- a/fredygames-compat/boost/thread/condition_variable.hpp +++ b/fredygames-compat/boost/thread/condition_variable.hpp @@ -0,0 +1 @@ +#include --- a/fredygames-compat/boost/thread/mutex.hpp +++ b/fredygames-compat/boost/thread/mutex.hpp @@ -0,0 +1 @@ +#include --- a/fredygames-compat/boost/thread/thread.hpp +++ b/fredygames-compat/boost/thread/thread.hpp @@ -0,0 +1 @@ +#include --- a/fredygames-compat/boost/thread.hpp +++ b/fredygames-compat/boost/thread.hpp @@ -0,0 +1,66 @@ +// FredyGames: Boost.Thread substitute for WebAssembly without threads (Plee the Bear). +// There is no concurrency: a "thread" runs its function at once, in the constructor, and mutexes do nothing. +#ifndef FREDYGAMES_BOOST_THREAD_HPP +#define FREDYGAMES_BOOST_THREAD_HPP + +#include + +namespace boost +{ + class mutex + { + public: + mutex() {} + mutex( const mutex& ) = delete; + mutex& operator=( const mutex& ) = delete; + + void lock() {} + void unlock() {} + bool try_lock() { return true; } + + class scoped_lock + { + public: + explicit scoped_lock( mutex& m ) : m_mutex( &m ) {} + scoped_lock( const scoped_lock& ) = delete; + scoped_lock& operator=( const scoped_lock& ) = delete; + + void lock() {} + void unlock() {} + bool owns_lock() const { return true; } + mutex* mutex_() const { return m_mutex; } + + private: + mutex* m_mutex; + }; + }; + + typedef mutex recursive_mutex; + + class condition_variable + { + public: + void notify_one() {} + void notify_all() {} + + template + void wait( Lock& ) {} + }; + + class thread + { + public: + thread() {} + + template + explicit thread( F f ) + { + f(); + } + + void join() {} + bool joinable() const { return false; } + }; +} + +#endif --- a/fredygames-compat/stdcompat.hpp +++ b/fredygames-compat/stdcompat.hpp @@ -0,0 +1,64 @@ +// FredyGames: C++98 adapters that libc++ no longer has (std::mem_fun and friends), for Plee the Bear. +#ifndef FREDYGAMES_STDCOMPAT_HPP +#define FREDYGAMES_STDCOMPAT_HPP + +#include + +namespace std +{ + template + class mem_fun_t + { + public: + typedef R (T::*pmf_type)(); + explicit mem_fun_t( pmf_type p ) : m_pmf( p ) {} + R operator()( T* t ) const { return (t->*m_pmf)(); } + private: + pmf_type m_pmf; + }; + + template + class const_mem_fun_t + { + public: + typedef R (T::*pmf_type)() const; + explicit const_mem_fun_t( pmf_type p ) : m_pmf( p ) {} + R operator()( const T* t ) const { return (t->*m_pmf)(); } + private: + pmf_type m_pmf; + }; + + template + class mem_fun_ref_t + { + public: + typedef R (T::*pmf_type)(); + explicit mem_fun_ref_t( pmf_type p ) : m_pmf( p ) {} + R operator()( T& t ) const { return (t.*m_pmf)(); } + private: + pmf_type m_pmf; + }; + + template + class const_mem_fun_ref_t + { + public: + typedef R (T::*pmf_type)() const; + explicit const_mem_fun_ref_t( pmf_type p ) : m_pmf( p ) {} + R operator()( const T& t ) const { return (t.*m_pmf)(); } + private: + pmf_type m_pmf; + }; + + template mem_fun_t mem_fun( R (T::*p)() ) + { return mem_fun_t( p ); } + template const_mem_fun_t mem_fun( R (T::*p)() const ) + { return const_mem_fun_t( p ); } + template mem_fun_ref_t mem_fun_ref( R (T::*p)() ) + { return mem_fun_ref_t( p ); } + template + const_mem_fun_ref_t mem_fun_ref( R (T::*p)() const ) + { return const_mem_fun_ref_t( p ); } +} + +#endif --- a/launcher/src/code/launcher.cpp +++ b/launcher/src/code/launcher.cpp @@ -36,6 +36,8 @@ #ifdef WIN32 bindtextdomain( "bear-engine", "..\\share\\locale\\" ); +#elif defined __EMSCRIPTEN__ + // No translation catalogs: the texts stay in English. #elif defined PTB_STATIC bindtextdomain( "bear-engine", "share/locale/" ); @@ -107,6 +109,7 @@ text_domain_dir = get_application_path() + "..\\share\\locale"; +#elif defined __EMSCRIPTEN__ #elif defined PTB_STATIC text_domain_dir = get_application_path() + "share/locale"; @@ -162,15 +165,19 @@ data_path_argument.c_str(), -#ifdef PTB_STATIC +#if defined(__EMSCRIPTEN__) + // The items register themselves in the factory: nothing to load. +#elif defined PTB_STATIC "--auto-load-symbols", #else generic_item_argument.c_str(), ptb_argument.c_str(), #endif +#ifndef __EMSCRIPTEN__ "--stats-destination=" "http://www.stuff-o-matic.com/plee-the-bear/stats/save.php", +#endif "--start-level=level/start.cl", NULL @@ -244,7 +251,9 @@ { std::string a( "--data-path=" ); -#ifdef _WIN32 +#ifdef __EMSCRIPTEN__ + return a + "/ptb-data"; +#elif defined _WIN32 return a + get_application_path() + STRINGIZE( PTB_DATA_DIRECTORY ); #elif defined PTB_STATIC return a + get_application_path() + "share/plee-the-bear"; --- a/lib/src/ptb/expr/impl/boolean_player_function.tpp +++ b/lib/src/ptb/expr/impl/boolean_player_function.tpp @@ -25,7 +25,7 @@ template ptb::boolean_player_function::boolean_player_function ( unsigned int player_index, const bear::engine::level_globals* g ) - : m_player_index(player_index), m_player(NULL), m_level_globals(g) + : m_player_index(player_index), m_player(static_cast(NULL)), m_level_globals(g) { search_player(); } // boolean_player_function::boolean_player_function() --- a/lib/src/ptb/item/code/add_ingame_layers.cpp +++ b/lib/src/ptb/item/code/add_ingame_layers.cpp @@ -53,7 +53,7 @@ */ void ptb::add_ingame_layers::pre_cache() { - get_level_globals().load_font("font/Fava-black.ttf"); + get_level_globals().load_font("font/LilitaOne-Regular.ttf"); get_level_globals().load_font("font/lobster.otf"); get_level_globals().load_font("font/fixed_white-7x12.fnt"); get_level_globals().load_font("font/fixed_yellow-10x20.fnt"); --- a/lib/src/ptb/item_brick/impl/item_that_speaks.tpp +++ b/lib/src/ptb/item_brick/impl/item_that_speaks.tpp @@ -36,7 +36,7 @@ { super::pre_cache(); - this->get_level_globals().load_font("font/comic.ttf"); + this->get_level_globals().load_font("font/ComicNeue-Regular.ttf"); this->get_level_globals().load_image("gfx/ui/balloon-1.png"); } // item_that_speaks::pre_cache() @@ -62,5 +62,5 @@ ( "gfx/ui/balloon-1.png", "vertical border" ) ); this->get_balloon().set_font - ( this->get_level_globals().get_font("font/comic.ttf", 24) ); + ( this->get_level_globals().get_font("font/ComicNeue-Regular.ttf", 24) ); } // item_that_speaks::build() --- a/lib/src/ptb/layer/code/player_arrows_layer.cpp +++ b/lib/src/ptb/layer/code/player_arrows_layer.cpp @@ -180,7 +180,7 @@ unsigned int dist = (unsigned int)vect.length() / 100; const bear::universe::rectangle_type box = m_player.get_bounding_box(); - bear::visual::font f = glob.get_font("font/Fava-black.ttf", 30); + bear::visual::font f = glob.get_font("font/LilitaOne-Regular.ttf", 30); if ( box.intersects( visible_area ) ) m_distance.create(f, ""); else @@ -274,7 +274,7 @@ ( get_size(), p, get_level_globals().auto_sprite ("gfx/ui/status/status.png", "arrow 1"), - get_level_globals().get_font("font/Fava-black.ttf", 30) ); + get_level_globals().get_font("font/LilitaOne-Regular.ttf", 30) ); } if ( game_variables::get_players_count() == 2 ) @@ -287,6 +287,6 @@ ( get_size(), p, get_level_globals().auto_sprite ("gfx/ui/status/status.png", "arrow 2"), - get_level_globals().get_font("font/Fava-black.ttf", 30) ); + get_level_globals().get_font("font/LilitaOne-Regular.ttf", 30) ); } } // player_arrows_layer::search_players( ) --- a/lib/src/ptb/layer/code/status_layer.cpp +++ b/lib/src/ptb/layer/code/status_layer.cpp @@ -483,7 +483,7 @@ if ( p != NULL ) m_data_1 = new player_status ( get_level_globals(), - get_level_globals().get_font("font/Fava-black.ttf", 30), p, + get_level_globals().get_font("font/LilitaOne-Regular.ttf", 30), p, bear::visual::position_type(s_margin,get_size().y - s_margin), status_component::left_placement, get_size()); } @@ -495,7 +495,7 @@ if ( p != NULL ) m_data_2 = new player_status ( get_level_globals(), - get_level_globals().get_font("font/Fava-black.ttf", 30), p, + get_level_globals().get_font("font/LilitaOne-Regular.ttf", 30), p, bear::visual::position_type (get_size().x - s_margin,get_size().y - s_margin), status_component::right_placement, get_size() ); --- a/lib/src/ptb/layer/status/code/corrupting_bonus_component.cpp +++ b/lib/src/ptb/layer/status/code/corrupting_bonus_component.cpp @@ -47,7 +47,7 @@ const bear::universe::size_box_type& layer_size, bool auto_disappear ) : super(glob,p,active_position,side, x_p, y_p, layer_size, auto_disappear), - m_font(glob.get_font("font/Fava-black.ttf", 30)), + m_font(glob.get_font("font/LilitaOne-Regular.ttf", 30)), m_corrupting_bonus_scale(1) { } // corrupting_bonus_component::corrupting_bonus_component() --- a/lib/src/ptb/layer/status/code/lives_component.cpp +++ b/lib/src/ptb/layer/status/code/lives_component.cpp @@ -47,7 +47,7 @@ const bear::universe::size_box_type& layer_size, bool auto_disappear ) : super(glob,p,active_position,side, x_p, y_p, layer_size, auto_disappear), - m_font(glob.get_font("font/Fava-black.ttf", 30)), m_lives_scale(1) + m_font(glob.get_font("font/LilitaOne-Regular.ttf", 30)), m_lives_scale(1) { } // lives_component::lives_component() --- a/lib/src/ptb/layer/status/code/score_component.cpp +++ b/lib/src/ptb/layer/status/code/score_component.cpp @@ -46,7 +46,7 @@ const bear::universe::size_box_type& layer_size, bool auto_disappear ) : super(glob,p,active_position,side, x_p, y_p, layer_size, auto_disappear), - m_font(glob.get_font("font/Fava-black.ttf", 30)) + m_font(glob.get_font("font/LilitaOne-Regular.ttf", 30)) { } // score_component::score_component() --- a/lib/src/ptb/layer/status/code/throwable_item_component.cpp +++ b/lib/src/ptb/layer/status/code/throwable_item_component.cpp @@ -48,7 +48,7 @@ const bear::universe::size_box_type& layer_size, bool auto_disappear ) : super(glob,p,active_position,side, x_p, y_p, layer_size, auto_disappear), - m_font(glob.get_font("font/Fava-black.ttf", 30)) + m_font(glob.get_font("font/LilitaOne-Regular.ttf", 30)) { } // throwable_item_component::throwable_item_component() --- a/lib/src/ptb/layer/status/code/time_component.cpp +++ b/lib/src/ptb/layer/status/code/time_component.cpp @@ -45,7 +45,7 @@ const bear::universe::size_box_type& layer_size, bool auto_disappear ) : super(glob,p,active_position,side, x_p, y_p, layer_size, auto_disappear), - m_font(glob.get_font("font/Fava-black.ttf", 30)), + m_font(glob.get_font("font/LilitaOne-Regular.ttf", 30)), m_time_on(true), m_timer(t) { } // time_component::time_component() @@ -85,7 +85,7 @@ m_text_time->set_intensity(1, 0.8, 0); m_text_time.create - ( get_level_globals().get_font("font/Fava-black.ttf", 30), t ); + ( get_level_globals().get_font("font/LilitaOne-Regular.ttf", 30), t ); } else m_time_on = false;