aboutsummaryrefslogtreecommitdiff
path: root/sys/gio/cursor/gtrwstran.x
diff options
context:
space:
mode:
Diffstat (limited to 'sys/gio/cursor/gtrwstran.x')
-rw-r--r--sys/gio/cursor/gtrwstran.x490
1 files changed, 490 insertions, 0 deletions
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