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