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