void on_mouse_button_down(int x, int y, unsigned flags) { if(flags & 1) { double xd = x; double yd = y; double r = 4.0 / m_scale.scale(); m_scale.inverse_transform(&xd, &yd); m_point_idx = m_shape.hit_test(xd, yd, r); force_redraw(); } }
virtual void on_draw() { typedef agg::renderer_base<pixfmt_pre> renderer_base; typedef agg::renderer_scanline_aa_solid<renderer_base> renderer_scanline; typedef agg::scanline_u8 scanline; pixfmt_pre pixf(rbuf_window()); renderer_base ren_base(pixf); ren_base.clear(agg::rgba(1.0, 1.0, 0.95)); renderer_scanline ren(ren_base); agg::rasterizer_scanline_aa<agg::rasterizer_sl_clip_dbl> ras; agg::scanline_u8 sl; agg::conv_transform<agg::compound_shape> shape(m_shape, m_scale); agg::conv_stroke<agg::conv_transform<agg::compound_shape> > stroke(shape); m_shape.approximation_scale(m_scale.scale()); unsigned i; agg::path_storage tmp_path; ras.clip_box(0, 0, width(), height()); // This is an alternative method of Flash rasterization. // We decompose the compound shape into separate paths // and select the ones that fit the given style (left or right). // So that, we form a sub-shape and draw it as a whole. // // Here the regular scanline rasterizer is used, but it doesn't // automatically close the polygons. So that, the rasterizer // actually works with a set of polylines instead of polygons. // Of course, the data integrity must be preserved, that is, // the polylines must eventually form a closed contour // (or a set of closed contours). So that, first we set // auto_close(false); // // The second important thing is that one path can be rasterized // twice, if it has both, left and right fill. Sometimes the // path has equal left and right fill, so that, the same path // will be added twice even for a single sub-shape. If the // rasterizer can tolerate these degenerates you can add them, // but it's also fine just to omit them. // // The third thing is that for one side (left or right) // you should invert the direction of the paths. // // The main disadvantage of this method is imperfect stitching // of the adjacent polygons. The problem can be solved if we use // compositing operation "plus" instead of alpha-blend. But // in this case we are forced to use an RGBA buffer, clean it with // zero, rasterize using "plus" operation, and then alpha-blend // the result over the final scene. It can be too expensive. //------------------------------------------------------------ ras.auto_close(false); //ras.filling_rule(agg::fill_even_odd); start_timer(); for(int s = m_shape.min_style(); s <= m_shape.max_style(); s++) { ras.reset(); for(i = 0; i < m_shape.paths(); i++) { const agg::path_style& style = m_shape.style(i); if(style.left_fill != style.right_fill) { if(style.left_fill == s) { ras.add_path(shape, style.path_id); } if(style.right_fill == s) { tmp_path.remove_all(); tmp_path.concat_path(shape, style.path_id); tmp_path.invert_polygon(0); ras.add_path(tmp_path); } } } agg::render_scanlines_aa_solid(ras, sl, ren_base, m_colors[s]); } double tfill = elapsed_time(); ras.auto_close(true); // Draw strokes //---------------------- start_timer(); stroke.width(sqrt(m_scale.scale())); stroke.line_join(agg::round_join); stroke.line_cap(agg::round_cap); for(i = 0; i < m_shape.paths(); i++) { ras.reset(); if(m_shape.style(i).line >= 0) { ras.add_path(stroke, m_shape.style(i).path_id); ren.color(agg::srgba8(0,0,0, 128)); agg::render_scanlines(ras, sl, ren); } } double tstroke = elapsed_time(); char buf[256]; agg::gsv_text t; t.size(8.0); t.flip(true); agg::conv_stroke<agg::gsv_text> ts(t); ts.width(1.6); ts.line_cap(agg::round_cap); sprintf(buf, "Fill=%.2fms (%dFPS) Stroke=%.2fms (%dFPS) Total=%.2fms (%dFPS)\n\n" "Space: Next Shape\n\n" "+/- : ZoomIn/ZoomOut (with respect to the mouse pointer)", tfill, int(1000.0 / tfill), tstroke, int(1000.0 / tstroke), tfill+tstroke, int(1000.0 / (tfill+tstroke))); t.start_point(10.0, 20.0); t.text(buf); ras.add_path(ts); ren.color(agg::rgba(0,0,0)); agg::render_scanlines(ras, sl, ren); }
virtual void on_draw() { typedef agg::renderer_base<pixfmt> renderer_base; typedef agg::renderer_scanline_aa_solid<renderer_base> renderer_scanline; typedef agg::scanline_u8 scanline; pixfmt pixf(rbuf_window()); renderer_base ren_base(pixf); ren_base.clear(agg::rgba(1.0, 1.0, 0.95)); renderer_scanline ren(ren_base); unsigned i; unsigned w = unsigned(width()); m_gradient.resize(w); agg::rgba8 c1(255, 0, 0, 180); agg::rgba8 c2(0, 0, 255, 180); for(i = 0; i < w; i++) { m_gradient[i] = c1.gradient(c2, i / width()); m_gradient[i].premultiply(); } agg::rasterizer_scanline_aa<agg::rasterizer_sl_clip_dbl> ras; agg::rasterizer_compound_aa<agg::rasterizer_sl_clip_dbl> rasc; agg::scanline_u8 sl; agg::scanline_bin sl_bin; agg::conv_transform<agg::compound_shape> shape(m_shape, m_scale); agg::conv_stroke<agg::conv_transform<agg::compound_shape> > stroke(shape); agg::test_styles style_handler(m_colors, m_gradient.data()); agg::span_allocator<agg::rgba8> alloc; m_shape.approximation_scale(m_scale.scale()); // Fill shape //---------------------- rasc.clip_box(0, 0, width(), height()); rasc.reset(); //rasc.filling_rule(agg::fill_even_odd); start_timer(); for(i = 0; i < m_shape.paths(); i++) { if(m_shape.style(i).left_fill >= 0 || m_shape.style(i).right_fill >= 0) { rasc.styles(m_shape.style(i).left_fill, m_shape.style(i).right_fill); rasc.add_path(shape, m_shape.style(i).path_id); } } agg::render_scanlines_compound(rasc, sl, sl_bin, ren_base, alloc, style_handler); double tfill = elapsed_time(); // Hit-test test bool draw_strokes = true; if(m_hit_x >= 0 && m_hit_y >= 0) { if(rasc.hit_test(m_hit_x, m_hit_y)) { draw_strokes = false; } } // Draw strokes //---------------------- start_timer(); if(draw_strokes) { ras.clip_box(0, 0, width(), height()); stroke.width(sqrt(m_scale.scale())); stroke.line_join(agg::round_join); stroke.line_cap(agg::round_cap); for(i = 0; i < m_shape.paths(); i++) { ras.reset(); if(m_shape.style(i).line >= 0) { ras.add_path(stroke, m_shape.style(i).path_id); ren.color(agg::rgba8(0,0,0, 128)); agg::render_scanlines(ras, sl, ren); } } } double tstroke = elapsed_time(); char buf[256]; agg::gsv_text t; t.size(8.0); t.flip(true); agg::conv_stroke<agg::gsv_text> ts(t); ts.width(1.6); ts.line_cap(agg::round_cap); sprintf(buf, "Fill=%.2fms (%dFPS) Stroke=%.2fms (%dFPS) Total=%.2fms (%dFPS)\n\n" "Space: Next Shape\n\n" "+/- : ZoomIn/ZoomOut (with respect to the mouse pointer)", tfill, int(1000.0 / tfill), tstroke, int(1000.0 / tstroke), tfill+tstroke, int(1000.0 / (tfill+tstroke))); t.start_point(10.0, 20.0); t.text(buf); ras.add_path(ts); ren.color(agg::rgba(0,0,0)); agg::render_scanlines(ras, sl, ren); if(m_gamma.gamma() != 1.0) { pixf.apply_gamma_inv(m_gamma); } }
unsigned CAggMemoryDC::DrawScaledText( const TCHAR* text, const GraphTypes::RectF& rc, const GraphTypes::Color& clr, const char* font, int size, const PointF & descsubtract) { if (m_buf==0) return 0; unsigned len=0; pixel_format pixf(m_rbuf); ren_base renb(pixf); solid_renderer ren_solid(renb); ATLASSERT(m_buf); conv_font_curve_type fcurves(m_fonts->m_fman.path_adaptor()); conv_font_segm_type fsegm(fcurves); conv_font_trans_type ftrans(fsegm, m_mtx); // fsegm.approximation_scale(3.0); // fcurves.approximation_scale(2.0); m_fonts->m_feng.flip_y(true); m_fonts->m_feng.hinting(true); if(m_fonts->m_feng.create_font( font, agg::glyph_ren_outline, size, 0.0, FW_NORMAL, false, ANSI_CHARSET, DEFAULT_PITCH | FF_SWISS )) { double x = 0.0; double y = 0.0; const TCHAR* p = text; TEXTMETRIC tm; GetTextMetrics(&tm); //double descent=(tm.tmDescent>descsubtract.y)?(tm.tmDescent-descsubtract.y):(tm.tmDescent-1); //ATLASSERT(tm.tmDescent>descsubtract.y); //ATLASSERT(descent>0); //descent *= m_mtx.scale(); //m_mtx *= agg::trans_affine_translation(rc.x-m_rcUpdate.left, rc.y+rc.Height-descent-m_rcUpdate.top); double ascent=tm.tmAscent-descsubtract.y; ATLASSERT(ascent>0.0f); ascent *= m_mtx.scale(); m_mtx *= agg::trans_affine_translation(rc.x-m_rcUpdate.left, rc.y+ascent-m_rcUpdate.top); ren_solid.color(agg::rgba8(clr.GetR(), clr.GetG(), clr.GetB(), clr.GetA())); while(*p) { const agg::glyph_cache* glyph = m_fonts->m_fman.glyph(*p); if(glyph) { m_fonts->m_fman.add_kerning(&x, &y); m_fonts->m_fman.init_embedded_adaptors(glyph, x, y); if(glyph->data_type == agg::glyph_data_outline) { m_ras_aa.add_path(ftrans); } // increment pen position x += glyph->advance_x; y += glyph->advance_y; } ++p; ++len; } agg::render_scanlines(m_ras_aa, m_sl, ren_solid); ATLASSERT(m_buf); } return len; }
virtual void on_draw() { pixfmt pf(rbuf_window()); renderer_base ren_base(pf); ren_base.clear(agg::rgba(0.5, 0.75, 0.85)); renderer_scanline ren(ren_base); rasterizer_scanline ras; scanline sl; ras.clip_box(0, 0, width(), height()); // Pattern source. Must have an interface: // width() const // height() const // pixel(int x, int y) const // Any agg::renderer_base<> or derived // is good for the use as a source. //----------------------------------- pattern_src_brightness_to_alpha_rgba8 p1(rbuf_img(0)); agg::pattern_filter_bilinear_rgba8 fltr; // Filtering functor // agg::line_image_pattern is the main container for the patterns. It creates // a copy of the patterns extended according to the needs of the filter. // agg::line_image_pattern can operate with arbitrary image width, but if the // width of the pattern is power of 2, it's better to use the modified // version agg::line_image_pattern_pow2 because it works about 15-25 percent // faster than agg::line_image_pattern (because of using simple masking instead // of expensive '%' operation). typedef agg::line_image_pattern<agg::pattern_filter_bilinear_rgba8> pattern_type; typedef agg::renderer_base<pixfmt> base_ren_type; typedef agg::renderer_outline_image<base_ren_type, pattern_type> renderer_img_type; typedef agg::rasterizer_outline_aa<renderer_img_type, agg::line_coord_sat> rasterizer_img_type; typedef agg::renderer_outline_aa<base_ren_type> renderer_line_type; typedef agg::rasterizer_outline_aa<renderer_line_type, agg::line_coord_sat> rasterizer_line_type; //-- Create with specifying the source //pattern_type patt(fltr, src); //-- Create uninitialized and set the source pattern_type patt(fltr); patt.create(p1); renderer_img_type ren_img(ren_base, patt); rasterizer_img_type ras_img(ren_img); //-- create uninitialized and set parameters agg::line_profile_aa profile; profile.smoother_width(10.0); //optional profile.width(8.0); //mandatory! renderer_line_type ren_line(ren_base, profile); ren_line.color(agg::rgba8(0,0,127)); //mandatory! rasterizer_line_type ras_line(ren_line); ras_line.round_cap(true); //optional //ras_line.line_join(agg::outline_no_join); //optional // Calculate the dilation value so that, the line caps were // drawn correctly. //--------------- double w2 = 9.0;//p1.height() / 2 + 2; // Set the clip box a bit bigger than you expect. You need it // to draw the clipped line caps correctly. The correct result // is achieved with raster clipping. //------------------------ ren_img.scale_x(m_scale_x.value()); ren_img.start_x(m_start_x.value()); ren_img.clip_box (50-w2, 50-w2, width()-50+w2, height()-50+w2); ren_line.clip_box(50-w2, 50-w2, width()-50+w2, height()-50+w2); // First, draw polyline without raster clipping just to show the idea //------------------------ draw_polyline(ras_line, ren_line, m_line1.polygon(), m_line1.num_points()); draw_polyline(ras_img, ren_img, m_line1.polygon(), m_line1.num_points()); // Clear the area, almost opaque, but not completely //------------------------ ren_base.blend_bar(0, 0, (int)width(), (int)height(), agg::rgba(1,1,1), 200); // Set the raster clip box and then, draw again. // In reality there shouldn't be two calls above. // It's done only for demonstration //------------------------ ren_base.clip_box((int)50, (int)50, (int)width()-50, (int)height()-50); // This "copy_bar" is also for demonstration only //------------------------ ren_base.copy_bar(0, 0, (int)width(), (int)height(), agg::rgba(1,1,1)); // Finally draw polyline correctly clipped: We use double clipping, // first is vector clipping, with extended clip box, second is raster // clipping with normal clip box. //------------------------ ren_img.scale_x(m_scale_x.value()); ren_img.start_x(m_start_x.value()); draw_polyline(ras_line, ren_line, m_line1.polygon(), m_line1.num_points()); draw_polyline(ras_img, ren_img, m_line1.polygon(), m_line1.num_points()); // Reset clipping and draw the controls and stuff ren_base.reset_clipping(true); m_line1.line_width(1/m_scale.scale()); m_line1.point_radius(5/m_scale.scale()); agg::render_ctrl(ras, sl, ren_base, m_line1); agg::render_ctrl(ras, sl, ren_base, m_scale_x); agg::render_ctrl(ras, sl, ren_base, m_start_x); char buf[256]; agg::gsv_text t; t.size(10.0); agg::conv_stroke<agg::gsv_text> pt(t); pt.width(1.5); pt.line_cap(agg::round_cap); const double* p = m_line1.polygon(); sprintf(buf, "Len=%.2f", agg::calc_distance(p[0], p[1], p[2], p[3]) * m_scale.scale()); t.start_point(10.0, 30.0); t.text(buf); ras.add_path(pt); ren.color(agg::rgba(0,0,0)); agg::render_scanlines(ras, sl, ren); }