English Amiga Board


Go Back   English Amiga Board > Coders > Coders. Asm / Hardware

 
 
Thread Tools
Old 03 June 2013, 16:36   #1
phx
Natteravn
 
phx's Avatar
 
Join Date: Nov 2009
Location: Herford / Germany
Posts: 2,496
Combining copper scrolling with copper background

In my current game project I'm scrolling a huge map with the algorithm described here: http://aminet.net/package/dev/src/ScrollingTrick

It is a combination of copper and blitter scrolling and needs to reset the bitplane pointers at a variable line on the screen.

Now I have the problem that I would also like to have a copper background, which gives each line a different colour. It seems that the only option is to create the copper list dynamically in every new frame. But writing the dynamic part of that copper list requires nearly 50 scan lines (WAIT and COLOR for 240 lines and writing the BPLxPT at the split line)! Is there any way to improve that? Or a completely different approach to the problem?
phx is offline  
Old 03 June 2013, 16:53   #2
hooverphonique
ex. demoscener "Bigmama"
 
Join Date: Jun 2012
Location: Fyn / Denmark
Posts: 1,624
if the colors set by the copper also need to shift/scroll along with the bitmap, you need to move them around as well, which will be almost like generating a new copper list each frame.

with regards to the bitplane pointers, writing the modulos on each scanline and then updating those instead might save some (presuming your bitplanes are below 32k each).
hooverphonique is offline  
Old 03 June 2013, 17:12   #3
phx
Natteravn
 
phx's Avatar
 
Join Date: Nov 2009
Location: Herford / Germany
Posts: 2,496
Quote:
Originally Posted by hooverphonique View Post
if the colors set by the copper also need to shift/scroll along with the bitmap,
Yes. Although with a different speed (I think about vertical scrolling speed /2 or /4).

Quote:
you need to move them around as well, which will be almost like generating a new copper list each frame.
Too bad. That's very expensive. Does Turrican do it the same way?

Quote:
with regards to the bitplane pointers, writing the modulos on each scanline and then updating those instead might save some (presuming your bitplanes are below 32k each).
The bitmaps are quite large (IIRC 352x288x5) and double buffered. Doesn't fit.
phx is offline  
Old 03 June 2013, 17:19   #4
phx
Natteravn
 
phx's Avatar
 
Join Date: Nov 2009
Location: Herford / Germany
Posts: 2,496
Currently I'm writing the copper list like below. a2 points to the copper list. d0 is the line where I have to insert the split. Needs about 48 scan lines.

Code:
        lea     Cl_colors(a2),a2 
        lea     TestColors(pc),a0
        movem.l .Clistreginit(pc),d1-d4
        move.w  #0,d5                   ; @@@@ background color index
        moveq   #15,d6                  ; color index mask

.4:     move.w  (a0,d5.w),d3
        move.l  d2,(a2)+                ; WAIT
        addq.w  #2,d5
        and.w   d6,d5

        subq.w  #1,d0
        beq     .7                      ; reached the split line

.5:     move.l  d3,(a2)+                ; COLOR01  
        add.l   d4,d2                   ; next line
        bcs     .6   
        dbf     d1,.4

        moveq   #-2,d0
        move.l  d0,(a2)                 ; end of copper list
        movem.w Xpos(a4),d2-d4
        rts

        ; insert extra WAIT for raster line $100
.6:     COPWAIT $ff,$de,(a2)+
        dbf     d1,.4
        illegal                         ; never reached

        ; write updated bitplane pointers for the split section
.7:     swap    d1                      ; BPL1PTH to LSW
        moveq   #PLANES-1,d0
.8:     move.w  d1,(a2)+
        swap    d7
        move.w  d7,(a2)+
        addq.w  #2,d1   
        move.w  d1,(a2)+
        swap    d7
        move.w  d7,(a2)+
        addq.w  #2,d1   
        add.l   a1,d7   
        dbf     d0,.8   
        swap    d1                      ; get loop counter back into LSW
        bra     .5

.Clistreginit:
        dc.l    BPL1PTH<<16|DISPH-1     ; d1
        dc.l    VSTART<<24|1<<16|$fffe  ; d2
        dc.l    COLOR01<<16             ; d3
        dc.l    $01000000               ; d4
phx is offline  
Old 05 June 2013, 22:41   #5
Asman
68k
 
Asman's Avatar
 
Join Date: Sep 2005
Location: Somewhere
Posts: 828
Some idea:
Generate two above copperlists and keep them in memory and write only things which will change, like all colors, screen pointers (for double buffering omit this)

I have question:
How many lines will have own color ? 256 ? (sorry I'm too tired to count from your source)
Asman is offline  
Old 06 June 2013, 05:10   #6
mc6809e
Registered User
 
Join Date: Jan 2012
Location: USA
Posts: 372
Quote:
Originally Posted by phx View Post

Now I have the problem that I would also like to have a copper background, which gives each line a different colour. It seems that the only option is to create the copper list dynamically in every new frame. But writing the dynamic part of that copper list requires nearly 50 scan lines (WAIT and COLOR for 240 lines and writing the BPLxPT at the split line)! Is there any way to improve that? Or a completely different approach to the problem?
Maybe you can treat your copper list as a circular queue.

You're already doing something similar with bitplane memory. You don't build a new screen each frame. Instead you change the edges and shift the rest by changing pointers. Same thing will work with a copper list, except in one dimension instead of two.

You'll need to have the copper enter the list at a variable point, with each scanline having at least a move and a wait for the end of the line. The last instruction of the list should include the BPLxPT moves and a strobe to the top of the list. By waiting for the end of the line between instructions, you can avoid special waits like the wait for line $100.

Exiting the loop on the last displayable line might be tricky. You probably don't want the background to change after that.
mc6809e is offline  
Old 06 June 2013, 11:32   #7
phx
Natteravn
 
phx's Avatar
 
Join Date: Nov 2009
Location: Herford / Germany
Posts: 2,496
Quote:
Originally Posted by Asman View Post
How many lines will have own color ? 256 ? (sorry I'm too tired to count from your source)
My first approach was stupid. I had 240 lines in the display window and tried to change the color in each line.

This is not necessary, when I think about it. It already looks good enough when changing the color every 10 lines or so.

Now I have a more flexible copper background definition, in this form:
Code:
        dc.w    $d5e,10
        dc.w    $d6e,1
        dc.w    $d5e,1
        dc.w    $d6e,10
        ...
Each pair of words defines the color and the number of lines it is valid for. A level has a maximum height of 4096 pixels (256 16 pixel tiles), so I want to define a copper background for 2048 lines this way. I will divide the current y-position by 2 to find the first color to display.

There will be three variables to optimize this process:
CbackPos: Current offset on the copper background, 0-2047 (not on the list).
CbackPtr: Pointer to an entry of the above list, which defines the color of the topmost visible line.
CbackOffs: Offset into the topmost color bar, i.e. number of lines which already left the display on top.

But maybe this is still too complicated? I will think about the implementation now...
phx is offline  
Old 06 June 2013, 11:38   #8
phx
Natteravn
 
phx's Avatar
 
Join Date: Nov 2009
Location: Herford / Germany
Posts: 2,496
Quote:
Originally Posted by mc6809e View Post
You'll need to have the copper enter the list at a variable point, with each scanline having at least a move and a wait for the end of the line. The last instruction of the list should include the BPLxPT moves and a strobe to the top of the list.
Hmm... that's a nice idea. I could write COPLC and then use COPJMP to jump into the list at variable points?
But as far as I understand, I still have to rewrite the VPOS-part of all the WAIT-instructions when scrolling vertically? The copper background should scroll vertically at half of the real scrolling speed.

Quote:
By waiting for the end of the line between instructions, you can avoid special waits like the wait for line $100.
Yes, that would work!

But now I decided that I no longer want to change the color in each line (see above).
phx is offline  
Old 07 June 2013, 08:46   #9
Toni Wilen
WinUAE developer
 
Join Date: Aug 2001
Location: Hämeenlinna/Finland
Age: 49
Posts: 26,502
(Modification of mc6809e's suggestion)

I'd create big copper list that has as many wait/move pairs as you have vertical pixels (2048?). WAIT only waits for end of horizontal line, MOVE changes background color.

Normal copper list waits for first visible line, jumps to big copper list, matching Y-position.

When you need to move split point, replace color register write with write to COPJMPx (and restore old COPJMPx with COLOR0 write) which handles the split and color change (if also needed) and finally jumps back to big copper list.

Now you only need to change COPJMP pointer and 2 words (or more if you need to also exit the big list before end of display) in copper list when you need to change vertical position. Of course copper list will waste some time doing mostly useless waits and moves but it is still faster and more optimal than rewriting whole copperlist with CPU.
Toni Wilen is offline  
Old 07 June 2013, 11:45   #10
phx
Natteravn
 
phx's Avatar
 
Join Date: Nov 2009
Location: Herford / Germany
Posts: 2,496
Quote:
Originally Posted by Toni Wilen View Post
I'd create big copper list that has as many wait/move pairs as you have vertical pixels (2048?). WAIT only waits for end of horizontal line, MOVE changes background color.
Ahhh! Now I understand! Maybe mc6809e also said that, but I didn't get it.

The WAIT instructions will only wait for end of line, but ignore the VPOS. Something like $00df,$00fe? After writing to COLOR the next line has started and I can wait for end of line again. Very good idea!


Quote:
When you need to move split point, replace color register write with write to COPJMPx (and restore old COPJMPx with COLOR0 write) which handles the split and color change (if also needed) and finally jumps back to big copper list.
Ok. The only question here is whether the number of available memory cycles until DDFSTART are sufficient to load the pointers for all five bitplanes, write the COPJMP and COLOR.
phx is offline  
Old 07 June 2013, 11:55   #11
Toni Wilen
WinUAE developer
 
Join Date: Aug 2001
Location: Hämeenlinna/Finland
Age: 49
Posts: 26,502
Quote:
Originally Posted by phx View Post
Ahhh! Now I understand! Maybe mc6809e also said that, but I didn't get it.

The WAIT instructions will only wait for end of line, but ignore the VPOS. Something like $00df,$00fe? After writing to COLOR the next line has started and I can wait for end of line again. Very good idea!
Yeah.

Quote:
Ok. The only question here is whether the number of available memory cycles until DDFSTART are sufficient to load the pointers for all five bitplanes, write the COPJMP and COLOR.
It should fit if you only need to modify low 16-bit of bitplane pointers. If not, split copper list can be started 1 line earlier, wait for nearly end of next line and then do the split.
Toni Wilen is offline  
Old 07 June 2013, 22:37   #12
mc6809e
Registered User
 
Join Date: Jan 2012
Location: USA
Posts: 372
Quote:
Originally Posted by phx View Post
Ok. The only question here is whether the number of available memory cycles until DDFSTART are sufficient to load the pointers for all five bitplanes, write the COPJMP and COLOR.
If you're very desperate, you can use the CPU to change the bitplane pointers. The Amiga CPU interrupt mechanism is very clever and allows the CPU to be well-synced to the display if necessary. This means you can pre-load registers with data, STOP the CPU, trigger an interrupt with the copper, and then blast the hardware registers using a MOVEM.L instruction. There is quite a delay between the interrupt and moment the CPU begins to write to the registers, but it is predictable for a 68000 with the interrupt handler and supervisor stack in chipram. Other processors introduce complications, though.
mc6809e is offline  
Old 08 June 2013, 21:09   #13
phx
Natteravn
 
phx's Avatar
 
Join Date: Nov 2009
Location: Herford / Germany
Posts: 2,496
Quote:
Originally Posted by mc6809e View Post
There is quite a delay between the interrupt and moment the CPU begins to write to the registers, but it is predictable for a 68000 with the interrupt handler and supervisor stack in chipram. Other processors introduce complications, though.
Not an option then. Although it will be an A500 OCS game I want to make sure it works on any existing Amiga.
phx is offline  
Old 15 June 2013, 18:24   #14
Photon
Moderator
 
Photon's Avatar
 
Join Date: Nov 2004
Location: Eksjö / Sweden
Posts: 5,602
An interrupt that starts with a busy-wait for the intended HPOS can be predictably triggered for a minimum busy-wait on 68000. Should you have a fast CPU you waste part of a scanline busy-waiting, but on the other hand if the game runs on A500 the CPU can waste that time and still be able to run the game. A good method to know when you are A500-centric (write for the A500 platform specifically) but don't want to rule out faster Amigas.
Photon is offline  
Old 16 June 2013, 07:26   #15
mc6809e
Registered User
 
Join Date: Jan 2012
Location: USA
Posts: 372
Quote:
Originally Posted by Photon View Post
An interrupt that starts with a busy-wait for the intended HPOS can be predictably triggered for a minimum busy-wait on 68000. Should you have a fast CPU you waste part of a scanline busy-waiting, but on the other hand if the game runs on A500 the CPU can waste that time and still be able to run the game. A good method to know when you are A500-centric (write for the A500 platform specifically) but don't want to rule out faster Amigas.
Great idea. And the initial MOVEM.L M->R can be done inside the handler, too, followed by the wait.

Thanks!
mc6809e is offline  
Old 13 February 2021, 11:10   #16
earok
Registered User
 
Join Date: Dec 2013
Location: Auckland
Posts: 3,539
This thread was really useful!

For my copper splitscreen solution, I originally was using 17 copper operations per line, which were:
- The line wait
- 12x spare ops for setting all 6x bitplane pointers (these are normally NOP but will be set to bitplane pointers on the one line that they're used on)
- 4x ops for setting Color0 with a 24Bit AGA color


Using COPJMP, I was able to reduce it to 5 - just the line wait (which can be substituted with a COPJMP to a secondary copperlist that takes care of resetting the bitplane pointers) and the color operations.
earok is offline  
Old 13 February 2021, 12:41   #17
DanScott
Lemon. / Core Design
 
DanScott's Avatar
 
Join Date: Mar 2016
Location: Tier 5
Posts: 1,211
This is what I did for Chuck Rock 2 (and Wonderdog)


I had a table with an entry for each scanline, with the total number of copper instructions cumulative up to that line.

Then if the bitplanes need resetting at line X, I read value Y from table at position X, blit that part of the copperlist, then insert bitplane stuff, then blit the rest of the copperlist.

It took hardly any time in total.

This also allowed for any (variable) number of other copper instructions per line..
DanScott is online now  
 


Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools

Similar Threads
Thread Thread Starter Forum Replies Last Post
Copper timing yaqube Coders. General 61 08 April 2019 00:41
Copper tricks Lonewolf10 Coders. General 14 31 March 2011 22:09
Best use of copper in a game donnie Retrogaming General Discussion 16 09 August 2010 21:34
Copper Bars Vortex Coders. Tutorials 51 26 June 2009 23:23
Stuck with copper example cosmiq Coders. General 6 17 October 2008 22:29

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT +2. The time now is 17:50.

Top

Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2024, vBulletin Solutions Inc.
Page generated in 0.16244 seconds with 13 queries