?? gameswf_text.cpp
字號:
// gameswf_text.cpp -- Thatcher Ulrich <tu@tulrich.com> 2003// This source code has been donated to the Public Domain. Do// whatever you want with it.// Code for the text tags.#include "base/utf8.h"#include "base/utility.h"#include "gameswf_impl.h"#include "gameswf_shape.h"#include "gameswf_stream.h"#include "gameswf_log.h"#include "gameswf_font.h"#include "gameswf_fontlib.h"#include "gameswf_render.h"#include "gameswf_textformat.h"namespace gameswf{ // // text_character // // Helper struct. struct text_style { int m_font_id; mutable font* m_font; rgba m_color; float m_x_offset; float m_y_offset; float m_text_height; bool m_has_x_offset; bool m_has_y_offset; text_style() : m_font_id(-1), m_font(NULL), m_x_offset(0), m_y_offset(0), m_text_height(1.0f), m_has_x_offset(false), m_has_y_offset(false) { } void resolve_font(movie_definition_sub* root_def) const { if (m_font == NULL) { assert(m_font_id >= 0); m_font = root_def->get_font(m_font_id); if (m_font == NULL) { log_error("error: text style with undefined font; font_id = %d\n", m_font_id); } } } }; // Helper struct. struct text_glyph_record { struct glyph_entry { int m_glyph_index; float m_glyph_advance; }; text_style m_style; array<glyph_entry> m_glyphs; void read(stream* in, int glyph_count, int glyph_bits, int advance_bits) { m_glyphs.resize(glyph_count); for (int i = 0; i < glyph_count; i++) { m_glyphs[i].m_glyph_index = in->read_uint(glyph_bits); m_glyphs[i].m_glyph_advance = (float) in->read_sint(advance_bits); } } }; // Render the given glyph records. static void display_glyph_records( const matrix& this_mat, character* inst, const array<text_glyph_record>& records, movie_definition_sub* root_def) { static array<fill_style> s_dummy_style; // used to pass a color on to shape_character::display() static array<line_style> s_dummy_line_style; s_dummy_style.resize(1); matrix mat = inst->get_world_matrix(); mat.concatenate(this_mat); cxform cx = inst->get_world_cxform(); float pixel_scale = inst->get_pixel_scale();// display_info sub_di = di;// sub_di.m_matrix.concatenate(mat);// matrix base_matrix = sub_di.m_matrix; matrix base_matrix = mat; float base_matrix_max_scale = base_matrix.get_max_scale(); float scale = 1.0f; float x = 0.0f; float y = 0.0f; for (int i = 0; i < records.size(); i++) { // Draw the characters within the current record; i.e. consecutive // chars that share a particular style. const text_glyph_record& rec = records[i]; rec.m_style.resolve_font(root_def); font* fnt = rec.m_style.m_font; if (fnt == NULL) { continue; } scale = rec.m_style.m_text_height / 1024.0f; // the EM square is 1024 x 1024 float text_screen_height = base_matrix_max_scale * scale * 1024.0f / 20.0f * pixel_scale; int nominal_glyph_height = fnt->get_texture_glyph_nominal_size(); float max_glyph_height = fontlib::get_texture_glyph_max_height(fnt);#ifdef GAMESWF_ALWAYS_USE_TEXTURES_FOR_TEXT_WHEN_POSSIBLE const bool use_glyph_textures = true;#else bool use_glyph_textures = text_screen_height <= max_glyph_height * 1.0f;#endif if (rec.m_style.m_has_x_offset) { x = rec.m_style.m_x_offset; } if (rec.m_style.m_has_y_offset) { y = rec.m_style.m_y_offset; } s_dummy_style[0].set_color(rec.m_style.m_color); rgba transformed_color = cx.transform(rec.m_style.m_color); for (int j = 0; j < rec.m_glyphs.size(); j++) { int index = rec.m_glyphs[j].m_glyph_index; mat = base_matrix; mat.concatenate_translation(x, y); mat.concatenate_scale(scale); if (index == -1) { // Invalid glyph; render it as an empty box. render::set_matrix(mat); render::line_style_color(transformed_color); // The EM square is 1024x1024, but usually isn't filled up. // We'll use about half the width, and around 3/4 the height. // Values adjusted by eye. // The Y baseline is at 0; negative Y is up. static const Sint16 s_empty_char_box[5 * 2] = { 32, 32, 480, 32, 480, -656, 32, -656, 32, 32 }; render::draw_line_strip(s_empty_char_box, 5); } else { const texture_glyph& tg = fnt->get_texture_glyph(index); shape_character_def* glyph = fnt->get_glyph(index); if (tg.is_renderable() && (use_glyph_textures || glyph == NULL)) { fontlib::draw_glyph(mat, tg, transformed_color, nominal_glyph_height); } else { // Draw the character using the filled outline. if (glyph) { glyph->display(mat, cx, pixel_scale, s_dummy_style, s_dummy_line_style); } } } x += rec.m_glyphs[j].m_glyph_advance; } } } struct text_character_def : public character_def { movie_definition_sub* m_root_def; rect m_rect; matrix m_matrix; array<text_glyph_record> m_text_glyph_records; text_character_def(movie_definition_sub* root_def) : m_root_def(root_def) { assert(m_root_def); } void read(stream* in, int tag_type, movie_definition_sub* m) { assert(m != NULL); assert(tag_type == 11 || tag_type == 33); m_rect.read(in); m_matrix.read(in); int glyph_bits = in->read_u8(); int advance_bits = in->read_u8(); IF_VERBOSE_PARSE(log_msg("begin text records\n")); bool last_record_was_style_change = false; text_style style; for (;;) { int first_byte = in->read_u8(); if (first_byte == 0) { // This is the end of the text records. IF_VERBOSE_PARSE(log_msg("end text records\n")); break; } // Style changes and glyph records just alternate. // (Contrary to what most SWF references say!) if (last_record_was_style_change == false) { // This is a style change. last_record_was_style_change = true; bool has_font = (first_byte >> 3) & 1; bool has_color = (first_byte >> 2) & 1; bool has_y_offset = (first_byte >> 1) & 1; bool has_x_offset = (first_byte >> 0) & 1; IF_VERBOSE_PARSE(log_msg(" text style change\n")); if (has_font) { Uint16 font_id = in->read_u16(); style.m_font_id = font_id; IF_VERBOSE_PARSE(log_msg(" has_font: font id = %d\n", font_id)); } if (has_color) { if (tag_type == 11) { style.m_color.read_rgb(in); } else { assert(tag_type == 33); style.m_color.read_rgba(in); } IF_VERBOSE_PARSE(log_msg(" has_color\n")); } if (has_x_offset) { style.m_has_x_offset = true; style.m_x_offset = in->read_s16(); IF_VERBOSE_PARSE(log_msg(" has_x_offset = %g\n", style.m_x_offset)); } else { style.m_has_x_offset = false; style.m_x_offset = 0.0f; } if (has_y_offset) { style.m_has_y_offset = true; style.m_y_offset = in->read_s16(); IF_VERBOSE_PARSE(log_msg(" has_y_offset = %g\n", style.m_y_offset)); } else { style.m_has_y_offset = false; style.m_y_offset = 0.0f; } if (has_font) { style.m_text_height = in->read_u16(); IF_VERBOSE_PARSE(log_msg(" text_height = %g\n", style.m_text_height)); } } else { // Read the glyph record. last_record_was_style_change = false; int glyph_count = first_byte;// if (! last_record_was_style_change)// {// glyph_count &= 0x7F;// }// // else { Don't mask the top bit; the first record is allowed to have > 127 glyphs. } m_text_glyph_records.resize(m_text_glyph_records.size() + 1); m_text_glyph_records.back().m_style = style; m_text_glyph_records.back().read(in, glyph_count, glyph_bits, advance_bits); IF_VERBOSE_PARSE(log_msg(" glyph_records: count = %d\n", glyph_count)); } } } void display(character* inst) // Draw the string. { display_glyph_records(m_matrix, inst, m_text_glyph_records, m_root_def); } }; void define_text_loader(stream* in, int tag_type, movie_definition_sub* m) // Read a DefineText tag. { assert(tag_type == 11 || tag_type == 33); Uint16 character_id = in->read_u16(); text_character_def* ch = new text_character_def(m); IF_VERBOSE_PARSE(log_msg("text_character, id = %d\n", character_id)); ch->read(in, tag_type, m); // IF_VERBOSE_PARSE(print some stuff); m->add_character(character_id, ch); } // // edit_text_character_def // struct edit_text_character_def : public character_def // A definition for a text display character, whose text can // be changed at runtime (by script or host). { movie_definition_sub* m_root_def; rect m_rect; tu_string m_default_name; text_format m_format; bool m_word_wrap; bool m_multiline; bool m_password; // show asterisks instead of actual characters bool m_readonly; bool m_auto_size; // resize our bound to fit the text bool m_no_select; bool m_border; // forces white background and black border -- silly, but sometimes used bool m_html; // Allowed HTML (from Alexi's SWF Reference): // // <a href=url target=targ>...</a> -- hyperlink // <b>...</b> -- bold // <br> -- line break // <font face=name size=[+|-][0-9]+ color=#RRGGBB>...</font> -- font change; size in TWIPS // <i>...</i> -- italic // <li>...</li> -- list item // <p>...</p> -- paragraph // <tab> -- insert tab // <TEXTFORMAT> </TEXTFORMAT> // [ BLOCKINDENT=[0-9]+ ] // [ INDENT=[0-9]+ ] // [ LEADING=[0-9]+ ] // [ LEFTMARGIN=[0-9]+ ] // [ RIGHTMARGIN=[0-9]+ ] // [ TABSTOPS=[0-9]+{,[0-9]+} ] // // Change the different parameters as indicated. The // sizes are all in TWIPs. There can be multiple // positions for the tab stops. These are seperated by // commas. // <U>...</U> -- underline bool m_use_outlines; // when true, use specified SWF internal font. Otherwise, renderer picks a default font int m_font_id; font* m_font; float m_text_height; rgba m_color; int m_max_length; enum alignment { ALIGN_LEFT = 0, ALIGN_RIGHT, ALIGN_CENTER, ALIGN_JUSTIFY // probably don't need to implement... }; alignment m_alignment; float m_left_margin; // extra space between box border and text float m_right_margin; float m_indent; // how much to indent the first line of multiline text float m_leading; // extra space between lines (in addition to default font line spacing) tu_string m_default_text; edit_text_character_def(movie_definition_sub* root_def) : m_root_def(root_def), m_word_wrap(false), m_multiline(false), m_password(false), m_readonly(false), m_auto_size(false), m_no_select(false), m_border(false), m_html(false), m_use_outlines(false), m_font_id(-1), m_font(NULL), m_text_height(1.0f), m_max_length(0), m_alignment(ALIGN_LEFT), m_left_margin(0.0f), m_right_margin(0.0f), m_indent(0.0f), m_leading(0.0f) { assert(m_root_def); m_color.set(0, 0, 0, 255); } // Set the format of the text void set_format(text_format &format) { m_format = format; } ~edit_text_character_def() { } character* create_character_instance(movie* parent, int id); void read(stream* in, int tag_type, movie_definition_sub* m) { assert(m != NULL); assert(tag_type == 37); m_rect.read(in); in->align(); bool has_text = in->read_uint(1) ? true : false; m_word_wrap = in->read_uint(1) ? true : false; m_multiline = in->read_uint(1) ? true : false; m_password = in->read_uint(1) ? true : false; m_readonly = in->read_uint(1) ? true : false; bool has_color = in->read_uint(1) ? true : false; bool has_max_length = in->read_uint(1) ? true : false; bool has_font = in->read_uint(1) ? true : false; in->read_uint(1); // reserved m_auto_size = in->read_uint(1) ? true : false; bool has_layout = in->read_uint(1) ? true : false; m_no_select = in->read_uint(1) ? true : false; m_border = in->read_uint(1) ? true : false; in->read_uint(1); // reserved m_html = in->read_uint(1) ? true : false; m_use_outlines = in->read_uint(1) ? true : false; if (has_font) { m_font_id = in->read_u16(); m_text_height = (float) in->read_u16(); } if (has_color) { m_color.read_rgba(in); } if (has_max_length) { m_max_length = in->read_u16(); } if (has_layout) { m_alignment = (alignment) in->read_u8(); m_left_margin = (float) in->read_u16(); m_right_margin = (float) in->read_u16(); m_indent = (float) in->read_s16(); m_leading = (float) in->read_s16(); } char* name = in->read_string(); m_default_name = name; delete [] name; if (has_text) { char* str = in->read_string(); m_default_text = str; delete [] str; } IF_VERBOSE_PARSE(log_msg("edit_text_char, varname = %s, text = %s\n", m_default_name.c_str(), m_default_text.c_str())); } }; // // edit_text_character // struct edit_text_character : public character { edit_text_character_def* m_def; array<text_glyph_record> m_text_glyph_records; array<fill_style> m_dummy_style; // used to pass a color on to shape_character::display() array<line_style> m_dummy_line_style; rect m_text_bounding_box; // bounds of dynamic text, as laid out tu_string m_text; edit_text_character(movie* parent, edit_text_character_def* def, int id) : character(parent, id), m_def(def) { assert(parent); assert(m_def); set_text_value(m_def->m_default_text.c_str()); m_dummy_style.push_back(fill_style()); reset_bounding_box(0, 0); } ~edit_text_character() { } virtual const char* get_text_name() const { return m_def->m_default_name.c_str(); } void reset_bounding_box(float x, float y)
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -