![]() |
![]() |
![]() |
#1 |
Natteravn
![]() Join Date: Nov 2009
Location: Herford / Germany
Posts: 2,315
|
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? |
![]() |
![]() |
#2 |
ex. demoscener "Bigmama"
![]() Join Date: Jun 2012
Location: Fyn / Denmark
Posts: 1,432
|
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). |
![]() |
![]() |
#3 | |||
Natteravn
![]() Join Date: Nov 2009
Location: Herford / Germany
Posts: 2,315
|
Quote:
Quote:
![]() Quote:
|
|||
![]() |
![]() |
#4 |
Natteravn
![]() Join Date: Nov 2009
Location: Herford / Germany
Posts: 2,315
|
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 |
![]() |
![]() |
#5 |
68k
![]() Join Date: Sep 2005
Location: Somewhere
Posts: 807
|
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) |
![]() |
![]() |
#6 | |
Registered User
Join Date: Jan 2012
Location: USA
Posts: 351
|
Quote:
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. |
|
![]() |
![]() |
#7 | |
Natteravn
![]() Join Date: Nov 2009
Location: Herford / Germany
Posts: 2,315
|
Quote:
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 ... 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... |
|
![]() |
![]() |
#8 | ||
Natteravn
![]() Join Date: Nov 2009
Location: Herford / Germany
Posts: 2,315
|
Quote:
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:
![]() But now I decided that I no longer want to change the color in each line (see above). |
||
![]() |
![]() |
#9 |
WinUAE developer
Join Date: Aug 2001
Location: Hämeenlinna/Finland
Age: 48
Posts: 25,800
|
(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. |
![]() |
![]() |
#10 | ||
Natteravn
![]() Join Date: Nov 2009
Location: Herford / Germany
Posts: 2,315
|
Quote:
![]() 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:
|
||
![]() |
![]() |
#11 | ||
WinUAE developer
Join Date: Aug 2001
Location: Hämeenlinna/Finland
Age: 48
Posts: 25,800
|
Quote:
Quote:
|
||
![]() |
![]() |
#12 |
Registered User
Join Date: Jan 2012
Location: USA
Posts: 351
|
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.
|
![]() |
![]() |
#13 | |
Natteravn
![]() Join Date: Nov 2009
Location: Herford / Germany
Posts: 2,315
|
Quote:
![]() |
|
![]() |
![]() |
#14 |
Moderator
![]() Join Date: Nov 2004
Location: Eksjö / Sweden
Posts: 5,318
|
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.
|
![]() |
![]() |
#15 | |
Registered User
Join Date: Jan 2012
Location: USA
Posts: 351
|
Quote:
Thanks! |
|
![]() |
![]() |
#16 |
Registered User
![]() Join Date: Dec 2013
Location: Auckland
Posts: 3,280
|
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. |
![]() |
![]() |
#17 |
Lemon. / Core Design
![]() Join Date: Mar 2016
Location: Tier 5
Posts: 1,134
|
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.. |
![]() |
Currently Active Users Viewing This Thread: 1 (0 members and 1 guests) | |
Thread Tools | |
![]() |
||||
Thread | Thread Starter | Forum | Replies | Last Post |
Copper timing | yaqube | Coders. General | 61 | 08 April 2019 01:41 |
Copper tricks | Lonewolf10 | Coders. General | 14 | 31 March 2011 23:09 |
Best use of copper in a game | donnie | Retrogaming General Discussion | 16 | 09 August 2010 22:34 |
Copper Bars | Vortex | Coders. Tutorials | 51 | 27 June 2009 00:23 |
Stuck with copper example | cosmiq | Coders. General | 6 | 17 October 2008 23:29 |
|
|