Annotation of OpenXM_contrib/gnuplot/term/apollo.trm, Revision 1.1.1.2
1.1 maekawa 1: /*
1.1.1.2 ! maekawa 2: * $Id: apollo.trm,v 1.9 1999/01/14 19:34:40 lhecking Exp $
1.1 maekawa 3: *
4: */
5:
6: /* GNUPLOT - apollo.trm */
7: /*
8: Apollo terminal driver for gnuplot.
9:
10: Open a pad for the graphics, and use GPR routines. For additional
11: speed, we do the graphics to a separate bitmap, and the blt the
12: entire bitmap to the display. When the user specifies an output
13: file name, however, we draw directly to the screen, so the graphics
14: are written to the file correctly. Thus, the user can save the
15: graphics in a file, to be viewed later. If we try the bitmap
16: trick, it looks funny.
17:
18: Ray Lischner (uunet!mntgfx!lisch)
19: 4 October 1989 file created for gnuplot 1.1
20: 26 March 1990 updated for gnuplot 2.0
21: 30 October 1991 fixed minor problem in apollo_tic_sizes
22:
23: As of 13 January 1999, this file has been placed in the
24: public domain by Ray Lischner.
25:
26: */
27:
28: /*
29: * adapted to the new terminal layout by Stefan Bodewig (Dec. 1995)
30: */
31:
32: #include "driver.h"
33:
34: #ifdef TERM_REGISTER
35: register_term(apollo)
36: #endif
37:
38: #ifdef TERM_PROTO
39: TERM_PUBLIC void APOLLO_init __PROTO((void));
40: TERM_PUBLIC void APOLLO_graphics __PROTO((void));
41: TERM_PUBLIC void APOLLO_linetype __PROTO((int ltype));
42: TERM_PUBLIC void APOLLO_move __PROTO((unsigned int x, unsigned int y));
43: TERM_PUBLIC void APOLLO_vector __PROTO((unsigned int x, unsigned int y));
44: TERM_PUBLIC void APOLLO_text __PROTO((void));
45: TERM_PUBLIC int APOLLO_text_angle __PROTO((int ang));
46: TERM_PUBLIC int APOLLO_justify_text __PROTO((enum JUSTIFY mode));
47: TERM_PUBLIC void APOLLO_put_text __PROTO((unsigned int x, unsigned int y, char str[]));
48: TERM_PUBLIC void APOLLO_reset __PROTO((void));
49: /* default tick sizes for small windows */
50: #define APOLLO_VTIC 6
51: #define APOLLO_HTIC 6
52: #endif
53:
54: #ifndef TERM_PROTO_ONLY
55: #ifdef TERM_BODY
56:
57: #include <apollo/base.h>
58: #include <apollo/error.h>
59: #include <apollo/pad.h>
60: #include <apollo/gpr.h>
61:
62: int apollo_isa_pad __PROTO((void));
63: static void apollo_font_info __PROTO((struct termentry * tbl, char *fname));
64: static void apollo_gpr_init __PROTO((struct termentry * tbl, pad_$window_desc_t * window));
65: static void apollo_tic_sizes __PROTO((struct termentry * tbl));
66: static void apollo_gpr_terminate __PROTO((void));
67: static void apollo_redo_window __PROTO((pad_$window_desc_t * window));
68: static void apollo_xy_error __PROTO((char *s, int x, int y, status_$t status));
69:
70: /* issue an error message, using additional text "s" */
71: #define apollo_error(s) error_$print_name(status, (s), strlen(s))
72:
73: /* if "status" indicates an error, then issue an error message */
74: #define apollo_check(s) if (status.all != status_$ok) apollo_error(s)
75:
76: static ios_$id_t stream = -1; /* the stream for the pad */
77: static gpr_$bitmap_desc_t screen_desc; /* the screen's bitmap */
78: static gpr_$bitmap_desc_t bitmap_desc; /* the graphics bitmap */
79: static gpr_$attribute_desc_t attr; /* attribute block for saved bitmap */
80: static int APOLLO_XMAX, APOLLO_YMAX; /* window size */
81: static short draw_width; /* default GPR draw width */
82: static name_$long_pname_t font_name; /* font path name */
83: static boolean use_bitmap; /* use a separate bitmap? */
84:
85: /* return whether stdout is a DM pad */
86: apollo_isa_pad()
87: {
88: status_$t status;
89: pad_$isa(1, &status);
90: return (status.all == status_$ok);
91: }
92:
93: /*
94: Find out what the default font is for the pad, and save the
95: character height and width information.
96:
97: Note that we must save the font file name because we need
98: to reload the font file everytime the window changes size.
99: */
100: static void apollo_font_info(struct termentry *tbl, char *fname)
101: {
102: short fwidth, fheight, flen;
103: status_$t status;
104:
105: /* get the font size & update the termentry table */
106: pad_$inq_font(stream, &fwidth, &fheight, fname, name_$long_pnamlen_max,
107: &flen, &status);
108: apollo_check("inq_font");
109: fname[flen] = NUL;
110:
111: tbl->v_char = fheight;
112: tbl->h_char = fwidth;
113: }
114:
115: /*
116: Initialize all the GPR stuff. To save time, we draw into a separate
117: bitmap, and then blt it onto the screen all at once. This results
118: in 5-10 times speed-up in the graphics, with only a little
119: complication. Most of the complication is right here, making sure
120: we allocate the right bitmaps, etc., in the right order. The rest
121: is in APOLLO_text(), where we actually BLT the bitmap onto the screen.
122: Everything else is the same.
123:
124: The bitmaps have the same size as the window. If the window changes
125: size, then the bitmaps retain the same size, so the user sees part
126: of the plot or a lot of space around the plot. Drawing a new plot,
127: or replotting the previous one causes APOLLO_graphics() to see if
128: the window has changed size, in which case the GPR is terminated,
129: and this routine is called again. Thus, make sure any changes
130: preserve this ability. Anything that should only be done once
131: to the pad should be handled by APOLLO_init().
132:
133: By the way, we save the current draw width, to be used later
134: for drawing extra wide lines. This way we don't need to know
135: anything about the current output device characteristics;
136: we can just draw the default width, or twice the default width, etc.
137: */
138: static void apollo_gpr_init(struct termentry *tbl, pad_$window_desc_t * window)
139: {
140: gpr_$offset_t size;
141: short fontid;
142: status_$t status;
143:
144: size.x_size = APOLLO_XMAX = tbl->xmax = window->width;
145: size.y_size = APOLLO_YMAX = tbl->ymax = window->height;
146:
147: /* now initialize GPR */
148: gpr_$init(gpr_$frame, stream, size, 1, &screen_desc, &status);
149: apollo_check("gpr_$init");
150:
151: if (use_bitmap) {
152: /* allocate the bitmap and its attribute block */
153: gpr_$allocate_attribute_block(&attr, &status);
154: apollo_check("allocate_attribute_block");
155:
156: gpr_$allocate_bitmap(size, 1, attr, &bitmap_desc, &status);
157: apollo_check("allocate_bitmap");
158:
159: gpr_$set_bitmap(bitmap_desc, &status);
160: apollo_check("set_bitmap");
161: }
162: /* set the font file */
163: gpr_$load_font_file(font_name, strlen(font_name), &fontid, &status);
164: apollo_check(font_name);
165:
166: gpr_$set_text_font(fontid, &status);
167: apollo_check("set_text_font");
168:
169: gpr_$inq_draw_width(&draw_width, &status);
170: apollo_check("inq_draw_width");
171: }
172:
173: /*
174: Determine the tick sizes to be used for labelling borders.
175: By default, we use 1/50 of the window size, which looks nice to me.
176: If this makes the ticks too small, however, we use a minimum
177: size, to make sure they are visible. The minimum size was also
178: determined experimentally.
179:
180: Feel free to changes the sizes to something you feel looks better.
181:
182: This routine must be called after apollo_gpr_init(), because we
183: need to know the window size, as stored in the termentry table.
184: */
185: static void apollo_tic_sizes(struct termentry *tbl)
186: {
187: /* base the tick size on the window size */
188: tbl->v_tic = tbl->ymax / 50;
189: if (tbl->v_tic < APOLLO_VTIC)
190: tbl->v_tic = APOLLO_VTIC;
191: tbl->h_tic = tbl->xmax / 50;
192: if (tbl->h_tic < APOLLO_HTIC)
193: tbl->h_tic = APOLLO_HTIC;
194: }
195:
196: /*
197: Terminate the GPR. This is called whenever the window size
198: changes, and we need to reinitialize the GPR. I assume that
199: calling gpr_$terminate() also deallocates the bitmaps and
200: attribute blocks because deallocating the screen's bitmap
201: causes terminate() to think GPR has already been terminated.
202:
203: Since this can be called many times, make sure nothing
204: drastic is done here, like closing the stream to the pad.
205: The only actions should be those that will be reinitialized
206: by apollo_gpr_init().
207: */
208: static void apollo_gpr_terminate()
209: {
210: status_$t status;
211:
212: gpr_$terminate(false, &status);
213: apollo_check("terminate");
214: }
215:
216: /*
217: Initialize the graphics. This is called once, so we do things
218: here that should be done exactly once, such as opening the window.
219: I like to give windows names, so it is obvious what the window's
220: contents are, but this causes a transcript to be kept in a file
221: whose name is the window's name. This might be nice in some
222: circumstances, but to me it is a nuisance, so the file is
223: deleted immediately. The name is unlikely to appear normally,
224: so there should be little interference with users' normal files.
225: If the user has explicitly set the output file, however, then
226: we use that name, and do not delete the file. Thus, the
227: user can get a metafile of the plot. We can tell if the
228: output file has been set because outstr is NULL. Otherwise,
229: outstr is the filename, in alloc-ed store.
230:
231: The DM defaults are used for window sizes and positions. If
232: the user doesn't like it, he or she can change is and issue
233: a replot command (assuming a plot has already been generated).
234:
235: Note, also, that we must call pad_$set_scale() or else
236: pad_$inq_windows() returns scaled values, which is not what
237: we want. Setting the scale to one (1) turns off the scaling,
238: so we get real pixel sizes.
239:
240: Finally, we get the name and size of the default font. The
241: name is kept, as explained earlier. Then we can initialize
242: the GPR stuff.
243:
244: Note that there is a way that APOLLO_init() gets called more
245: than once. If the user issues the "set terminal apollo" command
246: more than once, then this is called, so we need to make sure
247: that we do not keep creating windows.
248:
249: An alternative strategy would be to interpret multiple "set term
250: apollo"s to mean create multiple windows. The user could only
251: access the most recent window because gnuplot has no concept of
252: multiple terminals. The user would, in fact, have no way of
253: removing old windows because they are still active. We could try
254: catching keyboard events to see if the user presses EXIT, but I do
255: not want to start getting into that mess. If the user really
256: wants this kind of functionality, then he or she can run gnuplot
257: multiple times. I think that is a lot cleaner, don't you?
258: */
259: TERM_PUBLIC void APOLLO_init()
260: {
261: /* only initialize once */
262: if (stream == -1) {
263: struct termentry *tbl;
264: pad_$window_desc_t window;
265: name_$long_name_t wname;
266: short wnum; /* junk needed by pad_$inq_windows() */
267: boolean unlink_wname;
268: status_$t status;
269:
270: tbl = term;
271:
272: /* make the window name unique, with "gnuplot" in the label */
273: if (outstr == NULL) {
274: sprintf(wname, "gnuplot-%d", getpid());
275: unlink_wname = true;
276: } else {
277: strcpy(wname, outstr);
278: unlink_wname = false;
279: }
280:
281: use_bitmap = unlink_wname;
282:
283: /* use the default window position and size */
284: window.top = window.left = window.width = window.height = 0;
285: pad_$create_window(wname, strlen(wname), pad_$transcript, 1, window,
286: &stream, &status);
287: apollo_check("create_window");
288:
289: /* if this is not the user's name, then delete the file */
290: if (unlink_wname)
291: unlink(wname);
292:
293: /* remove all scaling, to revert to pixel units, not char. units */
294: pad_$set_scale(stream, 1, 1, &status);
295: apollo_check("set_scale");
296:
297: /* get rid of the window when the program exits */
298: pad_$set_auto_close(stream, 1, true, &status);
299: apollo_check("set_auto_close");
300:
301: /* now determine the window size & update the termentry table */
302: pad_$inq_windows(stream, &window, 1, &wnum, &status);
303: apollo_check("inq_windows");
304:
305: /* the order of the next three calls is important */
306: apollo_font_info(tbl, font_name);
307: apollo_gpr_init(tbl, &window);
308: apollo_tic_sizes(tbl);
309: }
310: }
311:
312: /*
313: Prepare for graphics output. Since this is what the user wants to
314: do when preparing a new plot, this is a meaningful time to see if
315: the window has changed size. Thus, we avoid mucking about with
316: asynchronous traps, and we avoid the bigger problem of dealing
317: with a half-finished plot when the window changes size.
318:
319: Simply put, get the current window size, and if it has changed,
320: then get rid of the old bitmaps, etc., and allocate new ones at
321: the new size. We also need to update the termentry table.
322: If the window stays the same size, then just clear it.
323: */
324: static void apollo_redo_window(pad_$window_desc_t * window)
325: {
326: struct termentry *tbl = term;
327: status_$t status;
328:
329: /* the order of the following calls is important */
330: apollo_gpr_terminate();
331: apollo_gpr_init(tbl, window);
332: apollo_tic_sizes(tbl);
333: }
334:
335: TERM_PUBLIC void APOLLO_graphics()
336: {
337: pad_$window_desc_t window;
338: short wnum;
339: status_$t status;
340:
341: pad_$inq_windows(stream, &window, 1, &wnum, &status);
342: apollo_check("inq_windows");
343:
344: if (window.width != APOLLO_XMAX || window.height != APOLLO_YMAX)
345: apollo_redo_window(&window);
346: else {
347: gpr_$clear(0, &status);
348: apollo_check("clear");
349: }
350: }
351:
352: /* set a line type:
353: -2 heavy, solid (border)
354: -1 heavy, dotted (axis)
355: 0 solid (normal)
356: 1 dots (other curves)
357: 2 short dash
358: 3 long dash
359: 4 dash dot
360:
361: Apparently, GPUplot draws a lot of short line segments, and each
362: one starts a new pattern. This makes the patterns somewhat useless,
363: but one can still tell the difference between solid, dotted, and
364: dashed lines. The utility of fancier styles is limited, however.
365:
366: On a color workstation, we should use different colors, but I
367: don't have one.
368: */
369:
370: /*
371: To draw different line styles on an Apollo, we use two different
372: parameters. One is a line thickness, which is just an integral
373: multiple of the default line thickness. The second is a 16-bit
374: pattern that is repeated. We could use fancier patterns, since
375: GPR supports up to 64-bits, but, as I explained earlier, this
376: really does not buy us anything.
377:
378: I used patterns that do not start with all bits on because
379: gnuplot seems to use lots of short line segments to draw
380: a curve, and this might make a very curvey plot seem like
381: a solid line, regardless of pattern. I don't want to start
382: with too many zeros, however, or else the curve might not
383: appear at all! All the patterns, therefore, start with one
384: bit on. The rest of the bits determine the true pattern.
385:
386: By examining graphics.c, we see that linetype -2 is used exclusively
387: for the border, -1 for the axes, and the non-negative integers for
388: the curves. We use heavy lines for the border and axes, and normal
389: width lines for the curves.
390:
391: Since C arrays start at zero, make sure all the offsets are correct,
392: so that it is easy to access the array with -2...n linetypes.
393: */
394:
395: typedef struct {
396: short width;
397: short pattern;
398: } APOLLO_LINE;
399:
400: static APOLLO_LINE apollo_lines[] =
401: {
402: {2, ~0}, /* heavy, solid */
403: {2, 0x6666}, /* heavy, dotted */
404: {1, ~0}, /* normal */
405: {1, 0xAAAA}, /* dotted */
406: {1, 0xC3C3}, /* short dash */
407: {1, 0xE01F}, /* long dash */
408: {1, 0x87F8}, /* dash dot */
409: {1, 0x6666}, /* big dots */
410: };
411:
412: #define BITS_PER_LINETYPE 16
413:
414: /* apollo_line(-2) is the border style, etc. */
415: #define apollo_line(x) apollo_lines[(x)+2]
416: #define apollo_pattern(x) &apollo_line(x).pattern
417: #define apollo_width(x) apollo_line(x).width
418:
419: #define APOLLO_MIN_LINE (-2)
420: #define APOLLO_MAX_LINE (sizeof(apollo_lines)/sizeof(*apollo_lines)-2)
421:
422: /* set the line style */
423: TERM_PUBLIC void APOLLO_linetype(ltype)
424: int ltype;
425: {
426: status_$t status;
427:
428: if (ltype < APOLLO_MIN_LINE)
429: ltype = APOLLO_MIN_LINE;
430: if (ltype >= APOLLO_MAX_LINE)
431: ltype %= APOLLO_MAX_LINE;
432:
433: gpr_$set_line_pattern(1, apollo_pattern(ltype), BITS_PER_LINETYPE, &status);
434: apollo_check("set_line_pattern");
435:
436: gpr_$set_draw_width(draw_width * apollo_width(ltype), &status);
437: apollo_check("set_draw_width");
438: }
439:
440: /* issue an error message that includes an (x, y) coordinate */
441: static void apollo_xy_error(char *s, int x, int y, status_$t status)
442: {
443: char buffer[128];
444:
445: sprintf(buffer, "%s(%d, %d)", s, x, y);
446: apollo_error(buffer);
447: }
448:
449: #define apollo_xy_check(s) \
450: if (status.all != status_$ok) apollo_xy_error((s), x, y, status)
451:
452: /*
453: Note that gnuplot and GPR have reversed ideas of where the Y origin is.
454: This means subtracting the Y coordinate from Y max.
455: */
456: #define plot_to_gpr(y) (APOLLO_YMAX - (y))
457:
458: /* move to a new position */
459: TERM_PUBLIC void APOLLO_move(unsigned int x, unsigned int y)
460: {
461: status_$t status;
462:
463: gpr_$move((gpr_$coordinate_t) x, plot_to_gpr(y), &status);
464: apollo_xy_check("move");
465: }
466:
467: /* draw a line to a new position */
468: TERM_PUBLIC void APOLLO_vector(unsigned int x, unsigned int y)
469: {
470: status_$t status;
471:
472: gpr_$line((gpr_$coordinate_t) x, plot_to_gpr(y), &status);
473: apollo_xy_check("line");
474: }
475:
476: /*
477: On terminals, this switches to text mode. The real meaning,
478: however, is that the graphics are finished. This means we can
479: now display the saved bitmap.
480: */
481: TERM_PUBLIC void APOLLO_text()
482: {
483: if (use_bitmap) {
484: static gpr_$position_t pos; /* always zero */
485: gpr_$window_t window;
486: status_$t status;
487:
488: /* bitblt the entire bitmap to the entire window */
489: window.window_base.x_coord = 0;
490: window.window_base.y_coord = 0;
491: window.window_size.x_size = APOLLO_XMAX;
492: window.window_size.y_size = APOLLO_YMAX;
493:
494: gpr_$set_bitmap(screen_desc, &status);
495: apollo_check("set_bitmap(screen_desc)");
496:
497: gpr_$pixel_blt(bitmap_desc, window, pos, &status);
498: apollo_check("bitblt");
499:
500: gpr_$set_bitmap(bitmap_desc, &status);
501: apollo_check("set_bitmap(bitmap_desc)");
502: }
503: }
504:
505: TERM_PUBLIC int APOLLO_text_angle(ang)
506: int ang;
507: {
508: status_$t status;
509:
510: gpr_$set_text_path(ang ? gpr_$up : gpr_$right, &status);
511: apollo_check("set_text_path");
512: return TRUE;
513: }
514:
515: static enum JUSTIFY apollo_text_mode;
516:
517: TERM_PUBLIC int APOLLO_justify_text(mode)
518: enum JUSTIFY mode;
519: {
520: apollo_text_mode = mode;
521: return TRUE;
522: }
523:
524: /*
525: Write "str" right justified on row "row". A row is assumed to
526: have whatever height the current text has. Make sure the
527: text does not cover the tick marks.
528: */
529: TERM_PUBLIC void APOLLO_put_text(x, y, str)
530: unsigned int x, y;
531: char str[];
532: {
533: gpr_$offset_t size;
534: status_$t status;
535:
536: gpr_$inq_text_extent(str, strlen(str), &size, &status);
537: apollo_check("inq_text_extent");
538:
539: y -= size.y_size / 2; /* center around "y" */
540: switch (apollo_text_mode) {
541: case LEFT:
542: break;
543: case CENTRE:
544: x -= size.x_size / 2;
545: break;
546: case RIGHT:
547: x -= size.x_size;
548: break;
549: }
550: APOLLO_move(x, y);
551:
552: gpr_$text(str, strlen(str), &status);
553: apollo_check("put_text");
554: }
555:
556: /* reset the graphics state and terminate */
557: TERM_PUBLIC void APOLLO_reset()
558: {
559: if (stream != -1) {
560: apollo_gpr_terminate();
561: stream = -1;
562: }
563: }
564:
565: #endif /* TERM_BODY */
566:
567: #ifdef TERM_TABLE
568: TERM_TABLE_START(apollo_driver)
569: "apollo",
570: "Apollo Graphics Primitive Resource, rescaling of subsequent plots after window resizing",
571: 0, 0, 0, 0, /* APOLLO_XMAX, APOLLO_YMAX, APOLLO_VCHAR, APOLLO_HCHAR, are filled in at run-time */
572: APOLLO_VTIC, APOLLO_HTIC, options_null, APOLLO_init, APOLLO_reset,
573: APOLLO_text, null_scale, APOLLO_graphics, APOLLO_move, APOLLO_vector,
574: APOLLO_linetype, APOLLO_put_text, APOLLO_text_angle,
575: APOLLO_justify_text, line_and_point, do_arrow, set_font_null
576: TERM_TABLE_END(apollo_driver)
577:
578: #undef LAST_TERM
579: #define LAST_TERM apollo_driver
580:
581: #endif /* TERM_TABLE */
582: #endif /* TERM_PROTO_ONLY */
583:
584: #ifdef TERM_HELP
585: START_HELP(apollo)
586: "1 apollo",
587: "?commands set terminal apollo",
588: "?set terminal apollo",
589: "?set term apollo",
590: "?terminal apollo",
591: "?term apollo",
592: "?apollo",
593: " The `apollo` terminal driver supports the Apollo Graphics Primitive Resource",
594: " with rescaling after window resizing. It has no options.",
595: "",
596: " If a fixed-size window is desired, the `gpr` terminal may be used instead."
597: END_HELP(apollo)
598: #endif /* TERM_HELP */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>