'Demo showing use of 'arc' SUB and rand() FUNCTION in graphics applications
'Programmer: Andy Amaya
'Date: 5/18/03

'Released to Public Domain AS IS
'End user accepts ALL responsibility for using correctly

'FUNCTION rand() returns random number within range
'SUB arc - plots a user defined arc in graphics window

NOMAINWIN
DIM dx(360): DIM dy(360)    'arrays to hold COS() and SIN() results
                            'used in SUB 'arc' and plotting circular paths

degree = 3.14159 / 180      'constant FOR converting radians to degrees

FOR x = 0 TO 360            'calculate and store the COS and SIN results
    dx(x)=COS(x*degree)     'in their respective arrays
    dy(x)=SIN(x*degree)
NEXT x
'Initialize line drawing mode at start of pgm
mode = 1

RANDOMIZE TIME$("ms")/86400 'seed random timer FOR new set of random numbers

'NOTE: graphic demos will scale appropriately to windows with 4:3 aspect ratio
'(e.g. 480x360 640x480, 720x540, 800x600, 1024x768, 1440x1060, 1280x1024, 1600x1200)
WindowWidth = 800
WindowHeight = 600
UpperLeftX = INT((DisplayWidth-WindowWidth)/2)
UpperLeftY = INT((DisplayHeight-WindowHeight)/2)
GRAPHICBOX  #1.g, WindowWidth-WindowHeight,0, WindowHeight, WindowHeight

Button #1.btn1, "RGB Circle",[rgb1],UL, 1, 5, 120, 25
Button #1.btn2, "Fast RGB Circle",[rgb2],UL, 1, 45, 120, 25
Button #1.btn3, "Smiley-go-round",[goSmiley],UL, 1, 85, 120, 25
Button #1.btn4, "Flower",[flower],UL, 1, 125, 120, 25
Button #1.btn5, "Abstract Arcs",[abstract],UL, 1, 165, 120, 25
Button #1.btn6, "Toggle Draw Mode",[drawMode],UL, 1, WindowHeight-100, 120, 25
Button #1.btn7, "Exit",[quit],UL, 1, WindowHeight-60, 120, 25

OPEN "Arc SUB demo - by Andy Amaya" FOR WINDOW_NF AS #1
PRINT #1, "TRAPCLOSE [quit]"
PRINT #1, "FONT MS_SANS_SERIF 10"
PRINT #1.g, "DOWN; FILL blue; FLUSH"

LOADBMP "smile1","sprites\smiley2.bmp"
LOADBMP "smile2","sprites\smiley4.bmp"
LOADBMP "bak","sprites\bg1.bmp"
PRINT #1.g,"ADDSPRITE s1 smile1"
PRINT #1.g,"ADDSPRITE s2 smile2"

[loop]
WAIT

[quit]
UNLOADBMP ("smile1")
UNLOADBMP ("smile2")
UNLOADBMP ("bak")
PRINT #1.g,"CLS"
CLOSE #1
END

[drawMode]
'toggle mode between 1 and 0
mode = 1 - mode
GOTO [loop]

'demonstrate accurate arc drawing 
[rgb1]
GOSUB [newFillColor]
PRINT #1.g, "SIZE 6"
incSize=1
GOSUB [triColorCircle]
PRINT #1.g,"FLUSH"
GOTO [loop]

'demonstrate faster arc drawing, but with less accuracy
[rgb2]
GOSUB [newFillColor]
PRINT #1.g, "SIZE 6"
'This time 'arc' subroutine is 5x faster because there are 5x fewer lines to draw!
'Instead of drawing a circles, now drawing 72 sided convex regular polygons
'change incSize to number that divides evenly into 360 FOR different polygons
incSize= 5
GOSUB [triColorCircle]
PRINT #1.g,"FLUSH"
GOTO [loop]

