News:

Printed Amstrad Addict magazine announced, check it out here!

Main Menu
avatar_llopis

Making screen memory not visible on the sides?

Started by llopis, 20:49, 01 December 22

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

llopis

I have a question for those of you with lots of CRTC modifying experience.

I know I can change the CRTC parameters to change the dimensions of the screen. What I'm not sure about is whether it's possible to have the CRTC "skip" a byte or so on the left and the right and not display those as part of the screen draw. I guess it would probably have something to do with the first 3 registers, but I haven't been able to find anything about it (probably because I don't know the name of the technique).

Just in case it's not clear, here's an example. With the normal screen configuration, make it so #C000 isn't visible and the leftmost pixel starts at #C001. Same thing with #C800 and #C801, etc. And ideally on the right as well (so #C04F not visible, but #C04E visible).

Also, another requirement is that this is something that can be set and it'll just work. Not interested in having to modify CRTC registers every few rasters since this is for a game, not a demo.

Thanks.

andycadley

No. Only the Plus machines can do that.

llopis

Aha! That's what I feared. OK, so I guess I'll continue blanking pixels on the edges by hand for now :-)
Thanks!

abalore

Sadly you can't clip sprites horizontally as easily as vertically. But depending on how you draw the sprites it can be very easy to do a clipping routine.

llopis

Clipping the sprites is fine. This is caused because I'm doing horizontal scroll in 1 byte increments (the standard technique using R3) but that means that one frame the screen moves one byte to the left, and the next frame it does that but two new bytes appear on the right. So to preserve the illusion of 1-byte scroll, I'm having to blank out the leftmost and rightmost columns almost all the time (which is not a huge deal, but I was wondering if there was a way to avoid that).

andycadley

The "classic" trick is just to make the screen wider than the monitor, so that the display itself clips it for you. But obviously that only works if your game suits a full width display.

llopis

Oh interesting! It's probably not ideal because it's going to make the somewhat-coarse horizontal scroll already more noticeable. And besides, does that trick play well with emulators and LCDs, or is it limited to CRTs?

What games use that trick out of curiosity?

Axelay

#7
Quote from: llopis on 00:50, 02 December 22Oh interesting! It's probably not ideal because it's going to make the somewhat-coarse horizontal scroll already more noticeable. And besides, does that trick play well with emulators and LCDs, or is it limited to CRTs?

What games use that trick out of curiosity?
Out of this world (87), BMX kidz (I think), Super Cauldron & Prehistorik 2.  If you look on CPC power and check the horizontal overscan tag and look for those that hardware scroll as well, you should find a couple of others.

Extending the screen width wont trouble an emulator or LCD, but using R3 to scroll will cause an LCD to spit the dummy and display no image from what I understand.  From what I've seen on Youtube, even adjusting R2 during a frame will cause at least some LCDs to not display an image either.  Although that might be what they were using to connect to the screen instead.

Quote from: llopis on 23:07, 01 December 22So to preserve the illusion of 1-byte scroll, I'm having to blank out the leftmost and rightmost columns almost all the time (which is not a huge deal, but I was wondering if there was a way to avoid that).
Maybe I am misunderstanding what you're saying, but wouldn't you only need to blank either the left or right byte column on any given frame, not both?

llopis

Hmm.... I had read about that, but I was somehow hoping that wasn't common. I don't have an LCD to test it (and LCD isn't my primary target), but I suppose it's easy enough to create an LCD version with choppier scroll. I'll have to do some tests at some point. Thanks for bringing that up.

llopis

Quote from: andycadley on 23:30, 01 December 22The "classic" trick is just to make the screen wider than the monitor, so that the display itself clips it for you. But obviously that only works if your game suits a full width display.
Thinking back about that (and about what @Axelay said), are you talking about increasing the width of the screen area, or actually implementing real overscan with more than 16KB of screen RAM? I don't think I'm ready to give up more video RAM yet, but if there's a way to stretch the screen horizontally and vertically so there's no border, that'd be awesome (and I'm sure every game would be using it, so I doubt it's that simple  :) ).

Axelay

All the commercial era games I am familiar with that extended the screen width to 48 characters to hide the R3 edge 'jitter' also reduced the screen height to a maximum of 21 characters to keep the total character count under 1024, or within a single 16kb screen.  Though Super Cauldron & Prehistorik 2 also use a second screen for a score panel.

abalore

Ghosts'n'goblins seems to deal with that problem pretty well. Did you check how it works?

andycadley

Exactly, you just trade height for width. You didn't see it that much back in the day because:

A) The Spectrum and C64 can't do it and games were typically designed for all three.

B) Mostly games used software scrolling and so wanted the drawn area to be as small as possible to avoid needing too much CPU time for drawing.

llopis

Quote from: abalore on 15:41, 02 December 22Ghosts'n'goblins seems to deal with that problem pretty well. Did you check how it works?
The original one, right? I just had a look at some videos and I see that sprites disappear before getting to the end of the screen :) I imagine the scroll is 2 bytes at a time, so they don't have to worry about clearing out a one-byte column like I do.

This really makes me want to just make the scroll vertical, but I think the game will be better if I have both, so I'll keep going until it becomes impossible.

abalore

Quote from: llopis on 23:08, 02 December 22
Quote from: abalore on 15:41, 02 December 22Ghosts'n'goblins seems to deal with that problem pretty well. Did you check how it works?
The original one, right? I just had a look at some videos and I see that sprites disappear before getting to the end of the screen :) I imagine the scroll is 2 bytes at a time, so they don't have to worry about clearing out a one-byte column like I do.

This really makes me want to just make the scroll vertical, but I think the game will be better if I have both, so I'll keep going until it becomes impossible.

Here is a list of games using R3 scrolling a other techniques

https://www.cpcwiki.eu/index.php/Programming_methods_used_in_games

Axelay

Quote from: llopis on 23:08, 02 December 22
Quote from: abalore on 15:41, 02 December 22Ghosts'n'goblins seems to deal with that problem pretty well. Did you check how it works?
The original one, right? I just had a look at some videos and I see that sprites disappear before getting to the end of the screen :) I imagine the scroll is 2 bytes at a time, so they don't have to worry about clearing out a one-byte column like I do.

There's the danger of using youtube as a technical reference! ;)  It very definitely is using R3 to scroll by byte steps horizontally.  Try playing it in an emulator like WinApe with the interrupt highlight turned on, and you'll see what it's doing.

gurneyh

What technique do you use to clean the columns?
By using res/set to browse the rows you can achieve a significant gain. Not to mention loop unrolling.

llopis

Guilty as charged :)
But what's amazing to me is that such an early game as Ghost n Goblins was using that technique and that supposedly it doesn't work on non-CRT displays. Is that true for today as well, or was that only true of old flat-panel displays from 20 years ago? (I'd try it but I don't have access to an LCD with RGB input at the moment).

llopis

Quote from: gurneyh on 12:50, 03 December 22What technique do you use to clean the columns?
By using res/set to browse the rows you can achieve a significant gain. Not to mention loop unrolling.
Well, they're full bytes (2 pixels--yes, it's still pretty chunky), so no need to do res/set.

I haven't spent any time optimizing this (beyond the unrolling), but this is what I have so far for the blanking of that pixel:


;; IN: HL address to draw a black column at
DrawBlackColAtAddress:
       ld     b, SCREEN_HEIGHT/8
       ld     c, 0
.loop:
       ld     a, h
       ld     (hl), c
       add    #8
       ld     h, a
       ld     (hl), c
       add    #8
       ld     h, a
       ld     (hl), c
       add    #8
       ld     h, a
       ld     (hl), c
       add    #8
       ld     h, a
       ld     (hl), c
       add    #8
       ld     h, a
       ld     (hl), c
       add    #8
       ld     h, a
       ld     (hl), c
       add    #8
       ld     h, a
       ld     (hl), c

       ld     de, #c850
       add    hl, de

       djnz   .loop
       ret



Axelay

You can also use set/res to change the address hl points to as well, not just for modifying contents of a screen byte.  For example, this will clear a column of bytes in a character, 'b' times:

.clear_col2
  xor a
  ld de,80 - #2000
.clr_lp2
  ld (hl),a:set 3,h
  ld (hl),a:set 4,h
  ld (hl),a:res 3,h
  ld (hl),a:set 5,h
  ld (hl),a:set 3,h
  ld (hl),a:res 4,h
  ld (hl),a:res 3,h
  ld (hl),a
  add hl,de:res 3,h
  djnz clr_lp2

As for LCDs, I'm not an expert on that side of things so I'm not the best one to answer, but I gather not being 'analogue' technology they don't have the tolerance for changes to Hsync during a frame like CRTs do, so I'm not sure the age of the LCD will matter.

llopis

Quote from: Axelay on 13:57, 03 December 22You can also use set/res to change the address hl points to as well, not just for modifying contents of a screen byte.  For example, this will clear a column of bytes in a character, 'b' times:

.clear_col2
  xor a
  ld de,80 - #2000
.clr_lp2
  ld (hl),a:set 3,h
  ld (hl),a:set 4,h
  ld (hl),a:res 3,h
  ld (hl),a:set 5,h
  ld (hl),a:set 3,h
  ld (hl),a:res 4,h
  ld (hl),a:res 3,h
  ld (hl),a
  add hl,de:res 3,h
  djnz clr_lp2

As for LCDs, I'm not an expert on that side of things so I'm not the best one to answer, but I gather not being 'analogue' technology they don't have the tolerance for changes to Hsync during a frame like CRTs do, so I'm not sure the age of the LCD will matter.
Ooh, great point! Love it! I'm copying it right now. Thanks!

martin464

me too! this looks stunning to save some nops and more importantly... registers. i honestly can't believe its that simple
i was using xor to reset H back to C000 range or 8000 for double buffer, with registers for adding 8/80
but i think this will work for either screen addresses just like that did with the same bit setting
wow. now i've got so many registers free i don't know what to do with them, in a routine that's been spanking my butt for days trying to optimise and one register short. Axelay must be working for the Stormlord fairy
CPC 464 - 212387 K31-4Z

"One essential object is to choose that arrangement which shall tend to reduce to a minimum the time necessary for completing the calculation." Ada Lovelace

llopis

Quote from: Axelay on 13:57, 03 December 22You can also use set/res to change the address hl points to as well, not just for modifying contents of a screen byte.  For example, this will clear a column of bytes in a character, 'b' times:

.clear_col2
  xor a
  ld de,80 - #2000
.clr_lp2
  ld (hl),a:set 3,h
  ld (hl),a:set 4,h
  ld (hl),a:res 3,h
  ld (hl),a:set 5,h
  ld (hl),a:set 3,h
  ld (hl),a:res 4,h
  ld (hl),a:res 3,h
  ld (hl),a
  add hl,de:res 3,h
  djnz clr_lp2

As for LCDs, I'm not an expert on that side of things so I'm not the best one to answer, but I gather not being 'analogue' technology they don't have the tolerance for changes to Hsync during a frame like CRTs do, so I'm not sure the age of the LCD will matter.

By the way, I spent some more time thinking through that code and it's great. I also noticed it doesn't go through the scanlines in order, but it doesn't matter for clearing.
What's even better, is that I changed my exporter to export column-order tiles in that order (0 1 3 2 6 7 5 4), and now I'm also using that in the sprite column drawing function and it's super fast.
Thank you!

Prodatron

Maybe you could even make your sprites "direct addressed"?

Have a look:
https://www.cpcwiki.eu/index.php/Programming:Fast_Textoutput

There is a routine for each single char (like "mftchr036" for plotting a $).

You could do the same for sprites, the bitmap data would be integrated in the code.
Of course this will generate a lot of code, when you have many different sprites. So the question is, if you have enough memory left for this methode.

GRAPHICAL Z80 MULTITASKING OPERATING SYSTEM

llopis

Interesting. I think that's what we used to call "compiled sprites" back on the MS-DOS/Mode 13h days. I definitely don't have enough room for that though. It's already bad enough that I'm storing tiles in row and column format. But we'll see. 

Right now I'm just doing a tech prototype, so part of it is going to be finding out how much memory do I have to play with, how much stuff I can do in a frame, etc. And then I'll have to set the development target (64K? 128K? ROM? Cartridge? Disk?). So many options!

Powered by SMFPacks Menu Editor Mod