Images |
If we have a closer look, these images are built by pixels (what a surprise):
As we already learned, each pixel in the screen is just a byte, so both the apple and the pear can be
represented by a byte array. (In this lesson, don't ask, how we generated these arrays. Assume we have them
somehow.)
It's really important, that we have to store the sizes as well, without this information we couldn't show the image properly. |
|
Show the image - no transparency
Anyway, the image itself is a rectangular object, so the way we put this to the screen will be similar as we did it for the bars. Remember, in the lesson 5 we used a REP STOSB instruction to draw one pixelline of a bar object. For images, instead of filling up the line with a solid color (STOSB) we have to copy over the pixels from the source array (MOVSB). The basic steps in this method are the following:
Ok, do it then. See the implementation below. Notice, that we use the register pair DS:SI to get the data from the source variable (lds si,src - this is the instruction that takes the pointer). Because the DS is required for the pascal internal work, we have to save it (push DS) at the beginning and load back at the end (pop DS). In the inner loop (CX takes width times) we use the REP MOVSB instruction, this is the one that shows a line of the image.
procedure ShowImage(x,y,width,height:integer; var src); assembler; asm push DS mov ES,SegA000 { Screen segment } mov ax,320 mul y add ax,x mov bx,ax { Address calculation, store the result in BX } cld lds si,src mov dx,height @l0: mov cx,width mov di,bx { show one line from the source data } rep movsb add bx,320 { address for the next line } dec dx jnz @l0 { draw all lines } pop DS end; |
Test
Time to test. We show both fruits on the screen. Notice, that the array definitions are in a different file (fruits.inc) as we don't want to mix the code with pure data.
|
The result as we see on the screen:
The procedure ShowImage obviously works, but there is an issue here. If you see the fruits below, the image of the pear covers some pixels from the previously drawn apple. This is not an error, ShowImage does its job. The problem is that we don't handle the possible transparency, therefore the image covers all pixels inside its rectangular area. So we need another routine that takes care of this issue. |
Show the image - with transparency
If we want some pixels to be transparent, we have to choose a color index (one from the possible 256) as a special one. When an image contains pixel with this color index, instead of showing the pixel, we skip that point, so the background remains. Usually, most of the game programmers use the color index $00 for the transparency. As we know, by default the color $00 is the color black.
Understand, that the $00 is just a palette index and not the color itself. Therefore, even if we use the $00 for the transparent pixels, this DOES NOT MEAN that we can't show the color black on the screen anymore. For example, if you go back to the lesson 6, you will see, that color index 16 ($10) has the color black as well. Anyway, you can define your own colors with the SegRGB procedure, therefore you could setup other indexes as black.
Now, how will the transparent image routine work? Instead of the previous REP MOVSB instruction, we have to take each pixel, check if the value is $00, and if it is, we don't show that pixel. So the internal loop that draws one line will look like this:
@l1: lodsb { get the pixel from the source data } test al,al { skip if the value is zero } jz @skip mov ES:[di],al { put the pixel } @skip: inc di { next pixel position } loop @l1 { draw all pixels in this line }
Do you get me? If the pixel's value is $00, we don't show it, just skip. Apart form this little modification, the rest is the same. Put it together:
procedure ShowImageTransparent(x,y,width,height:integer; var src); assembler; asm push DS mov ES,SegA000 { Screen segment } mov ax,320 mul y add ax,x mov bx,ax { Address calculation, store the result in BX } cld lds si,src mov dx,height @l0: mov cx,width mov di,bx @l1: lodsb { get the pixel from the source data } test al,al { skip if the value is zero } jz @skip mov ES:[di],al { put the pixel } @skip: inc di { next pixel position } loop @l1 { draw all pixels in this line } add bx,320 { address for the next line } dec dx jnz @l0 { draw all lines } pop DS end; |
|
The result now is this:
In this case the color $00 is transparent, therefore we see the background's pixels where the recangular area contains this value. |
Okay, see some notes at the end, because we will use something similar showing sprites on the screen soon...
Downloads: [ Gfx256 unit | Fruits | Normal Images | Transparent images ]