diff --git a/CMakeLists.txt b/CMakeLists.txt index a8ac9c5..c2ac7e8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -262,10 +262,16 @@ if(EMSCRIPTEN) "-sEXPORT_NAME=\"createWAFlashCore\"" "-sALLOW_MEMORY_GROWTH=1" "-sUSE_ZLIB=1" + "-sUSE_LIBJPEG=1" "-sEXPORTED_FUNCTIONS=['_malloc','_free','_wasm_get_audio_samples']" "-sEXPORTED_RUNTIME_METHODS=['ccall','cwrap','getValue','HEAPU8','HEAP16','HEAPU32']" "-O3" ) + + target_compile_definitions(gameswf_core PUBLIC + TU_CONFIG_LINK_TO_JPEGLIB=1 + TU_CONFIG_LINK_TO_ZLIB=1 + ) endif() # Target 1: Libretro Core Shared Library diff --git a/src/gameswf_render_wasm.cpp b/src/gameswf_render_wasm.cpp index 50e0ef5..ad9f4be 100644 --- a/src/gameswf_render_wasm.cpp +++ b/src/gameswf_render_wasm.cpp @@ -10,6 +10,38 @@ extern std::vector g_wasm_framebuffer; extern uint32_t g_wasm_width; extern uint32_t g_wasm_height; +struct dummy_bitmap_info : public gameswf::bitmap_info { + int get_width() const override { return 1; } + int get_height() const override { return 1; } +}; + +class glyph_provider_wasm : public gameswf::glyph_provider { + gameswf::gc_ptr m_stub_bi; +public: + glyph_provider_wasm() { + m_stub_bi = new dummy_bitmap_info(); + } + ~glyph_provider_wasm() override {} + + gameswf::bitmap_info* get_char_image(gameswf::character_def* shape_glyph, Uint16 code, + const tu_string& fontname, bool is_bold, bool is_italic, + int fontsize, gameswf::rect* bounds, float* advance) override { + (void)shape_glyph; (void)code; (void)fontname; (void)is_bold; (void)is_italic; + if (bounds) { + bounds->m_x_min = 0.0f; + bounds->m_x_max = 0.0f; + bounds->m_y_min = 0.0f; + bounds->m_y_max = 0.0f; + } + if (advance) { + float em_size = static_cast(fontsize); + if (em_size <= 0.0f) em_size = 1024.0f; + *advance = em_size * 0.6f; + } + return m_stub_bi.get_ptr(); + } +}; + class render_handler_wasm : public gameswf::render_handler { gameswf::matrix m_current_matrix; gameswf::cxform m_current_cxform; @@ -19,18 +51,19 @@ class render_handler_wasm : public gameswf::render_handler { render_handler_wasm() {} ~render_handler_wasm() override {} - struct dummy_bitmap_info : public gameswf::bitmap_info {}; - gameswf::bitmap_info* create_bitmap_info_empty() override { return new dummy_bitmap_info(); } gameswf::bitmap_info* create_bitmap_info_alpha(int w, int h, unsigned char* data) override { + (void)w; (void)h; (void)data; return new dummy_bitmap_info(); } gameswf::bitmap_info* create_bitmap_info_rgb(image::rgb* im) override { + (void)im; return new dummy_bitmap_info(); } gameswf::bitmap_info* create_bitmap_info_rgba(image::rgba* im) override { + (void)im; return new dummy_bitmap_info(); } gameswf::video_handler* create_video_handler() override { @@ -41,6 +74,8 @@ class render_handler_wasm : public gameswf::render_handler { int viewport_x0, int viewport_y0, int viewport_width, int viewport_height, float x0, float x1, float y0, float y1) override { + (void)viewport_x0; (void)viewport_y0; (void)viewport_width; (void)viewport_height; + (void)x0; (void)x1; (void)y0; (void)y1; uint32_t bg_xrgb = (background_color.m_r << 16) | (background_color.m_g << 8) | background_color.m_b; if (!g_wasm_framebuffer.empty()) { std::fill(g_wasm_framebuffer.begin(), g_wasm_framebuffer.end(), bg_xrgb); @@ -57,18 +92,21 @@ class render_handler_wasm : public gameswf::render_handler { m_current_cxform = cx; } - void fill_style_disable(int fill_side) override {} + void fill_style_disable(int fill_side) override { (void)fill_side; } void fill_style_color(int fill_side, const gameswf::rgba& color) override { + (void)fill_side; m_current_color = color; } void fill_style_bitmap(int fill_side, gameswf::bitmap_info* bi, const gameswf::matrix& m, - bitmap_wrap_mode wm, bitmap_blend_mode bm) override {} + bitmap_wrap_mode wm, bitmap_blend_mode bm) override { + (void)fill_side; (void)bi; (void)m; (void)wm; (void)bm; + } void line_style_disable() override {} - void line_style_color(gameswf::rgba color) override {} - void line_style_width(float width) override {} + void line_style_color(gameswf::rgba color) override { (void)color; } + void line_style_width(float width) override { (void)width; } void draw_mesh_strip(const void* coords, int vertex_count) override { if (!coords || vertex_count < 3 || g_wasm_framebuffer.empty()) return; @@ -114,20 +152,23 @@ class render_handler_wasm : public gameswf::render_handler { } } - void draw_line_strip(const void* coords, int vertex_count) override {} + void draw_line_strip(const void* coords, int vertex_count) override { (void)coords; (void)vertex_count; } void draw_bitmap(const gameswf::matrix& m, gameswf::bitmap_info* bi, - const gameswf::rect& coords, const gameswf::rect& uv_coords, gameswf::rgba color) override {} + const gameswf::rect& coords, const gameswf::rect& uv_coords, gameswf::rgba color) override { + (void)m; (void)bi; (void)coords; (void)uv_coords; (void)color; + } - void set_antialiased(bool enable) override {} - bool test_stencil_buffer(const gameswf::rect& bound, Uint8 pattern) override { return false; } + void set_antialiased(bool enable) override { (void)enable; } + bool test_stencil_buffer(const gameswf::rect& bound, Uint8 pattern) override { (void)bound; (void)pattern; return false; } void begin_submit_mask() override {} void end_submit_mask() override {} void disable_mask() override {} - bool is_visible(const gameswf::rect& bound) override { return true; } + bool is_visible(const gameswf::rect& bound) override { (void)bound; return true; } void open() override {} }; gameswf::render_handler* create_render_handler_wasm() { + gameswf::set_glyph_provider(new glyph_provider_wasm()); return new render_handler_wasm(); } diff --git a/third_party/gameswf/base/tu_timer.cpp b/third_party/gameswf/base/tu_timer.cpp index a57b889..6f29e3e 100644 --- a/third_party/gameswf/base/tu_timer.cpp +++ b/third_party/gameswf/base/tu_timer.cpp @@ -1,270 +1,268 @@ -// tu_timer.cpp -- by Thatcher Ulrich - -// This source code has been donated to the Public Domain. Do -// whatever you want with it. - -// Utility/profiling timer. - -//Pete H - no sys/timeb in marmalade -//#include // for ftime() -#include -#ifndef _WIN32 -#include -#endif - -#if !defined(_WIN32) && !defined(__EMSCRIPTEN__) && \ - !defined(_TIME_T_DEFINED) && !defined(__time_t_defined) && \ - !defined(_TIME_T) - typedef long time_t; - #define _TIME_T_DEFINED -#endif - -struct timeb { - time_t time; /* [XSI] Seconds since the Epoch */ - unsigned short millitm; /* [XSI] Milliseconds since the Epoch */ - short timezone; /* [XSI] Minutes west of CUT */ - short dstflag; /* [XSI] non-zero if DST in effect */ -}; - -void ftime (timeb* b) -{ - if (b) - { -#ifndef _WIN32 - struct timeval tv; - gettimeofday(&tv, 0); - b->time = (time_t) tv.tv_sec; - b->millitm = (unsigned short) (tv.tv_usec / 1000); -#else - b->time = time(NULL); - b->millitm = 0; -#endif - b->timezone = 0; - b->dstflag = 0; - } -} - - -#include -#include "base/tu_timer.h" - -static timeb s_start_time; -void tu_timer::init_timer() -{ - ftime(&s_start_time); -} - -Uint32 tu_timer::get_ticks() -{ - struct timeb tv; - ftime(&tv); - if (s_start_time.time == 0) - { - s_start_time = tv; - } - return (Uint32) ((tv.time - s_start_time.time) * 1000 + (tv.millitm - s_start_time.millitm)); -} - -tu_datetime::tu_datetime() -{ - m_time = (time_t) tu_timer::get_systime(); -} - -// Returns the date for the specified Date object in milliseconds since midnight on January 1, 1970, -double tu_datetime::get_time() const -{ - return (double) m_time * 1000; // *1000 means that time in milliseconds -} - -// Sets the date for the specified Date object in milliseconds since midnight on January 1, 1970, -void tu_datetime::set_time(double t) -{ - m_time = (time_t) (t / 1000); -} - -int tu_datetime::get(part part) -{ - struct tm* gmt = localtime(&m_time); - if (gmt) - { - switch (part) - { - case FULLYEAR: - return gmt->tm_year + 1900; - break; - - case YEAR: - return gmt->tm_year; - break; - - case MON: - return gmt->tm_mon; - break; - - case MDAY: - // Returns the day of the month (an integer from 1 to 31) - return gmt->tm_mday; - - case WDAY: - // Returns the day of the month (an integer from 1 to 31) - return gmt->tm_wday; - - case HOUR: - // Returns the hour (an integer from 0 to 23) - return gmt->tm_hour; - break; - - case MIN: - return gmt->tm_min; - break; - - case SEC: - return gmt->tm_sec; - break; - - default: - assert(0); - } - } - return -1; -} - -void tu_datetime::set(part part, int val) -{ - struct tm* gmt = localtime(&m_time); - if (gmt) - { - switch (part) - { - case FULLYEAR: - gmt->tm_year = val - 1900; // (current year minus 1900). - break; - - case YEAR: - gmt->tm_year = val; - break; - - case MON: - gmt->tm_mon = val; - break; - - case MDAY: - gmt->tm_mday = val; - break; - - case WDAY: - gmt->tm_wday = val; - break; - - case HOUR: - gmt->tm_hour = val; - break; - - case MIN: - gmt->tm_min = val; - break; - - case SEC: - gmt->tm_sec = val; - break; - - default: - assert(0); - } - m_time = mktime(gmt); - } -} - - -Uint64 tu_timer::get_systime() -{ - time_t ltime; - time(<ime); - return (Uint64) ltime; -} - -#ifdef _WIN32 - -#include - -void tu_timer::sleep(int milliseconds) -{ - ::Sleep(milliseconds); -} - - -uint64 tu_timer::get_profile_ticks() -{ - // @@ use rdtsc? - - LARGE_INTEGER li; - QueryPerformanceCounter(&li); - - return li.QuadPart; -} - - -double tu_timer::profile_ticks_to_seconds(uint64 ticks) -{ - LARGE_INTEGER freq; - QueryPerformanceFrequency(&freq); - - double seconds = (double) ticks; - seconds /= (double) freq.QuadPart; - - return seconds; -} - -#else // not _WIN32 - - -#include -#include - - -// The profile ticks implementation is just fine for a normal timer. - -void tu_timer::sleep(int milliseconds) -{ - usleep(milliseconds * 1000); -} - - -uint64 tu_timer::get_profile_ticks() -{ - // @@ TODO prefer rdtsc when available? - - // Return microseconds. - struct timeval tv; - uint64 result; - - gettimeofday(&tv, 0); - - result = tv.tv_sec * 1000000; - result += tv.tv_usec; - - return result; -} - - -double tu_timer::profile_ticks_to_seconds(uint64 ticks) -{ - // ticks is microseconds. Convert to seconds. - return ticks / 1000000.0; -} - -double tu_timer::profile_ticks_to_milliseconds(uint64 ticks) -{ - // ticks is microseconds. Convert to milliseconds. - return ticks / 1000.0; -} - -#endif // not _WIN32 - - -// Local Variables: -// mode: C++ -// c-basic-offset: 8 -// tab-width: 8 -// indent-tabs-mode: t -// End: +// tu_timer.cpp -- by Thatcher Ulrich + +// This source code has been donated to the Public Domain. Do +// whatever you want with it. + +// Utility/profiling timer. + +//Pete H - no sys/timeb in marmalade +//#include // for ftime() +#include +#ifndef _WIN32 +#include +#endif + +#if !defined(_WIN32) && !defined(__EMSCRIPTEN__) && !defined(_TIME_T_DEFINED) && !defined(__time_t_defined) + typedef long time_t; + #define _TIME_T_DEFINED +#endif + +struct timeb { + time_t time; /* [XSI] Seconds since the Epoch */ + unsigned short millitm; /* [XSI] Milliseconds since the Epoch */ + short timezone; /* [XSI] Minutes west of CUT */ + short dstflag; /* [XSI] non-zero if DST in effect */ +}; + +void ftime (timeb* b) +{ + if (b) + { +#ifndef _WIN32 + struct timeval tv; + gettimeofday(&tv, 0); + b->time = (time_t) tv.tv_sec; + b->millitm = (unsigned short) (tv.tv_usec / 1000); +#else + b->time = time(NULL); + b->millitm = 0; +#endif + b->timezone = 0; + b->dstflag = 0; + } +} + + +#include +#include "base/tu_timer.h" + +static timeb s_start_time; +void tu_timer::init_timer() +{ + ftime(&s_start_time); +} + +Uint32 tu_timer::get_ticks() +{ + struct timeb tv; + ftime(&tv); + if (s_start_time.time == 0) + { + s_start_time = tv; + } + return (Uint32) ((tv.time - s_start_time.time) * 1000 + (tv.millitm - s_start_time.millitm)); +} + +tu_datetime::tu_datetime() +{ + m_time = (time_t) tu_timer::get_systime(); +} + +// Returns the date for the specified Date object in milliseconds since midnight on January 1, 1970, +double tu_datetime::get_time() const +{ + return (double) m_time * 1000; // *1000 means that time in milliseconds +} + +// Sets the date for the specified Date object in milliseconds since midnight on January 1, 1970, +void tu_datetime::set_time(double t) +{ + m_time = (time_t) (t / 1000); +} + +int tu_datetime::get(part part) +{ + struct tm* gmt = localtime(&m_time); + if (gmt) + { + switch (part) + { + case FULLYEAR: + return gmt->tm_year + 1900; + break; + + case YEAR: + return gmt->tm_year; + break; + + case MON: + return gmt->tm_mon; + break; + + case MDAY: + // Returns the day of the month (an integer from 1 to 31) + return gmt->tm_mday; + + case WDAY: + // Returns the day of the month (an integer from 1 to 31) + return gmt->tm_wday; + + case HOUR: + // Returns the hour (an integer from 0 to 23) + return gmt->tm_hour; + break; + + case MIN: + return gmt->tm_min; + break; + + case SEC: + return gmt->tm_sec; + break; + + default: + assert(0); + } + } + return -1; +} + +void tu_datetime::set(part part, int val) +{ + struct tm* gmt = localtime(&m_time); + if (gmt) + { + switch (part) + { + case FULLYEAR: + gmt->tm_year = val - 1900; // (current year minus 1900). + break; + + case YEAR: + gmt->tm_year = val; + break; + + case MON: + gmt->tm_mon = val; + break; + + case MDAY: + gmt->tm_mday = val; + break; + + case WDAY: + gmt->tm_wday = val; + break; + + case HOUR: + gmt->tm_hour = val; + break; + + case MIN: + gmt->tm_min = val; + break; + + case SEC: + gmt->tm_sec = val; + break; + + default: + assert(0); + } + m_time = mktime(gmt); + } +} + + +Uint64 tu_timer::get_systime() +{ + time_t ltime; + time(<ime); + return (Uint64) ltime; +} + +#ifdef _WIN32 + +#include + +void tu_timer::sleep(int milliseconds) +{ + ::Sleep(milliseconds); +} + + +uint64 tu_timer::get_profile_ticks() +{ + // @@ use rdtsc? + + LARGE_INTEGER li; + QueryPerformanceCounter(&li); + + return li.QuadPart; +} + + +double tu_timer::profile_ticks_to_seconds(uint64 ticks) +{ + LARGE_INTEGER freq; + QueryPerformanceFrequency(&freq); + + double seconds = (double) ticks; + seconds /= (double) freq.QuadPart; + + return seconds; +} + +#else // not _WIN32 + + +#include +#include + + +// The profile ticks implementation is just fine for a normal timer. + +void tu_timer::sleep(int milliseconds) +{ + usleep(milliseconds * 1000); +} + + +uint64 tu_timer::get_profile_ticks() +{ + // @@ TODO prefer rdtsc when available? + + // Return microseconds. + struct timeval tv; + uint64 result; + + gettimeofday(&tv, 0); + + result = tv.tv_sec * 1000000; + result += tv.tv_usec; + + return result; +} + + +double tu_timer::profile_ticks_to_seconds(uint64 ticks) +{ + // ticks is microseconds. Convert to seconds. + return ticks / 1000000.0; +} + +double tu_timer::profile_ticks_to_milliseconds(uint64 ticks) +{ + // ticks is microseconds. Convert to milliseconds. + return ticks / 1000.0; +} + +#endif // not _WIN32 + + +// Local Variables: +// mode: C++ +// c-basic-offset: 8 +// tab-width: 8 +// indent-tabs-mode: t +// End: diff --git a/third_party/gameswf/gameswf/gameswf_sprite.cpp b/third_party/gameswf/gameswf/gameswf_sprite.cpp index b110c7d..0b1fd99 100644 --- a/third_party/gameswf/gameswf/gameswf_sprite.cpp +++ b/third_party/gameswf/gameswf/gameswf_sprite.cpp @@ -40,6 +40,7 @@ namespace gameswf m_mouse_state(UP), m_enabled(true), m_on_event_load_called(false), + m_defer_enterframe(false), m_script(NULL) { assert(m_def != NULL); @@ -318,7 +319,31 @@ namespace gameswf if (m_on_event_load_called) { - on_event(event_id::ENTER_FRAME); + bool skip_enterframe = false; + if (m_defer_enterframe) { + character* parent = get_parent(); + if (parent) { + sprite_instance* parent_sp = cast_to(parent); + if (parent_sp) { + for (int i = 0, n = parent_sp->m_display_list.size(); i < n; i++) { + character* sib = parent_sp->m_display_list.get_character(i); + if (sib && sib != this) { + sprite_instance* sib_sp = cast_to(sib); + if (sib_sp && sib_sp->get_character_def() && sib_sp->get_frame_count() > 0 && sib_sp->get_loaded_bytes() == 0) { + skip_enterframe = true; + break; + } + } + } + } + } + if (!skip_enterframe) { + m_defer_enterframe = false; + } + } + if (!skip_enterframe) { + on_event(event_id::ENTER_FRAME); + } } do_actions(); @@ -751,6 +776,20 @@ namespace gameswf parent->replace_display_object( sprite, get_name(), get_depth(), false, get_cxform(), false, get_matrix(), get_ratio(), get_clip_depth(), get_blend_mode()); + // Set m_defer_enterframe on siblings when loadMovie is called + sprite_instance* parent_sp = cast_to(parent); + if (parent_sp) { + for (int i = 0, n = parent_sp->m_display_list.size(); i < n; i++) { + character* sib = parent_sp->m_display_list.get_character(i); + if (sib && sib != sprite) { + sprite_instance* sib_sp = cast_to(sib); + if (sib_sp) { + sib_sp->m_defer_enterframe = true; + } + } + } + } + return sprite; } diff --git a/third_party/gameswf/gameswf/gameswf_sprite.h b/third_party/gameswf/gameswf/gameswf_sprite.h index 111a858..2a22976 100644 --- a/third_party/gameswf/gameswf/gameswf_sprite.h +++ b/third_party/gameswf/gameswf/gameswf_sprite.h @@ -1,224 +1,225 @@ -// gameswf_sprite.h -- Thatcher Ulrich 2003 - -// This source code has been donated to the Public Domain. Do -// whatever you want with it. - -// Some implementation code for the gameswf SWF player library. - - -#ifndef GAMESWF_SPRITE_H -#define GAMESWF_SPRITE_H - - -#include "gameswf/gameswf.h" -#include "gameswf/gameswf_action.h" -#include "gameswf/gameswf_as_classes/as_mcloader.h" -#include "gameswf/gameswf_dlist.h" -#include "gameswf/gameswf_log.h" -#include "gameswf/gameswf_movie_def.h" -#include "gameswf/gameswf_root.h" -#include "gameswf/gameswf_sprite_def.h" -#include "gameswf/gameswf_types.h" -#include "gameswf/gameswf_canvas.h" - -#include "base/container.h" -#include "base/utility.h" -#include - -namespace gameswf -{ - - struct sprite_instance : public character - { - // Unique id of a gameswf resource - enum { m_class_id = AS_SPRITE }; - virtual bool is(int class_id) const - { - if (m_class_id == class_id) return true; - else return character::is(class_id); - } - - gc_ptr m_def; - root* m_root; - - display_list m_display_list; - array m_action_list; - array m_goto_frame_action_list; - - play_state m_play_state; - int m_current_frame; - bool m_update_frame; - array m_init_actions_executed; // a bit-array class would be ideal for this - - as_environment m_as_environment; - - enum mouse_state - { - UP = 0, - DOWN, - OVER - }; - mouse_state m_mouse_state; - bool m_enabled; - bool m_on_event_load_called; - gc_ptr m_canvas; - - // flash9 - hash >* m_script; // - gc_ptr m_frame_script; // current script - - // for setMask - weak_ptr m_mask_clip; - - sprite_instance(player* player, movie_definition_sub* def, root* r, character* parent, int id); - virtual ~sprite_instance(); - - virtual character_def* get_character_def() { return m_def.get_ptr(); } - virtual bool has_keypress_event(); - root* get_root() { return m_root; } - - // used in loadMovieClip() - void set_root(root* mroot) { m_root = mroot; } - uint32 get_file_bytes() const; - uint32 get_loaded_bytes() const; - - exported_module character* get_root_movie() const { return m_root->get_root_movie(); } - movie_definition* get_movie_definition() { return m_def.get_ptr(); } - - virtual void get_bound(rect* bound); - - virtual int get_current_frame() const { return m_current_frame; } - virtual int get_frame_count() const { return m_def->get_frame_count(); } - virtual int get_loading_frame() const { return m_def->get_loading_frame(); } - - character* add_empty_movieclip(const char* name, int depth); - - exported_module void set_play_state(play_state s); - play_state get_play_state() const; - - character* get_character(int character_id) - { - // return m_def->get_character_def(character_id); - // @@ TODO -- look through our dlist for a match - if (character_id >= m_display_list.size()) - { - return NULL; - } - - return m_display_list.get_character(character_id); - } - - float get_background_alpha() const - { - // @@ this doesn't seem right... - return m_root->get_background_alpha(); - } - - float get_pixel_scale() const { return m_root->get_pixel_scale(); } - - virtual void get_mouse_state(int* x, int* y, int* buttons) - { - m_root->get_mouse_state(x, y, buttons); - } - - void set_background_color(const rgba& color) - { - m_root->set_background_color(color); - } - -// virtual bool has_looped() const { return m_has_looped; } - - inline int transition(int a, int b) const - // Combine the flags to avoid a conditional. It would be faster with a macro. - { - return (a << 2) | b; - } - - virtual bool can_handle_mouse_event(); - virtual bool get_topmost_mouse_entity( character * &te, float x, float y); - void advance(float delta_time); - - virtual void alive(); - void execute_frame_tags(int frame, bool state_only = false); - void execute_frame_tags_reverse(int frame); - execute_tag* find_previous_replace_or_add_tag(int frame, int depth, int id); - void execute_remove_tags(int frame); - void set_frame_script(int frame); // flash9 - void do_actions(); - virtual void do_actions(const array& action_list); - exported_module void goto_frame(const tu_string& target_frame); - exported_module void goto_frame(int target_frame_number); - exported_module bool goto_labeled_frame(const char* label); - - void display(); - - character* add_display_object( Uint16 character_id, const tu_string& name, - const array& event_handlers, int depth, bool replace_if_depth_is_occupied, - const cxform& color_transform, const matrix& matrix, float ratio, Uint16 clip_depth, Uint8 blend_mode); - void move_display_object( int depth, bool use_cxform, const cxform& color_xform, bool use_matrix, - const matrix& mat, float ratio, Uint16 clip_depth, Uint8 blend_mode); - void replace_display_object( Uint16 character_id, const char* name, int depth, bool use_cxform, - const cxform& color_transform, bool use_matrix, const matrix& mat, float ratio, Uint16 clip_depth, Uint8 blend_mode); - void replace_display_object( character* ch, const char* name, int depth, bool use_cxform, - const cxform& color_transform, bool use_matrix, const matrix& mat, float ratio, Uint16 clip_depth, Uint8 blend_mode); - - void remove_display_object(int depth, int id); - void remove_display_object(const tu_string& name); - void remove_display_object(character* ch); - void clear_display_objects(); - - virtual character* replace_me(movie_definition* md); - virtual character* replace_me(character_def* def); - - void add_action_buffer(action_buffer* a); - int get_id_at_depth(int depth); - int get_highest_depth(); - - // - // ActionScript support - // - - virtual void set_variable(const char* path_to_var, const char* new_value); - virtual void set_variable(const char* path_to_var, const wchar_t* new_value); - virtual const char* get_variable(const char* path_to_var) const; - - virtual bool set_member(const tu_stringi& name, const as_value& val); - virtual bool get_member(const tu_stringi& name, as_value* val); - virtual void call_frame_actions(const as_value& frame_spec); - virtual void stop_drag(); - character* clone_display_object(const tu_string& newname, int depth); - virtual bool on_event(const event_id& id); - virtual const char* call_method_args(const char* method_name, const char* method_arg_fmt, va_list args); - virtual tu_string call_method(const char* method_name, as_value * arguments, int argument_count ); - virtual void attach_display_callback(const char* path_to_object, void (*callback)(void*), void* user_ptr); - bool hit_test(character* target); - virtual bool hit_test(double x, double y, bool shape_flag); - sprite_instance* attach_movie(const tu_string& id, const tu_string name, int depth); - - void local_to_global(as_object* pt); - void global_to_local(as_object* pt); - - character* create_text_field(const char* name, int depth, int x, int y, int width, int height); - - virtual void clear_refs(hash* visited_objects, as_object* this_ptr); - virtual as_environment* get_environment() { return &m_as_environment; } - virtual void dump(tu_string& tabs); - - virtual character_def* find_exported_resource(const tu_string& symbol); - - // gameSWF extension - void set_fps(float fps); - - // drawing API - canvas* get_canvas(); - - virtual const char* type_of() { return "movieclip"; } - virtual void enumerate(as_environment* env); - virtual bool is_enabled() const; - - // flash9 - void add_script(int frame, as_function* func); - }; -} - -#endif +// gameswf_sprite.h -- Thatcher Ulrich 2003 + +// This source code has been donated to the Public Domain. Do +// whatever you want with it. + +// Some implementation code for the gameswf SWF player library. + + +#ifndef GAMESWF_SPRITE_H +#define GAMESWF_SPRITE_H + + +#include "gameswf/gameswf.h" +#include "gameswf/gameswf_action.h" +#include "gameswf/gameswf_as_classes/as_mcloader.h" +#include "gameswf/gameswf_dlist.h" +#include "gameswf/gameswf_log.h" +#include "gameswf/gameswf_movie_def.h" +#include "gameswf/gameswf_root.h" +#include "gameswf/gameswf_sprite_def.h" +#include "gameswf/gameswf_types.h" +#include "gameswf/gameswf_canvas.h" + +#include "base/container.h" +#include "base/utility.h" +#include + +namespace gameswf +{ + + struct sprite_instance : public character + { + // Unique id of a gameswf resource + enum { m_class_id = AS_SPRITE }; + virtual bool is(int class_id) const + { + if (m_class_id == class_id) return true; + else return character::is(class_id); + } + + gc_ptr m_def; + root* m_root; + + display_list m_display_list; + array m_action_list; + array m_goto_frame_action_list; + + play_state m_play_state; + int m_current_frame; + bool m_update_frame; + array m_init_actions_executed; // a bit-array class would be ideal for this + + as_environment m_as_environment; + + enum mouse_state + { + UP = 0, + DOWN, + OVER + }; + mouse_state m_mouse_state; + bool m_enabled; + bool m_defer_enterframe; + bool m_on_event_load_called; + gc_ptr m_canvas; + + // flash9 + hash >* m_script; // + gc_ptr m_frame_script; // current script + + // for setMask + weak_ptr m_mask_clip; + + sprite_instance(player* player, movie_definition_sub* def, root* r, character* parent, int id); + virtual ~sprite_instance(); + + virtual character_def* get_character_def() { return m_def.get_ptr(); } + virtual bool has_keypress_event(); + root* get_root() { return m_root; } + + // used in loadMovieClip() + void set_root(root* mroot) { m_root = mroot; } + uint32 get_file_bytes() const; + uint32 get_loaded_bytes() const; + + exported_module character* get_root_movie() const { return m_root->get_root_movie(); } + movie_definition* get_movie_definition() { return m_def.get_ptr(); } + + virtual void get_bound(rect* bound); + + virtual int get_current_frame() const { return m_current_frame; } + virtual int get_frame_count() const { return m_def->get_frame_count(); } + virtual int get_loading_frame() const { return m_def->get_loading_frame(); } + + character* add_empty_movieclip(const char* name, int depth); + + exported_module void set_play_state(play_state s); + play_state get_play_state() const; + + character* get_character(int character_id) + { + // return m_def->get_character_def(character_id); + // @@ TODO -- look through our dlist for a match + if (character_id >= m_display_list.size()) + { + return NULL; + } + + return m_display_list.get_character(character_id); + } + + float get_background_alpha() const + { + // @@ this doesn't seem right... + return m_root->get_background_alpha(); + } + + float get_pixel_scale() const { return m_root->get_pixel_scale(); } + + virtual void get_mouse_state(int* x, int* y, int* buttons) + { + m_root->get_mouse_state(x, y, buttons); + } + + void set_background_color(const rgba& color) + { + m_root->set_background_color(color); + } + +// virtual bool has_looped() const { return m_has_looped; } + + inline int transition(int a, int b) const + // Combine the flags to avoid a conditional. It would be faster with a macro. + { + return (a << 2) | b; + } + + virtual bool can_handle_mouse_event(); + virtual bool get_topmost_mouse_entity( character * &te, float x, float y); + void advance(float delta_time); + + virtual void alive(); + void execute_frame_tags(int frame, bool state_only = false); + void execute_frame_tags_reverse(int frame); + execute_tag* find_previous_replace_or_add_tag(int frame, int depth, int id); + void execute_remove_tags(int frame); + void set_frame_script(int frame); // flash9 + void do_actions(); + virtual void do_actions(const array& action_list); + exported_module void goto_frame(const tu_string& target_frame); + exported_module void goto_frame(int target_frame_number); + exported_module bool goto_labeled_frame(const char* label); + + void display(); + + character* add_display_object( Uint16 character_id, const tu_string& name, + const array& event_handlers, int depth, bool replace_if_depth_is_occupied, + const cxform& color_transform, const matrix& matrix, float ratio, Uint16 clip_depth, Uint8 blend_mode); + void move_display_object( int depth, bool use_cxform, const cxform& color_xform, bool use_matrix, + const matrix& mat, float ratio, Uint16 clip_depth, Uint8 blend_mode); + void replace_display_object( Uint16 character_id, const char* name, int depth, bool use_cxform, + const cxform& color_transform, bool use_matrix, const matrix& mat, float ratio, Uint16 clip_depth, Uint8 blend_mode); + void replace_display_object( character* ch, const char* name, int depth, bool use_cxform, + const cxform& color_transform, bool use_matrix, const matrix& mat, float ratio, Uint16 clip_depth, Uint8 blend_mode); + + void remove_display_object(int depth, int id); + void remove_display_object(const tu_string& name); + void remove_display_object(character* ch); + void clear_display_objects(); + + virtual character* replace_me(movie_definition* md); + virtual character* replace_me(character_def* def); + + void add_action_buffer(action_buffer* a); + int get_id_at_depth(int depth); + int get_highest_depth(); + + // + // ActionScript support + // + + virtual void set_variable(const char* path_to_var, const char* new_value); + virtual void set_variable(const char* path_to_var, const wchar_t* new_value); + virtual const char* get_variable(const char* path_to_var) const; + + virtual bool set_member(const tu_stringi& name, const as_value& val); + virtual bool get_member(const tu_stringi& name, as_value* val); + virtual void call_frame_actions(const as_value& frame_spec); + virtual void stop_drag(); + character* clone_display_object(const tu_string& newname, int depth); + virtual bool on_event(const event_id& id); + virtual const char* call_method_args(const char* method_name, const char* method_arg_fmt, va_list args); + virtual tu_string call_method(const char* method_name, as_value * arguments, int argument_count ); + virtual void attach_display_callback(const char* path_to_object, void (*callback)(void*), void* user_ptr); + bool hit_test(character* target); + virtual bool hit_test(double x, double y, bool shape_flag); + sprite_instance* attach_movie(const tu_string& id, const tu_string name, int depth); + + void local_to_global(as_object* pt); + void global_to_local(as_object* pt); + + character* create_text_field(const char* name, int depth, int x, int y, int width, int height); + + virtual void clear_refs(hash* visited_objects, as_object* this_ptr); + virtual as_environment* get_environment() { return &m_as_environment; } + virtual void dump(tu_string& tabs); + + virtual character_def* find_exported_resource(const tu_string& symbol); + + // gameSWF extension + void set_fps(float fps); + + // drawing API + canvas* get_canvas(); + + virtual const char* type_of() { return "movieclip"; } + virtual void enumerate(as_environment* env); + virtual bool is_enabled() const; + + // flash9 + void add_script(int frame, as_function* func); + }; +} + +#endif