PLplot  5.10.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
wxwidgets_agg.cpp
Go to the documentation of this file.
1 // $Id: wxwidgets_agg.cpp 12334 2013-05-04 16:43:33Z airwin $
2 //
3 // Copyright (C) 2008 Werner Smekal
4 //
5 // This file is part of PLplot.
6 //
7 // PLplot is free software; you can redistribute it and/or modify
8 // it under the terms of the GNU Library General Public License as published
9 // by the Free Software Foundation; either version 2 of the License, or
10 // (at your option) any later version.
11 //
12 // PLplot is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Library General Public License for more details.
16 //
17 // You should have received a copy of the GNU Library General Public License
18 // along with PLplot; if not, write to the Free Software
19 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 //
21 
22 // TODO:
23 // - let the AGG library process the text. In the moment most of the relevant code
24 // is commented out, since there are problems with the affine transformation
25 //
26 
27 // wxwidgets headers
28 #include <wx/wx.h>
29 #include <wx/strconv.h>
30 
31 #include "plDevs.h"
32 
33 // plplot headers
34 #include "plplotP.h"
35 #include "plfci-truetype.h"
36 
37 // std and driver headers
38 #include "wxwidgets.h"
39 #include <wchar.h>
40 
41 // helper functions
42 #if !defined ( WIN32 ) || defined ( __GNUC__ )
43  #include <unistd.h>
44 #else
45  #define F_OK 1
46  #include <stdio.h>
47 int access( char *filename, int flag )
48 {
49  FILE *infile;
50  infile = fopen( filename, "r" );
51  if ( infile != NULL )
52  {
53  fclose( infile );
54  return 0;
55  }
56  else
57  return 1;
58 }
59 #endif
60 
61 #define makeunixslash( b ) do { char *I; for ( I = b; *I != 0; *I++ ) if ( *I == '\\' ) *I = '/';} while ( 0 )
62 
63 //--------------------------------------------------------------------------
64 // wxPLDevAGG::wxPLDevAGG()
65 //
66 // Constructor of the AGG wxWidgets device based on the wxPLDevBase
67 // class. Initialisations of variables and objects are done.
68 //--------------------------------------------------------------------------
69 wxPLDevAGG::wxPLDevAGG() :
71  mRenderingBuffer(),
72  mPixFormat( mRenderingBuffer ),
73  mRendererBase( mPixFormat ),
74  mRendererSolid( mRendererBase ),
75 
76  mPath(),
77  mTransform(),
78  mConvCurve( mPath ),
79  mConvStroke( mConvCurve ),
80  mPathTransform( mConvCurve, mTransform ),
81  mStrokeTransform( mConvStroke, mTransform ),
82 
83  mFontEngine(),
84  mFontManager( mFontEngine ),
85  mCurves( mFontManager.path_adaptor() ),
86  mContour( mCurves ),
87 
88  mBuffer( NULL ),
89  mStrokeWidth( 1.0 ),
90  mStrokeOpacity( 255 ),
91  mColorRedStroke( 255 ),
92  mColorGreenStroke( 255 ),
93  mColorBlueStroke( 255 ),
94  mColorRedFill( 0 ),
95  mColorGreenFill( 0 ),
96  mColorBlueFill( 0 )
97 {
98  mCurves.approximation_scale( 2.0 );
99  mContour.auto_detect_orientation( false );
100  mConvStroke.line_join( agg::round_join );
101  mConvStroke.line_cap( agg::round_cap );
102 
103  // determine font directory
104 #if defined ( WIN32 )
105  //static char *default_font_names[]={"arial.ttf","times.ttf","timesi.ttf","arial.ttf",
106  // "symbol.ttf"};
107  // char WINDIR_PATH[255];
108  // char *b;
109  // b=getenv("WINDIR");
110  // strncpy(WINDIR_PATH,b,255);
111 
112 //
113 // Work out if we have Win95+ or Win3.?... sort of.
114 // Actually, this just tries to find the place where the fonts live by looking
115 // for arial, which should be on all windows machines.
116 // At present, it only looks in two places, on one drive. I might change this
117 // soon.
118 //
119  //if (WINDIR_PATH==NULL)
120  // {
121  // if (access("c:\\windows\\fonts\\arial.ttf", F_OK)==0) {
122  // strcpy(font_dir,"c:/windows/fonts/");
123  // }
124  // else if ( access("c:\\windows\\system\\arial.ttf", F_OK)==0) {
125  // strcpy(font_dir,"c:/windows/system/");
126  // }
127  // else
128  // plwarn("Could not find font path; I sure hope you have defined fonts manually !");
129  // }
130  // else
131  // {
132  // strncat(WINDIR_PATH,"\\fonts\\arial.ttf",255);
133  // if (access(WINDIR_PATH, F_OK)==0)
134  // {
135  // b=strrchr(WINDIR_PATH,'\\');
136  // b++;
137  //b=0;
138  // makeunixslash(WINDIR_PATH);
139  // strcpy(font_dir,WINDIR_PATH);
140  // }
141  // else
142  // plwarn("Could not find font path; I sure hope you have defined fonts manually !");
143  // }
144  //
145  // if (pls->debug) fprintf( stderr, "%s\n", font_dir ) ;
146 #else
147  // For Unix systems, we will set the font path up a little differently in
148  // that the configured PL_FREETYPE_FONT_DIR has been set as the default path,
149  // but the user can override this by setting the environmental variable
150  // "PLPLOT_FREETYPE_FONT_DIR" to something else.
151  // NOTE WELL - the trailing slash must be added for now !
152  //
153  // const char *str;
154  //
155  // fontdir.Clear();
156  // if( (str=getenv("PLPLOT_FREETYPE_FONT_DIR"))!=NULL )
157  // fontdir.Append( wxString(str, wxConvFile) );
158  // else
159  // fontdir.Append( wxT(PL_FREETYPE_FONT_DIR) );
160  //
161  // //printf("fontdir=%s, len=%d\n", fontdir.c_str(), fontdir.Length() );
162 #endif
163 }
164 
165 
166 //--------------------------------------------------------------------------
167 // wxPLDevAGG::~wxPLDevAGG()
168 //
169 // Deconstructor frees allocated buffer.
170 //--------------------------------------------------------------------------
171 wxPLDevAGG::~wxPLDevAGG()
172 {
173  if ( ownGUI )
174  if ( mBuffer )
175  delete mBuffer;
176 }
177 
178 
179 //--------------------------------------------------------------------------
180 // void wxPLDevAGG::drawPath( drawPathFlag flag )
181 //
182 // Common function which either draws a stroke along a path or a filled
183 // polygon surrounded by a stroke depending on flag.
184 //--------------------------------------------------------------------------
185 void wxPLDevAGG::drawPath( drawPathFlag flag )
186 {
187  mRasterizer.reset();
188 
189  switch ( flag )
190  {
191  case Stroke:
192  if ( mStrokeOpacity && mStrokeWidth > 0.0 )
193  {
194  mConvStroke.width( mStrokeWidth );
195  mRasterizer.add_path( mStrokeTransform );
196  mRendererSolid.color( agg::rgba8( mColorRedStroke, mColorGreenStroke, mColorBlueStroke, mStrokeOpacity ) );
197  agg::render_scanlines( mRasterizer, mScanLine, mRendererSolid );
198  }
199  break;
200  case FillAndStroke:
201  if ( mStrokeOpacity )
202  {
203  mRasterizer.add_path( mPathTransform );
204  mRendererSolid.color( agg::rgba8( mColorRedStroke, mColorGreenStroke, mColorBlueStroke, mStrokeOpacity ) );
205  agg::render_scanlines( mRasterizer, mScanLine, mRendererSolid );
206  }
207 
208  if ( mStrokeOpacity && mStrokeWidth > 0.0 )
209  {
210  mConvStroke.width( mStrokeWidth );
211  mRasterizer.add_path( mStrokeTransform );
212  mRendererSolid.color( agg::rgba8( mColorRedStroke, mColorGreenStroke, mColorBlueStroke, mStrokeOpacity ) );
213  agg::render_scanlines( mRasterizer, mScanLine, mRendererSolid );
214  }
215  break;
216  }
217 }
218 
219 
220 //--------------------------------------------------------------------------
221 // void wxPLDevAGG::DrawLine( short x1a, short y1a, short x2a, short y2a )
222 //
223 // Draw a line from (x1a, y1a) to (x2a, y2a).
224 //--------------------------------------------------------------------------
225 void wxPLDevAGG::DrawLine( short x1a, short y1a, short x2a, short y2a )
226 {
227  mPath.remove_all();
228  mPath.move_to( x1a, y1a );
229  mPath.line_to( x2a, y2a );
230 
231  if ( !resizing && ownGUI )
232  AGGAddtoClipRegion( x1a, y1a, x2a, y2a );
233 
234  drawPath( Stroke );
235 }
236 
237 
238 //--------------------------------------------------------------------------
239 // void wxPLDevAGG::DrawPolyline( short *xa, short *ya, PLINT npts )
240 //
241 // Draw a poly line - coordinates are in the xa and ya arrays.
242 //--------------------------------------------------------------------------
243 void wxPLDevAGG::DrawPolyline( short *xa, short *ya, PLINT npts )
244 {
245  mPath.remove_all();
246  mPath.move_to( xa[0], ya[0] );
247  for ( PLINT i = 1; i < npts; i++ )
248  {
249  mPath.line_to( xa[i], ya[i] );
250  if ( !resizing && ownGUI )
251  AGGAddtoClipRegion( xa[i - 1], ya[i - 1], xa[i], ya[i] );
252  }
253 
254  drawPath( Stroke );
255 }
256 
257 
258 //--------------------------------------------------------------------------
259 // void wxPLDevAGG::ClearBackground( PLINT bgr, PLINT bgg, PLINT bgb,
260 // PLINT x1, PLINT y1, PLINT x2, PLINT y2 )
261 //
262 // Clear parts ((x1,y1) to (x2,y2)) of the background in color (bgr,bgg,bgb).
263 //--------------------------------------------------------------------------
264 void wxPLDevAGG::ClearBackground( PLINT bgr, PLINT bgg, PLINT bgb, PLINT x1, PLINT y1, PLINT x2, PLINT y2 )
265 {
266  if ( x1 < 0 && y1 < 0 && x2 < 0 && y2 < 0 )
267  {
268  mRendererBase.clear( agg::rgba8( bgr, bgg, bgb ) );
269  if ( !resizing && ownGUI )
270  AddtoClipRegion( 0, 0, width, height );
271  }
272  else
273  {
274  mPath.remove_all();
275  mPath.move_to( x1, y1 );
276  mPath.line_to( x2, y1 );
277  mPath.line_to( x2, y2 );
278  mPath.line_to( x1, y2 );
279  mPath.close_polygon();
280 
281  mRasterizer.reset();
282  mRasterizer.add_path( mPathTransform );
283  mRendererSolid.color( agg::rgba8( bgr, bgg, bgb, 255 ) );
284  agg::render_scanlines( mRasterizer, mScanLine, mRendererSolid );
285 
286  mConvStroke.width( 1.0 );
287  mRasterizer.add_path( mStrokeTransform );
288  mRendererSolid.color( agg::rgba8( bgr, bgg, bgb, 255 ) );
289  agg::render_scanlines( mRasterizer, mScanLine, mRendererSolid );
290 
291  if ( !resizing && ownGUI )
292  AGGAddtoClipRegion( x1, y1, x2, y2 );
293  }
294 }
295 
296 
297 //--------------------------------------------------------------------------
298 // void wxPLDevAGG::AGGAddtoClipRegion( short x1, short y1,
299 // short x2, short y2 )
300 //
301 // Adds the region (x1,y1)-(x2,y2) to the regions which needs to be
302 // updated/redrawn.
303 //--------------------------------------------------------------------------
304 void wxPLDevAGG::AGGAddtoClipRegion( short x1, short y1, short x2, short y2 )
305 {
306  double x1d = x1, x2d = x2, y1d = y1, y2d = y2;
307 
308  mTransform.transform( &x1d, &y1d );
309  mTransform.transform( &x2d, &y2d );
310  AddtoClipRegion( (int) floor( x1d ), (int) floor( y1d ), (int) ceil( x2d ), (int) ceil( y2d ) );
311 }
312 
313 
314 //--------------------------------------------------------------------------
315 // void wxPLDevAGG::FillPolygon( PLStream *pls )
316 //
317 // Draw a filled polygon.
318 //--------------------------------------------------------------------------
319 void wxPLDevAGG::FillPolygon( PLStream *pls )
320 {
321  short *xa = pls->dev_x;
322  short *ya = pls->dev_y;
323 
324  mPath.remove_all();
325  mPath.move_to( xa[0], ya[0] );
326  for ( PLINT i = 1; i < pls->dev_npts; i++ )
327  {
328  mPath.line_to( xa[i], ya[i] );
329  if ( !resizing && ownGUI )
330  AGGAddtoClipRegion( xa[i - 1], ya[i - 1], xa[i], ya[i] );
331  }
332  mPath.line_to( xa[0], ya[0] );
333  mPath.close_polygon();
334 
335  drawPath( FillAndStroke );
336 }
337 
338 
339 //--------------------------------------------------------------------------
340 // void wxPLDevAGG::BlitRectangle( wxDC* dc, int vX, int vY,
341 // int vW, int vH )
342 //
343 // Copy/Blit a rectangle ((vX,vY) to (vX+vW,vY+vH)) into given dc.
344 //--------------------------------------------------------------------------
345 void wxPLDevAGG::BlitRectangle( wxDC* dc, int vX, int vY, int vW, int vH )
346 {
347  if ( mBuffer )
348  {
349  wxMemoryDC MemoryDC;
350  wxBitmap bitmap( mBuffer->GetSubImage( wxRect( vX, vY, vW, vH ) ), -1 );
351  MemoryDC.SelectObject( bitmap );
352  dc->Blit( vX, vY, vW, vH, &MemoryDC, 0, 0 );
353  MemoryDC.SelectObject( wxNullBitmap );
354  }
355 }
356 
357 
358 //--------------------------------------------------------------------------
359 // void wxPLDevAGG::CreateCanvas( void )
360 //
361 // Create canvas (bitmap and dc) if the driver provides the GUI.
362 //--------------------------------------------------------------------------
363 void wxPLDevAGG::CreateCanvas()
364 {
365  if ( ownGUI )
366  {
367  // get a new wxImage (image buffer)
368  if ( mBuffer )
369  delete mBuffer;
370  mBuffer = new wxImage( bm_width, bm_height );
371  mRenderingBuffer.attach( mBuffer->GetData(), bm_width, bm_height, bm_width * 3 );
372  }
373  else
374  mRenderingBuffer.attach( mBuffer->GetData(), width, height, width * 3 );
375 
376  mRendererBase.reset_clipping( true );
377  mTransform.reset();
378  mTransform.premultiply( agg::trans_affine_translation( 0.0, height ) );
379  mTransform.premultiply( agg::trans_affine_scaling( 1.0 / scalex, -1.0 / scaley ) );
380  mStrokeWidth = ( scalex + scaley ) / 2.0;
381 }
382 
383 
384 //--------------------------------------------------------------------------
385 // void wxPLDevAGG::SetWidth( PLStream *pls )
386 //
387 // Set the width of the drawing pen.
388 //--------------------------------------------------------------------------
389 void wxPLDevAGG::SetWidth( PLStream *pls )
390 {
391  mStrokeWidth = ( scalex + scaley ) / 2.0 * ( pls->width > 0 ? pls->width : 1 ); // TODO: why and when ist width 0???
392 }
393 
394 
395 //--------------------------------------------------------------------------
396 // void wxPLDevAGG::SetColor0( PLStream *pls )
397 //
398 // Set color from colormap 0.
399 //--------------------------------------------------------------------------
400 void wxPLDevAGG::SetColor0( PLStream *pls )
401 {
402  mColorRedStroke = pls->curcolor.r;
403  mColorGreenStroke = pls->curcolor.g;
404  mColorBlueStroke = pls->curcolor.b;
405  mStrokeOpacity = (wxUint8) ( pls->curcolor.a * 255 );
406 }
407 
408 
409 //--------------------------------------------------------------------------
410 // void wxPLDevAGG::SetColor1( PLStream *pls )
411 //
412 // Set color from colormap 1.
413 //--------------------------------------------------------------------------
414 void wxPLDevAGG::SetColor1( PLStream *pls )
415 {
416  mColorRedStroke = pls->curcolor.r;
417  mColorGreenStroke = pls->curcolor.g;
418  mColorBlueStroke = pls->curcolor.b;
419  mStrokeOpacity = (wxUint8) ( pls->curcolor.a * 255 );
420 }
421 
422 
423 //--------------------------------------------------------------------------
424 // void wxPLDevAGG::SetExternalBuffer( void* dc )
425 //
426 // Adds a dc to the device. In that case, the drivers doesn't provide
427 // a GUI. A new buffer (image) will be created and set up.
428 //--------------------------------------------------------------------------
429 void wxPLDevAGG::SetExternalBuffer( void* image )
430 {
431  mBuffer = (wxImage *) image; // Add the image to the device
432  mRenderingBuffer.attach( mBuffer->GetData(), width, height, width * 3 );
433 
434  mRendererBase.reset_clipping( true );
435  mTransform.reset();
436  mTransform.premultiply( agg::trans_affine_translation( 0.0, height ) );
437  mTransform.premultiply( agg::trans_affine_scaling( 1.0 / scalex, -1.0 / scaley ) );
438  mStrokeWidth = ( scalex + scaley ) / 2.0;
439 
440  ready = true;
441  ownGUI = false;
442 }
443 
444 
445 #ifdef PL_HAVE_FREETYPE
446 
447 //--------------------------------------------------------------------------
448 // void wxPLDevAGG::PutPixel( short x, short y, PLINT color )
449 //
450 // Draw a pixel in color color @ (x,y).
451 //--------------------------------------------------------------------------
452 void wxPLDevAGG::PutPixel( short x, short y, PLINT color )
453 {
454  mBuffer->SetRGB( x, y, GetRValue( color ), GetGValue( color ), GetBValue( color ) );
455  AddtoClipRegion( x, y, x, y );
456 }
457 
458 
459 //--------------------------------------------------------------------------
460 // void wxPLDevAGG::PutPixel( short x, short y )
461 //
462 // Draw a pixel in current color @ (x,y).
463 //--------------------------------------------------------------------------
464 void wxPLDevAGG::PutPixel( short x, short y )
465 {
466  mBuffer->SetRGB( x, y, mColorRedStroke, mColorGreenStroke, mColorBlueStroke );
467  AddtoClipRegion( x, y, x, y );
468 }
469 
470 
471 //--------------------------------------------------------------------------
472 // PLINT wxPLDevAGG::GetPixel( short x, short y )
473 //
474 // Get color information from pixel @ (x,y).
475 //--------------------------------------------------------------------------
476 PLINT wxPLDevAGG::GetPixel( short x, short y )
477 {
478  return RGB( mBuffer->GetRed( x, y ), mBuffer->GetGreen( x, y ), mBuffer->GetBlue( x, y ) );
479 }
480 
481 #endif // PL_HAVE_FREETYPE
482 
483 
484 void wxPLDevAGG::PSDrawTextToDC( char* utf8_string, bool drawText )
485 {
486  // Log_Verbose( "%s", __FUNCTION__ );
487  printf( "utf8_string=%s\n", utf8_string );
488 
489  double start_x = 0.0;
490  double start_y = 0.0;
491 
492  //wchar_t str[512];
493  //size_t len=wxConvUTF8.ToWChar( str, 512, utf8_string );
494  size_t len = strlen( utf8_string );
495  char * str = utf8_string;
496  printf( "len=%lu\n", (unsigned long) len );
497 
498  const agg::glyph_cache* glyph;
499  if ( !drawText )
500  {
501  double x = 0;
502  double y = 0;
503  bool first = true;
504  char * saveStr = str;
505  while ( *str && len )
506  {
507  glyph = mFontManager.glyph( *str );
508  if ( glyph )
509  {
510  if ( !first )
511  mFontManager.add_kerning( &x, &y );
512  x += glyph->advance_x;
513  y += glyph->advance_y;
514  first = false;
515  }
516  textHeight = textHeight > ( glyph->bounds.y2 - glyph->bounds.y1 + yOffset ) ?
517  textHeight : ( glyph->bounds.y2 - glyph->bounds.y1 + yOffset );
518  ++str; --len;
519  }
520  textWidth = x;
521  printf( "str: %s, textWidth=%lf\n", saveStr, textWidth );
522  }
523  else
524  {
525  for ( size_t i = 0; i < len && str[i]; i++ )
526  {
527  glyph = mFontManager.glyph( str[i] );
528  if ( glyph )
529  {
530  printf( "before: start_x=%f, start_y=%f\n", start_x, start_y );
531  if ( i )
532  mFontManager.add_kerning( &start_x, &start_y );
533  printf( "after: start_x=%f, start_y=%f\n", start_x, start_y );
534  mFontManager.init_embedded_adaptors( glyph, start_x, start_y );
535 
536  mRendererSolid.color( agg::rgba8( mColorRedStroke, mColorGreenStroke, mColorBlueStroke, mStrokeOpacity ) );
537  agg::render_scanlines( mFontManager.gray8_adaptor(), mFontManager.gray8_scanline(), mRendererSolid );
538 
539  start_x += glyph->advance_x / scalex;
540  //start_y += glyph->advance_y/scaley;
541  }
542  }
543  }
544 
545  memset( utf8_string, '\0', max_string_length );
546 }
547 
548 
549 void wxPLDevAGG::PSSetFont( PLUNICODE fci )
550 {
551  // convert the fci to Base14/Type1 font information
552  wxString fontname = fontdir + wxString( plP_FCI2FontName( fci, TrueTypeLookup, N_TrueTypeLookup ), *wxConvCurrent );
553 
554  if ( !mFontEngine.load_font( "/usr/share/fonts/truetype/freefont/FreeSans.ttf", 0, agg::glyph_ren_agg_gray8 ) )
555  plabort( "Font could not be loaded" );
556  //mFontEngine.load_font( "c:\\windows\\fonts\\arial.ttf", 0, agg::glyph_ren_agg_gray8 );
557  mFontEngine.height( fontSize * fontScale );
558  mFontEngine.width( fontSize * fontScale );
559  mFontEngine.hinting( true );
560  mFontEngine.flip_y( false );
561  mContour.width( fontSize * fontScale * 0.2 );
562 }
563 
564 
565 void wxPLDevAGG::ProcessString( PLStream* pls, EscText* args )
566 {
567  plabort( "The AGG backend can't process the text yet own its own!" );
568 
569  // Check that we got unicode, warning message and return if not
570  if ( args->unicode_array_len == 0 )
571  {
572  printf( "Non unicode string passed to a wxWidgets driver, ignoring\n" );
573  return;
574  }
575 
576  // Check that unicode string isn't longer then the max we allow
577  if ( args->unicode_array_len >= 500 )
578  {
579  printf( "Sorry, the wxWidgets drivers only handles strings of length < %d\n", 500 );
580  return;
581  }
582 
583  // Calculate the font size (in pixels)
584  fontSize = pls->chrht * DEVICE_PIXELS_PER_MM * 1.2 * scaley;
585 
586  // calculate rotation of text
587  plRotationShear( args->xform, &rotation, &shear, &stride );
588  rotation -= pls->diorot * M_PI / 2.0;
589  cos_shear = cos( shear );
590  sin_shear = sin( shear );
591 
592  PSDrawText( args->unicode_array, args->unicode_array_len, false );
593  printf( "textWidth=%f, textHeight=%f\n", textWidth, textHeight );
594 
595  agg::trans_affine mtx;
596  mtx.reset();
597  mtx *= agg::trans_affine_translation( args->x, args->y );
598  //mtx *= agg::trans_affine_rotation( rotation );
599  //mtx *= agg::trans_affine_skewing( shear, shear );
600  mtx *= mTransform;
601  mtx *= agg::trans_affine_translation( -args->just * textWidth / scalex, -0.5 * textHeight );
602  mtx *= agg::trans_affine_translation( -args->just * textWidth / scalex, -0.5 * textHeight );
603  mFontEngine.transform( mtx );
604 
605  PSDrawText( args->unicode_array, args->unicode_array_len, true );
606 
607  AddtoClipRegion( 0, 0, width, height );
608 }