.........1.........2.........3.........4.........5.........6.........7.........8

LIGHT SCREEN DESIGNER
ZX Computing, June/July 1985
Part 06 of 13

Toni Baker continues our machine code mega-program

[There was no LSD article in the April/May 1985 issue, although there were]
[a couple of letters from readers pointing out mistakes; the corrections  ]
[for these have all been included in earlier parts.                   JimG]


This part of the program concentrates on some of the simpler geometry
functions. In particular, I intend to activate four more of the keys.
In order of complexity; TRIANGLE (key K), RECTANGLE (key J),
PARALLELOGRAM (key U), and CIRCLE_CENTRE (key H). In addition I intend
to modify the main loop and ESCAPE routine (key SPACE) so that a full
return to BASIC is possible in all circumstances and without error.

The MAIN LOOP for this gram was first listed in Light Screen Designer
Part 3. The addition of new code in part 4 (a copy screen subroutine)
meant that the main loop could be improved by altering part of the
code. However, the new code was in error and the correction for it
appeared in part 5. It stands to reason, therefore, that if I make
further alterations in part six then things will get very, very
confusing indeed, with the listing of a single routine spread over
four issues. I intend, therefore, to re-list the MAIN_LOOP and ESCAPE
routines in full and in one piece in this issue. NOTE THAT BOTH OF
THESE ROUTINES HAVE BEEN UPDATED, SO EVEN IF YOU HAVE THE MAIN LOOP
WORKING ALREADY YOU SHOULD REPLACE IT BY THAT GIVEN IN THIS ARTICLE.

