DECLARE FUNCTION vsinsaft% (i%)
DECLARE FUNCTION vsinsbef% (i%)
DECLARE SUB vsdel (i%)
DECLARE SUB fillconvpoly (x!(), y!(), n%, col%, bcol%)
DECLARE SUB drawtri (x0!, y0!, x1!, y1!, x2!, y2!, col%, bcol%)
DECLARE SUB drawquad (x0!, y0!, x1!, y1!, x2!, y2!, x3!, y3!, col%, bcol%)
DECLARE SUB domost (x0!, y0!, x1!, y1!, upd%)
DECLARE SUB initmosts ()
DECLARE SUB printsmall (bx%, y%, c%, nam$)

SCREEN 9: CONST XDIM = 640, YDIM = 350
DIM SHARED pag%, lastx%(YDIM + 2), maskhack%

DIM SHARED regs%(7): regs%(0) = 11: CALL int86old(&H33, regs%(), regs%())
mousx% = XDIM \ 2: mousy% = YDIM \ 2

DIM SHARED smallfnt(64 - 1) AS LONG  '0-63 represent chars: 32-95
FOR z% = 0 TO 63: READ smallfnt(z%): NEXT z%

TYPE point2d
   x AS SINGLE: n AS INTEGER: p AS INTEGER: tag AS INTEGER
   cy0 AS SINGLE: cy1 AS SINGLE: ctag AS INTEGER
   fy0 AS SINGLE: fy1 AS SINGLE: ftag AS INTEGER
END TYPE
CONST VSPMAX = XDIM '<- careful!
DIM SHARED vsp(VSPMAX) AS point2d, vcnt%, gtag%

CALL initmosts
'CALL domost(320, 176, 128, 272, 1)
'CALL domost(128, 272, 320, 176, 1)

