• Please review our updated Terms and Rules here

Plotting a circle the Hard way (in GWBASIC)

CP/M User

Veteran Member
Joined
May 2, 2003
Messages
2,986
Location
Back of Burke (Guday!), Australia
---- PCIRC.BAS ---
Code:
10 CLS:SCREEN 2:FOR A=1 TO 360
20 X=50*COS(A):Y=50*SIN(A)
30 PSET(50+X,50+Y)
40 NEXT A
---- End PCIRC.BAS ----
Some Notes:
Code:
Line 10: Clear Screen
         Set Video Mode (2 : 640x200 mono)
         Begin FOR loop
Line 20: Calculate X 
         (50 = size of Circle * COS of 1 to 360)
         Calculate Y 
         (50 = size of Circle * SIN of 1 to 360)
Line 30: Plot Point 
         - Added 50 to draw complete Circle on Screen for X
         - Added 50 to draw complete Circle on Screen for Y
Line 40: Go back & add one to FOR loop
 
Of course, you can make it even harder by writing your own implementations of sinus and cosinus. The BASIC Handbook by David A. Lien (now, is that a made-up name?) has such subroutines for the poor computers not equipped with trigonometric functions:

Code:
1000 REM SIN(X) subroutine: X in radians, result stored in Y
1001 REM C and Z used internally
1002 X=X*57.29578 : REM Skip this line if X is in degrees
1003 IF X=0 THEN 1016
1004 Z=ABS(X)/X : C=X : X=Z*X : IF X<360 THEN 1006
1005 X=X-INT(X/360)*360
1006 IF X<=90 THEN 1012
1007 X=X/90 : Y=INT(X) : X=(X-Y)*90
1008 ON Y GOTO 1009,1010,1011
1009 X=90-X : GOTO 1012
1010 X=-X : GOTO 1012
1011 X=X-90
1012 X=Z*X/57.29578
1013 IF ABS(X)<2.48616E-4 THEN 1016
1014 Y=X*X : Y=((((Y/72-1)*Y/42+1)*Y/20-1)*Y/6+1)*X
1015 GOTO 1017
1016 Y=X
1017 X=C/57.29578 : RETURN

How to use this routine to calculate cosinus is left as an exercise to the reader. :)
 
"Terry Yager" wrote:

> Kewl! Can you do it in MBASIC-80 under CP/M?
> (Now that's the hard way, no pset command.)

Actually, I'm not one for using MBASIC-80 once,
getting something like this into CP/M would req.
a machine with Graphical abilities. I could
probably do one for the Amstrad.

When I was referening to plotting a circle the hard
way, I was referning to using the standard
graphical commands for archieving this. Normally,
if you want circles & you are using GWBASIC,
then the circle command would be the common
way! :)

Cheers,
CP/M User.
 
"carlsson" wrote:

> Of course, you can make it even harder by
> writing your own implementations of sinus
> and cosinus. The BASIC Handbook by David
> A. Lien (now, is that a made-up name?) has
> such subroutines for the poor computers not
> equipped with trigonometric functions:

Code:
1000 REM SIN(X) subroutine: X in radians, result stored in Y
1001 REM C and Z used internally
1002 X=X*57.29578 : REM Skip this line if X is in degrees
1003 IF X=0 THEN 1016
1004 Z=ABS(X)/X : C=X : X=Z*X : IF X<360 THEN 1006
1005 X=X-INT(X/360)*360
1006 IF X<=90 THEN 1012
1007 X=X/90 : Y=INT(X) : X=(X-Y)*90
1008 ON Y GOTO 1009,1010,1011
1009 X=90-X : GOTO 1012
1010 X=-X : GOTO 1012
1011 X=X-90
1012 X=Z*X/57.29578
1013 IF ABS(X)<2.48616E-4 THEN 1016
1014 Y=X*X : Y=((((Y/72-1)*Y/42+1)*Y/20-1)*Y/6+1)*X
1015 GOTO 1017
1016 Y=X
1017 X=C/57.29578 : RETURN

> How to use this routine to calculate cosinus is left as
> an exercise to the reader. :)

Wow! That looks interesting. I had the problem of trying
to make my Turbo Pascal programs faster (even though
it had cosine & sine) by writing some faster cosine &
sine, but in actual fact, I made the program much faster
by writing a program which calculates the sine & cosine
& store them into a constant array (also since it was for
a graphical demo, I rounded the numbers to the nearest
decimal number - since the video display doesn't consist
of decimal numbers).

Cheers,
CP/M User.
 
Circles in MBASIC

Circles in MBASIC

"Terry Yager" wrote:

