Programming by Example

 

A BB4W Compendium

freeman69@gmx.com

IDIC BBC_Owl2 M&P

User-Defined Character Designer

'Characters' were the standard method of displaying text on the BBC Micro. Each character consisted of a pattern of dots (pixels) defined within an 8 x 8 grid. While appearing out-of-date next to modern fonts and bitmaps, this method of creating simple graphics still serves as a convenient tool.

 

  10 MODE 9:OFF

  20 DIM grid(7,7)

  30 DIM list(7)

  40

  50 ON CLOSE:PROCsave:QUIT

  60 ON MOUSE:PROCmouse:RETURN

  70

  80 PRINTTAB(10,2);"Character Design: "

  90 ORIGIN 384,256

 100 CIRCLEFILL 0,0,8

 110 FOR X=0 TO 8

 120   LINE X*64,0,X*64,512

 130 NEXT

 140 FOR Y=0 TO 8

 150   LINE 0,Y*64,512,Y*64

 160 NEXT

 170

 180 VDU 5

 190 FOR X=0 TO 7

 200   MOVE X*64-32,(X MOD 2)*-24

 210   T$=STR$(2^(7-X)):T$=STRING$(3-LEN(T$)," ")+T$

 220   PRINT;T$:REM The ^ symbol is above the 6 on a standard keyboard

 230 NEXT

 240 VDU 4

 250

 260 GCOL 3,7

 270 overgrid=FALSE

 280 REPEAT

 290   TIME=0

 300   MOUSE x,y,buttons

 310   IF overgrid PROCdrawcross

 320  

 330   IF x>0 AND x<512 AND y>0 AND y<512 THEN

 340     cx=(x DIV 64)*64

 350     cy=(y DIV 64)*64

 360     PROCdrawcross

 370     overgrid=TRUE

 380   ELSE

 390     overgrid=FALSE

 400   ENDIF

 410  

 420   WAIT 4-TIME

 430 UNTIL FALSE

 440 END

 450

 460 DEF PROCdrawcross

 470 LINE cx,cy,cx+64,cy+64

 480 LINE cx,cy+64,cx+64,cy

 490 ENDPROC

 500

 510 DEF PROCmouse

 520 IF overgrid THEN

 530   RECTANGLEFILL cx,cy,64

 540   grid(cx/64,cy/64)EOR=1

 550   PROCcalculate

 560 ENDIF

 570 ENDPROC

 580

 590 DEF PROCcalculate

 600 text$="VDU 23,224"

 610 FOR r=0 TO 7

 620   rowsum=0

 630   FOR c=0 TO 7

 640     rowsum+=grid(c,7-r)*2^(7-c)

 650   NEXT

 660   list(r)=rowsum

 670   PRINTTAB(30,8+r*2);STR$(rowsum);"  ";

 680   text$+=","+STR$(rowsum)

 690 NEXT

 700 VDU 23,224,list(0),list(1),list(2),list(3),list(4),list(5),list(6),list(7)

 710 PRINTTAB(28,2);CHR$(224)

 720 ENDPROC

 730

 740 DEF PROCsave

 750 PROCcalculate

 760 X=OPENOUT("VDU23.txt")

 770 PRINT#X,text$

 780 CLOSE#X

 790 ENDPROC

 

Run the program using the RUN option from the menu.

 

Use the mouse pointer and buttons to turn grid squares on and off.

 

Note how each square in each column has a specific related value, and by turning a square on or off we alter the sum of a particular row. These numbers represent the binary pattern of each row. On closing the program window, the complete definition is saved to a text file in the form of a BB4W command. This command can be copied and pasted into any program.

Character Designer: Code explained...

 

  10 MODE 9:OFF

 

BB4W includes a set of standard display modes, defining the window size. A Mode 9 window has dimensions of 1280 x 1024 graphical units.

Colons ':' allow us to enter more than one command per line.