pt% = 0
DO
   IF backcnt% > 0 THEN
      LINE (0, 0)-(XDIM - 1, YDIM - 1), 13, BF
      backcnt% = backcnt% - 1
   END IF
  
   oz% = 0: z% = vsp(0).n: fcol% = 0: ccol% = 0
   DO
      nz% = vsp(z%).n

      IF vsp(z%).ctag <> vsp(oz%).ctag THEN cx0 = vsp(z%).x: cy0 = vsp(z%).cy0
      IF vsp(z%).ctag <> vsp(nz%).ctag THEN
         maskhack% = 8
         CALL drawquad(cx0, 0, vsp(nz%).x, 0, vsp(nz%).x, vsp(z%).cy1, cx0, cy0, ccol%, ccol%)
         maskhack% = 0: ccol% = ccol% XOR 8
         CALL printsmall((cx0 + vsp(nz%).x) \ 2, 2, 6, LTRIM$(STR$(vsp(z%).ctag)))
      END IF

      CALL drawquad(vsp(z%).x, vsp(z%).cy0, vsp(nz%).x, vsp(z%).cy1, vsp(nz%).x, vsp(z%).fy1, vsp(z%).x, vsp(z%).fy0, 6, 4)
     
      IF vsp(z%).ftag <> vsp(oz%).ftag THEN fx0 = vsp(z%).x: fy0 = vsp(z%).fy0
      IF vsp(z%).ftag <> vsp(nz%).ftag THEN
         maskhack% = 8
         CALL drawquad(fx0, fy0, vsp(nz%).x, vsp(z%).fy1, vsp(nz%).x, YDIM, fx0, YDIM, fcol%, fcol%)
         maskhack% = 0: fcol% = fcol% XOR 8
         CALL printsmall((fx0 + vsp(nz%).x) \ 2, YDIM - 3, 6, LTRIM$(STR$(vsp(z%).ftag)))
      END IF
     
      oz% = z%: z% = nz%
   LOOP WHILE vsp(z%).n

   IF vsp(vsp(vsp(0).n).n).n = 0 AND vsp(vsp(0).n).ftag < 0 THEN
      LOCATE 1, 1: PRINT "done!";
   END IF

   z$ = INKEY$
   regs%(0) = 5: CALL int86old(&H33, regs%(), regs%())
   obstatus% = bstatus%: bstatus% = regs%(0)
   regs%(0) = 11: CALL int86old(&H33, regs%(), regs%())
   mousx% = mousx% + regs%(2): IF mousx% < 0 THEN mousx% = 0
   mousy% = mousy% + regs%(3): IF mousy% < 0 THEN mousy% = 0
   IF mousx% > XDIM THEN mousx% = XDIM
   IF mousy% > YDIM THEN mousy% = YDIM
        
   IF pt% = 0 THEN x0 = (mousx% + 3) AND NOT 7: y0 = (mousy% + 3) AND NOT 7
   x1 = (mousx% + 3) AND NOT 7: y1 = (mousy% + 3) AND NOT 7
  
   IF (bstatus% AND 1) > (obstatus% AND 1) THEN pt% = 1
   IF (bstatus% AND 1) < (obstatus% AND 1) THEN
      DEF SEG = 0: IF (PEEK(&H417) AND 3) THEN upd% = 0 ELSE upd% = 1
      IF x0 <> x1 THEN CALL domost(x0, y0, x1, y1, upd%): pt% = 2 ELSE pt% = 0
   END IF
  
   CALL printsmall(8, 8, 15, LTRIM$(STR$((mousx% + 3) AND NOT 7)))
   CALL printsmall(24, 8, 15, LTRIM$(STR$((mousy% + 3) AND NOT 7)))
   IF pt% THEN
      IF x0 < x1 THEN
         LINE (x1, y1)-(x1, YDIM - 1), 15
      ELSEIF x0 > x1 THEN
         LINE (x1, y1)-(x1, 0), 15
      END IF
      LINE (x0, y0)-(x1, y1), 15
      CIRCLE (x1, y1), 1, 12, , , 1
   END IF
   IF x0 < x1 THEN
      LINE (x0, y0)-(x0, YDIM - 1), 15
   ELSEIF x0 > x1 THEN
      LINE (x0, y0)-(x0, 0), 15
   END IF
   CIRCLE (x0, y0), 1, 15, , , 1
  
   IF 0 THEN
      z% = vsp(0).n: c% = 1
      DO
         nz% = vsp(z%).n

         c% = c% + 1: LOCATE c%, 1
         PRINT "z"; z%;
         PRINT "x"; vsp(z%).x; ; "n"; vsp(z%).n; "p"; vsp(z%).p; "tag"; vsp(z%).tag;
         IF nz% THEN
            PRINT "cy0"; vsp(z%).cy0; "cy1"; vsp(z%).cy1; "ctag"; vsp(z%).ctag;
            PRINT "fy0"; vsp(z%).fy0; "fy1"; vsp(z%).fy1; "ftag"; vsp(z%).ftag
         END IF

         z% = nz%
      LOOP WHILE z%
   END IF

   
   SCREEN , , pag%, 1 - pag%: pag% = 1 - pag%
   WAIT &H3DA, &H8, &H8: WAIT &H3DA, &H8
   OUT &H3C8, 2
   IF pt% = 2 THEN
      OUT &H3C9, 32: OUT &H3C9, 0: OUT &H3C9, 0
   ELSE
      OUT &H3C9, 0: OUT &H3C9, 63: OUT &H3C9, 0
   END IF
  
   IF pt% = 2 THEN
      p = 2.2: dt = 1 / 16
      r0 = 42: g0 = 0: b0 = 0 '"apparent" average of colors 4&6
      r1 = 0: g1 = 63: b1 = 0: dt = 1 / 16
      FOR t = 0 TO 1 STEP dt
         OUT &H3C8, 2
         OUT &H3C9, ((r1 ^ p - r0 ^ p) * t + r0 ^ p) ^ (1 / p)
         OUT &H3C9, ((g1 ^ p - g0 ^ p) * t + g0 ^ p) ^ (1 / p)
         OUT &H3C9, ((b1 ^ p - b0 ^ p) * t + b0 ^ p) ^ (1 / p)
         WAIT &H3DA, &H8, &H8: WAIT &H3DA, &H8
      NEXT t
     
      DO
         z$ = INKEY$
         regs%(0) = 5: CALL int86old(&H33, regs%(), regs%())
         obstatus% = bstatus%: bstatus% = regs%(0)
      LOOP WHILE z$ = "" AND bstatus% = 0

      FOR z% = 15 TO 0 STEP -1
         OUT &H3C8, 2: OUT &H3C9, 0: OUT &H3C9, z% * 4: OUT &H3C9, 0
         WAIT &H3DA, &H8, &H8: WAIT &H3DA, &H8
      NEXT z%

      backcnt% = 2
      pt% = 0
   END IF
   