> Kewl! Can you do it in MBASIC-80 under CP/M?
> (Now that's the hard way, no pset command.)

Terry, I was wonderning which CP/M system you
were referning to with this?

The way I see it, to get something reasonibly
quick, it may have to be system specific, with
graphical abilities.

I don't know how you would make the code as
portable as possible, since I tend to look at
things by a system by system case.

Cheers,
CP/M User.
 
CP/M User said:
I had the problem of trying to make my Turbo Pascal programs faster (even though it had cosine & sine) by writing some faster cosine & sine
I would believe the built in routines are written in assembler, not compiled Pascal, so it might be hard to beat those.

but in actual fact, I made the program much faster by writing a program which calculates the sine & cosine & store them into a constant array
Yes, that is very common in the demo and game programming world, both because one does not have to write a routine to calculate the values and also because it is faster if the needed values already are there.

Speaking about circles, a number of years ago I heard a rumour about a person who had attended a course in drawing circles on free hand. I don't know if it was a bad joke or not, but the rumour claimed anyone who went through the course could draw perfectly round circles on the whiteboard without any tools. I'm sure it is possible to train, but who arranges a course only in drawing circles?
 
"carlsson" wrote:

>> I had the problem of trying to make my Turbo Pascal
>> programs faster (even though it had cosine & sine)
>> by writing some faster cosine & sine

> I would believe the built in routines are written in
> assembler, not compiled Pascal, so it might be hard
> to beat those.

In actual fact, I found that on a machine like my
Amstrad, the Interpreted BASICs Cosine & Sine were
quicker than the ones used in Turbo Pascal. I can
only guess (which maybe a reasonible guess) that
since the interpreted BASIC automatically translated
a decimal number into an Integer, it was doing this
quicker than TP (because I had the problem where I
needed to convert the number into an integer, since
TP wouldn't automatically do it for me! :)

>> but in actual fact, I made the program much faster
>> by writing a program which calculates the sine &
>> cosine & store them into a constant array

> Yes, that is very common in the demo and game
> programming world, both because one does not have
> to write a routine to calculate the values and also
> because it is faster if the needed values already are
> there.

Maybe less so nowadays, since computers are so quick
that it's not so noticable. I guess it's good for games
as they need to quick & just leave the more random
features to be worked out instead.

> Speaking about circles, a number of years ago I
> heard a rumour about a person who had attended a
> course in drawing circles on free hand. I don't know if
> it was a bad joke or not, but the rumour claimed
> anyone who went through the course could draw
> perfectly round circles on the whiteboard without any
> tools. I'm sure it is possible to train, but who arranges
> a course only in drawing circles?

I think it's hard enough drawing a perfectly round circle
on the computer, let alone doing one freehand. So, I'd
take that as a bad joke! :)

Cheers,
CP/M User.
 
This is an interesting thread. It gives me some ideas for one of my side projects.

On a PCjr there are video modes supported by the special 'Cartridge BASIC' but not supported by programming environments like Turbo Pascal or Turbo C. It was the only machine with those video modes, so none of the software houses bothered to support it. (The Tandy 1000 video modes are similar.) If you wanted to use these video modes, you need to write your own assembler.

I've started playing with machine language to do primitives, like putting up specific pixels and drawing lines. It's done using assembler and poking directly into the video buffer for speed. (The BIOS routines are slow because they are general purpose.)

It's a lot harder than it sounds. Although video memory is 32K and it is contiguous, it is not a linear mapping. i.e: The screen is interleaved in memory. On a machine with an 8088 floating point takes too long; integer arithmetic is preferred.

People should try their hand at drawing lines, circles, doing fill routines, etc. - it's not that easy. It makes you appreciate BASIC a little more. :)
 
Integer graphics

Integer graphics

I once took a (3D) graphics course, and the first lab was to produce a triangle filler to be used later. The basic version used floating point, but as a bonus exercise we had to do an integer version. I might locate my code somewhere and let you find ideas if you need. It is written in C though and only does lines/triangles.

Re: the PCjr and Tandy - I knew a Wang PC which apart from its IBM PC/CGA emulation mode had a few extended modes on its own, namely 320x200x16 and 640x200x4. Does those sound like the PCjr modes, or did it have even more variation? Obviously the BASIC in Wang mode took care of the more colours. It is one of the few personal (incl. UNIX workstations) computers I would like to have gotten.
 
"mbbrutman" wrote:

> This is an interesting thread. It gives me some ideas for
> one of my side projects.

Good! :)

> On a PCjr there are video modes supported by the
> special 'Cartridge BASIC' but not supported by
> programming environments like Turbo Pascal or Turbo
> C. It was the only machine with those video modes, so
> none of the software houses bothered to support it.
> (The Tandy 1000 video modes are similar.) If you
> wanted to use these video modes, you need to write
> your own assembler.

Which Video Mode are you referning to?

