HGFX Intro, part 5 In the fifth part of the introduction to HGFX, we will talk about two basic and often used system functions, combined with the value PlanarMask. In the beginning let's repeat with an example to make sure we understand how to work with bitmaps, to become familiar with graphics layers. Controlling the HGFX is simple if you are experienced in bitplanes (mainly because of colours), other things to do are easy then. Example: We need a three-colour sprite, an arrow. Because we write into bitplanes, we have graphic data prepared in layers. On the ZX Spectrum, there are mostly monochrome or two-colour sprites, i.e. 1 bitmap (1 layer, possibly with a mask), in which active bits specify the image and zeros mean an empty space where is nothing or a background is rendered. For our three colours we need 2 layers (they allow up to 4 colours). Folded layers will give us the desired result. With the arrow, we intend that: colour no.1 will colour the shiny (top) half of the arrow colour no.2 the matte (bottom) half of the arrow colour no.3 edges and the spine of the arrow In the rows, the colours are arranged as follows: Colour 1 Colour 2 Colour 3 b0 1 0 1 b1 0 1 1 By putting everything "on top of each other" in the planar, are bits, lying on top of each other in individual layers, connected and provide the expected colour. In our case, for example, colour No. 3 must have a bit set in each layer. Both layers and the displayed result look like this: 1. layer 2. layer Result + + + + + + + + + + + + + + + + # # # # # # # # + + + + + + + . + + . . . . + . # # @ @ @ @ # . + . + + + + . . + + + . . + . . # % # @ @ # . . + . . + + + + . + + + + . . + . # % % # @ @ # . + . . . + + + + + + + + + . . + # % % % # @ @ # + . + . . + + . + + + + + + + . # % # % % # # . + + . + . + . . + + . + + + . . # # . # % # . . + . . . + . . . + . . . + . . . # . . . # . . . We will place the arrow in bitplanes 3 and 4. That means the first arrow-graphics layer will go to bitplane 3 and the second layer to bitplane 4. We will set the desired colour beforehand. Let's draw then: 1. PlanarMask value = 8 (000001000 bin, i.e. bitplane no.3) 2. We render the first layer of the sprite. 3. PlanarMask value = 16 (000010000 bin, i.e. bitplane no.4) 4. We render the second layer of the sprite. Even though it would seem that re-printing sprite graphics layers into bitplanes (a kind of stamping across bitplanes) must slow down programs, it won't happen. With the HGFX, we save time not only that we selectively work with bitplanes and graphics layers, and we also use offsets, so do not have to scroll graphics bit by bit. This is supported by simple but very fast special functions for copying and deleting. As a result, even with 16 sprite colours, the HGFX is faster than original ZX Spectrum monochrome or attribute graphics. How different graphics can be combined, in several layers and with a different number of colours, we will show in the example of a flying owl (famous animation from Agony demo). In the HGFX version, you can find it at at https://vimeo.com/429052052 Static, animated and scrolling graphics areas of this demo are divided between the bitplanes, with the ratio 1 : 3 : 2 : 2 Bitplanes: / grass / no. 0 (nearest foreground) ------------------ / no. 1 =================== ------------------ / no. 2 trees (foreground) ------------------ / no. 3 =================== ------------------ / no. 4 logo ------------------ and / no. 5 flying owl ------------------ / no. 6 =================== ------------------ dark forest / no. 7 (background) ------------------ Naturally, the owl, the main object on the screen requires the most colours. Its graphic data is copied into 3 bitplanes. An interesting thing, apart from the planar layers, is that the farthest background with the moon and stars is not stored in any bitplane, but in the ZX-screen. ZX-screen "shines" through bitplanes where HGFX is colour #0. In addition to the 8 bitplanes, there is one more layer, the classic ZX with coloured attributes. COPY_ALL and ERASE_ALL are parts of a separate unit in HGFX. These are functions, which can do two useful actions: on command, they will perform either copying or deleting, within the entire buffer. Both functions will start by a command, written to a memory HGFX register. COPY_ALL always copies the entire content of the videoRAM from one buffer (source) to another (destination). While doing so, it is governed by value PlanarMask, which allows you to copy only some bits of each point, i.e. copy only some bitplans. ERASE_ALL fills the entire buffer with zeros. The PlanarMask says, which bitplans are involved. So it erases, through the mask, chosen layers - bitplanes (when we have a value of 0 in PlanarMask, no bit mask is set, nothing is deleted). Both functions process the entire videoRAM and that takes some time. During this period is not suitable to work with videoram, but the Z80-CPU can do other activity. To find out that a function has ended and we can reach again buffers, the STATUS memory registr is used. For a quick idea, a matter of speed: the COPY operation takes less than two milliseconds, the ERASE a little more than 1 millisecond. For programmers: the COPY_ALL time is well remembered, 3.5 MHz machine implementation this function takes 6144 T-states :-)