PLplot: wxwidgets_agg.cpp Source File

PLplot 5.10.0

- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

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() :
70 wxPLDevBase( wxBACKEND_AGG ),
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 }