LOOP WHILE z$ <> CHR$(27)

   '3*5 font, chars:32-95.  HACK: ; looks like a , (Should be &H40480)
DATA 0,&H444040,&HAA0000,&HAFAFA0,&H6C46C0,&HA248A0,&H4A4CE0,&H240000
DATA &H488840,&H422240,&HA4A00,&H4E400,&H224,&HE000,&H40,&H224480
DATA &HEAAAE0,&H444440,&HE2E8E0,&HE2E2E0,&HAAE220,&HE8E2E0,&HE8EAE0,&HE22220
DATA &HEAEAE0,&HEAE220,&H40400,&H224,&H248420,&HE0E00,&H842480,&HC24040
DATA &HEAECE0,&H4AEAA0,&HCACAC0,&H688860,&HCAAAC0,&HE8C8E0,&HE8C880,&HE8AAE0
DATA &HAAEAA0,&HE444E0,&HE22A60,&HAACAA0,&H8888E0,&HAEEAA0,&HAEEEA0,&HEAAAE0
DATA &HEAE880,&HEAAE60,&HEACAA0,&HE8E2E0,&HE44440,&HAAAAE0,&HAAA440,&HAAEEA0
DATA &HAA4AA0,&HAAE440,&HE248E0,&HC888C0,&H844220,&H622260,&H4A0000,&HE0

