News:

Printed Amstrad Addict magazine announced, check it out here!

Main Menu
avatar_Xyphoe

The Living Daylights (Extra colours in Mode 1... Rasters? Screen splits?)

Started by Xyphoe, 06:38, 02 April 25

Previous topic - Next topic

0 Members and 2 Guests are viewing this topic.

Xyphoe

This will be for a video I'm making so I need to explain in simple terms for the average person to understand, but I'm curious anyway to learn how Graham Stafford and David Fish (coders of) "The Living Daylights" game pulled off getting more than the standard 4 colours of Mode 1 - in fact 8 colours ALSO along with parallax scrolling. Despite the gameplay not being that good, I think it's actually really very impressive! And deserves more recognition and praise.



CPC-Power website (https://www.cpc-power.com/index.php?page=detail&num=1307) says it's by the use of "rasters" that it's gone beyond the use of 4 colours, but reading the CPC Wiki page (https://www.cpcwiki.eu/index.php/Rasters) I can sort of understand a bit how it may be done in demos for nice coloured bars maybe... but I'm struggling to understand or see how that would apply to more complex scrolling background objects in a game such as this one.

If you look at a video of the game or attached screenshot - the main game window looks like it's "split" but it has 3 different layers scrolling, eg the top mountains which include enemy sprites popping up and down shooting, the middle area with Bond running, and the smaller bottom area with green bushes moving past quickly - giving a very nice parallax effect overall.

Are these 'screen splits'? You've then got the HUD below with the score, lives, energy, etc so that would mean even more splits.

How is this all done to give more colours in Mode 1 and why didn't more coders do this in their games? :)

In simple terms so non-coders can understand! Thanks in advance!


andycadley

Yeah, they're "rasters", i.e. carefully timed changes of the colour palette so that different sections of the screen appear to be different colours. It's not a particularly advanced technique, but there are some limitations:
  • There are only a few fixed positions you can wait for (except on a Plus) so you have to either carefully design the changes around those points or wait for one and then burn a lot of CPU cycles to get the change to happen where you want.
  • Because the rasters scans left to right, top to bottom, you can really only achieve horizontal bands of colours so you have to design things around that. This tends to restrict how things can move on the screen to avoid them crossing the boundaries which would cause them to change colour. The very limited movement in Living Daylights (probably because it was designed to be a light gun game on other platforms) makes this easier.

It's possible that it's also doing "screen splits" aka "ruptures". That's about changing the screen address for certain (again horizontal) portions of the screen. That lets you do things like hardware scroll different sections while keeping some bits static. It's quite an advanced technique though and was often shied away from by commercial teams for fear it might cause issues on some displays (since it's basically abusing the CRTC timing)

Anthony Flack

You can change the colours at any time by simply setting a new colour value. The effect is immediate. If you're midway through the frame, the colour will change midway through the frame. If you keep doing this every frame at the same time, you have a colour split.

The trick is with the timing. The CPC won't actually tell you what scanline is currently being drawn. However, it does have an interrupt that goes off every 300th of a second - 6 times per frame, or every 52 scanlines - which you can sync to. It's fairly easy to write some code that changes the colours at any one of these interrupt points, giving you up to six colour splits. You can leave this code running on the interrupt and once it's initialised you can pretty much ignore it. That's the easiest way. A lot of games do this to put a split between the play area and the score panel.

You can change colours at other times besides the interrupt points, if you have some code that always takes exactly the same amount of time each frame so that you know exactly where you are. Because again, the CPC annoyingly won't tell you. If you don't keep the timing the same every frame, the location of your split will jitter around.

The scrolling here is probably an ordinary software scroll, so no complicated rupture effect is needed.

The colour does look particularly nice in The Living Daylights. IIRC the title screen also uses some line-by-line colour changes.

Axelay

From the colour point of view, it might help to look at the video memory for understanding.  It is all in normal mode 1's 4 colours, so you can see from the video memory that it's just the 4 colours being changed at points in the screen.

I've also added a screen of the display with Winape having interupts highlighted in blue.  You can see from those the 6 interrupts per frame haven't fallen exactly where they want the colour changes, so they have extended them (paused or other code) to be able to make the colour changes where they want.  The 1st colour set will most likely be on the first interrupt, which is above the frame.  I've added the numbers 2-4 where during those interrupts they will have changed the colours.

Also from the video memory image, you can see a large gap between the player sprite and the bushes below, along with the level name text that is no longer visible on the screen, so it does appear they are using screen splits.  Though I had assumed they were because the game has had trouble with some emulators in the past, I think the split hasn't got the timing quite right.  Scratch that, I just checked it in AceDL, and it is showing the screen is 304 lines high instead of the 312 it should be.

Update:  I scrolled along and you can see the images in video memory have now offset from the base in the extra image I just added.  It appears to be using that large amount of space that was initially there to allow it to scroll a number of screens without worrying about screen address reset (guessing, not checking code).  I think it is probably doing something different with the bushes part at the bottom.  But it does appear each scrolled section is in hardware.

Anthony Flack

And there's a smaller gap between the bushes and the score panel in the memory map... so I am guessing that they are using a hardware scroll just on that foreground layer of bushes.

Oop, I see in your updated picture it is indeed all layers.

Xyphoe

Quote from: Anthony Flack on 09:11, 02 April 25You can change colours at other times besides the interrupt points, if you have some code that always takes exactly the same amount of time each frame so that you know exactly where you are. Because again, the CPC annoyingly won't tell you. If you don't keep the timing the same every frame, the location of your split will jitter around.

The scrolling here is probably an ordinary software scroll, so no complicated rupture effect is needed.

Interestingly there is some 'jitter' between the top background layer, and the middle 'Bond' layer... (if you look closely)

Xyphoe

Quote from: Axelay on 09:14, 02 April 25From the colour point of view, it might help to look at the video memory for understanding.  It is all in normal mode 1's 4 colours, so you can see from the video memory that it's just the 4 colours being changed at points in the screen.

I've also added a screen of the display with Winape having interupts highlighted in blue.  You can see from those the 6 interrupts per frame haven't fallen exactly where they want the colour changes, so they have extended them (paused or other code) to be able to make the colour changes where they want.  The 1st colour set will most likely be on the first interrupt, which is above the frame.  I've added the numbers 2-4 where during those interrupts they will have changed the colours.

Thanks Axelay! So for my understanding, the top game screen area between interrupt 1 and 2 ("interrupt" is the same as "screen split" or "rupture" as Andy described above right?) is doing the following -> 

(1) Initially in purple, white and orange (ignoring black here) like the rest of the main screen (in Mode 1)
(2) They have carefully timed 'raster' code that scans down and...
(3) Where it finds 'white' flips it to 'yellow' (for the mountain)
(4) Where it finds 'orange' flips it to 'grey/green' 
etc

Am I on the right track here?

Anthony Flack

So it IS using ruptures, which is more complicated than just changing colours.

This is how you trick the CRTC into hardware scrolling only part of the screen (which it believes it can't do):

Basically, instead of setting the CRTC registers to output a regular PAL video frame at 50hz and leaving it alone to do its job (as you normally would), you disable vsync, then tell it to output a much smaller screen fragment. Then when it gets to the end of that you send it updated values to draw a second one, or a third, and so on, and providing you get all the timing right the whole thing will add up to something that resembles the timing for a complete PAL frame at the end. Then you trigger vsync and hope your monitor doesn't notice any difference.

This involves a bit of doing things manually that the CRTC would ordinarily handle automatically for you, like maintaining vsync.

Anthony Flack

Pardon my interjection, but interrupts are not the same thing as screen splits... however the interrupt is useful for timing.

Interrupt is just a trigger that goes off every 300th of a second but it's the fastest clock you can sync to on the CPC, and you can also tell the Z80 to stop whatever it's doing and run a particular bit of code - automatically - every time the interrupt goes off. So it's handy to put your screen split code on the interrupt. It will run independently of your main game code and maintain the correct timing.

...more or less; there are some complicating factors but that's the general idea.

Interrupt

I think the best way to think of rasters is that they are changes to the *palette* that can occur anywhere as the electron beam scans across the screen. You can change the background colour or any of the inks (just as the border and ink commands do in BASIC for the whole screen). It takes a little time to select which you want to update and a little time to change the colour so that limits the number of changes you can make to about one every inch or two. If you make no further changes the palette remains until the beginning of the next frame when you must provide them all over again (unlike in BASIC where the firmware handles this for you).

Interrupts are a way to temporarily suspend your code at a regular point to allow you to change the palette. Without them you must carefully time your code to a precise number of clock cycles to hit the exact point in time that the electron beam that you need. It is hard to write code that way so those effects are mostly done in demos. 

I keep imagining that I will make some explainer videos on this stuff as part of my demo channel but having started trying to make one on displaying graphics I'm not enjoying the process of making explainer so far and it's a bit of a drag :-(

Xyphoe

Thank you Anthony and Interrupt! (Quite an apt name for this topic! :D )

So "The Living Daylights" is basically using a mixture of rasters, interrupts and rupture/screen splits then! All 3?

I'm hoping someone could give a simple breakdown/overview of what's happening there and what Graham/David have done.

So far from my understanding it seems like -> 
(1) They've started by using several rupture/screen splits (4? 3 in the main game area and 1 for the HUD at the bottom), then...
(2) They can use that for the hardware scroll for the 3 areas in the game window using the CRTC chip. I believe you use the registers in the CRTC chip - R3 isn't it for horizontal sync? And R12 and R13 to define the start address (checking old notes)
(3) They've then used 'interrupts' to help with timing roughly around the areas of the ruptures/screen splits to do the rasters/colour changes...
(4) And as Interrupt described above, using rasters they done palette colour changes on each rupture/screen split area to give up to 8 colours in game

Am I roughly right there / on the right lines?


Axelay

I would say it starts with interrupts, as these are what are being used to implement the multiple screens (ruptures, and it does look like 4 screens) and the colour changes.

They wont be using R3 for the scrolling though, only R12/13.  R3 is for scrolling in half character steps, but I am not aware of a way you can use different R3 settings on directly adjacent screens.  Also, looking closely at the slowest scrolling section at the top of screen, it appears to be scrolling in character steps which only needs R12/13, so it looks like it would be scrolling slower by moving half as often rather than half the step as the section below. 

arnoldemu

Quote from: Xyphoe on 12:00, 02 April 25Thank you Anthony and Interrupt! (Quite an apt name for this topic! :D )

So "The Living Daylights" is basically using a mixture of rasters, interrupts and rupture/screen splits then! All 3?

I'm hoping someone could give a simple breakdown/overview of what's happening there and what Graham/David have done.

So far from my understanding it seems like ->
(1) They've started by using several rupture/screen splits (4? 3 in the main game area and 1 for the HUD at the bottom), then...
(2) They can use that for the hardware scroll for the 3 areas in the game window using the CRTC chip. I believe you use the registers in the CRTC chip - R3 isn't it for horizontal sync? And R12 and R13 to define the start address (checking old notes)
(3) They've then used 'interrupts' to help with timing roughly around the areas of the ruptures/screen splits to do the rasters/colour changes...
(4) And as Interrupt described above, using rasters they done palette colour changes on each rupture/screen split area to give up to 8 colours in game

Am I roughly right there / on the right lines?


Yes.

I will call out the rupture part as the cleverest bit as this is something most coders at the time didn't do.

Colour changing was common, R12/R13 for hardware scroll was done in quite a few games, but rupture very very few.

I would love to know why they chose this and where they found out about it.

One coder I asked who used rupture in a game did it 'to save memory' and didn't remember where they had heard of it from.

Also to add to this, changing colours and doing rupture must be done every frame (50Hz) to maintain the display regardless of the speed the actual gameplay is running at.
My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource

Interrupt

This is my basic understanding and as I haven't yet coded any ruptures I'm going on what is written above and my background reading over the years. The CRTC and palette information has to be updated every frame (50hz) for stable "ruptures". Everything is being updated as the electron beam is in motion.

There are six interrupts available per frame (see Axelay's screenshot). When an interrupt happens an interrupt handler is called. On each call to the interrupt handler you do something different. Once you return from the handler your game code continues as before.

On some of the interrupt handler calls that involves telling the CRTC to believe it is starting an entirely new screen that is a smaller height than a full screen. This is a "rupture" in what would otherwise be a standard continuous screen. At that time you also change the palette.

They will have needed to do this 4 times (I think) - interrupt 1 for the sky, interrupt 2 for the ground, interrupt 3 for the bushes and interrupt 4 for the status panel. See Axelays images.

The interrupt timings are fixed so if the interrupt doesn't occur at the right place on the screen for your need (Axelay shows they don't for this game) you have to either execute enough "no operation (NOP)" instructions to wait until the electron beam is in the right place or you have to do something else that takes the same amount of time. This code is hard to write as both paths for optional conditions (if A then do X else do Y) must take the same amount of time or your timing will be unstable. Without disassembling we won't know which choice they are making where. The gap to get from interrupt 3 to the right place for the bushes seems like a long time to just sit doing nothing.

Does that help?

ZorrO

CPC+PSX 4ever

abalore

If I had to do this, for me the easier way would be this:

- Try to make fixed duration (or relatively fixed) code blocks, like for painting sprites, detect collisions, painting UI, etc
- Not using the interrupt handler (that adds a lot of uncertainty).
- Run some code blocks that I know won't take more than 3328 us (the time between interrupts)
- Wait for raster to be in next screen block with HALT
- Set the palette for that new block
- Start over again

That's what I do, for instance, to have a lot of colours in mode 1 in the Acon 2020 menu screen. The drawback is that it waste some CPU time waiting but it may be enough for some games.

Anthony Flack

That's the other way to do it... put the splits inline with your main code, which you can do if you know your code will take the same amount of time each frame. Examples in demos using many more ruptures by doing them inline and writing code with exact timing.

As Abalore says you also have the option to HALT at any time and just wait for the next interrupt to come along, but we hate to waste CPU time doing nothing. But this is actually what you have to do to get your timing 100% perfect.

The way interrupts work, the interrupt call only happens AFTER the CPU finishes its current instruction, and instructions don't all take the same amount of time. So the interrupt can end up being delayed by a small amount, depending on what exactly it is doing when being interrupted... causing a small timing jitter. 

However with a HALT instruction, you always know exactly what you're doing - halting - so when the interrupt hits and your code resumes, you know you are exactly synced with the interrupt, therefore no jitter.

Trouble is, when it's inline you have to keep this loop going all the time, no matter what your code is doing, and it has to be at 50hz. If your code fails to complete before the interrupt it's supposed to halt for, it will wait for the next one instead, and all the timing will break. Losing the colour changes for a frame or two might not be a complete disaster, but if you mess up the timings for a rupture, your image will lose vsync and the picture will roll...

This is all because there is no way for the CPC to check what the exact time is. The CRTC knows, but those values are internal and hidden from the CPU. The only thing you can do to check the time is to wait for the next interrupt pulse to occur, and then count cycles from there. 

You can see where the interrupts are occurring in WinAPE - when you tell it to display interrupts, it turns the border blue every time the interrupt is called, and then back to normal once the interrupt is returned from - making those blue stripes in the border of the images above. If you read the screen like a graph, with the top of the screen being the start of the frame and the bottom of the screen being the end, all the blue sections represent the times when the main code has been interrupted. So we can see that the splits in this case are happening on the interrupt.



andycadley

Since I know Xyphoe is a Plus man like myself, it's also just worth mentioning that two of the most useful additions to the Plus were the Programmable Raster Interrupt (PRI) and Split registers. The PRI lets you do away with all the "six interrupts at fixed position" nonsense and just let you tell the hardware "I want the next interrupt to occur on line X" - which makes many of the timing issues with colour changes go away. The Split register is even more powerful, since it lets you do roughly the same thing as a rupture split automatically, by just telling the hardware what line you want it in and what address to start fetching screen data from. Whilst the code for Living Daylights probably took days, if not weeks, of skilled coding to get right you could probably knock up the equivalent on a Plus in half an hour, even if you were only a mediocre developer.

And yet people just think it was just some extra colours and some hardware sprites...

abalore

Quote from: Anthony Flack on 02:40, 03 April 25That's the other way to do it... put the splits inline with your main code, which you can do if you know your code will take the same amount of time each frame. Examples in demos using many more ruptures by doing them inline and writing code with exact timing.

As Abalore says you also have the option to HALT at any time and just wait for the next interrupt to come along, but we hate to waste CPU time doing nothing. But this is actually what you have to do to get your timing 100% perfect.

The way interrupts work, the interrupt call only happens AFTER the CPU finishes its current instruction, and instructions don't all take the same amount of time. So the interrupt can end up being delayed by a small amount, depending on what exactly it is doing when being interrupted... causing a small timing jitter.

However with a HALT instruction, you always know exactly what you're doing - halting - so when the interrupt hits and your code resumes, you know you are exactly synced with the interrupt, therefore no jitter.

Trouble is, when it's inline you have to keep this loop going all the time, no matter what your code is doing, and it has to be at 50hz. If your code fails to complete before the interrupt it's supposed to halt for, it will wait for the next one instead, and all the timing will break. Losing the colour changes for a frame or two might not be a complete disaster, but if you mess up the timings for a rupture, your image will lose vsync and the picture will roll...

This is all because there is no way for the CPC to check what the exact time is. The CRTC knows, but those values are internal and hidden from the CPU. The only thing you can do to check the time is to wait for the next interrupt pulse to occur, and then count cycles from there.

You can see where the interrupts are occurring in WinAPE - when you tell it to display interrupts, it turns the border blue every time the interrupt is called, and then back to normal once the interrupt is returned from - making those blue stripes in the border of the images above. If you read the screen like a graph, with the top of the screen being the start of the frame and the bottom of the screen being the end, all the blue sections represent the times when the main code has been interrupted. So we can see that the splits in this case are happening on the interrupt.



Just one clarification, if you use double buffer the game doesn't need to run at 50 fps. You just need to set the inks in the proper places but you can switch the buffers after several passes.

andycadley

Quote from: abalore on 11:23, 03 April 25Just one clarification, if you use double buffer the game doesn't need to run at 50 fps. You just need to set the inks in the proper places but you can switch the buffers after several passes.
Not if you're using Ruptures or colour rasters. They need to happen on every frame (regardless of whether you redraw anything) or the display will corrupt. Double buffering doesn't change this.

abalore

Quote from: andycadley on 15:16, 03 April 25
Quote from: abalore on 11:23, 03 April 25Just one clarification, if you use double buffer the game doesn't need to run at 50 fps. You just need to set the inks in the proper places but you can switch the buffers after several passes.
Not if you're using Ruptures or colour rasters. They need to happen on every frame (regardless of whether you redraw anything) or the display will corrupt. Double buffering doesn't change this.
I think you didn't understand a single word of what I said, because I said the same than you. You need to respect the timings for ink changes and ruptures, but you don't need to draw the whole screen in a single frame, can take all the frames you want

Anthony Flack

We all know how it works so we're not in disagreement, but everybody loves the opportunity to explain. It's rare to find somebody who doesn't know how to code already, who isn't bored to hear about it. 

I should say that the game can update at whatever speed you like, but all all that raster malarky has to run on a 50hz loop without fail. So if your game loop is locked to 25hz, all the raster stuff will turn up twice in each game loop.

In this case TLD appears to have all the raster stuff running on the interrupt, so the main game code can ignore it and is free to drop frames whenever it cares to. 


Anthony Flack

Also, this makes way more sense as a light gun game. I didn't know that was the idea.

Xyphoe

Quote from: Anthony Flack on 01:46, 04 April 25Also, this makes way more sense as a light gun game. I didn't know that was the idea.

We don't know for sure.

The ZX Spectrum version of The Living Daylights which also came out in 1987 looks and plays very similar, it was coded by the same guys (Graham Stafford & David Fish) and likely co-developed at the same time.

The ZX Spectrum also later got a light gun version of the game which was bundled with Amstrad's new +2A versions of the Speccy for Xmas '89... (and it was rubbish) was it Amstrad's intentions all along and they had a word with Domark to make sure they could turn their Bond game into something that would be 'light gun compatible' down the line? In time for a relaunch/refresh of Amstrad/Spectrum computers seeing as Amstrad had just bought out Sinclair? But which took 2 years to happen? But never on the CPC?

Speccy light gun version ->



(Although the Speccy, to the best of my knowledge, doesn't have an internal video chip like the Amstrad's CRTC - it has 16K of RAM that the CPU can access, which means quickly porting would be an issue, especially when the CPC version utilised the CRTC chip...)

Here's a timeline...

1986 -> Amstrad bought out Sinclair

1987 -> Amstrad and ZX Spectrum versions of The Living Daylights Released
ALSO Magnum Light Phaser Released - Maybe Amstrad knew they could do something with this and the game?

Xmas 1989 -> The James Bond 007 Action Pack for the Spectrum +2A with the light gun modified The Living Daylights (as "Mission Zero") released
https://www.mi6-hq.com/sections/games/james-bond-007-action-pack


Who knows. A lot of speculation on my part.

Longshot

Quote from: andycadley on 08:49, 02 April 25That lets you do things like hardware scroll different sections while keeping some bits static. It's quite an advanced technique though and was often shied away from by commercial teams for fear it might cause issues on some displays (since it's basically abusing the CRTC timing)
Absolutely.
Besides, "The Living DayLights" suffers from a compatibility issue related to its rupture on CRTC 1.
It works as expected on other CRTCs.
This can be seen in two screenshots presented in this article about the Compendium (sorry, in French).
On the screenshot (CRTC 1) we can see that the HUD appears prematurely, and therefore when the palette has not yet been modified.
https://blog.logonsystem.eu/compendium/

The technical explanation is in the compendium (V1.8 page 235)
https://shaker.logonsystem.eu/ACCC1.8-EN.pdf

Another game "3D STARSTRIKE", published by "Realtime Games Software" in 1985, was developed on CRTC 0.
The developers did not modify the programmed value in ROM for the length of the VSYNC.
This causes a bug during the game on CRTC 1 and 2, because the firing cursor is not in phase with the display and flashes, while this is not the case on CRTC 0, 3 and 4.

Quote from: Interrupt on 13:12, 02 April 25The interrupt timings are fixed so if the interrupt doesn't occur at the right place on the screen for your need (Axelay shows they don't for this game) you have to either execute enough "no operation (NOP)" instructions to wait until the electron beam is in the right place or you have to do something else that takes the same amount of time
As an exception, if interrupts have been disabled for more than 52 lines, an interrupt is pending and occurs when the Z80A allows it.
If this interrupt occurs during the counter areas between 32 and 51, then the next interrupt is delayed by 32 lines.(e.g. bit 5 of R52 is cleared)
Finally, all this is true if we don't play with Hsync frequency.
At the fastest, we can force the Gate Array to issue one interrupt every 104 nops (with one Hsync every 2 µseconds)
(a test in Shaker shows this).
Also playing with the CRTC which generates the HSYNC signal allows you to "manage" an interruption on a given screen line by creating "small lines" during one or two displayed lines.

Rhaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa!!

Powered by SMFPacks Menu Editor Mod