Original Progress Thread
Moderator: benryves
- benryves
- Maxcoderz Staff
- Posts: 3089
- Joined: Thu 16 Dec, 2004 10:06 pm
- Location: Croydon, England
- Contact:
The easiest way to edit programs is directly on BASIC's command line, though people may wish to edit programs using an editor that's more similar to the TI-OS editor rather than by line.
As BBC BASIC programs are stored in a tokenised format, the files cannot be directly edited. However, if I implement *SPOOL and *EXEC, these could be used to convert BASIC programs to ASCII text and back again.
As BBC BASIC programs are stored in a tokenised format, the files cannot be directly edited. However, if I implement *SPOOL and *EXEC, these could be used to convert BASIC programs to ASCII text and back again.
Is this like the related feature on the old Apple ][, where you press ESC, then move the text cursor anywhere on the screen, hit ESC to exit that mode, then you hit the right arrow to type in characters under the cursor?benryves wrote:This screenshot shows a feature borrowed from the BBC Micro: copy key editing. By pressing a cursor key when entering a line of code, the cursor splits into two - a read cursor and a write cursor. The write cursor remains on the end of the line you were editing (a solid block), but the read cursor can be moved to any location on the screen. Pressing the COPY key (in this case, I've commandeered the XTθn key for this purpose) reads the character that is under the read cursor and copies it to the write cursor, then increments both.
You know your hexadecimal output routine is broken when it displays the character 'G'.
- benryves
- Maxcoderz Staff
- Posts: 3089
- Joined: Thu 16 Dec, 2004 10:06 pm
- Location: Croydon, England
- Contact:
Sounds like it.
EDIT: I'll try to make my post a bit more meaningful; I've started adding support for external devices via ".DEV" files. For example, here's a program that flashes the keyboard LEDs back and forth using AT.DEV to send and receive bytes using the AT protocol.
As there may or may not be data waiting for us from the device, incoming data is buffered and you can check how much stuff is in the buffer by using EXT# (which usually returns the size of the file). In this way, if EXT# returns a positive value, that means there's stuff in the buffer and you can safely call BGET# to retrieve it.
In the above code, PROC_flushin is used to ignore any input from the keyboard. It checks the length of the buffer and tries to read data from it until it's empty.
PROC_setled(l%) sets the keyboard LED state, which is done by sending the control byte &ED followed by the LED state value. After each value is sent to the keyboard, PROC_flushin is called to ignore any response the keyboard tries to send.
PROC_pause(t%) is just a little procedure to pause for a particular number of centiseconds, using the TIME pseudo-variable.
I'd include an animated GIF, but my AVI->GIF software isn't working. Oh well.
EDIT: I'll try to make my post a bit more meaningful; I've started adding support for external devices via ".DEV" files. For example, here's a program that flashes the keyboard LEDs back and forth using AT.DEV to send and receive bytes using the AT protocol.
Code: Select all
10 keyb%=OPENOUT"AT.DEV"
20 DATA 2,4,1,4,-1 : REM LED flash pattern (-1 terminated).
30 REPEAT
40 READ l%
50 REPEAT
60 PROC_setled(l%)
70 PROC_pause(30)
80 READ l%
90 UNTIL l%=-1
100 RESTORE
110 UNTIL FALSE
120 END
130 :
140 DEF PROC_flushin
150 REPEAT
160 IF EXT#keyb% d%=BGET#keyb%
170 UNTIL NOT EXT#keyb%
180 ENDPROC
190 :
200 DEF PROC_setled(l%)
210 BPUT#keyb%,&ED
220 PROC_flushin
230 BPUT#keyb%,l%
240 PROC_flushin
250 ENDPROC
260 :
270 DEF PROC_pause(t%)
280 start%=TIME
290 REPEAT UNTIL TIME >= start%+t%
300 ENDPROC
In the above code, PROC_flushin is used to ignore any input from the keyboard. It checks the length of the buffer and tries to read data from it until it's empty.
PROC_setled(l%) sets the keyboard LED state, which is done by sending the control byte &ED followed by the LED state value. After each value is sent to the keyboard, PROC_flushin is called to ignore any response the keyboard tries to send.
PROC_pause(t%) is just a little procedure to pause for a particular number of centiseconds, using the TIME pseudo-variable.
I'd include an animated GIF, but my AVI->GIF software isn't working. Oh well.
- benryves
- Maxcoderz Staff
- Posts: 3089
- Joined: Thu 16 Dec, 2004 10:06 pm
- Location: Croydon, England
- Contact:
Regarding the speed issue; no doubt somebody is going to write a 5-line TI-BASIC program that runs at three times the speed and textures the cube at the same time, but here's a very simple 3D demo.
On the left is the program running on an 83+ SE at 15MHz, on the right on the regular 83+ at 6MHz. If you really wanted to do 3D in BBC BASIC you could probably get away with writing some of the more expensive operations -- such as transforming/projecting vertices in batches -- in assembly, but that would sort of go against the whole point of trying to write a program to test the speed of BASIC.
Here's the rather naïve code:
On the left is the program running on an 83+ SE at 15MHz, on the right on the regular 83+ at 6MHz. If you really wanted to do 3D in BBC BASIC you could probably get away with writing some of the more expensive operations -- such as transforming/projecting vertices in batches -- in assembly, but that would sort of go against the whole point of trying to write a program to test the speed of BASIC.
Here's the rather naïve code:
Code: Select all
10 *REFRESH OFF
20 DIM p%(15)
30 fps%=0
40 lfps%=0
50 fpst%=TIME+100
60 REPEAT
70 rX=TIME/300
80 rY=TIME/400
90 SrX=SIN(rX)
100 CrX=COS(rX)
110 SrY=SIN(rY)
120 CrY=COS(rY)
130 pt%=0
140 FOR x=-1TO1STEP2
150 FOR y=-1TO1STEP2
160 FOR z=-1TO1STEP2
170 tX=y*CrX-x*SrX
180 tY=-x*CrX*SrY-y*SrX*SrY-z*CrY
190 tZ=3-x*CrX*CrY-y*SrX*CrY+z*SrY
200 p%(pt%)=tX*40/tZ+48
210 pt%=pt%+1
220 p%(pt%)=tY*40/tZ+32
230 pt%=pt%+1
240 NEXT
250 NEXT
260 NEXT
270 CLG
280 PRINTTAB(10,0)lfps%" FPS"
290 MOVE p%(0),p%(1)
300 DRAW p%(4),p%(5)
310 DRAW p%(12),p%(13)
320 DRAW p%(8),p%(9)
330 DRAW p%(0),p%(1)
340 DRAW p%(2),p%(3)
350 DRAW p%(6),p%(7)
360 DRAW p%(14),p%(15)
370 DRAW p%(10),p%(11)
380 DRAW p%(2),p%(3)
390 MOVE p%(4),p%(5)
400 DRAW p%(6),p%(7)
410 MOVE p%(12),p%(13)
420 DRAW p%(14),p%(15)
430 MOVE p%(8),p%(9)
440 DRAW p%(10),p%(11)
450 *REFRESH
460 fps%=fps%+1
470 IF TIME>fpst% THEN lfps%=fps%:fps%=0:fpst%=TIME+100
480 UNTIL INKEY(0)<>-1
490 *REFRESH ON
500 END
- benryves
- Maxcoderz Staff
- Posts: 3089
- Joined: Thu 16 Dec, 2004 10:06 pm
- Location: Croydon, England
- Contact:
qarnos has supplied some amazing code to the project. First up is a fast 16-bit line clipping routine.
What isn't shown is that this also uses a new line drawing routine that is a bit faster than the TI-OS ILine (2FPS->3FPS in the above demo on an 83+, no change on an SE) and also supports different colours more easily (black, white, inverse). I need to add support for dotted, dashed and broken lines too.
He's also written an awesome set of ellipse drawing and filling routines which are also nice and fast.
GCOL m,c is used to set the graphics colour. m sets the mode; 0 is to "plot" the colour directly, the other settings are used to perform logical operations (OR, AND, EOR -- none of which are fully implemented yet). c sets the colour; 0..127 sets the foreground and 128..255 the background colour. As all we have is a black and white LCD to play with, the colour is mapped to a dither pattern, with 0 being fully black and 127 being fully white.
The code for the screenshot on the left is as follows:
The code for the screenshot on the right is as follows:
For an explanation of PLOT as it relates to ellipses, see Draw solid ellipse - PLOT 200 to 207.
All of the above screenshots are running at 15MHz (SE).
What isn't shown is that this also uses a new line drawing routine that is a bit faster than the TI-OS ILine (2FPS->3FPS in the above demo on an 83+, no change on an SE) and also supports different colours more easily (black, white, inverse). I need to add support for dotted, dashed and broken lines too.
He's also written an awesome set of ellipse drawing and filling routines which are also nice and fast.
GCOL m,c is used to set the graphics colour. m sets the mode; 0 is to "plot" the colour directly, the other settings are used to perform logical operations (OR, AND, EOR -- none of which are fully implemented yet). c sets the colour; 0..127 sets the foreground and 128..255 the background colour. As all we have is a black and white LCD to play with, the colour is mapped to a dither pattern, with 0 being fully black and 127 being fully white.
The code for the screenshot on the left is as follows:
Code: Select all
10 CLG
20 REPEAT
30 GCOL 0,RND(127)
40 MOVE RND(48),RND(32)
50 MOVE RND(48),RND(32)
60 PLOT 205,RND(48),RND(32)
70 UNTIL INKEY(0)<>-1
Code: Select all
10 CLG
20 FOR i=120 TO 0 STEP -8
30 GCOL 0,i
40 MOVE 48,32
50 MOVE 48+i*0.4,32
60 PLOT 205,48,2
70 NEXT i
All of the above screenshots are running at 15MHz (SE).
- benryves
- Maxcoderz Staff
- Posts: 3089
- Joined: Thu 16 Dec, 2004 10:06 pm
- Location: Croydon, England
- Contact:
qarnos wrote:So I assume you are generating the dither patterns dynamically? 128 would seem like too much to store statically.
There are only 16 discrete dither patterns, so I'm just using the static image above (generated by Photoshop's pattern dithering tool).
This one bothers me too, but as far as I'm aware the current BASIC helper libraries also rely on memorising numeric codes for each command (through necessity, not design). However, I cannot modify the BBC BASIC language (and add new keyword). I can add new star commands (*ELLIPSE) as these are intended to be executed by the OS, but no numeric parsing is available for these.Dwedit wrote:A "PLOT 205" command sounds really obscure. Like the kind of thing you'd need a manual right in front of you to program with. Maybe add extra commands, like "ELIPSE"?
Fortunately, there is a pattern to the numbers used; the two least significant bits define the colour (0=none, 1=foreground, 2=inverse, 3=background), bit 2 specifies whether the passed coordinates are absolute (1) or relative to the last point (0) and the remaining five bits define the type of shape.
There's nothing to stop you from doing this, either:
Code: Select all
DEF PROC_ellipse(cx,cy,rx,ry)
MOVE cx,cy
PLOT 0,rx,0
PLOT 201,0,ry
ENDPROC
I've done some work on improving the console (it stores a bitmap of the area under the cursor so moving the cursor around no longer destroys graphics or inverted text - before it was just storing the character under each cell and repainting) and graphics code in general. I've added some code to emulate some of the useful features of the BBC Micro VDU, such as the ability to define the graphics viewport.
"VDU" sends data directly to the output device; an argument that is followed by a comma is sent as a byte and one that is followed by a semicolon is sent as a word. VDU 24,<left>;<top>;<right>;<bottom>; is used in the above example to define a graphics "window" with a 10 pixel border around it. (VDU 26 resets it). The background colour is set to 32 (25%) to make the effect of this statement more obvious.
Yes, that's more arcane number codes to memorise.
EDIT: Added a couple of new screenshots to demonstrate bitwise operations when plotting.
- benryves
- Maxcoderz Staff
- Posts: 3089
- Joined: Thu 16 Dec, 2004 10:06 pm
- Location: Croydon, England
- Contact:
After trying to avoid it I finally gave in and added support for text viewports to complement graphics viewports.
The following VDU commands are now supported:
You may be asking why some VDU commands are semicolon delimited whereas others are comma delimited. The semicolon makes BBC BASIC send the previous value as a 16-bit value rather than an 8-bit value (so VDU 24,0;0;47;63; sends 9 bytes to the VDU emulator -- 24,0,0,0,0,47,0,63,0). All graphics commands work in 16-bit coordinates, even though they don't really need to on the TI-83+.
The line at the bottom of the text viewport on the right hand side is the result of some previous graphics tests; as each character is 6 pixels high there's a 4 pixel gap at the bottom of the screen that text (currently) cannot be written to. VDU 5 will let you use the graphics cursor to position text, so pixel-perfect text is only a matter of time (ie, when I get around to adding sprite routines).
The following VDU commands are now supported:
- VDU 24,<left>;<top>;<right>;<bottom>;
Define a graphics viewport. - VDU 28,<left>,<top>,<right>,<bottom>
Define a text viewport. - VDU 26
Reset both viewports to their default settings (full screen). - VDU 29,<x>;<y>;
Defines the graphics origin.
Code: Select all
VDU 24,0;0;47;63;
VDU 28,12,0,23,9
VDU 29,24;32;
The line at the bottom of the text viewport on the right hand side is the result of some previous graphics tests; as each character is 6 pixels high there's a 4 pixel gap at the bottom of the screen that text (currently) cannot be written to. VDU 5 will let you use the graphics cursor to position text, so pixel-perfect text is only a matter of time (ie, when I get around to adding sprite routines).
- benryves
- Maxcoderz Staff
- Posts: 3089
- Joined: Thu 16 Dec, 2004 10:06 pm
- Location: Croydon, England
- Contact:
Well, I'm glad you can think of some uses for this feature (I wasn't too sure of what I'd personally use it for), but having a text viewport complements the graphics viewport nicely.
As characters are 6 pixels high, this means that the console only fills the top 60 rows. Maybe I should add a command that lets you specify which line is the top of the display, so the console can be shunted down a few pixel rows if need be.
I've been thinking about the sprite-drawing API, something like this might work well:
As characters are 6 pixels high, this means that the console only fills the top 60 rows. Maybe I should add a command that lets you specify which line is the top of the display, so the console can be shunted down a few pixel rows if need be.
I've been thinking about the sprite-drawing API, something like this might work well:
Code: Select all
DIM spr% 7 : REM Allocate 8 bytes (0..7) of RAM, pointed to by spr%
spr%?0=&3C : REM Set [spr% + 0] = &3C
spr%?1=&7E : REM Set [spr% + 1] = &7E
spr%?2=&FF : REM Set [spr% + 2] = &FF (and so on)
spr%?3=&FF
spr%?4=&FF
spr%?5=&FF
spr%?6=&7E
spr%?7=&3C
GCOL 3,127 : REM Set plot mode to EOR (3) and foreground colour to black (127)
PLOT 213,10,20,spr% : REM Draw sprite (PLOT code 213) at (10,20)
Do you text routines handle vertical clipping? If so, why not just allow the top line to scroll half-off screen? Sure, it's unnecessarily complicated and adds no real functionality... but it would look cool .benryves wrote:Well, I'm glad you can think of some uses for this feature (I wasn't too sure of what I'd personally use it for), but having a text viewport complements the graphics viewport nicely.
As characters are 6 pixels high, this means that the console only fills the top 60 rows. Maybe I should add a command that lets you specify which line is the top of the display, so the console can be shunted down a few pixel rows if need be.
Nice job with the text window, though. I'm sure someone will find it useful. It's one less thing for people to think "why can't I do this...".
"I don't know why a refrigerator is now involved, but put that aside for now". - Jim e on unitedti.org
avatar courtesy of driesguldolf.
avatar courtesy of driesguldolf.
- benryves
- Maxcoderz Staff
- Posts: 3089
- Joined: Thu 16 Dec, 2004 10:06 pm
- Location: Croydon, England
- Contact:
Aye, it does rather complicate issues. Nice idea, though, but I think I'll keep the console within a rigid grid (as far as it is handled automatically, an explicit command to change its offset from the top of the display might be useful). VDU 5 lets you use the graphics cursor to position text anywhere on screen; this rather nicely brings me onto the next thing I've added, sprites.qarnos wrote:Do you text routines handle vertical clipping? If so, why not just allow the top line to scroll half-off screen? Sure, it's unnecessarily complicated and adds no real functionality... but it would look cool .
Code: Select all
10 DIM ball 7
20 ball?0=&3C
30 ball?1=&5E
40 ball?2=&8F
50 ball?3=&DF
60 ball?4=&FF
70 ball?5=&FF
80 ball?6=&7E
90 ball?7=&3C
100 *REFRESH OFF
110 REPEAT
120 CLG
130 T=TIME/100
140 FOR P=0 TO 5
150 A=P/3*PI+T
160 X=16*SIN(A)+44
170 Y=16*COS(A)+28
180 PLOT 213,X,Y,ball
190 NEXT
200 *REFRESH
210 UNTIL INKEY(0)<>-1
220 *REFRESH ON
In reality, it would be more space efficient to store the sprite data in external files, maybe like this (assuming a file named SPRITES that contains the sprite data).
Code: Select all
10 ball%=FN_loadSprite("SPRITES",0)
20 face%=FN_loadSprite("SPRITES",1)
30 *REFRESH OFF
40 REPEAT
50 CLG
60 T=TIME/100
70 FOR P=0 TO 5
80 A=P/3*PI+T
90 X=16*SIN(A)+44
100 Y=16*COS(A)+28
110 PLOT 213,X,Y,ball%
120 NEXT
130 PLOT 213,44,28,face%
140 *REFRESH
150 UNTIL INKEY(0)<>-1
160 *REFRESH ON
170 END
180 DEF FN_loadSprite(f$,i%)
190 fh%=OPENIN(f$)
200 PTR#fh%=i%*8
210 DIM spr 7
220 FOR j%=0 TO 7
230 spr?j%=BGET#fh%
240 NEXT j%
250 CLOSE#fh%
260 =spr
270 ENDPROC
As iterating over an array (for, say, tilemapping) is quite slow in BBC BASIC (BBC BASIC seems faster than TI BASIC but it's no miracle-worker) I'll need to think about how this could be sped up. I'm hesitant to add more PLOT commands (as tilemapping is quite specific), so it may be through an OS command (*TILEMAP?), an entry point (CALL <address>,<args>) or left as an exercise to the reader (custom assembly routines mixed into the BASIC program).