SUB domost (bx0, by0, bx1, by1, upd%)
   DIM spx(4), spy(4), spt%(4), cy(2), cv(2)
   x0 = bx0: y0 = by0: x1 = bx1: y1 = by1
   IF bx0 < bx1 THEN
      dir% = 1
      y0 = y0 - .01: y1 = y1 - .01
   ELSE
      IF bx0 = bx1 THEN EXIT SUB
      SWAP x0, x1: SWAP y0, y1: dir% = 0
      y0 = y0 + .01: y1 = y1 + .01
   END IF
  
   i% = vsp(0).n: slop = (y1 - y0) / (x1 - x0)
   DO WHILE i%
      newi% = vsp(i%).n

      nx0 = vsp(i%).x: nx1 = vsp(newi%).x
      IF x0 >= nx1 OR nx0 >= x1 OR vsp(i%).ctag <= 0 THEN GOTO domostcont
      dx = nx1 - nx0
      cy(0) = vsp(i%).cy0: cv(0) = vsp(i%).cy1 - cy(0)
      cy(1) = vsp(i%).fy0: cv(1) = vsp(i%).fy1 - cy(1)

      scnt% = 0

         'Test if left edge requires split (x0,y0) (nx0,cy(0)),<dx,cv(0)>
      IF x0 > nx0 AND x0 < nx1 THEN
         t = (x0 - nx0) * cv(dir%) - (y0 - cy(dir%)) * dx
         IF ((dir% = 0) AND (t < 0)) OR ((dir% = 1) AND (t > 0)) THEN
            spx(scnt%) = x0: spy(scnt%) = y0
            spt%(scnt%) = -1: scnt% = scnt% + 1
         END IF
      END IF
     
         'Test for intersection on umost (j% == 0) and dmost (j% == 1)
      FOR j% = 0 TO 1
         d = (y0 - y1) * dx - (x0 - x1) * cv(j%)
         n = (y0 - cy(j%)) * dx - (x0 - nx0) * cv(j%)
         IF ABS(n) <= ABS(d) AND d * n >= 0 AND d <> 0 THEN
            t = n / d: nx = (x1 - x0) * t + x0
            IF nx > nx0 AND nx < nx1 THEN
               spx(scnt%) = nx: spy(scnt%) = (y1 - y0) * t + y0
               spt%(scnt%) = j%: scnt% = scnt% + 1
            END IF
         END IF
      NEXT j%

         'Nice hack to avoid full sort later :)
      IF scnt% >= 2 THEN
         IF spx(scnt% - 1) < spx(scnt% - 2) THEN
            SWAP spx(scnt% - 1), spx(scnt% - 2)
            SWAP spy(scnt% - 1), spy(scnt% - 2)
            SWAP spt%(scnt% - 1), spt%(scnt% - 2)
         END IF
      END IF
     
         'Test if right edge requires split
      IF x1 > nx0 AND x1 < nx1 THEN
         t = (x1 - nx0) * cv(dir%) - (y1 - cy(dir%)) * dx
         IF ((dir% = 0) AND (t < 0)) OR ((dir% = 1) AND (t > 0)) THEN
            spx(scnt%) = x1: spy(scnt%) = y1
            spt%(scnt%) = -1: scnt% = scnt% + 1
         END IF
      END IF
     
      vsp(i%).tag = -1: vsp(newi%).tag = -1
     
      IF upd% = 0 THEN oi% = i%: ocy1 = vsp(i%).cy1: ofy1 = vsp(i%).fy1
      FOR z% = 0 TO scnt%
         IF z% < scnt% THEN
            vcnt% = vsinsaft%(i%)
            CIRCLE (spx(z%), spy(z%)), 3, 15 - spt%(z%), , , 1
            t = (spx(z%) - nx0) / dx
            vsp(i%).cy1 = t * cv(0) + cy(0)
            vsp(i%).fy1 = t * cv(1) + cy(1)
            vsp(vcnt%).x = spx(z%)
            vsp(vcnt%).cy0 = vsp(i%).cy1
            vsp(vcnt%).fy0 = vsp(i%).fy1
            vsp(vcnt%).tag = spt%(z%)

            IF upd% = 0 THEN spt%(z%) = vcnt% 'save vcnt% for deletion
         END IF
           
         ni% = vsp(i%).n: dx0 = vsp(i%).x: dx1 = vsp(ni%).x
         IF ni% AND x0 <= dx0 AND x1 >= dx1 THEN
            ny0 = (dx0 - x0) * slop + y0
            ny1 = (dx1 - x0) * slop + y0
                          
               '      dx0            dx1
               '       ³              ³
               '-----------------------------
               '     t0%+=0         t1%+=0
               '  vsp(i%).cy0    vsp(i%).cy1
               '=============================
               '     t0%+=1         t1%+=3
               '=============================
               '  vsp(i%).fy0    vsp(i%).fy1
               '     t0%+=2         t1%+=6
               '
               '       ny0 ?         ny1 ?
                       
            t% = 1 + 3
            IF vsp(i%).tag = 0 OR ny0 <= vsp(i%).cy0 THEN t% = t% - 1
            IF vsp(i%).tag = 1 OR ny0 >= vsp(i%).fy0 THEN t% = t% + 1
            IF vsp(ni%).tag = 0 OR ny1 <= vsp(i%).cy1 THEN t% = t% - 3
            IF vsp(ni%).tag = 1 OR ny1 >= vsp(i%).fy1 THEN t% = t% + 3
           
            IF dir% = 0 THEN
               SELECT CASE t%
                  CASE 1, 2:
                     CALL drawtri(dx0, vsp(i%).cy0, dx1, vsp(i%).cy1, dx0, ny0, 2, 14)
                     IF upd% THEN vsp(i%).cy0 = ny0: vsp(i%).ctag = gtag%
                  CASE 3, 6:
                     CALL drawtri(dx0, vsp(i%).cy0, dx1, vsp(i%).cy1, dx1, ny1, 2, 14)
                     IF upd% THEN vsp(i%).cy1 = ny1: vsp(i%).ctag = gtag%
                  CASE 4, 5, 7:
                     CALL drawquad(dx0, vsp(i%).cy0, dx1, vsp(i%).cy1, dx1, ny1, dx0, ny0, 2, 14)
                     IF upd% THEN vsp(i%).cy0 = ny0: vsp(i%).cy1 = ny1: vsp(i%).ctag = gtag%
                  CASE 8:
                     CALL drawquad(dx0, vsp(i%).cy0, dx1, vsp(i%).cy1, dx1, vsp(i%).fy1, dx0, vsp(i%).fy0, 2, 14)
                     IF upd% THEN
                        vsp(i%).cy0 = YDIM \ 2: vsp(i%).cy1 = YDIM \ 2: vsp(i%).ctag = -1
                        vsp(i%).fy0 = YDIM \ 2: vsp(i%).fy1 = YDIM \ 2: vsp(i%).ftag = -1
                     END IF
               END SELECT
            ELSE
               SELECT CASE t%
                  CASE 7, 6:
                     CALL drawtri(dx0, ny0, dx1, vsp(i%).fy1, dx0, vsp(i%).fy0, 2, 14)
                     IF upd% THEN vsp(i%).fy0 = ny0: vsp(i%).ftag = gtag%
                  CASE 5, 2:
                     CALL drawtri(dx0, vsp(i%).fy0, dx1, ny1, dx1, vsp(i%).fy1, 2, 14)
                     IF upd% THEN vsp(i%).fy1 = ny1: vsp(i%).ftag = gtag%
                  CASE 4, 3, 1:
                     CALL drawquad(dx0, ny0, dx1, ny1, dx1, vsp(i%).fy1, dx0, vsp(i%).fy0, 2, 14)
                     IF upd% THEN vsp(i%).fy0 = ny0: vsp(i%).fy1 = ny1: vsp(i%).ftag = gtag%
                  CASE 0:
                     CALL drawquad(dx0, vsp(i%).cy0, dx1, vsp(i%).cy1, dx1, vsp(i%).fy1, dx0, vsp(i%).fy0, 2, 14)
                     IF upd% THEN
                        vsp(i%).cy0 = YDIM \ 2: vsp(i%).cy1 = YDIM \ 2: vsp(i%).ctag = -1
                        vsp(i%).fy0 = YDIM \ 2: vsp(i%).fy1 = YDIM \ 2: vsp(i%).ftag = -1
                     END IF
               END SELECT
            END IF
         END IF
         i% = vcnt%
      NEXT z%

      IF upd% = 0 THEN
         FOR z% = scnt% - 1 TO 0 STEP -1: CALL vsdel(spt%(z%)): NEXT z%
         vsp(oi%).cy1 = ocy1: vsp(oi%).fy1 = ofy1
      END IF