The command OFF simply inhibits the appearance of the flashing text cursor.

 

  20 DIM grid(7,7)

  30 DIM list(7)

 

DIM is a command to dimension an array. An array can be thought of as a list or table. In line 30 we are literally defining an array named 'list' that contains 8 rows or elements. Each row has an address, like a house number and the numbering always starts at zero. Our list is defined as list(7), but contains 8 available spaces i.e. zero to seven, not one to seven.

Line 20 creates a 2-dimensional array named 'grid'. A 2 dimensional array is a  table, very similar to a spreadsheet. The elements (or cells) in 'grid' will hold either a one or a zero depending on whether a square in the 8 x 8 grid is filled or empty.

 

  50 ON CLOSE:PROCsave:QUIT

  60 ON MOUSE:PROCmouse:RETURN

 

We're going to return to lines 50 and 60 further down.

 

  80 PRINTTAB(10,2);"Character Design: "

 

This line is a combination of two commands: PRINT and TAB. The text within the quotes “” is printed 10 characters across and 2 down, from the top left corner of the window. Be aware that the term 'character' relates to the old fixed standard of 8 x 8 pixel characters, rather than to the variable width letters of modern fonts.

 

  90 ORIGIN 384,256

 

By default, the graphics origin of a BB4W window is located at the bottom left corner. For convenience, we're moving the origin to the right by 384 units and up by 256 units. This shift was calculated to place the grid in the centre of the window.

One consequence of a change to the graphics origin is a similar change the mouse pointer co-ordinates. However, this works to our advantage.

 

 100 CIRCLEFILL 0,0,8

 

Draws a 'solid', i.e. a filled circle, centred on location zero,zero of radius 8 units. This line was added simply to show the location of the shifted graphics origin. Note that all graphics are drawn in white until a graphics colour command is encountered.

 

 110 FOR X=0 TO 8

 120   LINE X*64,0,X*64,512

 130 NEXT

 

Our first encounter with a variable, as well as a 'FOR, NEXT' loop. Loops are used to repeat one or more instructions contained within the limits of the loop.

The 'variable' is called 'X'. A variable is simply a box, and in this instance the box is named 'X'. The 'FOR, NEXT' loop executes line 120 nine times in succession, with 'X' containing the values zero through 8, respectively.

The LINE command requires 2 pairs of co-ordinates: the start and end of a line. Our loop draws nine vertical lines, defining the 8 columns of the design grid.

 

 140 FOR Y=0 TO 8

 150   LINE 0,Y*64,512,Y*64

 160 NEXT

 

This loop draws nine horizontal lines, completing the grid pattern.

 

 180 VDU 5

 

VDU is a command inherited directly from the old BBC Micro. VDU 5 is a control code that instructs BB4W to PRINT all text at the graphics cursor. (Recall how the PRINTTAB command prints text to the nearest 'character', as measured from the top left of the window.) VDU 5 allows us to be more precise with the placement of text within the window. To turn this off use VDU 4.

 

 190 FOR X=0 TO 7

 

The beginning of another loop. This one will print numeric values beneath our grid.

 

 200   MOVE X*64-32,(X MOD 2)*-24

 

MOVE is a command to place the graphics cursor at a specific location in preparation for another instruction. The format of the instruction is MOVE (relative to the graphics origin to) x, y.

The 'x' value is calculated as 'X' multiplied by 64 and then subtract 32 units.

The 'y' value is calculated as a the remainder of 'X' after division by 2, multiplied by -24. Note that (X MOD 2) returns a value of either zero or one. This resulting pattern places the numeric values, to be displayed, on alternating lines:

 

   128   32   8   2

         64  16   4   1

 

 210   T$=STR$(2^(7-X)):T$=STRING$(3-LEN(T$)," ")+T$

 

T$ is a variable of a different kind, called a string. Strings can be extremely useful and they have their own set of related commands. A string is literally a string of characters up to 65535 characters long. Strings can be comprised of digits, letters and punctuation marks.

 

