00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #include "a2dprec.h"
00013
00014 #ifdef __BORLANDC__
00015 #pragma hdrstop
00016 #endif
00017
00018 #if wxART2D_USE_AGGDRAWER
00019
00020 #if wxART2D_USE_GRAPHICS_CONTEXT
00021
00022 #ifndef WX_PRECOMP
00023 #include "wx/image.h"
00024 #include "wx/window.h"
00025 #include "wx/dc.h"
00026 #include "wx/utils.h"
00027 #include "wx/dialog.h"
00028 #include "wx/app.h"
00029 #include "wx/bitmap.h"
00030 #include "wx/dcmemory.h"
00031 #include "wx/log.h"
00032 #include "wx/icon.h"
00033 #include "wx/dcprint.h"
00034 #include "wx/module.h"
00035 #endif
00036
00037 #include "wx/aggdrawer/graphicagg.h"
00038 #include "wx/artbase/stylebase.h"
00039
00040 #include "wx/dc.h"
00041
00042 #include "wx/graphics.h"
00043 #include "wx/rawbmp.h"
00044
00045 #if wxART2D_USE_FREETYPE
00046 #include <ft2build.h>
00047 #ifdef _MSC_VER
00048
00049
00050 #include <freetype/freetype.h>
00051 #include <freetype/ftoutln.h>
00052 #else // _MSC_VER
00053
00054 #include FT_FREETYPE_H
00055 #include FT_OUTLINE_H
00056 #endif // _MSC_VER
00057 #endif
00058
00059 #include <vector>
00060
00061 using namespace std;
00062
00063
00064
00065
00066
00067 const double RAD2DEG = 180.0 / M_PI;
00068
00069
00070
00071
00072
00073 static inline double dmin(double a, double b)
00074 {
00075 return a < b ? a : b;
00076 }
00077 static inline double dmax(double a, double b)
00078 {
00079 return a > b ? a : b;
00080 }
00081
00082 static inline double DegToRad(double deg)
00083 {
00084 return (deg * M_PI) / 180.0;
00085 }
00086 static inline double RadToDeg(double deg)
00087 {
00088 return (deg * 180.0) / M_PI;
00089 }
00090
00091
00092
00093
00094
00095
00096
00097
00098 #ifndef max
00099 #define max(a,b) (((a) > (b)) ? (a) : (b))
00100 #endif
00101
00102 #ifndef min
00103 #define min(a,b) (((a) < (b)) ? (a) : (b))
00104 #endif
00105
00106
00107
00108
00109
00110 template< class PathT >
00111 void a2dAggContext::_ras_add_stroked_path_xform(PathT &path, const
00112 agg::trans_affine& mtx)
00113 {
00114
00115
00116
00117
00118
00119 if (m_style == a2dSTROKE_SOLID)
00120 {
00121 if ( m_preStroke )
00122 {
00123 typedef agg::conv_stroke< PathT > path_stroke_t;
00124 typedef agg::conv_transform< path_stroke_t > path_stroke_trans_t;
00125
00126 path_stroke_t stroke(path);
00127 path_stroke_trans_t trans_path( stroke, mtx );
00128 stroke.line_join(m_join);
00129 stroke.line_cap(m_cap);
00130 if ( m_activestroke.GetPixelStroke() )
00131 stroke.width( m_strokewidthDev );
00132 else
00133 stroke.width( m_strokewidth );
00134 m_rasterizer.reset();
00135 m_rasterizer.add_path( trans_path );
00136 }
00137 else
00138 {
00139 typedef agg::conv_transform<PathT> trans_t;
00140 typedef agg::conv_stroke< trans_t > path_stroke_t;
00141
00142 trans_t trans_path(path,mtx);
00143 path_stroke_t stroke(trans_path);
00144
00145 stroke.line_join(m_join);
00146 stroke.line_cap(m_cap);
00147 stroke.width( m_strokewidthDev );
00148 m_rasterizer.reset();
00149 m_rasterizer.add_path( stroke );
00150 }
00151 }
00152 else
00153 {
00154 if ( m_preStroke )
00155 {
00156 typedef agg::conv_dash< PathT > path_dash_t;
00157 typedef agg::conv_stroke< path_dash_t > path_dashstroked_t;
00158 typedef agg::conv_transform< path_dashstroked_t > path_transdash_t;
00159
00160 path_dash_t dash_path(path);
00161 path_dashstroked_t stroke(dash_path);
00162 path_transdash_t trans_path( stroke, mtx);
00163
00164 double scale = m_strokewidth;
00165 if (scale < 1.0) scale = 1.0;
00166
00167 switch(m_style)
00168 {
00169 case a2dSTROKE_DOT:
00170 dash_path.add_dash( 0.25*scale, 1.5*scale);
00171 break;
00172 case a2dSTROKE_DOT_DASH:
00173 dash_path.add_dash( 0.25*scale, 1.5*scale);
00174 dash_path.add_dash(2.0*scale, 2.0*scale);
00175 break;
00176 case a2dSTROKE_LONG_DASH:
00177 dash_path.add_dash(2.0*scale, 2.0*scale);
00178 break;
00179 case a2dSTROKE_SHORT_DASH:
00180 dash_path.add_dash( 2.0*scale, 2.0*scale);
00181 break;
00182
00183
00184 }
00185
00186 stroke.line_join(m_join);
00187 stroke.line_cap(m_cap);
00188
00189 if ( m_activestroke.GetPixelStroke() )
00190 stroke.width( m_strokewidthDev );
00191 else
00192 stroke.width( m_strokewidth );
00193 m_rasterizer.reset();
00194 m_rasterizer.add_path(trans_path);
00195 }
00196 else
00197 {
00198 typedef agg::conv_transform<PathT> trans_t;
00199 typedef agg::conv_dash< trans_t > path_transdash_t;
00200 typedef agg::conv_stroke< path_transdash_t > path_dashstroked_t;
00201
00202 trans_t trans_path(path, mtx);
00203 path_transdash_t dash_path(trans_path);
00204 path_dashstroked_t stroke(dash_path);
00205
00206 double scale = m_strokewidthDev;
00207 if (scale < 1.0) scale = 1.0;
00208
00209 switch(m_style)
00210 {
00211 case a2dSTROKE_DOT:
00212 dash_path.add_dash( 0.25*scale, 1.5*scale);
00213 break;
00214 case a2dSTROKE_DOT_DASH:
00215 dash_path.add_dash( 0.25*scale, 1.5*scale);
00216 dash_path.add_dash(2.0*scale, 2.0*scale);
00217 break;
00218 case a2dSTROKE_LONG_DASH:
00219 dash_path.add_dash(2.0*scale, 2.0*scale);
00220 break;
00221 case a2dSTROKE_SHORT_DASH:
00222 dash_path.add_dash( 2.0*scale, 2.0*scale);
00223 break;
00224
00225
00226 }
00227
00228 stroke.line_join(m_join);
00229 stroke.line_cap(m_cap);
00230
00231 stroke.width( m_strokewidthDev );
00232 m_rasterizer.reset();
00233 m_rasterizer.add_path(stroke);
00234 }
00235
00236 }
00237 }
00238
00239
00240 void a2dAggContext::_stipple_render_scanlines( agg::rasterizer_scanline_aa<>& ras,
00241 agg::scanline_u8& sl,
00242 RendererBaseA &renb,
00243 agg::rendering_buffer pat,
00244 double alpha)
00245 {
00246 unsigned offset_x = 0;
00247 unsigned offset_y = 0;
00248
00249
00250
00251 typedef agg::wrap_mode_repeat wrap_x_type;
00252 typedef agg::wrap_mode_repeat wrap_y_type;
00253
00254 typedef agg::image_accessor_wrap<PixFormat, wrap_x_type, wrap_y_type> img_source_type;
00255 typedef agg::span_pattern_a2d<img_source_type> span_gen_type;
00256 typedef agg::span_allocator<color_type> span_alloc_type;
00257
00258 typedef agg::renderer_scanline_aa<RendererBaseA, span_alloc_type, span_gen_type> renderer_type;
00259
00260 PixFormat img_pixf(pat);
00261 img_source_type img_src(img_pixf);
00262 span_gen_type sg(img_src, offset_x, offset_y);
00263
00264 sg.alpha(span_gen_type::value_type(alpha));
00265
00266 span_alloc_type sa;
00267 renderer_type rp(renb, sa, sg);
00268
00269 agg::render_scanlines(ras, sl, rp);
00270 }
00271
00272 a2dAggContext::a2dAggContext( wxGraphicsRenderer* renderer, const wxImage& drawable )
00273 :
00274 m_rendering_buffer(),
00275 m_pixFormat(m_rendering_buffer),
00276 m_pixFormatComp(m_rendering_buffer),
00277 m_renBase(m_pixFormat),
00278 m_renBaseComp(m_pixFormatComp),
00279 m_renderer(m_renBase),
00280 m_renSolidComp(m_renBaseComp),
00281 m_rasterizer(),
00282 m_fillGradient(),
00283 m_lineGradient(),
00284 m_fillGradientMatrix(),
00285 m_lineGradientMatrix(),
00286 m_fillGradientD1(0.0),
00287 m_lineGradientD1(0.0),
00288 m_fillGradientD2(100.0),
00289 m_lineGradientD2(100.0),
00290 m_fillGradientInterpolator(m_fillGradientMatrix),
00291 m_lineGradientInterpolator(m_lineGradientMatrix),
00292 m_linearGradientFunction(),
00293 m_radialGradientFunction(),
00294 a2dContext(renderer, drawable.GetWidth(), drawable.GetHeight() )
00295 {
00296 m_buffer = new a2dImageRGBA( m_width, m_height );
00297 m_pdata = m_buffer->GetData();
00298 m_rendering_buffer.attach(m_pdata, m_width, m_height, m_width*4);
00299 ResetClip();
00300 m_preStroke = true;
00301 }
00302
00303 a2dAggContext::a2dAggContext( wxGraphicsRenderer* renderer, a2dImageRGBA* drawable )
00304 :
00305 m_rendering_buffer(),
00306 m_pixFormat(m_rendering_buffer),
00307 m_pixFormatComp(m_rendering_buffer),
00308 m_renBase(m_pixFormat),
00309 m_renBaseComp(m_pixFormatComp),
00310 m_renderer(m_renBase),
00311 m_renSolidComp(m_renBaseComp),
00312 m_rasterizer(),
00313 m_fillGradient(),
00314 m_lineGradient(),
00315 m_fillGradientMatrix(),
00316 m_lineGradientMatrix(),
00317 m_fillGradientD1(0.0),
00318 m_lineGradientD1(0.0),
00319 m_fillGradientD2(100.0),
00320 m_lineGradientD2(100.0),
00321 m_fillGradientInterpolator(m_fillGradientMatrix),
00322 m_lineGradientInterpolator(m_lineGradientMatrix),
00323 m_linearGradientFunction(),
00324 m_radialGradientFunction(),
00325 a2dContext(renderer, drawable->GetWidth(), drawable->GetHeight() )
00326 {
00327 m_buffer = drawable;
00328 m_pdata = m_buffer->GetData();
00329 m_rendering_buffer.attach(m_pdata, m_width, m_height, m_width*4);
00330 ResetClip();
00331 m_preStroke = true;
00332 }
00333
00334 a2dAggContext::~a2dAggContext()
00335 {
00336 }
00337
00338 void a2dAggContext::Clip( const wxRegion& region )
00339 {
00340
00341 wxGraphicsPath path = GetRenderer()->CreatePath();
00342 wxRegionIterator ri(region);
00343 while (ri)
00344 {
00345 path.AddRectangle(ri.GetX(), ri.GetY(), ri.GetW(), ri.GetH());
00346 ri++;
00347 }
00348 }
00349
00350 void a2dAggContext::Clip( wxDouble x, wxDouble y, wxDouble w, wxDouble h )
00351 {
00352
00353
00354 wxPoint trpoints[4];
00355 double dx,dy;
00356
00357 m_usertodevice.TransformPoint( x, y, dx, dy );
00358 trpoints[0] = wxPoint( dx, dy );
00359 m_usertodevice.TransformPoint( x, y + h, dx, dy );
00360 trpoints[1] = wxPoint( dx, dy );
00361 m_usertodevice.TransformPoint( x + w, y + h, dx, dy );
00362 trpoints[2] = wxPoint( dx, dy);
00363 m_usertodevice.TransformPoint( x + w, y, dx, dy );
00364 trpoints[3] = wxPoint( dx, dy );
00365
00366 double xmin = trpoints[0].x;
00367 double ymin = trpoints[0].y;
00368 double xmax = trpoints[0].x;
00369 double ymax = trpoints[0].y;
00370 for ( int i = 1; i < 4; i ++ )
00371 {
00372 xmin = wxMin( xmin, trpoints[i].x );
00373 xmax = wxMax( xmax, trpoints[i].x );
00374 ymin = wxMin( ymin, trpoints[i].y );
00375 ymax = wxMax( ymax, trpoints[i].y );
00376 }
00377 wxRect cliprect = wxRect( xmin, ymin, xmax-xmin, ymax-ymin );
00378 m_clipboxdev = cliprect;
00379
00380 m_renBase.clip_box( xmin, ymin, xmax, ymax );
00381 m_renBaseComp.clip_box( xmin, ymin, xmax, ymax );
00382 m_rasterizer.clip_box( 0, 0, m_width, m_height );
00383
00384
00385 }
00386
00387 void a2dAggContext::ResetClip()
00388 {
00389 m_clipboxdev = wxRect( 0, 0, m_width, m_height );
00390 m_renBase.clip_box( 0, 0, m_width, m_height );
00391 m_renBaseComp.clip_box( 0, 0, m_width, m_height );
00392 m_rasterizer.clip_box( 0, 0, m_width, m_height );
00393 }
00394
00395 void a2dAggContext::Render( bool fillColor )
00396 {
00397 if ( fillColor )
00398 {
00399 agg::rgba8 colorfill( m_colour1redFill, m_colour1greenFill, m_colour1blueFill, m_FillOpacityCol1 );
00400 m_renderer.color( colorfill );
00401 m_renSolidComp.color( colorfill );
00402 }
00403 else
00404 {
00405 agg::rgba8 colorstroke( m_colour1redStroke, m_colour1greenStroke, m_colour1blueStroke, m_StrokeOpacityCol1 );
00406 m_renderer.color( colorstroke );
00407 m_renSolidComp.color( colorstroke );
00408 }
00409
00410 if(m_blendMode == agg::end_of_comp_op_e)
00411 agg::render_scanlines(m_rasterizer, m_sl, m_renderer);
00412 else
00413 agg::render_scanlines(m_rasterizer, m_sl, m_renSolidComp);
00414 }
00415
00416 void a2dAggContext::RenderGradient( bool radial )
00417 {
00418 if ( !radial )
00419 {
00420 span_allocator_type aggallocator;
00421 LinearGradientSpan span(
00422 m_fillGradientInterpolator,
00423 m_linearGradientFunction,
00424 m_fillGradient,
00425 m_fillGradientD1,
00426 m_fillGradientD2);
00427 RendererLinearGradientA ren( m_renBase, aggallocator, span );
00428 RendererLinearGradientComp renComp( m_renBaseComp, aggallocator, span );
00429
00430 if(m_blendMode == agg::end_of_comp_op_e)
00431 agg::render_scanlines(m_rasterizer, m_sl, ren );
00432 else
00433 agg::render_scanlines(m_rasterizer, m_sl, renComp );
00434 }
00435 else
00436 {
00437 span_allocator_type aggallocator;
00438 RadialGradientSpan span(
00439 m_fillGradientInterpolator,
00440 m_radialGradientFunction,
00441 m_fillGradient,
00442 m_fillGradientD1,
00443 m_fillGradientD2);
00444 RendererRadialGradientA ren( m_renBase, aggallocator, span );
00445 RendererRadialGradientComp renComp( m_renBaseComp, aggallocator, span );
00446
00447 if(m_blendMode == agg::end_of_comp_op_e)
00448 agg::render_scanlines(m_rasterizer, m_sl, ren );
00449 else
00450 agg::render_scanlines(m_rasterizer, m_sl, renComp );
00451
00452 }
00453 }
00454
00455 void a2dAggContext::RenderBitmapFill()
00456 {
00457 unsigned offset_x = 0;
00458 unsigned offset_y = 0;
00459
00460
00461
00462 typedef agg::wrap_mode_repeat wrap_x_type;
00463 typedef agg::wrap_mode_repeat wrap_y_type;
00464
00465 typedef agg::image_accessor_wrap<PixFormat, wrap_x_type, wrap_y_type> img_source_type;
00466 typedef agg::span_pattern_a2d<img_source_type> span_gen_type;
00467 typedef agg::span_allocator<color_type> span_alloc_type;
00468
00469 typedef agg::renderer_scanline_aa<RendererBaseA, span_alloc_type, span_gen_type> renderer_type;
00470
00471 PixFormat img_pixf( m_pattern_rbuf );
00472 img_source_type img_src(img_pixf);
00473 span_gen_type sg(img_src, offset_x, offset_y);
00474
00475 sg.alpha(span_gen_type::value_type( m_FillOpacityCol1 ));
00476
00477 span_alloc_type sa;
00478 renderer_type rp( m_renBase, sa, sg);
00479
00480 agg::render_scanlines(m_rasterizer, m_sl, rp);
00481 }
00482
00483 void a2dAggContext::Rotate( wxDouble angle )
00484 {
00485 m_usertodevice.Rotate( angle ) ;
00486 }
00487
00488 void a2dAggContext::Translate( wxDouble dx , wxDouble dy )
00489 {
00490 m_usertodevice.Translate( dx, dy) ;
00491 }
00492
00493 void a2dAggContext::Scale( wxDouble xScale , wxDouble yScale )
00494 {
00495 m_usertodevice.Scale( xScale, yScale, 0, 0 ) ;
00496 }
00497
00498
00499 void a2dAggContext::ConcatTransform( const wxGraphicsMatrix& matrix )
00500 {
00501 a2dAffineMatrix* m = (a2dAffineMatrix*) matrix.GetNativeMatrix();
00502 m_usertodevice *= *m;
00503 }
00504
00505
00506 void a2dAggContext::SetTransform( const wxGraphicsMatrix& matrix )
00507 {
00508 a2dAffineMatrix* m = (a2dAffineMatrix*) matrix.GetNativeMatrix();
00509 m_usertodevice = *m;
00510 }
00511
00512
00513 wxGraphicsMatrix a2dAggContext::GetTransform() const
00514 {
00515 wxGraphicsMatrix matrix = CreateMatrix();
00516 a2dAffineMatrix* m = (a2dAffineMatrix*) matrix.GetNativeMatrix();
00517 *m = m_usertodevice;
00518 return matrix;
00519 }
00520
00521 #if wxCHECK_VERSION(2,9,0)
00522 bool a2dAggContext::SetCompositionMode(wxCompositionMode op)
00523 {
00524 if ( m_composition == op )
00525 return true;
00526
00527 m_composition = op;
00528
00529 switch (op)
00530 {
00531 case wxCOMPOSITION_CLEAR:
00532 m_blendMode = agg::comp_op_clear;
00533 break;
00534 case wxCOMPOSITION_SOURCE:
00535 m_blendMode = agg::comp_op_src;
00536 break;
00537 case wxCOMPOSITION_OVER:
00538 m_blendMode = agg::comp_op_src_over;
00539 break;
00540 case wxCOMPOSITION_IN:
00541 m_blendMode = agg::comp_op_src_in;
00542 break;
00543 case wxCOMPOSITION_OUT:
00544 m_blendMode = agg::comp_op_src_out;
00545 break;
00546 case wxCOMPOSITION_ATOP:
00547 m_blendMode = agg::comp_op_src_atop;
00548 break;
00549 case wxCOMPOSITION_DEST:
00550 m_blendMode = agg::comp_op_dst;
00551 break;
00552 case wxCOMPOSITION_DEST_OVER:
00553 m_blendMode = agg::comp_op_dst_over;
00554 break;
00555 case wxCOMPOSITION_DEST_IN:
00556 m_blendMode = agg::comp_op_dst_in;
00557 break;
00558 case wxCOMPOSITION_DEST_OUT:
00559 m_blendMode = agg::comp_op_dst_out;
00560 break;
00561 case wxCOMPOSITION_DEST_ATOP:
00562 m_blendMode = agg::comp_op_dst_atop;
00563 break;
00564 case wxCOMPOSITION_XOR:
00565 m_blendMode = agg::comp_op_xor;
00566 break;
00567 case wxCOMPOSITION_ADD:
00568 m_blendMode = agg::comp_op_plus;
00569 break;
00570 default:
00571 m_blendMode = agg::end_of_comp_op_e;
00572 }
00573 return true;
00574 }
00575 #endif
00576
00577 void a2dAggContext::SetDrawStyle( a2dDrawStyle drawstyle )
00578 {
00579 m_drawstyle = drawstyle;
00580
00581 switch( drawstyle )
00582 {
00583 case a2dWIREFRAME_INVERT:
00584 m_activestroke = *a2dBLACK_STROKE;
00585 m_activefill = *a2dTRANSPARENT_FILL;
00586 m_blendMode = agg::comp_op_invert;
00587 break;
00588
00589 case a2dWIREFRAME:
00590 m_activestroke = *a2dBLACK_STROKE;
00591 m_activefill = *a2dTRANSPARENT_FILL;
00592 m_blendMode = agg::end_of_comp_op_e;
00593 break;
00594
00595 case a2dWIREFRAME_ZERO_WIDTH:
00596 m_activestroke = *a2dBLACK_STROKE;
00597 m_activefill = *a2dTRANSPARENT_FILL;
00598 m_blendMode = agg::end_of_comp_op_e;
00599 break;
00600
00601 case a2dWIREFRAME_INVERT_ZERO_WIDTH:
00602 m_activestroke = *a2dBLACK_STROKE;
00603 m_activefill = *a2dTRANSPARENT_FILL;
00604 m_blendMode = agg::comp_op_invert;
00605 break;
00606
00607 case a2dFILLED:
00608 m_blendMode = agg::end_of_comp_op_e;
00609 break;
00610
00611 default:
00612 wxASSERT( 0 );
00613 }
00614 m_pixFormatComp.comp_op( m_blendMode );
00615 }
00616
00617 bool a2dAggContext::SetLogicalFunction( int function )
00618 {
00619 switch( function )
00620 {
00621 case wxINVERT:
00622 m_activestroke = *a2dBLACK_STROKE;
00623 m_activefill = *a2dTRANSPARENT_FILL;
00624 m_blendMode = agg::comp_op_invert;
00625 m_drawstyle = a2dWIREFRAME_INVERT;
00626 break;
00627 default:
00628 m_blendMode = agg::end_of_comp_op_e;
00629 m_drawstyle = a2dFILLED;
00630 }
00631
00632 m_pixFormatComp.comp_op( m_blendMode );
00633 return true;
00634 }
00635
00636 void a2dAggContext::DoSetActiveStroke()
00637 {
00638 if ( m_drawstyle == a2dWIREFRAME_INVERT_ZERO_WIDTH )
00639 {
00640 m_strokewidth = 0;
00641 m_strokewidthDev = 1;
00642 }
00643 else if ( m_activestroke.GetType() == a2dSTROKE_ONE_COLOUR )
00644 {
00645 switch( m_activestroke.GetStyle() )
00646 {
00647 case a2dSTROKE_SOLID:
00648 case a2dSTROKE_TRANSPARENT:
00649 case a2dSTROKE_DOT:
00650 case a2dSTROKE_DOT_DASH:
00651 case a2dSTROKE_LONG_DASH:
00652 case a2dSTROKE_SHORT_DASH:
00653 m_style = m_activestroke.GetStyle();
00654 break;
00655
00656
00657
00658
00659
00660
00661
00662
00663
00664
00665
00666
00667
00668
00669
00670
00671
00672
00673
00674
00675
00676 default: m_style=a2dSTROKE_SOLID;
00677 }
00678
00679 m_strokewidth = m_activestroke.GetWidth();
00680 if ( m_drawstyle == a2dWIREFRAME_ZERO_WIDTH )
00681 {
00682 a2dAffineMatrix invert = m_usertodevice;
00683 invert.Invert();
00684 m_strokewidthDev = 1;
00685 m_strokewidth = invert.TransformDistance( m_strokewidthDev );
00686 m_join = agg::round_join;
00687 m_cap = agg::round_cap;
00688 }
00689 else
00690 {
00691 switch ( m_activestroke.GetJoin() )
00692 {
00693 case wxJOIN_MITER: m_join = agg::miter_join;
00694 break;
00695 case wxJOIN_ROUND: m_join = agg::round_join;
00696 break;
00697 case wxJOIN_BEVEL: m_join = agg::bevel_join;
00698 break;
00699 default: m_join = agg::round_join;
00700 }
00701 switch ( m_activestroke.GetCap() )
00702 {
00703 case wxCAP_BUTT: m_cap = agg::butt_cap;
00704 break;
00705 case wxCAP_ROUND: m_cap = agg::round_cap;
00706 break;
00707 case wxCAP_PROJECTING: m_cap = agg::square_cap;
00708 break;
00709 default: m_cap = agg::round_cap;
00710 }
00711
00712 if ( m_activestroke.GetPixelStroke() )
00713 {
00714 a2dAffineMatrix invert = m_usertodevice;
00715 invert.Invert();
00716 m_strokewidthDev = m_activestroke.GetWidth();
00717 m_strokewidthDev = !m_strokewidthDev ? 1: m_strokewidthDev;
00718 m_strokewidth = invert.TransformDistance( m_strokewidthDev );
00719 }
00720 else
00721 {
00722 m_strokewidth = m_activestroke.GetWidth();
00723 m_strokewidthDev = m_usertodevice.TransformDistance( m_strokewidth );
00724 if ( !m_strokewidthDev )
00725 {
00726 m_strokewidthDev = 1;
00727 a2dAffineMatrix invert = m_usertodevice;
00728 invert.Invert();
00729 m_strokewidth = invert.TransformDistance( m_strokewidthDev );
00730 }
00731 }
00732 }
00733 }
00734 }
00735
00736
00737 void a2dAggContext::DoSetActiveFill()
00738 {
00739 if ( m_activefill.GetType() == a2dFILL_ONE_COLOUR )
00740 {
00741 switch( m_activefill.GetStyle() )
00742 {
00743 case a2dFILL_TRANSPARENT:
00744 break;
00745 case a2dFILL_SOLID:
00746 break;
00747 case a2dFILL_BDIAGONAL_HATCH:
00748 m_pattern = wxImage( BDIAGONAL_HATCH_XPM );
00749 break;
00750 case a2dFILL_CROSSDIAG_HATCH:
00751 m_pattern = wxImage( CROSSDIAG_HATCH_XPM );
00752 break;
00753 case a2dFILL_FDIAGONAL_HATCH:
00754 m_pattern = wxImage( FDIAGONAL_HATCH_XPM );
00755 break;
00756 case a2dFILL_CROSS_HATCH:
00757 m_pattern = wxImage( CROSS_HATCH_XPM );
00758 break;
00759 case a2dFILL_HORIZONTAL_HATCH:
00760 m_pattern = wxImage( HORIZONTAL_HATCH_XPM );
00761 break;
00762 case a2dFILL_VERTICAL_HATCH:
00763 m_pattern = wxImage( VERTICAL_HATCH_XPM );
00764 break;
00765 default: ;
00766 }
00767 if ( m_activefill.GetStyle() >= a2dFIRST_HATCH && m_activefill.GetStyle() <= a2dLAST_HATCH )
00768 {
00769 m_pattern.Replace( 0, 0, 0,
00770 m_colour1redFill,
00771 m_colour1greenFill,
00772 m_colour1blueFill );
00773
00774 m_pattern_rbuf.attach(m_pattern.GetData(), m_pattern.GetWidth(), m_pattern.GetHeight(), m_pattern.GetWidth()*3);
00775 }
00776 }
00777 else if ( m_activefill.GetType() == a2dFILL_HATCH_TWO_COLOUR )
00778 {
00779 bool nohatch = false;
00780 switch( m_activefill.GetStyle() )
00781 {
00782 case a2dFILL_TWOCOL_BDIAGONAL_HATCH:
00783 m_pattern = wxImage( BDIAGONAL_HATCH_XPM );
00784 break;
00785 case a2dFILL_TWOCOL_CROSSDIAG_HATCH:
00786 m_pattern = wxImage( CROSSDIAG_HATCH_XPM );
00787 break;
00788 case a2dFILL_TWOCOL_FDIAGONAL_HATCH:
00789 m_pattern = wxImage( FDIAGONAL_HATCH_XPM );
00790 break;
00791 case a2dFILL_TWOCOL_CROSS_HATCH:
00792 m_pattern = wxImage( CROSS_HATCH_XPM );
00793 break;
00794 case a2dFILL_TWOCOL_HORIZONTAL_HATCH:
00795 m_pattern = wxImage( HORIZONTAL_HATCH_XPM );
00796 break;
00797 case a2dFILL_TWOCOL_VERTICAL_HATCH:
00798 m_pattern = wxImage( VERTICAL_HATCH_XPM );
00799 break;
00800 default:
00801 nohatch = true;
00802 break;
00803 }
00804 m_pattern.Replace( 255, 255, 255,
00805 m_colour2redFill,
00806 m_colour2greenFill,
00807 m_colour2blueFill );
00808
00809 m_pattern.Replace( 0, 0, 0,
00810 m_colour1redFill,
00811 m_colour1greenFill,
00812 m_colour1blueFill );
00813
00814 m_pattern_rbuf.attach(m_pattern.GetData(), m_pattern.GetWidth(), m_pattern.GetHeight(), m_pattern.GetWidth()*3);
00815 }
00816 else if ( m_activefill.GetType() == a2dFILL_BITMAP )
00817 {
00818 wxBrush dcbrush;
00819
00820 switch( m_activefill.GetStyle() )
00821 {
00822 case a2dFILL_STIPPLE:
00823 case a2dFILL_STIPPLE_MASK_OPAQUE_TRANSPARENT:
00824 case a2dFILL_STIPPLE_MASK_OPAQUE:
00825 {
00826 static const int MASK_RED = 1;
00827 static const int MASK_GREEN = 2;
00828 static const int MASK_BLUE = 3;
00829
00830 m_pattern = m_activefill.GetStipple().ConvertToImage();
00831 m_pattern.Replace( MASK_RED, MASK_GREEN, MASK_BLUE,
00832 m_colour1redFill,
00833 m_colour1greenFill,
00834 m_colour1blueFill );
00835
00836 m_pattern_rbuf.attach(m_pattern.GetData(), m_pattern.GetWidth(), m_pattern.GetHeight(), m_pattern.GetWidth()*3);
00837
00838
00839
00840
00841
00842
00843 }
00844 break;
00845 default:
00846 break;
00847 }
00848 }
00849 else if ( m_activefill.GetType() == a2dFILL_GRADIENT_FILL_LINEAR )
00850 {
00851 double profile=1.0;
00852 int i;
00853 double x1 = m_activefill.GetStart().m_x;
00854 double y1 = m_activefill.GetStart().m_y;
00855 double x2 = m_activefill.GetStop().m_x;
00856 double y2 = m_activefill.GetStop().m_y;
00857 color_type c1( m_colour1redFill, m_colour1greenFill, m_colour1blueFill, m_FillOpacityCol1 );
00858 color_type c2( m_colour2redFill, m_colour2greenFill, m_colour2blueFill, m_FillOpacityCol2 );
00859 int startGradient = 128 - int(profile * 128.0);
00860 int endGradient = 128 + int(profile * 128.0);
00861 if (endGradient <= startGradient) endGradient = startGradient + 1;
00862 double k = 1.0 / double(endGradient - startGradient);
00863 for (i = 0; i < startGradient; i++)
00864 {
00865 m_fillGradient[i] = c1;
00866 }
00867 for (; i < endGradient; i++)
00868 {
00869 m_fillGradient[i] = c1.gradient(c2, double(i - startGradient) * k);
00870 }
00871 for (; i < 256; i++)
00872 {
00873 m_fillGradient[i] = c2;
00874 }
00875 double angle = atan2(y2-y1, x2-x1);
00876 m_fillGradientMatrix.reset();
00877 m_fillGradientMatrix *= agg::trans_affine_rotation(angle);
00878 m_fillGradientMatrix *= agg::trans_affine_translation(x1, y1);
00879 m_fillGradientMatrix *= _get_agg_user_to_device_transform();
00880 m_fillGradientMatrix.invert();
00881 m_fillGradientD1 = 0;
00882 m_fillGradientD2 = sqrt((x2-x1) * (x2-x1) + (y2-y1) * (y2-y1));
00883 }
00884 else if ( m_activefill.GetType() == a2dFILL_GRADIENT_FILL_RADIAL )
00885 {
00886 double profile=1.0;
00887 int i;
00888 double xf = m_activefill.GetFocal().m_x;
00889 double yf = m_activefill.GetFocal().m_y;
00890 double x = m_activefill.GetCenter().m_x;
00891 double y = m_activefill.GetCenter().m_y;
00892 double r = m_activefill.GetRadius();
00893
00894 color_type c1( m_colour1redFill, m_colour1greenFill, m_colour1blueFill, m_FillOpacityCol1 );
00895 color_type c2( m_colour2redFill, m_colour2greenFill, m_colour2blueFill, m_FillOpacityCol2 );
00896 int startGradient = 128 - int(profile * 127.0);
00897 int endGradient = 128 + int(profile * 127.0);
00898 if (endGradient <= startGradient) endGradient = startGradient + 1;
00899 double k = 1.0 / double(endGradient - startGradient);
00900 for (i = 0; i < startGradient; i++)
00901 {
00902 m_fillGradient[i] = c1;
00903 }
00904 for (; i < endGradient; i++)
00905 {
00906 m_fillGradient[i] = c1.gradient(c2, double(i - startGradient) * k);
00907 }
00908 for (; i < 256; i++)
00909 {
00910 m_fillGradient[i] = c2;
00911 }
00912 m_fillGradientD2 = m_usertodevice.TransformDistance( r );
00913 m_usertodevice.TransformPoint( x, y, x, y );
00914 m_fillGradientMatrix.reset();
00915 m_fillGradientMatrix *= agg::trans_affine_translation(x, y);
00916 m_fillGradientMatrix.invert();
00917 m_fillGradientD1 = 0;
00918 }
00919 }
00920
00921 #if wxCHECK_VERSION(2,9,0)
00922 void a2dAggContext::DrawBitmap(const wxGraphicsBitmap &bmp, wxDouble x, wxDouble y, wxDouble w, wxDouble h )
00923 #else
00924 void a2dAggContext::DrawGraphicsBitmap(const wxGraphicsBitmap &bmp, wxDouble x, wxDouble y, wxDouble w, wxDouble h )
00925 #endif
00926 {
00927 a2dBitmapData* data = static_cast<a2dBitmapData*>(bmp.GetRefData());
00928 wxImage image = data->GetImage();
00929
00930 int imagew = image.GetWidth();
00931 int imageh = image.GetHeight();
00932
00933 agg::trans_affine mtxi;
00934 mtxi *= agg::trans_affine_scaling( w/imagew, h/imageh );
00935 mtxi *= agg::trans_affine_translation( x-w/2, y-h/2 );
00936
00937
00938
00939
00940 agg::trans_affine mtx = _get_agg_user_to_device_transform();
00941 mtxi *= mtx;
00942 mtxi.invert();
00943
00944 typedef agg::span_allocator<agg::rgba8> span_alloc_type;
00945
00946 span_alloc_type sa;
00947 typedef agg::image_accessor_clip<PixFormat> img_source_type;
00948 typedef agg::span_interpolator_linear<> interpolator_type;
00949 interpolator_type interpolator(mtxi);
00950
00951 typedef agg::span_image_filter_rgb_bilinear<img_source_type, interpolator_type> span_gen_type;
00952
00953
00954 typedef agg::span_converter<span_gen_type, span_conv_const_alpha_rgba8> span_conv;
00955
00956 typedef agg::renderer_scanline_aa<RendererBaseA, span_alloc_type, span_conv> renderer_type_alpha;
00957
00958 typedef agg::renderer_scanline_bin<RendererBaseA, span_alloc_type, span_gen_type> renderer_type_normal;
00959
00960 agg::rendering_buffer image_buffer;
00961 image_buffer.attach( image.GetData(), imagew, imageh, ( m_yaxis ) ? -imagew*3: imagew*3 );
00962 PixFormat img_pixf(image_buffer);
00963 img_source_type img_src(img_pixf, agg::rgba(1,1,1,0));
00964
00965 span_gen_type sg(img_src, interpolator);
00966
00967
00968
00969
00970
00971
00972
00973
00974
00975
00976
00977
00978
00979
00980
00981
00982
00983 agg::rounded_rect er(x-w/2, y-h/2 ,x+w/2, y+h/2, 0);
00984 er.normalize_radius();
00985 agg::conv_transform<agg::rounded_rect> tr(er, mtx);
00986 m_rasterizer.reset();
00987 m_rasterizer.add_path(tr);
00988
00989
00990 if ( m_OpacityFactor != 255 )
00991 {
00992 span_conv_const_alpha_rgba8 color_alpha( m_OpacityFactor );
00993 span_conv sc(sg, color_alpha);
00994 renderer_type_alpha ri(m_renBase, sa, sc);
00995
00996 agg::render_scanlines(m_rasterizer, m_sl, ri);
00997 }
00998 else
00999 {
01000 renderer_type_normal ri(m_renBase, sa, sg);
01001 agg::render_scanlines(m_rasterizer, m_sl, ri);
01002 }
01003
01004
01005 }
01006
01007 void a2dAggContext::GetTextExtent( const wxString &str, wxDouble *width, wxDouble *height,
01008 wxDouble *descent, wxDouble *externalLeading ) const
01009 {
01010 }
01011
01012 void a2dAggContext::GetPartialTextExtents(const wxString& text, wxArrayDouble& widths) const
01013 {
01014 }
01015
01016 void a2dAggContext::DrawCharDc( wxChar c )
01017 {
01018 #if wxART2D_USE_FREETYPE && defined(__USE_WINAPI__)
01019 if ( m_a2dfont.GetType() == a2dFONT_WXDC && m_a2dfont.GetFreetypeFont().Ok() )
01020 {
01021 a2dFont oldfont = m_a2dfont;
01022 m_a2dfont = m_a2dfont.GetFreetypeFont();
01023 DrawCharFreetype( c );
01024 m_a2dfont = oldfont;
01025 }
01026 else
01027 a2dContext::DrawCharDc( c );
01028 #else // wxART2D_USE_FREETYPE && defined(__USE_WINAPI__)
01029 a2dContext::DrawCharDc( c );
01030 #endif // wxART2D_USE_FREETYPE && defined(__USE_WINAPI__)
01031
01032 }
01033
01034 void a2dAggContext::DrawTextDc( const wxString& text, double x, double y )
01035 {
01036
01037 unsigned int fontsize;
01038 double dx = m_usertodevice.GetValue( 1, 0 );
01039 double dy = m_usertodevice.GetValue( 1, 1 );
01040 fontsize = ( unsigned int ) fabs( m_a2dfont.GetSize() * sqrt( dx * dx + dy * dy ) );
01041 if ( fontsize < 1 )
01042 fontsize = 1;
01043 m_a2dfont.GetFont().SetPointSize( fontsize );
01044
01045
01046
01047
01048
01049 DrawTextGeneric( text, x, y, ( void ( a2dContext::* )( wxChar ) ) & a2dAggContext::DrawCharDc );
01050 }
01051
01052 void a2dAggContext::DrawCharStroke( wxChar c )
01053 {
01054 agg::path_storage path;
01055 double size = m_a2dfont.GetSize();
01056 a2dVertexList** ptr = m_a2dfont.GetGlyphStroke(c);
01057 if (ptr)
01058 {
01059 while (*ptr)
01060 {
01061 a2dVertexList::iterator iter = (*ptr)->begin();
01062 if ( (*ptr)->size() )
01063 {
01064 a2dPoint2D point = (*iter)->GetPoint();
01065 path.move_to( point.m_x * size, point.m_y * size );
01066 iter++;
01067 }
01068 while ( iter != (*ptr)->end() )
01069 {
01070 a2dPoint2D point = (*iter)->GetPoint();
01071 path.line_to( point.m_x * size, point.m_y * size );
01072 iter++;
01073 }
01074 ptr++;
01075 }
01076 }
01077
01078
01079 agg::trans_affine mtx = _get_agg_user_to_device_transform();
01080 agg::conv_transform< agg::path_storage > tr( path, mtx );
01081 agg::conv_stroke< agg::conv_transform< agg::path_storage > > stroke( tr );
01082
01083 agg::rgba8 color( m_colour1redStroke, m_colour1greenStroke, m_colour1blueStroke, m_StrokeOpacityCol1 );
01084 stroke.line_join( m_join );
01085 stroke.line_cap( m_cap );
01086 stroke.width( m_a2dfont.GetStrokeWidth() );
01087 m_rasterizer.reset();
01088 m_rasterizer.add_path( stroke );
01089 m_renderer.color( color );
01090 m_renSolidComp.color( color );
01091 if(m_blendMode == agg::end_of_comp_op_e)
01092 agg::render_scanlines(m_rasterizer, m_sl, m_renderer);
01093 else
01094 agg::render_scanlines(m_rasterizer, m_sl, m_renSolidComp);
01095 }
01096
01097 #if wxART2D_USE_FREETYPE
01098 extern FT_Library g_freetypeLibrary;
01099
01100
01101 typedef struct
01102 {
01103 wxColour colour;
01104 int xmin, ymax;
01105 int stride;
01106 unsigned char* buf;
01107 }
01108 a2dSpanData;
01109
01110
01111 static void a2dSpanFuncGray( int y, int count, FT_Span* spans, a2dSpanData* user )
01112 {
01113 unsigned int alpha, invalpha, len;
01114
01115 unsigned int r, g, b, rpm, gpm, bpm;
01116 r = user->colour.Red();
01117 g = user->colour.Green();
01118 b = user->colour.Blue();
01119
01120 unsigned char *buf, *buf2;
01121 buf = user->buf + ( user->ymax - y ) * user->stride - user->xmin * 3;
01122 do
01123 {
01124 buf2 = buf + spans->x * 3;
01125 len = spans->len;
01126 alpha = spans->coverage;
01127 if ( alpha == 255 )
01128 {
01129 do
01130 {
01131
01132
01133 #ifdef __WXGTK__
01134 buf2[0] = r;
01135 buf2[1] = g;
01136 buf2[2] = b;
01137 #else
01138 buf2[0] = b;
01139 buf2[1] = g;
01140 buf2[2] = r;
01141 #endif
01142 buf2 += 3;
01143 }
01144 while( --len );
01145 }
01146 else
01147 {
01148 rpm = r * alpha;
01149 gpm = g * alpha;
01150 bpm = b * alpha;
01151 invalpha = 255 - alpha;
01152 do
01153 {
01154
01155
01156 #ifdef __WXGTK__
01157 buf2[0] = ( buf2[0] * invalpha + rpm ) / 255;
01158 buf2[1] = ( buf2[1] * invalpha + gpm ) / 255;
01159 buf2[2] = ( buf2[2] * invalpha + bpm ) / 255;
01160 #else
01161 buf2[0] = ( buf2[0] * invalpha + bpm ) / 255;
01162 buf2[1] = ( buf2[1] * invalpha + gpm ) / 255;
01163 buf2[2] = ( buf2[2] * invalpha + rpm ) / 255;
01164 #endif
01165 buf2 += 3;
01166 }
01167 while( --len );
01168 }
01169 spans++;
01170 }
01171 while ( --count );
01172 }
01173 #endif
01174
01175
01176 void a2dAggContext::DrawCharFreetype( wxChar c )
01177 {
01178 double x, y;
01179 x = y = 0.0;
01180
01181 #if wxART2D_USE_FREETYPE
01182 y += m_a2dfont.GetDescent();
01183
01184 agg::path_storage path;
01185 double scale = m_a2dfont.GetSize() / (64 * FTNORMFONT);
01186
01187 FT_Glyph glyph = m_a2dfont.GetGlyphFreetype( c )->m_glyph;
01188 if (glyph->format != FT_GLYPH_FORMAT_OUTLINE)
01189 return;
01190 FT_Outline& outline = ((FT_OutlineGlyph) glyph)->outline;
01191
01192 FT_Vector v_last;
01193 FT_Vector v_control;
01194 FT_Vector v_start;
01195
01196 FT_Vector* point;
01197 FT_Vector* limit;
01198 char* tags;
01199
01200 int n;
01201 int first;
01202 char tag;
01203
01204 first = 0;
01205
01206 for(n = 0; n < outline.n_contours; n++)
01207 {
01208 int last;
01209
01210 last = outline.contours[n];
01211 limit = outline.points + last;
01212
01213 v_start = outline.points[first];
01214 v_last = outline.points[last];
01215
01216 v_control = v_start;
01217
01218 point = outline.points + first;
01219 tags = outline.tags + first;
01220 tag = FT_CURVE_TAG(tags[0]);
01221
01222
01223 if(tag == FT_CURVE_TAG_CUBIC) return;
01224
01225
01226 if( tag == FT_CURVE_TAG_CONIC)
01227 {
01228
01229 if(FT_CURVE_TAG(outline.tags[last]) == FT_CURVE_TAG_ON)
01230 {
01231
01232 v_start = v_last;
01233 limit--;
01234 }
01235 else
01236 {
01237
01238
01239
01240 v_start.x = (v_start.x + v_last.x) / 2;
01241 v_start.y = (v_start.y + v_last.y) / 2;
01242
01243 v_last = v_start;
01244 }
01245 point--;
01246 tags--;
01247 }
01248
01249 path.move_to( v_start.x, v_start.y);
01250
01251 while(point < limit)
01252 {
01253 point++;
01254 tags++;
01255
01256 tag = FT_CURVE_TAG(tags[0]);
01257 switch(tag)
01258 {
01259 case FT_CURVE_TAG_ON:
01260 {
01261 path.line_to( point->x, point->y );
01262 continue;
01263 }
01264
01265 case FT_CURVE_TAG_CONIC:
01266 {
01267 v_control.x = point->x;
01268 v_control.y = point->y;
01269
01270 Do_Conic:
01271 if(point < limit)
01272 {
01273 FT_Vector vec;
01274 FT_Vector v_middle;
01275
01276 point++;
01277 tags++;
01278 tag = FT_CURVE_TAG(tags[0]);
01279
01280 vec.x = point->x;
01281 vec.y = point->y;
01282
01283 if(tag == FT_CURVE_TAG_ON)
01284 {
01285 path.curve3( v_control.x, v_control.y, vec.x, vec.y );
01286 continue;
01287 }
01288
01289 if(tag != FT_CURVE_TAG_CONIC) return;
01290
01291 v_middle.x = (v_control.x + vec.x) / 2;
01292 v_middle.y = (v_control.y + vec.y) / 2;
01293
01294 path.curve3( v_control.x, v_control.y, v_middle.x, v_middle.y );
01295
01296 v_control = vec;
01297 goto Do_Conic;
01298 }
01299 path.curve3( v_control.x, v_control.y, v_start.x, v_start.y );
01300 goto Close;
01301 }
01302
01303 default:
01304 {
01305 FT_Vector vec1, vec2;
01306
01307 if(point + 1 > limit || FT_CURVE_TAG(tags[1]) != FT_CURVE_TAG_CUBIC)
01308 {
01309 return;
01310 }
01311
01312 vec1.x = point[0].x;
01313 vec1.y = point[0].y;
01314 vec2.x = point[1].x;
01315 vec2.y = point[1].y;
01316
01317 point += 2;
01318 tags += 2;
01319
01320 if(point <= limit)
01321 {
01322 FT_Vector vec;
01323
01324 vec.x = point->x;
01325 vec.y = point->y;
01326
01327 path.curve4( vec1.x, vec1.y, vec2.x, vec2.y, vec.x, vec.y );
01328 continue;
01329 }
01330
01331 path.curve4( vec1.x, vec1.y, vec2.x, vec2.y, v_start.x, v_start.y );
01332 goto Close;
01333 }
01334 }
01335 }
01336
01337 path.close_polygon();
01338
01339 Close:
01340 first = last + 1;
01341 }
01342
01343
01344 a2dAffineMatrix affine;
01345 affine.Scale( scale );
01346 affine.Translate( x, y );
01347 affine = m_usertodevice * affine;
01348
01349 agg::trans_affine mtx(affine.GetValue(0,0), affine.GetValue(0,1),
01350 affine.GetValue(1,0), affine.GetValue(1,1),
01351 affine.GetValue(2,0), affine.GetValue(2,1) );
01352 agg::conv_transform< agg::path_storage > tr( path, mtx );
01353 agg::conv_curve< agg::conv_transform< agg::path_storage > > stroke( tr );
01354
01355 agg::rgba8 color( m_colour1redStroke, m_colour1greenStroke, m_colour1blueStroke, m_StrokeOpacityCol1 );
01356 m_rasterizer.reset();
01357 m_rasterizer.add_path( stroke );
01358 m_renderer.color( color );
01359 m_renSolidComp.color( color );
01360 if(m_blendMode == agg::end_of_comp_op_e)
01361 agg::render_scanlines(m_rasterizer, m_sl, m_renderer);
01362 else
01363 agg::render_scanlines(m_rasterizer, m_sl, m_renSolidComp);
01364
01365 #else // wxART2D_USE_FREETYPE
01366 a2dContext::DrawCharFreetype( c );
01367 #endif // wxART2D_USE_FREETYPE
01368 }
01369
01370 void a2dAggContext::DrawRoundedRectangle( wxDouble x, wxDouble y, wxDouble width, wxDouble height, wxDouble radius)
01371 {
01372 if ( width == 0 || height == 0 )
01373 return;
01374
01375 if ( m_pen.IsNull() && m_brush.IsNull() )
01376 return;
01377
01378 if ( !IsStrokeOnly() )
01379 {
01380 agg::trans_affine mtx = _get_agg_user_to_device_transform();
01381
01382 if ( fabs(radius) <= 0.00000001 )
01383 {
01384 plain_rect r( x, y, x+width, y+height );
01385 agg::conv_transform<plain_rect> tr(r, mtx);
01386 m_rasterizer.reset();
01387 m_rasterizer.add_path( tr );
01388 }
01389 else
01390 {
01391 agg::rounded_rect r( x, y, x+width, y+height, radius );
01392 r.normalize_radius();
01393 agg::conv_transform<agg::rounded_rect> tr(r, mtx);
01394 m_rasterizer.reset();
01395 m_rasterizer.add_path( tr );
01396 }
01397 if ( m_activefill.GetType() == a2dFILL_GRADIENT_FILL_LINEAR )
01398 {
01399 RenderGradient( false );
01400 }
01401 else if ( m_activefill.GetType() == a2dFILL_GRADIENT_FILL_RADIAL )
01402 {
01403 RenderGradient( true );
01404 }
01405 else if ( m_activefill.GetType() == a2dFILL_BITMAP ||
01406 (m_activefill.GetStyle() >= a2dFIRST_HATCH && m_activefill.GetStyle() <= a2dLAST_HATCH ) ||
01407 (m_activefill.GetStyle() >= a2dFIRST_TWOCOL_HATCH && m_activefill.GetStyle() <= a2dLAST_TWOCOL_HATCH ) )
01408 {
01409 RenderBitmapFill();
01410 }
01411 else
01412 {
01413 Render( true );
01414 }
01415 }
01416
01417 if ( IsStroked() )
01418 {
01419 if ( fabs(radius) <= 0.00000001 )
01420 {
01421 plain_rect r( x, y, x+width, y+height );
01422 agg::trans_affine mtx = _get_agg_user_to_device_transform();
01423 m_rasterizer.reset();
01424 _ras_add_stroked_path_xform( r, mtx );
01425 }
01426 else
01427 {
01428 m_rasterizer.reset();
01429 agg::rounded_rect r( x, y, x+width, y+height, radius );
01430 r.normalize_radius();
01431 agg::trans_affine mtx = _get_agg_user_to_device_transform();
01432 _ras_add_stroked_path_xform( r, mtx );
01433 }
01434 Render(false);
01435 }
01436 }
01437
01438 void a2dAggContext::DrawEllipse( wxDouble x, wxDouble y, wxDouble w, wxDouble h)
01439 {
01440 if ( m_activefill.GetType() == a2dFILL_GRADIENT_FILL_LINEAR || m_activefill.GetType() == a2dFILL_GRADIENT_FILL_RADIAL )
01441 {
01442 a2dContext::DrawEllipse( x, y, w, h );
01443 return;
01444 }
01445
01446 if ( m_pen.IsNull() && m_brush.IsNull() )
01447 return;
01448
01449 double dphi;
01450 unsigned int segments;
01451
01452
01453 double radiusDev = m_usertodevice.TransformDistance( wxMax( w, h ) );
01454 Aberration( m_displayaberration, wxPI*2, radiusDev , dphi, segments );
01455
01456 agg::trans_affine mtx = _get_agg_user_to_device_transform();
01457
01458 agg::rgba8 color( m_colour1redFill, m_colour1greenFill, m_colour1blueFill, m_FillOpacityCol1 );
01459 agg::ellipse ellipse( x + w/2.0, y + h/2.0, w/2.0, h/2.0, segments );
01460
01461 agg::conv_transform<agg::ellipse> tr(ellipse, mtx);
01462
01463 if ( !IsStrokeOnly() )
01464 {
01465 m_path.remove_all();
01466 m_path.concat_path(tr,0);
01467
01468 m_rasterizer.reset();
01469 m_rasterizer.add_path( m_path );
01470
01471 if ( m_activefill.GetType() == a2dFILL_GRADIENT_FILL_LINEAR )
01472 {
01473 RenderGradient( false );
01474 }
01475 else if ( m_activefill.GetType() == a2dFILL_GRADIENT_FILL_RADIAL )
01476 {
01477 RenderGradient( true );
01478 }
01479 else if ( m_activefill.GetType() == a2dFILL_BITMAP ||
01480 (m_activefill.GetStyle() >= a2dFIRST_HATCH && m_activefill.GetStyle() <= a2dLAST_HATCH ) ||
01481 (m_activefill.GetStyle() >= a2dFIRST_TWOCOL_HATCH && m_activefill.GetStyle() <= a2dLAST_TWOCOL_HATCH ) )
01482 {
01483 RenderBitmapFill();
01484 }
01485 else
01486 Render( true );
01487 }
01488 if ( IsStroked() )
01489 {
01490 m_rasterizer.reset();
01491 _ras_add_stroked_path_xform( ellipse, mtx );
01492 Render( false );
01493 }
01494 }
01495
01496 void a2dAggContext::DrawPolygon( const a2dVertexList *list, wxPolygonFillMode fillStyle )
01497 {
01498 if ( m_pen.IsNull() && m_brush.IsNull() )
01499 return;
01500
01501 int segments = ToAggPath( list, false );
01502
01503 if ( segments == 0 )
01504 return;
01505
01506 agg::trans_affine mtx = _get_agg_user_to_device_transform();
01507 if ( IsStrokeOnly() )
01508 {
01509 }
01510 else if ( m_activefill.GetType() == a2dFILL_GRADIENT_FILL_LINEAR )
01511 {
01512 m_path.close_polygon();
01513 agg::conv_transform<agg::path_storage> tr( m_path, mtx );
01514 m_rasterizer.reset();
01515 m_rasterizer.add_path( tr );
01516
01517 RenderGradient( false );
01518 }
01519 else if ( m_activefill.GetType() == a2dFILL_GRADIENT_FILL_RADIAL )
01520 {
01521 m_path.close_polygon();
01522 agg::conv_transform<agg::path_storage> tr( m_path, mtx );
01523 m_rasterizer.reset();
01524 m_rasterizer.add_path( tr );
01525
01526 RenderGradient( true );
01527 }
01528 else if ( m_activefill.GetType() == a2dFILL_BITMAP ||
01529 (m_activefill.GetStyle() >= a2dFIRST_HATCH && m_activefill.GetStyle() <= a2dLAST_HATCH ) ||
01530 (m_activefill.GetStyle() >= a2dFIRST_TWOCOL_HATCH && m_activefill.GetStyle() <= a2dLAST_TWOCOL_HATCH ) )
01531 {
01532 m_path.close_polygon();
01533 agg::conv_transform<agg::path_storage> tr( m_path, mtx );
01534 m_rasterizer.reset();
01535 m_rasterizer.add_path( tr );
01536
01537 RenderBitmapFill();
01538 }
01539 else
01540 {
01541 m_path.close_polygon();
01542 agg::conv_transform<agg::path_storage> tr( m_path, mtx );
01543 m_rasterizer.reset();
01544 m_rasterizer.add_path( tr );
01545
01546 Render( true );
01547 }
01548
01549 if ( IsStroked() )
01550 {
01551 m_rasterizer.reset();
01552 m_path.close_polygon();
01553 _ras_add_stroked_path_xform( m_path, mtx );
01554
01555 Render( false );
01556 }
01557 }
01558
01559 void a2dAggContext::DrawLines( const a2dVertexList* list )
01560 {
01561 if ( m_pen.IsNull() )
01562 return;
01563
01564 int segments = ToAggPath( list, false );
01565
01566 if ( segments == 0 )
01567 return;
01568
01569 agg::trans_affine mtx = _get_agg_user_to_device_transform();
01570 m_rasterizer.reset();
01571 _ras_add_stroked_path_xform( m_path, mtx );
01572 Render( false );
01573 }
01574
01575 int a2dAggContext::ToAggPath( a2dVertexArray* points, bool transform )
01576 {
01577 unsigned int segments = 0;
01578
01579 m_path.remove_all();
01580
01581 unsigned int count = 0;
01582 double x, y, lastx, lasty;
01583 int i;
01584 for ( i = 0; i < points->size(); i++ )
01585 {
01586 const a2dLineSegmentPtr seg = points->Item( i );
01587
01588 if ( !seg->GetArc() )
01589 {
01590 if ( transform )
01591 m_usertodevice.TransformPoint( seg->m_x, seg->m_y, x, y );
01592 else
01593 {
01594 x = seg->m_x;
01595 y = seg->m_y;
01596 }
01597
01598
01599 if( !count || fabs( x - lastx ) > 0.001 || fabs( y - lasty ) > 0.001 )
01600 {
01601 if ( count == 0 )
01602 m_path.move_to( x, y );
01603 else
01604 m_path.line_to( x, y );
01605 lastx = x;
01606 lasty = y;
01607 count++;
01608 }
01609 }
01610 else
01611 {
01612 const a2dArcSegment* cseg = ( const a2dArcSegment* ) seg.Get();
01613
01614 double radius, center_x, center_y, beginrad, midrad, endrad, phit;
01615
01616 if ( cseg->CalcR( *(points->Item( i ? i - 1 : 0 )), radius, center_x, center_y, beginrad, midrad, endrad, phit ) )
01617 {
01618 double dphi;
01619 unsigned int segments;
01620 double radiusDev = m_usertodevice.TransformDistance( radius );
01621 Aberration( m_displayaberration, phit, radiusDev , dphi, segments );
01622
01623 double theta = beginrad;
01624 unsigned int step;
01625
01626 double x, y;
01627 for ( step = 0; step < segments + 1; step++ )
01628 {
01629 if ( transform )
01630 m_usertodevice.TransformPoint( center_x + radius * cos ( theta ), center_y + radius * sin ( theta ), x, y );
01631 else
01632 {
01633 x = center_x + radius * cos ( theta );
01634 y = center_y + radius * sin ( theta );
01635 }
01636
01637 if( !count || fabs( x - lastx ) > 0.001 || fabs( y - lasty ) > 0.001 )
01638 {
01639 if ( count == 0 )
01640 m_path.move_to( x, y );
01641 else
01642 m_path.line_to( x, y );
01643
01644 lastx = x;
01645 lasty = y;
01646 count++;
01647 }
01648 theta = theta + dphi;
01649 }
01650 }
01651 else
01652 {
01653 double x, y;
01654 if ( transform )
01655 m_usertodevice.TransformPoint( cseg->m_x, cseg->m_y, x, y );
01656 else
01657 {
01658 x = cseg->m_x;
01659 y = cseg->m_y;
01660 }
01661
01662
01663 if( !count || fabs( x - lastx ) > 0.001 || fabs( y - lasty ) > 0.001 )
01664 {
01665 if ( count == 0 )
01666 m_path.move_to( x, y );
01667 else
01668 m_path.line_to( x, y );
01669 lastx = x;
01670 lasty = y;
01671 count++;
01672 }
01673 }
01674 }
01675 }
01676
01677 return count;
01678 }
01679
01680 int a2dAggContext::ToAggPath( const a2dVertexList *list, bool transform )
01681 {
01682 unsigned int segments = 0;
01683
01684 if ( list->empty() )
01685 return 0;
01686
01687 m_path.remove_all();
01688
01689 a2dVertexList::const_iterator iterprev = list->end();
01690
01691 unsigned int count = 0;
01692 double x, y, lastx, lasty;
01693 iterprev = list->end();
01694 if ( iterprev != list->begin() )
01695 iterprev--;
01696 a2dVertexList::const_iterator iter = list->begin();
01697 iter = list->begin();
01698 while ( iter != list->end() )
01699 {
01700 a2dLineSegment * seg = ( *iter );
01701
01702 if ( !seg->GetArc() )
01703 {
01704 if ( transform )
01705 m_usertodevice.TransformPoint( seg->m_x, seg->m_y, x, y );
01706 else
01707 {
01708 x = seg->m_x;
01709 y = seg->m_y;
01710 }
01711
01712
01713 if( !count || fabs( x - lastx ) > 0.001 || fabs( y - lasty ) > 0.001 )
01714 {
01715 if ( count == 0 )
01716 m_path.move_to( x, y );
01717 else
01718 m_path.line_to( x, y );
01719 lastx = x;
01720 lasty = y;
01721 count++;
01722 }
01723 }
01724 else
01725 {
01726 a2dArcSegment* cseg = ( a2dArcSegment* ) seg;
01727
01728 double radius, center_x, center_y, beginrad, midrad, endrad, phit;
01729
01730 if ( cseg->CalcR( *( *iterprev ), radius, center_x, center_y, beginrad, midrad, endrad, phit ) )
01731 {
01732 double dphi;
01733 unsigned int segments;
01734 double radiusDev = m_usertodevice.TransformDistance( radius );
01735 Aberration( m_displayaberration, phit, radiusDev , dphi, segments );
01736
01737 double theta = beginrad;
01738 unsigned int step;
01739
01740 double x, y;
01741 for ( step = 0; step < segments + 1; step++ )
01742 {
01743 if ( transform )
01744 m_usertodevice.TransformPoint( center_x + radius * cos ( theta ), center_y + radius * sin ( theta ), x, y );
01745 else
01746 {
01747 x = center_x + radius * cos ( theta );
01748 y = center_y + radius * sin ( theta );
01749 }
01750
01751
01752 if( !count || fabs( x - lastx ) > 0.001 || fabs( y - lasty ) > 0.001 )
01753 {
01754 if ( count == 0 )
01755 m_path.move_to( x, y );
01756 else
01757 m_path.line_to( x, y );
01758 lastx = x;
01759 lasty = y;
01760 count++;
01761 }
01762 theta = theta + dphi;
01763 }
01764 }
01765 else
01766 {
01767 double x, y;
01768 if ( transform )
01769 m_usertodevice.TransformPoint( cseg->m_x, cseg->m_y, x, y );
01770 else
01771 {
01772 x = cseg->m_x;
01773 y = cseg->m_y;
01774 }
01775
01776
01777 if( !count || fabs( x - lastx ) > 0.001 || fabs( y - lasty ) > 0.001 )
01778 {
01779 if ( count == 0 )
01780 m_path.move_to( x, y );
01781 else
01782 m_path.line_to( x, y );
01783 lastx = x;
01784 lasty = y;
01785 count++;
01786 }
01787 }
01788 }
01789 iterprev = iter++;
01790 }
01791
01792 return count;
01793 }
01794
01795
01796
01797
01798 IMPLEMENT_DYNAMIC_CLASS( a2dGcAggDrawer, a2dGcBaseDrawer )
01799
01800 void a2dGcAggDrawer::InitContext()
01801 {
01802 m_clip.Clear();
01803 m_buffer = a2dImageRGBA( m_width,m_height );
01804 m_pdata = m_buffer.GetData();
01805 m_render = new a2dRenderer();
01806 m_context = new a2dAggContext( m_render, &m_buffer );
01807 }
01808
01809 a2dGcAggDrawer::a2dGcAggDrawer( const wxSize& size ): a2dGcBaseDrawer( size.GetWidth(), size.GetHeight() )
01810 {
01811 InitContext();
01812 }
01813
01814 a2dGcAggDrawer::a2dGcAggDrawer( int width, int height ): a2dGcBaseDrawer( width, height )
01815 {
01816 InitContext();
01817 }
01818
01819 a2dGcAggDrawer::a2dGcAggDrawer( const a2dGcAggDrawer& other )
01820 : a2dGcBaseDrawer( other )
01821 {
01822 InitContext();
01823 }
01824
01825 a2dGcAggDrawer::a2dGcAggDrawer( const a2dDrawer2D& other )
01826 : a2dGcBaseDrawer( other )
01827 {
01828 InitContext();
01829 }
01830
01831 a2dGcAggDrawer::~a2dGcAggDrawer()
01832 {
01833 delete m_context;
01834 delete m_render;
01835 }
01836
01837 void a2dGcAggDrawer::SetYaxis( bool up )
01838 {
01839 a2dDrawer2D::SetYaxis( up );
01840
01841 }
01842
01843 wxBitmap a2dGcAggDrawer::GetBuffer() const
01844 {
01845 return wxBitmap( m_buffer.GetImage() );
01846 }
01847
01848 void a2dGcAggDrawer::SetBufferSize( int w, int h )
01849 {
01850 a2dImageRGBA newbuf( w, h );
01851
01852 int old_pixelwidth = m_width * 4;
01853 int new_pixelwidth = w * 4;
01854 int pixelwidth = wxMin( w, m_width) *4;
01855 int minheight = wxMin( h, m_height);
01856
01857
01858 unsigned char* oldpdata = m_pdata;
01859 unsigned char* newpdata = newbuf.GetData();
01860
01861 for (int yp = 0; yp < minheight; yp++)
01862 {
01863 memcpy( newpdata, oldpdata, pixelwidth);
01864 oldpdata += old_pixelwidth;
01865 newpdata += new_pixelwidth;
01866 }
01867
01868 m_width = w;
01869 m_height = h;
01870 m_buffer = newbuf;
01871
01872 m_pdata = m_buffer.GetData();
01873 DestroyClippingRegion();
01874 delete m_context;
01875 m_context = new a2dAggContext( m_render, &m_buffer );
01876 }
01877
01878 wxBitmap a2dGcAggDrawer::GetSubBitmap( wxRect rect ) const
01879 {
01880 return wxBitmap( m_buffer.GetImage().GetSubImage(rect) );
01881 }
01882
01883 void a2dGcAggDrawer::CopyIntoBuffer( const wxBitmap& bitm )
01884 {
01885 m_buffer = a2dImageRGBA( bitm.ConvertToImage() );
01886 }
01887
01888 void a2dGcAggDrawer::BlitBuffer( wxDC* dc, wxRect rect, const wxPoint& bufferpos )
01889 {
01890
01891 if (rect.x < 0)
01892 {
01893 rect.width += rect.x;
01894 rect.x = 0;
01895 }
01896 if (rect.width <= 0) return;
01897
01898 if (rect.y < 0)
01899 {
01900 rect.height += rect.y;
01901 rect.y = 0;
01902 }
01903 if (rect.height <= 0) return;
01904
01905 if (rect.x+rect.width >= m_width)
01906 rect.width = m_width - rect.x;
01907
01908 if (rect.width <= 0) return;
01909
01910 if (rect.y+rect.height >= m_height)
01911 rect.height = m_height - rect.y;
01912
01913 if (rect.height <= 0) return;
01914
01915 int xmax = rect.x + rect.width;
01916 int ymax = rect.y + rect.height;
01917
01918 a2dImageRGBA* subImage = m_buffer.GetSubImage(rect);
01919 wxBitmap subbitmap = subImage->CreateBitmap();
01920 delete subImage;
01921
01922 wxMemoryDC mdc;
01923 mdc.SelectObject( subbitmap );
01924
01925 dc->Blit( rect.x - bufferpos.x, rect.y - bufferpos.y, xmax-rect.x, ymax-rect.y, &mdc, 0, 0, wxCOPY, false );
01926
01927 mdc.SelectObject( wxNullBitmap );
01928 }
01929
01930 void a2dGcAggDrawer::ShiftBuffer( int dxy, bool yshift )
01931 {
01932 if (yshift)
01933 {
01934 int pixelwidth = m_width*4;
01935
01936 if (dxy > 0 && dxy < m_height )
01937 {
01938 unsigned char* highline = m_pdata + (m_height-dxy)*pixelwidth ;
01939 unsigned char* lowline = m_pdata + m_height*pixelwidth ;
01940
01941 for (int yp = 0; yp < m_height-dxy; yp++)
01942 {
01943 highline -= pixelwidth;
01944 lowline -= pixelwidth;
01945 memcpy( lowline, highline, pixelwidth);
01946 }
01947 }
01948 else if (dxy < 0 && dxy > -m_height)
01949 {
01950 dxy = -dxy;
01951 unsigned char* highline = m_pdata;
01952 unsigned char* lowline = m_pdata + dxy*pixelwidth ;
01953
01954 for (int yp = 0; yp < m_height-dxy ; yp++)
01955 {
01956 memcpy( highline, lowline, pixelwidth);
01957 highline += pixelwidth;
01958 lowline += pixelwidth;
01959 }
01960 }
01961 else
01962 wxFAIL_MSG( wxT("you can only shift within height of buffer") );
01963 }
01964 else
01965 {
01966 int pixelwidth = m_width*4;
01967 if (dxy > 0 && dxy < m_width)
01968 {
01969 int subwidth = (m_width - dxy)*4;
01970 unsigned char* low = m_pdata;
01971 unsigned char* high = m_pdata + dxy*4 ;
01972
01973 for (int yp = 0; yp < m_height ; yp++)
01974 {
01975 memcpy( high, low, subwidth);
01976 high += pixelwidth;
01977 low += pixelwidth;
01978 }
01979 }
01980 else if (dxy < 0 && dxy > -m_width )
01981 {
01982 dxy = -dxy;
01983 int subwidth = (m_width - dxy)*4;
01984 unsigned char* low = m_pdata;
01985 unsigned char* high = m_pdata + dxy*4 ;
01986
01987 for (int yp = 0; yp < m_height ; yp++)
01988 {
01989 memcpy( low, high, subwidth );
01990 high += pixelwidth;
01991 low += pixelwidth;
01992 }
01993 }
01994 else
01995 wxFAIL_MSG( wxT("you can only shift within width of buffer") );
01996 }
01997 }
01998
01999 void a2dGcAggDrawer::DoSetActiveStroke()
02000 {
02001 if ( 1 )
02002 {
02003
02004
02005 a2dRenderer* render = (a2dRenderer*) m_render;
02006 a2dContext* context = (a2dContext*) m_context;
02007 wxGraphicsPen p = render->CreateStroke( m_activestroke );
02008 m_context->SetPen( p );
02009 }
02010 else
02011 {
02012 a2dGcBaseDrawer::DoSetActiveStroke();
02013 }
02014 }
02015
02016 void a2dGcAggDrawer::DoSetActiveFill()
02017 {
02018 if ( 1 )
02019 {
02020
02021
02022 a2dRenderer* render = (a2dRenderer*) m_render;
02023 a2dContext* context = (a2dContext*) m_context;
02024 wxGraphicsBrush b = render->CreateFill( m_activefill );
02025 m_context->SetBrush( b );
02026 }
02027 else
02028 {
02029 a2dGcBaseDrawer::DoSetActiveFill();
02030 }
02031 }
02032
02033 void a2dGcAggDrawer::DoSetActiveFont( const a2dFont& font )
02034 {
02035 a2dContext* context = (a2dContext*) m_context;
02036 a2dRenderer* render = (a2dRenderer*) m_render;
02037 wxGraphicsFont f = render->CreateFont( font );
02038 context->SetFont( font );
02039 }
02040
02041 void a2dGcAggDrawer::DrawPoint( double xc, double yc )
02042 {
02043 if ( m_disableDrawing )
02044 return;
02045
02046 double xt, yt;
02047 GetUserToDeviceTransform().TransformPoint( xc, yc, xt, yt );
02048
02049 }
02050
02051 void a2dGcAggDrawer::DrawImage( const wxImage& imagein, double x, double y, double width, double height, wxUint8 Opacity )
02052 {
02053 if ( m_disableDrawing )
02054 return;
02055
02056 a2dAffineMatrix affine;
02057 if ( GetYaxis() )
02058 {
02059 affine.Translate( 0.0, -(y) );
02060 affine.Mirror( true, false );
02061 affine.Translate( 0.0, y );
02062 }
02063 PushTransform( affine );
02064
02065 a2dContext* context = (a2dContext*) m_context;
02066 a2dRenderer* render = (a2dRenderer*) m_render;
02067 wxGraphicsBitmap bitmap = render->CreateBitmap( imagein );
02068 #if wxCHECK_VERSION(2,9,0)
02069 m_context->DrawBitmap( bitmap, x, y, width, height );
02070 #else
02071 context->DrawGraphicsBitmap( bitmap, x, y, width, height );
02072 #endif
02073
02074 PopTransform();
02075 }
02076
02077 void a2dGcAggDrawer::DrawImage( const a2dImageRGBA& image, double x, double y, double width, double height, wxUint8 Opacity )
02078 {
02079 if ( m_disableDrawing )
02080 return;
02081
02082 a2dContext* context = (a2dContext*) m_context;
02083 a2dRenderer* render = (a2dRenderer*) m_render;
02084 wxImage wximage = image.GetImage();
02085 wxGraphicsBitmap bitmap = render->CreateBitmap( wximage );
02086 #if wxCHECK_VERSION(2,9,0)
02087 m_context->DrawBitmap( bitmap, x - width/2.0, y - height/2.0, width, height );
02088 #else
02089 context->DrawGraphicsBitmap( bitmap, x - width/2.0, y - height/2.0, width, height );
02090 #endif
02091 }
02092
02093
02094
02095
02096
02097
02098
02099
02100
02101
02102
02103
02104
02105
02106
02107 void a2dGcAggDrawer::DrawCharFreetype( wxChar c )
02108 {
02109 wxGraphicsMatrix m = m_context->CreateMatrix();
02110 m.Set(
02111 m_usertodevice( 0, 0), m_usertodevice( 0, 1),
02112 m_usertodevice( 1, 0), m_usertodevice( 1, 1),
02113 m_usertodevice( 2, 0), m_usertodevice( 2, 1) );
02114 m_context->SetTransform( m );
02115 static_cast<a2dAggContext*>(m_context)->DrawCharFreetype( c );
02116 }
02117 */
02118
02119
02120 #endif // wxART2D_USE_GRAPHICS_CONTEXT
02121
02122 #endif //wxART2D_USE_AGGDRAWER
02123