domostcont:
      i% = newi%
   LOOP

   gtag% = gtag% + 1
  
   IF upd% THEN
      i% = vsp(0).n
      DO WHILE i%
         ni% = vsp(i%).n
         IF vsp(i%).cy0 >= vsp(i%).fy0 AND vsp(i%).cy1 >= vsp(i%).fy1 THEN
            vsp(i%).ctag = -1: vsp(i%).ftag = -1
         END IF
         IF vsp(i%).ctag = vsp(ni%).ctag AND vsp(i%).ftag = vsp(ni%).ftag THEN
            vsp(i%).cy1 = vsp(ni%).cy1
            vsp(i%).fy1 = vsp(ni%).fy1
            CALL vsdel(ni%)
         ELSE
            i% = ni%
         END IF
      LOOP
   END IF

END SUB

SUB drawquad (x0, y0, x1, y1, x2, y2, x3, y3, col%, bcol%)
   DIM x(4 - 1), y(4 - 1)
   x(0) = x0: y(0) = y0
   x(1) = x1: y(1) = y1
   x(2) = x2: y(2) = y2
   x(3) = x3: y(3) = y3
   CALL fillconvpoly(x(), y(), 4, col%, bcol%) '2 triangles
   IF col% <> bcol% THEN
      IF ABS(y0 - y2) < ABS(y1 - y3) THEN
         LINE (x0, y0)-(x2, y2), bcol%, , &H6666
      ELSE
         LINE (x1, y1)-(x3, y3), bcol%, , &H6666
      END IF
   END IF
