![]() |
![]() |
#1 |
It's coming back!
Join Date: Jul 2018
Location: comp.sys.amiga
Posts: 762
|
Calculations for a simple blit?
I'm having trouble figuring out all the values I need for this, and maybe it will be less frustrating to just ask than to try and work it all out myself.
For context, this is for the direction indicator on the flight sim game I'm attempting. I have an image, 128x7 px (3 interleaved bitplanes), this has the compass points for my direction indicator: [ . N . E . S . W . N . ] I'm trying to grab a 37 px wide segment of that, starting at an x position I've already calculated, and blit it to a fixed point (266, 50) on my instrument panel (also 3 interleaved bitplanes). I'm coming unstuck trying to understand the shifting and masking and first and last words. I've read the "Copying Arbitrary Regions" page in the HRM, but I'm not getting it all. Can anyone help? Code:
static void BlitterCopy(WORD start) { WORD offset = (start >> 3) & 0xfffe; WORD shift = start & 0x000f; KPrintF("start = %ld, offset = %ld, shift = %ld.\n", start, offset, shift); WaitForBlitter(); custom->bltcon0 = (SRCB | SRCC | DEST) | (ABC | ABNC | NABC | NANBC); custom->bltcon1 = (shift << BSHIFTSHIFT); custom->bltafwm = 0x001f; custom->bltalwm = 0xffff; custom->bltadat = 0xffff; custom->bltbpt = headingIndicator + offset; custom->bltcpt = custom->bltdpt = display.displayBuffers[display.back].instrumentsBuffer + 50 * INSTRUMENTS_DISPLAY_DEPTH * DISPLAY_WIDTH_IN_BYTES + 32; // 32 = (266 >> 3) & 0xfffe custom->bltamod = custom->bltbmod = 10; custom->bltcmod = custom->bltdmod = DISPLAY_WIDTH_IN_BYTES - WIDTH_IN_BYTES; custom->bltsize = INSTRUMENTS_DISPLAY_DEPTH * HEIGHT << 6 | WIDTH_IN_WORDS; } The attached screenshot is for values: start = 48, offset = 6, shift = 0.(from the KPrintF). It's gone off the edge of the source. I don't see why. Last edited by deimos; 21 November 2021 at 11:30. |
![]() |
![]() |
#2 |
Registered User
Join Date: Jul 2015
Location: The Netherlands
Posts: 3,464
|
Ok, perhaps this helps:
Masking is just picking which pixels the Blitter ignores. Every bit in the first word mask (BLTAFWM) corresponds to a single pixel of the source image (or mask, but that achieves the same result). These are ordered left to right, so bit 15 is the first pixel of the source/mask, bit 14 the second, etc. In this mask, setting a bit to 1 means the pixels needs to be included into the blit, setting it to 0 means it should be excluded. For the last word mask (BLTALWM), the same goes but rather than applying to the leftmost word of the source/mask, it applies to the rightmost word of the source/mask. As an example: suppose your source image is stored from pixels 13-50. This would mean using the Blitter to grab pixels 0-63. The mask then needs to be set up to ignore pixels 0-12 and 51-63. This would mean setting the BLTAFWM to 0 for bits 15-4 and to 1 for bits 3-0. The last word mask meanwhile needs to be set to 1 for bits 15-13 and to 0 for bits 12-0. Note here that the masks only apply to the non-shifted source (or mask). Shifting is done separately from masking. Shifts only apply to what the Blitter outputs. To shift, the Blitter usually needs to blit one extra word (where any shifted pixels go) and it needs a shift value for both the mask and the source image. This value is just the number of pixels the image needs to be moved to the right from the nearest multiple of 16 pixels to be in the correct position. So, blitting to X=0 means a shift value for A&B channels of 0. Blitting to X=1 means a value of 1, etc. Similarly, blitting to X=28 would mean a shift value of 12 (nearest multiple of 16=16. 28-16=12). Note you can use a bitwise AND to quickly get the number of pixels that need to be shifted. Edit: there is an important caveat I forgot to mention. While the Blitter indeed shifts only after masking, you do have keep in mind that blitting an extra word in the output also blits an extra word from the input. This probably affects the required values for masking. Last edited by roondar; 22 December 2019 at 11:24. |
![]() |
![]() |
#3 | |
It's coming back!
Join Date: Jul 2018
Location: comp.sys.amiga
Posts: 762
|
Quote:
Back in a bit. |
|
![]() |
![]() |
#4 |
Lemon. / Core Design
Join Date: Mar 2016
Location: Tier 5
Posts: 1,220
|
Remember also, the blitting a masked area from one arbitrary x position, to another, may require a subtraction of 2 from the destination address (essentially you are "scrolling" the source image left)
and also if your destination is not word aligned, will require being "or'd" in rather than a straight D=A copy Last edited by DanScott; 22 December 2019 at 11:59. |
![]() |
![]() |
#5 | |
It's coming back!
Join Date: Jul 2018
Location: comp.sys.amiga
Posts: 762
|
Quote:
|
|
![]() |
![]() |
#6 |
Registered User
Join Date: Jun 2016
Location: europe
Posts: 1,097
|
Not going to tell you how to design stuff, but I have to say you are... too artistic :P.
266? 37? What's wrong with nicely rounded sizes and coords, multiples of 16. Makes life much easier. Now, about how you shift B (heading image)... If the offset if say 1 and you have to skip the first pixel, you have to shift towards the left. And since you are blitting top-to-bottom/left-to-right, blitter shifts towards the right, you actually have to shift B by 16-1 and adjust pointer. And additionally, since your D pixel is not word-aligned, it starts at bit 266&$000f = 10 (256+10), you have to shift B into position 10. So even if the offset is 0, you still have to shift B by 10 towards the right. This is all easier with say x=272, and width=32 (maybe too narrow) wouldn't hurt either but it's just extra masking if it's not. |
![]() |
![]() |
#7 | |
It's coming back!
Join Date: Jul 2018
Location: comp.sys.amiga
Posts: 762
|
Quote:
If I can get the first step of blitting with shifting without masking to work correctly I'll be back, but at the moment that just seems to be randomly broken. |
|
![]() |
![]() |
#8 | |
Registered User
Join Date: Jul 2015
Location: The Netherlands
Posts: 3,464
|
Quote:
![]() When using the Blitter, it makes your life a lot easier if the source images are aligned to 16 pixel boundaries because the Blitter only ever operates on data a word at a time (which corresponds to 16 pixels in memory). Like a/b said, it's not for me to tell you how to design your source images. But still, it's worth a thought. |
|
![]() |
![]() |
#9 | |
It's coming back!
Join Date: Jul 2018
Location: comp.sys.amiga
Posts: 762
|
Quote:
Last edited by deimos; 21 November 2021 at 11:30. |
|
![]() |
![]() |
#10 | |
Registered User
Join Date: Jul 2015
Location: The Netherlands
Posts: 3,464
|
Quote:
*) Assuming it's stored in memory in a sane, Amiga friendly way - which is normally the case. |
|
![]() |
![]() |
#11 | |
It's coming back!
Join Date: Jul 2018
Location: comp.sys.amiga
Posts: 762
|
Quote:
Right now all I expect is to be able to take parts of it to blit to my fixed destination. But, that's not working at all, as if my shift and offsets aren't calculated correctly, but I can't see how that could be incorrect: Code:
WORD offset = ((start >> 3) & 0xfffe); WORD shift = start & 0x000f; // ... custom->bltcon1 = (shift << BSHIFTSHIFT); // ... custom->bltbpt = headingIndicator + offset; For example, when start = 87, I get offset = 10 and shift = 7, which looks sensible to me, but what gets blit looks corrupted, as if it's gone round the edge of the bitmap? Last edited by deimos; 21 November 2021 at 11:30. |
|
![]() |
![]() |
#12 | |
It's coming back!
Join Date: Jul 2018
Location: comp.sys.amiga
Posts: 762
|
Quote:
My shifting is still not right though, working on that. |
|
![]() |
![]() |
#13 |
It's coming back!
Join Date: Jul 2018
Location: comp.sys.amiga
Posts: 762
|
|
![]() |
![]() |
#14 | |
It's coming back!
Join Date: Jul 2018
Location: comp.sys.amiga
Posts: 762
|
Quote:
Code:
static void BlitterCopy(WORD start) { WORD offset = ((start >> 3) & 0xfffe); WORD shift = 15 - (start & 0x000f); KPrintF("start = %ld, offset = %ld, shift = %ld.\n", start, offset, shift); WaitForBlitter(); custom->bltcon0 = (SRCB | SRCC | DEST) | (ABC | ABNC | NABC | NANBC); custom->bltcon1 = (shift << BSHIFTSHIFT); custom->bltafwm = 0x001f; custom->bltalwm = 0x0000; custom->bltadat = 0xffff; custom->bltbpt = (APTR) headingIndicator + offset; custom->bltcpt = custom->bltdpt = display.displayBuffers[display.back].instrumentsBuffer + 50 * INSTRUMENTS_DISPLAY_DEPTH * DISPLAY_WIDTH_IN_BYTES + 32; custom->bltamod = custom->bltbmod = 8; custom->bltcmod = custom->bltdmod = DISPLAY_WIDTH_IN_BYTES - WIDTH_IN_BYTES; custom->bltsize = INSTRUMENTS_DISPLAY_DEPTH * HEIGHT << 6 | WIDTH_IN_WORDS; } Last edited by deimos; 21 November 2021 at 11:30. |
|
![]() |
![]() |
#15 |
Registered User
Join Date: Jul 2015
Location: The Netherlands
Posts: 3,464
|
About adding a word for shifting. I find it helps to consider the Blitter as if it's working on a stream of memory, rather than a rectangular block of memory. Whenever the Blitter reaches the rightmost word of the block it is blitting, it adds the modulo and continues blitting as if there is no gap in memory. If it's shifting, it does a bitwise shift once every time it should blit on a new line.
Kind of like this: Code:
Some part of the screen <some stuff on the left>.xx.xx.<some stuff on the right> <some stuff on the left>x..x..x<some stuff on the right> <some stuff on the left>...xxx.<some stuff on the right> <some stuff on the left>xx..x.x<some stuff on the right> Same, as stored in memory <some bytes>.xx.xx.<some bytes>x..x..x<some bytes>...xxx.<some bytes>xx..x.x<some bytes> Same, as seen by the Blitter after modulos are applied <some bytes>.xx.xx.x..x..x...xxx.xx..x.x<some bytes> Same, after three pixel shift by Blitter <some bytes>....xx.xx....x..x..x......xx<some bytes> Now, doing this will obviously create corruption without some additional measures. This is where the extra word comes in. By adding an extra word to blit for both source and destination, there is some 'space' to shift in the extra bits we end up with. If this word is kept empty in the source, the extra pixels can fit there without corruption showing up. So let's repeat this, but now with the extra word for shifting Code:
Some part of the screen <some stuff on the left>.xx.xx.****<some stuff on the right> <some stuff on the left>x..x..x****<some stuff on the right> <some stuff on the left>...xxx.****<some stuff on the right> <some stuff on the left>xx..x.x****<some stuff on the right> Same, as stored in memory <some bytes>.xx.xx.****<some bytes>x..x..x****<some bytes>...xxx.****<some bytes>xx..x.x****<some bytes> Same, as seen by the Blitter after modulos are applied <some bytes>.xx.xx.****x..x..x****...xxx.****xx..x.x****<some bytes> Same, after three pixel shift by Blitter <some bytes>....xx.xx.*...x..x..x*......xxx.*...xx..x.x*<some bytes> The * represent the extra word blit This can however be solved by using the Blitter's last word mask (BLTALWM) feature and changing the source modulo's. Without getting into the details (this post is long enough as it is), you change the source modulo from 0 to -2 and change the last word mask from #$ffff to #$0000. This way you'll still need to blit the extra word per line, but no longer need to store empty space in memory for it. Edit: just to be clear, my diagrams are not full words per line. Just pretend they are ![]() Last edited by roondar; 22 December 2019 at 16:55. Reason: Corrected my diagram (again!) |
![]() |
![]() |
#16 | |
It's coming back!
Join Date: Jul 2018
Location: comp.sys.amiga
Posts: 762
|
Quote:
I'm extracting a variable part of my source image strip [ N E S W] - if I'm facing north I'll extract essentially the left quarter [ N ], if I'm facing south I'll take the middle quarter [ S ]. From your first reply to this thread, I believe I should set up the first and last word masks according to what I want to extract, regardless of how it's going to be shifted in the output. I'm not currently doing this. I should set my blit size to be bigger by one word to allow for the shifts (and adjust the modulo to match). I should widen my image to make sure there are bits to shift, but I already repeat part of the image to allow for wrap-around, so maths might mean it's not needed, I'll check. I guess I need a separate mask and shifting to get things into the right spot on the output without overwriting stuff. But then these shifts need to be coordinated with the shifts needed to extract the source? |
|
![]() |
![]() |
#17 | |
It's coming back!
Join Date: Jul 2018
Location: comp.sys.amiga
Posts: 762
|
Quote:
|
|
![]() |
![]() |
#18 |
It's coming back!
Join Date: Jul 2018
Location: comp.sys.amiga
Posts: 762
|
Got it!
Thank you everyone. Edit: For those playing along at home, this is the working version I've come up with: Code:
const WORD fwms [16] = { 0xffff, 0x7fff, 0x3fff, 0x1fff, 0x0fff, 0x07ff, 0x03ff, 0x01ff, 0x00ff, 0x007f, 0x003f, 0x001f, 0x000f, 0x0007, 0x0003, 0x0001 }; const WORD lwms [16] = { 0x8000, 0xc000, 0xe000, 0xf000, 0xf800, 0xfc00, 0xfe00, 0xff00, 0xff80, 0xffc0, 0xffe0, 0xfff0, 0xfff8, 0xfffc, 0xfffe, 0xffff }; static void BlitterCopy(const WORD startX) { const WORD sourceShift = startX & 0x000f; const WORD destinationShift = (11 + (16 - sourceShift)) & 0x000f; const WORD byteOffset = (startX >> 3) & 0xfffe; WaitForBlitter(); custom->bltcon0 = (destinationShift << ASHIFTSHIFT) | (SRCB | SRCC | DEST) | (ABC | ABNC | NABC | NANBC); custom->bltcon1 = destinationShift << BSHIFTSHIFT; custom->bltafwm = fwms[sourceShift]; custom->bltalwm = lwms[(sourceShift + 4) & 0x000f]; custom->bltadat = 0xffff; custom->bltbpt = (APTR) headingIndicator + byteOffset; if (sourceShift <= 11) { custom->bltcpt = custom->bltdpt = display.displayBuffers[display.back].instrumentsBuffer + 50 * INSTRUMENTS_DISPLAY_DEPTH * DISPLAY_WIDTH_IN_BYTES + 32; custom->bltamod = custom->bltbmod = SOURCE_WIDTH_IN_BYTES - WIDTH_IN_BYTES; custom->bltcmod = custom->bltdmod = DISPLAY_WIDTH_IN_BYTES - WIDTH_IN_BYTES; custom->bltsize = (INSTRUMENTS_DISPLAY_DEPTH * HEIGHT << 6) | WIDTH_IN_WORDS; } else { custom->bltcpt = custom->bltdpt = display.displayBuffers[display.back].instrumentsBuffer + 50 * INSTRUMENTS_DISPLAY_DEPTH * DISPLAY_WIDTH_IN_BYTES + 32 - 2; custom->bltamod = custom->bltbmod = SOURCE_WIDTH_IN_BYTES - (WIDTH_IN_BYTES + 2); custom->bltcmod = custom->bltdmod = DISPLAY_WIDTH_IN_BYTES - (WIDTH_IN_BYTES + 2); custom->bltsize = (INSTRUMENTS_DISPLAY_DEPTH * HEIGHT << 6) | (WIDTH_IN_WORDS + 1); } } Last edited by deimos; 24 December 2019 at 09:41. |
![]() |
![]() |
#19 |
Registered User
Join Date: Jul 2015
Location: The Netherlands
Posts: 3,464
|
|
![]() |
![]() |
#20 |
It's coming back!
Join Date: Jul 2018
Location: comp.sys.amiga
Posts: 762
|
This week I hope to actually have the planes moving around rather than just spinning round on fixed positions.
But before I build a physics model I want a visual representation of the throttle position on the screen. Every attempt I've made to draw something has ended up looking like the slider on a 1980s Amstrad stereo. I want to do this once, as it's a pain to lay out the pixels for every change, and I seem to have hit the limits of my pixel art skills. Edit: I've just spent all afternoon trying to draw something, and searching for examples to copy, I think I might just have to give up. I'd hire a pixel artist, but I think my requirements will be too hard to work with someone else with. Last edited by deimos; 21 November 2021 at 12:01. |
![]() |
Currently Active Users Viewing This Thread: 1 (0 members and 1 guests) | |
Thread Tools | |
![]() |
||||
Thread | Thread Starter | Forum | Replies | Last Post |
How to calculate possible blit times? | Tigerskunk | Coders. Asm / Hardware | 32 | 11 January 2022 08:24 |
Blitz- cannot blit a shape | peceha | Coders. Blitz Basic | 8 | 10 April 2021 23:56 |
BLIT interrupts being triggered, even when disabled? | deimos | Coders. General | 21 | 30 September 2019 21:43 |
Copper Interrupts and Blit Performance | mcgeezer | Coders. Asm / Hardware | 14 | 04 May 2019 02:15 |
[BlitzBasic] blit outside bitmap error | Raislin77it | Coders. Blitz Basic | 8 | 08 February 2014 11:42 |
|
|