The STR$ command is one of those string-specific commands mentioned above. It converts a numeric value into a string format. In this instance the numeric value is calculated as:

2^(7-X)

The ^ symbol means 'to the power of'. We're using it to calculate the values shown above e.g. 128, 64, 32 etc. 128 is 2^7 which is simply 2*2*2*2*2*2*2. Note that (7-X) returns the values 7,6,5,4,3,2,1,0 as each loop is executed and 'X' contains the values 0,1,2,3,4,5,6,7 respectively.

The ^ symbol is found above the '6' on a standard keyboard.

 

STRING$ creates a repeating pattern of characters in a string format. In this instance we're using it to pad the string values of 128,64,32 etc with leading spaces. For example, the number 8 is one digit (or character) in length. The STRING$ command will add 2 spaces in front of it to make the string 3 characters in length. We're using this simply to align the numbers 128,64 etc beneath the grid columns. 128 is already 3 characters in length, so it won't have any spaces added.

 

LEN is a command that returns the length of a string.

 

 220   PRINT;T$

 230 NEXT

 240 VDU 4

 

Recall that the PRINT command will print at the graphics cursor due to the VDU 5 command.

NEXT marks the end of this loop.

VDU 4 places future text at the text cursor, rather than the graphics cursor.

 

 260 GCOL 3,7

 

GCOL controls the graphics colour and also affects the method of drawing.

The BASIC palette relatively simple with colours zero through 7 being: Black, red, green, yellow, blue, magenta, cyan and white.

Normally, we would use GCOL 0,7 to draw in white, on top of anything already appearing in the window.

GCOL 3,7 instructs BB4W to 'merge' what we're about to draw with the current contents of the window by using the exclusive-or function. Exclusive-or is a logical function that is best understood by using examples in binary, but for the moment consider it as a very convenient method to draw and 'un-draw' things.

The net result of using GCOL 3,7 is that the first time we draw anything on a black background, our drawing will appear as white. If we repeat the drawing process exactly then the exclusive-or function erases the part of the image we've just drawn. This graphical flip-flopping is a simple way to achieve basic animation.

 

 270 overgrid=FALSE

 

'overgrid' is a variable of yet another kind. In this instance we want it to be either TRUE or FALSE. This is known as a boolean variable. 'overgrid' will store the result of a test that determines if the mouse pointer is directly over our 8 x 8 grid.

 

 280 REPEAT

 

REPEAT, UNTIL is another form of loop (like FOR, NEXT). Where FOR, NEXT executes for a pre-determined number of loops, REPEAT, UNTIL exits the loop when certain, user-defined, conditions are met. In this instance the end of the loop is at line 430. The condition UNTIL FALSE will never be met i.e. this loop is designed to repeat indefinitely. This REPEAT statement represents the start of the main body of the program.

 

 290   TIME=0

 

TIME is a system variable that can be set to any value, but also read, because the system increments TIME (i.e. adds one) every 100th of a second. We're using TIME to determine how long a single cycle of the main loop takes to execute.

 

 300   MOUSE x,y,buttons

 

The MOUSE command returns the x and y position of the mouse pointer. And 'buttons' contains a value reflecting the status of the mouse buttons i.e. currently pressed or not. Any variable names can be used, not just x,y and 'buttons'.

 

 310   IF overgrid PROCdrawcross

 

The IF command usually appears in the format of: IF... THEN... ELSE...

Recall that 'overgrid' is either TRUE or FALSE. Because 'overgrid' is a boolean value we can use a shorthand version of the IF statement. The following executes in exactly the same way:

IF overgrid=TRUE THEN PROCdrawcross

 

PROCdrawcross is a 'procedure' defined from line 460 on.

The purpose of this statement is to 'un-draw' a large 'X' that indicates which grid square the mouse pointer is directly over. The first time this IF statement is encountered, 'overgrid' is FALSE, therefore PROCdrawcross will not be 'called'.