END SUB

SUB drawtri (x0, y0, x1, y1, x2, y2, col%, bcol%)
   DIM x(3 - 1), y(3 - 1)
   x(0) = x0: y(0) = y0
   x(1) = x1: y(1) = y1
   x(2) = x2: y(2) = y2
   CALL fillconvpoly(x(), y(), 3, col%, bcol%)
END SUB

SUB fillconvpoly (x(), y(), n%, col%, bcol%)
   mini% = ABS(y(0) >= y(1)): maxi% = 1 - mini%
   FOR z% = 2 TO n% - 1
      IF y(z%) < y(mini%) THEN mini% = z%
      IF y(z%) > y(maxi%) THEN maxi% = z%
   NEXT z%

   area = 0: zz% = n% - 1
   FOR z% = 0 TO n% - 1
      area = area + (x(zz%) - x(z%)) * (y(z%) + y(zz%)): zz% = z%
   NEXT z%
   IF area <= 0 THEN EXIT SUB
  
   i% = maxi%: y2% = INT(y(i%) - .5)
   DO
      j% = i% + 1: IF j% = n% THEN j% = 0
      y% = INT(y(j%) + .5)
      IF y% <= y2% THEN
         xi = (x(j%) - x(i%)) / (y(j%) - y(i%))
         x = (y2% - y(j%)) * xi + x(j%) + .5
         FOR y2% = y2% TO y% STEP -1
            lastx%(y2%) = INT(x): x = x - xi
         NEXT y2%
      END IF
      i% = j%
   LOOP WHILE i% <> mini%
   DO
      j% = i% + 1: IF j% = n% THEN j% = 0
      y2% = INT(y(j%) - .5)
      IF y2% >= y% THEN
         xi = (x(j%) - x(i%)) / (y(j%) - y(i%))
         x = (y% - y(i%)) * xi + x(i%) + .5
         ncol% = col%: IF (y% AND 1) THEN ncol% = ncol% XOR maskhack%
         FOR y% = y% TO y2%
            LINE (lastx%(y%), y%)-(INT(x), y%), ncol%: x = x + xi
            ncol% = ncol% XOR maskhack%
         NEXT y%
      END IF
      i% = j%
   LOOP WHILE i% <> maxi%

   IF col% <> bcol% THEN
      oz% = n% - 1
      FOR z% = 0 TO n% - 1
         LINE (x(oz%), y(oz%))-(x(z%), y(z%)), bcol%
         oz% = z%
      NEXT z%
   END IF

END SUB