'show how to move sprites in circles (or arcs)
[goSmiley]
GOSUB [newFillColor]
PRINT #1.g, "BACKGROUND bak; FLUSH"
PRINT #1.g,"SPRITEVISIBLE s1 ON"
PRINT #1.g,"SPRITEVISIBLE s2 ON"
centX = WindowHeight/2
centY = WindowHeight/2-15
r1 = WindowHeight/2-80
r2 = r1 - 35
clock = 0
counter = 360
'NOTE: when mode=0 in this routine, increment movement by three degrees, instead of 1 degree
IF mode = 0 THEN inc = 3 ELSE inc = 1
FOR i = 0 TO 1080 STEP inc       'make smiley's go 'round 3x
    IF clock > 360 THEN clock = inc
    IF counter < 0 THEN counter = 360 - inc
    sx1 = dx(clock) * r1 + centX
    sy1 = dy(clock) * r1 + centY
    sx2 = dx(counter) * r2 + centX
    sy2 = dy(counter) * r2 + centY
    PRINT #1.g,"SPRITEXY s1 ";sx1;" ";sy1
    PRINT #1.g,"SPRITEXY s2 ";sx2;" ";sy2
    PRINT #1.g,"DRAWSPRITES"
    clock = clock + inc
    counter = counter - inc
    'a delay to make sprite motion easier to discern
    FOR j = 0 TO 3000: NEXT j
    'NOTE: TIMER is too slow to use here. Comment FOR..NEXT loop on prior line
    'and uncomment lines below to see the difference (maybe take a coffee break)
    'TIMER 56, [dunWaiting]  'values below 56 exceed resolution of TIMER
    'WAIT
    '[dunWaiting]
    'TIMER 0
NEXT i
PRINT #1.g, "SPRITEVISIBLE s1 OFF"
PRINT #1.g, "SPRITEVISIBLE s2 OFF"
PRINT #1.g, "DRAWSPRITES"
GOTO [loop]

'show simple drawing capabilility using arcs
[flower]
GOSUB [newFillColor]
PRINT #1.g,"COLOR 224 80 80; SIZE 3"
centX = WindowHeight/2
centY = WindowHeight/2 - 15
r1 = centX
r2 = r1 * 2
r3 = r2 + WindowHeight * .083
r4 = WindowHeight * .078125
FOR i = 0 to 360 step 30
    tempX = dx(i)*r2+centX
    tempY = dy(i)*r2+centY
    ang1 = i - 180 - 23
    ang2 = i - 180 + 23
    IF ang1 < 0 THEN
         ang1 = ang1 + 360
         ang2 = ang2 + 360
    END IF
    CALL arc tempX,tempY,r3,ang1,ang2,1,mode
NEXT i
PRINT #1.g,"COLOR yellow"
FOR i = r4 TO 1 step -5
    CALL arc centX,centY,i,0,360,5,mode
NEXT i
PRINT #1.g,"FLUSH"
GOTO [loop]

'demonstrate how quickly many arcs can be drawn, without API calls
[abstract]
GOSUB [newFillColor]
winX = WindowHeight/2
winY = WindowHeight/2 - 15
FOR i = 1 TO 40
    tempS = rand(3,30)
    PRINT #1.g,"SIZE ";tempS
    r = rand(80,160): g = rand(80,160): b = rand(80,160)
    PRINT #1.g,"COLOR ";r;" ";g;" ";b
    tempX = rand(winX-winY/2, winX+winY/2)
    tempY = rand(winY-winY/2, winY+winY/2)
    rad = rand(winY * .1, winY * .9)
    toggle = 1 - toggle
    IF toggle = 1 THEN
        lwr = 180:upr = 540
    ELSE
        lwr = 0:upr = 360
    END IF
    ang1 = rand(lwr,upr)
    ang2 = rand(lwr,upr)
    WHILE ang2 = ang1
        ang2 = rand(lwr,upr)
    WEND
    CALL arc tempX, tempY, rad, ang1, ang2, 5, mode
NEXT i
GOTO [loop]

'**************************** FUNCTION rand() *******************************
'** Parameters are: lowerLimit, upperLimit                                 **
'** All parameters are positive integers, error occurs IF strings are used **
'** RETURN VALUE is the integer random number generated in defined range   **
'** Source: Can't remember it's been so many moons ago.                    **
'**      (TIP: be polite, don't ask how many moons. see entry below ;)     **
'****************************************************************************
FUNCTION rand(lowerLimit, upperLimit)
    'eliminate error checking to increase speed of function
    'just make sure that parameters are correct or program WILL error
    IF lowerLimit < 0 OR upperLimit < 0 OR lowerLimit > upperLimit THEN
        rand = 0
    ELSE
        x = INT(RND(0)*(upperLimit - lowerLimit + 1)) + lowerLimit
        rand = x
    END IF
END FUNCTION

'*********************************   SUB arc  *******************************
'** Parameters are:                                                        **
'** CenterX coord, CenterY coord, Radius, Angle1, Angle2, incSize, mode    **
'** incSize determines spacing between points, mode: 0 = dots, 1 = lines   **
'**                                                                        **
'** All parameters are numeric, compiler error occurs IF strings are used. **
'**                                                                        **
'** Includes logic to allow plotting from 180 to > 360 degrees. Avoiding   **
'** having to call routine twice to plot from 180 to 360 then calling again**
'** from 0 to 179. To cross 360/0 boundary, make call with 2nd angle       **
'** greater than 360 and less than or equal to 540.                        **
'** For Example: make call with angle1=180, angle2=539 (clockwise) or      **
'** angle1=539, angle2=180 (counter-clockwise).                            **
'**                                                                        **
'** Source: Developed this routine FOR use with TRS-80 mode1 I graphics    **
'****************************************************************************
SUB arc centerX,centerY,radius,angle1,angle2,incSize,mode
    'check angles: make sure they are within acceptable range
    IF angle1 < 0 OR angle1 > 540 OR angle2 < 0 OR angle2 > 540 THEN [badParm]
    
    'Determine 'STEP' direction and magnitude used in FOR..NEXT loop to plot
    IF angle1 < angle2 THEN inc = incSize ELSE inc = -1 * incSize
    
    'one degree of arc resolution, otherwise it's a single point
    IF angle1 <> angle2 THEN            'plot arc
    
        'use mode=0 to plot single dots, use mode=1 to connect dots with lines
        IF mode = 0 THEN
            FOR x = angle1 TO angle2 STEP inc
                IF x > 360 THEN rx = x - 360 ELSE rx = x
                arcX=dx(rx) * radius + centerX
                arcY=dy(rx) * radius + centerY
                'change to handle name of graphic window used in your program
                PRINT #1.g,"SET ";arcX;" ";arcY
            NEXT x
        ELSE    
            IF angle1 > 360 THEN rx = angle1 - 360 ELSE rx = angle1
            x1 = dx(rx) * radius + centerX
            y1 = dy(rx) * radius + centerY
            FOR x = angle1+inc TO angle2 STEP inc
                IF x > 360 THEN rx = x - 360 ELSE rx = x
                arcX = dx(rx) * radius + centerX
                arcY = dy(rx) * radius + centerY
                'change to handle name of graphic window used in your program
                PRINT #1.g,"LINE ";x1;" ";y1;" ";arcX;" ";arcY
                x1 = arcX
                y1 = arcY
            NEXT x
        END IF
    ELSE
        'angles are the same, so just plot a single point indicated by angle
        PRINT #1.g,"SET ";arcX;" ";arcY
    END IF
[badParm]
END SUB

'********************************* Subroutines ******************************

[triColorCircle]
'draw circles composed of 3 different colored arcs
winX = WindowHeight/2
winY = WindowHeight/2-15
radMax = WindowHeight/2-20
FOR rad = 10 TO radMax step 10
    PRINT #1.g,"COLOR red"
    CALL arc winX,winY, rad,0,120,incSize,mode
    PRINT #1.g,"COLOR green"
    CALL arc winX,winY,rad,120,240,incSize,mode
    PRINT #1.g,"COLOR blue"
    CALL arc winX,winY,rad,240,360,incSize,mode
NEXT rad
RETURN


[newFillColor]
'choose a random color FOR the background using rand() function
clr$=str$(rand(160,255))+" "+str$(rand(160,255))+" "+str$(rand(160,255))
'NOTE: defining clr$ this way makes easy to use any where else in program
PRINT #1.g,"CLS; FILL ";clr$
RETURN