'Calling' a procedure, by using its name, instructs the program to temporarily jump to the start of the procedure and then to return when the execution of that procedure had finished.

 

 330   IF x>0 AND x<512 AND y>0 AND y<512 THEN

 340     cx=(x DIV 64)*64

 350     cy=(y DIV 64)*64

 360     PROCdrawcross

 370     overgrid=TRUE

 380   ELSE

 390     overgrid=FALSE

 400   ENDIF

 

Note how this 'IF' statement is spread across multiple lines (IF... ELSE... ENDIF). In this instance the statement was split to make the code easier to read. This format also allows IF statements to be 'nested' (demonstrated later). Always include 'THEN' when using this format.

 

This IF statement determines whether the mouse pointer is over the large 8 x 8 grid and stores the result of the test in 'overgrid' as either TRUE or FALSE. If the pointer is over the grid, then we call the PROCdrawcross routine to draw a large 'X' in the relevant square.

Lines 340 & 350 calculate the square over which the pointer is located. 'cx' and 'cy' will contain one of the values: 64, 128, 192, 256, 320, 384, 448, 512

The DIV command divides two values and drops any remainder, retaining the integer value only. e.g. 8 DIV 3 returns a value of 2, not 2.666.

 

 420   WAIT 4-TIME

 

We're at the end of our main cycle and at some point Windows will want to do other things, like pass control to other programs executing in its multi-tasking environment. The WAIT command is a Windows-friendly way of telling Windows that it can have some time to complete these other chores. Recall that TIME increments in 100ths of a second. As a rule of thumb, animations appear smooth at 25 frames per second. IF our program can do what it needs to in 4 one hundredth's of a second, or less, then we have time to spare. WAIT 4-TIME tells Windows how much time it can have, based on how quickly our program has executed the main loop.

 

 430 UNTIL FALSE

 440 END

 

As mentioned above, at line 280, this marks the end of our main loop. Although our program will never reach line 440, it's good practice to include an 'END' statement to mark the notional end of our program. Everything below this line will be the definition of a procedure or function called via the main loop.

 

So how does our program terminate?

 

Despite the fact that we're being Windows-friendly by using the WAIT command, control always returns to Windows at regular points during execution. This is because Windows needs to maintain control to test for the window being closed, amongst other things.

 

Hopefully, you can see how a program tends to follow a well-defined path of execution, cycling through loops and occasionally diverting into procedures.

Line 50 is one exception to this rule...

 

'ON CLOSE' is an instruction to BB4W to be vigilant for a specific 'event'. In this instance we want to know when the user closes the program window. BB4W does this in the background and out of our sight. When the user does close the window, BB4W diverts control to line 50 where we have a standing instruction for PROCsave to be called, before QUITting where QUITting terminates our program immediately.

 

'ON MOUSE' is another standing instruction to BB4W to be vigilant for the common event of a mouse button being pressed. Whenever a mouse button is pressed, BB4W executes our instruction to call PROCmouse, before RETURNing to the point in our program where it was before BB4W detected the mouse button event.

Event handling is a subject in its own right and even the basis for some languages. Don't worry if you find this process confusing. It is quite possible to write programs without using events of this nature.

 

 460 DEF PROCdrawcross

 470 LINE cx,cy,cx+64,cy+64

 480 LINE cx,cy+64,cx+64,cy

 490 ENDPROC

 

DEF is a statement indicating the beginning of definition of a PROCedure (or function).

ENDPROC is a statement indicating the end of a PROCedure definition.

 

Procedures can be thought of as little programs and are important for several reasons:

 

   1. It's tidier to call a procedure to execute a group of commands than to duplicate a similar group of instructions in multiple places.

   2. Analysing problems and tasks by breaking them down into separate procedures is a necessity when creating large programs.

   3. Procedures can call other procedures, and sometimes even themselves!

 

 510 DEF PROCmouse

 520 IF overgrid THEN

 530   RECTANGLEFILL cx,cy,64

 540   grid(cx/64,cy/64)EOR=1

 550   PROCcalculate

 560 ENDIF

 570 ENDPROC

 

This routine (called via a mouse button 'event') draws a white square on our grid, the location of which is derived from the location of the mouse pointer. Note that because of the GCOL 3,7 command at line 260, the first call draws a square and a subsequent call erases the square, another call again redraws the square, etc.

 

RECTANGLEFILL cx,cy,64 defines a filled square of dimensions 64 units per side, to be drawn at cx,cy (the co-ordinates of the bottom left corner of the square).

 

grid(cx/64,cy/64)EOR=1 is an instruction that enters a zero or 1 in the 'grid' array, reflecting whether a grid square is currently filled in white or not.

This instruction is shorthand for: grid(cx/64,cy/64) = grid(cx/64,cy/64) EOR 1

 

This type of shorthand is optional and can appear in various commands e.g:

a = a + 1, is the same as, a += 1

fred = fred * 10, is the same as, fred *= 10

 

EOR is the logical instruction for 'exclusive-or'. Similar to its effect upon graphics, we're using it to toggle between two values of zero and 1.

zero EOR 1, returns 1

1 EOR 1, returns zero

 

Alternatively, an equivalent IF statement could be used to the same effect:

IF grid(cx/64,cy/64)=0 THEN grid(cx/64,cy/64)=1 ELSE grid(cx/64,cy/64)=0

 

 590 DEF PROCcalculate

 600 text$="VDU 23,224"

 610 FOR r=0 TO 7

 620   rowsum=0

 630   FOR c=0 TO 7

 640     rowsum+=grid(c,7-r)*2^(7-c)

 

The purpose of this program is to enable the reader to design and use very simple graphics. BB4W characters are defined using the command VDU 23,c,r1,r2,r3,r4,r5,r6,r7,r8. Where c is a character code between 32 and 255. Values r1 to r8 relate to the sum of the numeric values of up to 8 pixels, in each of 8 rows.

 

Line 610 begins an outer loop for each of 8 rows.

Line 630 begins an inner loop for each of 8 columns (within each row).

rowsum+=grid(c,7-r)*2^(7-c) calculates the values: r1 to r8 (one per row), using the zero or 1 contained in the 'grid' array multiplied by 2^(7-c).

 

 650   NEXT

 660   list(r)=rowsum

 670   PRINTTAB(30,8+r*2);STR$(rowsum);"  ";

 680   text$+=","+STR$(rowsum)

 690 NEXT

 

The values r1 to r8 are stored, temporarily, in our 'list' array. These values are also PRINTed on the right hand side of our grid. We then append the values r1 to r8 onto a text$ variable that will be written to a '.txt' file in PROCsave below.

 

 700 VDU 23,224,list(0),list(1),list(2),list(3),list(4),list(5),list(6),list(7)

 710 PRINTTAB(28,2);CHR$(224)

 720 ENDPROC

 

The last action of this procedure is to create the character, as it appears after every mouse click, and to display it to the right of the text: 'Character Designer:'

CHR$ converts a value (usually 32 to 255) into the string format of its equivalent character.

 

 740 DEF PROCsave

 750 PROCcalculate

 760 X=OPENOUT("VDU23.txt")

 770 PRINT#X,text$

 780 CLOSE#X

 790 ENDPROC

 

And finally, when the user closes the program window, the PROCsave procedure calculates the numeric values of the design (in case no mouse buttons have been pressed) and writes 'text$' into the file called VDU23.txt. This file can then be opened using any text editor and its contents copied and pasted into other BB4W programs.

 

OPENOUT creates a new file if one doesn't already exist, otherwise it overwrites the contents of an existing file.

ChrDes Arrow black large