VOGONS

Common searches


CGA Graphics library

Topic actions

Reply 80 of 85, by Zorko

User metadata
Rank Newbie
Rank
Newbie

So, this algorithm is a good starting point. Although it can be slightly improved, since we have one free register.

But it has some drawback. It outputs a sprite that is a multiple of a byte, not a pixel. I don't think we should convert bytes representation to pixels, but we should add another parameter to the sprite property. It may be a mask, or number of "nulled" extra bits of sprite. We need an accurate pixel-by-pixel output. If the "extra" bits on the right are insignificant for the OR/XOR operations, they are still important for AND/PUT.

So we need to improve this subroutine, as well as implement PUT/AND, since it can only work correctly with XOR/OR right now. Otherwise, the pixel accuracy of the sprite width suffers. You understand.

Attachments

Reply 81 of 85, by wbhart

User metadata
Rank Newbie
Rank
Newbie

@zorko Thanks for your efforts here. Sorry I have taken so long to reply, but it is sometimes quite difficult to keep up with everything.

I agree that a sprite should not be a multiple of 4 pixels wide. One way to deal with this is to add an additional "colour" in the sprite which does not really correspond to a colour at all, but which means the pixel is transparent. This is not easy to do efficiently.

Another way is to supply a bit mask along with the sprite and only alter pixels which are marked in the mask. Of course this means taking twice the memory for a sprite, as the mask takes up the same amount of space as the sprite itself. However, this is better than having four copies of the sprite (one for each x position modulo 4).

I once read a comment on Hacker News that said it was possible to mask the edges of a sprite using just one additional AND instruction per byte, adding just 4 cycles per byte. The way he said he did it was to pass a 1-D array of bits which was as wide as the sprite and to use this as a mask for each line of the sprite.

I spent many, many hours trying to figure out how to do this with a sprite compiler, but I have not been successful. I really don't believe it is possible on the 8088/8086. (If someone knows how to do this, I would absolutely love to hear about it. )

However, we are not using a sprite compiler here. If the sprite is written one column of 4 pixels at a time then it is possible to use the same mask, corresponding to that column, over and over again without reading the mask from the 1-D array each time.

However, I still don't see how to do this with just one additional AND instruction. One must AND the pixels from video memory with the complement of the mask and then mask the pixels from the sprite with the mask. Even if the mask byte and its complement are in registers already so that one doesn't have to compute them over and over again, there are still two additional AND instructions.

And I don't see how one can move down a column instead of across a row without incurring additional costs due to the odd/even layout of screen lines in CGA memory.

If anyone has any ideas about this, I'd really like to hear them.

YouTube Channel - PCRetroTech

Reply 82 of 85, by Zorko

User metadata
Rank Newbie
Rank
Newbie
wbhart wrote:

And I don't see how one can move down a column instead of across a row without incurring additional costs due to the odd/even layout of screen lines in CGA memory.

At least for this problem, we have a solution. This can be done as in my code above.

        Calculate whether the first line of the sprite is even or odd. If the odd then goto ODD
EVEN:
Draw the even line
If no more lines to draw, exit
Calculate next column by adding 2000H
ODD:
Draw the odd line
If no more lines to draw, exit
Calculate next column by subtracting 1FB0H
goto EVEN

There is only one feature here. The subroutine for drawing a sprite line should not change the current screen address globally, only locally. But it is very easy to do this by simply saving the address via PUSH at start of DrawLine, and restoring it at end via POP.

  asm       MOV  DI, BX ; <- address of the first line of the sprite
asm CMP BH, 20H ; <- check by the higher byte: is that address of the first line even or odd? (<20H is even; >=20H is odd)
asm JNC ODD
EVEN:
asm CALL @DRAWLINE /* Draw even line */
asm JZ EXIT
asm ADD DI, 2000H ; <- move down a column for even line
ODD:
asm CALL @DRAWLINE /* Draw odd line */
asm JZ EXIT
asm SUB DI, 1FB0H ; <- move down a column for odd line
asm JMP SHORT EVEN

This code was tested and works o.k.

Reply 83 of 85, by wbhart

User metadata
Rank Newbie
Rank
Newbie

@zorko Yes I saw that code. It works, but you are incurring the cost once per line. If we were to draw the sprite in columns instead of rows then the cost would be incurred every byte instead. That is what I meant when I said I don't see how to do it really fast.

YouTube Channel - PCRetroTech

Reply 85 of 85, by dr.zeissler

User metadata
Rank l33t
Rank
l33t

I put it up here so it's perhaps better then the text in yt.

Attachments

  • Filename
    STARS.ASM.zip
    File size
    2.58 KiB
    Downloads
    47 downloads
    File license
    Public domain

Retro-Gamer 😀 ...on different machines