SUB initmosts
      '0 is dummy solid node
   vsp(1).x = 0: vsp(1).cy0 = YDIM * .25: vsp(1).fy0 = YDIM * .75
   IF 1 THEN
      vsp(2).x = XDIM: vsp(2).cy0 = YDIM * .25: vsp(2).fy0 = YDIM * .75
      vsp(3).x = XDIM
      vcnt% = 3
   ELSE
      vsp(2).x = 160: vsp(2).cy0 = 48 + 50: vsp(2).fy0 = YDIM - 48 - 50
      vsp(3).x = 224: vsp(3).cy0 = 16 + 50: vsp(3).fy0 = YDIM - 16 - 50
      vsp(4).x = 384: vsp(4).cy0 = 96 + 50: vsp(4).fy0 = YDIM - 96 - 50
      vsp(5).x = XDIM: vsp(5).cy0 = 0: vsp(5).fy0 = YDIM
      vsp(6).x = XDIM
      vcnt% = 6
   END IF
   FOR z% = 0 TO vcnt% - 1
      vsp(z%).cy1 = vsp(z% + 1).cy0: vsp(z%).ctag = z%
      vsp(z%).fy1 = vsp(z% + 1).fy0: vsp(z%).ftag = z%
      vsp(z%).n = z% + 1: vsp(z%).p = z% - 1
   NEXT z%
   vsp(vcnt% - 1).n = 0: vsp(0).p = vcnt% - 1
   gtag% = vcnt%
  
      'VSPMAX-1 is dummy empty node
   FOR z% = vcnt% TO VSPMAX - 1
      vsp(z%).n = z% + 1: vsp(z%).p = z% - 1
   NEXT z%
   vsp(VSPMAX - 1).n = vcnt%: vsp(vcnt%).p = VSPMAX - 1
END SUB

DEFDBL A-Z
SUB printsmall (bx%, y%, c%, nam$)
   l% = LEN(nam$): IF l% = 0 THEN EXIT SUB
   x% = bx% - l% - l%: LINE (x% - 1, y% - 3)-STEP(l% * 4, 6), 0, BF
   FOR z% = 1 TO l%
      i& = smallfnt((ASC(MID$(nam$, z%, 1)) - 32) AND 63)
      FOR yy% = y% + 3 TO y% - 2 STEP -1
         IF (i& AND 8) THEN PSET (x% + 0, yy%), c%
         IF (i& AND 4) THEN PSET (x% + 1, yy%), c%
         IF (i& AND 2) THEN PSET (x% + 2, yy%), c%
         IF (i& AND 1) THEN PSET (x% + 3, yy%), c%
         i& = i& \ 16
      NEXT yy%
      x% = x% + 4
   NEXT z%
END SUB

DEFSNG A-Z
SUB vsdel (i%)
      'Delete i%
   pi% = vsp(i%).p
   ni% = vsp(i%).n
   vsp(ni%).p = pi%
   vsp(pi%).n = ni%

      'Add i% to empty list
   vsp(i%).n = vsp(VSPMAX - 1).n
   vsp(i%).p = VSPMAX - 1
   vsp(vsp(VSPMAX - 1).n).p = i%
   vsp(VSPMAX - 1).n = i%
END SUB

FUNCTION vsinsaft% (i%)
      'i% = next element from empty list
   r% = vsp(VSPMAX - 1).n
   vsp(vsp(r%).n).p = VSPMAX - 1
   vsp(VSPMAX - 1).n = vsp(r%).n

   vsp(r%) = vsp(i%) 'copy i% to r%

      'insert r% after i%
   vsp(r%).p = i%: vsp(r%).n = vsp(i%).n
   vsp(vsp(i%).n).p = r%: vsp(i%).n = r%

   vsinsaft% = r%
END FUNCTION

FUNCTION vsinsbef% (i%)
      'i% = next element from empty list
   r% = vsp(VSPMAX - 1).n
   vsp(vsp(r%).n).p = VSPMAX - 1
   vsp(VSPMAX - 1).n = vsp(r%).n

   vsp(r%) = vsp(i%) 'copy i% to r%

      'insert r% before i%
   vsp(r%).p = vsp(i%).p: vsp(r%).n = i%
   vsp(vsp(i%).p).n = r%: vsp(i%).p = r%

   vsinsbef% = r%
END FUNCTION

