PLplot  5.10.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
plr.c
Go to the documentation of this file.
1 // $Id: plr.c 12288 2013-01-30 04:40:35Z airwin $
2 //
3 // Copyright 1993, 1994, 1995
4 // Maurice LeBrun
5 // IFS, University of Texas at Austin
6 //
7 // This software may be freely copied, modified and redistributed under the
8 // terms of the GNU Library General Public License.
9 //
10 // There is no warranty or other guarantee of fitness of this software.
11 // It is provided solely "as is". The author(s) disclaim(s) all
12 // responsibility and liability with respect to this software's usage or
13 // its effect upon hardware or computer systems.
14 //
15 //--------------------------------------------------------------------------
16 //
17 // Support routines to render a PLplot byte stream, interpreting the PLplot
18 // metacode.
19 //
20 // Although this code is duplicated to some extent by plrender and the
21 // plot buffer redraw code (in plbuf.c), they are all different in some
22 // significant ways, namely:
23 //
24 // - plrender must always retain backward compatibility code to
25 // handle old metafiles, as well as stuff to support seeking.
26 //
27 // - plbuf by definition is redrawing on the same machine so no
28 // special effort is necessary to make the byte stream portable,
29 // also, only low-level graphics calls are used (grline, etc)
30 //
31 // The rendering code here must (by contrast to plbuf) use the high level
32 // plot routines (as does plrender), to support local zooms as well as the
33 // ability to dump the associated window into plot space to a file, but is
34 // otherwise pretty minimal. A portable byte stream is used since network
35 // communication over a socket may be used.
36 //
37 //--------------------------------------------------------------------------
38 
39 //
40 // #define DEBUG
41 // #define DEBUG_ENTER
42 //
43 
44 #include "plserver.h"
45 #include "plevent.h"
46 #include "metadefs.h"
47 
48 // Some wrapper macros to return (-1) on error
49 
50 // Note we use %lu and an explicit cast to unsigned long to print size_t pointers.
51 // C99 adds %zd as an explicit format specifier for size_t but this is not yet
52 // fully adopted.
53 
54 #define plr_rd( code ) \
55  if ( code ) { fprintf( stderr, \
56  "Unable to read from %s in %s at line %d, bytecount %lu\n", \
57  plr->iodev->typeName, __FILE__, __LINE__, (unsigned long) plr->pdfs->bp ); \
58  return -1; }
59 
60 #define plr_cmd( code ) \
61  if ( ( code ) == -1 ) return -1;
62 
63 // Error termination
64 
65 #define barf( msg ) \
66  { fprintf( stderr, "%s\nCommand code: %d, byte count: %lu\n", \
67  msg, csave, (unsigned long) plr->pdfs->bp ); return -1; }
68 
69 // Static function prototypes.
70 
71 static int plr_process1( PLRDev *plr, int c );
72 static int plr_init( PLRDev *plr );
73 static int plr_line( PLRDev *plr, int c );
74 static int plr_eop( PLRDev *plr );
75 static int plr_bop( PLRDev *plr );
76 static int plr_state( PLRDev *plr );
77 static int plr_esc( PLRDev *plr );
78 static int plr_get( PLRDev *plr );
79 static int plr_unget( PLRDev *plr, U_CHAR c );
80 static int get_ncoords( PLRDev *plr, PLFLT *x, PLFLT *y, PLINT n );
81 static int plresc_fill( PLRDev *plr );
82 
83 // variables
84 
85 static int csave = -1;
89 
90 //--------------------------------------------------------------------------
91 // plr_start()
92 //
93 // Set default state parameters before anyone else has a chance to.
94 //--------------------------------------------------------------------------
95 
96 void
98 {
99  dbug_enter( "plr_start" );
100 
101  plr->xmin = 0;
102  plr->xmax = PIXELS_X - 1;
103  plr->ymin = 0;
104  plr->ymax = PIXELS_Y - 1;
105 
106  plr->xold = PL_UNDEFINED;
107  plr->yold = PL_UNDEFINED;
108 }
109 
110 //--------------------------------------------------------------------------
111 // plr_process()
112 //
113 // Read & process commands until plr->nbytes bytes have been read.
114 //--------------------------------------------------------------------------
115 
116 int
118 {
119  int c;
120 
121  dbug_enter( "plr_process" );
122 
123  while ( plr->pdfs->bp < (size_t) plr->nbytes )
124  {
125  plr_cmd( c = plr_get( plr ) );
126  csave = c;
127  plr_cmd( plr_process1( plr, c ) );
128  }
129  return 0;
130 }
131 
132 //--------------------------------------------------------------------------
133 // plr_process1()
134 //
135 // Process a command. Note: because of line->polyline compression, this
136 // may actually process an arbitrary number of LINE or LINETO commands.
137 // Since the data buffer (fifo or socket) is only flushed after a complete
138 // command, there should be no danger in rushing blindly ahead to execute
139 // each plot command.
140 //--------------------------------------------------------------------------
141 
142 static int
143 plr_process1( PLRDev *plr, int c )
144 {
145  switch ( c )
146  {
147  case INITIALIZE:
148  plr_cmd( plr_init( plr ) );
149  break;
150 
151  case LINE:
152  case LINETO:
153  case POLYLINE:
154  plr_cmd( plr_line( plr, c ) );
155  break;
156 
157  case EOP:
158  plr->at_eop = 1;
159  plr_cmd( plr_eop( plr ) );
160  break;
161 
162  case BOP:
163  plr->at_bop = 1;
164  plr_cmd( plr_bop( plr ) );
165  break;
166 
167  case CHANGE_STATE:
168  plr_cmd( plr_state( plr ) );
169  break;
170 
171  case ESCAPE:
172  plr_cmd( plr_esc( plr ) );
173  break;
174 
175  default:
176  fprintf( stderr, "plr_process1: Unrecognized command code %d\n", c );
177  }
178 
179  return 0;
180 }
181 
182 //--------------------------------------------------------------------------
183 // void plr_init()
184 //
185 // Handle initialization.
186 //--------------------------------------------------------------------------
187 
188 static int
190 {
191  char tk_magic[80], tk_version[80], tag[80];
192 
193  dbug_enter( "plr_init" );
194 
195 // Read header info
196 
197  plr_cmd( pdf_rd_header( plr->pdfs, tk_magic ) );
198  if ( strcmp( tk_magic, PLSERV_HEADER ) )
199  barf( "plr_init: Invalid header" );
200 
201 // Read version field of header. We need to check that we can read the
202 // byte stream, in case this is an old version of plserver.
203 
204  plr_cmd( pdf_rd_header( plr->pdfs, tk_version ) );
205  if ( strcmp( tk_version, PLSERV_VERSION ) > 0 )
206  {
207  fprintf( stderr,
208  "Error: incapable of reading output of version %s.\n", tk_version );
209  barf( "plr_init: Please obtain a newer copy of plserver." );
210  }
211 
212 // Read tagged initialization info.
213 // Overkill, but a no-brainer since plrender already uses this
214 
215  for (;; )
216  {
217  plr_cmd( pdf_rd_header( plr->pdfs, tag ) );
218  if ( *tag == '\0' )
219  break;
220 
221  if ( !strcmp( tag, "xmin" ) )
222  {
223  plr_rd( pdf_rd_2bytes( plr->pdfs, &dum_ushort ) );
224  plr->xmin = (short) dum_ushort;
225  continue;
226  }
227 
228  if ( !strcmp( tag, "xmax" ) )
229  {
230  plr_rd( pdf_rd_2bytes( plr->pdfs, &dum_ushort ) );
231  plr->xmax = (short) dum_ushort;
232  continue;
233  }
234 
235  if ( !strcmp( tag, "ymin" ) )
236  {
237  plr_rd( pdf_rd_2bytes( plr->pdfs, &dum_ushort ) );
238  plr->ymin = (short) dum_ushort;
239  continue;
240  }
241 
242  if ( !strcmp( tag, "ymax" ) )
243  {
244  plr_rd( pdf_rd_2bytes( plr->pdfs, &dum_ushort ) );
245  plr->ymax = (short) dum_ushort;
246  continue;
247  }
248 
249  if ( !strcmp( tag, "width" ) )
250  {
251  plr_rd( pdf_rd_1byte( plr->pdfs, &dum_uchar ) );
252  plwidth( dum_uchar );
253  continue;
254  }
255 
256  barf( "plr_init: Unrecognized initialization tag." );
257  }
258 
259  return 0;
260 }
261 
262 //--------------------------------------------------------------------------
263 // plr_line()
264 //
265 // Draw a line or polyline.
266 //--------------------------------------------------------------------------
267 
268 static int
269 plr_line( PLRDev *plr, int c )
270 {
271  int c1;
272  U_SHORT npts;
273  PLFLT *x, *y;
274 
275  // "Temporary" logic until can figure out what value of npts will
276  // actually be required which would allow use of malloc whenever
277  // that npts value > PL_MAXPOLY.
278  x = xstatic;
279  y = ystatic;
280 
281  npts = 1;
282  x[0] = plr->xold;
283  y[0] = plr->yold;
284 
285  switch ( (int) c )
286  {
287  case LINE:
288  plr_cmd( get_ncoords( plr, x, y, 1 ) );
289  // n.b. falls through to LINETO case.
290 
291  case LINETO:
292  for (;; )
293  {
294  plr_cmd( get_ncoords( plr, x + npts, y + npts, 1 ) );
295 
296  npts++;
297  if ( npts == PL_MAXPOLY || ( plr->pdfs->bp == (size_t) plr->nbytes ) )
298  break;
299 
300  plr_cmd( c1 = plr_get( plr ) );
301  if ( c1 != LINETO )
302  {
303  plr_cmd( plr_unget( plr, (U_CHAR) c1 ) );
304  break;
305  }
306  }
307  break;
308 
309  case POLYLINE:
310  plr_rd( pdf_rd_2bytes( plr->pdfs, &npts ) );
311  plr_cmd( get_ncoords( plr, x, y, npts ) );
312  break;
313  }
314 
315  plline( npts, x, y );
316 
317  plr->xold = x[npts - 1];
318  plr->yold = y[npts - 1];
319 
320  return 0;
321 }
322 
323 //--------------------------------------------------------------------------
324 // get_ncoords()
325 //
326 // Read n coordinate vectors.
327 //--------------------------------------------------------------------------
328 
329 #define plr_rdn( code ) \
330  if ( code ) { fprintf( stderr, \
331  "Unable to read from %s in %s at line %d, bytecount %d\n\
332 Bytes requested: %d\n", plr->iodev->typeName, __FILE__, __LINE__, \
333  (int) plr->pdfs->bp, (int) 2 * n ); return -1; }
334 
335 static int
336 get_ncoords( PLRDev *plr, PLFLT *x, PLFLT *y, PLINT n )
337 {
338  PLINT i;
339  short _xs[PL_MAXPOLY], _ys[PL_MAXPOLY];
340  short *xs, *ys;
341 
342  if ( n > PL_MAXPOLY )
343  {
344  xs = (short *) malloc( sizeof ( short ) * (size_t) n );
345  ys = (short *) malloc( sizeof ( short ) * (size_t) n );
346  }
347  else
348  {
349  xs = _xs;
350  ys = _ys;
351  }
352 
353  plr_rdn( pdf_rd_2nbytes( plr->pdfs, (U_SHORT *) xs, n ) );
354  plr_rdn( pdf_rd_2nbytes( plr->pdfs, (U_SHORT *) ys, n ) );
355 
356  for ( i = 0; i < n; i++ )
357  {
358  x[i] = xs[i];
359  y[i] = ys[i];
360  }
361 
362  if ( n > PL_MAXPOLY )
363  {
364  free( xs );
365  free( ys );
366  }
367 
368  return 0;
369 }
370 
371 //--------------------------------------------------------------------------
372 // plr_eop()
373 //
374 // Clear screen.
375 //--------------------------------------------------------------------------
376 
377 static int
379 {
380  dbug_enter( "plr_eop" );
381 
382  pleop();
383  return 0;
384 }
385 
386 //--------------------------------------------------------------------------
387 // plr_bop()
388 //
389 // Page advancement.
390 //--------------------------------------------------------------------------
391 
392 static int
394 {
395  dbug_enter( "plr_bop" );
396 
397 // Advance and setup the page
398 
399  plbop();
400  plvpor( 0., 1., 0., 1. );
401  plwind( plr->xmin, plr->xmax, plr->ymin, plr->ymax );
402 
403  return 0;
404 }
405 
406 //--------------------------------------------------------------------------
407 // plr_state()
408 //
409 // Handle change in PLStream state (color, pen width, fill attribute,
410 // etc).
411 //--------------------------------------------------------------------------
412 
413 static int
415 {
416  U_CHAR op;
417  int i;
418 
419  plr_rd( pdf_rd_1byte( plr->pdfs, &op ) );
420 
421  switch ( op )
422  {
423  case PLSTATE_WIDTH: {
424  U_SHORT width;
425 
426  plr_rd( pdf_rd_2bytes( plr->pdfs, &width ) );
427 
428  plwidth( width );
429  break;
430  }
431 
432  case PLSTATE_COLOR0: {
433  short icol0;
434 
435  plr_rd( pdf_rd_2bytes( plr->pdfs, (unsigned short *) &icol0 ) );
436 
437  if ( icol0 == PL_RGB_COLOR )
438  {
439  U_CHAR r, g, b;
440  plr_rd( pdf_rd_1byte( plr->pdfs, &r ) );
441  plr_rd( pdf_rd_1byte( plr->pdfs, &g ) );
442  plr_rd( pdf_rd_1byte( plr->pdfs, &b ) );
443  plscol0( icol0, r, g, b );
444  }
445  else
446  {
447  plcol0( icol0 );
448  }
449  break;
450  }
451 
452  case PLSTATE_COLOR1: {
453  U_SHORT icol1;
454  PLFLT col1;
455 
456  plr_rd( pdf_rd_2bytes( plr->pdfs, &icol1 ) );
457  col1 = (double) icol1 / (double) plsc->ncol1;
458  plcol1( col1 );
459  break;
460  }
461 
462  case PLSTATE_FILL: {
463  signed char patt;
464 
465  plr_rd( pdf_rd_1byte( plr->pdfs, (U_CHAR *) &patt ) );
466  plpsty( patt );
467  break;
468  }
469 
470  case PLSTATE_CMAP0: {
471  U_SHORT ncol0;
472 
473  plr_rd( pdf_rd_2bytes( plr->pdfs, &ncol0 ) );
474  plscmap0n( (PLINT) ncol0 );
475  for ( i = 0; i < plsc->ncol0; i++ )
476  {
477  plr_rd( pdf_rd_1byte( plr->pdfs, &plsc->cmap0[i].r ) );
478  plr_rd( pdf_rd_1byte( plr->pdfs, &plsc->cmap0[i].g ) );
479  plr_rd( pdf_rd_1byte( plr->pdfs, &plsc->cmap0[i].b ) );
480  }
482  break;
483  }
484 
485  case PLSTATE_CMAP1: {
486  U_SHORT ncol1, ncp1;
487  float h, l, s;
488  U_CHAR rev;
489 
490  plr_rd( pdf_rd_2bytes( plr->pdfs, &ncol1 ) );
491  plscmap1n( (PLINT) ncol1 );
492  for ( i = 0; i < plsc->ncol1; i++ )
493  {
494  plr_rd( pdf_rd_1byte( plr->pdfs, &plsc->cmap1[i].r ) );
495  plr_rd( pdf_rd_1byte( plr->pdfs, &plsc->cmap1[i].g ) );
496  plr_rd( pdf_rd_1byte( plr->pdfs, &plsc->cmap1[i].b ) );
497  }
498  // Get the control points
499  plr_rd( pdf_rd_2bytes( plr->pdfs, &ncp1 ) );
500  plsc->ncp1 = ncp1;
501  for ( i = 0; i < plsc->ncp1; i++ )
502  {
503  plr_rd( pdf_rd_ieeef( plr->pdfs, &h ) );
504  plr_rd( pdf_rd_ieeef( plr->pdfs, &l ) );
505  plr_rd( pdf_rd_ieeef( plr->pdfs, &s ) );
506  plr_rd( pdf_rd_1byte( plr->pdfs, &rev ) );
507 
508  plsc->cmap1cp[i].h = h;
509  plsc->cmap1cp[i].l = l;
510  plsc->cmap1cp[i].s = s;
511  plsc->cmap1cp[i].alt_hue_path = rev;
512  }
514  break;
515  }
516  }
517 
518  return 0;
519 }
520 
521 //--------------------------------------------------------------------------
522 // plr_esc()
523 //
524 // Handle all escape functions.
525 // Only those that require additional data to be read need to be
526 // explicitly handled; the others are merely passed on to the actual
527 // driver.
528 //--------------------------------------------------------------------------
529 
530 static int
532 {
533  U_CHAR op;
534 
535  plr_rd( pdf_rd_1byte( plr->pdfs, &op ) );
536 
537  switch ( op )
538  {
539  case PLESC_FILL:
540  plr_cmd( plresc_fill( plr ) );
541  break;
542 
543  default:
544  pl_cmd( (PLINT) op, NULL );
545  break;
546  }
547 
548  return 0;
549 }
550 
551 //--------------------------------------------------------------------------
552 // plresc_fill()
553 //
554 // Fill polygon described in points plsc->dev_x[] and plsc->dev_y[].
555 //--------------------------------------------------------------------------
556 
557 static int
559 {
560  U_SHORT npts;
561  PLFLT *x, *y;
562 
563  dbug_enter( "plresc_fill" );
564 
565  plr_rd( pdf_rd_2bytes( plr->pdfs, &npts ) );
566  if ( npts > PL_MAXPOLY )
567  {
568  x = (PLFLT *) malloc( sizeof ( PLFLT ) * npts );
569  y = (PLFLT *) malloc( sizeof ( PLFLT ) * npts );
570  }
571  else
572  {
573  x = xstatic;
574  y = ystatic;
575  }
576  get_ncoords( plr, x, y, npts );
577  plfill( npts, x, y );
578 
579  if ( npts > PL_MAXPOLY )
580  {
581  free( x );
582  free( y );
583  }
584  return 0;
585 }
586 
587 //--------------------------------------------------------------------------
588 // plr_get()
589 //
590 // Read & return the next command
591 //--------------------------------------------------------------------------
592 
593 static int
595 {
596  int c;
597 
598  c = pdf_getc( plr->pdfs );
599  if ( c == EOF )
600  {
601  barf( "plr_get: Unable to read character" );
602  }
603 
604  return c;
605 }
606 
607 //--------------------------------------------------------------------------
608 // plr_unget()
609 //
610 // Push back the last command read.
611 //--------------------------------------------------------------------------
612 
613 static int
615 {
616  if ( pdf_ungetc( c, plr->pdfs ) == EOF )
617  {
618  barf( "plr_unget: Unable to push back character" );
619  }
620 
621  return 0;
622 }