wxArt2D
graphicagg.cpp
1 /*! \file aggdrawer/src/aggdrawer.cpp
2  \brief a2dAggContext - Drawer using the antigrain library
3  \author Klaas Holwerda
4 
5  Copyright: 2001-2004 (C) Klaas Holwerda
6 
7  Licence: wxWidgets licence
8 
9  RCS-ID: $Id: graphicagg.cpp,v 1.11 2009/10/06 18:40:31 titato Exp $
10 */
11 
12 #include "a2dprec.h"
13 
14 #ifdef __BORLANDC__
15 #pragma hdrstop
16 #endif
17 
18 #if wxART2D_USE_AGGDRAWER
19 
20 #if wxART2D_USE_GRAPHICS_CONTEXT
21 
22 #ifndef WX_PRECOMP
23 #include "wx/image.h"
24 #include "wx/window.h"
25 #include "wx/dc.h"
26 #include "wx/utils.h"
27 #include "wx/dialog.h"
28 #include "wx/app.h"
29 #include "wx/bitmap.h"
30 #include "wx/dcmemory.h"
31 #include "wx/log.h"
32 #include "wx/icon.h"
33 #include "wx/dcprint.h"
34 #include "wx/module.h"
35 #endif
36 
37 #include "wx/aggdrawer/graphicagg.h"
38 #include "wx/artbase/stylebase.h"
39 
40 #include "wx/dc.h"
41 
42 #include "wx/graphics.h"
43 #include "wx/rawbmp.h"
44 
45 #if wxART2D_USE_FREETYPE
46 #include <ft2build.h>
47 #ifdef _MSC_VER
48 // Do not use the define include for MSVC, because of a bug with precompiled
49 // headers. See (freetype)/doc/INSTALL.ANY for (some) more information
50 #include <freetype/freetype.h>
51 #include <freetype/ftoutln.h>
52 #else // _MSC_VER
53 // This is the way it should be included.
54 #include FT_FREETYPE_H
55 #include FT_OUTLINE_H
56 #endif // _MSC_VER
57 #endif
58 
59 #include <vector>
60 
61 using namespace std;
62 
63 //-----------------------------------------------------------------------------
64 // constants
65 //-----------------------------------------------------------------------------
66 
67 const double RAD2DEG = 180.0 / M_PI;
68 
69 //-----------------------------------------------------------------------------
70 // Local functions
71 //-----------------------------------------------------------------------------
72 
73 static inline double dmin( double a, double b )
74 {
75  return a < b ? a : b;
76 }
77 static inline double dmax( double a, double b )
78 {
79  return a > b ? a : b;
80 }
81 
82 static inline double DegToRad( double deg )
83 {
84  return ( deg * M_PI ) / 180.0;
85 }
86 static inline double RadToDeg( double deg )
87 {
88  return ( deg * 180.0 ) / M_PI;
89 }
90 
91 
92 //-----------------------------------------------------------------------------
93 // wxGraphicsPath implementation
94 //-----------------------------------------------------------------------------
95 
96 // TODO remove this dependency (gdiplus needs the macros)
97 
98 #ifndef max
99 #define max(a,b) (((a) > (b)) ? (a) : (b))
100 #endif
101 
102 #ifndef min
103 #define min(a,b) (((a) < (b)) ? (a) : (b))
104 #endif
105 
106 
107 //-----------------------------------------------------------------------------
108 // a2dAggContext implementation
109 //-----------------------------------------------------------------------------
110 template< class PathT >
111 void a2dAggContext::_ras_add_stroked_path_xform( PathT& path, const
112  agg::trans_affine& mtx )
113 {
114  // This does the job of constructing all stroke rendering pipelines
115  // based on the current stroke parameters.
116  // Transformation is always part of the pipeline, but sometimes its
117  // a no-op transformer (noop_conv_transform).
118 
119  if ( m_style == a2dSTROKE_SOLID )
120  {
121  if ( m_preStroke )
122  {
123  typedef agg::conv_stroke< PathT > path_stroke_t;
124  typedef agg::conv_transform< path_stroke_t > path_stroke_trans_t;
125 
126  path_stroke_t stroke( path );
127  path_stroke_trans_t trans_path( stroke, mtx );
128  stroke.line_join( m_join );
129  stroke.line_cap( m_cap );
130  if ( m_activestroke.GetPixelStroke() )
131  stroke.width( m_strokewidthDev );
132  else
133  stroke.width( m_strokewidth );
134  m_rasterizer.reset();
135  m_rasterizer.add_path( trans_path );
136  }
137  else
138  {
139  typedef agg::conv_transform<PathT> trans_t;
140  typedef agg::conv_stroke< trans_t > path_stroke_t;
141 
142  trans_t trans_path( path, mtx );
143  path_stroke_t stroke( trans_path );
144  //stroke.miter_limit();
145  stroke.line_join( m_join );
146  stroke.line_cap( m_cap );
147  stroke.width( m_strokewidthDev );
148  m_rasterizer.reset();
149  m_rasterizer.add_path( stroke );
150  }
151  }
152  else
153  {
154  if ( m_preStroke )
155  {
156  typedef agg::conv_dash< PathT > path_dash_t;
157  typedef agg::conv_stroke< path_dash_t > path_dashstroked_t;
158  typedef agg::conv_transform< path_dashstroked_t > path_transdash_t;
159 
160  path_dash_t dash_path( path );
161  path_dashstroked_t stroke( dash_path );
162  path_transdash_t trans_path( stroke, mtx );
163 
164  double scale = m_strokewidth;
165  if ( scale < 1.0 ) scale = 1.0;
166  //scale = 1.0;
167  switch( m_style )
168  {
169  case a2dSTROKE_DOT:
170  dash_path.add_dash( 0.25 * scale, 1.5 * scale );
171  break;
172  case a2dSTROKE_DOT_DASH:
173  dash_path.add_dash( 0.25 * scale, 1.5 * scale );
174  dash_path.add_dash( 2.0 * scale, 2.0 * scale );
175  break;
176  case a2dSTROKE_LONG_DASH:
177  dash_path.add_dash( 2.0 * scale, 2.0 * scale );
178  break;
180  dash_path.add_dash( 2.0 * scale, 2.0 * scale );
181  break;
182  //case a2dSTROKE_USER_DASH:
183  // break;
184  }
185  //dash_path.dash_start(m_dash_offset);
186  stroke.line_join( m_join );
187  stroke.line_cap( m_cap );
188  //stroke.miter_limit();
189  if ( m_activestroke.GetPixelStroke() )
190  stroke.width( m_strokewidthDev );
191  else
192  stroke.width( m_strokewidth );
193  m_rasterizer.reset();
194  m_rasterizer.add_path( trans_path );
195  }
196  else
197  {
198  typedef agg::conv_transform<PathT> trans_t;
199  typedef agg::conv_dash< trans_t > path_transdash_t;
200  typedef agg::conv_stroke< path_transdash_t > path_dashstroked_t;
201 
202  trans_t trans_path( path, mtx );
203  path_transdash_t dash_path( trans_path );
204  path_dashstroked_t stroke( dash_path );
205 
206  double scale = m_strokewidthDev;
207  if ( scale < 1.0 ) scale = 1.0;
208  //scale = 1.0;
209  switch( m_style )
210  {
211  case a2dSTROKE_DOT:
212  dash_path.add_dash( 0.25 * scale, 1.5 * scale );
213  break;
214  case a2dSTROKE_DOT_DASH:
215  dash_path.add_dash( 0.25 * scale, 1.5 * scale );
216  dash_path.add_dash( 2.0 * scale, 2.0 * scale );
217  break;
218  case a2dSTROKE_LONG_DASH:
219  dash_path.add_dash( 2.0 * scale, 2.0 * scale );
220  break;
222  dash_path.add_dash( 2.0 * scale, 2.0 * scale );
223  break;
224  //case a2dSTROKE_USER_DASH:
225  // break;
226  }
227  //dash_path.dash_start(m_dash_offset);
228  stroke.line_join( m_join );
229  stroke.line_cap( m_cap );
230  //stroke.miter_limit();
231  stroke.width( m_strokewidthDev );
232  m_rasterizer.reset();
233  m_rasterizer.add_path( stroke );
234  }
235 
236  }
237 }
238 
239 
240 void a2dAggContext::_stipple_render_scanlines( agg::rasterizer_scanline_aa<>& ras,
241  agg::scanline_u8& sl,
242  RendererBaseA& renb,
243  agg::rendering_buffer pat,
244  double alpha )
245 {
246  unsigned offset_x = 0;
247  unsigned offset_y = 0;
248 
249  //typedef agg::wrap_mode_reflect_auto_pow2 wrap_x_type;
250  //typedef agg::wrap_mode_reflect_auto_pow2 wrap_y_type;
251  typedef agg::wrap_mode_repeat wrap_x_type;
252  typedef agg::wrap_mode_repeat wrap_y_type;
253 
254  typedef agg::image_accessor_wrap<PixFormat, wrap_x_type, wrap_y_type> img_source_type;
255  typedef agg::span_pattern_a2d<img_source_type> span_gen_type;
256  typedef agg::span_allocator<color_type> span_alloc_type;
257 
258  typedef agg::renderer_scanline_aa<RendererBaseA, span_alloc_type, span_gen_type> renderer_type;
259 
260  PixFormat img_pixf( pat );
261  img_source_type img_src( img_pixf );
262  span_gen_type sg( img_src, offset_x, offset_y );
263 
264  sg.alpha( span_gen_type::value_type( alpha ) );
265 
266  span_alloc_type sa;
267  renderer_type rp( renb, sa, sg );
268 
269  agg::render_scanlines( ras, sl, rp );
270 }
271 
272 a2dAggContext::a2dAggContext( wxGraphicsRenderer* renderer, const wxImage& drawable )
273  :
274  m_rendering_buffer(),
275  m_pixFormat( m_rendering_buffer ),
276  m_pixFormatComp( m_rendering_buffer ),
277  m_renBase( m_pixFormat ),
278  m_renBaseComp( m_pixFormatComp ),
279  m_renderer( m_renBase ),
280  m_renSolidComp( m_renBaseComp ),
281  m_rasterizer(),
282  m_fillGradient(),
283  m_lineGradient(),
284  m_fillGradientMatrix(),
285  m_lineGradientMatrix(),
286  m_fillGradientD1( 0.0 ),
287  m_lineGradientD1( 0.0 ),
288  m_fillGradientD2( 100.0 ),
289  m_lineGradientD2( 100.0 ),
290  m_fillGradientInterpolator( m_fillGradientMatrix ),
291  m_lineGradientInterpolator( m_lineGradientMatrix ),
292  m_linearGradientFunction(),
293  m_radialGradientFunction(),
294  a2dContext( renderer, drawable.GetWidth(), drawable.GetHeight() )
295 {
296  m_buffer = new a2dImageRGBA( m_width, m_height );
297  m_pdata = m_buffer->GetData();
298  m_rendering_buffer.attach( m_pdata, m_width, m_height, m_width * 4 );
299  ResetClip();
300  m_preStroke = true;
301 }
302 
303 a2dAggContext::a2dAggContext( wxGraphicsRenderer* renderer, a2dImageRGBA* drawable )
304  :
305  m_rendering_buffer(),
306  m_pixFormat( m_rendering_buffer ),
307  m_pixFormatComp( m_rendering_buffer ),
308  m_renBase( m_pixFormat ),
309  m_renBaseComp( m_pixFormatComp ),
310  m_renderer( m_renBase ),
311  m_renSolidComp( m_renBaseComp ),
312  m_rasterizer(),
313  m_fillGradient(),
314  m_lineGradient(),
315  m_fillGradientMatrix(),
316  m_lineGradientMatrix(),
317  m_fillGradientD1( 0.0 ),
318  m_lineGradientD1( 0.0 ),
319  m_fillGradientD2( 100.0 ),
320  m_lineGradientD2( 100.0 ),
321  m_fillGradientInterpolator( m_fillGradientMatrix ),
322  m_lineGradientInterpolator( m_lineGradientMatrix ),
323  m_linearGradientFunction(),
324  m_radialGradientFunction(),
325  a2dContext( renderer, drawable->GetWidth(), drawable->GetHeight() )
326 {
327  m_buffer = drawable;
328  m_pdata = m_buffer->GetData();
329  m_rendering_buffer.attach( m_pdata, m_width, m_height, m_width * 4 );
330  ResetClip();
331  m_preStroke = true;
332 }
333 
334 a2dAggContext::~a2dAggContext()
335 {
336 }
337 
338 void a2dAggContext::Clip( const wxRegion& region )
339 {
340  // Create a path with all the rectangles in the region
341  wxGraphicsPath path = GetRenderer()->CreatePath();
342  wxRegionIterator ri( region );
343  while ( ri )
344  {
345  path.AddRectangle( ri.GetX(), ri.GetY(), ri.GetW(), ri.GetH() );
346  ri++;
347  }
348 }
349 
350 void a2dAggContext::Clip( wxDouble x, wxDouble y, wxDouble w, wxDouble h )
351 {
352  //need to calculate clip in device coordinates from world coordinates
353  // not even rectangular in the end, so assume a polygon as result.
354  wxPoint trpoints[4];
355  double dx, dy;
356 
357  m_usertodevice.TransformPoint( x, y, dx, dy );
358  trpoints[0] = wxPoint( dx, dy );
359  m_usertodevice.TransformPoint( x, y + h, dx, dy );
360  trpoints[1] = wxPoint( dx, dy );
361  m_usertodevice.TransformPoint( x + w, y + h, dx, dy );
362  trpoints[2] = wxPoint( dx, dy );
363  m_usertodevice.TransformPoint( x + w, y, dx, dy );
364  trpoints[3] = wxPoint( dx, dy );
365 
366  double xmin = trpoints[0].x;
367  double ymin = trpoints[0].y;
368  double xmax = trpoints[0].x;
369  double ymax = trpoints[0].y;
370  for ( int i = 1; i < 4; i ++ )
371  {
372  xmin = wxMin( xmin, trpoints[i].x );
373  xmax = wxMax( xmax, trpoints[i].x );
374  ymin = wxMin( ymin, trpoints[i].y );
375  ymax = wxMax( ymax, trpoints[i].y );
376  }
377  wxRect cliprect = wxRect( xmin, ymin, xmax - xmin, ymax - ymin );
378  m_clipboxdev = cliprect;
379 
380  m_renBase.clip_box( xmin, ymin, xmax, ymax );
381  m_renBaseComp.clip_box( xmin, ymin, xmax, ymax );
382  m_rasterizer.clip_box( 0, 0, m_width, m_height );
383  // why not the next, does not work??
384  //m_rasterizer.clip_box( minx, miny, xmax, ymax );
385 }
386 
387 void a2dAggContext::ResetClip()
388 {
389  m_clipboxdev = wxRect( 0, 0, m_width, m_height );
390  m_renBase.clip_box( 0, 0, m_width, m_height );
391  m_renBaseComp.clip_box( 0, 0, m_width, m_height );
392  m_rasterizer.clip_box( 0, 0, m_width, m_height );
393 }
394 
395 void a2dAggContext::Render( bool fillColor )
396 {
397  if ( fillColor )
398  {
399  agg::rgba8 colorfill( m_colour1redFill, m_colour1greenFill, m_colour1blueFill, m_FillOpacityCol1 );
400  m_renderer.color( colorfill );
401  m_renSolidComp.color( colorfill );
402  }
403  else
404  {
405  agg::rgba8 colorstroke( m_colour1redStroke, m_colour1greenStroke, m_colour1blueStroke, m_StrokeOpacityCol1 );
406  m_renderer.color( colorstroke );
407  m_renSolidComp.color( colorstroke );
408  }
409 
410  if( m_blendMode == agg::end_of_comp_op_e )
411  agg::render_scanlines( m_rasterizer, m_sl, m_renderer );
412  else
413  agg::render_scanlines( m_rasterizer, m_sl, m_renSolidComp );
414 }
415 
416 void a2dAggContext::RenderGradient( bool radial )
417 {
418  if ( !radial )
419  {
420  span_allocator_type aggallocator;
421  LinearGradientSpan span( /*gr.m_allocator, */
422  m_fillGradientInterpolator,
423  m_linearGradientFunction,
424  m_fillGradient,
425  m_fillGradientD1,
426  m_fillGradientD2 );
427  RendererLinearGradientA ren( m_renBase, aggallocator, span );
428  RendererLinearGradientComp renComp( m_renBaseComp, aggallocator, span );
429 
430  if( m_blendMode == agg::end_of_comp_op_e )
431  agg::render_scanlines( m_rasterizer, m_sl, ren );
432  else
433  agg::render_scanlines( m_rasterizer, m_sl, renComp );
434  }
435  else
436  {
437  span_allocator_type aggallocator;
438  RadialGradientSpan span( /*gr.m_allocator, */
439  m_fillGradientInterpolator,
440  m_radialGradientFunction,
441  m_fillGradient,
442  m_fillGradientD1,
443  m_fillGradientD2 );
444  RendererRadialGradientA ren( m_renBase, aggallocator, span );
445  RendererRadialGradientComp renComp( m_renBaseComp, aggallocator, span );
446 
447  if( m_blendMode == agg::end_of_comp_op_e )
448  agg::render_scanlines( m_rasterizer, m_sl, ren );
449  else
450  agg::render_scanlines( m_rasterizer, m_sl, renComp );
451 
452  }
453 }
454 
455 void a2dAggContext::RenderBitmapFill()
456 {
457  unsigned offset_x = 0;
458  unsigned offset_y = 0;
459 
460  //typedef agg::wrap_mode_reflect_auto_pow2 wrap_x_type;
461  //typedef agg::wrap_mode_reflect_auto_pow2 wrap_y_type;
462  typedef agg::wrap_mode_repeat wrap_x_type;
463  typedef agg::wrap_mode_repeat wrap_y_type;
464 
465  typedef agg::image_accessor_wrap<PixFormat, wrap_x_type, wrap_y_type> img_source_type;
466  typedef agg::span_pattern_a2d<img_source_type> span_gen_type;
467  typedef agg::span_allocator<color_type> span_alloc_type;
468 
469  typedef agg::renderer_scanline_aa<RendererBaseA, span_alloc_type, span_gen_type> renderer_type;
470 
471  PixFormat img_pixf( m_pattern_rbuf );
472  img_source_type img_src( img_pixf );
473  span_gen_type sg( img_src, offset_x, offset_y );
474 
475  sg.alpha( span_gen_type::value_type( m_FillOpacityCol1 ) );
476 
477  span_alloc_type sa;
478  renderer_type rp( m_renBase, sa, sg );
479 
480  agg::render_scanlines( m_rasterizer, m_sl, rp );
481 }
482 
483 void a2dAggContext::Rotate( wxDouble angle )
484 {
485  m_usertodevice.Rotate( angle ) ;
486 }
487 
488 void a2dAggContext::Translate( wxDouble dx , wxDouble dy )
489 {
490  m_usertodevice.Translate( dx, dy ) ;
491 }
492 
493 void a2dAggContext::Scale( wxDouble xScale , wxDouble yScale )
494 {
495  m_usertodevice.Scale( xScale, yScale, 0, 0 ) ;
496 }
497 
498 // concatenates this transform with the current transform of this context
499 void a2dAggContext::ConcatTransform( const wxGraphicsMatrix& matrix )
500 {
501  a2dAffineMatrix* m = ( a2dAffineMatrix* ) matrix.GetNativeMatrix();
502  m_usertodevice *= *m;
503 }
504 
505 // sets the transform of this context
506 void a2dAggContext::SetTransform( const wxGraphicsMatrix& matrix )
507 {
508  a2dAffineMatrix* m = ( a2dAffineMatrix* ) matrix.GetNativeMatrix();
509  m_usertodevice = *m;
510 }
511 
512 // gets the matrix of this context
513 wxGraphicsMatrix a2dAggContext::GetTransform() const
514 {
515  wxGraphicsMatrix matrix = CreateMatrix();
516  a2dAffineMatrix* m = ( a2dAffineMatrix* ) matrix.GetNativeMatrix();
517  *m = m_usertodevice;
518  return matrix;
519 }
520 
521 #if wxCHECK_VERSION(2,9,0)
522 bool a2dAggContext::SetCompositionMode( wxCompositionMode op )
523 {
524  if ( m_composition == op )
525  return true;
526 
527  m_composition = op;
528 
529  switch ( op )
530  {
531  case wxCOMPOSITION_CLEAR:
532  m_blendMode = agg::comp_op_clear;
533  break;
534  case wxCOMPOSITION_SOURCE:
535  m_blendMode = agg::comp_op_src;
536  break;
537  case wxCOMPOSITION_OVER:
538  m_blendMode = agg::comp_op_src_over;
539  break;
540  case wxCOMPOSITION_IN:
541  m_blendMode = agg::comp_op_src_in;
542  break;
543  case wxCOMPOSITION_OUT:
544  m_blendMode = agg::comp_op_src_out;
545  break;
546  case wxCOMPOSITION_ATOP:
547  m_blendMode = agg::comp_op_src_atop;
548  break;
549  case wxCOMPOSITION_DEST:
550  m_blendMode = agg::comp_op_dst;
551  break;
552  case wxCOMPOSITION_DEST_OVER:
553  m_blendMode = agg::comp_op_dst_over;
554  break;
555  case wxCOMPOSITION_DEST_IN:
556  m_blendMode = agg::comp_op_dst_in;
557  break;
558  case wxCOMPOSITION_DEST_OUT:
559  m_blendMode = agg::comp_op_dst_out;
560  break;
561  case wxCOMPOSITION_DEST_ATOP:
562  m_blendMode = agg::comp_op_dst_atop;
563  break;
564  case wxCOMPOSITION_XOR:
565  m_blendMode = agg::comp_op_xor;
566  break;
567  case wxCOMPOSITION_ADD:
568  m_blendMode = agg::comp_op_plus;
569  break;
570  default:
571  m_blendMode = agg::end_of_comp_op_e;
572  }
573  return true;
574 }
575 #endif
576 
577 void a2dAggContext::SetDrawStyle( a2dDrawStyle drawstyle )
578 {
579  m_drawstyle = drawstyle;
580 
581  switch( drawstyle )
582  {
583  case a2dWIREFRAME_INVERT:
584  m_activestroke = *a2dBLACK_STROKE;
585  m_activefill = *a2dTRANSPARENT_FILL;
586  m_blendMode = agg::comp_op_invert;
587  break;
588 
589  case a2dWIREFRAME:
590  m_activestroke = *a2dBLACK_STROKE;
591  m_activefill = *a2dTRANSPARENT_FILL;
592  m_blendMode = agg::end_of_comp_op_e;
593  break;
594 
596  m_activestroke = *a2dBLACK_STROKE;
597  m_activefill = *a2dTRANSPARENT_FILL;
598  m_blendMode = agg::end_of_comp_op_e;
599  break;
600 
602  m_activestroke = *a2dBLACK_STROKE;
603  m_activefill = *a2dTRANSPARENT_FILL;
604  m_blendMode = agg::comp_op_invert;
605  break;
606 
607  case a2dFILLED:
608  m_blendMode = agg::end_of_comp_op_e;
609  break;
610 
611  default:
612  wxASSERT( 0 );
613  }
614  m_pixFormatComp.comp_op( m_blendMode );
615 }
616 
617 bool a2dAggContext::SetLogicalFunction( int function )
618 {
619  switch( function )
620  {
621  case wxINVERT:
622  m_activestroke = *a2dBLACK_STROKE;
623  m_activefill = *a2dTRANSPARENT_FILL;
624  m_blendMode = agg::comp_op_invert;
625  m_drawstyle = a2dWIREFRAME_INVERT;
626  break;
627  default:
628  m_blendMode = agg::end_of_comp_op_e;
629  m_drawstyle = a2dFILLED;
630  }
631 
632  m_pixFormatComp.comp_op( m_blendMode );
633  return true;
634 }
635 
636 void a2dAggContext::DoSetActiveStroke()
637 {
638  if ( m_drawstyle == a2dWIREFRAME_INVERT_ZERO_WIDTH )
639  {
640  m_strokewidth = 0;
641  m_strokewidthDev = 1;
642  }
643  else if ( m_activestroke.GetType() == a2dSTROKE_ONE_COLOUR )
644  {
645  switch( m_activestroke.GetStyle() )
646  {
647  case a2dSTROKE_SOLID:
649  case a2dSTROKE_DOT:
650  case a2dSTROKE_DOT_DASH:
651  case a2dSTROKE_LONG_DASH:
653  m_style = m_activestroke.GetStyle();
654  break;
655  /*
656  // These aren't supported yet
657  case a2dSTROKE_USER_DASH:
658  break;
659  case a2dSTROKE_BDIAGONAL_HATCH:
660  break;
661  case a2dSTROKE_CROSSDIAG_HATCH
662  break;
663  case a2dSTROKE_FDIAGONAL_HATCH:
664  break;
665  case a2dSTROKE_CROSS_HATCH:
666  break;
667  case a2dSTROKE_HORIZONTAL_HATCH:
668  break;
669  case a2dSTROKE_VERTICAL_HATCH:
670  break;
671  case a2dSTROKE_STIPPLE:
672  break;
673  case a2dSTROKE_STIPPLE_MASK_OPAQUE:
674  break;
675  */
676  default: m_style=a2dSTROKE_SOLID;
677  }
678 
679  m_strokewidth = m_activestroke.GetWidth();
680  if ( m_drawstyle == a2dWIREFRAME_ZERO_WIDTH )
681  {
682  a2dAffineMatrix invert = m_usertodevice;
683  invert.Invert();
684  m_strokewidthDev = 1;
685  m_strokewidth = invert.TransformDistance( m_strokewidthDev );
686  m_join = agg::round_join;
687  m_cap = agg::round_cap;
688  }
689  else
690  {
691  switch ( m_activestroke.GetJoin() )
692  {
693  case wxJOIN_MITER: m_join = agg::miter_join;
694  break;
695  case wxJOIN_ROUND: m_join = agg::round_join;
696  break;
697  case wxJOIN_BEVEL: m_join = agg::bevel_join;
698  break;
699  default: m_join = agg::round_join;
700  }
701  switch ( m_activestroke.GetCap() )
702  {
703  case wxCAP_BUTT: m_cap = agg::butt_cap;
704  break;
705  case wxCAP_ROUND: m_cap = agg::round_cap;
706  break;
707  case wxCAP_PROJECTING: m_cap = agg::square_cap;
708  break;
709  default: m_cap = agg::round_cap;
710  }
711 
712  if ( m_activestroke.GetPixelStroke() )
713  {
714  a2dAffineMatrix invert = m_usertodevice;
715  invert.Invert();
716  m_strokewidthDev = m_activestroke.GetWidth();
717  m_strokewidthDev = !m_strokewidthDev ? 1 : m_strokewidthDev;
718  m_strokewidth = invert.TransformDistance( m_strokewidthDev );
719  }
720  else
721  {
722  m_strokewidth = m_activestroke.GetWidth();
723  m_strokewidthDev = m_usertodevice.TransformDistance( m_strokewidth );
724  if ( !m_strokewidthDev )
725  {
726  m_strokewidthDev = 1;
727  a2dAffineMatrix invert = m_usertodevice;
728  invert.Invert();
729  m_strokewidth = invert.TransformDistance( m_strokewidthDev );
730  }
731  }
732  }
733  }
734 }
735 
736 
737 void a2dAggContext::DoSetActiveFill()
738 {
739  if ( m_activefill.GetType() == a2dFILL_ONE_COLOUR )
740  {
741  switch( m_activefill.GetStyle() )
742  {
743  case a2dFILL_TRANSPARENT:
744  break;
745  case a2dFILL_SOLID:
746  break;
748  m_pattern = wxImage( BDIAGONAL_HATCH_XPM );
749  break;
751  m_pattern = wxImage( CROSSDIAG_HATCH_XPM );
752  break;
754  m_pattern = wxImage( FDIAGONAL_HATCH_XPM );
755  break;
756  case a2dFILL_CROSS_HATCH:
757  m_pattern = wxImage( CROSS_HATCH_XPM );
758  break;
760  m_pattern = wxImage( HORIZONTAL_HATCH_XPM );
761  break;
763  m_pattern = wxImage( VERTICAL_HATCH_XPM );
764  break;
765  default: ;
766  }
767  if ( m_activefill.GetStyle() >= a2dFIRST_HATCH && m_activefill.GetStyle() <= a2dLAST_HATCH )
768  {
769  m_pattern.Replace( 0, 0, 0,
770  m_colour1redFill,
771  m_colour1greenFill,
772  m_colour1blueFill );
773 
774  m_pattern_rbuf.attach( m_pattern.GetData(), m_pattern.GetWidth(), m_pattern.GetHeight(), m_pattern.GetWidth() * 3 );
775  }
776  }
777  else if ( m_activefill.GetType() == a2dFILL_HATCH_TWO_COLOUR )
778  {
779  bool nohatch = false;
780  switch( m_activefill.GetStyle() )
781  {
783  m_pattern = wxImage( BDIAGONAL_HATCH_XPM );
784  break;
786  m_pattern = wxImage( CROSSDIAG_HATCH_XPM );
787  break;
789  m_pattern = wxImage( FDIAGONAL_HATCH_XPM );
790  break;
792  m_pattern = wxImage( CROSS_HATCH_XPM );
793  break;
795  m_pattern = wxImage( HORIZONTAL_HATCH_XPM );
796  break;
798  m_pattern = wxImage( VERTICAL_HATCH_XPM );
799  break;
800  default:
801  nohatch = true;
802  break;
803  }
804  m_pattern.Replace( 255, 255, 255,
805  m_colour2redFill,
806  m_colour2greenFill,
807  m_colour2blueFill );
808 
809  m_pattern.Replace( 0, 0, 0,
810  m_colour1redFill,
811  m_colour1greenFill,
812  m_colour1blueFill );
813 
814  m_pattern_rbuf.attach( m_pattern.GetData(), m_pattern.GetWidth(), m_pattern.GetHeight(), m_pattern.GetWidth() * 3 );
815  }
816  else if ( m_activefill.GetType() == a2dFILL_BITMAP )
817  {
818  wxBrush dcbrush;
819  //wxBrushStyle style;
820  switch( m_activefill.GetStyle() )
821  {
822  case a2dFILL_STIPPLE:
825  {
826  static const int MASK_RED = 1;
827  static const int MASK_GREEN = 2;
828  static const int MASK_BLUE = 3;
829 
830  m_pattern = m_activefill.GetStipple().ConvertToImage();
831  m_pattern.Replace( MASK_RED, MASK_GREEN, MASK_BLUE,
832  m_colour1redFill,
833  m_colour1greenFill,
834  m_colour1blueFill );
835 
836  m_pattern_rbuf.attach( m_pattern.GetData(), m_pattern.GetWidth(), m_pattern.GetHeight(), m_pattern.GetWidth() * 3 );
837 
838  //test to see what effect it has
839  //PixFormat pixf(m_pattern_rbuf);
840  //agg::renderer_base<pixfmt> rb(pixf);
841  //rb.clear(agg::rgba(0.4, 0.5, 0.1, 1.0)); // Pattern background color
842  //rb.clear(agg::rgba8(0,250,80));
843  }
844  break;
845  default:
846  break;
847  }
848  }
849  else if ( m_activefill.GetType() == a2dFILL_GRADIENT_FILL_LINEAR )
850  {
851  double profile = 1.0;
852  int i;
853  double x1 = m_activefill.GetStart().m_x;
854  double y1 = m_activefill.GetStart().m_y;
855  double x2 = m_activefill.GetStop().m_x;
856  double y2 = m_activefill.GetStop().m_y;
857  color_type c1( m_colour1redFill, m_colour1greenFill, m_colour1blueFill, m_FillOpacityCol1 );
858  color_type c2( m_colour2redFill, m_colour2greenFill, m_colour2blueFill, m_FillOpacityCol2 );
859  int startGradient = 128 - int( profile * 128.0 );
860  int endGradient = 128 + int( profile * 128.0 );
861  if ( endGradient <= startGradient ) endGradient = startGradient + 1;
862  double k = 1.0 / double( endGradient - startGradient );
863  for ( i = 0; i < startGradient; i++ )
864  {
865  m_fillGradient[i] = c1;
866  }
867  for ( ; i < endGradient; i++ )
868  {
869  m_fillGradient[i] = c1.gradient( c2, double( i - startGradient ) * k );
870  }
871  for ( ; i < 256; i++ )
872  {
873  m_fillGradient[i] = c2;
874  }
875  double angle = atan2( y2 - y1, x2 - x1 );
876  m_fillGradientMatrix.reset();
877  m_fillGradientMatrix *= agg::trans_affine_rotation( angle );
878  m_fillGradientMatrix *= agg::trans_affine_translation( x1, y1 );
879  m_fillGradientMatrix *= _get_agg_user_to_device_transform();
880  m_fillGradientMatrix.invert();
881  m_fillGradientD1 = 0;
882  m_fillGradientD2 = sqrt( ( x2 - x1 ) * ( x2 - x1 ) + ( y2 - y1 ) * ( y2 - y1 ) );
883  }
884  else if ( m_activefill.GetType() == a2dFILL_GRADIENT_FILL_RADIAL )
885  {
886  double profile = 1.0;
887  int i;
888  double xf = m_activefill.GetFocal().m_x;
889  double yf = m_activefill.GetFocal().m_y;
890  double x = m_activefill.GetCenter().m_x;
891  double y = m_activefill.GetCenter().m_y;
892  double r = m_activefill.GetRadius();
893 
894  color_type c1( m_colour1redFill, m_colour1greenFill, m_colour1blueFill, m_FillOpacityCol1 );
895  color_type c2( m_colour2redFill, m_colour2greenFill, m_colour2blueFill, m_FillOpacityCol2 );
896  int startGradient = 128 - int( profile * 127.0 );
897  int endGradient = 128 + int( profile * 127.0 );
898  if ( endGradient <= startGradient ) endGradient = startGradient + 1;
899  double k = 1.0 / double( endGradient - startGradient );
900  for ( i = 0; i < startGradient; i++ )
901  {
902  m_fillGradient[i] = c1;
903  }
904  for ( ; i < endGradient; i++ )
905  {
906  m_fillGradient[i] = c1.gradient( c2, double( i - startGradient ) * k );
907  }
908  for ( ; i < 256; i++ )
909  {
910  m_fillGradient[i] = c2;
911  }
912  m_fillGradientD2 = m_usertodevice.TransformDistance( r );
913  m_usertodevice.TransformPoint( x, y, x, y );
914  m_fillGradientMatrix.reset();
915  m_fillGradientMatrix *= agg::trans_affine_translation( x, y );
916  m_fillGradientMatrix.invert();
917  m_fillGradientD1 = 0;
918  }
919 }
920 
921 #if wxCHECK_VERSION(2,9,0)
922 void a2dAggContext::DrawBitmap( const wxGraphicsBitmap& bmp, wxDouble x, wxDouble y, wxDouble w, wxDouble h )
923 #else
924 void a2dAggContext::DrawGraphicsBitmap( const wxGraphicsBitmap& bmp, wxDouble x, wxDouble y, wxDouble w, wxDouble h )
925 #endif
926 {
927  a2dBitmapData* data = static_cast<a2dBitmapData*>( bmp.GetRefData() );
928  wxImage image = data->GetImage();
929 
930  int imagew = image.GetWidth();
931  int imageh = image.GetHeight();
932 
933  agg::trans_affine mtxi;
934  mtxi *= agg::trans_affine_scaling( w / imagew, h / imageh );
935  mtxi *= agg::trans_affine_translation( x - w / 2, y - h / 2 );
936  // pictures always upwards
937  //if ( m_yaxis )
938  // mtxi *= agg::trans_affine_reflection_unit( 1, 0 );
939 
940  agg::trans_affine mtx = _get_agg_user_to_device_transform();
941  mtxi *= mtx;
942  mtxi.invert();
943 
944  typedef agg::span_allocator<agg::rgba8> span_alloc_type;
945 
946  span_alloc_type sa;
947  typedef agg::image_accessor_clip<PixFormat> img_source_type;
948  typedef agg::span_interpolator_linear<> interpolator_type;
949  interpolator_type interpolator( mtxi );
950 
951  typedef agg::span_image_filter_rgb_bilinear<img_source_type, interpolator_type> span_gen_type;
952  //typedef agg::span_image_filter_rgb_nn<img_source_type, interpolator_type> span_gen_type;
953 
954  typedef agg::span_converter<span_gen_type, span_conv_const_alpha_rgba8> span_conv;
955 
956  typedef agg::renderer_scanline_aa<RendererBaseA, span_alloc_type, span_conv> renderer_type_alpha;
957 
958  typedef agg::renderer_scanline_bin<RendererBaseA, span_alloc_type, span_gen_type> renderer_type_normal;
959 
960  agg::rendering_buffer image_buffer;
961  image_buffer.attach( image.GetData(), imagew, imageh, ( m_yaxis ) ? -imagew * 3 : imagew * 3 );
962  PixFormat img_pixf( image_buffer );
963  img_source_type img_src( img_pixf, agg::rgba( 1, 1, 1, 0 ) );
964 
965  span_gen_type sg( img_src, interpolator );
966 
967  //now add the path to render, which should be the image bounding polygon/rotate rectangle.
968  //But you could even make cuts from the image using ellipse etc.
969  /*
970  agg::rounded_rect er(0,0,m_width,m_height, 0);
971  er.normalize_radius();
972  m_rasterizer.add_path(er);
973 
974  agg::ellipse ellipse( x, y, width/2, height/2);
975  agg::conv_transform<agg::ellipse> tr(ellipse, mtx);
976  m_rasterizer.add_path( tr );
977 
978  agg::rounded_rect er(x-width/2, y-height/2 ,x+width/2, y+height/2, 0);
979  er.normalize_radius();
980  agg::conv_transform<agg::rounded_rect> tr(er, mtx);
981  m_rasterizer.add_path(tr);
982  */
983  agg::rounded_rect er( x - w / 2, y - h / 2 , x + w / 2, y + h / 2, 0 );
984  er.normalize_radius();
985  agg::conv_transform<agg::rounded_rect> tr( er, mtx );
986  m_rasterizer.reset();
987  m_rasterizer.add_path( tr );
988 
989  //NOT m_FillOpacityCol1 since for images fill does not influence the picture.
990  if ( m_OpacityFactor != 255 )
991  {
992  span_conv_const_alpha_rgba8 color_alpha( m_OpacityFactor );
993  span_conv sc( sg, color_alpha );
994  renderer_type_alpha ri( m_renBase, sa, sc );
995 
996  agg::render_scanlines( m_rasterizer, m_sl, ri );
997  }
998  else
999  {
1000  renderer_type_normal ri( m_renBase, sa, sg );
1001  agg::render_scanlines( m_rasterizer, m_sl, ri );
1002  }
1003 
1004 
1005 }
1006 
1007 void a2dAggContext::GetTextExtent( const wxString& str, wxDouble* width, wxDouble* height,
1008  wxDouble* descent, wxDouble* externalLeading ) const
1009 {
1010 }
1011 
1012 void a2dAggContext::GetPartialTextExtents( const wxString& text, wxArrayDouble& widths ) const
1013 {
1014 }
1015 
1016 void a2dAggContext::DrawCharDc( wxChar c )
1017 {
1018 #if wxART2D_USE_FREETYPE && defined(__USE_WINAPI__)
1019  if ( m_a2dfont.GetType() == a2dFONT_WXDC && m_a2dfont.GetFreetypeFont().Ok() )
1020  {
1021  a2dFont oldfont = m_a2dfont;
1022  m_a2dfont = m_a2dfont.GetFreetypeFont();
1023  DrawCharFreetype( c );
1024  m_a2dfont = oldfont;
1025  }
1026  else
1027  a2dContext::DrawCharDc( c );
1028 #else // wxART2D_USE_FREETYPE && defined(__USE_WINAPI__)
1029  a2dContext::DrawCharDc( c );
1030 #endif // wxART2D_USE_FREETYPE && defined(__USE_WINAPI__)
1031 
1032 }
1033 
1034 void a2dAggContext::DrawTextDc( const wxString& text, double x, double y )
1035 {
1036  // Get font size in device units
1037  unsigned int fontsize;
1038  double dx = m_usertodevice.GetValue( 1, 0 );
1039  double dy = m_usertodevice.GetValue( 1, 1 );
1040  fontsize = ( unsigned int ) fabs( m_a2dfont.GetSize() * sqrt( dx * dx + dy * dy ) );
1041  if ( fontsize < 1 )
1042  fontsize = 1;
1043  m_a2dfont.GetFont().SetPointSize( fontsize );
1044 
1045  //m_renderDC->SetFont( m_a2dfont.GetFont() );
1046  //m_renderDC->SetBackgroundMode( wxTRANSPARENT );
1047  //m_renderDC->SetTextForeground( m_stroke1 );
1048 
1049  DrawTextGeneric( text, x, y, ( void ( a2dContext::* )( wxChar ) ) & a2dAggContext::DrawCharDc );
1050 }
1051 
1052 void a2dAggContext::DrawCharStroke( wxChar c )
1053 {
1054  agg::path_storage path;
1055  double size = m_a2dfont.GetSize();
1056  a2dVertexList** ptr = m_a2dfont.GetGlyphStroke( c );
1057  if ( ptr )
1058  {
1059  while ( *ptr )
1060  {
1061  a2dVertexList::iterator iter = ( *ptr )->begin();
1062  if ( ( *ptr )->size() )
1063  {
1064  a2dPoint2D point = ( *iter )->GetPoint();
1065  path.move_to( point.m_x * size, point.m_y * size );
1066  iter++;
1067  }
1068  while ( iter != ( *ptr )->end() )
1069  {
1070  a2dPoint2D point = ( *iter )->GetPoint();
1071  path.line_to( point.m_x * size, point.m_y * size );
1072  iter++;
1073  }
1074  ptr++;
1075  }
1076  }
1077 
1078  // apply affine matrix
1079  agg::trans_affine mtx = _get_agg_user_to_device_transform();
1080  agg::conv_transform< agg::path_storage > tr( path, mtx );
1081  agg::conv_stroke< agg::conv_transform< agg::path_storage > > stroke( tr );
1082 
1083  agg::rgba8 color( m_colour1redStroke, m_colour1greenStroke, m_colour1blueStroke, m_StrokeOpacityCol1 );
1084  stroke.line_join( m_join );
1085  stroke.line_cap( m_cap );
1086  stroke.width( m_a2dfont.GetStrokeWidth() );
1087  m_rasterizer.reset();
1088  m_rasterizer.add_path( stroke );
1089  m_renderer.color( color );
1090  m_renSolidComp.color( color );
1091  if( m_blendMode == agg::end_of_comp_op_e )
1092  agg::render_scanlines( m_rasterizer, m_sl, m_renderer );
1093  else
1094  agg::render_scanlines( m_rasterizer, m_sl, m_renSolidComp );
1095 }
1096 
1097 #if wxART2D_USE_FREETYPE
1098 extern FT_Library g_freetypeLibrary;
1099 
1100 //! used in freetype rendering
1101 typedef struct
1102 {
1103  wxColour colour;
1104  int xmin, ymax;
1105  int stride;
1106  unsigned char* buf;
1107 }
1108 a2dSpanData;
1109 
1110 //! used in freetype rendering
1111 static void a2dSpanFuncGray( int y, int count, FT_Span* spans, a2dSpanData* user )
1112 {
1113  unsigned int alpha, invalpha, len;
1114  // although colours are chars, using ints is faster in multiplications.
1115  unsigned int r, g, b, rpm, gpm, bpm;
1116  r = user->colour.Red();
1117  g = user->colour.Green();
1118  b = user->colour.Blue();
1119 
1120  unsigned char* buf, *buf2;
1121  buf = user->buf + ( user->ymax - y ) * user->stride - user->xmin * 3;
1122  do
1123  {
1124  buf2 = buf + spans->x * 3;
1125  len = spans->len;
1126  alpha = spans->coverage;
1127  if ( alpha == 255 )
1128  {
1129  do
1130  {
1131  // do not try to replace by *buf2++ = r, etc.
1132  // it turns out that this code actually is faster (for x86).
1133 #ifdef __WXGTK__
1134  buf2[0] = r;
1135  buf2[1] = g;
1136  buf2[2] = b;
1137 #else
1138  buf2[0] = b;
1139  buf2[1] = g;
1140  buf2[2] = r;
1141 #endif
1142  buf2 += 3;
1143  }
1144  while( --len );
1145  }
1146  else
1147  {
1148  rpm = r * alpha;
1149  gpm = g * alpha;
1150  bpm = b * alpha;
1151  invalpha = 255 - alpha;
1152  do
1153  {
1154  // do not try to replace by *buf2++ = ..., etc.
1155  // it turns out that this code actually is faster (for x86).
1156 #ifdef __WXGTK__
1157  buf2[0] = ( buf2[0] * invalpha + rpm ) / 255;
1158  buf2[1] = ( buf2[1] * invalpha + gpm ) / 255;
1159  buf2[2] = ( buf2[2] * invalpha + bpm ) / 255;
1160 #else
1161  buf2[0] = ( buf2[0] * invalpha + bpm ) / 255;
1162  buf2[1] = ( buf2[1] * invalpha + gpm ) / 255;
1163  buf2[2] = ( buf2[2] * invalpha + rpm ) / 255;
1164 #endif
1165  buf2 += 3;
1166  }
1167  while( --len );
1168  }
1169  spans++;
1170  }
1171  while ( --count );
1172 }
1173 #endif
1174 
1175 //! \bug EW: DrawCharFreetype crashes when zoomed in extremely far.
1176 void a2dAggContext::DrawCharFreetype( wxChar c )
1177 {
1178  double x, y;
1179  x = y = 0.0;
1180 
1181 #if wxART2D_USE_FREETYPE
1182  y += m_a2dfont.GetDescent();
1183 
1184  agg::path_storage path;
1185  double scale = m_a2dfont.GetSize() / ( 64 * m_a2dfont.GetDeviceHeight() );
1186 
1187  FT_Glyph glyph = m_a2dfont.GetGlyphFreetype( c )->m_glyph;
1188  if ( glyph->format != FT_GLYPH_FORMAT_OUTLINE )
1189  return;
1190  FT_Outline& outline = ( ( FT_OutlineGlyph ) glyph )->outline;
1191 
1192  FT_Vector v_last;
1193  FT_Vector v_control;
1194  FT_Vector v_start;
1195 
1196  FT_Vector* point;
1197  FT_Vector* limit;
1198  char* tags;
1199 
1200  int n; // index of contour in outline
1201  int first; // index of first point in contour
1202  char tag; // current point's state
1203 
1204  first = 0;
1205 
1206  for( n = 0; n < outline.n_contours; n++ )
1207  {
1208  int last; // index of last point in contour
1209 
1210  last = outline.contours[n];
1211  limit = outline.points + last;
1212 
1213  v_start = outline.points[first];
1214  v_last = outline.points[last];
1215 
1216  v_control = v_start;
1217 
1218  point = outline.points + first;
1219  tags = outline.tags + first;
1220  tag = FT_CURVE_TAG( tags[0] );
1221 
1222  // A contour cannot start with a cubic control point!
1223  if( tag == FT_CURVE_TAG_CUBIC ) return;
1224 
1225  // check first point to determine origin
1226  if( tag == FT_CURVE_TAG_CONIC )
1227  {
1228  // first point is conic control. Yes, this happens.
1229  if( FT_CURVE_TAG( outline.tags[last] ) == FT_CURVE_TAG_ON )
1230  {
1231  // start at last point if it is on the curve
1232  v_start = v_last;
1233  limit--;
1234  }
1235  else
1236  {
1237  // if both first and last points are conic,
1238  // start at their middle and record its position
1239  // for closure
1240  v_start.x = ( v_start.x + v_last.x ) / 2;
1241  v_start.y = ( v_start.y + v_last.y ) / 2;
1242 
1243  v_last = v_start;
1244  }
1245  point--;
1246  tags--;
1247  }
1248 
1249  path.move_to( v_start.x, v_start.y );
1250 
1251  while( point < limit )
1252  {
1253  point++;
1254  tags++;
1255 
1256  tag = FT_CURVE_TAG( tags[0] );
1257  switch( tag )
1258  {
1259  case FT_CURVE_TAG_ON: // emit a single line_to
1260  {
1261  path.line_to( point->x, point->y );
1262  continue;
1263  }
1264 
1265  case FT_CURVE_TAG_CONIC: // consume conic arcs
1266  {
1267  v_control.x = point->x;
1268  v_control.y = point->y;
1269 
1270 Do_Conic:
1271  if( point < limit )
1272  {
1273  FT_Vector vec;
1274  FT_Vector v_middle;
1275 
1276  point++;
1277  tags++;
1278  tag = FT_CURVE_TAG( tags[0] );
1279 
1280  vec.x = point->x;
1281  vec.y = point->y;
1282 
1283  if( tag == FT_CURVE_TAG_ON )
1284  {
1285  path.curve3( v_control.x, v_control.y, vec.x, vec.y );
1286  continue;
1287  }
1288 
1289  if( tag != FT_CURVE_TAG_CONIC ) return;
1290 
1291  v_middle.x = ( v_control.x + vec.x ) / 2;
1292  v_middle.y = ( v_control.y + vec.y ) / 2;
1293 
1294  path.curve3( v_control.x, v_control.y, v_middle.x, v_middle.y );
1295 
1296  v_control = vec;
1297  goto Do_Conic;
1298  }
1299  path.curve3( v_control.x, v_control.y, v_start.x, v_start.y );
1300  goto Close;
1301  }
1302 
1303  default: // FT_CURVE_TAG_CUBIC
1304  {
1305  FT_Vector vec1, vec2;
1306 
1307  if( point + 1 > limit || FT_CURVE_TAG( tags[1] ) != FT_CURVE_TAG_CUBIC )
1308  {
1309  return;
1310  }
1311 
1312  vec1.x = point[0].x;
1313  vec1.y = point[0].y;
1314  vec2.x = point[1].x;
1315  vec2.y = point[1].y;
1316 
1317  point += 2;
1318  tags += 2;
1319 
1320  if( point <= limit )
1321  {
1322  FT_Vector vec;
1323 
1324  vec.x = point->x;
1325  vec.y = point->y;
1326 
1327  path.curve4( vec1.x, vec1.y, vec2.x, vec2.y, vec.x, vec.y );
1328  continue;
1329  }
1330 
1331  path.curve4( vec1.x, vec1.y, vec2.x, vec2.y, v_start.x, v_start.y );
1332  goto Close;
1333  }
1334  }
1335  }
1336 
1337  path.close_polygon();
1338 
1339 Close:
1340  first = last + 1;
1341  }
1342 
1343  // scale font to size
1344  a2dAffineMatrix affine;
1345  affine.Scale( scale );
1346  affine.Translate( x, y );
1347  affine = m_usertodevice * affine;
1348 
1349  agg::trans_affine mtx( affine.GetValue( 0, 0 ), affine.GetValue( 0, 1 ),
1350  affine.GetValue( 1, 0 ), affine.GetValue( 1, 1 ),
1351  affine.GetValue( 2, 0 ), affine.GetValue( 2, 1 ) );
1352  agg::conv_transform< agg::path_storage > tr( path, mtx );
1353  agg::conv_curve< agg::conv_transform< agg::path_storage > > stroke( tr );
1354 
1355  agg::rgba8 color( m_colour1redStroke, m_colour1greenStroke, m_colour1blueStroke, m_StrokeOpacityCol1 );
1356  m_rasterizer.reset();
1357  m_rasterizer.add_path( stroke );
1358  m_renderer.color( color );
1359  m_renSolidComp.color( color );
1360  if( m_blendMode == agg::end_of_comp_op_e )
1361  agg::render_scanlines( m_rasterizer, m_sl, m_renderer );
1362  else
1363  agg::render_scanlines( m_rasterizer, m_sl, m_renSolidComp );
1364 
1365 #else // wxART2D_USE_FREETYPE
1366  a2dContext::DrawCharFreetype( c );
1367 #endif // wxART2D_USE_FREETYPE
1368 }
1369 
1370 void a2dAggContext::DrawRoundedRectangle( wxDouble x, wxDouble y, wxDouble width, wxDouble height, wxDouble radius )
1371 {
1372  if ( width == 0 || height == 0 )
1373  return;
1374 
1375  if ( m_pen.IsNull() && m_brush.IsNull() )
1376  return;
1377 
1378  if ( !IsStrokeOnly() )
1379  {
1380  agg::trans_affine mtx = _get_agg_user_to_device_transform();
1381 
1382  if ( fabs( radius ) <= 0.00000001 )
1383  {
1384  plain_rect r( x, y, x + width, y + height );
1385  agg::conv_transform<plain_rect> tr( r, mtx );
1386  m_rasterizer.reset();
1387  m_rasterizer.add_path( tr );
1388  }
1389  else
1390  {
1391  agg::rounded_rect r( x, y, x + width, y + height, radius );
1392  r.normalize_radius();
1393  agg::conv_transform<agg::rounded_rect> tr( r, mtx );
1394  m_rasterizer.reset();
1395  m_rasterizer.add_path( tr );
1396  }
1397  if ( m_activefill.GetType() == a2dFILL_GRADIENT_FILL_LINEAR )
1398  {
1399  RenderGradient( false );
1400  }
1401  else if ( m_activefill.GetType() == a2dFILL_GRADIENT_FILL_RADIAL )
1402  {
1403  RenderGradient( true );
1404  }
1405  else if ( m_activefill.GetType() == a2dFILL_BITMAP ||
1406  ( m_activefill.GetStyle() >= a2dFIRST_HATCH && m_activefill.GetStyle() <= a2dLAST_HATCH ) ||
1407  ( m_activefill.GetStyle() >= a2dFIRST_TWOCOL_HATCH && m_activefill.GetStyle() <= a2dLAST_TWOCOL_HATCH ) )
1408  {
1409  RenderBitmapFill();
1410  }
1411  else
1412  {
1413  Render( true );
1414  }
1415  }
1416 
1417  if ( IsStroked() )
1418  {
1419  if ( fabs( radius ) <= 0.00000001 )
1420  {
1421  plain_rect r( x, y, x + width, y + height );
1422  agg::trans_affine mtx = _get_agg_user_to_device_transform();
1423  m_rasterizer.reset();
1424  _ras_add_stroked_path_xform( r, mtx );
1425  }
1426  else
1427  {
1428  m_rasterizer.reset();
1429  agg::rounded_rect r( x, y, x + width, y + height, radius );
1430  r.normalize_radius();
1431  agg::trans_affine mtx = _get_agg_user_to_device_transform();
1432  _ras_add_stroked_path_xform( r, mtx );
1433  }
1434  Render( false );
1435  }
1436 }
1437 
1438 void a2dAggContext::DrawEllipse( wxDouble x, wxDouble y, wxDouble w, wxDouble h )
1439 {
1440  if ( m_activefill.GetType() == a2dFILL_GRADIENT_FILL_LINEAR || m_activefill.GetType() == a2dFILL_GRADIENT_FILL_RADIAL )
1441  {
1442  a2dContext::DrawEllipse( x, y, w, h );
1443  return;
1444  }
1445 
1446  if ( m_pen.IsNull() && m_brush.IsNull() )
1447  return;
1448 
1449  double dphi;
1450  unsigned int segments;
1451 
1452  //circular approximation of radius.
1453  double radiusDev = m_usertodevice.TransformDistance( wxMax( w, h ) );
1454  Aberration( m_displayaberration, wxPI * 2, radiusDev , dphi, segments );
1455 
1456  agg::trans_affine mtx = _get_agg_user_to_device_transform();
1457 
1458  agg::rgba8 color( m_colour1redFill, m_colour1greenFill, m_colour1blueFill, m_FillOpacityCol1 );
1459  agg::ellipse ellipse( x + w / 2.0, y + h / 2.0, w / 2.0, h / 2.0, segments );
1460 
1461  agg::conv_transform<agg::ellipse> tr( ellipse, mtx );
1462 
1463  if ( !IsStrokeOnly() )
1464  {
1465  m_path.remove_all();
1466  m_path.concat_path( tr, 0 );
1467 
1468  m_rasterizer.reset();
1469  m_rasterizer.add_path( m_path );
1470 
1471  if ( m_activefill.GetType() == a2dFILL_GRADIENT_FILL_LINEAR )
1472  {
1473  RenderGradient( false );
1474  }
1475  else if ( m_activefill.GetType() == a2dFILL_GRADIENT_FILL_RADIAL )
1476  {
1477  RenderGradient( true );
1478  }
1479  else if ( m_activefill.GetType() == a2dFILL_BITMAP ||
1480  ( m_activefill.GetStyle() >= a2dFIRST_HATCH && m_activefill.GetStyle() <= a2dLAST_HATCH ) ||
1481  ( m_activefill.GetStyle() >= a2dFIRST_TWOCOL_HATCH && m_activefill.GetStyle() <= a2dLAST_TWOCOL_HATCH ) )
1482  {
1483  RenderBitmapFill();
1484  }
1485  else
1486  Render( true );
1487  }
1488  if ( IsStroked() )
1489  {
1490  m_rasterizer.reset();
1491  _ras_add_stroked_path_xform( ellipse, mtx );
1492  Render( false );
1493  }
1494 }
1495 
1496 void a2dAggContext::DrawPolygon( const a2dVertexList* list, wxPolygonFillMode fillStyle )
1497 {
1498  if ( m_pen.IsNull() && m_brush.IsNull() )
1499  return;
1500 
1501  int segments = ToAggPath( list, false );
1502 
1503  if ( segments == 0 )
1504  return;
1505 
1506  agg::trans_affine mtx = _get_agg_user_to_device_transform();
1507  if ( IsStrokeOnly() )
1508  {
1509  }
1510  else if ( m_activefill.GetType() == a2dFILL_GRADIENT_FILL_LINEAR )
1511  {
1512  m_path.close_polygon();
1513  agg::conv_transform<agg::path_storage> tr( m_path, mtx );
1514  m_rasterizer.reset();
1515  m_rasterizer.add_path( tr );
1516 
1517  RenderGradient( false );
1518  }
1519  else if ( m_activefill.GetType() == a2dFILL_GRADIENT_FILL_RADIAL )
1520  {
1521  m_path.close_polygon();
1522  agg::conv_transform<agg::path_storage> tr( m_path, mtx );
1523  m_rasterizer.reset();
1524  m_rasterizer.add_path( tr );
1525 
1526  RenderGradient( true );
1527  }
1528  else if ( m_activefill.GetType() == a2dFILL_BITMAP ||
1529  ( m_activefill.GetStyle() >= a2dFIRST_HATCH && m_activefill.GetStyle() <= a2dLAST_HATCH ) ||
1530  ( m_activefill.GetStyle() >= a2dFIRST_TWOCOL_HATCH && m_activefill.GetStyle() <= a2dLAST_TWOCOL_HATCH ) )
1531  {
1532  m_path.close_polygon();
1533  agg::conv_transform<agg::path_storage> tr( m_path, mtx );
1534  m_rasterizer.reset();
1535  m_rasterizer.add_path( tr );
1536 
1537  RenderBitmapFill();
1538  }
1539  else //normal solid case
1540  {
1541  m_path.close_polygon();
1542  agg::conv_transform<agg::path_storage> tr( m_path, mtx );
1543  m_rasterizer.reset();
1544  m_rasterizer.add_path( tr );
1545 
1546  Render( true );
1547  }
1548 
1549  if ( IsStroked() )
1550  {
1551  m_rasterizer.reset();
1552  m_path.close_polygon();
1553  _ras_add_stroked_path_xform( m_path, mtx );
1554 
1555  Render( false );
1556  }
1557 }
1558 
1559 void a2dAggContext::DrawLines( const a2dVertexList* list )
1560 {
1561  if ( m_pen.IsNull() )
1562  return;
1563 
1564  int segments = ToAggPath( list, false );
1565 
1566  if ( segments == 0 )
1567  return;
1568 
1569  agg::trans_affine mtx = _get_agg_user_to_device_transform();
1570  m_rasterizer.reset();
1571  _ras_add_stroked_path_xform( m_path, mtx );
1572  Render( false );
1573 }
1574 
1575 int a2dAggContext::ToAggPath( a2dVertexArray* points, bool transform )
1576 {
1577  unsigned int segments = 0;
1578 
1579  m_path.remove_all();
1580 
1581  unsigned int count = 0;
1582  double x, y, lastx, lasty;
1583  int i;
1584  for ( i = 0; i < points->size(); i++ )
1585  {
1586  const a2dLineSegmentPtr seg = points->Item( i );
1587 
1588  if ( !seg->GetArc() )
1589  {
1590  if ( transform )
1591  m_usertodevice.TransformPoint( seg->m_x, seg->m_y, x, y );
1592  else
1593  {
1594  x = seg->m_x;
1595  y = seg->m_y;
1596  }
1597 
1598  //to reduce the points count for lines or a polygon on the screen
1599  if( !count || fabs( x - lastx ) > 0.001 || fabs( y - lasty ) > 0.001 )
1600  {
1601  if ( count == 0 )
1602  m_path.move_to( x, y );
1603  else
1604  m_path.line_to( x, y );
1605  lastx = x;
1606  lasty = y;
1607  count++;
1608  }
1609  }
1610  else
1611  {
1612  const a2dArcSegment* cseg = ( const a2dArcSegment* ) seg.Get();
1613 
1614  double radius, center_x, center_y, beginrad, midrad, endrad, phit;
1615 
1616  if ( cseg->CalcR( *( points->Item( i ? i - 1 : 0 ) ), radius, center_x, center_y, beginrad, midrad, endrad, phit ) )
1617  {
1618  double dphi;
1619  unsigned int segments;
1620  double radiusDev = m_usertodevice.TransformDistance( radius );
1621  Aberration( m_displayaberration, phit, radiusDev , dphi, segments );
1622 
1623  double theta = beginrad;
1624  unsigned int step;
1625 
1626  double x, y;
1627  for ( step = 0; step < segments + 1; step++ )
1628  {
1629  if ( transform )
1630  m_usertodevice.TransformPoint( center_x + radius * cos ( theta ), center_y + radius * sin ( theta ), x, y );
1631  else
1632  {
1633  x = center_x + radius * cos ( theta );
1634  y = center_y + radius * sin ( theta );
1635  }
1636  //to reduce the points count for lines or a polygon on the screen
1637  if( !count || fabs( x - lastx ) > 0.001 || fabs( y - lasty ) > 0.001 )
1638  {
1639  if ( count == 0 )
1640  m_path.move_to( x, y );
1641  else
1642  m_path.line_to( x, y );
1643 
1644  lastx = x;
1645  lasty = y;
1646  count++;
1647  }
1648  theta = theta + dphi;
1649  }
1650  }
1651  else
1652  {
1653  double x, y;
1654  if ( transform )
1655  m_usertodevice.TransformPoint( cseg->m_x, cseg->m_y, x, y );
1656  else
1657  {
1658  x = cseg->m_x;
1659  y = cseg->m_y;
1660  }
1661 
1662  //to reduce the points count for lines or a polygon on the screen
1663  if( !count || fabs( x - lastx ) > 0.001 || fabs( y - lasty ) > 0.001 )
1664  {
1665  if ( count == 0 )
1666  m_path.move_to( x, y );
1667  else
1668  m_path.line_to( x, y );
1669  lastx = x;
1670  lasty = y;
1671  count++;
1672  }
1673  }
1674  }
1675  }
1676 
1677  return count;
1678 }
1679 
1680 int a2dAggContext::ToAggPath( const a2dVertexList* list, bool transform )
1681 {
1682  unsigned int segments = 0;
1683 
1684  if ( list->empty() )
1685  return 0;
1686 
1687  m_path.remove_all();
1688 
1689  a2dVertexList::const_iterator iterprev = list->end();
1690 
1691  unsigned int count = 0;
1692  double x, y, lastx, lasty;
1693  iterprev = list->end();
1694  if ( iterprev != list->begin() )
1695  iterprev--;
1696  a2dVertexList::const_iterator iter = list->begin();
1697  iter = list->begin();
1698  while ( iter != list->end() )
1699  {
1700  a2dLineSegment* seg = ( *iter );
1701 
1702  if ( !seg->GetArc() )
1703  {
1704  if ( transform )
1705  m_usertodevice.TransformPoint( seg->m_x, seg->m_y, x, y );
1706  else
1707  {
1708  x = seg->m_x;
1709  y = seg->m_y;
1710  }
1711 
1712  //to reduce the points count for lines or a polygon on the screen
1713  if( !count || fabs( x - lastx ) > 0.001 || fabs( y - lasty ) > 0.001 )
1714  {
1715  if ( count == 0 )
1716  m_path.move_to( x, y );
1717  else
1718  m_path.line_to( x, y );
1719  lastx = x;
1720  lasty = y;
1721  count++;
1722  }
1723  }
1724  else
1725  {
1726  a2dArcSegment* cseg = ( a2dArcSegment* ) seg;
1727 
1728  double radius, center_x, center_y, beginrad, midrad, endrad, phit;
1729 
1730  if ( cseg->CalcR( *( *iterprev ), radius, center_x, center_y, beginrad, midrad, endrad, phit ) )
1731  {
1732  double dphi;
1733  unsigned int segments;
1734  double radiusDev = m_usertodevice.TransformDistance( radius );
1735  Aberration( m_displayaberration, phit, radiusDev , dphi, segments );
1736 
1737  double theta = beginrad;
1738  unsigned int step;
1739 
1740  double x, y;
1741  for ( step = 0; step < segments + 1; step++ )
1742  {
1743  if ( transform )
1744  m_usertodevice.TransformPoint( center_x + radius * cos ( theta ), center_y + radius * sin ( theta ), x, y );
1745  else
1746  {
1747  x = center_x + radius * cos ( theta );
1748  y = center_y + radius * sin ( theta );
1749  }
1750 
1751  //to reduce the points count for lines or a polygon on the screen
1752  if( !count || fabs( x - lastx ) > 0.001 || fabs( y - lasty ) > 0.001 )
1753  {
1754  if ( count == 0 )
1755  m_path.move_to( x, y );
1756  else
1757  m_path.line_to( x, y );
1758  lastx = x;
1759  lasty = y;
1760  count++;
1761  }
1762  theta = theta + dphi;
1763  }
1764  }
1765  else
1766  {
1767  double x, y;
1768  if ( transform )
1769  m_usertodevice.TransformPoint( cseg->m_x, cseg->m_y, x, y );
1770  else
1771  {
1772  x = cseg->m_x;
1773  y = cseg->m_y;
1774  }
1775 
1776  //to reduce the points count for lines or a polygon on the screen
1777  if( !count || fabs( x - lastx ) > 0.001 || fabs( y - lasty ) > 0.001 )
1778  {
1779  if ( count == 0 )
1780  m_path.move_to( x, y );
1781  else
1782  m_path.line_to( x, y );
1783  lastx = x;
1784  lasty = y;
1785  count++;
1786  }
1787  }
1788  }
1789  iterprev = iter++;
1790  }
1791 
1792  return count;
1793 }
1794 
1795 /*******************************************************************
1796 a2dGcAggDrawer
1797 ********************************************************************/
1798 IMPLEMENT_DYNAMIC_CLASS( a2dGcAggDrawer, a2dGcBaseDrawer )
1799 
1800 void a2dGcAggDrawer::InitContext()
1801 {
1802  m_clip.Clear();
1803  m_buffer = a2dImageRGBA( m_width, m_height );
1804  m_pdata = m_buffer.GetData();
1805  m_render = new a2dRenderer();
1806  m_context = new a2dAggContext( m_render, &m_buffer );
1807 }
1808 
1809 a2dGcAggDrawer::a2dGcAggDrawer( const wxSize& size ): a2dGcBaseDrawer( size.GetWidth(), size.GetHeight() )
1810 {
1811  InitContext();
1812 }
1813 
1814 a2dGcAggDrawer::a2dGcAggDrawer( int width, int height ): a2dGcBaseDrawer( width, height )
1815 {
1816  InitContext();
1817 }
1818 
1819 a2dGcAggDrawer::a2dGcAggDrawer( const a2dGcAggDrawer& other )
1820  : a2dGcBaseDrawer( other )
1821 {
1822  InitContext();
1823 }
1824 
1825 a2dGcAggDrawer::a2dGcAggDrawer( const a2dDrawer2D& other )
1826  : a2dGcBaseDrawer( other )
1827 {
1828  InitContext();
1829 }
1830 
1831 a2dGcAggDrawer::~a2dGcAggDrawer()
1832 {
1833  delete m_context;
1834  delete m_render;
1835 }
1836 
1837 void a2dGcAggDrawer::SetYaxis( bool up )
1838 {
1839  a2dDrawer2D::SetYaxis( up );
1840  //static_cast<a2dAggContext*>(m_context)->SetYaxis( up );
1841 }
1842 
1843 wxBitmap a2dGcAggDrawer::GetBuffer() const
1844 {
1845  return wxBitmap( m_buffer.GetImage() );
1846 }
1847 
1848 void a2dGcAggDrawer::SetBufferSize( int w, int h )
1849 {
1850  a2dImageRGBA newbuf( w, h );
1851 
1852  int old_pixelwidth = m_width * 4;
1853  int new_pixelwidth = w * 4;
1854  int pixelwidth = wxMin( w, m_width ) * 4;
1855  int minheight = wxMin( h, m_height );
1856 
1857  //pixel coordinates so ( 0,0 ) upper left
1858  unsigned char* oldpdata = m_pdata;
1859  unsigned char* newpdata = newbuf.GetData();
1860 
1861  for ( int yp = 0; yp < minheight; yp++ )
1862  {
1863  memcpy( newpdata, oldpdata, pixelwidth );
1864  oldpdata += old_pixelwidth;
1865  newpdata += new_pixelwidth;
1866  }
1867 
1868  m_width = w;
1869  m_height = h;
1870  m_buffer = newbuf;
1871 
1872  m_pdata = m_buffer.GetData();
1873  DestroyClippingRegion();
1874  delete m_context;
1875  m_context = new a2dAggContext( m_render, &m_buffer );
1876 }
1877 
1878 wxBitmap a2dGcAggDrawer::GetSubBitmap( wxRect rect ) const
1879 {
1880  return wxBitmap( m_buffer.GetImage().GetSubImage( rect ) );
1881 }
1882 
1883 void a2dGcAggDrawer::CopyIntoBuffer( const wxBitmap& bitm )
1884 {
1885  m_buffer = a2dImageRGBA( bitm.ConvertToImage() );
1886 }
1887 
1888 void a2dGcAggDrawer::BlitBuffer( wxDC* dc, wxRect rect, const wxPoint& bufferpos )
1889 {
1890  // clip to buffer
1891  if ( rect.x < 0 )
1892  {
1893  rect.width += rect.x;
1894  rect.x = 0;
1895  }
1896  if ( rect.width <= 0 ) return;
1897 
1898  if ( rect.y < 0 )
1899  {
1900  rect.height += rect.y;
1901  rect.y = 0;
1902  }
1903  if ( rect.height <= 0 ) return;
1904 
1905  if ( rect.x + rect.width >= m_width )
1906  rect.width = m_width - rect.x;
1907 
1908  if ( rect.width <= 0 ) return;
1909 
1910  if ( rect.y + rect.height >= m_height )
1911  rect.height = m_height - rect.y;
1912 
1913  if ( rect.height <= 0 ) return;
1914 
1915  int xmax = rect.x + rect.width;
1916  int ymax = rect.y + rect.height;
1917 
1918  a2dImageRGBA* subImage = m_buffer.GetSubImage( rect );
1919  wxBitmap subbitmap = subImage->CreateBitmap();
1920  delete subImage;
1921 
1922  wxMemoryDC mdc;
1923  mdc.SelectObject( subbitmap );
1924 
1925  dc->Blit( rect.x - bufferpos.x, rect.y - bufferpos.y, xmax - rect.x, ymax - rect.y, &mdc, 0, 0, wxCOPY, false );
1926 
1927  mdc.SelectObject( wxNullBitmap );
1928 }
1929 
1930 void a2dGcAggDrawer::ShiftBuffer( int dxy, bool yshift )
1931 {
1932  if ( yshift )
1933  {
1934  int pixelwidth = m_width * 4;
1935  //pixel coordinates so ( 0,0 ) upper left
1936  if ( dxy > 0 && dxy < m_height )
1937  {
1938  unsigned char* highline = m_pdata + ( m_height - dxy ) * pixelwidth ;
1939  unsigned char* lowline = m_pdata + m_height * pixelwidth ;
1940 
1941  for ( int yp = 0; yp < m_height - dxy; yp++ )
1942  {
1943  highline -= pixelwidth;
1944  lowline -= pixelwidth;
1945  memcpy( lowline, highline, pixelwidth );
1946  }
1947  }
1948  else if ( dxy < 0 && dxy > -m_height )
1949  {
1950  dxy = -dxy;
1951  unsigned char* highline = m_pdata;
1952  unsigned char* lowline = m_pdata + dxy * pixelwidth ;
1953 
1954  for ( int yp = 0; yp < m_height - dxy ; yp++ )
1955  {
1956  memcpy( highline, lowline, pixelwidth );
1957  highline += pixelwidth;
1958  lowline += pixelwidth;
1959  }
1960  }
1961  else
1962  wxFAIL_MSG( wxT( "you can only shift within height of buffer" ) );
1963  }
1964  else
1965  {
1966  int pixelwidth = m_width * 4;
1967  if ( dxy > 0 && dxy < m_width )
1968  {
1969  int subwidth = ( m_width - dxy ) * 4;
1970  unsigned char* low = m_pdata;
1971  unsigned char* high = m_pdata + dxy * 4 ;
1972 
1973  for ( int yp = 0; yp < m_height ; yp++ )
1974  {
1975  memcpy( high, low, subwidth );
1976  high += pixelwidth;
1977  low += pixelwidth;
1978  }
1979  }
1980  else if ( dxy < 0 && dxy > -m_width )
1981  {
1982  dxy = -dxy;
1983  int subwidth = ( m_width - dxy ) * 4;
1984  unsigned char* low = m_pdata;
1985  unsigned char* high = m_pdata + dxy * 4 ;
1986 
1987  for ( int yp = 0; yp < m_height ; yp++ )
1988  {
1989  memcpy( low, high, subwidth );
1990  high += pixelwidth;
1991  low += pixelwidth;
1992  }
1993  }
1994  else
1995  wxFAIL_MSG( wxT( "you can only shift within width of buffer" ) );
1996  }
1997 }
1998 
1999 void a2dGcAggDrawer::DoSetActiveStroke()
2000 {
2001  if ( 1 )
2002  {
2003  // a2dRenderer render class does understand a2dStroke and a2dFill,
2004  // so we will have a2dSTROKE_STIPPLE_MASK_OPAQUE_TRANSPARENT available, else lost.
2005  a2dRenderer* render = ( a2dRenderer* ) m_render;
2006  a2dContext* context = ( a2dContext* ) m_context;
2007  wxGraphicsPen p = render->CreateStroke( m_activestroke );
2008  m_context->SetPen( p );
2009  }
2010  else
2011  {
2012  a2dGcBaseDrawer::DoSetActiveStroke();
2013  }
2014 }
2015 
2016 void a2dGcAggDrawer::DoSetActiveFill()
2017 {
2018  if ( 1 )
2019  {
2020  // a2dRenderer render class does understand a2dStroke and a2dFill,
2021  // so we will have a2dSTROKE_STIPPLE_MASK_OPAQUE_TRANSPARENT available, else lost.
2022  a2dRenderer* render = ( a2dRenderer* ) m_render;
2023  a2dContext* context = ( a2dContext* ) m_context;
2024  wxGraphicsBrush b = render->CreateFill( m_activefill );
2025  m_context->SetBrush( b );
2026  }
2027  else
2028  {
2029  a2dGcBaseDrawer::DoSetActiveFill();
2030  }
2031 }
2032 
2033 void a2dGcAggDrawer::DoSetActiveFont( const a2dFont& font )
2034 {
2035  a2dContext* context = ( a2dContext* ) m_context;
2036  a2dRenderer* render = ( a2dRenderer* ) m_render;
2037  wxGraphicsFont f = render->CreateFont( font );
2038  context->SetFont( font );
2039 }
2040 
2041 void a2dGcAggDrawer::DrawPoint( double xc, double yc )
2042 {
2043  if ( m_disableDrawing )
2044  return;
2045 
2046  double xt, yt;
2047  GetUserToDeviceTransform().TransformPoint( xc, yc, xt, yt );
2048  //DeviceDrawPixel( xt, yt, m_colour1redStroke, m_colour1greenStroke, m_colour1blueStroke, m_StrokeOpacityCol1 );
2049 }
2050 
2051 void a2dGcAggDrawer::DrawImage( const wxImage& imagein, double x, double y, double width, double height, wxUint8 Opacity )
2052 {
2053  if ( m_disableDrawing )
2054  return;
2055 
2056  a2dAffineMatrix affine;
2057  if ( GetYaxis() )
2058  {
2059  affine.Translate( 0.0, -( y ) );
2060  affine.Mirror( true, false );
2061  affine.Translate( 0.0, y );
2062  }
2063  PushTransform( affine );
2064 
2065  a2dContext* context = ( a2dContext* ) m_context;
2066  a2dRenderer* render = ( a2dRenderer* ) m_render;
2067  wxGraphicsBitmap bitmap = render->CreateBitmap( imagein );
2068 #if wxCHECK_VERSION(2,9,0)
2069  m_context->DrawBitmap( bitmap, x, y, width, height );
2070 #else
2071  context->DrawGraphicsBitmap( bitmap, x, y, width, height );
2072 #endif
2073 
2074  PopTransform();
2075 }
2076 
2077 void a2dGcAggDrawer::DrawImage( const a2dImageRGBA& image, double x, double y, double width, double height, wxUint8 Opacity )
2078 {
2079  if ( m_disableDrawing )
2080  return;
2081 
2082  a2dContext* context = ( a2dContext* ) m_context;
2083  a2dRenderer* render = ( a2dRenderer* ) m_render;
2084  wxImage wximage = image.GetImage();
2085  wxGraphicsBitmap bitmap = render->CreateBitmap( wximage );
2086 #if wxCHECK_VERSION(2,9,0)
2087  m_context->DrawBitmap( bitmap, x - width / 2.0, y - height / 2.0, width, height );
2088 #else
2089  context->DrawGraphicsBitmap( bitmap, x - width / 2.0, y - height / 2.0, width, height );
2090 #endif
2091 }
2092 
2093 /* HANDLED IN m_context
2094 void a2dGcAggDrawer::DrawCharDc( wxChar c )
2095 {
2096  wxGraphicsMatrix m = m_context->CreateMatrix();
2097  m.Set(
2098  m_usertodevice( 0, 0), m_usertodevice( 0, 1),
2099  m_usertodevice( 1, 0), m_usertodevice( 1, 1),
2100  m_usertodevice( 2, 0), m_usertodevice( 2, 1) );
2101  m_context->SetTransform( m );
2102 
2103  static_cast<a2dAggContext*>(m_context)->DrawCharDc( c );
2104 }
2105 
2106 //! \bug EW: DrawCharFreetype crashes when zoomed in extremely far.
2107 void a2dGcAggDrawer::DrawCharFreetype( wxChar c )
2108 {
2109  wxGraphicsMatrix m = m_context->CreateMatrix();
2110  m.Set(
2111  m_usertodevice( 0, 0), m_usertodevice( 0, 1),
2112  m_usertodevice( 1, 0), m_usertodevice( 1, 1),
2113  m_usertodevice( 2, 0), m_usertodevice( 2, 1) );
2114  m_context->SetTransform( m );
2115  static_cast<a2dAggContext*>(m_context)->DrawCharFreetype( c );
2116 }
2117 */
2118 
2119 
2120 #endif // wxART2D_USE_GRAPHICS_CONTEXT
2121 
2122 #endif //wxART2D_USE_AGGDRAWER
2123 
virtual void SetYaxis(bool up)
set if the Yaxis goes up or down
Definition: drawer2d.cpp:438
wxPoint2DDouble a2dPoint2D
this to define if coordinate numbers are integer or doubles
Definition: artglob.h:47
a2dAffineMatrix & Mirror(bool y=true, bool x=false)
mirror a matrix in x, y
Definition: afmatrix.cpp:396
const a2dStroke * a2dBLACK_STROKE
global a2dStroke stock object for BLACK stroking
Stroke and fill base classes.
Defines a font to be set to a2dDrawer2D or stored in a2dCanvsObject etc.
Definition: stylebase.h:779
Arc Segment in a2dVertexList.
Definition: polyver.h:371
vertex array of line and arc segments.
Definition: polyver.h:494
vertex list of line and arc segments.
Definition: polyver.h:600
double TransformDistance(double distance) const
Transform a distance.
Definition: afmatrix.cpp:616
a2dDrawStyle
Define the manner in which a2dCanvasView draws to the device.
Definition: artglob.h:280
bool CalcR(const a2dLineSegment &prev, double &radius, double &center_x, double &center_y, double &beginrad, double &midrad, double &endrad, double &phit) const
Calculation of center for the Arc.
Definition: polyver.cpp:411
Drawing context abstraction.
Definition: drawer2d.h:177
Normal straight line segment in a2dVertexList and a2dVertexArray.
Definition: polyver.h:163
agg::renderer_base< PixFormatA > RendererBaseA
base rendering Agg
Definition: aggdrawer.h:138
A 2x3 affine matrix class for 2D transformations.
Definition: afmatrix.h:53
agg::rgba8 color_type
color format in a2dAggDrawer
Definition: aggdrawer.h:112
double m_x
x endpoint of line
Definition: polyver.h:232
used in freetype rendering
Definition: dcdrawer.cpp:2165
double m_y
y endpoint of line
Definition: polyver.h:235
void Aberration(double aber, double angle, double radius, double &dphi, unsigned int &segments)
calculate number of segments in an arc such that a certain accuracy is maintained ...
Definition: artglob.cpp:67
bool Scale(double scale)
Scale by scale (isotropic scaling i.e. the same in x and y):
Definition: afmatrix.cpp:270
bool Translate(double x, double y)
Translate by dx, dy:
Definition: afmatrix.cpp:420
bool Invert(void)
Invert matrix.
Definition: afmatrix.cpp:197
const double wxPI
defines PI
Definition: artglob.cpp:28
const a2dFill * a2dTRANSPARENT_FILL
global a2dFill stock object for TRANSPARENT filling
graphicagg.cpp Source File -- Sun Oct 12 2014 17:04:21 -- Sun Oct 12 2014 -- 1.8.5 -- wxArt2D -- . -- Main Page Reference Documentation