The MAIN_LOOP has been altered for two reasons: (i) to get rid of the
six NOP instructions which are currently stuck in the middle; and (ii)
to make room for the new improved ESCAPE routine. The ESCAPE routine
has been extended by five bytes of code which guarantee a return to
BASIC following all of the procedures. The improvement is,
essentially, to ensure that the HL' register contains a value of 2758
on return to BASIC. It means that HL' now no longer needs to be
preserved by individual procedures and therefore represents a saving
of space. (All of the procedures in this article corrupt HL' as, I'm
sure, will many in the future. Also, it has been pointed out to me
that the DRAW_LINE routine corrupts HL', which is a bug I had overlooked.)

-----------------------------------------------------------------------------
;[In part 9 everything from #DDDD-#DE1A was moved down by 4 bytes,  ]
;[and the "LD IX,#DB40" at #DDD9 moved to the end, becoming the new ]
;[start point for MAIN_LOOP at #DE17. The "LD HL,MAIN_LOOP" at #DE52]
;[was changed accordingly.                                      JimG]

DE17 DD2140DB MAIN_LOOP LD   IX,#DB40      ;Initialise IX as required

DE1B CDB6DD   MAIN_LOOP CALL DRCURSORS     ;Draw all required cursors
DE1E CDB5DC             CALL GET_CHR       ;Wait for key press
DE21 CDB6DD   MAINLOOP2 CALL DRCURSORS     ;"Undraw" the cursors
DE24 2A14DB             LD   HL,(CURSOR)
DE27 ED4B16DB           LD   BC,(CURSOR+2)
DE2B D5                 PUSH DE            ;Stack the key scan
DE2C 7B                 LD   A,E           ;A= key code
DE2D FE03               CP   #03
DE2F 284D               JR   Z,CSR_DOWN    ;Jump if "cursor down" pressed
DE31 FE04               CP   #04
DE33 283A               JR   Z,CSR_LEFT    ;Jump if "cursor left" pressed
DE35 FE0B               CP   #0B
DE37 2840               JR   Z,CSR_UP      ;Jump if "cursor up" pressed
DE39 FE13               CP   #13
DE3B 2837               JR   Z,CSR_RIGHT   ;Jump if "cursor right" pressed
DE3D 21ADDE   ML_TEST   LD   HL,#DEAD      ;NULL_TABLE
DE40 011100             LD   BC,#0011
DE43 EDB1               CPIR               ;Is key pressed in null table?
DE45 280A               JR   Z,ML_ACTION   ;Jump if so
DE47 2141DB             LD   HL,JFLAGS hi
DE4A CB66               BIT  4,(HL)
DE4C CCC9DE             CALL Z,COPY_SCRN   ;Copy screen if allowed
DE4F CBAE               RES  5,(HL)
DE51 D1       ML_ACTION POP  DE            ;DE= keyboard scan
DE52 2117DE             LD   HL,MAIN_LOOP
DE55 E5                 PUSH HL            ;Force subroutine return address
                                           ;to be MAIN_LOOP
DE56 2142DB             LD   HL,CMD_ADDRS
DE59 14                 INC  D
DE5A 2803               JR   Z,ML_CASE     ;Jump unless "Shift" pressed
DE5C E1                 POP  HL            ;Drop MAIN_LOOP address
DE5D 1839               JR   RET_BASIC     ;Prepare to return to BASIC
DE5F 7B       ML_CASE   LD   A,E           ;A= key code
DE60 87                 ADD  A,A
DE61 85                 ADD  A,L
DE62 6F                 LD   L,A           ;HL points to subroutine address
DE63 4E                 LD   C,(HL)
DE64 23                 INC  HL
DE65 46                 LD   B,(HL)        ;BC= subroutine address
DE66 C5                 PUSH BC
DE67 2A14DB             LD   HL,(CURSOR)
DE6A ED4B16DB           LD   BC,(CURSOR+2)
DE6E C9                 RET                ;Jump to required subroutine
DE6F CD13DD   CSR_LEFT  CALL LEFT_PIX      ;Move cursor left
DE72 180D               JR   CSR_STORE
DE74 CD1FDD   CSR_RIGHT CALL RIGHT_PIX     ;Move cursor right
DE77 1808               JR   CSR_STORE
DE79 CD29DD   CSR_UP    CALL UP_PIX        ;Move cursor up
DE7C 1803               JR   CSR_STORE
DE7E CD36DD   CSR_DOWN  CALL DOWN_PIX      ;Move cursor down
DE81 3807     CSR_STORE JR   C,CSR_EXIT    ;Jump if cursor cannot move
DE83 2214DB             LD   (CURSOR),HL
DE86 ED4316DB           LD   (CURSOR+2),BC
DE8A D1       CSR_EXIT  POP  DE            ;DE= keyboard scan
DE8B 14                 INC  D
DE8C 288D               JR   Z,MAIN_LOOP   ;Loop back unless "Shift" pressed
DE8E CDB6DD             CALL DRCURSORS     ;Redraw the cursors
DE91 76                 HALT
DE92 76                 HALT               ;Wait for 1/25th of a second
DE93 CDC0DC             CALL GET_CHR_2     ;DE= keyboard scan
DE96 1889               JR   MAINLOOP2     ;Loop back
-----------------------------------------------------------------------------
DE98 CD9EDE   RET_BASIC CALL ESCAPE
DE9B C31BDE             JP   MAIN_LOOP
DE9E CDCCDC   ESCAPE    CALL MESSAGE
DEA1 12                 DEFB #12           ;Print message and await reply
DEA2 FE59               CP   "Y"
DEA4 C0                 RET  NZ            ;Return unless reply was "Y"
DEA5 D9                 EXX
DEA6 E1                 POP  HL            ;Drop return address to empty stack
DEA7 215827             LD   HL,#2758
DEAA D9                 EXX                ;HL'=2758 to ensure return to BASIC
DEAB C9                 RET                ;Return to BASIC
DEAC 00       ESC_BYTE  DEFB #00           ;Byte unused as yet
-----------------------------------------------------------------------------


Geometry Procedures

Four of the Designer's geometry procedures are given in this article.
The best way to illustrate their operation is by diagram - therefore I
have included four such diagrams [PART06.GIF]. Two of them - TRIANGLE
and PARALLELOGRAM - require the use of three cursors at once. The
third cursor is called the MARKER cursor, and may be activated by the
MARK key (key S) or deactivated by the CANCEL_MARK key (key D).
RECTANGLE draws a rectangle whose sides are always horizontal and
vertical - therefore it is only necessary to specify two opposite
corners. This is done with the ORIGIN cursor (the position of the last
point plotted, or the position set by MOVE (key A), and the CURSOR
itself. PARALLELOGRAM draws a four sided shape in which all opposite
sides are parallel. It works out for itself the position of the fourth
vertex.

While using LSD it is possible for the user to produce some errors.
Most of these are catered for by the program - for instance - if you
try to draw a triangle or a parallelogram whilst the marker cursor is
inactive, or if you try to draw a parallelogram whose fourth vertex
would need to be off the screen. In both of these cases no error
message will be supplied, however the shape will not be drawn. There
is, however, one error which LSD cannot cope with: that is if you try
to draw a circle which will not fit on the screen. If this error
should occur you can recover from it by the following procedure: type
the command CONTINUE to get back into Light Screen Designer (or
RANDOMIZE USR 56789 if originally operated as a direct command). Press
ESCAPE (SPACE) once to commence the program, and then press UNDO (key
zero).

In the next article I shall continue with, and hopefully complete, the
remaining geometry functions. With these available, Light Screen
Designer will begin to get some of the feel of its full potential.

The following changes must be made to the command addresses table:

DB44 8FE0               DEFW E0F8,CALC_CENT (CIRCLE_CENTRE)
DB54 3AE0               DEFW E03A,RECTANGLE
DB56 50E0               DEFW E050,PARALLGRM (PARALLELOGRAM)    [not 53E0]
DB64 2AE0               DEFW E02A,TRIANGLE
DB82 9EDE               DEFW DE9E,ESCAPE

-----------------------------------------------------------------------------
E01C CD41DD   DRAW_2_BC CALL PIX_ADDR      ;HL= pixel address
E01F C304DF             JP   DRAW_LINE     ;Jump to draw line
E022 E1       TEST_MRKR POP  HL            ;HL= address of next instruction
E023 3A13DB             LD   A,(MARKER+3)
E026 FEB0               CP   #B0
E028 D0                 RET  NC            ;Return if marker unused
E029 E9                 JP   (HL)          ;Otherwise continue from next
                                           ;instruction
E02A CD22E0   TRIANGLE  CALL TEST_MRKR     ;Return if marker not in use
E02D ED5B0EDB           LD   DE,(ORIGIN+2) ;DE= origin cursor coordinates
E031 C5                 PUSH BC            ;Stack main cursor coordinates
E032 D5                 PUSH DE
E033 C5                 PUSH BC
E034 ED4B12DB           LD   BC,(MARKER+2) ;BC= marker coordinates
E038 1845               JR   PAR_3         ;Jump to draw three lines

E03A C5       RECTANGLE PUSH BC            ;Stack main cursor coordinates
E03B ED5B0EDB           LD   DE,(ORIGIN+2) ;DE= origin coordinates
E03F D5                 PUSH DE
E040 C5                 PUSH BC
E041 42                 LD   B,D
E042 CD1CE0             CALL DRAW_2_BC     ;Draw first line
E045 C1                 POP  BC
E046 C5                 PUSH BC
E047 CD1CE0             CALL DRAW_2_BC     ;Draw second line
E04A C1                 POP  BC
E04B D1                 POP  DE
E04C D5                 PUSH DE
E04D 4B                 LD   C,E
E04E 1836               JR   PAR_2         ;Jump to draw remaining two lines
-----------------------------------------------------------------------------
E050 CD22E0   PARALLGRM CALL TEST_MRKR     ;Return if marker not in use
E053 ED5B12DB           LD   DE,(MARKER+2) ;DE= marker coordinates
E057 2A0EDB             LD   HL,(ORIGIN+2) ;HL= origin coordinates
E05A 79                 LD   A,C
E05B 93                 SUB  E
E05C 3804               JR   C,PAR_NEG1
E05E 85                 ADD  A,L           ;A= x coordinate of 4th vertex
E05F D8                 RET  C             ;Return if off screen
E060 1802               JR   PAR_X4
E062 85       PAR_NEG1  ADD  A,L           ;A= x coordinate of 4th vertex
E063 D0                 RET  NC            ;Return if off screen
E064 08       PAR_X4    EX   AF,AF'        ;Store in A'
E065 78                 LD   A,B
E066 92                 SUB  D
E067 3807               JR   C,PAR_NEG2
E069 84                 ADD  A,H           ;A= y coordinate of 4th vertex
E06A D8                 RET  C             ;Return if out of range
E06B FEB0               CP   #B0
E06D D0                 RET  NC            ;Return if off screen
E06E 1802               JR   PAR_Y4
E070 84       PAR_NEG2  ADD  A,H           ;A= y coordinate of 4th vertex
E071 D0                 RET  NC            ;Return if off screen
E072 C5       PAR_Y4    PUSH BC
E073 E5                 PUSH HL
E074 67                 LD   H,A
E075 08                 EX   AF,AF'
E076 6F                 LD   L,A           ;HL= coordinates of 4th vertex
E077 E5                 PUSH HL
E078 C5                 PUSH BC
E079 42                 LD   B,D
E07A 4B                 LD   C,E
E07B CD1CE0             CALL DRAW_2_BC     ;Draw first line
E07E C1                 POP  BC
E07F CD1CE0   PAR_3     CALL DRAW_2_BC     ;Draw next line
E082 CD38DF             CALL CANCEL_MK     ;Cancel marker cursor
E085 C1                 POP  BC
E086 CD1CE0   PAR_2     CALL DRAW_2_BC     ;Draw next line
E089 C1                 POP  BC
E08A CD1CE0             CALL DRAW_2_BC     ;Draw next line
E08D 183D               JR   CC_MOVE
-----------------------------------------------------------------------------
;[This was rewritten in Part 7. JimG]
E08F C5       CIRC_CENT PUSH BC            ;Stack cursor coords
E090 ED5B0EDB           LD   DE,(ORIGIN+2) ;DE= origin coords
E094 CDE6DE             CALL ADJUST_BD     ;Adjust to ROM convention
E097 C5                 PUSH BC
E098 D5                 PUSH DE
E099 21925C             LD   HL,MEMBOT
E09C 22655C             LD   (STKEND),HL   ;Point calculator stack into
                                           ;calculator memories
E09F 7A                 LD   A,D
E0A0 CD282D             CALL STACK_A       ;Stack origin-y on calc stack
E0A3 D1                 POP  DE
E0A4 7B                 LD   A,E
E0A5 CD282D             CALL STACK_A       ;Stack origin-x on calc stack
E0A8 C1                 POP  BC
E0A9 C5                 PUSH BC
E0AA 78                 LD   A,B
E0AB CD282D             CALL STACK_A       ;Stack cursor-y on calc stack
E0AE C1                 POP  BC
E0AF 79                 LD   A,C
E0B0 CD282D             CALL STACK_A       ;Stack cursor-x on calc stack
E0B3 2A635C             LD   HL,(STKBOT)
E0B6 22655C             LD   (STKEND),HL   ;Restore (empty) calc stack
E0B9 EF       CC_DRAW   RST  #28           ;Engage the calculator
E0BA E1                 recall M1          Ox
E0BB E0                 recall M0          Ox,Oy
E0BC 31                 duplicate          Ox,Oy,Oy
     E2                 recall M2          Ox,Oy,Oy,Cy
     03                 subtract           Ox,Oy,Oy-Cy
E0BF 31                 duplicate          Ox,Oy,Oy-Cy,Oy-Cy
     04                 multiply           Ox,Oy,(Oy-Cy)^2
     E1                 recall M1          Ox,Oy,(Oy-Cy)^2,Ox
E0C2 E3                 recall M3          Ox,Oy,(Oy-Cy)^2,Ox,Cx
E0C3 03                 subtract           Ox,Oy,(Oy-Cy)^2,Ox-Cx
E0C4 31                 duplicate          Ox,Oy,(Oy-Cy)^2,Ox-Cx,Ox-Cx
     04                 multiply           Ox,Oy,(Oy-Cy)^2,(Ox-Cx)^2
     0F                 add                Ox,Oy,(Oy-Cy)^2+(Ox-Cx)^2
E0C7 28                 sqr                Ox,Oy,radius
     38                 end calc

E0C9 CD2D23             CALL CIRCLE+13     ;Draw the circle
E0CC C1       CC_MOVE   POP  BC            ;BC= cursor coordinates
E0CD CD41DD             CALL PIX_ADDR      ;HL= cursor address
E0D0 C3F3DE             JP   MOVE          ;Move origin to cursor position
-----------------------------------------------------------------------------
