diff options
Diffstat (limited to 'sys/gio/cursor')
50 files changed, 5574 insertions, 0 deletions
diff --git a/sys/gio/cursor/README b/sys/gio/cursor/README new file mode 100644 index 00000000..6534b497 --- /dev/null +++ b/sys/gio/cursor/README @@ -0,0 +1,9 @@ +This directory contains the source for GIOTR and cursor mode, i.e., the code +required to process the graphics output of a graphics task, spooling and/or +applying the workstation transformation and passing the transformed metacode +instructions on to the builtin STDGRAPH kernel or to an external kernel. The +procedure RCURSOR is the main entry point for cursor mode. RCURSOR is called +by the CL to service a query for a cursor type parameter when query mode is +in effect. The workstation transformation is used to zoom and pan on a frame +buffer and consists of a viewport transformation in GKI coordinates with +clipping at the viewport boundary. diff --git a/sys/gio/cursor/doc/cursor.hlp b/sys/gio/cursor/doc/cursor.hlp new file mode 100644 index 00000000..d9912607 --- /dev/null +++ b/sys/gio/cursor/doc/cursor.hlp @@ -0,0 +1,194 @@ +.help GIO Mar85 "Cursor Mode" +.nh 3 +Cursor Mode + + In cursor mode, i.e., after a call to \fBclgcur\fR or after typing "=gcur", +a number of special keystrokes shall be recognized for interactive display +control. All graphics output to stdgraph and stdimage is routed through the +CL on the way to the graphics kernel. The CL will optionally spool in an +internal buffer all graphics instructions output to an interactive device. +This internal buffer is emptied whenever the device screen is cleared. +In cursor mode, special keystrokes may be used to redraw all or any portion +of the spooled graphics, e.g., one may zoom in on a portion of the plot and +then roam about on the plot at high magnification. Since the spooled graphics +vectors typically contain more information than can be displayed at normal +magnification, zooming in on a feature may bring out additional detail +(the maximum resolution is 32768 points in either axis). Increasing the +magnification will increase the precision of the cursor by the same factor. + +Cursor mode is implemented by performing coordinate transformation and +clipping on each GKI instruction in the frame buffer, passing the transformed +and clipped instructions on to the graphics kernel. +The cursor mode operations perform a simple geometric transformation on +the spooled graphics frame, mapping a rectangular window of the spooled +frame onto the device screen. The graphics frame itself is not modified, +hence zoom out or reset and redraw will restore the original display. + +If the graphics frame is a typical vector plot with drawn and labeled +axes, magnifying a portion of the plot may cause the axes to be lost. +If this is not what is desired a keystroke is provided to draw and label +the axes of the displayed window. The axes will be overplotted on the +current display and will not be saved in the frame buffer, hence they +will be lost when the frame is redrawn. In cursor mode the viewport is +the full display area of the output device, hence the tick mark labels +of the drawn axes will be drawn inside the viewport. This form of axes +labeling is used because it is simple and because it is appropriate for +both vector graphics and image display output devices (and cursor mode +must serve both). + +The cursor mode keystrokes are all upper case letters, reserving lower case +for applications programs. The terminal shift lock key may be used to +minimize typing. The recognized cursor mode keystrokes are shown below. + + +.ks +.nf +(*X* means not yet implemented) + + ? print list of keystrokes + *A* draw and label the axes of current viewport + C print the cursor position as it moves + *D* draw a line by marking the endpoints + E expand plot by setting window corners + F set fast cursor (for HJKL) + H step cursor left + J step cursor down + K step cursor up + L step cursor right + M move point under cursor to center of screen + P zoom out (restore previous expansion) + *S* select WCS at current position of cursor + *T* draw a text string + *U* undo (delete) the last instruction in the frame buffer + V set slow cursor (for HJKL) + X zoom in, X only + Y zoom in, Y only + Z zoom in, both X and Y + < set lower limit of plot to the cursor y value + > set upper limit of plot to the cursor y value + *\* escape next character + : set cursor mode options + :! send a command to the host system + 0 reset and redraw + 1-9 roam + +.fi +.ce +Figure 2. Cursor Mode Keystrokes +.ke + + +The numeric keypad of the terminal (if it has one) is used for directional +roaming. The directional significance of the numeric keys for roaming +is obvious if the terminal has a keypad, and is illustrated below. + + +.ks +.nf + 7 8 9 135 090 045 + + 4 5 6 180 000 000 + + 1 2 3 225 -90 -45 +.fi +.ke + + +If the character : is typed while in cursor mode the alpha cursor will appear +at the bottom of the screen, allowing a command line to be entered. If the +command \fIbegins with a period it is interpreted as a cursor mode command\fR, +otherwise the command is passed as a string to the applications program. +Multiple commands may be entered on a line delimited by semicolons. +The command set currently recognized is shown below. Minimum match +abbreviations are permitted. + +.ls 4 +.ls 15 help +Print a list of the cursor mode commands. +.le +.ls case[+-] +Ignore case when interpreting keystrokes. If this option is selected the cursor +mode keystrokes may conflict with those of the applications program. +.le +.ls clear +Clear the alpha screen (but not the graphics screen). This is done by writing +sufficient blank lines to scroll any text off the screen. Does not work if +terminal has only one memory. +.le +.ls markcur[+-] +Draw a small graphics mark at the position of the cursor whenever the cursor +is read, i.e., when cursor mode exits. The default is to not mark. +.le +.ls off [keys] +Disable all cursor mode keystrokes except : (colon). If followed by a list +of keys, e.g., ":.off 0-9IC", only the listed keys are disabled. +.le +.ls on [keys] +Renable all cursor mode keystrokes, or just the listed keystrokes. +.le +.ls page[+-] +Clear the screen when large blocks of text are to be printed, e.g., for '?', +show, and so on. If paging is disabled the text will overwrite the graphics +display. +.le +.ls read <file> +Load the graphics frame from the named metafile. +The current graphics frame is discarded. +.le +.ls reset +Disconnect any connected graphics kernels and free all file descriptors and +memory used by the graphics system. Exit cursor mode. +.le +.ls show +Print the values of all cursor mode parameters, show the status of any +connected graphics kernels, summarize memory utilization, etc. +.le +.ls snap [device] +Dispose of the graphics frame to the standard plotter or to the named device. +A magnified graph will be plotted as it appears on the screen. +.le +.ls txset [size] [up] +Set the text drawing parameters (character size and character up vector). +For example, ".tx 2 180" would set the character size to 2.0 and character +up to 180 degrees for a vertical string drawn upwards. +.le +.ls write <file> +Save the graphics frame in (or append to) the named metafile. +If an exclamation is appended to the command (e.g., "w! file") the output +file, if any, will be overwritten. If a plus sign is appended the entire +frame will be saved regardless of any plot expansion. +.le +.ls xres=N +Set the (soft) device resolution in X. A decrease in resolution will generally +yield an increase in plotting speed. Only plots generated on the graphics +terminal are affected. +.le +.ls yres=N +Set the (soft) device resolution in Y. +.le +.ls zero +Equivalent to the numeric key 0, i.e., restore the unitary workstation +transformation and redraw the screen. +.le +.le + + +For example, to set the X and Y resolutions to 250 and 100, respectively, +one could enter the following command (the computer will type the ':' at +the bottom of the screen when the ':' key is pressed): + + :.xres=250;yres=100 + +Cursor mode may be initialized at login time by supplying a CL environment +variable named "cminit". For example, + + cl> set cminit = off + +would disable cursor mode, and + + cl> set cminit = "mark;case-;xres=100;yres=50" + +would enable marking, turn off case sensitivity, and set the plotting +resolution to 100x50. Initialization is performed only once, when cursor +mode is first entered. +.sh diff --git a/sys/gio/cursor/doc/giotr.notes b/sys/gio/cursor/doc/giotr.notes new file mode 100644 index 00000000..a9221445 --- /dev/null +++ b/sys/gio/cursor/doc/giotr.notes @@ -0,0 +1,330 @@ +.help GIO Feb85 "Graphics I/O" +.nh +Graphics I/O Dataflow + + The GIO procedures are resident in an external applications task which +does graphics. GIO writes a GKI instruction stream which, if not sent directly +to a metafile, is sent to one of the standard graphics streams STDGRAPH, +STDIMAGE, or STDPLOT, much as output is sent to STDOUT or STDERR. +The procedure \fBprfilbuf\fR (directory etc$), which reads the command +stream from a subprocess, is resident in the CL and executes all pseudofile +i/o instructions from a subprocess. Note that \fBprfilbuf\fR is part of the +i/o system of IRAF and operates transparently to the CL. + + +.ks +.nf + GIO(task) ---ipc--> PRFILBUF(CL) --> file (or pipe) + | + v external + GIOTR ---ipc--> graphics + | kernel + v + stdgraph kernel + | + v + (zfioty) + graphics terminal + + + task | cl | task +.fi + +.ce +Graphics Output Dataflow +.ke + + +The \fBprfilbuf\fR procedure passes record read or write requests for the +pseudofiles STDIN, STDOUT or STDERR on to file descriptors assigned by the +CL with the \fBprredir\fR procedure at task execution time. The sole function +of the CL in graphics i/o is to control the redirection of the graphics +i/o streams with \fBprredir\fR. The CL may redirect any of the graphics +streams, i.e., the user may redirect any graphics stream on the command line +when a command is entered, but by default output is directed to a filter +resident in the CL process. This filter is a procedure named \fBgiotr\fR. + + giotr (stream, buffer, nchars) + +The primary function of GIOTR is to pass metacode instructions on to a kernel. +The instruction stream is scanned and special actions are taken for some of +the GKI control instructions. In particular, GIOTR must spawn graphics kernel +subprocesses upon demand. GIOTR is also capabable of performing an +additional transformation upon the drawing instructions before they are passed +to the kernel. This transformation, known as the \fBworkstation +transformation\fR, maps a rectangular portion of the NDC space into the full +device screen, clipping at the boundary of the viewport into NDC space. +The workstation transformation provides a zoom and pan capability and is +controlled interactively by the user in \fBcursor mode\fR (section 3.3). + +As noted earlier, the \fBstdgraph kernel\fR ("fast" kernel) is resident in +the CL process. This is necessary for efficiency reasons and is desirable +in any case because the CL process owns the graphics device, i.e., the +graphics terminal. All devices except the user's graphics terminal are +controlled by external graphics kernel processes. The STDGRAPH kernel is +itself available as an external process and may be called as such to drive +a graphics terminal other than the user terminal (or even to drive the user +terminal if one is willing to shuffle output back through IPC). A graphics +kernel may support an arbitrary number of devices, and may write to more +than one device simultaneously. In addition to being called by GIOTR, +a graphics kernel may be called directly as a CL task to process metacode from +either a file or the standard input, e.g., from a pipe. This offers +additional flexibility as the CL parameter mechanism may then be used to +gain control over metacode translation. + +.nh 2 +Graphics Stream I/O + + The functions performed by GIOTR are summarized in pseudocode below. +GIOTR maintains a separate descriptor for each of the three graphics streams +and is capable of servicing intermixed i/o requests for all streams +simultaneously. The information stored in the descriptor +includes the workstation name, process information, WCS storage for +the SETWCS and GETWCS instructions, the workstation transformation, +and the frame buffer, used to spool GKI instructions for cursor mode. + + +.tp 6 +.nf +procedure giotr (fd, buffer, nchars) + +fd graphics stream (STDGRAPH, etc.) +buffer[] buffer containing GKI metacode instructions +nchars number of chars to be read or written + +begin + # Note that a GKI instruction may span a buffer boundary. + # The code which gets the next instruction from the buffer + # must always return a full instruction, hence some local + # buffering is required therein to reconstruct instructions. + + while (get next instruction != buffer empty) { + + # Handle special instructions. + switch (instruction) { + + case GKI_OPENWS: + if (device not already open) { + read graphcap entry for device + get process name from graphcap entry + if (process not already connected) { + if (some other process is connected) + disconnect current kernel process + connect new kernel process + } + } + output instruction + flush output + clear frame buffer + + case GKI_CLOSEWS, GKI_FLUSH: + output instruction + flush output + + case GKI_CANCEL: + output instruction + flush output + clear frame buffer + + case GKI_SETWCS: + save WCS in descriptor + + case GKI_GETWCS: + write saved WCS to fd + flush (fd) + + default: + append unmodified instruction to frame buffer + perform workstation transformation upon instruction + output transformed instruction + } + } +end +.fi + + +The action implied by "output instruction" above is the following: + + +.ks +.nf + if (kernel is resident in this process) + call gki_execute to execute the instruction + else + call write (process, instruction, nchars) +.fi +.ke + + +The frame buffer (required for cursor mode) will be dynamically allocated and +will be no larger than it has to be, but will have a fixed (user defined) +upper limit, e.g., 128Kb. The median size for a plot is typically 5-10Kb. +Instructions will be silently discarded if the buffer grows too large. +Buffering can be turned off completely if desired, and will always be turned +off for STDPLOT. + +.nh 2 +Cursor Mode Details + + Most of the functionality required to implement cursor mode is provided +by GIOTR. The primary functions of the cursor mode code are to read the +cursor and keystroke, modify the workstation transformation, and redraw the +contents of the frame buffer subject to the new workstation transformation. +Cursor mode does not modify the contents of the frame buffer, except for +possibly appending new graphics instructions to the frame buffer. +A workstation transformation set with cursor mode remains in effect until +the frame buffer is cleared, hence any additional graphics output from the +task which initiated the cursor read (and cursor mode) will undergo the +workstation transformation when drawn. + + +.nf +# PR_FILBUF -- Fill FIO buffer from an IPC channel subject to the CL/IPC +# protocol for multiplexing pseudofile data streams with the command stream. +# Each process has an associated set of pseudofile streams. Each pseudofile +# stream is connected to one, and only one, file or pseudofile of another +# process. I/O requests to XMIT or XFER to an ordinary file are straightforward +# to satisfy. An i/o request from one pseudofile to another is satisfied +# by posting the request (pushing it on a stack) and redirecting our input +# to the process owning the pseudofile being read or written. Pseudofile +# requests are then processed from the second process until a request is +# received which satisfies the posted request from the original process. +# When the original request is satisfied it is popped from the stack and input +# will again be taken from the original process. Note that we cannot write +# directly to the output process since that would violate the IPC protocol +# (the second process may wish to write to its stdout or stderr rather than +# read, etc.: the process must be allowed to complete the original request +# itself). +# +# Request Packet (pushed onto stack for IPC to IPC i/o). +# +# pr process slot number of process placing the request +# iomode request is a read or a write +# count number of chars to be transferred +# ps_server pseudofile number in server process +# ps_receiver pseudofile number in receiver process +# +# The request packet describes a pending pseudofile i/o request. The named +# pseudofile in the server process is either reading from or writing to the +# named pseudofile in the receiver process. + +int procedure pr_filbuf (fd) + +begin + input = fd (the IPC input channel of a process) + + repeat { + get a line from the input file + if (neither XMIT nor XFER directive) + if (request pending) + error: IPC protocol corrupted + else + return command + + if (line is an XMIT directive) { + if (destination is a file) { + # Write from pseudofile to an ordinary file. + get data record from input + write data record to file + + } else { + # Write from pseudofile to another pseudofile. + if (XMIT satisfies XFER request on top of stack) + get data record from input + write record to stacked process + restore input to stacked process + pop request from stack + + } else { + # If writing to local kernel GIOTR will return a null + # length record and we are done. + + get data record from input + if (writing to a graphics stream) + call giotr filter to transform record + if (anything left to output) { + push request on stack + switch input to IPC input of receiver process + } + } + } + + } else if (line is an XFER directive) { + if (source is an ordinary file) { + # Read from a file. + read data record from file + write to active process + + } else if (source is another process) { + # Read from another pseudofile. + if (XFER satisfies XMIT request on top of stack) { + read record from stacked process + write to active process + restore input to stacked process + pop request from stack + } else { + push request on stack + switch input to IPC input channel of receiver process + } + } + } + } +end + + +# GIOTR -- Graphics i/o filter. + +procedure giotr (fd, buffer, nchars) + +fd graphics stream (STDGRAPH, etc.) +buffer[] buffer containing GKI metacode instructions +nchars number of chars to be read or written + +begin + # Note that a GKI instruction may span a buffer boundary. + # The code which gets the next instruction from the buffer + # must always return a full instruction, hence some local + # buffering is required therein to reconstruct instructions. + + while (buffer not empty) { + + # Handle special instructions. + switch (next_instruction) { + + case GKI_OPENWS: + if (device not already open) { + read graphcap entry for device + get process name from graphcap entry + if (process not already connected) { + if (some other process is connected) + disconnect current kernel process + connect new kernel process + } + } + output instruction + flush output + clear frame buffer + + case GKI_CLOSEWS, GKI_FLUSH: + output instruction + flush output + + case GKI_CANCEL: + output instruction + flush output + clear frame buffer + + case GKI_SETWCS: + save WCS in descriptor + + case GKI_GETWCS: + write saved WCS to fd + flush (fd) + + default: + append unmodified instruction to frame buffer + perform workstation transformation upon instruction + output transformed instruction + } + } +end diff --git a/sys/gio/cursor/giotr.x b/sys/gio/cursor/giotr.x new file mode 100644 index 00000000..cfc8f706 --- /dev/null +++ b/sys/gio/cursor/giotr.x @@ -0,0 +1,183 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <config.h> +include <xwhen.h> +include <gio.h> +include <gki.h> +include "gtr.h" + +# GIOTR -- A graphics filter, called by PR_PSIO (during normal graphics output) +# and RCURSOR (when in cursor mode) to perform the workstation transformation +# on a block of metacode instructions, writing the individual instructions to +# either the inline stdgraph kernel or to an external kernel. Input is taken +# from the frame buffer for the stream. All full instructions starting at the +# input pointer IP and ending at the output pointer OP are processed, leaving +# the input pointer positioned to BOI of the last (and incomplete) instruction +# in the frame buffer. If output is to an inline kernel the kernel is called +# to execute each instruction as it is extracted. If output is to an external +# kernel instructions are written to the named stream, i.e., into the FIO +# buffer associated with the stream, and later transferred to the kernel in the +# external process when the process requests input from the named stream in an +# XFER directive (see PR_PSIO). + +procedure giotr (stream) + +int stream # graphics stream + +pointer tr, gki +int jmpbuf[LEN_JUMPBUF], fn +int mode, xint, status, junk, nwords +common /gtrvex/ jmpbuf + +pointer gtr_init(), coerce() +extern giotr_onint(), gtr_delete() +int gtr_fetch_next_instruction(), locpr() +errchk gtr_init, gtr_fetch_next_instruction, gki_write +data status /OK/, xint /NULL/ +include "gtr.com" + +begin + tr = gtr_init (stream) + + # If an interrupt occurs while GIOTR is executing output is cancelled + # and further processing is disabled until the next frame begins. + + if (xint == NULL) + call xwhen (X_INT, locpr(giotr_onint), xint) + + call zsvjmp (jmpbuf, status) + if (status != OK) { + call gki_cancel (stream) + call gki_deactivatews (stream, 0) + } + + # Fetch, optionally transform, and execute each metacode instruction + # in the frame buffer. + + while (gtr_fetch_next_instruction (tr, gki) != EOF) { + switch (Mems[gki+GKI_HDR_OPCODE-1]) { + + case GKI_OPENWS: + mode = Mems[gki+GKI_OPENWS_M-1] + if (mode != APPEND) + status = OK + + if (status == OK) { + # If the open instruction has already been passed to the + # kernel by gtr_control, do not do so again here. + + if (TR_SKIPOPEN(tr) == YES) + TR_SKIPOPEN(tr) = NO + else + call gki_write (stream, Mems[gki]) + + # gtr_control does not call gki_escape so always do this. + call gki_escape (stream, GKI_OPENWS, 0, 0) + + # Discard frame buffer contents up to and including the + # openws instruction, so that it will only be executed + # once. + + if (Mems[gki+GKI_OPENWS_M-1] == NEW_FILE) + call gtr_frame (tr, TR_IP(tr), stream) + } + + case GKI_CLOSEWS, GKI_DEACTIVATEWS, GKI_REACTIVATEWS: + # These instructions are passed directly to the kernel via + # the PSIOCTRL stream at runtime, but are ignored in metacode + # to avoid unnecessary mode switching of the terminal. + ; + + case GKI_CANCEL: + # Cancel any buffered graphics data. + call gki_write (stream, Mems[gki]) + call gtr_frame (tr, TR_IP(tr), stream) + + case GKI_FLUSH, GKI_GETCURSOR, GKI_GETCELLARRAY: + # Do not buffer these instructions. + call gki_write (stream, Mems[gki]) + call gtr_delete (tr, gki) + + case GKI_CLEAR: + # Clear is special because it initializes things. + if (status != OK) { + call gki_reactivatews (stream, 0) + status = OK + } + # Execute the instruction. + call gki_write (stream, Mems[gki]) + call gki_escape (stream, GKI_CLEAR, 0, 0) + + # Discard frame buffer contents up to and including the clear. + call gtr_frame (tr, TR_IP(tr), stream) + + case GKI_SETWCS: + call gki_write (stream, Mems[gki]) + nwords = Mems[gki+GKI_SETWCS_N-1] + call amovs (Mems[gki+GKI_SETWCS_WCS-1], + Mems[coerce (TR_WCSPTR(tr,1), TY_STRUCT, TY_SHORT)], + min (nwords, LEN_WCS * MAX_WCS * SZ_STRUCT / SZ_SHORT)) + + case GKI_ESCAPE: + if (status == OK) { + fn = Mems[gki+GKI_ESCAPE_FN-1] + + # Execute the escape instruction. + if (wstranset == YES) { + call sge_wstran (fn, Mems[gki+GKI_ESCAPE_DC-1], + vx1,vy1, vx2,vy2) + } else + call gki_write (stream, Mems[gki]) + + # Allow the kernel escape handling code to preserve, + # delete, or edit the instruction. + + call sge_spoolesc (tr, gki, fn, Mems[gki+GKI_ESCAPE_DC-1], + TR_FRAMEBUF(tr), TR_OP(tr), locpr(gtr_delete)) + } + + default: + if (status == OK) + if (wstranset == YES) { + # Perform the workstation transformation and output the + # transformed instruction, if there is anything left. + call gtr_wstran (Mems[gki]) + } else + call gki_write (stream, Mems[gki]) + } + } + + # Clear the frame buffer if spooling is disabled. This is done by + # moving the upper part of the buffer to the beginning of the buffer, + # starting with the word pointed to by the second argument, preserving + # the partial instruction likely to be found at the end of the buffer. + # Truncate the buffer if it grows too large by the same technique of + # shifting data backwards, but in this case without destroying all + # of the data. + + if (TR_SPOOLDATA(tr) == NO) + call gtr_frame (tr, TR_IP(tr), stream) + else if (TR_OP(tr) - TR_FRAMEBUF(tr) > TR_MAXLENFRAMEBUF(tr)) + call gtr_truncate (tr, TR_IP(tr)) + + # Pop the interrupt handler. + if (xint != NULL) { + call xwhen (X_INT, xint, junk) + xint = NULL + } +end + + +# GIOTR_ONINT -- Interrupt handler for GIOTR. + +procedure giotr_onint (vex, next_handler) + +int vex # virtual exception +int next_handler # next exception handler in chain +int jmpbuf[LEN_JUMPBUF] +common /gtrvex/ jmpbuf + +begin + call xer_reset() + call zdojmp (jmpbuf, vex) +end diff --git a/sys/gio/cursor/grc.h b/sys/gio/cursor/grc.h new file mode 100644 index 00000000..35af451f --- /dev/null +++ b/sys/gio/cursor/grc.h @@ -0,0 +1,20 @@ +# GRC.H -- Global definitions and data structures for the RCURSOR (cursor read) +# procedures. + +define KEYSFILE "lib$scr/cursor.key" +define KEYSTROKES "ABCDEFHJKLMPRTUVWXYZ<>0123456789:=" +define MAX_KEYS 128 +define LEN_RCSTRUCT (10+(128/SZ_STRUCT)) + +define RC_CASE Memi[$1] # case sensitive +define RC_MARKCUR Memi[$1+1] # mark cursor +define RC_PHYSOPEN Memi[$1+2] # physical open by rcursor +define RC_AXES Memi[$1+3] # draw axes if screen redrawn + # (open) +define RC_KEYS Memc[P2C($1+10)+$2] # keystroke mappings + +define LEN_CT 2,4 +define CT_TRAN 1 +define CT_SCALE 2 +define CT_WORIGIN 3 +define CT_MORIGIN 4 diff --git a/sys/gio/cursor/grcaxes.x b/sys/gio/cursor/grcaxes.x new file mode 100644 index 00000000..f2f69e4f --- /dev/null +++ b/sys/gio/cursor/grcaxes.x @@ -0,0 +1,402 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <gset.h> +include <gio.h> +include "gtr.h" +include "grc.h" + +define LEN_POLYLINE 128 # polyline for axes and ticks +define NTICKS 6 # default rough ticks on an axis +define SZ_TICKFORMAT 6 # "%0.Xg" +define SZ_TICKLABEL 10 # encoded tick label +define TICKLEN 0.03 # tick length, ndc units +define LABELOFFSET 1.5 # offset to tick label in ticklen units + + +# GRC_AXES -- Draw and label the axes of the viewport. This is a simple +# routine not intended to be competitive with GLABAX. We draw a box around +# the edge of the screen, find and label the ticks within the plotting area. + +procedure grc_axes (stream, sx, sy, raster, rx, ry) + +int stream #I graphics stream +real sx, sy #I screen coords of cursor +int raster #I raster number +real rx, ry #I raster coords of cursor + +char tickformat[SZ_TICKFORMAT], ticklabel[SZ_TICKLABEL] +pointer tr, w, ap, save_op +int xt, yt, nwords, nticks, wcs, lt_save +real xb, xe, x1, dx, x, y, lw_save +real yb, ye, y1, dy, aspect_ratio, xticklen, yticklen + +int gt_ndigits() +pointer gtr_init() +real ttygetr() + +errchk gtr_init, ttygetr, realloc, gax_start +include "gtr.com" + +begin + tr = gtr_init (stream) + + # Draw the axes with a solid polyline of width 2.0. + ap = TR_PLAP(tr) + lt_save = PL_LTYPE(ap); PL_LTYPE(ap) = GL_SOLID + lw_save = PL_WIDTH(ap); PL_WIDTH(ap) = 2.0 + + # Select a WCS. + call grc_scrtowcs (stream, sx, sy, raster, rx, ry, x1, y1, wcs) + w = TR_WCSPTR(tr,wcs) + + # Get the coordinates of the axes corners and the tick parameters. + call gax_findticks (w, xb,xe,yb,ye, x1,dx,xt, y1,dy,yt) + + # Mark the position in the frame buffer. The axes drawing instructions + # will be appended to the frame buffer by the drawing routines. When + # we get all done we will move these instructions to the scratch buffer + # and reset the frame buffer pointers, since we do not want the axes + # to be a permanent part of the plot. + + save_op = TR_OP(tr) + + # Compute the X and Y tick lengths in NDC coordinates, corrected for + # the aspect ratio and workstation transformation. + + aspect_ratio = ttygetr (TR_TTY(tr), "ar") + if (aspect_ratio < .001) + aspect_ratio = 1.0 + xticklen = TICKLEN / xscale * aspect_ratio + yticklen = TICKLEN / yscale + + # Construct the polyline to draw the first two axes and ticks. We + # start at the lower left and draw to the lower right then upper right. + + nticks = int ((xe - xb) / dx) # Bottom axis. + call gax_start (xb, yb) + call gax_draw (x1, yb) + call gax_tick (0., yticklen) + + for (x=x1+dx; nticks > 0; nticks=nticks-1) { + call gax_draw (min(x,xe), yb) + call gax_tick (0., yticklen) + x = x + dx + } + + nticks = int ((ye - yb) / dy) # Right axis. + call gax_draw (xe, yb) + call gax_draw (xe, y1) + call gax_tick (-xticklen, 0.) + + for (y=y1+dy; nticks > 0; nticks=nticks-1) { + call gax_draw (xe, min(y,ye)) + call gax_tick (-xticklen, 0.) + y = y + dy + } + + call gax_draw (xe, ye) + call gax_flush (stream) + + # Construct the polyline to draw the second two axes and ticks. We + # start at the lower left and draw to the upper left then upper right. + + nticks = int ((ye - yb) / dy) # Left axis. + call gax_start (xb, yb) + call gax_draw (xb, y1) + call gax_tick (xticklen, 0.) + + for (y=y1+dy; nticks > 0; nticks=nticks-1) { + call gax_draw (xb, min(y,ye)) + call gax_tick (xticklen, 0.) + y = y + dy + } + + nticks = int ((xe - xb) / dx) # Top axis. + call gax_draw (xb, ye) + call gax_draw (x1, ye) + call gax_tick (0., -yticklen) + + for (x=x1+dx; nticks > 0; nticks=nticks-1) { + call gax_draw (min(x,xe), ye) + call gax_tick (0., -yticklen) + x = x + dx + } + + call gax_draw (xe, ye) + call gax_flush (stream) + + # Label the ticks on the bottom axis. The tick labels are centered + # just above each tick. + + nticks = int ((xe - xb) / dx) + 1 + call sprintf (tickformat, SZ_TICKFORMAT, "%%0.%dg") + call pargi (max (1, gt_ndigits (xb, xe, dx)) + 1) + + for (x=x1; nticks > 0; nticks=nticks-1) { + call glb_encode (x, ticklabel, SZ_TICKLABEL, tickformat, dx) + call gax_ndc (x, yb, sx, sy) + call gax_text (stream, sx, sy + (yticklen * LABELOFFSET), + ticklabel, GT_CENTER, GT_BOTTOM) + x = x + dx + } + + # Label the ticks on the left axis. The tick labels are left justified + # just to the right of each tick. + + nticks = int ((ye - yb) / dy) + 1 + call sprintf (tickformat, SZ_TICKFORMAT, "%%0.%dg") + call pargi (max (1, gt_ndigits (yb, ye, dy)) + 1) + + for (y=y1; nticks > 0; nticks=nticks-1) { + call glb_encode (y, ticklabel, SZ_TICKLABEL, tickformat, dy) + call gax_ndc (xb, y, sx, sy) + call gax_text (stream, sx + (xticklen * LABELOFFSET), sy, + ticklabel, GT_LEFT, GT_CENTER) + y = y + dy + } + + # Restore the default polyline attributes. + PL_LTYPE(ap) = lt_save + PL_WIDTH(ap) = lw_save + + # Move the axes drawing and labelling instructions to the scratch + # buffer and fix up the frame buffer pointers. + + nwords = TR_OP(tr) - save_op + if (nwords > TR_LENSCRATCHBUF(tr)) { + call realloc (TR_SCRATCHBUF(tr), nwords, TY_SHORT) + TR_LENSCRATCHBUF(tr) = nwords + } + + call amovs (Mems[save_op], Mems[TR_SCRATCHBUF(tr)], nwords) + TR_OPSB(tr) = TR_SCRATCHBUF(tr) + nwords + TR_OP(tr) = save_op + TR_IP(tr) = save_op + TR_LASTOP(tr) = save_op +end + + +# GAX_FINDTICKS -- Get the coordinates of the endpoints of the axes, the first +# tick on each axis, and the tick spacing on each axis. If log scaling is in +# use on an axis we shall work in log coordinate units, which are linear. + +procedure gax_findticks (w, wx1,wx2,wy1,wy2, x1,dx,xt, y1,dy,yt) + +pointer w # window descriptor +real wx1,wx2,wy1,wy2 # endpoints of axes +real x1,dx # tick start and spacing in X +int xt # type of scaling in X +real y1,dy # tick start and spacing in Y +int yt # type of scaling in Y + +pointer wp +real ct[LEN_CT] +common /ftkgcm/ wp, ct + +real sx1, sx2, sy1, sy2 +real elogr() + +begin + wp = w + + # Set up WCS/NDC coordinate transformations. + call grc_settran (w, ct) + + # Get NDC coords of the corners of the screen. + call grc_scrtondc (0.001, 0.001, sx1, sy1) + call grc_scrtondc (0.999, 0.999, sx2, sy2) + + # Move in a bit if the graphics viewport lies within the screen area. + # This depends upon the workstation transformation, of course. + sx1 = max (WCS_SX1(w), sx1) + sx2 = min (WCS_SX2(w), sx2) + sy1 = max (WCS_SY1(w), sy1) + sy2 = min (WCS_SY2(w), sy2) + + # Compute world coordinates of the viewport (of the axes to be drawn). + call grc_ndctowcs (ct, sx1, sy1, wx1, wy1) + call grc_ndctowcs (ct, sx2, sy2, wx2, wy2) + + # Find the ticks. If log scaling is in use on an axis we shall find + # and draw the ticks in log coordinates. + + switch (WCS_XTRAN(w)) { + case GW_LOG: + wx1 = log10 (wx1) + wx2 = log10 (wx2) + case GW_ELOG: + wx1 = elogr (wx1) + wx2 = elogr (wx2) + } + call gtickr (wx1, wx2, NTICKS, NO, x1, dx) + + switch (WCS_YTRAN(w)) { + case GW_LOG: + wy1 = log10 (wy1) + wy2 = log10 (wy2) + case GW_ELOG: + wy1 = elogr (wy1) + wy2 = elogr (wy2) + } + call gtickr (wy1, wy2, NTICKS, NO, y1, dy) + + xt = WCS_XTRAN(w) + yt = WCS_YTRAN(w) +end + + +# GAX_NDC -- Convert a pair of world or log-world coordinates to NDC +# coordinates. GAX_FINDTICKS must be called first to set up transformation. + +procedure gax_ndc (wx, wy, sx, sy) + +real wx, wy # world coords (input) +real sx, sy # ndc coords (output) + +pointer wp +real ct[LEN_CT] +common /ftkgcm/ wp, ct + +real x, y +real aelogr() + +begin + # Get X in world coordinates. + switch (WCS_XTRAN(wp)) { + case GW_LOG: + x = 10.0 ** wx + case GW_ELOG: + x = aelogr (wx) + default: + x = wx + } + + # Get Y in world coordinates. + switch (WCS_YTRAN(wp)) { + case GW_LOG: + y = 10.0 ** wy + case GW_ELOG: + y = aelogr (wy) + default: + y = wy + } + + # Transform to NDC coordinates and return. + call grc_wcstondc (ct, x, y, sx, sy) +end + + +# GAX_DRAW -- Add a point to the output polyline for an axis. The polyline +# is built up in NDC coordinates for output to GTR_POLYLINE. In addition to +# the draw routine, entry points are provided for start, flush, and tick +# drawing. + +procedure gax_draw (wx, wy) + +real wx, wy # world or log-world coords to draw to +real sx, sy +pointer polyline, op +common /gaxdcm/ polyline, op + +begin + # Transform to NDC coords and add the point to the polyline. + call gax_ndc (wx, wy, sx, sy) + Memr[op] = sx + op = op + 1 + Memr[op] = sy + op = op + 1 +end + + +# GAX_TICK -- Draw a tick at the current position. The offsets to draw the +# tick are given in NDC coordinates. + +procedure gax_tick (dx, dy) + +real dx, dy # tick offset in NDC coords for gax_tick +real x, y +pointer polyline, op +common /gaxdcm/ polyline, op + +begin + x = Memr[op-2] + y = Memr[op-1] + + Memr[op] = x + dx + op = op + 1 + Memr[op] = y + dy + op = op + 1 + + Memr[op] = x + op = op + 1 + Memr[op] = y + op = op + 1 +end + + +# GAX_START -- Start a new polyline at the indicated point in world coords. +# The polyline buffer is of a fixed length with no bounds checking. + +procedure gax_start (wx, wy) + +real wx, wy # world or log-world coords to draw to +pointer polyline, op + +errchk malloc +common /gaxdcm/ polyline, op + +begin + call malloc (polyline, LEN_POLYLINE, TY_REAL) + op = polyline + call gax_draw (wx, wy) +end + + +# GAX_FLUSH -- Flush the buffered polyline and free space on the heap. + +procedure gax_flush (stream) + +int stream # graphics stream +pointer polyline, op +common /gaxdcm/ polyline, op + +begin + call grc_polyline (stream, Memr[polyline], (op - polyline) / 2) + call mfree (polyline, TY_REAL) +end + + +# GAX_TEXT -- Draw a text string (tick label) of size 1.0 with the indicated +# justification. + +procedure gax_text (stream, sx, sy, text, hjustify, vjustify) + +int stream # graphics stream +real sx, sy # text coordinates, NDC +char text[ARB] # text string to be drawn +int hjustify # horizontal justification +int vjustify # vertical justification + +pointer tr, tx +int save_tx[LEN_TX] +errchk gtr_init +pointer gtr_init() + +begin + tr = gtr_init (stream) + tx = TR_TXAP(tr) + call amovi (Memi[tx], save_tx, LEN_TX) + + TX_UP(tx) = 90 + TX_SIZE(tx) = 1.0 + TX_PATH(tx) = GT_RIGHT + TX_SPACING(tx) = 0 + TX_HJUSTIFY(tx) = hjustify + TX_VJUSTIFY(tx) = vjustify + TX_FONT(tx) = GT_BOLD + TX_QUALITY(tx) = GT_NORMAL + TX_COLOR(tx) = 1 + + call grc_text (stream, sx, sy, text) + call amovi (save_tx, Memi[tx], LEN_TX) +end diff --git a/sys/gio/cursor/grcclose.x b/sys/gio/cursor/grcclose.x new file mode 100644 index 00000000..304a0904 --- /dev/null +++ b/sys/gio/cursor/grcclose.x @@ -0,0 +1,42 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <gio.h> +include "gtr.h" +include "grc.h" + +# GRC_CLOSE -- Close the workstation (kernel). Called by RCURSOR to close the +# kernel after a cursor read. Note that a cursor read may occur while the +# workstation is open, i.e., after gopen but before gclose, or after the +# workstation has been closed, i.e., after a plotting program terminates. +# If the workstation was already open (GKI_OPENWS) by the application when +# the cursor read occurred we must leave things as they were. + +procedure grc_close (fd, rc) + +int fd # graphics stream +pointer rc # rcursor descriptor + +pointer tr +pointer gtr_init() +errchk gtr_init + +begin + tr = gtr_init (fd) + + # Decrement the logical OPENWS count and issue the actual CLOSEWS + # only if the counter goes to zero. If the workstation was open + # but deactivated when grc_open() was called (WS_ACTIVE == NO), + # restore it to its former (deactivated) state. + + TR_WSOPEN(tr) = TR_WSOPEN(tr) - 1 + if (TR_WSOPEN(tr) <= 0) { + call gki_closews (fd, TR_DEVNAME(tr)) + TR_WSOPEN(tr) = 0 + TR_WSACTIVE(tr) = NO + } else if (TR_WSACTSAVE(tr) == NO) { + call gki_deactivatews (fd, 0) + TR_WSACTIVE(tr) = NO + } + + call gki_fflush (fd) +end diff --git a/sys/gio/cursor/grccmd.x b/sys/gio/cursor/grccmd.x new file mode 100644 index 00000000..5aca0f84 --- /dev/null +++ b/sys/gio/cursor/grccmd.x @@ -0,0 +1,533 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <ttyset.h> +include <ctype.h> +include <mach.h> +include <fset.h> +include <gset.h> +include <gki.h> +include <gio.h> +include "gtr.h" +include "grc.h" + +define MAX_KWLEN 10 + +# Assign opcodes to the recognized keywords. + +define KW_AXES 1 +define KW_CASE 2 +define KW_CLEAR 3 +define KW_CURSOR 4 +define KW_GFLUSH 5 +define KW_HELP 6 +define KW_INIT 7 +define KW_MARKCUR 8 +define KW_OFF 9 +define KW_ON 10 +define KW_PAGE 11 +define KW_READ 12 +define KW_SHOW 13 +define KW_SNAP 14 +define KW_TXQUALITY 15 +define KW_TXSET 16 +define KW_VIEWPORT 17 +define KW_WRITE 18 +define KW_XRES 19 +define KW_YRES 20 +define KW_ZERO 21 + + +# GRC_COMMAND -- Process a ":." cursor mode option string. The RC structure +# contains the current values of the cursor mode options. Some option strings +# are commands that do something, others set options, and still others show +# the status of the program. + +int procedure grc_command (rc, stream, sx, sy, raster, rx, ry, opstr) + +pointer rc #I rcursor descriptor +int stream #I graphics stream +real sx, sy #I screen coords of cursor +int raster #I raster number +real rx, ry #I raster coords of cursor +char opstr[ARB] #I options string excluding the leading ":.". + +pointer tr, p_tr, sp, fname, lbuf, tty +bool clobber, fullframe, auto_gflush +int ip, op, ch, opcode, cursor +int save1, save2, i, xres, yres, quality +char kwname[MAX_KWLEN] + +pointer gtr_init(), grc_open(), ttyodes() +int strdic(), grc_boolval(), ttygeti(), ttystati() +real grc_realval() +string keywords "|axes|case|clear|cursor|gflush|help|init|markcur|off|on|page|\ +read|show|snap|txquality|txset|viewport|write|xres|yres|zero|" +errchk gtr_redraw, gki_flush, gtr_init +define exit_ 91 + +begin + call smark (sp) + call salloc (fname, SZ_FNAME, TY_CHAR) + call salloc (lbuf, SZ_LINE, TY_CHAR) + + # The terminal is left in graphics mode when the user types return to + # enter the command. Echo the user command to the terminal without + # the newline to leave the terminal in status line mode, so that any + # output directly to the terminal from the lower level code in the CL + # goes into the status line. + + call strcpy (":.", Memc[lbuf], SZ_LINE) + op = lbuf + 2 + for (ip=1; opstr[ip] != EOS && opstr[ip] != '\n'; ip=ip+1) { + Memc[op] = opstr[ip] + op = op + 1 + } + Memc[op] = EOS + call stg_putline (STDERR, Memc[lbuf]) + + tr = gtr_init (stream) + ip = 1 + + while (ip == 1 || opstr[ip] != EOS) { + while (IS_WHITE(opstr[ip])) + ip = ip + 1 + + # If EOS and not first command, all done. If first command do + # not quit, rather assume ":.help" (see below). + + if (ip > 1 && opstr[ip] == EOS) + break + + # Extract the keyword into the KWNAME buffer. Leave the input + # pointer positioned to the first char following the keyword. + + for (op=1; opstr[ip] != EOS; ip=ip+1) { + ch = opstr[ip] + if (IS_ALNUM(ch)) { + kwname[op] = ch + op = op + 1 + } else + break + } + kwname[op] = EOS + + # Look up the keyword in the dictionary. If not found ring the bell + # but do not return EOF (do not quit cursor mode). + + if (op == 1) + opcode = KW_HELP + else { + opcode = strdic (kwname, kwname, MAX_KWLEN, keywords) + if (opcode <= 0) { + call fprintf (STDERR, "\7") + goto exit_ + } + } + + # Process the command. + + switch (opcode) { + case KW_AXES: + # Set flag to draw axes of viewport when screen readrawn. + RC_AXES(rc) = grc_boolval (opstr, ip) + + case KW_CASE: + # Enable/disable case sensitivity. + RC_CASE(rc) = grc_boolval (opstr, ip) + + case KW_CLEAR: + # Clear the alpha screen. + iferr (tty = ttyodes ("terminal")) + call grc_warn (STDERR) + else { + do i = 1, ttystati (tty, TTY_NLINES) { + call ttygoto (STDOUT, tty, 1, i) + call ttyclearln (STDOUT, tty) + } + call flush (STDOUT) + call ttycdes (tty) + } + + case KW_CURSOR: + # Select the cursor to be referenced in all subsequent reads + # and writes. + + ip = ip + 1 + cursor = max (0, nint (grc_realval (opstr, ip))) + call stg_lockcursor (cursor) + + case KW_GFLUSH: + # Flush any buffered graphics output (dispose of spooled + # plotter output). + + call stg_putline (STDERR, " - ") + call gtr_gflush (STDPLOT) + + case KW_HELP: + # Print help text for cursor mode. + call gtr_page (STDERR, stream) + iferr (call pagefile (KEYSFILE, "cursor mode help")) + call grc_warn (STDERR) + ip = ip + 1 + + case KW_INIT: + # Disconnect all kernels and free memory. Exits cursor mode + # with an EOF. + + call stg_putline (STDERR, " - ") + call gtr_reset (OK) + call sfree (sp) + return (EOF) + + case KW_MARKCUR: + # Enable marking of the cursor position when the cursor is read. + RC_MARKCUR(rc) = grc_boolval (opstr, ip) + + case KW_OFF: + # Disable the listed keys. + call grc_keys (rc, opstr, ip, 0) + + case KW_ON: + # Enable or set the listed keys. + call grc_keys (rc, opstr, ip, 1) + + case KW_PAGE: + # Enable screen clear when ?, show, etc. print text. + TR_PAGE(tr) = grc_boolval (opstr, ip) + + case KW_READ: + # Fill the frame buffer from a metacode spool file. + + call grc_word (opstr, ip, Memc[fname], SZ_FNAME) + call grc_read (tr, stream, Memc[fname]) + + case KW_SHOW: + # Show status of RCURSOR and GIOTR. + + call gtr_page (STDERR, stream) + call fprintf (STDERR, "Cursor Mode Parameters:\n\n") + call grc_status (STDERR, rc) + + call fprintf (STDERR, "\n\nGraphics Kernel Status:\n\n") + call gtr_status (STDERR) + + case KW_SNAP: + # Write a snapshot of the screen to a plotter. Open a subkernel + # on STDPLOT, redraw the screen into the STDPLOT fio buffer, + # flush the buffered metacode to the kernel, then restore + # everything. NOTE: should restore things automatically if an + # interrupt occurs. + + call stg_putline (STDERR, " - ") + call grc_word (opstr, ip, Memc[fname], SZ_FNAME) + iferr (p_tr = grc_open (Memc[fname], NEW_FILE, STDPLOT, rc)) { + call grc_warn (STDERR) + goto exit_ + } + + call gki_redir (stream, STDPLOT, save1, save2) + call fseti (STDPLOT, F_CANCEL, OK) + + iferr { + call gtr_redraw (stream) + call gki_flush (STDPLOT) + } then + call grc_warn (STDERR) + + call gki_redir (stream, 0, save1, save2) + + auto_gflush = (ttygeti (TR_TTY(p_tr), "MF") <= 1) + call grc_close (STDPLOT, rc) + + if (auto_gflush) + call gtr_gflush (STDPLOT) + + call stg_putline (STDERR, " done") + + case KW_VIEWPORT: + # Set the viewport in world coordinates. + call grc_viewport (tr, stream, + sx, sy, raster, rx, ry, opstr, ip) + + case KW_WRITE: + # Save the contents of the frame buffer in a file. + # "w!" clobbers any existing file and "w+" writes the + # full frame. By default the frame is appended to the + # output file. + + if (opstr[ip] == '!') { + clobber = true + ip = ip + 1 + } else + clobber = false + + if (opstr[ip] == '+') { + fullframe = true + ip = ip + 1 + } else + fullframe = false + + # Extract the filename. + call grc_word (opstr, ip, Memc[fname], SZ_FNAME) + + # Write to the spoolfile. + call grc_write (tr, stream, Memc[fname], clobber, fullframe) + + case KW_XRES: + # Set the stdgraph X resolution. + xres = nint (grc_realval (opstr, ip)) + yres = 0 + call stg_resolution (xres, yres) + + case KW_YRES: + # Set the stdgraph Y resolution. + xres = 0 + yres = nint (grc_realval (opstr, ip)) + call stg_resolution (xres, yres) + + case KW_TXQUALITY: + # Set character generator quality. + + while (IS_WHITE(opstr[ip])) + ip = ip + 1 + + switch (opstr[ip]) { + case 'l': + quality = GT_LOW + case 'm': + quality = GT_MEDIUM + case 'h': + quality = GT_HIGH + default: + quality = 0 + } + call stg_txquality (quality) + + case KW_TXSET: + # Set the text drawing attributes. + call gtxset (TR_TXAP(tr), opstr, ip) + + case KW_ZERO: + # Reset and redraw. + call gtr_ptran (stream, 0., 1., 0., 1.) + call gtr_writecursor (stream, .5, .5) + call gtr_redraw (stream) + } + + # Advance to the next statement or the end of string. Any unused + # characters in the statement just processed are discarded. + + while (opstr[ip] != ';' && opstr[ip] != EOS) + ip = ip + 1 + while (opstr[ip] == ';' || opstr[ip] == '.') + ip = ip + 1 + } +exit_ + # Restore the terminal to graphics mode if gtr_page was not called to + # deactivate the ws. (this leaves the waitpage flag set). + + if (TR_WAITPAGE(tr) == NO) + call stg_putline (STDERR, "\n") + + # Leave the graphics descriptor set up as we found it. + tr = gtr_init (stream) + + call flush (STDERR) + call sfree (sp) + return (OK) +end + + +# GRC_WORD -- Extract the next whitespace delimited word from the command line. + +procedure grc_word (opstr, ip, outstr, maxch) + +char opstr[ARB] # input string +int ip # pointer into input string +char outstr[ARB] # output string +int maxch # max chars out +int op + +begin + while (IS_WHITE (opstr[ip])) + ip = ip + 1 + + op = 1 + while (!IS_WHITE (opstr[ip]) && opstr[ip] != EOS) { + outstr[op] = opstr[ip] + op = op + 1 + ip = ip + 1 + } + + outstr[op] = EOS +end + + +# GRC_BOOL -- Get the boolean value of a parameter. Upon entry, the input +# pointer is positioned to the first character following the parameter name. + +int procedure grc_boolval (opstr, ip) + +char opstr[ARB] # command string +int ip # input pointer +int value +int btoi() + +begin + while (IS_WHITE (opstr[ip])) + ip = ip + 1 + + if (opstr[ip] == '=') { + ip = ip + 1 + while (IS_WHITE (opstr[ip])) + ip = ip + 1 + value = btoi (opstr[ip] != 'n' && opstr[ip] != 'N') + while (IS_ALPHA (opstr[ip])) + ip = ip + 1 + } else + value = btoi (opstr[ip] != '-') + + return (value) +end + + +# GRC_REALVAL -- Get the real value of a parameter. Upon entry, the input +# pointer is positioned to the first character following the parameter name. +# Zero is returned if no value is given. + +real procedure grc_realval (opstr, ip) + +char opstr[ARB] # command string +int ip # input pointer +real value +int ctor() + +begin + while (IS_WHITE (opstr[ip])) + ip = ip + 1 + if (opstr[ip] == '=') + ip = ip + 1 + while (IS_WHITE (opstr[ip])) + ip = ip + 1 + + if (ctor (opstr, ip, value) <= 0) + value = 0 + + return (value) +end + + +# GRC_KEYS -- Enable the listed keys or ranges of keys. The operation is +# additive, i.e., only the named keys are affected. + +procedure grc_keys (rc, opstr, ip, onoff) + +pointer rc # rcursor descriptor +char opstr[ARB] # command string +int ip # next char in opstr +int onoff # set keys on (1) or off (0) + +int new_value +int ch, ch1, ch2, ip_start, i +string keys KEYSTROKES + +begin + while (IS_WHITE (opstr[ip])) + ip = ip + 1 + + ip_start = ip + for (ch=opstr[ip]; ch != EOS; ch=opstr[ip]) { + if (ch == ';' || ch == '\n' || IS_WHITE(ch)) + break + + ch1 = ch + if (opstr[ip+1] == '-' && opstr[ip+2] != EOS) { + # Enable a range of keys. + ip = ip + 2 + ch2 = opstr[ip] + } else if (opstr[ip+1] == '=' && opstr[ip+2] != EOS) { + # Assign the value of a key. + ip = ip + 3 + RC_KEYS(rc,ch) = opstr[ip] + next + } else + ch2 = ch + + for (ch=ch1; ch <= ch2; ch=ch+1) { + if (onoff == 0) + new_value = 0 + else + new_value = ch + RC_KEYS(rc,ch) = new_value + } + + ip = ip + 1 + } + + # If no keys were listed, set all cursor mode keys. + if (ip == ip_start) + for (i=1; keys[i] != EOS; i=i+1) { + ch = keys[i] + if (onoff == 0) + new_value = 0 + else + new_value = ch + RC_KEYS(rc,ch) = new_value + } + + # The ":" key cannot be mapped or disabled. + RC_KEYS(rc,':') = ':' +end + + +# GRC_VIEWPORT -- Set the viewport in world coordinates. Use the current +# cursor position to determine the WCS, then convert the world coordinates +# of the viewport given by the user into NDC coordinates and set the work- +# station transformation. + +procedure grc_viewport (tr, stream, sx, sy, raster, rx, ry, opstr, ip) + +pointer tr #I giotr descriptor +int stream #I graphics stream +real sx, sy #I screen coordinates of cursor +int raster #I raster number +real rx, ry #I raster coordinates of cursor +char opstr[ARB] #I command string +int ip #I input pointer + +pointer w +int i, wcs +real wx, wy, value +real vn[4], vw[4], ct[LEN_CT] +int ctor() + +begin + # Select a WCS. We are not otherwise interested in the cursor value. + call grc_scrtowcs (stream, sx, sy, raster, rx, ry, wx, wy, wcs) + w = TR_WCSPTR(tr,wcs) + call grc_settran (w, ct) + + # Start with the current viewport. + call gtr_gtran (stream, vn[1], vn[2], vn[3], vn[4]) + + # Transform to world coordinates. + call grc_ndctowcs (ct, vn[1], vn[3], vw[1], vw[3]) + call grc_ndctowcs (ct, vn[2], vn[4], vw[2], vw[4]) + + # Get the new viewport (world) coordinates. + do i = 1, 4 + if (ctor (opstr, ip, value) <= 0) + break + else + vw[i] = value + + # Transform to NDC coordinates. + call grc_wcstondc (ct, vw[1], vw[3], vn[1], vn[3]) + call grc_wcstondc (ct, vw[2], vw[4], vn[2], vn[4]) + + # Set the new workstation transformation. + call gtr_ptran (stream, vn[1], vn[2], vn[3], vn[4]) + + # Redraw the screen. + call gtr_redraw (stream) +end diff --git a/sys/gio/cursor/grcinit.x b/sys/gio/cursor/grcinit.x new file mode 100644 index 00000000..3160203c --- /dev/null +++ b/sys/gio/cursor/grcinit.x @@ -0,0 +1,32 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <gio.h> +include "grc.h" + +# GRC_INIT -- Initialize the rcursor descriptor. Allocate storage for the +# descriptor and initialize all variables and the keystroke mapping. + +procedure grc_init (rc) + +pointer rc #U grc descriptor (pointer) + +int ip, ch +string keys KEYSTROKES +errchk malloc + +begin + if (rc == NULL) + call malloc (rc, LEN_RCSTRUCT, TY_STRUCT) + call aclri (Memi[rc], LEN_RCSTRUCT) + + # Initialize variables. + RC_CASE(rc) = YES + RC_MARKCUR(rc) = NO + RC_PHYSOPEN(rc) = NO + + # Initialize keystrokes. + for (ip=1; keys[ip] != EOS; ip=ip+1) { + ch = keys[ip] + RC_KEYS(rc,keys[ip]) = ch + } +end diff --git a/sys/gio/cursor/grcopen.x b/sys/gio/cursor/grcopen.x new file mode 100644 index 00000000..8a39d191 --- /dev/null +++ b/sys/gio/cursor/grcopen.x @@ -0,0 +1,105 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <syserr.h> +include <gio.h> +include <gki.h> +include "gtr.h" +include "grc.h" + +# GRC_OPEN -- Open the workstation. Most commonly used to reopen the +# workstation for a cursor read after plotting. + +pointer procedure grc_open (device, mode, stream, rc) + +char device[ARB] # device name (optional) +int mode # desired access mode +int stream # graphics stream +pointer rc # rcursor descriptor + +pointer sp, devname, envvar, tr +int envgets() +bool streq() +pointer gtr_init() + +include "gtr.com" +string stdgraph "stdgraph" +string stdimage "stdimage" +string stdplot "stdplot" +errchk syserrs, gtr_openws, gki_openws, gtr_init + +begin + call smark (sp) + call salloc (envvar, SZ_FNAME, TY_CHAR) + call salloc (devname, SZ_FNAME, TY_CHAR) + + tr = gtr_init (stream) + + # If the workstation is already connected and the kernel is open + # issue the openws directive if it has not already been issued. + + if (TR_DEVNAME(tr) != EOS) + if (device[1] == EOS || streq (device, TR_DEVNAME(tr))) { + # Kernel is already physically open on this stream. Activate + # it if necessary; record whether or not is was active when + # we were called, so that we can restore the original state + # when grc_close() is called. + + if (TR_WSOPEN(tr) <= 0) { + call gki_openws (stream, TR_DEVNAME(tr), mode) + TR_WSACTIVE(tr) = YES + TR_WSACTSAVE(tr) = NO + } else { + TR_WSACTSAVE(tr) = TR_WSACTIVE(tr) + call gki_reactivatews (stream, 0) + TR_WSACTIVE(tr) = YES + } + + call gki_fflush (stream) + + TR_WSOPEN(tr) = TR_WSOPEN(tr) + 1 + call sfree (sp) + return (tr) + } + + # If no device name given fetch the device name from the environment. + + if (device[1] == EOS) { + switch (stream) { + case STDGRAPH: + call strcpy (stdgraph, Memc[envvar], SZ_FNAME) + case STDIMAGE: + call strcpy (stdimage, Memc[envvar], SZ_FNAME) + default: + call strcpy (stdplot, Memc[envvar], SZ_FNAME) + } + + # Convert environment variable name into device name. Indirection + # and assumption of the value of "terminal" are allowed. + + repeat { + if (envgets (Memc[envvar], Memc[devname], SZ_FNAME) <= 0) + call syserrs (SYS_ENVNF, Memc[envvar]) + if (Memc[devname] == '@') { + # Indirection in environment variable name. + call strcpy (Memc[devname+1], Memc[envvar], SZ_FNAME) + } else if (streq (Memc[devname], "terminal")) { + call strcpy (Memc[devname], Memc[envvar], SZ_FNAME) + } else + break + } + } else + call strcpy (device, Memc[devname], SZ_FNAME) + + # Open the workstation (kernel) on stream FD. + call gtr_openws (Memc[devname], mode, stream, NULL) + + TR_WSOPEN(tr) = TR_WSOPEN(tr) + 1 + TR_WSACTSAVE(tr) = NO + TR_WSACTIVE(tr) = YES + + call gki_openws (stream, Memc[devname], mode) + call gki_fflush (stream) + + call sfree (sp) + return (tr) +end diff --git a/sys/gio/cursor/grcpl.x b/sys/gio/cursor/grcpl.x new file mode 100644 index 00000000..7768bf85 --- /dev/null +++ b/sys/gio/cursor/grcpl.x @@ -0,0 +1,69 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <gset.h> +include <gki.h> +include <gio.h> +include "gtr.h" +include "grc.h" + +# GRC_POLYLINE -- Draw a solid polyline. The instruction is encoded and +# appended to the frame buffer and GIOTR is called to draw the line, +# possibly applying the workstation transformation in the process. + +procedure grc_polyline (stream, v, npts) + +int stream # graphics stream +real v[ARB] # polyline, NDC units +int npts # number of points (coord pairs) in polyline + +pointer tr, sp, p, pl, op, last_op +int nwords, fd, save1, save2, i +int stropen() +pointer gtr_init(), gtr_writep() +errchk gtr_init, gtr_writep, gki_redir + +begin + call smark (sp) + call salloc (p, npts * 2, TY_SHORT) + + tr = gtr_init (stream) + + # Transform the type real, NDC polyline to GKI units, type short. + do i = 1, npts * 2, 2 { + Mems[p+i-1] = v[i ] * GKI_MAXNDC + Mems[p+i ] = v[i+1] * GKI_MAXNDC + } + + # Allocate space in the frame buffer for the polyline set attribute + # and line drawing instructions. Set the last op for undo to undo + # the line. This is also set by writep, hence we must wait to set + # TR_LASTOP until after the call to writep. + + last_op = TR_OP(tr) + nwords = GKI_PLSET_LEN + GKI_POLYLINE_LEN + (npts * 2) + op = gtr_writep (stream, nwords) + TR_LASTOP(tr) = last_op + + # Open the frame buffer as a file and redirect the graphics stream + # output into the buffer. + + fd = stropen (Mems[op], nwords, NEW_FILE) + call gki_redir (stream, fd, save1, save2) + + # Output a polyline set attribute instruction to ensure that a solid + # line is drawn. Output the polyline. + + pl = TR_PLAP(tr) + call gki_plset (stream, pl) + call gki_polyline (stream, Mems[p], npts) + + # Restore the normal output for the stream. + call gki_redir (stream, 0, save1, save2) + call close (fd) + + # Call giotr to send the new instructions off the to the kernel, + # optionally applying the workstation transformation in the process. + + call giotr (stream) + call sfree (sp) +end diff --git a/sys/gio/cursor/grcread.x b/sys/gio/cursor/grcread.x new file mode 100644 index 00000000..ce95fc07 --- /dev/null +++ b/sys/gio/cursor/grcread.x @@ -0,0 +1,60 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <fset.h> +include <gio.h> +include "gtr.h" + +# GRC_READ -- Fill the frame buffer from a metacode spool file and redraw +# the screen. The contents of the frame buffer are overwritten. + +procedure grc_read (tr, stream, fname) + +pointer tr # graphics descriptor +int stream # graphics stream +char fname[ARB] # metacode file + +pointer sp, lbuf, op +int fd, nchars, filelen +long fstatl() +pointer gtr_writep() +int open(), read() +errchk read +define err_ 91 + +begin + call smark (sp) + call salloc (lbuf, SZ_LINE, TY_CHAR) + + iferr (fd = open (fname, READ_ONLY, BINARY_FILE)) { + call grc_message (stream, " - cannot open file") + call sfree (sp) + return + } + + filelen = fstatl (fd, F_FILESIZE) + call sprintf (Memc[lbuf], SZ_LINE, " - file size %d chars") + call pargi (filelen) + call grc_message (stream, Memc[lbuf]) + + # Discard the current frame. + call gtr_frame (tr, TR_FRAMEBUF(tr), stream) + + # Read new frame buffer. + nchars = filelen + if (nchars <= 0) + goto err_ + op = gtr_writep (stream, nchars) + if (read (fd, Mems[op], nchars) < nchars) + goto err_ + + # Redraw the new frame buffer. + call gtr_redraw (stream) + + call close (fd) + call sfree (sp) + return +err_ + call close (fd) + call grc_message (stream, " [READ ERROR]") + call sfree (sp) +end diff --git a/sys/gio/cursor/grcredraw.x b/sys/gio/cursor/grcredraw.x new file mode 100644 index 00000000..4317db96 --- /dev/null +++ b/sys/gio/cursor/grcredraw.x @@ -0,0 +1,21 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <gio.h> +include "grc.h" + +# GRC_REDRAW -- Redraw the screen, and, if the "axes" flag is set, draw the axes +# of the plot. + +procedure grc_redraw (rc, stream, sx, sy, raster, rx, ry) + +pointer rc #I rcursor descriptor +int stream #I graphics stream +real sx, sy #I screen coords of cursor +int raster #I raster number +real rx, ry #I raster coords of cursor + +begin + call gtr_redraw (stream) + if (RC_AXES(rc) == YES) + call grc_axes (stream, sx, sy, raster, rx, ry) +end diff --git a/sys/gio/cursor/grcscr.x b/sys/gio/cursor/grcscr.x new file mode 100644 index 00000000..add322b4 --- /dev/null +++ b/sys/gio/cursor/grcscr.x @@ -0,0 +1,49 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <gio.h> +include <gki.h> +include "gtr.h" + +# GRC_SCRTONDC -- Coordinate transformation from screen coordinates to NDC +# coordinates. Screen coordinates physically address the device screen and +# range from 0 to 1 in either axis. NDC coordinates also range from 0 to 1 +# in either axis but differ from screen coordinates when the workstation +# transformation is non unitary. The workstation transformation parameters +# are cached in the GTR common. We assume that GTR_INIT has already been +# called to initialize the common for a graphics stream. + +procedure grc_scrtondc (sx, sy, mx, my) + +real sx, sy # screen coordinates (input) +real mx, my # NDC coordinates (output) +include "gtr.com" + +begin + if (wstranset == YES) { + mx = ((sx * GKI_MAXNDC - xorigin) / xscale + mx1) / GKI_MAXNDC + my = ((sy * GKI_MAXNDC - yorigin) / yscale + my1) / GKI_MAXNDC + } else { + mx = sx + my = sy + } +end + + +# GRC_NDCTOSCR -- Coordinate transformation from NDC coordinates to screen +# coordinates. + +procedure grc_ndctoscr (mx, my, sx, sy) + +real mx, my # NDC coordinates (input) +real sx, sy # screen coordinates (output) +include "gtr.com" + +begin + if (wstranset == YES) { + sx = ((mx * GKI_MAXNDC - mx1) * xscale + xorigin) / GKI_MAXNDC + sy = ((my * GKI_MAXNDC - my1) * yscale + yorigin) / GKI_MAXNDC + } else { + sx = mx + sy = my + } +end diff --git a/sys/gio/cursor/grcstatus.x b/sys/gio/cursor/grcstatus.x new file mode 100644 index 00000000..55f44f18 --- /dev/null +++ b/sys/gio/cursor/grcstatus.x @@ -0,0 +1,49 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <gio.h> +include "gtr.h" +include "grc.h" + +# GRC_STATUS -- Called by ":.show" to print the values of the cursor mode +# parameters. + +procedure grc_status (fd, rc) + +int fd # output file +pointer rc # rcursor descriptor + +int ip, ch +string keys KEYSTROKES +include "gtr.com" + +begin + call fprintf (fd, "\tcase\t= %b\n") + call pargi (RC_CASE(rc)) + call fprintf (fd, "\tmarkcur\t= %b\n") + call pargi (RC_MARKCUR(rc)) + call fprintf (fd, "\taxes\t= %b\n") + call pargi (RC_AXES(rc)) + + if (wstranset == YES) { + call fprintf (fd, "\tview\t= %5.3f %5.3f %5.3f %5.3f\n") + call pargr (vx1) + call pargr (vx2) + call pargr (vy1) + call pargr (vy2) + } else + call fprintf (fd, "\tview\t= full screen\n") + + call fprintf (fd, "\tkeys\t= %s\n") + call pargstr (keys) + call fprintf (fd, "\t\t->") + + for (ip=1; keys[ip] != EOS; ip=ip+1) { + ch = RC_KEYS(rc,keys[ip]) + if (ch != 0) + call putci (fd, ch) + else + call putci (fd, ' ') + } + + call fprintf (fd, "\n") +end diff --git a/sys/gio/cursor/grctext.x b/sys/gio/cursor/grctext.x new file mode 100644 index 00000000..5bee9b34 --- /dev/null +++ b/sys/gio/cursor/grctext.x @@ -0,0 +1,57 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <gset.h> +include <gki.h> +include <gio.h> +include "gtr.h" +include "grc.h" + +# GRC_TEXT -- Draw a text string. The instruction is encoded and appended to +# the frame buffer and GIOTR is called to draw the new instructions. + +procedure grc_text (stream, x, y, text) + +int stream # graphics stream +real x, y # NDC coordinates of ll corner of first char +char text[ARB] # text string + +pointer tr, op, last_op +int fd, save1, save2, nwords +int stropen(), strlen() +pointer gtr_init(), gtr_writep() +errchk gtr_init, stropen, gki_redir + +begin + tr = gtr_init (stream) + + # Allocate space in the frame buffer for the text set attribute + # and text drawing instructions. Set the last op for undo to undo + # the line. This is also set by writep, hence we must wait to set + # TR_LASTOP until after the call to writep. + + last_op = TR_OP(tr) + nwords = GKI_TXSET_LEN + GKI_TEXT_LEN + strlen(text) + op = gtr_writep (stream, nwords) + TR_LASTOP(tr) = last_op + + # Open the frame buffer as a file and redirect the graphics stream + # output into the buffer. + + fd = stropen (Mems[op], nwords, NEW_FILE) + call gki_redir (stream, fd, save1, save2) + + # Output the set text attribute instruction and the text drawing + # instruction. + + call gki_txset (stream, TR_TXAP(tr)) + call gki_text (stream, nint(x*GKI_MAXNDC), nint(y*GKI_MAXNDC), text) + + # Restore the normal output for the stream. + call gki_redir (stream, 0, save1, save2) + call close (fd) + + # Call giotr to send the new instructions off to the kernel, optionally + # applying the workstation transformation in the process. + + call giotr (stream) +end diff --git a/sys/gio/cursor/grcwarn.x b/sys/gio/cursor/grcwarn.x new file mode 100644 index 00000000..ba9fcb0e --- /dev/null +++ b/sys/gio/cursor/grcwarn.x @@ -0,0 +1,27 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +# GRC_WARN -- Called in an error handler to intercept an error message string +# and write it to the workstation in the status line. + +procedure grc_warn (fd) + +int fd # output stream + +int errcode +pointer sp, msg, ip +int errget() + +begin + call smark (sp) + call salloc (msg, SZ_LINE, TY_CHAR) + + errcode = errget (Memc[msg], SZ_LINE) + for (ip=msg; Memc[ip] != EOS && Memc[ip] != '\n'; ip=ip+1) + ; + Memc[ip] = EOS + + call stg_putline (fd, " - ") + call stg_putline (fd, Memc[msg]) + + call sfree (sp) +end diff --git a/sys/gio/cursor/grcwcs.x b/sys/gio/cursor/grcwcs.x new file mode 100644 index 00000000..7c73657a --- /dev/null +++ b/sys/gio/cursor/grcwcs.x @@ -0,0 +1,282 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <mach.h> +include <gio.h> +include <gki.h> +include "gtr.h" +include "grc.h" + +# GRC_SCRTOWCS -- Transform screen coordinates (raw cursor coordinates) to +# world coordinates. This is not terribly efficient, but it does not matter +# for cursor mode applications which do not involve many coordinate +# transformations. + +procedure grc_scrtowcs (stream, sx, sy, raster, rx, ry, wx, wy, wcs) + +int stream #I graphics stream +real sx, sy #I screen coordinates +int raster #I raster number +real rx, ry #I raster coordinates +real wx, wy #O world coordinates +int wcs #O world coordinate system + +pointer w, tr +real mx, my +real ct[LEN_CT] +int grc_selectwcs() +pointer gtr_init() +errchk gtr_init + +begin + tr = gtr_init (stream) + + # Convert screen (raster 0) to NDC coordinates, undoing the effects + # of the workstation transformation. This is not done for raster + # coordinates since these are already raster-normalized coordinates + # as returned by the server. + + if (raster == 0) + call grc_scrtondc (rx, ry, mx, my) + else { + mx = rx + my = ry + } + + # Select a WCS. The TR_WCS variable is set only if the user + # explicitly fixes the WCS to override automatic selection. The + # best WCS for the raster is used if there is one, otherwise the + # best screen WCS is used. + + if (TR_WCS(tr) == NULL) { + wcs = grc_selectwcs (tr, raster, mx, my) + if (wcs == 0) { + call grc_scrtondc (sx, sy, mx, my) + wcs = grc_selectwcs (tr, 0, mx, my) + } + } else + wcs = TR_WCS(tr) + + # Set up the coordinate transformation. + w = TR_WCSPTR(tr,wcs) + call grc_settran (w, ct) + + # Transform NDC coordinates to WCS coordinates. + call grc_ndctowcs (ct, mx, my, wx, wy) +end + + +# GRC_SETTRAN -- Set up the coordinate transformation parameters for a given +# world coordinate system. + +procedure grc_settran (w, ct) + +pointer w # window descriptor +real ct[LEN_CT] # transformation descriptor + +real worigin, scale +real m1, m2, w1, w2 +int transformation, ax +bool fp_equalr() +real elogr() + +begin + # Compute world -> NDC coordinate transformation. + + do ax = 1, 2 { + if (ax == 1) { + transformation = WCS_XTRAN(w) + w1 = WCS_WX1(w) + w2 = WCS_WX2(w) + m1 = WCS_SX1(w) + m2 = WCS_SX2(w) + } else { + transformation = WCS_YTRAN(w) + w1 = WCS_WY1(w) + w2 = WCS_WY2(w) + m1 = WCS_SY1(w) + m2 = WCS_SY2(w) + } + + if (transformation == LINEAR) { + worigin = w1 + if (fp_equalr (w1, w2)) + scale = 1.0 + else + scale = (m2 - m1) / (w2 - w1) + } else if (transformation == LOG && w1 > 0 && w2 > 0) { + worigin = log10 (w1) + if (fp_equalr (log10(w2), worigin)) + scale = 1.0 + else + scale = (m2 - m1) / (log10(w2) - worigin) + } else { + worigin = elogr (w1) + if (fp_equalr (elogr(w2), worigin)) + scale = 1.0 + else + scale = (m2 - m1) / (elogr(w2) - worigin) + } + + ct[ax,CT_TRAN] = transformation + ct[ax,CT_SCALE] = scale + ct[ax,CT_WORIGIN] = worigin + ct[ax,CT_MORIGIN] = m1 + } +end + + +# GRC_WCSTONDC -- Transform world coordinates to NDC coordinates using the +# computed transformation parameters. + +procedure grc_wcstondc (ct, wx, wy, mx, my) + +real ct[LEN_CT] # coordinate transformation descriptor +real wx, wy # world coordinates of point +real mx, my # ndc coordinates of point + +real v +int transformation, ax +real elogr() + +begin + do ax = 1, 2 { + transformation = nint (ct[ax,CT_TRAN]) + if (ax == 1) + v = wx + else + v = wy + + if (transformation == LINEAR) + ; + else if (transformation == LOG) + v = log10 (v) + else + v = elogr (v) + + v = ((v - ct[ax,CT_WORIGIN]) * ct[ax,CT_SCALE]) + ct[ax,CT_MORIGIN] + if (ax == 1) + mx = v + else + my = v + } +end + + +# GRC_NDCTOWCS -- Transform NDC coordinates to world coordinates using the +# computed transformation parameters. + +procedure grc_ndctowcs (ct, mx, my, wx, wy) + +real ct[LEN_CT] # coordinate transformation descriptor +real mx, my # ndc coordinates of point +real wx, wy # world coordinates of point + +real v +int transformation, ax +real aelogr() + +begin + do ax = 1, 2 { + transformation = nint (ct[ax,CT_TRAN]) + if (ax == 1) + v = mx + else + v = my + + v = ((v - ct[ax,CT_MORIGIN]) / ct[ax,CT_SCALE]) + ct[ax,CT_WORIGIN] + if (transformation == LINEAR) + ; + else if (transformation == LOG) + v = 10.0 ** v + else + v = aelogr (v) + + if (ax == 1) + wx = v + else + wy = v + } +end + + +# GRC_SELECTWCS -- Select the WCS nearest to the given position in NDC +# coordinates. If the point falls within a single WCS then that WCS is +# selected. If the point falls within multiple WCS then the closest WCS +# is selected. If multiple (non unitary) WCS are defined at the same +# distance, e.g., when the WCS share the same viewport, then the highest +# numbered WCS is selected. + +int procedure grc_selectwcs (tr, raster, mx, my) + +pointer tr #I GTR descriptor +int raster #I raster number +real mx, my #I NDC coordinates of point + +pointer w +int wcs, closest_wcs, flags +real tol, sx1, sx2, sy1, sy2 +real distance, old_distance, xcen, ycen +int nin, in[MAX_WCS] + +begin + nin = 0 + closest_wcs = 0 + old_distance = 1.0 + tol = EPSILON * 10.0 + + # Inspect each WCS. All WCS are passed even though only one or two + # WCS will be set to nonunitary values for a given plot. Omitting + # the unitary WCS, determine the closest WCS and make a list of the + # WCS containing the given point. + + do wcs = 1, MAX_WCS { + w = TR_WCSPTR(tr,wcs) + + # Cache WCS params in local storage. + sx1 = WCS_SX1(w) + sx2 = WCS_SX2(w) + sy1 = WCS_SY1(w) + sy2 = WCS_SY2(w) + flags = WCS_FLAGS(w) + xcen = (sx1 + sx2) / 2.0 + ycen = (sy1 + sy2) / 2.0 + + # Skip to next WCS if the raster number doesn't match. + if (WF_RASTER(flags) != raster) + next + + # Skip to next WCS if this one is not defined. + if (and (flags, WF_NEWFORMAT) == 0) { + # Preserve old semantics if passed old format WCS. + if (sx1 == 0 && sx2 == 0 || sy1 == 0 && sy2 == 0) + next + if (abs ((sx2-sx1) - 1.0) < tol && abs ((sy2-sy1) - 1.0) < tol) + next + } else if (and (flags, WF_DEFINED) == 0) + next + + # Determine closest WCS to point (mx,my). + distance = ((mx - xcen) ** 2) + ((my - ycen) ** 2) + if (distance <= old_distance) { + closest_wcs = wcs + old_distance = distance + } + + # Check if point is inside this WCS. + if (mx >= sx1 && mx <= sx2 && my >= sy1 && my <= sy2) { + nin = nin + 1 + in[nin] = wcs + } + } + + # If point is inside exactly one non-unitary WCS then select that WCS. + if (nin == 1) + return (in[1]) + + # If point is inside more than one WCS, or if point is not inside any + # WCS, select the closest WCS. If multiple WCS are at the same + # distance we have already selected the higher numbered WCS due to + # the way the distance test is conducted, above. + + return (closest_wcs) +end diff --git a/sys/gio/cursor/grcwrite.x b/sys/gio/cursor/grcwrite.x new file mode 100644 index 00000000..c0a602a9 --- /dev/null +++ b/sys/gio/cursor/grcwrite.x @@ -0,0 +1,66 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <fset.h> +include <gio.h> +include "gtr.h" +include "grc.h" + +# GRC_WRITE -- Write the contents of the frame buffer to a file, with or +# without applying the workstation transformation, optionally clobbering +# any existing file of the same name. + +procedure grc_write (tr, stream, fname, clobber, fullframe) + +pointer tr # graphics stream descriptor +int stream # graphics stream +char fname[ARB] # file name +bool clobber # clobber existing file +bool fullframe # write full frame (no workstation transform) + +pointer sp, lbuf +long size1, size2 +int save1, save2, fd, nchars +long fstatl() +int open() +errchk write, gtr_redraw + +begin + call smark (sp) + call salloc (lbuf, SZ_LINE, TY_CHAR) + + # Delete existing file if clobber requested. + if (clobber) + iferr (call delete (fname)) + ; + + # Open metacode spool file for appending. + iferr (fd = open (fname, APPEND, BINARY_FILE)) { + call grc_message (stream, " - cannot open file for appending") + call sfree (sp) + return + } + + # Write either the full frame or the displayed frame into spool file. + + size1 = fstatl (fd, F_FILESIZE) + if (fullframe) { + nchars = (TR_OP(tr) - TR_FRAMEBUF(tr)) * SZ_SHORT + call write (fd, Mems[TR_FRAMEBUF(tr)], nchars) + } else { + call gki_redir (stream, fd, save1, save2) + call gtr_redraw (stream) + call gki_redir (stream, 0, save1, save2) + } + + size2 = fstatl (fd, F_FILESIZE) + call sprintf (Memc[lbuf], SZ_LINE, " - %d chars %s") + call pargi (size2 - size1) + if (size1 > 0) + call pargstr ("appended") + else + call pargstr ("") + call grc_message (stream, Memc[lbuf]) + + call close (fd) + call sfree (sp) +end diff --git a/sys/gio/cursor/gtr.com b/sys/gio/cursor/gtr.com new file mode 100644 index 00000000..ae5c3ac6 --- /dev/null +++ b/sys/gio/cursor/gtr.com @@ -0,0 +1,25 @@ +# GTR.COM -- Polyline clipping common for the workstation transformation. +# The length of this common in integer units from startcom to endcom inclusive +# is a defined parameter in giotr.h. Values within the save area are saved +# in the TR descriptor for a device and loaded into the common (which serves +# as a cache) when GIOTR or RCURSOR is called for a device. LENGTH=28 + +pointer trdes[MAX_PSEUDOFILES] # pointers to giotr descriptors +int tr_stream # graphics stream currently in the cache +int startcom # dummy entry marking start of common +int pl_op # index of next cell in polyline array +bool last_point_inbounds # last point was inbounds +int pl_type # type of instruction (polyline, polymarker,...) +int wstranset # workstation transformation has been set +real xscale, yscale # scale factor, world to GKI, for transform +real xorigin, yorigin # origins in GKI coords, for transform +long cx, cy # current pen position, GKI coords +long mx1, mx2, my1, my2 # clipping viewport, GKI coords +real vx1, vx2, vy1, vy2 # NDC viewport, may extend beyond boundary +long xs[4], ys[4] # last point plotted (for clipping code) +int endcom # dummy entry marking end of saved area +short pl[LEN_PLBUF+5] # output polyline buffer (plus GKI header) + +common /gtrcom/ trdes, tr_stream, startcom, pl_op, last_point_inbounds, + pl_type, wstranset, xscale, yscale, xorigin, yorigin, cx, cy, + mx1, mx2, my1, my2, vx1, vx2, vy1, vy2, xs, ys, endcom, pl diff --git a/sys/gio/cursor/gtr.h b/sys/gio/cursor/gtr.h new file mode 100644 index 00000000..3fbf93f5 --- /dev/null +++ b/sys/gio/cursor/gtr.h @@ -0,0 +1,51 @@ +# GIOTR.H -- Global definitions for the GIOTR graphics i/o workstation +# transformation and i/o program unit. Note: requires <gio.h>. + +define DEF_MAXLENFRAMEBUF 128000 +define DEF_LENFRAMEBUF 8192 +define INC_LENFRAMEBUF 4096 +define DEF_LENSCRATCHBUF 256 +define INC_LENSCRATCHBUF 256 +define MAX_PSEUDOFILES 10 +define SZ_TRDEVNAME 229 +define SZ_KERNFNAME 259 +define LEN_GTRCOM 28 # see "gtr.com" +define KSHIFT 10000 # encode pr ("etc$prpsio.x") such that + # + # ((pr*KSHIFT)+stream) > LAST_FD + # + # see also <gio.h> + +define LEN_TRSTRUCT (564+204) + +define TR_PID Memi[$1] # process id of kernel +define TR_IN Memi[$1+1] # input from process +define TR_OUT Memi[$1+2] # output to process +define TR_TTY Memi[$1+3] # graphcap descriptor +define TR_SPOOLDATA Memi[$1+4] # spool metacode instructions +define TR_FRAMEBUF Memi[$1+5] # pointer to frame buffer +define TR_LENFRAMEBUF Memi[$1+6] # length of the frame buffer +define TR_MAXLENFRAMEBUF Memi[$1+7] # max length of the frame buffer +define TR_IP Memi[$1+8] # input pointer into frame buf +define TR_OP Memi[$1+9] # output pointer into frame buf +define TR_LASTOP Memi[$1+10] # last OP (for undo) +define TR_SCRATCHBUF Memi[$1+11] # for annotating plots +define TR_LENSCRATCHBUF Memi[$1+12] # length of the scratch buffer +define TR_OPSB Memi[$1+13] # output pointer, scratch buf +define TR_NOPEN Memi[$1+14] # number of opens +define TR_REDIR Memi[$1+15] # redirection information +define TR_WCS Memi[$1+16] # WCS selected, 0 if none +define TR_PAGE Memi[$1+17] # clear screen for text +define TR_WAITPAGE Memi[$1+18] # grc_waitpage flag +define TR_WSOPEN Memi[$1+19] # workstation open count +define TR_SKIPOPEN Memi[$1+20] # skip wsopen in metacode +define TR_WSACTIVE Memi[$1+21] # workstation activated? +define TR_WSACTSAVE Memi[$1+22] # save old wsactive state +define TR_INTERACTIVE Memi[$1+23] # the user graphics terminal? + # (open) +define TR_TXAP ($1+30) # text drawing attributes +define TR_PLAP ($1+40) # text drawing attributes +define TR_DEVNAME Memc[P2C($1+44)] # device name +define TR_KERNFNAME Memc[P2C($1+274)] # name of kernel file (or "cl") +define TR_GTRCOM Memi[$1+534] # storage for the gtr common +define TR_WCSPTR (($1)+564+($2)*LEN_WCS) # WCS storage (0=not used) diff --git a/sys/gio/cursor/gtrbackup.x b/sys/gio/cursor/gtrbackup.x new file mode 100644 index 00000000..9ab13c0b --- /dev/null +++ b/sys/gio/cursor/gtrbackup.x @@ -0,0 +1,74 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <gset.h> +include <gio.h> +include <gki.h> +include "gtr.h" + +# GTR_BACKUP -- Backup one drawing instruction in the frame buffer. Erase +# the graphics if possible. The effects of this function may be undone by +# the UNDO operator. + +procedure gtr_backup (stream) + +int stream # graphics stream + +int opcode +pointer tr, op, bp, sp, ap +pointer gtr_init() +errchk gtr_init +include "gtr.com" + +begin + call smark (sp) + call salloc (ap, LEN_PL, TY_STRUCT) + + tr = gtr_init (stream) + + # Scan backward to the beginning of the last drawing instruction in the + # frame buffer. + + op = TR_OP(tr) + bp = TR_FRAMEBUF(tr) + if (op <= bp) { + call sfree (sp) + return + } + + repeat { + op = op - 1 + while (Mems[op] != BOI) + if (op <= bp) { + TR_OP(tr) = bp + TR_IP(tr) = bp + call sfree (sp) + return + } else + op = op - 1 + opcode = Mems[op+GKI_HDR_OPCODE-1] + } until (opcode >= GKI_POLYLINE && opcode <= GKI_PUTCELLARRAY) + + # Redraw the last instruction to erase it (device permitting). + if (opcode == GKI_POLYLINE) { + PL_LTYPE(ap) = GL_CLEAR + PL_WIDTH(ap) = 1.0 + PL_COLOR(ap) = 1 + call gki_plset (stream, ap) + + if (wstranset == YES) + call gtr_wstran (Mems[op]) + else + call gki_write (stream, Mems[op]) + + PL_LTYPE(ap) = GL_SOLID + call gki_plset (stream, ap) + call gki_fflush (stream) + } + + # Return the space in the buffer. + TR_LASTOP(tr) = TR_OP(tr) + TR_OP(tr) = op + TR_IP(tr) = min (op, TR_IP(tr)) + + call sfree (sp) +end diff --git a/sys/gio/cursor/gtrconn.x b/sys/gio/cursor/gtrconn.x new file mode 100644 index 00000000..c2e6fb47 --- /dev/null +++ b/sys/gio/cursor/gtrconn.x @@ -0,0 +1,78 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <syserr.h> + +# GTR_CONNECT -- Connect a subprocess containing a graphics kernel task to a +# graphics stream. The graphics kernel task is a conventional IRAF task +# linked into the kernel process. After spawning the subprocess, we command +# the process to run the named kernel task, then service the parameter +# requests from the task as it begins running. Graphics i/o will be via one +# of the graphics streams, leaving STDIN, STDOUT, and STDERR free to access +# the corresponding streams in the parent (the CL). A kernel may be opened +# either to drive a particular device (if devname is specified) or to drive +# a device selected at runtime. If the kernel is opened to drive a particular +# device the device name in the OPENWS instruction will be ignored. We require +# that the graphics kernel begin processing metacode immediately after +# receiving "yes" for the value of the parameter "generic", signifying that +# the caller wishes a generic kernel, i.e., cannot return the values of any +# kernel dependent parameters. + +int procedure gtr_connect (kernfname, taskname, devname, stream, in, out) + +char kernfname[ARB] # name of executable kernel file +char taskname[ARB] # name of kernel task +char devname[ARB] # device name or null string +int stream # graphics stream to connect process to +int in, out # input and output streams to process + +pointer sp, lbuf +int pid +bool streq() +int propen(), getline() +errchk propen, flush, getline, syserr + +begin + call smark (sp) + call salloc (lbuf, SZ_LINE, TY_CHAR) + + pid = propen (kernfname, in, out) + call fprintf (out, "%s\n") + call pargstr (taskname) + call flush (out) + + # Pass values of the kernel parameters. For a kernel run as + # part of the graphics system there are only three parameters, + # the input file name (STDGRAPH, etc. for a connected kernel) + # the device name if the kernel is to ignore device names in + # OPENWS instructions, and "generic=yes", signifying that the + # kernel dependent parameters are not to be requested. + + while (getline (in, Memc[lbuf]) != EOF) { + if (streq (Memc[lbuf], "=input\n")) { + call fprintf (out, "%s\n") + switch (stream) { + case STDGRAPH: + call pargstr ("STDGRAPH") + case STDIMAGE: + call pargstr ("STDIMAGE") + case STDPLOT: + call pargstr ("STDPLOT") + } + call flush (out) + } else if (streq (Memc[lbuf], "=device\n")) { + call fprintf (out, "%s\n") + call pargstr (devname) + call flush (out) + } else if (streq (Memc[lbuf], "=generic\n")) { + call putline (out, "yes\n") + call flush (out) + break + } else { + call putline (STDERR, Memc[lbuf]) + call syserr (SYS_GKERNPARAM) + } + } + + call sfree (sp) + return (pid) +end diff --git a/sys/gio/cursor/gtrctrl.x b/sys/gio/cursor/gtrctrl.x new file mode 100644 index 00000000..8de08ccb --- /dev/null +++ b/sys/gio/cursor/gtrctrl.x @@ -0,0 +1,122 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <prstat.h> +include <config.h> +include <fset.h> +include <gset.h> +include <gio.h> +include <gki.h> +include "gtr.h" + +# GTR_CONTROL -- Execute a graphics control instruction, e.g., connect a +# graphics kernel to a graphics stream and set or get the WCS for a frame. +# The control instructions are GKI encoded instructions transmitted to the +# pseudofile GIOCONTROL. The PR_PSIO procedure (which processes the pseudofile +# directives from a subprocess) calls us whenever data is sent to this +# special pseudofile. + +procedure gtr_control (stream, gki, source_pid) + +int stream # graphics stream +short gki[ARB] # encoded graphics control instruction +int source_pid # pid of requesting process + +bool redirected +pointer tr, sp, devname, gki_out +int flags, mode, nwords, fd, p_fd +int prstati(), pr_getredir() +pointer gtr_init(), coerce() +errchk gtr_init, gtr_openws, write, flush, gki_write +include "gtr.com" + +begin + call smark (sp) + call salloc (devname, SZ_TRDEVNAME, TY_CHAR) + + nwords = gki[GKI_HDR_LENGTH] + call salloc (gki_out, nwords, TY_SHORT) + call amovs (gki, Mems[gki_out], nwords) + + tr = gtr_init (stream) + p_fd = abs (pr_getredir (source_pid, stream)) + redirected = (p_fd >= FIRST_FD && p_fd <= LAST_FD) + + switch (gki[GKI_HDR_OPCODE]) { + case GKI_OPENWS: + mode = gki[GKI_OPENWS_M] + nwords = gki[GKI_OPENWS_N] + + # Unpack the device name, passed as a short integer array. + call achtsc (gki[GKI_OPENWS_D], Memc[devname], nwords) + Memc[devname+nwords] = EOS + + # Connect the kernel. + call fseti (stream, F_CANCEL, OK) + call gtr_openws (Memc[devname], mode, stream, source_pid) + + # Count the logical openws. + TR_WSOPEN(tr) = TR_WSOPEN(tr) + 1 + TR_WSACTIVE(tr) = YES + TR_WSACTSAVE(tr) = NO + + # Due to a call to F_CANCEL in prpsio the openws instruction + # spooled by gki_write below is being lost for subkernels, + # so don't set the skipopen flag. This causes giotr to pass + # the openws on to the subkernel. For inline kernels setting + # skipopen prevents the openws from being executed twice. + + if (TR_INTERACTIVE(tr) == YES) + TR_SKIPOPEN(tr) = YES + + # If opening NEW_FILE, discard any previous WCS and clear the + # frame buffer. + + if (mode == NEW_FILE) { + call aclri (Memi[TR_WCSPTR(tr,1)], LEN_WCS * MAX_WCS) + call gtr_frame (tr, TR_FRAMEBUF(tr), stream) + } + + case GKI_CLOSEWS: + # Count the logical closews. + TR_WSOPEN(tr) = TR_WSOPEN(tr) - 1 + TR_WSACTIVE(tr) = NO + + case GKI_DEACTIVATEWS: + TR_WSACTIVE(tr) = NO + if (TR_INTERACTIVE(tr) == YES && TR_PAGE(tr) == NO) { + flags = gki[GKI_REACTIVATEWS_F] + if (and (flags, AW_CLEAR) != 0) + Mems[gki_out+GKI_REACTIVATEWS_F-1] = flags - AW_CLEAR + } + + case GKI_REACTIVATEWS: + TR_WSACTIVE(tr) = YES + if (TR_INTERACTIVE(tr) == YES) { + flags = gki[GKI_REACTIVATEWS_F] + if (and (flags, AW_PAUSE) != 0) + call gtr_waitpage (STDERR, stream) + } + + case GKI_SETWCS: + nwords = gki[GKI_SETWCS_N] + call amovs (gki[GKI_SETWCS_WCS], + Mems[coerce (TR_WCSPTR(tr,1), TY_STRUCT, TY_SHORT)], + min (nwords, LEN_WCS * MAX_WCS * SZ_STRUCT / SZ_SHORT)) + + case GKI_GETWCS: + nwords = gki[GKI_GETWCS_N] + fd = prstati (source_pid, PR_OUTFD) + + call write (fd, Memi[TR_WCSPTR(tr,1)], nwords * SZ_SHORT) + call flush (fd) + } + + # Pass the (possibly modified) instruction on to the kernel. + # We must NOT call gki_flush or gki_fflush here, as this would + # result in a reentrant call to prpsio when writing to a subkernel. + + if (!redirected) + call gki_write (stream, Mems[gki_out]) + + call sfree (sp) +end diff --git a/sys/gio/cursor/gtrdelete.x b/sys/gio/cursor/gtrdelete.x new file mode 100644 index 00000000..97f418a0 --- /dev/null +++ b/sys/gio/cursor/gtrdelete.x @@ -0,0 +1,45 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <gio.h> +include <gki.h> +include "gtr.h" + +# GTR_DELETE -- Delete an instruction from the frame buffer. This prevents +# the instruction from being executed if the frame is redrawn. + +procedure gtr_delete (tr, gki) + +pointer tr #I giotr descriptor +pointer gki #I instruction to be deleted + +pointer inext +int nwords, shift, ilen + +begin + ilen = Mems[gki+GKI_HDR_LENGTH-1] + inext = gki + ilen + + if (inext >= TR_OP(tr)) { + # Instruction is the last one in the buffer. + TR_OP(tr) = gki + TR_LASTOP(tr) = TR_OP(tr) + if (TR_IP(tr) >= gki) + TR_IP(tr) = gki + + } else { + # If the instruction is small and would be expensive to delete + # just change the opcode to disable it, otherwise shift the + # buffer contents back to overwrite the deleted instruction. + + nwords = TR_OP(tr) - inext + if (ilen < 32 && nwords > 2048) + Mems[gki+GKI_HDR_OPCODE-1] = GKI_UNKNOWN + else { + call amovs (Mems[inext], Mems[gki], nwords) + shift = inext - gki + TR_IP(tr) = TR_IP(tr) - shift + TR_OP(tr) = TR_OP(tr) - shift + TR_LASTOP(tr) = TR_OP(tr) + } + } +end diff --git a/sys/gio/cursor/gtrdiscon.x b/sys/gio/cursor/gtrdiscon.x new file mode 100644 index 00000000..5eba23f4 --- /dev/null +++ b/sys/gio/cursor/gtrdiscon.x @@ -0,0 +1,66 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <gio.h> + +# GTR_DISCONNECT -- Disconnect from a kernel subprocess. To achieve an orderly +# shutdown we process any outstanding XMIT or XFER requests, then transmit an +# end of file (zero length record) to the kernel task when it reads from the +# graphics stream. The kernel should then shutdown and eventually we will +# receive "bye" from the process. We then call PRCLOSE to shutdown the +# process for good. Note: we do not expect anything but an XFER (read) request +# on the graphics stream, but it seems prudent to do something reasonable if +# some other request is received. + +procedure gtr_disconnect (pid, in, out, stream) + +int pid # process id of subprocess +int in, out # command i/o streams of the subprocess +int stream # graphics stream used by kernel + +pointer sp, sp2, lbuf, buf +int pseudofile, nchars, junk +bool streq() +int getline(), read(), strncmp(), psio_isxmit(), prclose(), pr_findproc() +errchk getline, prclose, read, write + +begin + call smark (sp) + call salloc (lbuf, SZ_LINE, TY_CHAR) + + while (getline (in, Memc[lbuf]) != EOF) { + if (streq (Memc[lbuf], "bye\n") || + strncmp (Memc[lbuf], "ERROR", 5) == 0) { + + junk = prclose (pid) + break + + } else if (Memc[lbuf] == '!') { + # OS escape. + call proscmd (pr_findproc(pid), Memc[lbuf+1]) + + } else { + call smark (sp2) + + switch (psio_isxmit (Memc[lbuf], pseudofile, nchars)) { + case XMIT: + call salloc (buf, nchars, TY_CHAR) + nchars = read (in, Memc[buf], nchars) + if (nchars > 0) + if (pseudofile == STDOUT || pseudofile == STDERR) + call write (pseudofile, Memc[buf], nchars) + + case XFER: + call salloc (buf, nchars, TY_CHAR) + if (pseudofile == STDIN) + nchars = read (pseudofile, Memc[buf], nchars) + else + nchars = 0 # this is the EOF + call psio_xfer (out, Memc[buf], nchars) + } + + call sfree (sp2) + } + } + + call sfree (sp) +end diff --git a/sys/gio/cursor/gtrfetch.x b/sys/gio/cursor/gtrfetch.x new file mode 100644 index 00000000..44ccfe60 --- /dev/null +++ b/sys/gio/cursor/gtrfetch.x @@ -0,0 +1,48 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <gio.h> +include <gki.h> +include "gtr.h" + +# GTR_FETCH_NEXT_INSTRUCTION -- Return a pointer to the next GKI metacode +# instruction in the input buffer. Only complete instructions resident in +# a contiguous section of memory are returned. EOF is returned when the +# end of the current buffer is reached, or when the last instruction in the +# frame buffer is not yet complete. EOF does not signify the end of the +# metacode stream. + +int procedure gtr_fetch_next_instruction (tr, gki) + +pointer tr # pointer to giotr descriptor +pointer gki # pointer to next instruction (output) + +int nleft, length +pointer ip, itop + +begin + ip = TR_IP(tr) + itop = TR_OP(tr) + + # Search for the beginning of the next instruction. + while (Mems[ip] != BOI && ip < itop) + ip = ip + 1 + + nleft = itop - ip + if (nleft < 3) { + # The length field of the next instruction is not yet present. + TR_IP(tr) = ip + return (EOF) + } else { + length = Mems[ip+GKI_HDR_LENGTH-1] + if (length > nleft) { + # Entire instruction is not yet present in buffer. + TR_IP(tr) = ip + return (EOF) + } else { + # Entire instruction is present in buffer. + TR_IP(tr) = ip + length + gki = ip + return (length) + } + } +end diff --git a/sys/gio/cursor/gtrframe.x b/sys/gio/cursor/gtrframe.x new file mode 100644 index 00000000..baf68ffb --- /dev/null +++ b/sys/gio/cursor/gtrframe.x @@ -0,0 +1,41 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <gio.h> +include <gki.h> +include "gtr.h" + +# GTR_FRAME -- Clear the frame buffer, used to spool the metacode instructions +# required to draw a graphics frame. This is done by moving the metacode data +# at the end of the buffer (beginning with the word pointed to by gki) to the +# beginning of the buffer and adjusting the input and output pointers +# accordingly. The workstation transformation is also reset to the unitary +# transformation when the frame is cleared, i.e., zoom is cancelled. + +procedure gtr_frame (tr, gki, stream) + +pointer tr # giotr descriptor +pointer gki # pointer to first word to be preserved +int stream # graphics stream + +pointer bp +int nwords, shift + +begin + bp = TR_FRAMEBUF(tr) + + if (gki > bp) { + nwords = TR_OP(tr) - gki + call amovs (Mems[gki], Mems[bp], nwords) + shift = gki - bp + TR_IP(tr) = TR_IP(tr) - shift + TR_OP(tr) = TR_OP(tr) - shift + } else { + TR_IP(tr) = bp + TR_OP(tr) = bp + } + + call gtr_ptran (stream, 0., 1., 0., 1.) + TR_OPSB(tr) = TR_SCRATCHBUF(tr) + TR_LASTOP(tr) = TR_OP(tr) + TR_WCS(tr) = NULL +end diff --git a/sys/gio/cursor/gtrgflush.x b/sys/gio/cursor/gtrgflush.x new file mode 100644 index 00000000..5681e234 --- /dev/null +++ b/sys/gio/cursor/gtrgflush.x @@ -0,0 +1,45 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <error.h> +include <gio.h> +include "gtr.h" + +# GTR_GFLUSH -- Dispose of any buffered output on the stream STDPLOT. The last +# plot sent to stdplot cannot be disposed of at CLOSEWS time due to the need +# to permit APPEND mode in the next OPENWS call. We are called to dispose +# of all output to the plotter device. Logging out or doing a reset will have +# the same effect. + +procedure gtr_gflush (stream) + +int stream +pointer tr +bool streq() +include "gtr.com" + +begin + tr = trdes[stream] + if (tr == NULL) + return + + # Disconnect the kernel. + iferr { + if (streq (TR_KERNFNAME(tr), "cl")) + call stg_close() + else if (TR_DEVNAME(tr) != EOS && TR_KERNFNAME(tr) != EOS) { + call gtr_disconnect (TR_PID(tr), TR_IN(tr), TR_OUT(tr), + stream) + TR_PID(tr) = NULL + } + } then + call erract (EA_WARN) + + # Free all storage. + call mfree (TR_FRAMEBUF(tr), TY_SHORT) + call mfree (TR_SCRATCHBUF(tr), TY_SHORT) + call mfree (tr, TY_STRUCT) + + trdes[stream] = NULL + if (tr_stream == stream) + tr_stream = NULL +end diff --git a/sys/gio/cursor/gtrgtran.x b/sys/gio/cursor/gtrgtran.x new file mode 100644 index 00000000..c83c83aa --- /dev/null +++ b/sys/gio/cursor/gtrgtran.x @@ -0,0 +1,28 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <gio.h> +include <gki.h> +include "gtr.h" + +# GTR_GTRAN -- Get the workstation transformation. + +procedure gtr_gtran (fd, x1, x2, y1, y2) + +int fd # graphics stream to be set +real x1, x2 # range of workstation viewport in X +real y1, y2 # range of workstation viewport in Y +include "gtr.com" + +begin + if (wstranset == YES) { + x1 = vx1 + x2 = vx2 + y1 = vy1 + y2 = vy2 + } else { + x1 = 0 + x2 = 1.0 + y1 = 0 + y2 = 1.0 + } +end diff --git a/sys/gio/cursor/gtrgtty.x b/sys/gio/cursor/gtrgtty.x new file mode 100644 index 00000000..0e67a1fd --- /dev/null +++ b/sys/gio/cursor/gtrgtty.x @@ -0,0 +1,20 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <gio.h> +include <gki.h> +include "gtr.h" + +# GTR_GTTY -- Get the graphcap descriptor for a stream. + +pointer procedure gtr_gtty (stream) + +int stream # graphics stream of interest + +pointer tr +pointer gtr_init() +errchk gtr_init + +begin + tr = gtr_init (stream) + return (TR_TTY(tr)) +end diff --git a/sys/gio/cursor/gtrinit.x b/sys/gio/cursor/gtrinit.x new file mode 100644 index 00000000..734d8202 --- /dev/null +++ b/sys/gio/cursor/gtrinit.x @@ -0,0 +1,136 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <gset.h> +include <gio.h> +include <gki.h> +include "gtr.h" + +# GTR_INIT -- Initialize the GIOTR data structures for a graphics stream. These +# data structures are initialized only once, when the first i/o occurs on the +# stream. Thereafter our only function is to fault the workstation +# transformation parameters into the cache (the gtr common). + +pointer procedure gtr_init (stream) + +int stream # graphics stream + +int i, len_fb, len_sb +pointer tr, tx, ap, w +bool first_time +int btoi(), envgeti() +data first_time /true/ +errchk calloc, malloc +include "gtr.com" + +begin + if (first_time) { + call amovki (NULL, trdes, MAX_PSEUDOFILES) + tr_stream = NULL + first_time = false + } + + tr = trdes[stream] + + if (tr == NULL) { + # This is the first time the stream has been accessed. + + # Allocate descriptor. + call calloc (tr, LEN_TRSTRUCT, TY_STRUCT) + + # Don't need a frame buffer for STDPLOT, but make a dummy one + # anyhow so that the stream looks like the interactive ones. + + if (stream == STDPLOT) { + len_fb = 1 + len_sb = 1 + } else { + len_fb = DEF_LENFRAMEBUF + len_sb = DEF_LENSCRATCHBUF + } + + call malloc (TR_FRAMEBUF(tr), len_fb, TY_SHORT) + call malloc (TR_SCRATCHBUF(tr), len_sb, TY_SHORT) + + trdes[stream] = tr + TR_IP(tr) = TR_FRAMEBUF(tr) + TR_OP(tr) = TR_FRAMEBUF(tr) + TR_OPSB(tr) = TR_SCRATCHBUF(tr) + TR_LENFRAMEBUF(tr) = len_fb + TR_LENSCRATCHBUF(tr) = len_sb + TR_SPOOLDATA(tr) = btoi (stream != STDPLOT) + TR_WAITPAGE(tr) = NO + TR_PAGE(tr) = YES + + # Set text drawing attributes for annotating plots. + tx = TR_TXAP(tr) + TX_UP(tx) = 90 + TX_SIZE(tx) = 1.0 + TX_PATH(tx) = GT_RIGHT + TX_SPACING(tx) = 0 + TX_HJUSTIFY(tx) = GT_LEFT + TX_VJUSTIFY(tx) = GT_BOTTOM + TX_FONT(tx) = GT_ROMAN + TX_QUALITY(tx) = GT_NORMAL + TX_COLOR(tx) = 1 + + # Set default polyline attributes for axis drawing. + ap = TR_PLAP(tr) + PL_LTYPE(ap) = GL_SOLID + PL_WIDTH(ap) = 1.0 + PL_COLOR(ap) = 1 + + # The user can override the default maximum frame buffer length + # if they wish, permitting spooling of frames of any size. + + iferr (TR_MAXLENFRAMEBUF(tr) = envgeti ("cmbuflen")) + TR_MAXLENFRAMEBUF(tr) = DEF_MAXLENFRAMEBUF + + if (tr_stream != NULL) { + # Save the workstation transformation parameters for the + # stream currently in the cache, if any. + + call amovi (startcom, TR_GTRCOM(trdes[tr_stream]), LEN_GTRCOM) + call amovi (TR_GTRCOM(tr), startcom, LEN_GTRCOM) + } + + # Initialize the transformation parameters for the new stream. + tr_stream = stream + xscale = 1.0 + yscale = 1.0 + mx2 = GKI_MAXNDC + my2 = GKI_MAXNDC + vx2 = 1.0 + vy2 = 1.0 + + # Initialize the WCS in case someone tries to read the cursor + # before there are any graphics. + + do i = 1, MAX_WCS { + w = TR_WCSPTR(tr,i) + WCS_SX1(w) = 0.0 + WCS_SX2(w) = 1.0 + WCS_SY1(w) = 0.0 + WCS_SY2(w) = 1.0 + + WCS_WX1(w) = 0.0 + WCS_WX2(w) = 1.0 + WCS_WY1(w) = 0.0 + WCS_WY2(w) = 1.0 + } + + } else if (stream != tr_stream) { + # The stream has already been initialized. + + # If the cache is currently validated for some different stream + # move the data for that stream out into its descriptor. + + if (tr_stream != NULL) + call amovi (startcom, TR_GTRCOM(trdes[tr_stream]), LEN_GTRCOM) + + # Load the data for the new stream into the cache. + call amovi (TR_GTRCOM(tr), startcom, LEN_GTRCOM) + tr_stream = stream + } + + return (tr) +end diff --git a/sys/gio/cursor/gtropenws.x b/sys/gio/cursor/gtropenws.x new file mode 100644 index 00000000..27a3072a --- /dev/null +++ b/sys/gio/cursor/gtropenws.x @@ -0,0 +1,206 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <syserr.h> +include <config.h> +include <error.h> +include <prstat.h> +include <fset.h> +include <fio.h> +include <gio.h> +include <gki.h> +include "gtr.h" + +# GTR_OPENWS -- Called by gtr_control(pr_psio) to connect a kernel to a +# graphics stream and to initialize the datapath to the kernel. +# The workstation is not physically opened until the GKI open workstation +# directive has been sent to the kernel. There are two types of kernels, +# the builtin (STDGRAPH) kernel, and all external kernels. The external +# kernels reside in connected subprocesses communicating via the central +# process (the CL process) with the graphics task in another subprocess. + +procedure gtr_openws (devspec, mode, stream, source_pid) + +char devspec[ARB] #I device specification +int mode #I access mode +int stream #I graphics stream +int source_pid #I process which issued the openws directive + +int redir_code, dd[LEN_GKIDD], ip +pointer sp, op, tr, tty, kernfname, taskname, device + +bool streq() +pointer ttygdes() +int pr_getredir(), ttygets(), gtr_connect(), pr_findproc(), locpr() +extern gtr_reset(), prpsio() + +errchk syserr, syserrs, fseti, ttygdes, ttycdes, pr_redir, stg_close, stg_open +errchk gtr_connect, gtr_disconnect +include "gtr.com" + +begin + call smark (sp) + call salloc (kernfname, SZ_FNAME, TY_CHAR) + call salloc (taskname, SZ_FNAME, TY_CHAR) + call salloc (device, SZ_FNAME, TY_CHAR) + + tr = trdes[stream] + + # Extract the device name field from the device specification. + op = device + for (ip=1; devspec[ip] != EOS; ip=ip+1) + if (devspec[ip] == ',') + break + else { + Memc[op] = devspec[ip] + op = op + 1 + } + Memc[op] = EOS + + # We only connect up the i/o channels, and do not issue the OPENWS + # to the gio kernel, so reset the counter to zero to indicate that + # the workstation has not yet been (logically) opened. + + TR_WSOPEN(tr) = 0 + + # If the stream has been redirected into a file, do not connect a + # kernel. + + redir_code = pr_getredir (source_pid, stream) + if (redir_code >= FIRST_FD && redir_code <= LAST_FD) { + call sfree (sp) + return + } + + # The graphics stream is a spoolfile in this process (the CL process). + # Spoolfiles are files that are fully buffered in memory and never + # get written to disk. Data is written into the spoolfile and then + # read back out by a different part of the program. + + call fseti (stream, F_TYPE, SPOOL_FILE) + call fseti (stream, F_CANCEL, OK) + + # If the device is already connected to the stream (or we are + # appending to a connected device) all we need do is reset the + # redirection code for the graphics stream. This code is reset to + # the default value (the code for the stream itself) by the CL when + # a task is spawned. + + if (TR_DEVNAME(tr) != EOS && mode == APPEND || + streq (devspec, TR_DEVNAME(tr))) { + call pr_redir (source_pid, stream, TR_REDIR(tr)) + call sfree (sp) + return + } + + # Connect the named kernel, i.e., disconnect the old kernel if any + # and connect the new one. Set the redirection information for the + # named stream of the source process. + + iferr { + # Close device graphcap descriptor. + if (TR_TTY(tr) != NULL) + call ttycdes (TR_TTY(tr)) + + # Disconnect old kernel. + if (streq (TR_KERNFNAME(tr), "cl")) + call stg_close() + else if (TR_DEVNAME(tr) != EOS && TR_KERNFNAME(tr) != EOS) { + call gtr_disconnect (TR_PID(tr), TR_IN(tr), TR_OUT(tr), stream) + TR_PID(tr) = NULL + TR_IN(tr) = NULL + TR_OUT(tr) = NULL + } + } then { + TR_DEVNAME(tr) = EOS + call erract (EA_ERROR) + } else + TR_DEVNAME(tr) = EOS + + # Get graphcap entry for the new device. The special device name + # "none" indicates that there is no suitable stdgraph device. + + if (streq (devspec, "none")) { + switch (stream) { + case STDGRAPH: + call syserr (SYS_GGNONE) + case STDIMAGE: + call syserr (SYS_GINONE) + case STDPLOT: + call syserr (SYS_GPNONE) + default: + call syserr (SYS_GGNONE) + } + } else { + tty = ttygdes (Memc[device]) + TR_TTY(tr) = tty + } + + # Get the name of the executable file containing the kernel for the + # device. The special name "cl" signifies the builtin STDGRAPH kernel. + + if (ttygets (tty, "kf", Memc[kernfname], SZ_FNAME) <= 0) { + call ttycdes (tty) + call syserrs (SYS_GNOKF, Memc[device]) + } else if (ttygets (tty, "tn", Memc[taskname], SZ_FNAME) <= 0) + ; + + # Connect the new kernel. + call strcpy (Memc[kernfname], TR_KERNFNAME(tr), SZ_KERNFNAME) + + if (streq (Memc[kernfname], "cl")) { + # Open the stdgraph kernel. Connect the referenced GKI stream to + # the stdgraph kernel. Set a negative redirection code value to + # flag that GIOTR is to be called to filter graphics output from + # the process. + + call stg_open (devspec, dd, STDIN, STDOUT, 0, 0, 0) + call gki_inline_kernel (stream, dd) + if (source_pid != NULL) + call pr_redir (source_pid, stream, -stream) + TR_REDIR(tr) = -stream + TR_INTERACTIVE(tr) = YES + + } else { + # Spawn subprocess and start up kernel task. + TR_PID(tr) = gtr_connect (Memc[kernfname], Memc[taskname], + devspec, stream, TR_IN(tr), TR_OUT(tr)) + + # Encode the process slot number of the kernel process in the + # redirection code for the source process (the process which + # issued the openws). If the stream is STDGRAPH or STDIMAGE + # make the redirection code negative to flag that graphics + # output is to be processed through GIOTR (the workstation + # transformation). + + if (source_pid != NULL) { + redir_code = (pr_findproc(TR_PID(tr)) * KSHIFT) + stream + if (stream == STDGRAPH || stream == STDIMAGE) + redir_code = -redir_code + call pr_redir (source_pid, stream, redir_code) + TR_REDIR(tr) = redir_code + + # Mark the process busy. This flags it it as busy executing + # some subprotocol (in this case processing GKI metacode) and + # prevents commands such as chdir/set from being sent to the + # process and corrupting the IPC protocol. + + call prseti (TR_PID(tr), PR_STATUS, P_BUSY) + } + + call gki_subkernel (stream, TR_PID(tr), locpr(prpsio)) + TR_INTERACTIVE(tr) = NO + } + + # Do not change value of DEVNAME until the new kernel has been + # successfully connected, since this variable is used to test if + # the kernel is already connected. + + call strcpy (devspec, TR_DEVNAME(tr), SZ_TRDEVNAME) + + # Post the gtr_reset procedure to be executed upon process shutdown, + # to close down any connected graphics subkernels in an orderly way. + + call onexit (gtr_reset) + + call sfree (sp) +end diff --git a/sys/gio/cursor/gtrpage.x b/sys/gio/cursor/gtrpage.x new file mode 100644 index 00000000..2caa53cb --- /dev/null +++ b/sys/gio/cursor/gtrpage.x @@ -0,0 +1,30 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <gset.h> +include <gio.h> +include "gtr.h" + +# GTR_PAGE -- Prepare the workstation for output of one or more pages of text. +# Whether or not the terminal is paged is optional. On terminals where the +# text and graphics are overlaid, it is possible to run the text by beneath +# the plot without affecting the plot. + +procedure gtr_page (fd, stream) + +int fd # output file +int stream # graphics stream + +pointer tr +pointer gtr_init() +errchk gtr_init + +begin + tr = gtr_init (stream) + + if (TR_PAGE(tr) == YES) + call gki_deactivatews (stream, AW_CLEAR) + else + call gki_deactivatews (stream, 0) + + TR_WAITPAGE(tr) = YES +end diff --git a/sys/gio/cursor/gtrptran.x b/sys/gio/cursor/gtrptran.x new file mode 100644 index 00000000..eba3075e --- /dev/null +++ b/sys/gio/cursor/gtrptran.x @@ -0,0 +1,74 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <mach.h> +include <gio.h> +include <gki.h> +include "gtr.h" + +# GTR_PTRAN -- Set the workstation transformation. The workstation +# transformation is automatically zeroed whenever the screen is cleared +# or when a workstation is opened. + +procedure gtr_ptran (stream, x1, x2, y1, y2) + +int stream # graphics stream to be set +real x1, x2 # range of workstation viewport in X +real y1, y2 # range of workstation viewport in Y + +pointer tr +real tol, min_width, dx, dy +real cx1, cx2, cy1, cy2 +include "gtr.com" + +begin + tr = trdes[stream] + tol = 5.0 * EPSILON + + if (abs(x1) < tol && abs (x2 - 1.0) < tol && + abs(y1) < tol && abs (y2 - 1.0) < tol) { + + wstranset = NO + + } else { + # Save viewport. + vx1 = x1 + vx2 = x2 + vy1 = y1 + vy2 = y2 + + # Clip viewport at NDC boundary. + cx1 = max (0., min (1., x1)) + cx2 = max (0., min (1., x2)) + cy1 = max (0., min (1., y1)) + cy2 = max (0., min (1., y2)) + + # Make sure the viewport does not have a zero extent in either + # axis after clipping. + min_width = 1E-4 + if (cx2 - cx1 < min_width) + cx2 = cx1 + min_width + if (cy2 - cy1 < min_width) + cy2 = cy1 + min_width + + # Set clipping viewport in input GKI space. + mx1 = nint (cx1 * GKI_MAXNDC) + mx2 = nint (cx2 * GKI_MAXNDC) + my1 = nint (cy1 * GKI_MAXNDC) + my2 = nint (cy2 * GKI_MAXNDC) + + # Set transformation upon the clipped GKI coordinates. + dx = max (min_width, (x2 - x1)) + dy = max (min_width, (y2 - y1)) + xorigin = (cx1 - x1) / dx * GKI_MAXNDC + yorigin = (cy1 - y1) / dy * GKI_MAXNDC + xscale = 1. / dx + yscale = 1. / dy + + wstranset = YES + } + + # Clear the scratch buffer whenever the workstation viewport is + # changed. + + TR_OPSB(tr) = TR_SCRATCHBUF(tr) +end diff --git a/sys/gio/cursor/gtrrcur.x b/sys/gio/cursor/gtrrcur.x new file mode 100644 index 00000000..495117a3 --- /dev/null +++ b/sys/gio/cursor/gtrrcur.x @@ -0,0 +1,32 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <gki.h> + +# GTR_READCURSOR -- Read the graphics cursor position in NDC coordinates. +# By the time we are called the plot has already been drawn and the +# workstation closed, hence we must reopen the workstation to read the +# cursor (the graphics terminal will not be in graphics mode otherwise). + +int procedure gtr_readcursor (fd, key, sx, sy, raster, rx, ry) + +int fd #I graphics stream +int key #O keystroke value +real sx, sy #O NDC screen coords of cursor +int raster #O raster number +real rx, ry #O NDC raster coords of cursor + +int cn +int m_sx, m_sy +int m_rx, m_ry + +begin + call gki_getcursor (fd, 0, + cn, key, m_sx, m_sy, raster, m_rx, m_ry) + + sx = real(m_sx) / GKI_MAXNDC + sy = real(m_sy) / GKI_MAXNDC + rx = real(m_rx) / GKI_MAXNDC + ry = real(m_ry) / GKI_MAXNDC + + return (key) +end diff --git a/sys/gio/cursor/gtrredraw.x b/sys/gio/cursor/gtrredraw.x new file mode 100644 index 00000000..ca2191b3 --- /dev/null +++ b/sys/gio/cursor/gtrredraw.x @@ -0,0 +1,48 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <gio.h> +include "gtr.h" + +# GTR_REDRAW -- Redraw the screen from the metacode spooled in the frame +# buffer. + +procedure gtr_redraw (stream) + +int stream # graphics stream to be redrawn + +pointer tr, ip_save, op_save +pointer gtr_init() +errchk gtr_init + +begin + tr = gtr_init (stream) + + if (TR_SPOOLDATA(tr) == YES && TR_OP(tr) > TR_FRAMEBUF(tr)) { + # Rewind the input pointer into the frame buffer. + TR_IP(tr) = TR_FRAMEBUF(tr) + + # Redraw frame buffer. + call gki_clear (stream) + call giotr (stream) + + # Redraw scratch buffer (axes). Set i/o pointers to the scratch + # buffer and draw its contents. Turn off interrupts to prevent + # an interrupt from leaving the pointers pointing to the wrong + # buffer. + + if (TR_OPSB(tr) > TR_SCRATCHBUF(tr)) { + call intr_disable() + ip_save = TR_IP(tr); TR_IP(tr) = TR_SCRATCHBUF(tr) + op_save = TR_OP(tr); TR_OP(tr) = TR_OPSB(tr) + + call giotr (stream) + + TR_IP(tr) = ip_save + TR_OP(tr) = op_save + call intr_enable() + } + + # Flush graphics output. + call gki_flush (stream) + } +end diff --git a/sys/gio/cursor/gtrreset.x b/sys/gio/cursor/gtrreset.x new file mode 100644 index 00000000..36c55a9a --- /dev/null +++ b/sys/gio/cursor/gtrreset.x @@ -0,0 +1,53 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <error.h> +include <gio.h> +include "gtr.h" + +# GTR_RESET -- Reset the graphics system. Disconnect all connected subkernels +# and free all file descriptors and memory. + +procedure gtr_reset (status) + +int status # not used (req. for ONEXIT) + +pointer tr +int stream +bool streq() +include "gtr.com" + +begin + do stream = STDGRAPH, STDPLOT { + tr = trdes[stream] + if (tr == NULL) + next + + iferr { + # Close device graphcap descriptor. + if (TR_TTY(tr) != NULL) + call ttycdes (TR_TTY(tr)) + + # Disconnect old kernel. + if (streq (TR_KERNFNAME(tr), "cl")) + call stg_close() + else if (TR_DEVNAME(tr) != EOS && TR_KERNFNAME(tr) != EOS) { + call gtr_disconnect (TR_PID(tr), + TR_IN(tr), TR_OUT(tr), stream) + TR_PID(tr) = NULL + TR_IN(tr) = NULL + TR_OUT(tr) = NULL + } + } then { + TR_DEVNAME(tr) = EOS + call erract (EA_WARN) + } else + TR_DEVNAME(tr) = EOS + + # Free all storage. + call mfree (TR_FRAMEBUF(tr), TY_SHORT) + call mfree (TR_SCRATCHBUF(tr), TY_SHORT) + call mfree (tr, TY_STRUCT) + + trdes[stream] = NULL + } +end diff --git a/sys/gio/cursor/gtrset.x b/sys/gio/cursor/gtrset.x new file mode 100644 index 00000000..629ef097 --- /dev/null +++ b/sys/gio/cursor/gtrset.x @@ -0,0 +1,28 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <gio.h> +include <gki.h> +include "gtr.h" + +# GTRSET -- Set the workstation transformation. The workstation transformation +# is automatically zeroed whenever the screen is cleared or when a workstation +# is opened. + +procedure gtrset (fd, x1, x2, y1, y2) + +int fd # graphics stream to be set +real x1, x2 # range of workstation viewport in X +real y1, y2 # range of workstation viewport in Y +include "gtr.com" + +begin + mx1 = x1 * GKI_MAXNDC + mx2 = x2 * GKI_MAXNDC + my1 = y1 * GKI_MAXNDC + my2 = y2 * GKI_MAXNDC + + xscale = GKI_MAXNDC / (mx2 - mx1) + yscale = GKI_MAXNDC / (my2 - my1) + + wstranset = YES +end diff --git a/sys/gio/cursor/gtrstatus.x b/sys/gio/cursor/gtrstatus.x new file mode 100644 index 00000000..45b5731c --- /dev/null +++ b/sys/gio/cursor/gtrstatus.x @@ -0,0 +1,100 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <fset.h> +include <gio.h> +include "gtr.h" + +define LEN_NAME 10 + + +# GTR_STATUS -- Print information summarizing the utilization of resources +# by each of the three graphics streams. + +procedure gtr_status (fd) + +int fd # output file +int stream, ip +string names "STDGRAPH:,STDIMAGE:,STDPLOT: " +include "gtr.com" + +begin + for (ip=1; names[ip] != EOS; ip=ip+1) + if (names[ip] == ',') + names[ip] = EOS + + do stream = STDGRAPH, STDPLOT { + ip = (stream - STDGRAPH) * LEN_NAME + 1 + if (trdes[stream] == NULL) { + call fprintf (fd, "\t%s disconnected\n") + call pargstr (names[ip]) + } else + call gtr_memusage (fd, stream, names[ip]) + } + + call fprintf (fd, "\n") + call flush (fd) +end + + +# GTR_MEMUSAGE -- Print information summarizing the utilization of memory and +# other resources by a graphics stream. + +procedure gtr_memusage (fd, stream, name) + +int fd # output file +int stream # graphics stream to be described +char name[ARB] # name of graphics stream + +pointer tr, tx +int bufsize +int fstati() +pointer gtr_init() +errchk gtr_init + +begin + tr = gtr_init (stream) + + call fprintf (fd, "\t%s kernel=%s, device=%s, page %s\n") + call pargstr (name) + call pargstr (TR_KERNFNAME(tr)) + call pargstr (TR_DEVNAME(tr)) + if (TR_PAGE(tr) == YES) + call pargstr ("enabled") + else + call pargstr ("disabled") + + bufsize = fstati (stream, F_BUFSIZE) + call fprintf (fd, + "\t\tmemory=%d (%dfb+%dsb+%dfio), frame=%d+%d words\n") + call pargi (TR_LENFRAMEBUF(tr) + TR_LENSCRATCHBUF(tr) + bufsize) + call pargi (TR_LENFRAMEBUF(tr)) + call pargi (TR_LENSCRATCHBUF(tr)) + call pargi (bufsize) + call pargi (TR_OP(tr) - TR_FRAMEBUF(tr)) + call pargi (TR_OPSB(tr) - TR_SCRATCHBUF(tr)) + + call fprintf (fd, + "\t\tspool=%s, nopen=%d, pid=%d, in=%d, out=%d, redir=%d, wcs=%d\n") + if (TR_SPOOLDATA(tr) == YES) + call pargstr ("yes") + else + call pargstr ("no") + call pargi (TR_NOPEN(tr)) + call pargi (TR_PID(tr)) + call pargi (TR_IN(tr)) + call pargi (TR_OUT(tr)) + call pargi (TR_REDIR(tr)) + call pargi (TR_WCS(tr)) + + tx = TR_TXAP(tr) + call fprintf (fd, + "\t\ttext size=%g, up=%d, path=%s, hj=%s, vj=%s, color=%d\n") + call pargr (TX_SIZE(tx)) + call pargi (TX_UP(tx)) + call gkp_txparg (TX_PATH(tx)) + call gkp_txparg (TX_HJUSTIFY(tx)) + call gkp_txparg (TX_VJUSTIFY(tx)) + call pargi (TX_COLOR(tx)) + + call fprintf (fd, "\n") +end diff --git a/sys/gio/cursor/gtrtrunc.x b/sys/gio/cursor/gtrtrunc.x new file mode 100644 index 00000000..6abda3ba --- /dev/null +++ b/sys/gio/cursor/gtrtrunc.x @@ -0,0 +1,39 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <gio.h> +include <gki.h> +include "gtr.h" + +# GTR_TRUNCATE -- Truncate the frame buffer, which has grown larger than +# the limit set by the user (or the system default). This is done by moving +# the metacode data at the end of the buffer (beginning with the word pointed +# to by gki) to the maximum upper limit of the buffer and adjusting the input +# and output pointers accordingly. + +procedure gtr_truncate (tr, gki) + +pointer tr # giotr descriptor +pointer gki # pointer to first word to be preserved +pointer top +int nwords + +begin + # Find the first instruction preceding the soft upper limit on the + # size of the buffer. + + top = TR_FRAMEBUF(tr) + TR_MAXLENFRAMEBUF(tr) + while (Mems[top] != BOI && top > TR_FRAMEBUF(tr)) + top = top - 1 + + # Move the partial instruction likely to be at the end of the buffer + # to the new "top". Note that we can only truncate (discard) + # instructions which have already been executed, hence the partial + # instruction at the end of the buffer must be preserved. + + if (gki != top) { + nwords = TR_OP(tr) - gki + call amovs (Mems[gki], Mems[top], nwords) + TR_IP(tr) = top + TR_OP(tr) = top + nwords + } +end diff --git a/sys/gio/cursor/gtrundo.x b/sys/gio/cursor/gtrundo.x new file mode 100644 index 00000000..5b8d3e02 --- /dev/null +++ b/sys/gio/cursor/gtrundo.x @@ -0,0 +1,76 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <gset.h> +include <gio.h> +include <gki.h> +include "gtr.h" + +# GTR_UNDO -- Undo the last frame buffer edit. Successive pairs of undos leave +# the frame buffer unchanged. + +procedure gtr_undo (stream) + +int stream # graphics stream +int opcode +pointer tr, op, new_op, old_op, sp, ap + +pointer gtr_init() +errchk gtr_init +include "gtr.com" + +begin + call smark (sp) + call salloc (ap, LEN_PL, TY_STRUCT) + + tr = gtr_init (stream) + + old_op = TR_OP(tr) + new_op = TR_LASTOP(tr) + if (new_op == old_op || new_op <= TR_FRAMEBUF(tr)) { + call sfree (sp) + return + } + + # Edit the frame buffer. + TR_LASTOP(tr) = old_op + TR_OP(tr) = new_op + TR_IP(tr) = min (new_op, TR_IP(tr)) + + # Redraw the last drawing instruction to erase it (device permitting), + # if we are backing up one instruction. Note that it may be necessary + # to skip one or more control instructions. We assume that the undo + # only has to undo one drawing instruction. + + if (new_op < old_op) { + op = new_op + repeat { + opcode = Mems[op+GKI_HDR_OPCODE-1] + if (opcode == GKI_POLYLINE) + break + else + op = op + Mems[op+GKI_HDR_LENGTH-1] + } until (op >= old_op) + + if (opcode == GKI_POLYLINE && op < old_op) { + PL_LTYPE(ap) = GL_CLEAR + PL_WIDTH(ap) = 1.0 + PL_COLOR(ap) = 1 + call gki_plset (stream, ap) + + if (wstranset == YES) + call gtr_wstran (Mems[op]) + else + call gki_write (stream, Mems[op]) + + PL_LTYPE(ap) = GL_SOLID + call gki_plset (stream, ap) + } + + } else if (new_op > old_op) { + # Call giotr to redraw the recovered instructions. + call giotr (stream) + } + + call gki_flush (stream) + call sfree (sp) +end diff --git a/sys/gio/cursor/gtrwaitp.x b/sys/gio/cursor/gtrwaitp.x new file mode 100644 index 00000000..67f46dd8 --- /dev/null +++ b/sys/gio/cursor/gtrwaitp.x @@ -0,0 +1,94 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <ttyset.h> +include <error.h> +include <fset.h> +include <gio.h> +include "gtr.h" +include "grc.h" + +# GTR_WAITPAGE -- Print the "hit return to continue" message on the terminal +# screen and wait for the user to respond before returning to graphics mode. +# Redrawing of the graphics frame is optional. + +procedure gtr_waitpage (fd, stream) + +int fd # output file +int stream # graphics stream + +int key, i +pointer tty, tr +int getci(), ttystati() +pointer ttyodes(), gtr_init() +errchk gtr_init, ttyodes + +begin + tr = gtr_init (stream) + tty = ttyodes ("terminal") + + repeat { + # Print prompt in standout mode. + call ttyclearln (fd, tty) + call ttyso (fd, tty, YES) + call fprintf (fd, + "[space=cmhelp,return=quit+redraw,q=quit+noredraw]") + call ttyso (fd, tty, NO) + call flush (fd) + + # Wait for user to hit a key. This is done in text mode via + # a raw getc rather than via a cursor read to avoid switching to + # graphics mode. On some terminals with separate text and + # graphics planes a switch to graphics mode turns off the text + # plane. + + call fseti (STDIN, F_RAW, YES) + if (getci (STDIN, key) == EOF) + key = '\r' + call fseti (STDIN, F_RAW, NO) + + # Take the action commanded by the user. At present the morehelp + # option merely prints cursor mode help; this is appropriate + # because the first waitpage call occurs after printing user help + # in response to ? (or after a :.show). + + switch (key) { + case 'q': + # Quit, do not clear graphics and redraw. + if (TR_PAGE(tr) == NO) { + # If screen paging is disabled (text drawn underneath + # transparent graphics overlay), clear the text frame + # only, using the clear line function. + + do i = 1, ttystati (tty, TTY_NLINES) { + call ttygoto (fd, tty, 1, i) + call ttyclearln (fd, tty) + } + } else + call ttyclearln (fd, tty) + + call flush (fd) + call gki_reactivatews (stream, 0) + break + + case '\r', '\n': + # Quit, clear graphics and redraw. + call ttyclearln (fd, tty) + call flush (fd) + call gki_reactivatews (stream, 0) + call gtr_redraw (stream) + break + + case ' ': + # Print cursor mode help. + iferr (call pagefile (KEYSFILE, "cursor mode help")) + call erract (EA_WARN) + + default: + # Illegal keystroke. + call printf ("\007") + call flush (STDOUT) + } + } + + call ttycdes (tty) +end diff --git a/sys/gio/cursor/gtrwcur.x b/sys/gio/cursor/gtrwcur.x new file mode 100644 index 00000000..9def0a67 --- /dev/null +++ b/sys/gio/cursor/gtrwcur.x @@ -0,0 +1,19 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <gki.h> + +# GTR_WRITECURSOR -- Write the graphics cursor position in NDC coordinates. + +procedure gtr_writecursor (fd, x, y) + +int fd # graphics stream +real x, y # NDC coords of cursor + +int mx, my + +begin + mx = max(0, min(GKI_MAXNDC, nint (x * GKI_MAXNDC))) + my = max(0, min(GKI_MAXNDC, nint (y * GKI_MAXNDC))) + + call gki_setcursor (fd, mx, my, 0) +end diff --git a/sys/gio/cursor/gtrwritep.x b/sys/gio/cursor/gtrwritep.x new file mode 100644 index 00000000..d1a3fd4a --- /dev/null +++ b/sys/gio/cursor/gtrwritep.x @@ -0,0 +1,68 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <syserr.h> +include <error.h> +include <gio.h> +include <gki.h> +include "gtr.h" + +# GTR_WRITEP -- Virtually write (append) to the graphics frame buffer. Return a +# pointer to the start of the area reserved for the data and advance the +# output pointer beyond the new data area. The use of a buffer pointer here +# yields a very efficient graphics i/o dataflow. For the stdgraph kernel, +# XMIT (pr_psio) places a block of metacode directly in the frame buffer at +# the memory location we point to. GIOTR is then called to process the new +# data block. GIOTR calls GTR_FETCH, which "fetches" the next instruction +# by merely returning a pointer into the frame buffer. The stdgraph kernel +# is then called to execute the instruction. Hence in the simple case, there +# are no memory to memory copies and the contents of an instruction are +# touched only by the kernel. + +pointer procedure gtr_writep (fd, nchars) + +int fd # graphics stream +int nchars # nchars to reserve at end of buffer + +pointer tr, bufp, top, segp +int blen, nwords, ip_offset, op_offset +errchk syserr, realloc +include "gtr.com" + +begin + tr = trdes[fd] + if (tr == NULL) + call syserr (SYS_GWRITEP) + + nwords = nchars / SZ_SHORT + bufp = TR_FRAMEBUF(tr) + blen = TR_LENFRAMEBUF(tr) + segp = TR_OP(tr) # pointer to next segment + top = bufp + blen + + # Make space available in the buffer. We must always allocate the + # requested space, even if the result is a buffer larger than the + # (soft) maximum size permitted. Buffer space will be returned + # after GIOTR processes the new instructions if the buffer grows + # too large. + + if (nwords > top - segp) { + # Note that realloc may move the buffer, hence we must adjust any + # pointers into the buffer after the call to realloc. + + ip_offset = TR_IP(tr) - bufp + op_offset = segp - bufp + blen = blen + max (INC_LENFRAMEBUF, nwords) + + call realloc (bufp, blen, TY_SHORT) + + TR_FRAMEBUF(tr) = bufp + TR_LENFRAMEBUF(tr) = blen + TR_IP(tr) = bufp + ip_offset + segp = bufp + op_offset + } + + TR_OP(tr) = segp + nwords + TR_LASTOP(tr) = TR_OP(tr) + + return (segp) +end diff --git a/sys/gio/cursor/gtrwsclip.x b/sys/gio/cursor/gtrwsclip.x new file mode 100644 index 00000000..3a0a384b --- /dev/null +++ b/sys/gio/cursor/gtrwsclip.x @@ -0,0 +1,144 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +# GTR_POLYCLIP -- Clip a convex polygon to a box. If the polygon is entirely +# outside the box 0 is returned; if the polygon is entirely within the box 1 +# is returned, otherwise the polygon is clipped and a value other than 0 or 1 +# is returned. This is based on code by Paul Heckbert from Graphics Gems, +# 1985/1989. + +int procedure gtr_polyclip (pv, npts, x1, x2, y1, y2) + +short pv[ARB] #U polygon to be clipped +int npts #U number of points in polygon +int x1,x2,y1,y2 #I clipping box + +pointer sp, p1, p2, pt +int x1out, x2out, y1out, y2out, i +int gtr_cliptoplane() +define nopts_ 91 + +begin + x1out = 0; x2out = 0 + y1out = 0; y2out = 0 + + # Count vertices which are outside with respect to each of the + # four planes. + + do i = 1, npts*2, 2 { + if (pv[i+0] < x1) x1out = x1out + 1 + if (pv[i+0] > x2) x2out = x2out + 1 + if (pv[i+1] < y1) y1out = y1out + 1 + if (pv[i+1] > y2) y2out = y2out + 1 + } + + # Is the polygon entirely inside the clipping box? + if (x1out + x2out + y1out + y2out == 0) + return (1) + + # Is the polygon entirely outside the clipping box? + if (x1out == npts || x2out == npts || y1out == npts || y2out == npts) + return (0) + + # If we get here the polygon partially intersects the clipping box. + # Clip against each of the planes that might cut the polygon, clipping + # the previously clipped polygon in each step. This is done in + # floating point to minimize accumulation of error when interpolating + # to the clipping plane to compute a new polygon vertex when the plane + # is crossed. + + call smark (sp) + call salloc (p1, npts * 4, TY_REAL) + p2 = p1 + npts * 2 + + call achtsr (pv, Memr[p1], npts * 2) + + if (x1out > 0) + if (gtr_cliptoplane (p1, p2, npts, 0, -1.0, real(x1)) == 0) + goto nopts_ + else { + pt = p1; p1 = p2; p2 = pt + } + if (x2out > 0) + if (gtr_cliptoplane (p1, p2, npts, 0, 1.0, real(x2)) == 0) + goto nopts_ + else { + pt = p1; p1 = p2; p2 = pt + } + if (y1out > 0) + if (gtr_cliptoplane (p1, p2, npts, 1, -1.0, real(y1)) == 0) + goto nopts_ + else { + pt = p1; p1 = p2; p2 = pt + } + if (y2out > 0) + if (gtr_cliptoplane (p1, p2, npts, 1, 1.0, real(y2)) == 0) + goto nopts_ + else { + pt = p1; p1 = p2; p2 = pt + } + + call achtrs (Memr[p1], pv, npts * 2) + call sfree (sp) + return (npts) + +nopts_ + call sfree (sp) + return (0) +end + + +# GTR_CLIPTOPLANE -- Clip the convex polygon P1 against a plane, copying +# the inbounds portion to the output polygon P2. + +int procedure gtr_cliptoplane (p1, p2, npts, index, s, ref) + +pointer p1 #I pointer to input polygon +pointer p2 #I pointer to output polygon +int npts #U number of polygon points or vertices +int index #I index of coordinate to be tested +real s #I sign for comparison +real ref #I value to compare against + +int nout, i +pointer op, u, v +real tu, tv, t + +begin + nout = 0 + op = p2 + + u = p1 + (npts - 1) * 2 + tu = s * Memr[u+index] - ref + v = p1 + + do i = 1, npts { + # On old polygon P1, U is previous vertex, V is current vertex, + # TV is negative if vertex V is in. + + tv = s * Memr[v+index] - ref + + if (! ((tu <= 0 && tv <= 0) || (tu > 0 && tv > 0))) { + # Edge crosses plane; add intersection point to P2. + t = tu / (tu - tv) + Memr[op+0] = Memr[u+0] + t * (Memr[v+0] - Memr[u+0]) + Memr[op+1] = Memr[u+1] + t * (Memr[v+1] - Memr[u+1]) + nout = nout + 1 + op = op + 2 + } + + if (tv <= 0) { + # Vertex V is in, copy it out. + Memr[op+0] = Memr[v+0] + Memr[op+1] = Memr[v+1] + nout = nout + 1 + op = op + 2 + } + + u = v + tu = tv + v = v + 2 + } + + npts = nout + return (nout) +end diff --git a/sys/gio/cursor/gtrwstran.x b/sys/gio/cursor/gtrwstran.x new file mode 100644 index 00000000..9262e00a --- /dev/null +++ b/sys/gio/cursor/gtrwstran.x @@ -0,0 +1,490 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <mach.h> +include <gio.h> +include <gki.h> +include "gtr.h" + +define MOVE 0 +define DRAW 1 +define LEFT 0 +define RIGHT 1 +define BELOW 0 +define ABOVE 1 +define INSIDE 2 +define FIRSTPT GKI_POLYLINE_P + + +# GTR_WSTRAN -- Apply the workstation transformation to an instruction and +# write the transformed instruction to the graphics kernel. The transformation +# parameters etc. should have been initialized in the gtr common before we +# are called. + +procedure gtr_wstran (gki) + +short gki[ARB] #I metacode instruction to be spooled + +long x, y +pointer sp, buf +int length, npts, data +int gtr_polyclip() +bool sge_wsenable() +include "gtr.com" + +begin + # Check with the graphics kernel to see if scaling of graphics + # instructions is enabled (it is disabled if the graphics device is + # already doing it for us). + + if (!sge_wsenable()) { + call gki_write (tr_stream, gki) + return + } + + switch (gki[GKI_HDR_OPCODE]) { + case GKI_FILLAREA: + npts = gki[GKI_FILLAREA_N] + data = GKI_FILLAREA_P + length = gki[GKI_HDR_LENGTH] + call amovs (gki, pl, length) + + switch (gtr_polyclip (pl[data], npts, mx1, mx2, my1, my2)) { + case 0: + # Entire instruction out of bounds. + case 1: + # Entire instruction in bounds. + pl_op = GKI_POLYLINE_P + npts * 2 + call gpt_flush() + default: + # Instruction has been clipped. + pl_op = GKI_POLYLINE_P + npts * 2 + call gpt_flush() + } + + case GKI_POLYLINE, GKI_POLYMARKER: + call gtr_polytran (gki) + + case GKI_SETCURSOR: + length = gki[GKI_HDR_LENGTH] + call smark (sp) + call salloc (buf, length, TY_SHORT) + + # Move cursor to edge of screen if point referenced is out of + # bounds. + + call amovs (gki, Mems[buf], length) + x = gki[GKI_SETCURSOR_POS] + y = gki[GKI_SETCURSOR_POS+1] + call gtr_ctran (x, y, x, y) + Mems[buf+GKI_SETCURSOR_POS-1] = x + Mems[buf+GKI_SETCURSOR_POS] = y + call gki_write (tr_stream, Mems[buf]) + + call sfree (sp) + + case GKI_TEXT: + length = gki[GKI_HDR_LENGTH] + call smark (sp) + call salloc (buf, length, TY_SHORT) + + # Discard text drawing instruction if the point referenced is + # out of bounds. If in bounds, transform coordinates and draw + # at the transformed point. + + call amovs (gki, Mems[buf], length) + x = gki[GKI_TEXT_P] + y = gki[GKI_TEXT_P+1] + if (x >= mx1 && x <= mx2 && y >= my1 && y <= my2) { + call gtr_ctran (x, y, x, y) + Mems[buf+GKI_TEXT_P-1] = x + Mems[buf+GKI_TEXT_P] = y + call gki_write (tr_stream, Mems[buf]) + } + + call sfree (sp) + + case GKI_PUTCELLARRAY: + # Just filter these out for now. + + default: + call gki_write (tr_stream, gki) + } +end + + +# GTR_CTRAN -- Apply the workstation transform to a set of GKI coordinates, +# i.e., transform raw GKI coords to screen coords in GKI units. + +procedure gtr_ctran (mx, my, sx, sy) + +int mx, my # raw GKI coordinates +int sx, sy # screen coordinates in GKI units +include "gtr.com" + +begin + sx = max(0, min(GKI_MAXNDC, nint ((mx - mx1) * xscale + xorigin))) + sy = max(0, min(GKI_MAXNDC, nint ((my - my1) * yscale + yorigin))) +end + + +# GTR_POLYTRAN -- Scale a polyline, polymarker, or fill area instruction +# by applying the workstation transformation. The workstation transformation +# scales vectors in a viewport defined in NDC(GKI) space to fit the full +# device screen. Vectors or segments of vectors lying outside the viewport +# are clipped at the screen boundary. + +procedure gtr_polytran (gki) + +short gki[ARB] # gki instruction to be transformed +long mx, my +int last_ip, opcode, i, ip +bool inbounds, otherside, points +int gpt_firstpt() +include "gtr.com" + +begin + last_ip = gki[GKI_HDR_LENGTH] + opcode = gki[GKI_HDR_OPCODE] + points = (opcode == GKI_POLYMARKER) + + # In the process of clipping a polyline may be broken into several + # smaller polylines (or polymarkers or fillareas, all of which are + # very similar at the instruction level). We store the GKI header + # in the first few words of the PL array so that when the transformed + # polyline is broken it is ready for execution. + + do i = 1, GKI_POLYLINE_P - 1 + pl[i] = gki[i] + pl_op = GKI_POLYLINE_P + + # Clip all points until either a point is encountered which is inbounds + # or which is on the other side of the viewport (in either axis). This + # is a fast way of clipping polylines which are mostly out of bounds. + # Return immediately if the entire vector is out of bounds. + + otherside = true + ip = FIRSTPT + if (gpt_firstpt (gki, ip, last_ip) <= 0) + return + + # Set initial position. + cx = gki[ip] + cy = gki[ip+1] + + # Clip the remaining points. Clipping is performed in GKI coordinates. + # The workstation transformation is not applied until the clipped + # vector is output. + + for (ip=ip+2; ip < last_ip; ip=ip+2) { + mx = gki[ip] + my = gki[ip+1] + + # Check to see if this is the first point of a new polyline. + # If so we must set the first physical point in the output + # polyline to the current position, making the current point + # the second physical point of the output polyline. + + if (pl_op <= GKI_POLYLINE_P) { + # Place the current pen position in the polyline as the + # first point if it is inbounds. + + if (cy <= my2 && cy >= my1 && cx <= mx2 && cx >= mx1) { + last_point_inbounds = true + pl[pl_op] = cx + pl_op = pl_op + 1 + pl[pl_op] = cy + pl_op = pl_op + 1 + } else { + last_point_inbounds = false + do i = 1, 4 { + xs[i] = cx + ys[i] = cy + } + } + } + + # Update the current position. + + cx = mx + cy = my + + # Clip at the edge of the device screen. + + inbounds = (my <= my2 && my >= my1 && mx <= mx2 && mx >= mx1) + + if (inbounds && (last_point_inbounds || points)) { + # Add point to polyline (the fast way). + pl[pl_op] = mx + pl_op = pl_op + 1 + pl[pl_op] = my + pl_op = pl_op + 1 + + } else if ((inbounds||last_point_inbounds||otherside) && !points) { + # Clip at viewport boundary. + + if (last_point_inbounds) { + # Update coords of last point drawn (necessary since we did + # not use the clipping code for inbounds points). + do i = 1, 4 { + xs[i] = pl[pl_op-2] + ys[i] = pl[pl_op-1] + } + } + call gpt_clipl (DRAW, mx, my) + otherside = false + + } else { + # Both points are out of bounds. Scan along until a point is + # found which is again in bounds, or which is on the other side + # of the viewport, requiring clipping across the viewport. + + if (gpt_firstpt (gki, ip, last_ip) > 0) { + do i = 1, 4 { + xs[i] = gki[ip] + ys[i] = gki[ip+1] + } + cx = gki[ip] + cy = gki[ip+1] + } + + otherside = true + inbounds = false + } + + last_point_inbounds = inbounds + } + + call gpt_flush() +end + + +# GPT_FIRSTPT -- Scan a vector and return the index of the next good point. +# A good point is a point which is either inbounds or which preceeds a point +# which is either inbounds or on the other side of the viewport, necessitating +# clipping across the viewport. + +int procedure gpt_firstpt (gki, ip, last_ip) + +short gki[ARB] # vector being clipped +int last_ip # last legal value of ip +int ip # starting index + +int mx, my, i +int first_ip, new_ip +include "gtr.com" + +begin + mx = gki[ip] + my = gki[ip+1] + first_ip = ip + new_ip = last_ip + + if (mx < mx1) { + do i=ip+2, last_ip, 2 + if (gki[i] >= mx1) { + new_ip = i + break + } + } else if (mx > mx2) { + do i=ip+2, last_ip, 2 + if (gki[i] <= mx2) { + new_ip = i + break + } + } else if (my < my1) { + do i=ip+3, last_ip, 2 + if (gki[i] >= my1) { + new_ip = i - 1 + break + } + } else if (my > my2) { + do i=ip+3, last_ip, 2 + if (gki[i] <= my2) { + new_ip = i - 1 + break + } + } else + return (ip) + + if (new_ip >= last_ip) + return (0) # entire vector is indefinite + else + ip = max (first_ip, new_ip - 2) + + return (ip) +end + + +# GPT_CLIPL -- Clip at left boundary. + +procedure gpt_clipl (pen, mx, my) + +int pen # move or draw +long mx, my # point to be clipped +long new_my +int newpen +include "gtr.com" + +begin + # Does line cross boundary? + if ((mx >= mx1 && xs[1] < mx1) || (mx <= mx1 && xs[1] > mx1)) { + if (mx >= mx1) + newpen = MOVE + else + newpen = pen + new_my = real(my - ys[1]) * real(mx1 - mx) / real(mx - xs[1]) + + my + 0.5 + call gpt_clipr (newpen, mx1, new_my) + } + + xs[1] = mx + ys[1] = my + + if (mx >= mx1) + call gpt_clipr (pen, mx, my) +end + + +# GPT_CLIPR -- Clip at right boundary. + +procedure gpt_clipr (pen, mx, my) + +int pen # move or draw +long mx, my # point to be clipped +long new_my +int newpen +include "gtr.com" + +begin + # Does line cross boundary? + if ((mx <= mx2 && xs[2] > mx2) || (mx >= mx2 && xs[2] < mx2)) { + if (mx <= mx2) + newpen = MOVE + else + newpen = pen + new_my = real(my - ys[2]) * real(mx2 - mx) / real(mx - xs[2]) + + my + 0.5 + call gpt_clipb (newpen, mx2, new_my) + } + + xs[2] = mx + ys[2] = my + + if (mx <= mx2) + call gpt_clipb (pen, mx, my) +end + + +# GPT_CLIPB -- Clip at bottom boundary. + +procedure gpt_clipb (pen, mx, my) + +int pen # move or draw +long mx, my # point to be clipped +long new_mx +int newpen +include "gtr.com" + +begin + # Does line cross boundary? + if ((my >= my1 && ys[3] < my1) || (my <= my1 && ys[3] > my1)) { + if (my >= my1) + newpen = MOVE + else + newpen = pen + new_mx = real(mx - xs[3]) * real(my1 - my) / real(my - ys[3]) + + mx + 0.5 + call gpt_clipt (newpen, new_mx, my1) + } + + xs[3] = mx + ys[3] = my + + if (my >= my1) + call gpt_clipt (pen, mx, my) +end + + +# GPT_CLIPT -- Clip at top boundary and put the final clipped point(s) in +# the output polyline. Note that a "move" at this level does not affect +# the current position (cx,cy), since the vector endpoints have been clipped +# and the current position vector follows the unclipped vector points input +# by the user. + +procedure gpt_clipt (pen, mx, my) + +int pen # move or draw +long mx, my # point to be clipped +include "gtr.com" + +begin + # Does line cross boundary? + if ((my <= my2 && ys[4] > my2) || (my >= my2 && ys[4] < my2)) { + if (my <= my2 || pen == MOVE) + call gpt_flush() + pl[pl_op] = real(mx - xs[4]) * real(my2 - my) / real(my - ys[4]) + + mx + 0.5 + pl_op = pl_op + 1 + pl[pl_op] = my2 + pl_op = pl_op + 1 + } + + xs[4] = mx + ys[4] = my + + if (my <= my2) { + if (pen == MOVE) + call gpt_flush() + pl[pl_op] = mx + pl_op = pl_op + 1 + pl[pl_op] = my + pl_op = pl_op + 1 + } +end + + +# GPT_FLUSH -- Flush the buffered "polyline", i.e., array of transformed and +# clipped points. For a polyline or fill area polygon there must be at least +# two points (4 cells) or it will be discarded. A single point polymarker is +# permitted. + +procedure gpt_flush() + +int npts, i +long mx, my +include "gtr.com" + +begin + if (pl_op >= GKI_POLYLINE_P + 2) { + npts = (pl_op - GKI_POLYLINE_P) / 2 + + # Apply the workstation transformation. + do i = GKI_POLYLINE_P, pl_op, 2 { + mx = nint ((pl[i] - mx1) * xscale + xorigin) + my = nint ((pl[i+1] - my1) * yscale + yorigin) + pl[i] = max(0, min(GKI_MAXNDC, mx)) + pl[i+1] = max(0, min(GKI_MAXNDC, my)) + } + + switch (pl[GKI_HDR_OPCODE]) { + case GKI_POLYMARKER: + pl[GKI_POLYMARKER_L] = pl_op - 1 + pl[GKI_POLYMARKER_N] = npts + call gki_write (tr_stream, pl) + + case GKI_FILLAREA: + pl[GKI_FILLAREA_L] = pl_op - 1 + pl[GKI_FILLAREA_N] = npts + call gki_write (tr_stream, pl) + + default: + if (npts >= 2) { + pl[GKI_POLYLINE_L] = pl_op - 1 + pl[GKI_POLYLINE_N] = npts + call gki_write (tr_stream, pl) + } + } + + pl_op = GKI_POLYLINE_P + } +end diff --git a/sys/gio/cursor/mkpkg b/sys/gio/cursor/mkpkg new file mode 100644 index 00000000..f6a79332 --- /dev/null +++ b/sys/gio/cursor/mkpkg @@ -0,0 +1,57 @@ +# Make the CURSOR package. + +$checkout libcur.a lib$ +$update libcur.a +$checkin libcur.a lib$ +$exit + +libcur.a: + # $set xflags = "$(xflags) -qfx" + + giotr.x gtr.com gtr.h <config.h> <gio.h> <gki.h> <xwhen.h> + grcaxes.x grc.h gtr.com gtr.h <gio.h> <gset.h> + grcclose.x grc.h gtr.h <gio.h> + grccmd.x grc.h gtr.h <ctype.h> <fset.h> <gio.h> <gki.h>\ + <gset.h> <mach.h> <ttyset.h> + grcinit.x grc.h <gio.h> + grcopen.x grc.h gtr.com gtr.h <gio.h> <gki.h> + grcpl.x gtr.h <gio.h> <gki.h> <gset.h> grc.h + grcread.x gtr.h <fset.h> <gio.h> + grcredraw.x grc.h <gio.h> + grcscr.x gtr.com gtr.h <gio.h> <gki.h> + grcstatus.x grc.h gtr.com gtr.h <gio.h> + grctext.x gtr.h <gio.h> <gki.h> <gset.h> grc.h + grcwarn.x + grcwcs.x grc.h gtr.h <gio.h> <gki.h> <mach.h> + grcwrite.x grc.h gtr.h <fset.h> <gio.h> + gtrbackup.x gtr.com gtr.h <gio.h> <gki.h> <gset.h> + gtrconn.x + gtrctrl.x gtr.com gtr.h <fset.h> <gio.h> <gki.h> <gset.h>\ + <prstat.h> <config.h> + gtrdelete.x gtr.h <gio.h> <gki.h> + gtrdiscon.x <gio.h> + gtrfetch.x gtr.h <gio.h> <gki.h> + gtrframe.x gtr.h <gio.h> <gki.h> + gtrgflush.x gtr.com gtr.h <error.h> <gio.h> + gtrgtran.x gtr.com gtr.h <gio.h> <gki.h> + gtrgtty.x gtr.h <gio.h> <gki.h> + gtrinit.x gtr.com gtr.h <gio.h> <gki.h> <gset.h> + gtropenws.x gtr.com gtr.h <config.h> <error.h> <fio.h> <prstat.h>\ + <fset.h> <gio.h> <gki.h> + gtrpage.x gtr.h <gio.h> <gset.h> + gtrptran.x gtr.com gtr.h <gio.h> <gki.h> <mach.h> + gtrrcur.x <gki.h> + gtrredraw.x gtr.h <gio.h> + gtrreset.x gtr.com gtr.h <error.h> <gio.h> + gtrset.x gtr.com gtr.h <gio.h> <gki.h> + gtrstatus.x gtr.com gtr.h <fset.h> <gio.h> + gtrtrunc.x gtr.h <gio.h> <gki.h> + gtrundo.x gtr.com gtr.h <gio.h> <gki.h> <gset.h> + gtrwaitp.x grc.h gtr.h <error.h> <fset.h> <gio.h> <ttyset.h> + gtrwcur.x <gki.h> + gtrwritep.x gtr.com <error.h> <gio.h> <gki.h> gtr.h + gtrwstran.x gtr.com gtr.h <gio.h> <gki.h> <mach.h> + gtrwsclip.x + prpsinit.x + rcursor.x grc.h gtr.com gtr.h <ctype.h> <gio.h> <gki.h> <ttset.h> + ; diff --git a/sys/gio/cursor/prpsinit.x b/sys/gio/cursor/prpsinit.x new file mode 100644 index 00000000..4959deff --- /dev/null +++ b/sys/gio/cursor/prpsinit.x @@ -0,0 +1,15 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +# PRPSINIT -- Load the gio.cursor graphics driver for pseudofile i/o to the +# graphics streams. + +procedure prpsinit() + +extern giotr() +extern gtr_control(), gtr_gflush(), gtr_writep() +extern stg_readtty(), stg_writetty() + +begin + call prpsload (giotr, gtr_control, gtr_gflush, gtr_writep, + stg_readtty, stg_writetty) +end diff --git a/sys/gio/cursor/rcursor.x b/sys/gio/cursor/rcursor.x new file mode 100644 index 00000000..cc7dc739 --- /dev/null +++ b/sys/gio/cursor/rcursor.x @@ -0,0 +1,692 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <ctype.h> +include <ttset.h> +include <gio.h> +include <gki.h> +include "gtr.h" +include "grc.h" + +define SZ_CHARCON 5 +define MARKLEN 0.01 + +# Cursor step algorithm parameters. + +define MAX_STEP 0.1 # max cursor step size, cursor motions +define MIN_STEP 0.002 # min cursor step size, cursor motions +define LARGER_STEP 2.0 # factor by which step size is increased +define SMALLER_STEP 0.5 # factor by step size is decreased +define NSTEP 2 # number of steps before larger step +define MANUAL_STEP 5.0 # gear ratio for F/V cursor control +define SLOW 1 # for fast/slow algorithm +define FAST 2 + +# Zoom parameters. + +define X_ZOOMFACTOR 0.5 # zoom factors +define Y_ZOOMFACTOR 0.5 +#define X_ZOOMFACTOR 0.666 # zoom factors +#define Y_ZOOMFACTOR 0.666 + +# Roam factors. + +define X_ROAM 0.333 # fraction of the current window +define Y_ROAM 0.333 # fraction of the current window + + +# RCURSOR -- Read the position of a cursor. This is the main entry point to +# cursor mode/cursor input from the CL; we are called by the QUERY procedure +# of the CL when a cursor type parameter is read. The cursor position is +# returned as a string of the form +# +# x y wcs key stringval +# +# where the "stringval" field may be absent if not appropriate for a given key. +# If EOF is returned the cursor value string is undefined. + +int procedure rcursor (stream, outstr, maxch) + +int stream # graphics stream +char outstr[ARB] # encoded cursor value (output) +int maxch + +bool cminit +int xroam[9], yroam[9] +pointer rc, tr, sp, lbuf, ip +char charcon[SZ_CHARCON], ch +real x1, x2, y1, y2, xt, yt, v[10] +real lx1, lx2, ly1, ly2, aspect_ratio +real x, y, rx, ry, xw, yw, dx, dy, xc, yc +int junk, key, nukey, last_zoom, i, wcs, ppos, ucasein, raster + +bool ttygetb() +pointer grc_open() +int envfind(), ctocc(), oscmd(), gtr_readcursor(), grc_readtty() +int grc_cursor(), grc_command(), grc_selectwcs(), grc_mapkey(), ttstati() +real ttygetr() + +errchk grc_text, grc_readtty, grc_writecursor +errchk grc_init, grc_open, grc_command, grc_cursor, grc_message +errchk grc_readcursor, grc_mapkey, grc_redraw, envfind + +data xroam /1,0,-1,1,0,-1,1,0,-1/ +data yroam /1,1,1,0,0,0,-1,-1,-1/ +data rc /NULL/ +define done_ 91 +define coloncmd_ 92 + +begin + call smark (sp) + call salloc (lbuf, SZ_COMMAND, TY_CHAR) + + # Allocate and initialize the RCURSOR descriptor. + if (rc == NULL) { + call grc_init (rc) + cminit = true + } else + cminit = false + + # Open or reopen the graphics kernel. + tr = grc_open ("", APPEND, stream, rc) + + # Process CMINIT command string, if present in environment. This is + # only done once. + + if (cminit) { + if (envfind ("cminit", Memc[lbuf], SZ_COMMAND) > 0) { + ip = lbuf + while (IS_WHITE(Memc[ip]) || Memc[ip] == '.') + ip = ip + 1 + junk = grc_command (rc, stream, 0.,0.,0,0.,0., Memc[ip]) + } + cminit = false + } + + # If the graphics device does not permit input, i.e., does not have + # a cursor, return EOF. + + if (!ttygetb (TR_TTY(tr), "in")) { + x = 0; y = 0 + key = EOF + goto done_ + } + + # Determine if input keys are to be mapped to lower case by default, + # i.e., ucasein mode has been set for the terminal driver. + + ucasein = ttstati (STDIN, TT_UCASEIN) + + last_zoom = 3 + ppos = NO + + # Enter cursor mode loop. The loop terminates when a non cursor mode + # keystroke is typed. + + while (grc_cursor (rc, stream, key,x,y, raster,rx,ry, ppos) != EOF) { + Memc[lbuf] = EOS + + # As a rule, no processing is performed on escaped keys. The only + # exception is when ucasein mode is set in the terminal driver, + # causing upper case input to be mapped to lower case. This mapping + # is disabled in a raw mode cursor read, hence we must perform the + # mapping explicitly here, returning a lower case key to the + # applications program. Unescaped upper case input keystrokes will + # be intercepted by cursor mode when ucasein mode is in effect. + + if (key == '\\') { + junk = gtr_readcursor (stream, key, x, y, raster, rx, ry) + if (ucasein == YES && IS_UPPER(key)) + key = TO_LOWER (key) + break + } + + # Map keystroke. If the keystroke maps to a null value the key + # is not recognized as a cursor mode keystroke and we exit. + + if (grc_mapkey (rc, key, nukey) == NULL) + break + + switch (nukey) { + case 'M': + # Move the feature under the cursor to the center of the + # screen without changing the scaling. + + call grc_scrtondc (x, y, xc, yc) + call gtr_gtran (stream, x1, x2, y1, y2) + xw = (x2 - x1) / 2. + yw = (y2 - y1) / 2. + call gtr_ptran (stream, xc-xw, xc+xw, yc-yw, yc+yw) + call grc_redraw (rc, stream, x, y, raster, rx, ry) + call grc_restorecurpos (stream, xc, yc) + + case 'Z': + # Zoom in in both X and Y. + call grc_scrtondc (x, y, xc, yc) + call gtr_gtran (stream, x1, x2, y1, y2) + xw = (x2 - x1) * X_ZOOMFACTOR / 2. + yw = (y2 - y1) * Y_ZOOMFACTOR / 2. + call gtr_ptran (stream, xc-xw, xc+xw, yc-yw, yc+yw) + call grc_redraw (rc, stream, x, y, raster, rx, ry) + call grc_restorecurpos (stream, xc, yc) + last_zoom = 3 + + case 'X': + # Zoom in in X. + call grc_scrtondc (x, y, xc, yc) + call gtr_gtran (stream, x1, x2, y1, y2) + xw = (x2 - x1) * X_ZOOMFACTOR / 2. + call gtr_ptran (stream, xc-xw, xc+xw, y1, y2) + call grc_redraw (rc, stream, x, y, raster, rx, ry) + call grc_restorecurpos (stream, xc, yc) + last_zoom = 1 + + case 'Y': + # Zoom in in Y. + call grc_scrtondc (x, y, xc, yc) + call gtr_gtran (stream, x1, x2, y1, y2) + yw = (y2 - y1) * Y_ZOOMFACTOR / 2. + call gtr_ptran (stream, x1, x2, yc-yw, yc+yw) + call grc_redraw (rc, stream, x, y, raster, rx, ry) + call grc_restorecurpos (stream, xc, yc) + last_zoom = 2 + + case '>': + # Zoom in in Y by setting the upper limit of the viewport + # to the cursor Y position. + + call grc_scrtondc (x, y, xc, yc) + call gtr_gtran (stream, lx1, lx2, ly1, ly2) + call gtr_ptran (stream, lx1, lx2, ly1, yc) + call grc_redraw (rc, stream, x, y, raster, rx, ry) + call gtr_writecursor (stream, x, 0.5) + last_zoom = 'E' + + case '<': + # Zoom in in Y by setting the lower limit of the viewport + # to the cursor Y position. + + call grc_scrtondc (x, y, xc, yc) + call gtr_gtran (stream, lx1, lx2, ly1, ly2) + call gtr_ptran (stream, lx1, lx2, yc, ly2) + call grc_redraw (rc, stream, x, y, raster, rx, ry) + call gtr_writecursor (stream, x, 0.5) + last_zoom = 'E' + + case 'E': + # Expand by marking corners of new viewport. If the range is + # small in either X or Y only the other axis will be expanded. + + call gtr_gtran (stream, lx1, lx2, ly1, ly2) + call grc_scrtondc (x, y, x1, y1) + call grc_message (stream, "again:") + junk = grc_cursor (rc, stream, key,x2,y2, raster,rx,ry, ppos) + call grc_scrtondc (x2, y2, x2, y2) + + if (x1 > x2) + { xt = x2; x2 = x1; x1 = xt } + if (y1 > y2) + { yt = y2; y2 = y1; y1 = yt } + + if (abs (x1 - x2) < .01) + call gtr_ptran (stream, lx1, lx2, y1, y2) + else if (abs (y1 - y2) < .01) + call gtr_ptran (stream, x1, x2, ly1, ly2) + else + call gtr_ptran (stream, x1, x2, y1, y2) + + call grc_redraw (rc, stream, x, y, raster, rx, ry) + call gtr_writecursor (stream, 0.5, 0.5) + last_zoom = 'E' + + case 'P': + # Zoom out. + call grc_scrtondc (x, y, xc, yc) + call gtr_gtran (stream, x1, x2, y1, y2) + + if (last_zoom == 'E') { + call gtr_ptran (stream, lx1, lx2, ly1, ly2) + lx1 = x1; lx2 = x2; ly1 = y1; ly2 = y2 + } else { + if (last_zoom == 1 || last_zoom == 3) { + xw = (x2 - x1) / X_ZOOMFACTOR / 2. + x1 = xc - xw + x2 = xc + xw + } + if (last_zoom == 2 || last_zoom == 3) { + yw = (y2 - y1) / Y_ZOOMFACTOR / 2. + y1 = yc - yw + y2 = yc + yw + } + call gtr_ptran (stream, x1, x2, y1, y2) + } + + call grc_redraw (rc, stream, x, y, raster, rx, ry) + call grc_restorecurpos (stream, xc, yc) + + case 'W': + # Select and fix WCS to be used for scr->wcs coordinate + # transformations. + + call grc_scrtondc (x, y, xc, yc) + TR_WCS(tr) = grc_selectwcs (tr, raster, xc, yc) + + case 'C': + # Running tally of cursor position. + #if (ppos == NO) { + # call grc_pcursor (stream, x, y, raster, rx, ry) + # ppos = YES + #} else { + # call grc_message (stream, "\n\n") + # ppos = NO + #} + + call grc_pcursor (stream, x, y, raster, rx, ry) + + case 'D': + # Draw a line by marking the endpoints. + call grc_scrtondc (x, y, v[1], v[2]) + call grc_message (stream, "again:") + junk = grc_cursor (rc, stream, key,x2,y2, raster,rx,ry, ppos) + call grc_scrtondc (x2, y2, v[3], v[4]) + call grc_polyline (stream, v, 2) + + case 'T': + # Draw a text string. + if (grc_readtty (stream, "text: ", Memc[lbuf], SZ_COMMAND) <= 0) + next + call grc_scrtondc (x, y, xc, yc) + call grc_text (stream, xc, yc, Memc[lbuf]) + + case 'A': + # Draw and label the axes of the viewport. + call grc_axes (stream, x, y, raster, rx, ry) + + case 'B': + # Backup one instruction in the frame buffer. + call gtr_backup (stream) + + case 'U': + # Undo the last frame buffer edit. + call gtr_undo (stream) + + case 'R': + # Redraw the screen. + call grc_redraw (rc, stream, x, y, raster, rx, ry) + + case '0': + # Reset and redraw. + call gtr_ptran (stream, 0., 1., 0., 1.) + call gtr_writecursor (stream, .5, .5) + call grc_redraw (rc, stream, x, y, raster, rx, ry) + + case '5': + # Redraw (null roam request). + call grc_redraw (rc, stream, x, y, raster, rx, ry) + + case '1','2','3','4','6','7','8','9': + # Roam. + i = TO_INTEG (key) + if (xroam[i] != 0 || yroam[i] != 0) { + call gtr_gtran (stream, x1, x2, y1, y2) + dx = (x2 - x1) * X_ROAM * xroam[i] + dy = (y2 - y1) * Y_ROAM * yroam[i] + call gtr_ptran (stream, x1+dx, x2+dx, y1+dy, y2+dy) + call grc_redraw (rc, stream, x, y, raster, rx, ry) + } + + case ':': + # Enter a colon command string and terminate cursor mode. + + # Get the string value. + if (grc_readtty (stream, ":", Memc[lbuf], SZ_COMMAND) <= 0) + next + + # All cursor mode commands must begin with a ".". An osescape + # begins with an "!". + + if (Memc[lbuf] == '!') { + call gtr_page (STDERR, stream) + if (oscmd (Memc[lbuf+1], "", "", "") == ERR) + call fprintf (STDERR, "\7") + call gtr_waitpage (STDERR, stream) + + } else if (Memc[lbuf] == '.') { + # Save viewport for 'P'. +coloncmd_ + call gtr_gtran (stream, lx1, lx2, ly1, ly2) + last_zoom = 'E' + + TR_WAITPAGE(tr) = NO + if (grc_command (rc, stream, x, y, raster, rx, ry, + Memc[lbuf+1]) == EOF) { + key = EOF + goto done_ + } + + # The following is a no-op for most colon commands. + if (TR_WAITPAGE(tr) == YES) + call gtr_waitpage (STDERR, stream) + } else + break + + case '=': + # Shorthand for :.snap. The latter must be used once to + # set the plotter device, else the default stdplot device + # will be used. + + call strcpy (".snap", Memc[lbuf], SZ_COMMAND) + goto coloncmd_ + + default: + call fprintf (STDERR, "\007") + } + } + + # Mark the cursor position if markcur enabled. + if (RC_MARKCUR(rc) == YES && key != EOF) { + call grc_scrtondc (x, y, xc, yc) + aspect_ratio = ttygetr (TR_TTY(tr), "ar") + if (aspect_ratio < .001) + aspect_ratio = 1.0 + + v[1] = xc - MARKLEN * aspect_ratio + v[2] = yc + v[3] = xc + MARKLEN * aspect_ratio + v[4] = yc + v[5] = xc + v[6] = yc + v[7] = xc + v[8] = yc - MARKLEN + v[9] = xc + v[10] = yc + MARKLEN + call grc_polyline (stream, v, 5) + } + + # Close the workstation, leave graphics mode, position alpha cursor to + # lower left corner of graphics terminal. + + call grc_close (stream, rc) + + # Encode the cursor value as a string for the CL. +done_ + if (key != EOF) { + if (key == ' ') + call strcpy ("\\40", charcon, SZ_CHARCON) + else { + ch = char (key) + junk = ctocc (ch, charcon, SZ_CHARCON) + } + call grc_scrtowcs (stream, x, y, raster, rx, ry, xc, yc, wcs) + + call sprintf (outstr, maxch, "%g %g %d %s %s\n") + call pargr (xc) + call pargr (yc) + call pargi (wcs) + call pargstr (charcon) + call pargstr (Memc[lbuf]) + } else + outstr[1] = EOS + + call sfree (sp) + return (key) +end + + +# GRC_CURSOR -- Read the position of a cursor in screen coordinates. Recognizes +# the cursor movement keystrokes H, J, K, and L, exiting only when some other +# keystroke is received. The cursor movement algorithm is initialized upon +# entry. Two algorithms are provided for controlling the cursor step size. +# The first algorithm (automatic control) starts with a large initial step +# size. In the vicinity of a feature the cursor will overshoot the feature +# and the user will step back in the opposite direction, causing the step size +# to be decreased, rapidly converging to the desired position. Several steps +# in the same direction cause the large step size to be restored. The second +# algorithm (manual control) uses the F and V keys to directly control the step +# size. + +int procedure grc_cursor (rc, stream, key, x, y, raster, rx, ry, ppos) + +pointer rc #I rcursor descriptor +int stream #I graphics stream +int key #O keystroke typed +real x, y #O cursor screen coordinates +int raster #O raster number +real rx, ry #O cursor raster coordinates +int ppos #I print cursor position flag + +int speed +int xdir, ydir, nukey +real xstep, ystep, newx, newy + +bool ttygetb() +pointer gtr_gtty() +int gtr_readcursor(), grc_mapkey() +errchk gtr_readcursor, gtr_writecursor + +begin + # Reset the cursor step size to the default. + xstep = MAX_STEP + ystep = MAX_STEP + xdir = 0 + ydir = 0 + speed = 0 + + while (gtr_readcursor (stream, key, x, y, raster, rx, ry) != EOF) { + if (grc_mapkey (rc, key, nukey) == NULL) + break + + newx = x + newy = y + + switch (nukey) { + case 'F': + # Faster. + xstep = min (MAX_STEP, xstep * MANUAL_STEP) + ystep = min (MAX_STEP, ystep * MANUAL_STEP) + speed = FAST + + case 'V': + # Slower. + xstep = max (MIN_STEP, xstep / MANUAL_STEP) + ystep = max (MIN_STEP, ystep / MANUAL_STEP) + speed = SLOW + + case 'H': + # Step cursor left. + if (speed == 0) + if (xdir < -NSTEP) { + xstep = MAX_STEP + xdir = -1 + } else if (xdir > 0) { + xstep = max (MIN_STEP, xstep * SMALLER_STEP) + xdir = -1 + } else + xdir = xdir - 1 + newx = newx - xstep + call gtr_writecursor (stream, newx, newy) + + case 'J': + # Step cursor down. + if (speed == 0) + if (ydir < -NSTEP) { + ystep = MAX_STEP + ydir = -1 + } else if (ydir > 0) { + ystep = max (MIN_STEP, ystep * SMALLER_STEP) + ydir = -1 + } else + ydir = ydir - 1 + newy = newy - ystep + call gtr_writecursor (stream, newx, newy) + + case 'K': + # Step cursor up. + if (speed == 0) + if (ydir > NSTEP) { + ystep = MAX_STEP + ydir = 1 + } else if (ydir < 0) { + ystep = max (MIN_STEP, ystep * SMALLER_STEP) + ydir = 1 + } else + ydir = ydir + 1 + newy = newy + ystep + call gtr_writecursor (stream, newx, newy) + + case 'L': + # Step cursor right. + if (speed == 0) + if (xdir > NSTEP) { + xstep = MAX_STEP + xdir = 1 + } else if (xdir < 0) { + xstep = max (MIN_STEP, xstep * SMALLER_STEP) + xdir = 1 + } else + xdir = xdir + 1 + newx = newx + xstep + call gtr_writecursor (stream, newx, newy) + + default: + break + } + + # We assume the cursor may have moved if the WC capability exists + # for this device. + + if (ttygetb (gtr_gtty (stream), "WC")) { + x = newx + y = newy + } + + # Print the cursor position. + if (ppos == YES) + call grc_pcursor (stream, x, y, raster, rx, ry) + } + + return (key) +end + + +# GRC_MAPKEY -- Map keystroke. If the keystroke maps to a null value the key +# is not recognized as a cursor mode keystroke and we exit. Note that if case +# sensitivity is disabled, KEYS comparisions must be made in upper case but +# only lower case is to be returned to the calling program. + +int procedure grc_mapkey (rc, key, nukey) + +pointer rc #I rcursor descriptor +int key #U raw key value +int nukey #O mapped key value + +begin + nukey = max(1, min(MAX_KEYS, key)) + if (RC_CASE(rc) == NO && IS_LOWER(nukey)) + nukey = TO_UPPER(nukey) + + nukey = RC_KEYS(rc,nukey) + if (nukey == NULL) { + # Not a cursor mode key. + if (RC_CASE(rc) == NO && IS_UPPER(nukey)) + key = TO_LOWER(key) + } else if (IS_LOWER(nukey)) + nukey = TO_UPPER(nukey) + + return (nukey) +end + + +# GRC_RESTORECURPOS -- Restore the cursor position in NDC coordinates +# regardless of the current workstation transformation. + +procedure grc_restorecurpos (stream, x, y) + +int stream # graphics stream +real x, y # new cursor position in NDC coords +real sx, sy +include "gtr.com" + +begin + call grc_ndctoscr (x, y, sx, sy) + call gtr_writecursor (stream, sx, sy) +end + + +# GRC_READTTY -- Read from the terminal via the graphics kernel. If the +# kernel already has message data buffered we merely return that data, +# otherwise we issue the prompt given and interactively read the data. + +int procedure grc_readtty (stream, prompt, obuf, maxch) + +int stream #I graphics stream +char prompt[ARB] #I prompt, if read is interactive +char obuf[ARB] #O output buffer +int maxch #I max chars out + +bool issue_prompt +int nchars, index +int stg_msglen(), stg_readtty() +int stridxs(), strlen() + +begin + issue_prompt = (stg_msglen(STDIN) <= 0) + if (issue_prompt) + call stg_putline (STDERR, prompt) + + nchars = stg_readtty (STDIN, obuf, maxch) + index = stridxs ("\n", obuf) + if (index > 0) + obuf[index] = EOS + nchars = strlen (obuf) + + if (issue_prompt && nchars == 0) + call grc_message (stream, "\n\n") + + return (nchars) +end + + +# GRC_MESSAGE -- Write a message on the status line at the bottom of the +# screen. If the string is not newline terminated the terminal is left in +# status line text mode. To clear the status line and force the terminal +# back into graphics mode, output the string "\n\n". + +procedure grc_message (stream, message) + +int stream # graphics stream +char message[ARB] # message to be printed + +begin + call stg_putline (STDERR, message) +end + + +# GRC_PCURSOR -- Convert the cursor position in screen coordinates to world +# coordinates and print on the standard output. + +procedure grc_pcursor (stream, sx, sy, raster, rx, ry) + +int stream #I graphics stream +real sx, sy #I screen coords of cursor +int raster #I raster number +real rx, ry #I raster coords of cursor + +int wcs +real xc, yc +pointer sp, lbuf + +begin + call smark (sp) + call salloc (lbuf, SZ_LINE, TY_CHAR) + + call grc_scrtowcs (stream, sx, sy, raster, rx, ry, xc, yc, wcs) + if (abs(xc) > 1 && abs(xc) < 10000 && abs(yc) > 1 && abs(yc) < 10000) + call sprintf (Memc[lbuf], SZ_LINE, "%10.3f %10.3f \n") + else + call sprintf (Memc[lbuf], SZ_LINE, "%12.7g %12.7g \n") + call pargr (xc) + call pargr (yc) + + call stg_putline (STDERR, Memc[lbuf]) + call sfree (sp) +end |