Cheers,
CP/M User.
 
Jrs have 3 non-standard modes:

320x200 in 16 colors. This requires 32K of video ram.
160x200 in 16 colors. This requires just 16K of video ram.
640x200 in 4 colors. This requires 32K of video ram.

And of course you have the standard CGA modes.

On standard CGA modes and the 160x200 mode, the screen memory is in two banks. On the modes requiring 32K, the screen memory is divided into four banks.

On a Jr things are compounded more by the goofy video circuitry. Normal CGA starts at B8000 in the memory map, and goes for 16K. The Jr's video memory is actually on the first 128K of the system board, and it lessens the amount available for DOS. To be compatible with CGA, memory references to the 16K starting at B8000 are magically remapped to the correct memory segment on the system board.

That works fine for the 16K modes. However to hit the upper part of a 32K mode video screen you actually have to hit the real memory location, not an offset from B8000. That's because the redirection circuitry only redirects 16K.

It's not a big problem, except that the Jr tries to hide the true location of video memory from you. Have have to try to find it in the first 128K. :)
 
"mbbrutman" wrote:

> Jrs have 3 non-standard modes:

> 320x200 in 16 colors. This requires 32K of video ram.
> 160x200 in 16 colors. This requires just 16K of video ram.
> 640x200 in 4 colors. This requires 32K of video ram.

> And of course you have the standard CGA modes.

I suspect that this would be an enhancement of the CGA
card, since CGA allowed up to 16k of memory I believe.

Though it doesn't have 160x200x16, only 160x100x16
which a couple of games made use of (it wasn't support
from the BIOS - so special routines were required to
access this).

> On standard CGA modes and the 160x200 mode, the
> screen memory is in two banks. On the modes
> requiring 32K, the screen memory is divided into four
> banks.

> On a Jr things are compounded more by the goofy
> video circuitry. Normal CGA starts at B8000 in the
> memory map, and goes for 16K. The Jr's video
> memory is actually on the first 128K of the system
> board, and it lessens the amount available for DOS.
> To be compatible with CGA, memory references to
> the 16K starting at B8000 are magically remapped
> to the correct memory segment on the system
> board.

> That works fine for the 16K modes. However to
> hit the upper part of a 32K mode video screen you
> actually have to hit the real memory location, not
> an offset from B8000. That's because the
> redirection circuitry only redirects 16K.

It's seems easy enough to redirect the first 16k,
since standard IBM programs (for CGA) would
look there. So it seems like an deliberate way of
telling the programmer that if you know where
the other 32k is, then use that, unfortuately it's
not friendly, if someone tried to use a Jnr program
which does that on their IBM! ;-)

Cheers,
CP/M User.
 
Oh yes - it's definitely non standard CGA. The Jr had these extra video modes, most (or all) of which are available on the Tandy 1000. The Tandy 1000 was a PCjr clone .. a bit more successful though.

As a cost cutting measure the Jr shared video memory with main memory, instead of having a separate 16K of video memory on a CGA card. The circuitry allows you to grow and shrink the amount of memory used by the video controller dynamically.

A true CGA 160x100 mode probably would have been done by programing that 6845 CRT controller directly. On the Jr 160x200x16 was a fully supported mode in BIOS and BASIC.

We generally don't worry about Jr specific programs running on other machines - I can count those programs on my fingers. Any machine that was Jr specific for sound or video checked the ID byte in BIOS on the machine first to see if the extra hardware was available. Same with the Tandy 1000 video modes and sound ..
 
"mbbrutman" wrote:

> As a cost cutting measure the Jr shared video memory
> with main memory, instead of having a separate 16K
> of video memory on a CGA card. The circuitry allows
> you to grow and shrink the amount of memory used
> by the video controller dynamically.

Do you know how far this can go, or is it like you said
between 16k & 32k.

Cheers,
CP/M User.
 
The whole 128K can be used. In reality, it's more like 96K. If you tried to use the whole 128K, you'd be stepping on the interrupt vector area, and that's a definite no-no .. You'd also have no place to run software to use the video buffer.

I've used 64K before - 2 screens of 32K. Generally the most that is used is 32K.

Tandy 1000 machines should be a lot more flexible - their video memory comes out of the high memory ranges, either right below 512K or right below 640K. (The Jr was only designed to have 128K, so conceptually the video memory is pulled from the top of memory too.) The Tandy 1000 probably can allocate gobs of memory because they don't have to worry about bumping into the interrupt vector. Can any Tandy 1000 owners confirm this?
 
"mbbrutman" wrote:

> The whole 128K can be used. In reality, it's more
> like 96K. If you tried to use the whole 128K,
> you'd be stepping on the interrupt vector area,
> and that's a definite no-no .. You'd also have no
> place to run software to use the video buffer.

