?? gameswf_shape.cpp
字號(hào):
current_path.m_ay = y; } int style = in->read_uint(num_line_bits); if (style > 0) { style += line_base; } current_path.m_line = style; if (SHAPE_LOG) IF_VERBOSE_PARSE(log_msg(" shape_character_read: line = %d\n", current_path.m_line)); } if (flags & 0x10) { assert(tag_type >= 22); IF_VERBOSE_PARSE(log_msg(" shape_character read: more fill styles\n")); // Store the current path if any. if (! current_path.is_empty()) { m_paths.push_back(current_path); current_path.m_edges.resize(0); // Clear styles. current_path.m_fill0 = -1; current_path.m_fill1 = -1; current_path.m_line = -1; } // Tack on an empty path signalling a new shape. // @@ need better understanding of whether this is correct??!?!! // @@ i.e., we should just start a whole new shape here, right? m_paths.push_back(path()); m_paths.back().m_new_shape = true; fill_base = m_fill_styles.size(); line_base = m_line_styles.size(); read_fill_styles(&m_fill_styles, in, tag_type, m); read_line_styles(&m_line_styles, in, tag_type); num_fill_bits = in->read_uint(4); num_line_bits = in->read_uint(4); } } else { // EDGERECORD int edge_flag = in->read_uint(1); if (edge_flag == 0) { // curved edge int num_bits = 2 + in->read_uint(4); float cx = x + in->read_sint(num_bits); float cy = y + in->read_sint(num_bits); float ax = cx + in->read_sint(num_bits); float ay = cy + in->read_sint(num_bits); if (SHAPE_LOG) IF_VERBOSE_PARSE(log_msg(" shape_character read: curved edge = %4g %4g - %4g %4g - %4g %4g\n", x, y, cx, cy, ax, ay)); current_path.m_edges.push_back(edge(cx, cy, ax, ay)); x = ax; y = ay; } else { // straight edge int num_bits = 2 + in->read_uint(4); int line_flag = in->read_uint(1); float dx = 0, dy = 0; if (line_flag) { // General line. dx = (float) in->read_sint(num_bits); dy = (float) in->read_sint(num_bits); } else { int vert_flag = in->read_uint(1); if (vert_flag == 0) { // Horizontal line. dx = (float) in->read_sint(num_bits); } else { // Vertical line. dy = (float) in->read_sint(num_bits); } } if (SHAPE_LOG) IF_VERBOSE_PARSE(log_msg(" shape_character_read: straight edge = %4g %4g - %4g %4g\n", x, y, x + dx, y + dy)); current_path.m_edges.push_back(edge(x + dx, y + dy, x + dx, y + dy)); x += dx; y += dy; } } } } void shape_character_def::display(character* inst) // Draw the shape using our own inherent styles. { matrix mat = inst->get_world_matrix(); cxform cx = inst->get_world_cxform(); float pixel_scale = inst->get_parent()->get_pixel_scale(); display(mat, cx, pixel_scale, m_fill_styles, m_line_styles); }#ifdef DEBUG_DISPLAY_SHAPE_PATHS#include "base/ogl.h" static void point_normalize(point* p) { float mag2 = p->m_x * p->m_x + p->m_y * p->m_y; if (mag2 < 1e-9f) { // Very short vector. // @@ log error // Arbitrary unit vector. p->m_x = 1; p->m_y = 0; } float inv_mag = 1.0f / sqrtf(mag2); p->m_x *= inv_mag; p->m_y *= inv_mag; } static void show_fill_number(const point& p, int fill_number) { // We're inside a glBegin(GL_LINES) // Eh, let's do it in binary, least sig four bits... float x = p.m_x; float y = p.m_y; int mask = 8; while (mask) { if (mask & fill_number) { // Vert line --> 1. glVertex2f(x, y - 40.0f); glVertex2f(x, y + 40.0f); } else { // Rectangle --> 0. glVertex2f(x - 10.0f, y - 40.0f); glVertex2f(x + 10.0f, y - 40.0f); glVertex2f(x + 10.0f, y - 40.0f); glVertex2f(x + 10.0f, y + 40.0f); glVertex2f(x - 10.0f, y + 40.0f); glVertex2f(x + 10.0f, y + 40.0f); glVertex2f(x - 10.0f, y - 40.0f); glVertex2f(x - 10.0f, y + 40.0f); } x += 40.0f; mask >>= 1; } } static void debug_display_shape_paths( const matrix& mat, float object_space_max_error, const array<path>& paths, const array<fill_style>& fill_styles, const array<line_style>& line_styles) { for (int i = 0; i < paths.size(); i++) {// if (i > 0) break;//xxxxxxxx const path& p = paths[i]; if (p.m_fill0 == 0 && p.m_fill1 == 0) { continue; } gameswf::render::set_matrix(mat); // Color the line according to which side has // fills. if (p.m_fill0 == 0) glColor4f(1, 0, 0, 0.5); else if (p.m_fill1 == 0) glColor4f(0, 1, 0, 0.5); else glColor4f(0, 0, 1, 0.5); // Offset according to which loop we are. float offset_x = (i & 1) * 80.0f; float offset_y = ((i & 2) >> 1) * 80.0f; glMatrixMode(GL_MODELVIEW); glPushMatrix(); glTranslatef(offset_x, offset_y, 0.f); point pt; glBegin(GL_LINE_STRIP); mat.transform(&pt, point(p.m_ax, p.m_ay)); glVertex2f(pt.m_x, pt.m_y); for (int j = 0; j < p.m_edges.size(); j++) { mat.transform(&pt, point(p.m_edges[j].m_cx, p.m_edges[j].m_cy)); glVertex2f(pt.m_x, pt.m_y); mat.transform(&pt, point(p.m_edges[j].m_ax, p.m_edges[j].m_ay)); glVertex2f(pt.m_x, pt.m_y); } glEnd(); // Draw arrowheads. point dir, right, p0, p1; glBegin(GL_LINES); {for (int j = 0; j < p.m_edges.size(); j++) { mat.transform(&p0, point(p.m_edges[j].m_cx, p.m_edges[j].m_cy)); mat.transform(&p1, point(p.m_edges[j].m_ax, p.m_edges[j].m_ay)); dir = point(p1.m_x - p0.m_x, p1.m_y - p0.m_y); point_normalize(&dir); right = point(-dir.m_y, dir.m_x); // perpendicular const float ARROW_MAG = 60.f; // TWIPS? if (p.m_fill0 != 0) { glColor4f(0, 1, 0, 0.5); glVertex2f(p0.m_x, p0.m_y); glVertex2f(p0.m_x - dir.m_x * ARROW_MAG - right.m_x * ARROW_MAG, p0.m_y - dir.m_y * ARROW_MAG - right.m_y * ARROW_MAG); show_fill_number(point(p0.m_x - right.m_x * ARROW_MAG * 4, p0.m_y - right.m_y * ARROW_MAG * 4), p.m_fill0); } if (p.m_fill1 != 0) { glColor4f(1, 0, 0, 0.5); glVertex2f(p0.m_x, p0.m_y); glVertex2f(p0.m_x - dir.m_x * ARROW_MAG + right.m_x * ARROW_MAG, p0.m_y - dir.m_y * ARROW_MAG + right.m_y * ARROW_MAG); show_fill_number(point(p0.m_x + right.m_x * ARROW_MAG * 4, p0.m_y + right.m_y * ARROW_MAG * 4), p.m_fill1); } }} glEnd(); glPopMatrix(); } }#endif // DEBUG_DISPLAY_SHAPE_PATHS void shape_character_def::display( const matrix& mat, const cxform& cx, float pixel_scale, const array<fill_style>& fill_styles, const array<line_style>& line_styles) const // Display our shape. Use the fill_styles arg to // override our default set of fill styles (e.g. when // rendering text). { // Compute the error tolerance in object-space. float max_scale = mat.get_max_scale(); if (fabsf(max_scale) < 1e-6f) { // Scale is essentially zero. return; } float object_space_max_error = 20.0f / max_scale / pixel_scale * s_curve_max_pixel_error;#ifdef DEBUG_DISPLAY_SHAPE_PATHS // Render a debug view of shape path outlines, instead // of the tesselated shapes themselves. if (gameswf_debug_show_paths) { debug_display_shape_paths(mat, object_space_max_error, m_paths, fill_styles, line_styles); return; }#endif // DEBUG_DISPLAY_SHAPE_PATHS // See if we have an acceptable mesh available; if so then render with it. for (int i = 0, n = m_cached_meshes.size(); i < n; i++) { const mesh_set* candidate = m_cached_meshes[i]; if (object_space_max_error > candidate->get_error_tolerance() * 3.0f) { // Mesh is too high-res; the remaining meshes are higher res, // so stop searching and build an appropriately scaled mesh. break; } if (object_space_max_error > candidate->get_error_tolerance()) { // Do it. candidate->display(mat, cx, fill_styles, line_styles); return; } } // Construct a new mesh to handle this error tolerance. mesh_set* m = new mesh_set(this, object_space_max_error * 0.75f); m_cached_meshes.push_back(m); m->display(mat, cx, fill_styles, line_styles); sort_and_clean_meshes(); } static int sort_by_decreasing_error(const void* A, const void* B) { const mesh_set* a = *(const mesh_set**) A; const mesh_set* b = *(const mesh_set**) B; if (a->get_error_tolerance() < b->get_error_tolerance()) { return 1; } else if (a->get_error_tolerance() > b->get_error_tolerance()) { return -1; } else { return 0; } } void shape_character_def::sort_and_clean_meshes() const // Maintain cached meshes. Clean out mesh_sets that haven't // been used recently, and make sure they're sorted from high // error to low error. { // Re-sort. if (m_cached_meshes.size() > 0) { qsort( &m_cached_meshes[0], m_cached_meshes.size(), sizeof(m_cached_meshes[0]), sort_by_decreasing_error); // Check to make sure the sort worked as intended. #ifndef NDEBUG for (int i = 0, n = m_cached_meshes.size() - 1; i < n; i++) { const mesh_set* a = m_cached_meshes[i]; const mesh_set* b = m_cached_meshes[i + 1]; assert(a->get_error_tolerance() > b->get_error_tolerance()); } #endif // not NDEBUG } } void shape_character_def::tesselate(float error_tolerance, tesselate::trapezoid_accepter* accepter) const // Push our shape data through the tesselator. { tesselate::begin_shape(accepter, error_tolerance); for (int i = 0; i < m_paths.size(); i++) { if (m_paths[i].m_new_shape == true) { // Hm; should handle separate sub-shapes in a less lame way. tesselate::end_shape(); tesselate::begin_shape(accepter, error_tolerance); } else { m_paths[i].tesselate(); } } tesselate::end_shape(); } bool shape_character_def::point_test_local(float x, float y) // Return true if the specified point is on the interior of our shape. // Incoming coords are local coords. { if (m_bound.point_test(x, y) == false) { // Early out. return false; } // Try each of the paths. for (int i = 0; i < m_paths.size(); i++) { if (m_paths[i].point_test(x, y)) { return true; } } return false; } float shape_character_def::get_height_local() { return m_bound.height(); } float shape_character_def::get_width_local() { return m_bound.width(); } void shape_character_def::compute_bound(rect* r) const // Find the bounds of this shape, and store them in // the given rectangle. { r->m_x_min = 1e10f; r->m_y_min = 1e10f; r->m_x_max = -1e10f; r->m_y_max = -1e10f; for (int i = 0; i < m_paths.size(); i++) { const path& p = m_paths[i]; r->expand_to_point(p.m_ax, p.m_ay); for (int j = 0; j < p.m_edges.size(); j++) { r->expand_to_point(p.m_edges[j].m_ax, p.m_edges[j].m_ay);// r->expand_to_point(p.m_edges[j].m_cx, p.m_edges[j].m_cy); } } } void shape_character_def::output_cached_data(tu_file* out, const cache_options& options) // Dump our precomputed mesh data to the given stream. { int n = m_cached_meshes.size(); out->write_le32(n); for (int i = 0; i < n; i++) { m_cached_meshes[i]->output_cached_data(out); } } void shape_character_def::input_cached_data(tu_file* in) // Initialize our mesh data from the given stream. { int n = in->read_le32(); m_cached_meshes.resize(n); for (int i = 0; i < n; i++) { mesh_set* ms = new mesh_set(); ms->input_cached_data(in); m_cached_meshes[i] = ms; } } } // end namespace gameswf// Local Variables:// mode: C++// c-basic-offset: 8 // tab-width: 8// indent-tabs-mode: t// End:
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -