Scrolling viewports

I love scrolling, yes I love scrolling a lot, I think I try and do some form of scrolling in every project I do. One of my main reasons to get into retro coding was to work within tight restrictions to see what solutions I could come up with to implement “non standard” features in hardware that didn’t support them. That was a  real big push for the work I do on Pac-Man hardware.

(the video below shows a character scroller, sine wave scroller and full screen pixel scrolling together !)

With my first Vectrex programming attempts I am working on a homage to Stunt Cycle the classic ttl game from Atari (available on lot’s of 70’s TV consoles)

The Atari original features a monitor in landscape orientation, but the Vectrex features a portrait orientated monitor.

4499766a7b1120b64202d8a82256731f--atari-arcade-games

IMG_20180303_191607914

This in basic terms means the horizontal screen area on the Vectrex is only 75% of that available on a landscape monitor. After some initial rendering tests it become very clear that I needed more width. There are 2 solutions that come to mind:

1) Connect 2 Vectrexes together via the player 2 port and synchronise them to allow the 2 machines to render a double width screen.

This would be cool (very cool) and is an idea for a project for the future, once I’ve learned how to do this communication stuff (sync may be a big problem, wouldn’t know until I did some experiments – greater coders than me have probably been here a long time ago).

2) Scrolling the screen as the bike moves to reveal more content to the right (or left) of the visible viewport i.e the Vectrex screen.

To implement this we need to introduce the concept of world and view coordinates. Let’s take a look in simple terms (ignoring scaling) at how the Vectrex drawing system works:

The centre of the screen is referenced as 0,0 a pair of bytes are used to hold the x and y position of the beam.

IMG_20180407_071719 1

if both these bytes are cleared (set to zero) then the beam will be positioned at the centre. a positive value in the byte representing x will move the beam towards the right, a negative value will move the beam to the left. Using just a single byte to represent this position information allows us to represent the values -128 <= x < 127 for x. Signed integers are stored in 2’s Compliment format, a very special coding system that makes the sign bit part of the number (different to how we write numbers called sign and magnitude), which enables quick arithmetic with positive and negative values.

So for an object to be on screen we have a range of 256 positions (in this simplistic non-scaled view) to place an object horizontally and vertically. In Stunt Man stories I only need horizontal scrolling so the Y positioning uses just a single byte (well it doesn’t cause I built a general multi-way scrolling system – but hey).

Maker:L,Date:2017-9-15,Ver:5,Lens:Kan03,Act:Kan02,E:Y

We can think of the viewport as a byte wide. The world can be the same width, but there is nothing to stop us making it wider than the screen, by implementing a different co-ordinate system. One obvious choice is to use 2 bytes (16 bits) to store a horizontal position of an object in the world. Doing this gives us a potential world width of 65536 positions or 256 viewports wide.  Each high byte of the position represents the number of viewports across the object is in the world (as we move right 256 positions the high byte increases by one). We can then use another 16bit value to state the position of the viewports left hand side in relation to the world.

When we draw the screen we only draw objects that are in the current viewport window. The neat thing is how we do this.

Maker:L,Date:2017-9-15,Ver:5,Lens:Kan03,Act:Kan02,E:Y

To draw an object on screen we need to transform the world position into a viewport position. This sounds complicated but actually just means subtracted the viewport position from the world position of the object. What’s cool is we can inspect the high byte of the result and if it is not zero then the object is either to the left or right of the viewport (outside the viewport width of 256). If we cared we could look at the sign of the high byte -ve means to left (as in circle above) +ve means to the right (as in diamond above).

This allows us to disregard these objects for drawing. In the image above I have performed these calculations on four different objects, I showed their positions and the viewport positions in hex,, so you can quickly see the high byte result of the subtraction (the first 2 hex digits).

So this transformation allows us to find out which objects are within the current cireport and need to be drawn, but, we now need to translate their viewport position into Vectrex co-ordinates.

Maker:L,Date:2017-9-15,Ver:5,Lens:Kan03,Act:Kan02,E:Y

Let’s take the + and X  objects from the previous example. IN the image above I have stated their relative positions again (in hex). Looking at the X this needs to be in the centre of the screen as it is sitting in the centre of the viewport. It’s relative viewport position was calculated as $0080 (128). In Vectres co-ordinates these needs to be 0. So we need to subtract a value from this relative position to get 0. as it is a byte value (it’s in the lo-byte of the number) the maximum we can subtract is 127 (because of 2’s Compliment representation for a byte means this is the biggest +ve value 0111 1111 or $7f). So that is what we do, this gives is a value of 1 which is close enough to be in the centre. At the end of the day we will subtract 127 to transform all the viewport co-ordinates into Vectrex co-ordinates so it doesn’t matter that it is out by 1 unit.

We do the same for the + which is at viewport position $0040, when we subtract 127. Let’s do this now in binary, we only need the lo-byte portion of the viewport number:

We want to perform the following arithmetic:

$40 – $7f (64 – 127) the answer is – 63

subtraction is horrible in binary but we can perform the arithmetic by re-writting it like this:

64 + -127

This is better because addition is easy and negation is quick. We just need to perform 2’s compliment on 127 to find the -ve version. This is easy to see in binary:

127 is  0111 1111

(the left most bit is the sign bit which states this number is positive)

to perform 2’s compliment on this value we work from the the left hand side an invert each bit (1 becomes 0, 0 becomes 1) until we get to the last 1, leaving this as a 1.

-127 is 1000 0001

  64 is 0100 0000

we now just need to add these values together, using binary addition

Maker:L,Date:2017-9-15,Ver:5,Lens:Kan03,Act:Kan02,E:Y

The only slight problem with this arithmetic occurs when we have a relative position of 255. If we subtract 127 from this we arrive at 128, unfortunately this is the largest magnitude -ve number in 2’s compliment binary. this would cause an object at the very rightmost part of the viewport to be drawn at the most extreme left hand side (see the screen grid image above). The simple thing to do is to discard any objects that have viewport co-ordinate of 255.

Anyway here’s an example of the code that does all these transformations:

World coords -> Viewport coords -> Vectrex coords

position_and_draw_sprite: 
 ldd      spr_x,x         ; load up the integer portion of sprite position 
 subd     viewport_x      ; subtract view position to get screen coordinate 
 cmpa     #0 
 bne      pads_offscreen  ; > if a register is other than 0 then it's either <0 or > 255 
 cmpb     #255            ; attempt to stop drawing wrapping right to left 
 beq      pads_offscreen  ; 
 subb     #127            ; take 127 away so we can position based on vectrex centre 
 lda      spr_y_screen,x  ; get the y position information for sprite 
                          ; d register now holds the y,x position of sprite
Advertisements

Re-writing after fatal cock up

At the end of last week I had a fatal lapse of concentration during a coding session. I have these from time to time as I have trouble with short term memory when I’m working on a problem if I get distracted I can seriously lose the thread of my idea. Normally this is ok and I manage to get back onto my idea eventually (I sometimes have to re-discover an idea to do this). Unfortunately this happened while I was in the middle of a major bit of refactoring of my code base. I had the code broken and far away from being rebuilt, but when I came back to it I couldn’t remember what I was in the middle of doing. I tried to reconstruct some of the code but got myself into a bit of a pickle.

The code was terminally naffing up the stack and I spent quite a bit of time trying to work out what I had done, but I never picked the idea thread up again. On Sunday I decided that it was probably gonna be more productive to junk practically all of the code, about 4KB worth and take my core idea for refactoring forward from scratch.

I’ve spent some time the last 3 days and now have a much better working codebase and have myself in a much better position.

saving memory

One of the “joys” of assembly programming in restricted environments is trying to make sure that your stack and your variables and data structures do not collide. Despite the way we always teach the abstract stack mechanism (as a series of locations with the index increasing as we add more items)., stacks managed by the cpu grow downwards and are usually placed at the very top of user RAM.

As we add things to the stack the stack moves nearer to our data. At some point we may have a meeting of stack and our data, this most often is fatal as the stack contains return address from subroutine calls and ISR calls.

If we overwrite a return address on the stack with some game data the control unit will retrieve an incorrect return address when it executes an RTS instruction and happily continue execution from that point. This could be some random bit of code or even an area of data. The control unit on the cpu doesn’t know the context of memory (this is a Von Neumann machine where data and instructions occupy the same memory and are stored in the same format) so will decode whatever byte of data it retrieved from the address in the PC and execute it. Its best to make sure the stack doesn’t encroach on user data.

This is exactly the problem I had today, so I’ve been on the initial memory saving hunt without having to do another major refactor (although that may still have to happen as I add more stories for the stunt man).

We can reduce the depth of the stack by making more use of jumps and macros, but this is not always desirable if a subroutine is to be used many times in different contexts. One way around this and a technique I fall back on when I’m using the improved speed of the stack for pushing data around on Z80 hardware is to supply a return address in an index register and jump to the routine I want to execute which ends with an indexed jump back like this in 6809  jmp [,x].

see my Pac-Man pixel scrolling code for an example of what you can do on that hardware.

packing data

Another thing you can do to save memory is to pack multiple data items into a single byte.

When we work in high level languages, we usually use native word lengths (32 or 64 bit) for data items even if all we want is a boolean value. This is very wasteful and completely acceptable most of the time as we have quite a large amount of RAM to play with on modern machines. We don’t have that luxury on old school hardware, Pac-Man has about 900 useable bytes of RAM and the Vectrex has about 1K of usable RAM.

Techniques that are easy and perfomant on a PC are usually impossible to implement on old hardware, that’s part of the fun of coding on this sort of cool restricted hardware.

Anyway back to packing, I had part of my object data structure that looked like this:

base_vis        equ  0             ; 1 byte - 1 means draw, 0 means don't draw 
base_size       equ base_vis + 1   ; scale factor for sprite 
base_x          equ base_size + 1  ; 2 bytes $xxxx 
base_x_screen   equ base_x + 1     ; offset to screenwidth position information 
base_y          equ base_x + 2     ; 2 bytes $xxxx 
base_y_screen   equ base_y + 1     ; offset to screenheight position information 
base_image      equ base_y + 2     ; 2 bytes $xxxx addr of image data 
base_len        equ base_image + 2 ; base_image + 2 ; length of a base sprite

In this structure I was using a byte for visiblity and the following one for the scale of an object. The visiblity only really requires a single bit to state whether an object is visible or not, so I looked to see if I could combine this with the scale byte. If I choose to keep the scale to 127 or less that frees up the MSB or Sign bit of the byte to be used to hold visiblity. The knock on of this is, if I set the MSB I can use this to indicate that the object should not be drawn, it doesn’t matter that looking at the byte would add 128 to the scale as we are not going to draw the object anyway. If we clear the MSB then we can use this to indicate that the object can be drawn, the bonus is when this is zero it has no effect on the 7 bits representing the scale, it’s a win win.

Testing for not to draw the object can be performed easily with some code like this, which just test checks for the sign of the last operation:

 lda line_vis,x            ; get visibliity 
 bmi draw_skip_not_visible

Making an object visible or invisible can be performed by using an AND mask and an OR MASK as follows:

;========================================
; sets sprite at X to be not drawn
; sets msb
;========================================
NOT_VISIBLE_X macro 
              lda spr_vis,x 
              ora #$80 
              sta spr_vis,x 
              endm 
;========================================
; sets sprite at X to be drawn
; clears msb
;========================================
VISIBLE_X     macro 
              lda spr_vis,x 
              anda #$7f 
              sta spr_vis,x 
              endm

this saves a byte per object (in my current format), giving me a little breathing room and hopefully stopping the stack coming a knocking. Here’s the current format:

base_vis      equ 0              ; msb 0 means visible, 1 means invisible
base_size     equ base_vis + 0   ; scale factor for sprite 
base_x        equ base_size + 1  ; 2 bytes $xxxx 
base_x_screen equ base_x + 1     ; offset to screenwidth position information 
base_y        equ base_x + 2     ; 2 bytes $xxxx 
base_y_screen equ base_y + 1     ; offset to screenheight position information 
base_image    equ base_y + 2     ; 2 bytes $xxxx addr of image data 
base_len      equ base_image + 2 ; base_image + 2 ; length of a base sprite

I’ve left the base_vis and base_size equates pointing at the same offset as sometimes I’m looking at the byte as visibility and sometimes as scale, it makes my code more self documenting (readable).

More complex packing systems can be used, but performance is always a consideration, when accessing and manipulating the data. It all depends on what you are trying to do.

Test Overlay print

I decided to have  go at printing a test overlay, this is a multi step process and not a professional one.

1) print overlay design onto acetate sheet, using a colour inkjet and transparency sheet

2) Cut acetate sheet down, making sure that the overlay is smaller than an actual real overlay

3) Laminate the acetate sheet, this stiffens it up enough to stand up (could double laminate)

4) hand paint a white mask on the back (took a couple of coats of white primer)

first coat pretty thin everywhere

IMG_20180303_102036160_HDR

view from front

IMG_20180303_102027901_HDR

5 Tidy up mask edges with scalpel

Before tidying up it looked like this

IMG_20180303_152349531.jpg

back after tidy up (it’s not perfect but good enough for testing position of elements)

IMG_20180303_190048170.jpg

front after tidy up

IMG_20180303_160002503

Overlay on the Vectrex

IMG_20180303_191607914.jpg

Can now start tweaking lengths and positions.

The curious drawing bug

I’m in the middle of refactoring all the drawing and positioning code for Stunt Man Rip it up and start again. This is quite a big job and does involve destroying not only huge swathes of code as I build automated routines to process data, but also throwing away data sets to produce more unified data models.

It’s often difficult to test code when you have to write so much before you can get some visual effects running. I’m using my title screen to test the code as I’m developing it before moving onto reworking all the game logic for jumping the buses.

During some of this initial testing I came across a bug, discussed here in this video

What’s interesting about this (well to me), is it shows how sometimes visual bugs can be a help. It has highlighted to me a semantic problem with my code, which may have been ignored for a long time. Not all bugs are bad. I still need to learn more about Dissi in VIDE so that I can do some more useful debugging than just straight breakpoints.

I’ve made some good progress so far and do have some interesting functional mechanics in place. Just got to finish refactoring the data for the bike and then I can work on the bigger job of reworking the game logic and then to start adding animation for the wheels and wheeling based on the inertia of the bike.

After that I will then have to tidy up and get of any outstanding and unnecessary data and work out what space I’ve got left to implement the other game modes I want to implement.

Stunt Man stories

I’ve decided I need to change the name of my game as there are a few games called stunt man and I don’t want to step on toes. So I’ve come up with “Stunt Man Stories”. As the full game will be a collection of different events, the bus jumping is just where I got my initial inspiration.

Load Screen

I’m going to code some form of clapper board (if that is the correct term) to act as introduction/attempt information counter. Here’s a mock up of how that might look.

scene board.fw

Next job is to convert the rest of the bus jumping mechanic over to the new 16 bit placement engine code and then going to work on animation.

I’ll post a bigger update when I have something complete.

Scrolling viewport

I need to scroll the objects as the stunt rider jumps the buses in order to allow a reasonable number of buses to be jumped. the original Atari arcade machine had 28 buses. I did some test of what this would look like and now I’ve started building the first iteration of the framework that will enable a scrolling viewport.

The system is relatively simple and requires using a double word (16 bits) to represent the location of all sprites and objects. this gives a playfield of 65536 positions. An associated viewport position is also represented using the same 16 bit format. It’s actually quite trivial to check to see if an object is withing the current viewport region as the width of the viewport spans a byte (0-255 points).

It’s quite an interesting effect and allows a lot of possibilities. There is a cost associated with this work but it allows quite complex scenes to be developed with minimal hackery.

I now need to finished the manager that has been partly built to enable this little demo, this will then enable me to finish work on the logic and jumping mechanics.

Rip it up and start again

When of the interesting aspects of coding on a platform you are not familiar with. Is that you iterate quite a lot, trying ideas and managing to implement features. Some times you can almost get a complete working product only to think of or stumble across a different way of doing things. This can often involve throwing away practically everything from the previous iteration.

This is very common (I find) with low level work, I’m currently onto revision 4 of stuntman and have decided to implement scrolling for the buses. This will allow 28 buses to be jumped while in standard portrait orientation (I am going to implement a tate mode with it’s own horizontal overlay, but will need to adjust the y scale to get 28 buses in).

I hacked up the existing code to see what the bottom row of graphics would look like when scrolling and it looks pretty good.

I don’t like the hacky way I got this to work (it was just for visual checking), so I’ve decided to work out and implement a 16 bit view-port system, this will in the long run allow me “easily” to implement sprites moving in and out of the current view-port. This involves quite a major re-write of handling routines. So hopefully in a couple of weeks I should have a good working base to get the Jumping mode of stunt man finished.

I’m enjoying programming the Vectrex and I think I picked a nice project to learn the machine on. Just need to implement a better scoring mechanic other than number of buses jumped. I’m leaning towards some form of landing accuracy system.