> I've used 64K before - 2 screens of 32K.
> Generally the most that is used is 32K.

> Tandy 1000 machines should be a lot more
> flexible - their video memory comes out of the
> high memory ranges, either right below 512K
> or right below 640K. (The Jr was only designed
> to have 128K, so conceptually the video memory
> is pulled from the top of memory too.) The
> Tandy 1000 probably can allocate gobs of
> memory because they don't have to worry about
> bumping into the interrupt vector. Can any
> Tandy 1000 owners confirm this?

Oh okay. Theorically, if it's possible to add more
memory for the Jnr, or move the Interrupt Vector
elsewhere, then the 128k could be used, couldn't
it, or is the Interrupt Vector part of the screen
memory?

Cheers,
CP/M User.
 
Ah, the big difference between a Jr and a Tandy ....

The Jr was designed with a max of 128K of memory. All of that memory sits on the motherboard, or in a special expansion card that goes on dedicated slot on the motherboard. The circuitry that redirects memory address references from B8000 down to the first 128K of memory doesn't have the wiring to access more memory. The wiring is on a specific piece of the motherboard, and doesn't extend down the I/O bus. There are also a limited number of bits in the register that controls which 16K chunk of memory will be used.

Both the Jr and the Tandy 1000 'grow' the video memory downward from the top of installed memory. The difference is that the Tandy 1000 is designed with 512 or 640K in mind, so it pulls from the top of memory. (Probably just up to 128K like the Jr to stay compatible with the register setup on the Jr.) The Tandy probably puts all of it's memory on the motherboard, and the circuitry can probably access the top 128K of memory no matter how much is installed.

Jr memory expansion products came later, and they sit on the I/O bus.

Let's compare the two machines, both with a hypothetical 384. The Jr's video memory has to come from the bottom 128K because of the wiring limitations. DOS interrupt vectors will be in the lowest 16K. Then will come space for video memory. At the 128K mark DOS and apps will start, giving you 16K for interrupt areas, 96K for video memory, and 128K for DOS and apps.

On a Tandy1000 you have the same 16K at the bottom of memory for interrupts. But right after that, you can have DOS and apps, and then the video memory at the very top of memory.

The Tandy 1000 setup is better because you can make a bigger contiguous chunk of memory for DOS and apps. On the PCJr because of the goofy wiring, the first 128K is best left for the interrupt vector, video memory, and a ram disk. The first 128K of memory has to give access to the video controller on a regular basis, so if you use it for programs and code (as originally designed), the processor gets lower priority and it runs slower than a normal PC clone.

I love these hardware tradeoffs - that's what makes each old machine unique. Nobody has to sweat stuff like this anymore ...
 
Another GWBASIC sin&cos functions coding

Another GWBASIC sin&cos functions coding

Here another way.... :

Sin function
Code:
10 INPUT X#
20 GOSUB 1000
30 PRINT Y#
40 END
1000 REM SIN(X#). X# IN RADIANTS. OUTPUT IN Y#
1010 RESULT# = 0 : SIGN%=-1
1020 DOUBLEPI#=6.283185307#
1030 PRECISION = 50
1040 TEMP% = X#/DOUBLEPI#
1050 X#=X#-TEMP%*DOUBLEPI#
1060 FOR K=1 TO PRECISION
1070 ADDENDUM#=X#
1080 FOR SCANIT=2 TO 2*K+1
1090 PARTQUOT#=X#/SCANIT
1100 ADDENDUM#=ADDENDUM#*PARTQUOT#
1110 NEXT SCANIT
1120 RESULT#=RESULT#+(ADDENDUM#*SIGN%)
1130 SIGN%=SIGN%*-1
1140 NEXT K
1150 Y#=X#+RESULT#
1160 RETURN

and Cos function
Code:
10 INPUT X#
20 GOSUB 1000
30 PRINT Y#
40 END
1000 REM COS(X#). X# IN RADIANTS. OUTPUT IN Y#
1010 RESULT# = 0 : SIGN%=-1
1020 DOUBLEPI#=6.283185307#
1030 PRECISION = 50
1040 TEMP% = X#/DOUBLEPI#
1050 X#=X#-TEMP%*DOUBLEPI#
1060 FOR K=1 TO PRECISION
1070 ADDENDUM#=X#
1080 FOR SCANIT=2 TO 2*K
1090 PARTQUOT#=X#/SCANIT
1100 ADDENDUM#=ADDENDUM#*PARTQUOT#
1110 NEXT SCANIT
1120 RESULT#=RESULT#+(ADDENDUM#*SIGN%)
1130 SIGN%=SIGN%*-1
1140 NEXT K
1150 Y#=1+RESULT#
1160 RETURN
 
Back
Top