📄 gameswf_impl.cpp
字号:
smart_ptr<resource> res = def->get_exported_resource(inf.m_symbol); bool imported = true; if (res == NULL) { log_error("import error: resource '%s' is not exported from movie '%s'\n", inf.m_symbol.c_str(), source_url); } else if (font* f = res->cast_to_font()) { // Add this shared font to our fonts. add_font(inf.m_character_id, f); imported = true; } else if (character_def* ch = res->cast_to_character_def()) { // Add this character to our characters. add_character(inf.m_character_id, ch); imported = true; } else { log_error("import error: resource '%s' from movie '%s' has unknown type\n", inf.m_symbol.c_str(), source_url); } if (imported) { m_imports.remove(i); // Hold a ref, to keep this source movie_definition alive. m_import_source_movies.push_back(source_movie); } } } } void add_character(int character_id, character_def* c) { assert(c); m_characters.add(character_id, c); } character_def* get_character_def(int character_id) {#ifndef NDEBUG // make sure character_id is resolved if (in_import_table(character_id)) { log_error("get_character_def(): character_id %d is still waiting to be imported\n", character_id); }#endif // not NDEBUG smart_ptr<character_def> ch; m_characters.get(character_id, &ch); assert(ch == NULL || ch->get_ref_count() > 1); return ch.get_ptr(); } bool get_labeled_frame(const char* label, int* frame_number) // Returns 0-based frame # { return m_named_frames.get(label, frame_number); } void add_font(int font_id, font* f) { assert(f); m_fonts.add(font_id, f); } font* get_font(int font_id) {#ifndef NDEBUG // make sure font_id is resolved if (in_import_table(font_id)) { log_error("get_font(): font_id %d is still waiting to be imported\n", font_id); }#endif // not NDEBUG smart_ptr<font> f; m_fonts.get(font_id, &f); assert(f == NULL || f->get_ref_count() > 1); return f.get_ptr(); } bitmap_character_def* get_bitmap_character(int character_id) { smart_ptr<bitmap_character_def> ch; m_bitmap_characters.get(character_id, &ch); assert(ch == NULL || ch->get_ref_count() > 1); return ch.get_ptr(); } void add_bitmap_character(int character_id, bitmap_character_def* ch) { assert(ch); m_bitmap_characters.add(character_id, ch); add_bitmap_info(ch->get_bitmap_info()); } sound_sample* get_sound_sample(int character_id) { smart_ptr<sound_sample> ch; m_sound_samples.get(character_id, &ch); assert(ch == NULL || ch->get_ref_count() > 1); return ch.get_ptr(); } virtual void add_sound_sample(int character_id, sound_sample* sam) { assert(sam); m_sound_samples.add(character_id, sam); } void add_execute_tag(execute_tag* e) { assert(e); m_playlist[m_loading_frame].push_back(e); } void add_init_action(int sprite_id, execute_tag* e) // Need to execute the given tag before entering the // currently-loading frame for the first time. // // @@ AFAIK, the sprite_id is totally pointless -- correct? { assert(e); m_init_action_list[m_loading_frame].push_back(e); } void add_frame_name(const char* name) // Labels the frame currently being loaded with the // given name. A copy of the name string is made and // kept in this object. { assert(m_loading_frame >= 0 && m_loading_frame < m_frame_count); tu_string n = name; assert(m_named_frames.get(n, NULL) == false); // frame should not already have a name (?) m_named_frames.add(n, m_loading_frame); // stores 0-based frame # } void set_jpeg_loader(jpeg::input* j_in) // Set an input object for later loading DefineBits // images (JPEG images without the table info). { assert(m_jpeg_in == NULL); m_jpeg_in = j_in; } jpeg::input* get_jpeg_loader() // Get the jpeg input loader, to load a DefineBits // image (one without table info). { return m_jpeg_in; } virtual const array<execute_tag*>& get_playlist(int frame_number) { return m_playlist[frame_number]; } /* movie_def_impl */ virtual const array<execute_tag*>* get_init_actions(int frame_number) { return &m_init_action_list[frame_number]; } /* movie_def_impl */ void read(tu_file* in) // Read a .SWF movie. { Uint32 file_start_pos = in->get_position(); Uint32 header = in->read_le32(); m_file_length = in->read_le32(); Uint32 file_end_pos = file_start_pos + m_file_length; m_version = (header >> 24) & 255; if ((header & 0x0FFFFFF) != 0x00535746 && (header & 0x0FFFFFF) != 0x00535743) { // ERROR log_error("gameswf::movie_def_impl::read() -- file does not start with a SWF header!\n"); return; } bool compressed = (header & 255) == 'C'; IF_VERBOSE_PARSE(log_msg("version = %d, file_length = %d\n", m_version, m_file_length)); tu_file* original_in = NULL; if (compressed) {#if TU_CONFIG_LINK_TO_ZLIB == 0 log_error("movie_def_impl::read(): unable to read zipped SWF data; TU_CONFIG_LINK_TO_ZLIB is 0\n"); return;#endif IF_VERBOSE_PARSE(log_msg("file is compressed.\n")); original_in = in; // Uncompress the input as we read it. in = zlib_adapter::make_inflater(original_in); // Subtract the size of the 8-byte header, since // it's not included in the compressed // stream length. file_end_pos = m_file_length - 8; } stream str(in); m_frame_size.read(&str); m_frame_rate = str.read_u16() / 256.0f; m_frame_count = str.read_u16(); m_playlist.resize(m_frame_count); m_init_action_list.resize(m_frame_count); IF_VERBOSE_PARSE(m_frame_size.print()); IF_VERBOSE_PARSE(log_msg("frame rate = %f, frames = %d\n", m_frame_rate, m_frame_count)); while ((Uint32) str.get_position() < file_end_pos) { int tag_type = str.open_tag(); if (s_progress_function != NULL) { s_progress_function((Uint32) str.get_position(), file_end_pos); } loader_function lf = NULL; //IF_VERBOSE_PARSE(log_msg("tag_type = %d\n", tag_type)); if (tag_type == 1) { // show frame tag -- advance to the next frame. IF_VERBOSE_PARSE(log_msg(" show_frame\n")); m_loading_frame++; } else if (s_tag_loaders.get(tag_type, &lf)) { // call the tag loader. The tag loader should add // characters or tags to the movie data structure. (*lf)(&str, tag_type, this); } else { // no tag loader for this tag type. IF_VERBOSE_PARSE(log_msg("*** no tag loader for type %d\n", tag_type)); IF_VERBOSE_PARSE(dump_tag_bytes(&str)); } str.close_tag(); if (tag_type == 0) { if ((unsigned int) str.get_position() != file_end_pos) { // Safety break, so we don't read past the end of the // movie. log_msg("warning: hit stream-end tag, but not at the " "end of the file yet; stopping for safety\n"); break; } } } if (m_jpeg_in) { delete m_jpeg_in; m_jpeg_in = NULL; } if (original_in) { // Done with the zlib_adapter. delete in; } } /* movie_def_impl */ void get_owned_fonts(array<font*>* fonts) // Fill up *fonts with fonts that we own. { assert(fonts); fonts->resize(0); array<int> font_ids; for (hash<int, smart_ptr<font> >::iterator it = m_fonts.begin(); it != m_fonts.end(); ++it) { font* f = it->second.get_ptr(); if (f->get_owning_movie() == this) { // Sort by character id, so the ordering is // consistent for cache read/write. int id = it->first; // Insert in correct place. int insert; for (insert = 0; insert < font_ids.size(); insert++) { if (font_ids[insert] > id) { // We want to insert here. break; } } fonts->insert(insert, f); font_ids.insert(insert, id); } } } /* movie_def_impl */ void generate_font_bitmaps() // Generate bitmaps for our fonts, if necessary. { // Collect list of fonts. array<font*> fonts; get_owned_fonts(&fonts); fontlib::generate_font_bitmaps(fonts, this); } // Increment this when the cache data format changes. #define CACHE_FILE_VERSION 4 /* movie_def_impl */ void output_cached_data(tu_file* out, const cache_options& options) // Dump our cached data into the given stream. { // Write a little header. char header[5]; strcpy(header, "gscX"); header[3] = CACHE_FILE_VERSION; compiler_assert(CACHE_FILE_VERSION < 256); out->write_bytes(header, 4); // Write font data. array<font*> fonts; get_owned_fonts(&fonts); fontlib::output_cached_data(out, fonts, this, options); // Write character data. {for (hash<int, smart_ptr<character_def> >::iterator it = m_characters.begin(); it != m_characters.end(); ++it) { out->write_le16(it->first); it->second->output_cached_data(out, options); }} out->write_le16((Sint16) -1); // end of characters marker } /* movie_def_impl */ void input_cached_data(tu_file* in) // Read in cached data and use it to prime our loaded characters. { // Read the header & check version. unsigned char header[4]; in->read_bytes(header, 4); if (header[0] != 'g' || header[1] != 's' || header[2] != 'c') { log_error("cache file does not have the correct format; skipping\n"); return; } else if (header[3] != CACHE_FILE_VERSION) { log_error( "cached data is version %d, but we require version %d; skipping\n", int(header[3]), CACHE_FILE_VERSION); return; } // Read the cached font data. array<font*> fonts; get_owned_fonts(&fonts); fontlib::input_cached_data(in, fonts, this); // Read the cached character data. for (;;) { if (in->get_error() != TU_FILE_NO_ERROR) { log_error("error reading cache file (characters); skipping\n"); return; } if (in->get_eof()) { log_error("unexpected eof reading cache file (characters); skipping\n"); return; } Sint16 id = in->read_le16(); if (id == (Sint16) -1) { break; } // done smart_ptr<character_def> ch; m_characters.get(id, &ch); if (ch != NULL) { ch->input_cached_data(in); } else { log_error("sync error in cache file (reading characters)! " "Skipping rest of cache data.\n"); return; } } } }; // // movie_root // // Global, shared root state for a movie and all its characters. // struct movie_root : public movie_interface { smart_ptr<movie_def_impl> m_def; smart_ptr<movie> m_movie; int m_viewport_x0, m_viewport_y0, m_viewport_width, m_viewport_height; float m_pixel_scale; rgba m_background_color; float m_timer; int m_mouse_x, m_mouse_y, m_mouse_buttons; void * m_userdata; movie::drag_state m_drag_state; // @@ fold this into m_mouse_button_state? mouse_button_state m_mouse_button_state; bool m_on_event_load_called; // Flags for event handlers bool m_on_event_xmlsocket_ondata_called; bool m_on_event_xmlsocket_onxml_called; bool m_on_event_load_progress_called; array<Timer *> m_interval_timers; movie_root(movie_def_impl* def) : m_def(def), m_movie(NULL), m_viewport_x0(0), m_viewport_y0(0), m_viewport_width(1), m_viewport_height(1), m_pixel_scale(1.0f), m_background_color(0, 0, 0, 255), m_timer(0.0f), m_mouse_x(0), m_mouse_y(0), m_mouse_buttons(0), m_userdata(NULL), m_on_event_load_called(false), m_on_event_xmlsocket_ondata_called(false), m_on_event_xmlsocket_onxml_called(false), m_on_event_load_progress_called(false) { assert(m_def != NULL); set_display_viewport(0, 0, (int) m_def->get_width_pixels(), (int) m_def->get_height_pixels()); } ~movie_root() { assert(m_def != NULL); m_movie = NULL; m_def = NULL; } // @@ should these delegate to m_movie? Probably... virtual void set_member(const tu_stringi& name, const as_value& val) {} virtual bool get_member(const tu_stringi& name, as_value* val) { return false; } virtual movie* to_movie() { assert(0); return 0; } // @@ should this return m_movie.get_ptr()? void set_root_movie(movie* root_movie) { m_movie = root_movie; assert(m_movie != NULL); } void set_display_viewport(int x0, int y0, int w, int h) { m_viewport_x0 = x0; m_viewport_y0 = y0; m_viewport_width = w; m_viewport_height = h; // Recompute pixel scale. float scale_x = m_viewport_width / TWIPS_TO_PIXELS(m_def->m_frame_size.width()); float scale_y = m_viewport_height / TWIPS_TO_PIXELS(m_def->m_frame_size.height()); m_pixel_scale = fmax(scale_x, scale_y); } void notify_mouse_state(int x, int y, int buttons) // The host app uses this to tell the movie where the // user's mouse pointer is. { m_mouse_x = x; m_mouse_y = y; m_mouse_buttons = buttons; } virtual void get_mouse_state(int* x, int* y, int* buttons) // Use this to retrieve the last state of the mouse, as set via // notify_mouse_state(). Coordinates are in PIXELS, NOT TWIPS. { assert(x); assert(y); assert(buttons);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -