RethinkDisplay()/MrgCop() on AGA?

21 posts / 0 new
Last post
SamuraiCrow
SamuraiCrow's picture
Offline
Last seen: 5 years 1 month ago
Joined: 2011-09-18 22:20
RethinkDisplay()/MrgCop() on AGA?
Hello, I'm trying to write a series of libraries for encapsulating all of the most common uses of hardware banging on OS 3.1+. Later on I plan on writing a version of the libraries for Mesa/OpenGL and graphics cards. My first attempt at writing a library that integrates with the Copper functionality is based on tile-scrolling algorithms. What I need to know is: How do I write the bitplane-wraparound Copper-list functions in such a way that they will work with RethinkDisplay() in Graphics.library? I've heard that it internally uses MrgCop() to patch together all of the partial Copper lists. My plan is as follows: I want to make a layer with 2 rectangles both pointing to the same screen memory but be located with the bottom rectangle at the bottom row of pixels in the top rectangle. This will allow me to use a Copper wraparound technique by having the last row of pixels and the first row of pixels in screen memory to be identical. When having the screen display the seam in the middle, the Copper will change the bitplane pointers all to the top of video memory. Is what I'm trying to do even possible? The algorithm I've seen on the Aminet does it but writes custom copper lists for the whole screen instead of just using the Graphics.library functions.
hypex
hypex's picture
Offline
Last seen: 8 hours 23 min ago
Joined: 2011-09-09 16:20
I think I can help.
I think I can help. Regardless of if the copper list can do what you want here is how to add one of your own in a system friendly way. It's actually quite easy and you don'tt need to do any calculations about where the top line sits. The OS works it out for you. What's more it will even move your copper list hwne you drag the screen! :-o 1. Okay you need to grab the ViewPort address. You can use ViewPortAddress() with a window. 2. Allocate some memory for a UCopList. And then use the copper functions in graphics.library to write it. 3. Attach it to ViewPort->U­CopIns Here's some E code to help. :-) viewport:=ViewPortAddress(window) rport:=window.rport backrgb:=Int(viewport.colormap.colortable) SetStdRast(rport) Box(0,linestart,width-1,screen.height-1) myucoplist:=AllocMem(SIZEOF ucoplist,MEMF_PUBLIC OR MEMF_CLEAR) CINIT(myucoplist,lines*4) FOR i:=linestart TO lines CWAIT(myucoplist,i,0) CMOVEA(myucoplist,BPLCON3,0) CMOVEA(myucoplist,COLOR+2,(i-linestart) AND $FFF) CMOVEA(myucoplist,BPLCON3,$200) CMOVEA(myucoplist,COLOR+2,($FFF-i) AND $FFF) ENDFOR CWAIT(myucoplist,i,0) CMOVEA(myucoplist,COLOR+2,backrgb) CEND(myucoplist) Forbid() viewport.ucopins:=myucoplist Permit() RethinkDisplay()
SamuraiCrow
SamuraiCrow's picture
Offline
Last seen: 5 years 1 month ago
Joined: 2011-09-18 22:20
Thanks! I'll try your
Thanks! I'll try your example before I write the library.
SamuraiCrow
SamuraiCrow's picture
Offline
Last seen: 5 years 1 month ago
Joined: 2011-09-18 22:20
Now that I've looked at your
Now that I've looked at your code it looks like a color-change similar to the one that appears in the RKRM examples in the example E sources. I'm writing my code in E as a prototype so that's fine but I'd like to discuss some of the pitfalls of having more than one tilemap active at a time. The code needs to be reentrant and shared. That's the main reason I'm making it a system-friendly shared library. If I'm using 2 tilemaps overlapping in dual-playfield mode, there is the possibility that the seam for one playfield may be in a different place than the foreground playfield. In order to get the bitplanes switched mid-screen, I'll need to probably calculate the merging of both copper lists since MrgCop() won't be able to handle both of them. That means I'll have to make the second playfield have a different wait that will be farther to the right than the one for the first. (I'm talking to myself as much as to you right now, Hypex, so I can get my thoughts straight. But for now I'll just try to get it working in one playfield.)
hypex
hypex's picture
Offline
Last seen: 8 hours 23 min ago
Joined: 2011-09-09 16:20
So how did you go with your
So how did you go with your library? Looking back, do dual playfield screens have dual copperlista? I know interlace mode has two copperlists for each frame but I wasn't aware it was the same for dual playfield. I do know that playfield bitplanes are ordered into even and odd planes per field.
SamuraiCrow
SamuraiCrow's picture
Offline
Last seen: 5 years 1 month ago
Joined: 2011-09-18 22:20
I still haven't gotten it to
I still haven't gotten it to work yet. I can tell you that the copper lists have to be merged into one for dual-plafields. The only time you have a hardware-supported second copper list is for interlaced displays (one for the even pixels, one for the odd ones). I think I can get it working in Kickstart 3.x soon. My idea involves making the partial copper-lists appear at different X offsets so that the don't collide when more than one occurs on a line. It may take me a little time to figure it out though. The hardest part is that there is a DyOffset field in the CopList structure but not a DxOffset. I may have to do some serious tinkering.
hypex
hypex's picture
Offline
Last seen: 8 hours 23 min ago
Joined: 2011-09-09 16:20
That's because copper lists
That's because copper lists start on a new line, not halfway through. What happens along the line is up to the copper list. But, you needn't concern yourself with DyOffset, as that is part of the system CopList structure. All you can use is UCopList. Or rather, build up your copper list in it and send it off to the system. I'm not sure what you are tryng to do now. It sounds like you are trying to do some advanced merging of copper lists that run at different points along the line. But that's not how it works to my understanding. As I understand it, all the copper lists involved, be that system and user ones are all stacked vertically on top of one another. So first there is the system list setting up the display, then yours in between and finally the system closing list or simple end. So a merging of these through MrgCop() essentually creates the real hardware copper list in chip ram. The only way you can specify an X position is in a WAIT instruction where Y comes first. It also looks like the system sorts them in Y/X order so you can see how lines are more important here. However, I don't see this as a problem. Even in interlace only one can run at a time. Whatever you need to do should be obtainable in a standard user copper list. AFAIK line 0 is the first line of the screen and 0 across should also be the leftmost of the screen. You don't need to concern yourself with the technical position as the OS will take care of this for you. So, to execute a copper list at some horizontal offset, write a user copper list than waits for the vertical line and the horizontal offset in your copper code. If you like you can make a few user lists, just remembering that they will be stacked in Y/X order. Have you seen the example in the RKM? Also included with AmigaE. :-)
SamuraiCrow
SamuraiCrow's picture
Offline
Last seen: 5 years 1 month ago
Joined: 2011-09-18 22:20
I have seen the example. The
I have seen the example. The conclusion I've been arriving at is that Graphics.library's implementation is incomplete. What I'm trying to do is make a seam so that the top pixels of each playfield will appear somewhere in the middle of the screen as a wraparound effect after the last pixels have been displayed from the screen buffer. Doing it for just one playfield is easy. Merging both playfields are the hard part. If the CPRNEXTBUF union entry had a wrapper function that would let me add it to the MrgCop's data then we should be able to make each line's CMOVEs could be aligned with a single CWAIT at the beginning of each buffer. That's the idea anyway.
hypex
hypex's picture
Offline
Last seen: 8 hours 23 min ago
Joined: 2011-09-09 16:20
What is offered with a user
What is offered with a user copper-list may seem incomplete as it's not made to give you complete control and is limited in what it can offer. But it does give you a way to add a copper-list to a screen easily even if best suited to be a simple one. Perhaps the best thing to do at this point is replicate your copper-list with a small program using hardware banging take over the entire display. Should be simple enough, ensure graphic data is in chip ram, forbid multitasking and then poke your copper-list in, wait for left mouse and then restore the system screen and state back. But what I wonder is how a dual play-field is set-up on the hardware? Does a dual-field require two copper lists like interlace? I would have thought the mode and bitplane pointers would be set along with scroll values and then it would come up? According to an ASM example of dual-playfield mode it is like that.
SamuraiCrow
SamuraiCrow's picture
Offline
Last seen: 5 years 1 month ago
Joined: 2011-09-18 22:20
But what I wonder is how a
But what I wonder is how a dual play-field is set-up on the hardware? Does a dual-field require two copper lists like interlace? I would have thought the mode and bitplane pointers would be set along with scroll values and then it would come up? According to an ASM example of dual-playfield mode it is like that.
Two independent playfields using odd and even bitplane pointers except that they need to share one Copper-list. The second Copper-list is for interlace mode only. The only way to implement independence of Copper instructions for both playfields is to merge them before the beginning of each frame, hence the need for MrgCop.
hypex
hypex's picture
Offline
Last seen: 8 hours 23 min ago
Joined: 2011-09-09 16:20
Okay, perhaps if you link to
Okay, perhaps if you link to the Aminet example I can see what the code is doing, rather than trying to visualise it from a description. So, to summarise, you have have two objectives you wish to solve: 1.) Single playfeld that reverses in centre of screen to seamlessly double the bitmap height with a mirror image. 2.) As above with dual playfields. I take it your bitmap is full height? Your idea would also work well with a half height bitmap. Working this out in my head, the OS would set the top bitplane pointers based on scroll position, so you should be able to skip this in the copperlist and use an OS function to set that. Then, in the copperlist, wait for the centre line and insert a reverse bitplane modulo into the register. This will cause the hardware to read the bitmap in reverse as it draws down the screen. For a dual playfield, set the screen to this mode so the OS knows about it, and repeat the procedure for a second bitmap modulo. Sounds simple enough but the trick is getting it to work in practice. :-D
SamuraiCrow
SamuraiCrow's picture
Offline
Last seen: 5 years 1 month ago
Joined: 2011-09-18 22:20
The bitmap is bigger than
The bitmap is bigger than full screen-height but only slightly. The bitmap is also slightly bigger than full screen-width but only by one or two tile-widths. The idea is to be able to store the top part of the image in the bottom part of the bitmap and the bottom part of the image in the top part of the bitmap. Once complete, the super-bitmap style scrolling will be able to scroll endlessly in the vertical direction because the upper portion of the image (in the bottom of the bitmap) will be set at the top of the display (by the Copper) and the wrap-around seam will be put in the middle of the screen where the bottom part of the image is at the top of the bitmap so its bitplanes are set to the top. Since it takes time to update 32-bit bitplane pointers and there is a possibility that both playfields might have their seams be on the same row of pixels, I was going to allow one row of identical pixels at the top and bottom of the bitmap. The Aminet example is at dev/src/ScollingTrick. It only supports one playfield at a time using the x-limited, y-unlimited algorithm. The docs are in HTML though and you might be able to figure out what is happening for the effect. Also, Georg was kind enough to relicense the code under a public-domain status so don't let the license scare you. If we can get this to work, maybe a version 2.0 of ScrollingTrick is in order.
SamuraiCrow
SamuraiCrow's picture
Offline
Last seen: 5 years 1 month ago
Joined: 2011-09-18 22:20
Re: RethinkDisplay()/MrgCop() on AGA?
Update: It has occurred to me that if I have an extra pixel height in the bottom of the playfield screen buffer that duplicates the top pixel of the playfield buffer, I can just move the copper seam down a pixel for that playfield and keep using the right-border bitplane pointer updates like the original ScrollingTrick did. It doesn't free up the right border for as many color changes as I wanted but at least it would avoid a clash in copper timings for having too many plane pointer updates in the right border.
hypex
hypex's picture
Offline
Last seen: 8 hours 23 min ago
Joined: 2011-09-09 16:20
Re: RethinkDisplay()/MrgCop() on AGA?
Back to this subject. It's been a while. Was looking into it but didn't finish my research. Okay so I've just read up on some docs and it looks like Scroller_YUnlimited2 is the closest to what you want. Granted, it doesn't do dual playfield effects, but it does have the seam trick. It looks like I was on the ball with what is needed, except for the mirror effect, since the bitmap continues from the top again. If we consider AGA and 8 bitplanes in all cases, then 32 pixels across will be needed to reset the bitplanes in the middle. The code uses a trick where it sets the low bitplane pointers by adjusting a modulo, so that only the high bitplane pointers need to be set. This would need only 18 pixels to reset bitplane pointers.You can do this on the line before. On anywhere across the line AFAIK. Now you mention changing colours as well. I don't know where you need to do this but that would complicate things a little more obviously. :-) In any case I should do some experiments. I wrote some OS copper routines years ago in Amiga E. All I need to do is modify the code and update it in an attempt to reprodice the scrolling trick. Which is easier than "porting" the scrolling trick code to be OS friendly. The only caveat is that setting the Y bitmap position or modifying the copper usually casues the OS to recalcuate the copper list and then put it in place. This would seem more inefficient than modfying in place and I would agree it is. But, perhaps appropriate for a double buffer setup where one copper list is displayed as another is calculated. One could always locate the resulting copper list after it is OS built and then modify that instead. Even if that seems like a cheat. But all the needed copper instructions would need to be located so perhaps not the best way about it.
hypex
hypex's picture
Offline
Last seen: 8 hours 23 min ago
Joined: 2011-09-09 16:20
Re: RethinkDisplay()/MrgCop() on AGA?
Okay good news! I've just done some testing the last few days and confirmed you can double a bitmap with an OS copper list.!:-D All that needs to be done is work out how to add some scrolling. And then of course get it working in dual playfield mode. So what this does it setup an OS copper list that waits for the raster to reach midscreen and then resets the bitplane pointer. The result is a double bitmap of the first half and also a colour change to match. The hint is a double title bar whichI kept to show what was going on as well as keeping it simple. :-)
  1. ->OSCopper.e
  2. ->Native graphics example using OS friendly copperlist
  3.  
  4. OPT PREPROCESS
  5.  
  6. MODULE 'graphics/gfxbase',
  7. 'graphics/gfxmacros',
  8. 'graphics/copper',
  9. 'graphics/view',
  10. 'graphics/gfx',
  11. 'graphics/rastport',
  12. 'hardware/custom',
  13. 'intuition/intuition',
  14. 'intuition/screens',
  15. 'exec/memory'
  16.  
  17. ENUM ERR_NONE,ERR_SCREEN,ERR_WINDOW
  18.  
  19. RAISE ERR_SCREEN IF OpenScreenTagList()=NIL,
  20. ERR_WINDOW IF OpenWindowTagList()=NIL,
  21. "MEM" IF AllocMem()=NIL
  22.  
  23. DEF screen=NIL:PTR TO screen,window=NIL:PTR TO window,myucoplist=NIL,i,
  24. viewport:PTR TO viewport,linestart,lines,backrgb,width,rport:PTR TO rastport,
  25. bitmap:PTR TO bitmap,modulo,planesize,bitplane
  26.  
  27. PROC main() HANDLE
  28. DEF x,y
  29.  
  30. KickVersion(37)
  31.  
  32. screen:=OpenScreenTagList(NIL,[SA_TITLE,'OS Copper',
  33. SA_WIDTH, 320,
  34. SA_HEIGHT, 256,
  35.  
  36. NIL])
  37. linestart:=screen.barheight+1
  38. lines:=screen.height-linestart
  39. width:=screen.width
  40.  
  41. window:=OpenWindowTagList(NIL,[WA_IDCMP,IDCMP_MOUSEBUTTONS,
  42. WA_FLAGS,WFLG_NOCAREREFRESH OR
  43. WFLG_ACTIVATE OR
  44. WFLG_BORDERLESS OR
  45. WFLG_BACKDROP,
  46. WA_CUSTOMSCREEN,screen,NIL])
  47.  
  48. viewport:=ViewPortAddress(window)
  49. backrgb:=Int(viewport.colormap.colortable)
  50. rport:=window.rport
  51. bitmap:=screen.rastport.bitmap
  52. modulo:=bitmap.bytesperrow-40
  53. planesize:=bitmap.bytesperrow*screen.height
  54. bitplane:=bitmap.planes[0]
  55.  
  56. SetStdRast(rport)
  57. SetColour(screen,0,0,0,0)
  58. SetColour(screen,1,255,255,255)
  59.  
  60. FOR y:=0 TO 64 STEP 64
  61. FOR x:=0 TO 256 STEP 64
  62. RectFill(rport,x,y,x+31,y+31)
  63. ENDFOR
  64. FOR x:=32 TO 288 STEP 64
  65. RectFill(rport,x,y+32,x+31,y+63)
  66. ENDFOR
  67. ENDFOR
  68.  
  69. myucoplist:=AllocMem(SIZEOF ucoplist,MEMF_PUBLIC OR MEMF_CLEAR)
  70. CINIT(myucoplist,8)
  71. CMOVEA(myucoplist,COLOR+2,$FFF)
  72. CWAIT(myucoplist,127,0)
  73. CMOVEA(myucoplist,BPLPT,Shr(bitplane,16))
  74. CMOVEA(myucoplist,BPLPT+2,bitplane AND $FFFF)
  75. CMOVEA(myucoplist,COLOR+2,$F00)
  76. CEND(myucoplist)
  77.  
  78. Forbid()
  79. viewport.ucopins:=myucoplist
  80. Permit()
  81. RethinkDisplay()
  82.  
  83. WaitLeftMouse(window)
  84. EXCEPT DO
  85. IF window
  86. IF viewport.ucopins
  87. FreeVPortCopLists(viewport)
  88. RemakeDisplay()
  89. ENDIF
  90. CloseWindow(window)
  91. ENDIF
  92.  
  93. IF screen THEN CloseScreen(screen)
  94.  
  95. SELECT exception
  96. CASE ERR_SCREEN; PrintF('Unable to open screen.\n')
  97. CASE ERR_WINDOW; PrintF('Unable to open window.\n')
  98. CASE "MEM"; PrintF('Unable to allocate some memory.\n')
  99. ENDSELECT
  100. ENDPROC
SamuraiCrow
SamuraiCrow's picture
Offline
Last seen: 5 years 1 month ago
Joined: 2011-09-18 22:20
Re: RethinkDisplay()/MrgCop() on AGA?
That's cool. I'm working on a tilemap library to encapsulate the ScrillingTricks in such a way that they will work on their respective chipsets. I can't really do it in AmigaE no matter how much I would like to since its library mode will trash the A4 register instead of storing its globals at the positive offsets of A6 like it is supposed to. I'll do the library in C but then I'll do an OOP wrapper in E to make it easy to use. I've decided against using mid-screen plane pointer updates because I've heard that the plane pointers update in realtime. Also the AGA Copper has an 8-pixel horizontal resolution when the display DMA is active and the FastCopper flag is disabled respectively. I'll do as many updates in the right border as I can.
hypex
hypex's picture
Offline
Last seen: 8 hours 23 min ago
Joined: 2011-09-09 16:20
Re: RethinkDisplay()/MrgCop() on AGA?
First, regarding AmigaE libraries. I've only used the LIBRARY mode to create a testing library. For real world uses I find it impractical. Which with I think you will agree. For example AmigaE creates a library base for each task opening it so it breaks duiing cross-threading calls. But, you can write a library in AmigaE. ;-) You have a few options. Apart from using AmigaE to do it which we just discarded. You can use ECX which looks like it does the job better but it does create a library base for each opener, which you can access in tyour code. Finally you can do it by hand. This is easier in ECX as it offers the OPT NOSTARTUP so you can create what is needed. Possibly you can do the manual method in AmigaE as well but would have redundant code at the start. I've done a hybrid way of doing it in The Maestrix. Easier than doing it all by hand. It runs as a commodity and I setup the library base and add it my self to the system. Here is some example code showing how.
  1. -> Create Library
  2.  
  3. maestixname:='maestix.library'
  4. maestrixbase:=MakeLibrary([{open},{close},{expunge},{extfunc},
  5. {allocMaestro},{freeMaestro},{setMaestro},{getStatus},{transmitData},{receiveData},{flushTransmit},{flushReceive},{startRealtime},{stopRealtime},TRUE],
  6. NIL,{init},SIZEOF maestrixbase,NIL)
  7.  
  8. -> Set up global variables and reset base structures
  9.  
  10. LEA globals(PC),A0
  11. MOVE.L A4,(A0)
  12.  
  13. -> ... Commodoty runs here
  14.  
  15. -> "maestix.library" initialisation and admin rotuines
  16.  
  17. init:
  18. MOVE.L D0,A0
  19. MOVE.B #NT_LIBRARY,LN_TYPE(A0)
  20. MOVE.L maestixname,LN_NAME(A0)
  21. LEA idstring(PC),A1
  22. MOVE.L A1,LIB_IDSTRING(A0)
  23. MOVE #39,LIB_VERSION(A0)
  24. RTS
  25. idstring:
  26. CHAR 'The Maestrix by Damien Stewart',0
  27. globals:
  28. LONG 0
  29. open:
  30. ADDQ.W #1,LIB_OPENCNT(A6)
  31. MOVE.L A6,D0
  32. RTS
  33. close:
  34. SUBQ.W #1,LIB_OPENCNT(A6)
  35. MOVEQ #0,D0
  36. RTS
  37. expunge:
  38. -> MOVE.L A6,A1
  39. -> MOVE.L 4,A6
  40. -> JSR Remove(A6)
  41. extfunc:
  42. MOVEQ #0,D0
  43. RTS
  44.  
  45. -> These are the direct LVO jumps. From here we put the parameters on the stack. Retrieve the globals pointer and call the function.
  46.  
  47. allocMaestro:
  48. MOVEM.L A2-A6/D2-D7,-(A7)
  49. MOVE.L A6,-(A7)
  50. MOVE.L A0,-(A7)
  51. MOVE.L globals(PC),A4
  52. BSR _AllocMaestro
  53. ADDQ.L #8,A7
  54. MOVEM.L (A7)+,A2-A6/D2-D7
  55. RTS
  56.  
  57. -> All the library functions in "high level" language.
  58.  
  59. PROC _AllocMaestro(base:PTR TO maestrixbase,tags=NIL)
  60. DEF maestrobase:PTR TO maestrobase,result=NIL
  61.  
  62. -> ...
  63.  
  64. RETURN result
  65. ENDPROC
As you can see I use a little assembler in there. Both in setup and for the actual jump calls. Which then act like "C" and sticks the parameters on the stack and grabs the global pointer. Then calls the actual high level function. :-)
hypex
hypex's picture
Offline
Last seen: 8 hours 23 min ago
Joined: 2011-09-09 16:20
Re: RethinkDisplay()/MrgCop() on AGA?
Now as to the copper. Yes the plane pointers would update as the screen is being drawn across the monitor. Then after in the horizontal blanking gap the modulo is added for the start location of the next line. Which will be zero for a non-interleaved screen sized bitmap. And in the border area, provided you haven't stretched them out by much, is where you can do your work. But, I wouldn't worry about that plane pointers update. You can reset the pointers in between. And on the line before you can also do a trick. Simply set the modulo for each playfield to the reverse of the bitplane size! And reset it next line. This how the mirroring effect would be produced used in games like Oscar for example to reflect the top screen onto water below. So plane pointers can be handled off screen. And also colours can be handled across the line provided the timing its right and it is set before the index is used.
SamuraiCrow
SamuraiCrow's picture
Offline
Last seen: 5 years 1 month ago
Joined: 2011-09-18 22:20
Re: RethinkDisplay()/MrgCop() on AGA?
Dual playfield mode is really easy to change palette entries on AGA. All I have to do is change the bank select for each playfield to be double-buffered every other row of pixels. This allows me to change almost all 16 palette entries in each playfield for each row of pixels during the display of the other 16-color bank. The only limitation is time used by the Copper. When the display DMA is active, 8 pixels per write is the time requirement. For the full 32-bit palette depth (25 bits used, 8 each for red, green and blue + 1 for genlock transparency), 4 times 8-bits that is needed to get the palette entry made. The bank-switch register bit is set for the high word and reset for the low word respectively for a total of 4 writes. If I use ECS-style 12-bit color entries it reduces it to 1 write per entry. That's not even touching the FastCopper bit behind the right border to allow the Copper to quadruple its write speed.
hypex
hypex's picture
Offline
Last seen: 8 hours 23 min ago
Joined: 2011-09-09 16:20
Re: RethinkDisplay()/MrgCop() on AGA?
By the sounds of it you want the palette to be seperate for each line. Which is not unusual. The copper will be worn out! :-) At least with DP mode you only have two sets of 16 colour palettes to change. You could speed up 24-bit palette writes by doing a set by the bank. For example, select high nibbles, write 16 high nibble words in, then repeat for low nibbles. You still need two copper writes per 24-bit colour but at least you can save a few writes. You could also slightly cheat and simulate a HAM mode by preloading the upper nibbles with preset values. Then just modify the lower nibble value in your copper list. Of course the high nibble is like a MSB for the colour here so maybe not so practical. Another thing I am considering ATM is copper interrupts. IOW a classic raster interupt. I don't know if there are any examples of this anywhere but I'd like to experiement and see how fast or slow the CPU is when writing a palette bank in. Perhaps it could even seam a bitmap in. :-)
SamuraiCrow
SamuraiCrow's picture
Offline
Last seen: 5 years 1 month ago
Joined: 2011-09-18 22:20
Re: RethinkDisplay()/MrgCop() on AGA?
But, I wouldn't worry about that plane pointers update. You can reset the pointers in between. And on the line before you can also do a trick. Simply set the modulo for each playfield to the reverse of the bitplane size! And reset it next line.
I like the sound of that! I'll have to try the negative modulo trick!
Log in or register to post comments