Output of black and white images with gradations of brightness

ZXNet echo conference «code.zx»

From Ivan Roshin To All 2 October 2002

Hello, All! ═══════════════════ 01 .C ══════════════════ (c) Ivan Roshchin, Moscow Fido: 2:5020/689.53 ZXNet: 500:95/462.53 E-mail: bestview@mtu-net.ru WWW: http://www.ivr.da.ru Output of black and white images with gradations of brightness ═════════════════════════ ═════════════════════════ ("Radiomir. Your computer" 8-10/2002) (Last edit date: 09/28/2002) As you probably already guessed :), we will talk about various ways to display black and white images on the ZX Spectrum screen with gradations of brightness. To be specific, let us assume that the size images - 256*192, which corresponds to the ZX screen resolution Spectrum, and the number of brightness gradations is 256. It is clear that about real 256 gradations of brightness on the ZX Spectrum we can only dream, so we can only deduce something similar to the original image. How can you determine which withdrawal method is better? Of course you can compare the original and resulting images “by eye”. But it is much more convenient to have an objective criterion - calculated by to some formula a value (let’s denote it R) reflecting the difference between these images: from 0 (the images are the same) to 1 (maximum difference). About how exactly I determined this value, you can read in Appendix 1. Next, next to each image, obtained by using one or another withdrawal method, II will give the value of R. Yes, but what image should we take as the initial one? Here it: ┌─────────────────────────┐ │ bw_s_1.pcx │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └─────────────────────────┘ Fig. 1 So, the first withdrawal method. All pixels with less brightness 128 is displayed in black, and with a brightness of 128 or more - in white: ┌─────────────────────────┐ │ bw_s_2.pcx │ │ │ │ │ │ │ R = 0.0906 │ │ │ │ │ │ │ │ └─────────────────────────┘ Fig. 2 The next method is using so-called “chunks”. In each 4*4 square we display one of the 17 textures with the most close brightness level (in the first texture all 16 pixelsblack, in the second - 15 black and 1 white... in the last - all 16 pixels white). Thus, 17 pseudogradations are obtained brightness ┌─────────────────────────┐ │ bw_s_3.pcx │ │ │ │ │ │ │ R = 0.0708 │ │ │ │ │ │ │ │ └─────────────────────────┘ Fig. 3 Consider such an image (as well as images obtained using the methods described below) preferably not at close range, when it is perceived as a jumble pixels, and from afar, when the brightness of neighboring pixels averaged. If you cannot move away from the monitor long enough distance, or from such a distance the image seems very small, then you can achieve the same effect by “blurring” image - to do this, just install it in front of the screen filter made of translucent polyethylene film. Another withdrawal method. For each pixel (not for plot 4*4, as in the previous method) we determine the most texture similar in brightness and display a pixel from this textures. The coordinates of the pixel that is taken from the texture areare defined as the remainders from dividing the pixel coordinates by image to texture size. In Fig. 4a shows the image obtained when using 17 4*4 textures, and in Fig. 4b - when using 256 textures 16*16 (actually there are 257, not 256, but, since in the original image has only 256 gradations of brightness, one of the textures not used). ┌─────────────────────────┐ ┌─────────────────────────┐ │ bw_s_4a.pcx │ │ bw_s_4b.pcx │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └─────────────────────────┘ └─────────────────────────┘ R = 0.0683 R = 0.0680 a) b) Fig. 4 ════════════════════════ ════════════════════════ Best regards, Ivan Roshchin.

From Ivan Roshin To All 2 October 2002

Hello, All! ═══════════════════ 01 .C ══════════════════ (c) Ivan Roshchin, Moscow Fido: 2:5020/689.53 ZXNet: 500:95/462.53 E-mail: bestview@mtu-net.ru WWW: http://www.ivr.da.ru Output of black and white images with gradations of brightness ═════════════════════════ ═════════════════════════ ("Radiomir. Your computer" 8-10/2002) (Last edit date: 09/28/2002) As you probably already guessed :), we will talk about various ways to display black and white images on the ZX Spectrum screen with gradations of brightness. To be specific, let us assume that the size images - 256*192, which corresponds to the ZX screen resolution Spectrum, and the number of brightness gradations is 256. It is clear that about real 256 gradations of brightness on the ZX Spectrum we can only dream, so we can only deduce something similar to the original image. How can you determine which withdrawal method is better? Of course you can compare the original and resulting images “by eye”. But it is much more convenient to have an objective criterion - calculated by to some formula a value (let’s denote it R) reflecting the difference between these images: from 0 (the images are the same) to 1 (maximum difference). About how exactly I determined this value, you can read in Appendix 1. Next, next to each image, obtained by using one or another withdrawal method, II will give the value of R. Yes, but what image should we take as the initial one? Here it: ┌─────────────────────────┐ │ bw_s_1.pcx │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └─────────────────────────┘ Fig. 1 So, the first withdrawal method. All pixels with less brightness 128 is displayed in black, and with a brightness of 128 or more - in white: ┌─────────────────────────┐ │ bw_s_2.pcx │ │ │ │ │ │ │ R = 0.0906 │ │ │ │ │ │ │ │ └─────────────────────────┘ Fig. 2 The next method is using so-called “chunks”. In each 4*4 square we display one of the 17 textures with the most close brightness level (in the first texture all 16 pixelsblack, in the second - 15 black and 1 white... in the last - all 16 pixels white). Thus, 17 pseudogradations are obtained brightness ┌─────────────────────────┐ │ bw_s_3.pcx │ │ │ │ │ │ │ R = 0.0708 │ │ │ │ │ │ │ │ └─────────────────────────┘ Fig. 3 Consider such an image (as well as images obtained using the methods described below) preferably not at close range, when it is perceived as a jumble pixels, and from afar, when the brightness of neighboring pixels averaged. If you cannot move away from the monitor long enough distance, or from such a distance the image seems very small, then you can achieve the same effect by “blurring” image - to do this, just install it in front of the screen filter made of translucent polyethylene film. Another withdrawal method. For each pixel (not for plot 4*4, as in the previous method) we determine the most texture similar in brightness and display a pixel from this textures. The coordinates of the pixel that is taken from the texture areare defined as the remainders from dividing the pixel coordinates by image to texture size. In Fig. 4a shows the image obtained when using 17 4*4 textures, and in Fig. 4b - when using 256 textures 16*16 (actually there are 257, not 256, but, since in the original image has only 256 gradations of brightness, one of the textures not used). ┌─────────────────────────┐ ┌─────────────────────────┐ │ bw_s_4a.pcx │ │ bw_s_4b.pcx │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └─────────────────────────┘ └─────────────────────────┘ R = 0.0683 R = 0.0680 a) b) Fig. 4 ════════════════════════ ════════════════════════ Best regards, Ivan Roshchin.

From Ivan Roshin To All 2 October 2002

Hello, All! ═══════════════════ 02.C ══════════════════ This was, so to speak, an introduction. :) Already considered known withdrawal methods, which, as you may have noticed, are not are of sufficient quality. And now we will talk about on how to get the most out of the ZX Spectrum. I I’ll tell you about ways to improve the quality of output The images are great! Look: on the ZX Spectrum we have 8 colors available with two gradations of brightness (bright=0 and bright=1). Because the color is black with bright=1 it remains black, in total there are not 16 colors, but 15. When displaying in black and white, these 15 colors turn into 15 gradations of brightness. Through their use and You can improve the image quality! Naturally, this requires that the ZX Spectrum be connected to a black and white monitor or TV (or to color, but with the ability to switch to black and white mode). But even if this is not the case in your case, I still advise read the article to the end: suddenly something turns out to be useful. Let me immediately note that a method based on this effect output of black and white images with gradations of brightness can be used on computers other than the ZX Spectrum, on which The image may be in color, but there is no grayscale. By the way, it seems to me (I haven’t tested it in practice) thatgetting a black and white image on a color monitor is enough build a simple adapter: three signals R, G, B coming from computer, convert it into one (black and white) and send it to monitor inputs R, G, B, that's all. At the same time, from the details only a few resistances are needed. So how to display an image? Obviously, first you need determine the brightness of each of the available 15 gradations - the number in range 0-255. The story about how to do this turned out to be quite voluminous, and I decided to include it in Appendix 2. A Now we will assume that the brightnesses have been calculated and we have received values a0-a7 for colors 0-7 with bright=0 and values b0-b7 for the same colors with bright=1. Since the attributes are set for familiarity (8*8 pixels), We will display the image familiarly. Let's consider the process output of one familiar place. Let MIN_PIX and MAX_PIX be the minimum and maximum brightness levels in the current familiarity of the original images. Let MIN and MAX be the brightness of paper and ink (if bright is selected) in the current familiarity output image. Knowing MIN_PIX and MAX_PIX, you need to determine familiarity attributes (ink, paper and bright) so that conditions: MIN <= MIN_PIX, MAX >= MAX_PIX. Obviously, in the majority In some cases this can be done in more than one way. Then from of all possible pairs (MIN, MAX) we choose such that the differencebetween MAX and MIN was the smallest. In order not to go through all 128 possible combinations of ink, paper and bright, it’s convenient to do the following. First we check is the condition MAX_PIX > a(7) satisfied? If yes, then bright is not may be equal to 0, i.e. bright=1. Among b0-b7 we find maximum b(i), under which the condition b(i) <= MIN_PIX, and the minimum b(j) at which the condition is satisfied b(j) >= MAX_PIX. Then paper=i, and ink=j. If MAX_PIX <= a(7), you will have to consider two options: bright=0 and bright=1. Find b(i) and b(j) as described above. Then, among a0-a7, we find the maximum a(k), at which the condition a(k) <= MIN_PIX is satisfied, and the minimum a(l), with which fulfills the condition a(l) >= MAX_PIX. Now we need to choose of two pairs (b(i),b(j)), (a(k),a(l)) such that the difference between values are less. If this is the first pair, then bright=1, ink=j, paper=i. If the second pair, then bright=0, ink=l, paper=k. After the attributes of the familiarity are determined, it remains find out which pixels in it will be ink colors and which ones will be paper colors. B In the previous output method we received 257 pseudogradations of brightness between black and white using 257 16*16 textures. Well, in this way we can get using the same textures 257 pseudo- gradations between MIN and MAX. For each pixel we define texture that is closest in brightness and display the pixel on the screen from this texture.This is what happens with this method of output. Isn't it true? Has the image quality improved significantly? ┌─────────────────────────┐ │ bw_s_5.pcx │ │ │ │ │ │ │ R = 0.0106 │ │ │ │ │ │ │ │ └─────────────────────────┘ Fig. 5 The procedure for outputting an image in this way is given in Appendix 3. There you will also find procedures for methods described below. To further improve image quality, you can use the so-called multicolor effect. Its essence is the following: if you change the familiarity attribute when the beam is already drew part of it on the screen, then the rest of the familiarity will be drawn with the new attribute value. It's possible increase vertical attribute resolution. If you need to double the resolution (i.e. set your attribute for each half of the familiarity area - an area measuring 8*4 pixel), it is more convenient not to overwrite attribute values when drawing the image, and do this: build the top half familiarize themselves with their attributes on one screen, the bottomhalves with their attributes - on the other, and then switch screens every time the next 4 lines of pixels are drawn (i.e. the top or bottom half of the line is familiar). This is what happens with this output method: ┌─────────────────────────┐ │ bw_s_6.pcx │ │ │ │ │ │ │ R = 0.0090 │ │ │ │ │ │ │ │ └─────────────────────────┘ Fig. 6 ════════════════════════ ════════════════════════ Best regards, Ivan Roshchin.

From Ivan Roshin To All 2 October 2002

Hello, All! ═══════════════════ 02.C ══════════════════ This was, so to speak, an introduction. :) Already considered known withdrawal methods, which, as you may have noticed, are not are of sufficient quality. And now we will talk about on how to get the most out of the ZX Spectrum. I I’ll tell you about ways to improve the quality of output The images are great! Look: on the ZX Spectrum we have 8 colors available with two gradations of brightness (bright=0 and bright=1). Because the color is black with bright=1 it remains black, in total there are not 16 colors, but 15. When displaying in black and white, these 15 colors turn into 15 gradations of brightness. Through their use and You can improve the image quality! Naturally, this requires that the ZX Spectrum be connected to a black and white monitor or TV (or to color, but with the ability to switch to black and white mode). But even if this is not the case in your case, I still advise read the article to the end: suddenly something turns out to be useful. Let me immediately note that a method based on this effect output of black and white images with gradations of brightness can be used on computers other than the ZX Spectrum, on which The image may be in color, but there is no grayscale. By the way, it seems to me (I haven’t tested it in practice) thatgetting a black and white image on a color monitor is enough build a simple adapter: three signals R, G, B coming from computer, convert it into one (black and white) and send it to monitor inputs R, G, B, that's all. At the same time, from the details only a few resistances are needed. So how to display an image? Obviously, first you need determine the brightness of each of the available 15 gradations - the number in range 0-255. The story about how to do this turned out to be quite voluminous, and I decided to include it in Appendix 2. A Now we will assume that the brightnesses have been calculated and we have received values a0-a7 for colors 0-7 with bright=0 and values b0-b7 for the same colors with bright=1. Since the attributes are set for familiarity (8*8 pixels), We will display the image familiarly. Let's consider the process output of one familiar place. Let MIN_PIX and MAX_PIX be the minimum and maximum brightness levels in the current familiarity of the original images. Let MIN and MAX be the brightness of paper and ink (if bright is selected) in the current familiarity output image. Knowing MIN_PIX and MAX_PIX, you need to determine familiarity attributes (ink, paper and bright) so that conditions: MIN <= MIN_PIX, MAX >= MAX_PIX. Obviously, in the majority In some cases this can be done in more than one way. Then from of all possible pairs (MIN, MAX) we choose such that the differencebetween MAX and MIN was the smallest. In order not to go through all 128 possible combinations of ink, paper and bright, it’s convenient to do the following. First we check is the condition MAX_PIX > a(7) satisfied? If yes, then bright is not may be equal to 0, i.e. bright=1. Among b0-b7 we find maximum b(i), under which the condition b(i) <= MIN_PIX, and the minimum b(j) at which the condition is satisfied b(j) >= MAX_PIX. Then paper=i, and ink=j. If MAX_PIX <= a(7), you will have to consider two options: bright=0 and bright=1. Find b(i) and b(j) as described above. Then, among a0-a7, we find the maximum a(k), at which the condition a(k) <= MIN_PIX is satisfied, and the minimum a(l), with which fulfills the condition a(l) >= MAX_PIX. Now we need to choose of two pairs (b(i),b(j)), (a(k),a(l)) such that the difference between values are less. If this is the first pair, then bright=1, ink=j, paper=i. If the second pair, then bright=0, ink=l, paper=k. After the attributes of the familiarity are determined, it remains find out which pixels in it will be ink colors and which ones will be paper colors. B In the previous output method we received 257 pseudogradations of brightness between black and white using 257 16*16 textures. Well, in this way we can get using the same textures 257 pseudo- gradations between MIN and MAX. For each pixel we define texture that is closest in brightness and display the pixel on the screen from this texture.This is what happens with this method of output. Isn't it true? Has the image quality improved significantly? ┌─────────────────────────┐ │ bw_s_5.pcx │ │ │ │ │ │ │ R = 0.0106 │ │ │ │ │ │ │ │ └─────────────────────────┘ Fig. 5 The procedure for outputting an image in this way is given in Appendix 3. There you will also find procedures for methods described below. To further improve image quality, you can use the so-called multicolor effect. Its essence is the following: if you change the familiarity attribute when the beam is already drew part of it on the screen, then the rest of the familiarity will be drawn with the new attribute value. It's possible increase vertical attribute resolution. If you need to double the resolution (i.e. set your attribute for each half of the familiarity area - an area measuring 8*4 pixel), it is more convenient not to overwrite attribute values when drawing the image, and do this: build the top half familiarize themselves with their attributes on one screen, the bottomhalves with their attributes - on the other, and then switch screens every time the next 4 lines of pixels are drawn (i.e. the top or bottom half of the line is familiar). This is what happens with this output method: ┌─────────────────────────┐ │ bw_s_6.pcx │ │ │ │ │ │ │ R = 0.0090 │ │ │ │ │ │ │ │ └─────────────────────────┘ Fig. 6 ════════════════════════ ════════════════════════ Best regards, Ivan Roshchin.

From Ivan Roshin To All 2 October 2002

Hello, All! ═══════════════════ 03.C ══════════════════ Obviously, the maximum possible is its own attribute for each familiarity lines (8 pixels). Here's what you get image: ┌─────────────────────────┐ │ bw_s_7.pcx │ │ │ │ │ │ │ R = 0.0071 │ │ │ │ │ │ │ │ └─────────────────────────┘ Fig. 7 In the practical implementation of the maximum attribute permissions, however, a problem arises. The thing is that for 224 clock cycle (time to draw one line) 32 bytes need to be updated string attributes, but this is not so easy to do: ordinary Data transfer methods take much longer. B Following the procedure given in Appendix 3, I solved this problem like this: not the entire image is displayed, but a window 11 characters wide, which can be moved left and right. You can try increase the width of the displayed image area using methods for fast data transfer - for example, described in [5]. There is another way to improve quality. Can be formedtwo images such that the average between them is the most similar to the original, and then quickly alternate them - while the viewer will just see the middle image. Let the attributes of both images be the same. If earlier the brightness of a pixel in a familiar location could be one of two: MIN or MAX, then when quickly alternating two images it can be already one of three: MIN, MAX or (MIN+MAX)/2 (when on one in the image the pixel brightness is MIN, and in the other - MAX). Due to This is what improves quality. If earlier we received 257 pseudo-gradations of brightness from MIN to MAX using 257 different textures 16*16, then now we get 257 pseudogradations from MIN to (MIN+MAX)/2 and another 257 - from (MIN+MAX)/2 to MAX, and in total, like this Thus, there will be 513 pseudogradations from MIN to MAX. When such two images are formed, their attributes (they are the same) are defined in the same way as before. For everyone pixel we determine which of the 513 pseudogradations (from 0 to 512) is closest to it in brightness. If the pseudogradation number is less than 256, then the corresponding pixel is in the first image turn it off, and on the second - take it from the texture with a number equal to pseudogradation number. If the pseudogradation number is greater or is 256, then in the first image we turn on the pixel, and in the second - we take it from a texture with a number equal to the number pseudogradation reduced by 256. Using this method to output the original image,we get these two images: ┌─────────────────────────┐ ┌─────────────────────────┐ │ bw_s_8a.pcx │ │ bw_s_8b.pcx │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └─────────────────────────┘ └─────────────────────────┘ a) b) Fig. 8 When they alternate quickly, we will see the middle image - here it is: ┌─────────────────────────┐ │ bw_s_9.pcx │ │ │ │ │ │ │ R = 0.0026 │ │ │ │ │ │ │ │ └─────────────────────────┘ Fig. 9 However, when considering it, you will be disappointed due toquite noticeable flicker with a frequency of 25 Hz. Is it possible reduce, and if so, how? I'll try to explain with an example. Suppose we need to get a gray color in some area of the screen for due to the quick change of white and black. You can do this: in one show this entire area white in one frame, and black in another (Fig. 10a). The flickering will be very noticeable. Is it possible in display a “checkerboard” texture in this area in one frame, and in in another frame - the same texture, but in which instead of white pixels are black and vice versa (Fig. 10b). Then there will be flickering much less, and from afar it will not be noticeable at all. ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ │████████│ │ │ │██ ██ │ │ ██ ██│ │████████│ + │ │ │ ██ ██│ + │██ ██ │ │████████│ │ │ │██ ██ │ │ ██ ██│ │████████│ │ │ │ ██ ██│ │██ ██ │ └────────┘ └────────┘ └────────┘ └────────┘ a) b) Fig. 10 ════════════════════════ ════════════════════════ Best regards, Ivan Roshchin.

From Ivan Roshin To All 2 October 2002

Hello, All! ═══════════════════ 04.C ══════════════════ Why does this happen? When looking at the image from afar, the brightness of neighboring pixels is averaged, and since in In the second case, neighboring pixels flicker in antiphase, then they the average brightness in both one and the other frame will be the same, and as a result the image will not flicker. In other words, the average brightness of fairly small areas on the first and second images should be approximately the same, and This can be achieved if the neighboring flickering pixels are in antiphase. In our case (Fig. 8) the images are very different from each other, and therefore the flickering when they change is very noticeable. To make the images more similar to each other, let's do the following: looking at the pixels (to be specific, on the left to the right and from top to bottom), we define flickering (i.e. different in the first and second images); let's make the first such pixel dark in the first image and light in the second, the next one is on the contrary, light in the first image and dark in the second (i.e. it will be in antiphase with the previous one), and so on. This is what those shown in Fig. turn into. 8 images after this processing: ┌─────────────────────────┐ ┌─────────────────────────┐ │ bw_s_11a.pcx │ │ bw_s_11b.pcx │ │ │ │ ││ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └─────────────────────────┘ └─────────────────────────┘ a) b) Fig. 11 It's immediately obvious that they are now much more similar to each other. friend. Flickering when they change quickly becomes significantly less, and from a distance it is not noticeable at all. Resulting the image will, of course, be the same (Fig. 9): after all, from changing the places of the terms does not change the sum. By the way, here’s some advice on how to avoid seeing flickering even from close up distances. Take a piece of paper, poke a hole in it and look at the screen through this hole. Amount of light There will be less light entering the eye, and the flicker will be greatly reduced. Rapid alternation of two images can be combined with multicolor, which will further improve the quality. This is what happens when for each half of the familiar place its own attribute is set: ┌─────────────────────────┐ │ bw_s_12.pcx │ │ ││ │ │ │ R = 0.0022 │ │ │ │ │ │ │ │ └─────────────────────────┘ Fig. 12 But - when a different attribute is set for each line familiar places: ┌─────────────────────────┐ │ bw_s_13.pcx │ │ │ │ │ │ │ R = 0.0017 │ │ │ │ │ │ │ │ └─────────────────────────┘ Fig. 13 ════════════════════════ ════════════════════════ Best regards, Ivan Roshchin.

From Ivan Roshin To All 2 October 2002

Hello, All! ═══════════════════ 05 .C ══════════════════ The methods described above were illustrated using the example of one original image. Below are examples for a few more images (on the left - the original one, on the right - the resulting one output). A method was used with rapid alternation of two images and multicolor, attributes were set for each familiarity lines. (By the way, scanning photographs that served as source images, performed at my request by Alexey Letaev - thank you!) ┌─────────────────────────┐ ┌─────────────────────────┐ │ bw_s_14a.pcx ││ bw_s_14b.pcx │ │ ││ │ │ ││ │ │ ││ │R = 0.0020 │ ││ │ │ ││ │ │ ││ │ │ ││ │ └─────────────────────────┘ └─────────────────────────┘ ┌─────────────────────────┐ ┌─────────────────────────┐ │ bw_s_14c.pcx ││ bw_s_14d.pcx │ │ ││ │ │ ││ │ │ ││ │R = 0.0021│ ││ │ │ ││ │ │ ││ │ │ ││ │ └─────────────────────────┘└─────────────────────────┘ ┌─────────────────────────┐┌─────────────────────────┐ │ bw_s_14e.pcx ││ bw_s_14f.pcx │ │ ││ │ │ ││ │ │ ││ │R = 0,0029 │ ││ │ │ ││ │ │ ││ │ │ ││ │ └─────────────────────────┘└─────────────────────────┘ ┌─────────────────────────┐┌─────────────────────────┐ │ bw_s_14g.pcx ││ bw_s_14h.pcx │ │ ││ │ │ ││ │ │ ││ │R = 0,0023 │ ││ │ │ ││ │ │ ││ │ │ ││ │ └─────────────────────────┘└─────────────────────────┘ Rice. 14 To see even more detail in the image, you can: firstly, use output with magnification, and secondly, increase the contrast of the displayed image area. When outputting with magnification, we will not be able to see everything at once. picture, but due to this we will be able to distinguish on the visible fragment more details. Here is an example: in Fig. 15a shows the central part of fig. 5, doubled for ease of comparison, and fig. 15b - what happens if you double the central part directly in the withdrawal process. ┌─────────────────────────┐ ┌─────────────────────────┐ │ bw_s_15a.pcx │ │ bw_s_15b.pcx │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └─────────────────────────┘ └─────────────────────────┘ a) b) Fig. 15 The output procedures given in Appendix 3 can outputthe specified area of ​​the image with a magnification of 2, 4, 8... times. I think it won't be difficult for you to figure out how to increase image a number of times that is not a power of two. Now about increasing the contrast. If in the output image (or in the output part of the image) is the darkest point lighter than 0 and/or the lightest point darker than 255, then you can "stretch" the brightness range to 0 - 255 using the following formula: A-Amin A'= 255 ─────────── Amax-Amin where A is the original brightness, A' - new brightness, Amin - brightness of the darkest point, Amax - brightness of the brightest point. After this transformation we will see dark areas images are darker than necessary, and light images are lighter, but at the same time more details can be discerned. In Fig. 16 you can see the image obtained as in Fig. 15b, but with an increase contrast. ┌─────────────────────────┐ │ bw_s_16.pcx │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └─────────────────────────┘Rice. 16 ════════════════════════ ════════════════════════ Best regards, Ivan Roshchin.

From Ivan Roshin To All 2 October 2002

Hello, All! ═══════════════════ 05 .C ══════════════════ The methods described above were illustrated using the example of one original image. Below are examples for a few more images (on the left - the original one, on the right - the resulting one output). A method was used with rapid alternation of two images and multicolor, attributes were set for each familiarity lines. (By the way, scanning photographs that served as source images, performed at my request by Alexey Letaev - thank you!) ┌─────────────────────────┐ ┌─────────────────────────┐ │ bw_s_14a.pcx ││ bw_s_14b.pcx │ │ ││ │ │ ││ │ │ ││ │R = 0.0020 │ ││ │ │ ││ │ │ ││ │ │ ││ │ └─────────────────────────┘ └─────────────────────────┘ ┌─────────────────────────┐ ┌─────────────────────────┐ │ bw_s_14c.pcx ││ bw_s_14d.pcx │ │ ││ │ │ ││ │ │ ││ │R = 0.0021│ ││ │ │ ││ │ │ ││ │ │ ││ │ └─────────────────────────┘└─────────────────────────┘ ┌─────────────────────────┐┌─────────────────────────┐ │ bw_s_14e.pcx ││ bw_s_14f.pcx │ │ ││ │ │ ││ │ │ ││ │R = 0,0029 │ ││ │ │ ││ │ │ ││ │ │ ││ │ └─────────────────────────┘└─────────────────────────┘ ┌─────────────────────────┐┌─────────────────────────┐ │ bw_s_14g.pcx ││ bw_s_14h.pcx │ │ ││ │ │ ││ │ │ ││ │R = 0,0023 │ ││ │ │ ││ │ │ ││ │ │ ││ │ └─────────────────────────┘└─────────────────────────┘ Rice. 14 To see even more detail in the image, you can: firstly, use output with magnification, and secondly, increase the contrast of the displayed image area. When outputting with magnification, we will not be able to see everything at once. picture, but due to this we will be able to distinguish on the visible fragment more details. Here is an example: in Fig. 15a shows the central part of fig. 5, doubled for ease of comparison, and fig. 15b - what happens if you double the central part directly in the withdrawal process. ┌─────────────────────────┐ ┌─────────────────────────┐ │ bw_s_15a.pcx │ │ bw_s_15b.pcx │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └─────────────────────────┘ └─────────────────────────┘ a) b) Fig. 15 The output procedures given in Appendix 3 can outputthe specified area of ​​the image with a magnification of 2, 4, 8... times. I think it won't be difficult for you to figure out how to increase image a number of times that is not a power of two. Now about increasing the contrast. If in the output image (or in the output part of the image) is the darkest point lighter than 0 and/or the lightest point darker than 255, then you can "stretch" the brightness range to 0 - 255 using the following formula: A-Amin A'= 255 ─────────── Amax-Amin where A is the original brightness, A' - new brightness, Amin - brightness of the darkest point, Amax - brightness of the brightest point. After this transformation we will see dark areas images are darker than necessary, and light images are lighter, but at the same time more details can be discerned. In Fig. 16 you can see the image obtained as in Fig. 15b, but with an increase contrast. ┌─────────────────────────┐ │ bw_s_16.pcx │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └─────────────────────────┘Rice. 16 ════════════════════════ ════════════════════════ Best regards, Ivan Roshchin.

From Ivan Roshin To All 2 October 2002

Hello, All! ═══════════════════06 ══════════════════ Gamma correction ─────────────── The gradations of brightness in the original image are indicated by numbers from 0 to 255. We, in fact, considered these numbers to be brightness pixels (referring to the definition of brightness given in Appendix 2). That is, we assumed that the brightness of a pixel depends linearly on number corresponding to this pixel in the image: if, for example, one pixel corresponds to the number 10, and another - 20, then the second pixel is twice as bright as the first. However, in general this is not the case. Dependency is not here linear, but power (the exponent is called “gamma”). Linear dependence is only a special case when gamma is equal to 1. In Fig. Figure 17 shows graphs for three possible cases (along the axis x is the value corresponding to the pixel in the image, and the y-axis is the actual brightness of the pixel). ┌───────────────────┐┌───────── ──────────┐┌───────────────────┐ │ bw_s_17a.pcx ││ bw_s_17b.pcx ││ bw_s_17c.pcx │ │ ││ ││ │ │ ││ ││ │ │ ││ ││ │ │ ││ ││ │ │ ││ ││ │└───────────────────┘└───────── ──────────┘└───────────────────┘ a) gamma=1 b) gamma>1 c) gamma<1 Fig. 17 As we can see, if the gamma is greater than 1, then in an image with a larger information about dark areas is presented accurately and with less accuracy - about light ones, and if the gamma is less than 1 - vice versa. To correctly output images with a gamma other than units, and gamma correction is needed. From the pixel value (we denote its x) we must get its brightness (let's call it y). If and value, and brightness are numbers from 0 to 255, then the formula is: y=255*(x/255)^Gamma It is convenient to first calculate y for all x from 0 to 255 by putting values into the table, and when outputting, simply take from the table ready value. The withdrawal procedures given in Appendix 3 can be performed gamma correction if you set the conditional compilation flag to 1 GAMMA_CORR. In this case, the default gamma value is 1.5. For a different value, it will be necessary to recalculate the correction table with using the BASIC program given there. By the way, this you can run the program just to see what graphs are obtained at different gamma values. How can you find out what gamma value the output image has? If you are taking this image from a png file (or some other format where the gamma value is specified infile itself), then there are no difficulties. And if you (like me) you will take an image from a pcx file, where there is no such information contained? Then you will have to select this coefficient by experienced way. Try to display the image first without gamma correction. If it looks natural, then nothing else and don't. If it is too dark, it means the gamma is greater than 1; if it is too light, the gamma is less than 1. By the way: images with a gamma greater than 1 will be displayed more precisely due to the fact that they contain more information about the dark areas, and the distribution of Spectrum brightness gradations (see. fig. 19 in Appendix 2) is exactly that (at least for me) that dark areas are reproduced much more accurately light. Working with pcx files ──────────────────── The source images must be taken from somewhere. I read them from files in pcx format. Appendix 4 provides two procedures for working with such files. The first procedure reads data from pcx file and forms an array of pixel data in memory. Second the procedure performs the opposite task - writes a pcx file using pixel data located in memory (it is with its help that I prepared all pcx files with drawings for this article). Another procedure given there directly with pcx files does not work, but will be useful if you need convert the image to Spectrum format (6912 bytes)to a black and white pcx file. It forms an array of data in memory about the pixels of such an image based on specified gradation values brightness, and based on this data you can already create a pcx file. And one more small addition ─────────────────────────────── If the source image is color and you want to output it in black and white, then to obtain the pixel brightness by Given the known values of the components R, G, B, use the following formula: Y = 0.299R + 0.587G + 0.114B Since brightness needs to be calculated for each pixel, and even image the size of a Spectrum screen - 256*192 - contains 49152 pixels, it is clear that this calculation must be as fast as possible. It is convenient to use the tabular method. Let there be a table with a length of 768 (i.e. 3*256) bytes, starting with an address that is a multiple of 256 (let’s denote this address TAB_RGB). Let the first 256 bytes of this table contain function values y=0.299x for x from 0 to 255, rounded to integers (for practical use such accuracy is quite sufficient), in the second 256 bytes - the function values y=0.587x, and in the third 256 bytes - the function values y=0.114x (also for x from 0 to 255). ════════════════════════ ════════════════════════ Best regards, Ivan Roshchin.

From Ivan Roshin To All 2 October 2002

Hello, All! ═══════════════════06 ══════════════════ Gamma correction ─────────────── The gradations of brightness in the original image are indicated by numbers from 0 to 255. We, in fact, considered these numbers to be brightness pixels (referring to the definition of brightness given in Appendix 2). That is, we assumed that the brightness of a pixel depends linearly on number corresponding to this pixel in the image: if, for example, one pixel corresponds to the number 10, and another - 20, then the second pixel is twice as bright as the first. However, in general this is not the case. Dependency is not here linear, but power (the exponent is called “gamma”). Linear dependence is only a special case when gamma is equal to 1. In Fig. Figure 17 shows graphs for three possible cases (along the axis x is the value corresponding to the pixel in the image, and the y-axis is the actual brightness of the pixel). ┌───────────────────┐┌───────── ──────────┐┌───────────────────┐ │ bw_s_17a.pcx ││ bw_s_17b.pcx ││ bw_s_17c.pcx │ │ ││ ││ │ │ ││ ││ │ │ ││ ││ │ │ ││ ││ │ │ ││ ││ │└───────────────────┘└───────── ──────────┘└───────────────────┘ a) gamma=1 b) gamma>1 c) gamma<1 Fig. 17 As we can see, if the gamma is greater than 1, then in an image with a larger information about dark areas is presented accurately and with less accuracy - about light ones, and if the gamma is less than 1 - vice versa. To correctly output images with a gamma other than units, and gamma correction is needed. From the pixel value (we denote its x) we must get its brightness (let's call it y). If and value, and brightness are numbers from 0 to 255, then the formula is: y=255*(x/255)^Gamma It is convenient to first calculate y for all x from 0 to 255 by putting values into the table, and when outputting, simply take from the table ready value. The withdrawal procedures given in Appendix 3 can be performed gamma correction if you set the conditional compilation flag to 1 GAMMA_CORR. In this case, the default gamma value is 1.5. For a different value, it will be necessary to recalculate the correction table with using the BASIC program given there. By the way, this you can run the program just to see what graphs are obtained at different gamma values. How can you find out what gamma value the output image has? If you are taking this image from a png file (or some other format where the gamma value is specified infile itself), then there are no difficulties. And if you (like me) you will take an image from a pcx file, where there is no such information contained? Then you will have to select this coefficient by experienced way. Try to display the image first without gamma correction. If it looks natural, then nothing else and don't. If it is too dark, it means the gamma is greater than 1; if it is too light, the gamma is less than 1. By the way: images with a gamma greater than 1 will be displayed more precisely due to the fact that they contain more information about the dark areas, and the distribution of Spectrum brightness gradations (see. fig. 19 in Appendix 2) is exactly that (at least for me) that dark areas are reproduced much more accurately light. Working with pcx files ──────────────────── The source images must be taken from somewhere. I read them from files in pcx format. Appendix 4 provides two procedures for working with such files. The first procedure reads data from pcx file and forms an array of pixel data in memory. Second the procedure performs the opposite task - writes a pcx file using pixel data located in memory (it is with its help that I prepared all pcx files with drawings for this article). Another procedure given there directly with pcx files does not work, but will be useful if you need convert the image to Spectrum format (6912 bytes)to a black and white pcx file. It forms an array of data in memory about the pixels of such an image based on specified gradation values brightness, and based on this data you can already create a pcx file. And one more small addition ─────────────────────────────── If the source image is color and you want to output it in black and white, then to obtain the pixel brightness by Given the known values of the components R, G, B, use the following formula: Y = 0.299R + 0.587G + 0.114B Since brightness needs to be calculated for each pixel, and even image the size of a Spectrum screen - 256*192 - contains 49152 pixels, it is clear that this calculation must be as fast as possible. It is convenient to use the tabular method. Let there be a table with a length of 768 (i.e. 3*256) bytes, starting with an address that is a multiple of 256 (let’s denote this address TAB_RGB). Let the first 256 bytes of this table contain function values y=0.299x for x from 0 to 255, rounded to integers (for practical use such accuracy is quite sufficient), in the second 256 bytes - the function values y=0.587x, and in the third 256 bytes - the function values y=0.114x (also for x from 0 to 255). ════════════════════════ ════════════════════════ Best regards, Ivan Roshchin.

From Ivan Roshin To All 2 October 2002

Hello, All! ═══════════════════07 ══════════════════ Here is a 32-byte procedure for constructing such a table: MK_T_RGB LD BC,TAB_RGB+#2FF ;Address of the last byte of the table. LD H,29 ;0.114*256 CALL MK_T_RGB_1 LD H,150 ;0.587*256 CALL MK_T_RGB_1 LD H,77 ;0.299*256 MK_T_RGB_1 XOR A LD L,A LD D,A LD E,H MK_T_RGB_2 SBC HL,DE RET C ;Write the rounded result: LD A,H BIT 7,L JR Z,MK_T_RGB_3 INC A MK_T_RGB_3 LD (BC),A DEC B.C. JR MK_T_RGB_2 Using this table you can calculate brightness very quickly pixel - for example, using the following program fragment: ;Input: values of components R, G, B - in registers L, D, E ; respectively. ;Output: calculated Y value - in accumulator. ;Length: 9 bytes. ;Execution time: 44 clock cycles. LD H,TAB_RGB/256 LD A,(HL);A=0.299R INC H LD L,D ADD A,(HL) ;A=0.299R+0.587G INC H LD L,E ADD A,(HL) ;A=0.299R+0.587G+0.114B If you need to process a group of pixels at once, it will be more profitable do not load register H every time, but load it only oncetimes, and then only change with the INC and DEC commands (processing by two pixels per loop) as in the procedure below: ;Input: IX - source data start address (R1,G1,B1,R2,G2,B2...); ; DE - where to put the result (Y1,Y2...); ; BC - number of processed pixels (must be ; even) divided by 2. ;Length: 49 bytes. CALC_Y EXX LD DE,6 EXX LD H,TAB_RGB/256 CALC_Y_1 LD L,(IX) ;L=R1 LD A,(HL);A=0.299R1 INC H LD L,(IX+1) ;L=G1 ADD A,(HL) ;A=0.299R1+0.587G1 INC H LD L,(IX+2) ;L=B1 ADD A,(HL) ;A=0.299R1+0.587G1+0.114B1 LD(DE),A INC DE LD L,(IX+5) ;L=B2 LD A,(HL);A=0.114B2 DEC H LD L,(IX+4) ;L=G2 ADD A,(HL) ;A=0.114B2+0.587G2 DEC H LD L,(IX+3) ;L=R2 ADD A,(HL) ;A=0.114B2+0.587G2+0.299R2 LD(DE),A INC DE EXX ADD IX,DE ;IX:=IX+6 EXX DEC B.C. LD A,B OR C JR NZ,CALC_Y_1 RET If it is known in advance that DE at the input will be even (or odd), then the first (or, accordingly, second) commandINC DE can be replaced with the faster INC E. If no more than 512 pixels are processed, then counter, you can use not a register pair BC, but only one register B, using the DJNZ instruction to loop. Literature ────────── 1. A. Bordachev. "About the PCX format." Information library technology, vol. 8. Moscow, "Infoart", 1993. 2. T. Kencl. "Internet File Formats". St. Petersburg, "Peter", 1997. 3. K. Bochkov. "Scanning is so easy...". "PC World" 11/2000. 4. S. Kashchavtsev. "The Magic Power of Curves - II". "Computerra" 49-50/1998. 5. E. Zaretsky. "Fast graphics output." "Radio amateur. Yours computer" 5.6/2001. ════════════════════════ ════════════════════════ Best regards, Ivan Roshchin.

From Ivan Roshin To All 2 October 2002

Hello, All! ═══════════════════08 ══════════════════ Appendix 1 ──────────── Here I will talk about how I determined R - the difference between two images. Let's calculate the standard deviation: h-1 l-1 ┌── ┌── 2 > > (p1(x,y)-p2(x,y)) └── └── y=0 x=0 r1 = ───────────────────────── l*h where h is the height of the compared images, l - width, p1(x,y) - brightness of the pixel with coordinates (x,y) in the first image, reduced to the range 0-1 (if, for example, in an image there are 256 gradations of brightness, then the pixel value must be divided by 255), p2(x,y) - the same for the second image. Next, we similarly calculate the standard deviation for of all sections 2*2 pixels, considering the brightness of the section to be average brightness of its pixels: h-2 l-2 ┌── ┌── 2 > > (m1(x,y)-m2(x,y)) └── └── y=0 x=0 r2 = ───────────────────────── (l-1)*(h-1) 1 1 1 1┌── ┌── ┌── ┌── > > p1(x+i,y+j) > > p2(x+i,y+j) └── └── └── └── j=0 i=0 j=0 i=0 where m1(x,y) = ──────────────────, m2(x,y) = ──────────────────. 4 4 And for 4*4 pixel areas: h-4 l-4 ┌── ┌── 2 > > (n1(x,y)-n2(x,y)) └── └── y=0 x=0 r3 = ───────────────────────── (l-3)*(h-3) 3 3 3 3 ┌── ┌── ┌── ┌── > > p1(x+i,y+j) > > p2(x+i,y+j) └── └── └── └── j=0 i=0 j=0 i=0 where n1(x,y) = ──────────────────, n2(x,y) = ──────────────────. 16 16 The value of r1 reflects the difference at close range (when individual pixels can be distinguished in the compared images). The value r2 is the difference from the average distance (when it is impossible distinguish details less than 2*2 pixels). Finally, the sizer3 - difference from a long distance (when details are no longer visible less than 4*4 pixels). Let's define R as the average between r1, r2 and r3: r1 + r2 + r3 R = ────────────── 3 R (like r1, r2, r3) can take values in the range from 0 to 1, with 0 corresponding to a complete match of the compared images, and 1 - maximum difference. ════════════════════════ ════════════════════════ Best regards, Ivan Roshchin.

From Ivan Roshin To All 2 October 2002

Hello, All! ═══════════════════08 ══════════════════ Appendix 1 ──────────── Here I will talk about how I determined R - the difference between two images. Let's calculate the standard deviation: h-1 l-1 ┌── ┌── 2 > > (p1(x,y)-p2(x,y)) └── └── y=0 x=0 r1 = ───────────────────────── l*h where h is the height of the compared images, l - width, p1(x,y) - brightness of the pixel with coordinates (x,y) in the first image, reduced to the range 0-1 (if, for example, in an image there are 256 gradations of brightness, then the pixel value must be divided by 255), p2(x,y) - the same for the second image. Next, we similarly calculate the standard deviation for of all sections 2*2 pixels, considering the brightness of the section to be average brightness of its pixels: h-2 l-2 ┌── ┌── 2 > > (m1(x,y)-m2(x,y)) └── └── y=0 x=0 r2 = ───────────────────────── (l-1)*(h-1) 1 1 1 1┌── ┌── ┌── ┌── > > p1(x+i,y+j) > > p2(x+i,y+j) └── └── └── └── j=0 i=0 j=0 i=0 where m1(x,y) = ──────────────────, m2(x,y) = ──────────────────. 4 4 And for 4*4 pixel areas: h-4 l-4 ┌── ┌── 2 > > (n1(x,y)-n2(x,y)) └── └── y=0 x=0 r3 = ───────────────────────── (l-3)*(h-3) 3 3 3 3 ┌── ┌── ┌── ┌── > > p1(x+i,y+j) > > p2(x+i,y+j) └── └── └── └── j=0 i=0 j=0 i=0 where n1(x,y) = ──────────────────, n2(x,y) = ──────────────────. 16 16 The value of r1 reflects the difference at close range (when individual pixels can be distinguished in the compared images). The value r2 is the difference from the average distance (when it is impossible distinguish details less than 2*2 pixels). Finally, the magnituder3 - difference from a long distance (when details are no longer visible less than 4*4 pixels). Let's define R as the average between r1, r2 and r3: r1 + r2 + r3 R = ────────────── 3 R (like r1, r2, r3) can take values in the range from 0 to 1, with 0 corresponding to a complete match of the compared images, and 1 - maximum difference. ════════════════════════ ════════════════════════ Best regards, Ivan Roshchin.

From Ivan Roshin To All 2 October 2002

Hello, All! ═══════════════════09 ══════════════════ Appendix 2 ──────────── Here we will talk about how to determine the values a0-a7 (brightness of colors 0-7 at bright=0) and b0-b7 (brightness of the same colors with bright=1), when the image is displayed in black and white form. Obviously, these values may be different for different ZX Spectrum models, for different color converters signal in black and white, as well as for different monitors and TVs. Therefore, instead of providing a ready-made set numbers, I'll tell you how you can determine them specifically for your computer-monitor system, and for this you do not you will need any special equipment. What can you say right away? 1. The darkest color is black: a0 = 0, b0 = 0. 2. The brightest color is white with bright=1: b7 = 255. 3. The brightness of all other colors takes intermediate values: 0 < (a1-a7, b1-b6) < 255. 4. As the color number increases, the brightness increases: a1 > a0 b1 > b0 a2 > a1 b2 > b1 ....... ....... a7 > a6 b7 > b6. 5. For each color except black, brightness at bright=1 more than with bright=0: b1 > a1 b2 > a2 ....... b7 > a7.So, we already know something. Based on this information, it can be assumed that the brightness distribution will be approximately like this: ┌─────────────────────────┐ │ bw_s_18.pcx │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └─────────────────────────┘ Fig. 18 Above we said “brightness”, but what is the physical meaning of this concepts? Let's define it this way: the brightness of a certain color (more precisely, brightness of the gradation corresponding to this color in black and white display mode) is a value proportional to the amount photons emitted by a single region of a given color per unit of time. For example, if the brightness of one color is doubled brighter than another, this means that some area of this colors emits twice as many photons per unit time as the same area of a different color. If you display any color in one half of the screen (hereinafter - the original color), and in the other half - a mixture of pixels two colors, darker and lighter than the original (hereinafter referred to as dark color and light color), then, choosing the ratio of the numberpixels of these two colors, you can achieve equal brightness both halves of the screen. Equality of brightness means that both halves of the screen emit the same amount per unit time number of photons. Then the following formula is valid: x = k*y + (1-k)*z (1) where x is the brightness of the original color, y is the brightness of the dark color, z - brightness of light color, k is the proportion of pixels of dark color, 1-k - the proportion of pixels of light color. For example, if the brightness equalized when filling the second half of the screen with a 4*4 texture, in which there are 3 pixels of dark color and 13 pixels of light color, it would be written like this: x = 3/16*y + 13/16*z. We use the above to calculate the required brightnesses a0-a7 and b0-b7. First we express the brightness of each of the colors b1-b6 through the brightness of its neighboring colors: b1 = k1*b0 + (1-k1)*b2 (2) b2 = k2*b1 + (1-k2)*b3 ...................... b6 = k6*b5 + (1-k6)*b7. From (2) it follows: b1 - k1*b0 b2 = ────────── 1 - k1 And further: b2 - k2*b1 b3 = ────────── 1 - k2 b3 - k3*b2 b4 = ────────── 1 - k3 ............... b6 - k6*b5 b7 = ────────── 1 - k6 ════════════════════════ ════════════════════════ Best regards, Ivan Roshchin.

From Ivan Roshin To All 2 October 2002

Hello, All! ═══════════════════09 ══════════════════ Appendix 2 ──────────── Here we will talk about how to determine the values a0-a7 (brightness of colors 0-7 at bright=0) and b0-b7 (brightness of the same colors with bright=1), when the image is displayed in black and white form. Obviously, these values may be different for different ZX Spectrum models, for different color converters signal in black and white, as well as for different monitors and TVs. Therefore, instead of providing a ready-made set numbers, I'll tell you how you can determine them specifically for your computer-monitor system, and for this you do not you will need any special equipment. What can you say right away? 1. The darkest color is black: a0 = 0, b0 = 0. 2. The brightest color is white with bright=1: b7 = 255. 3. The brightness of all other colors takes intermediate values: 0 < (a1-a7, b1-b6) < 255. 4. As the color number increases, the brightness increases: a1 > a0 b1 > b0 a2 > a1 b2 > b1 ....... ....... a7 > a6 b7 > b6. 5. For each color except black, brightness at bright=1 more than with bright=0: b1 > a1 b2 > a2 ....... b7 > a7.So, we already know something. Based on this information, it can be assumed that the brightness distribution will be approximately like this: ┌─────────────────────────┐ │ bw_s_18.pcx │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └─────────────────────────┘ Fig. 18 Above we said “brightness”, but what is the physical meaning of this concepts? Let's define it this way: the brightness of a certain color (more precisely, brightness of the gradation corresponding to this color in black and white display mode) is a value proportional to the amount photons emitted by a single region of a given color per unit of time. For example, if the brightness of one color is doubled brighter than another, this means that some area of this colors emits twice as many photons per unit time as the same area of a different color. If you display any color in one half of the screen (hereinafter - the original color), and in the other half - a mixture of pixels two colors, darker and lighter than the original (hereinafter referred to as dark color and light color), then, choosing the ratio of the numberpixels of these two colors, you can achieve equal brightness both halves of the screen. Equality of brightness means that both halves of the screen emit the same amount per unit time number of photons. Then the following formula is valid: x = k*y + (1-k)*z (1) where x is the brightness of the original color, y is the brightness of the dark color, z - brightness of light color, k is the proportion of pixels of dark color, 1-k - the proportion of pixels of light color. For example, if the brightness equalized when filling the second half of the screen with a 4*4 texture, in which there are 3 pixels of dark color and 13 pixels of light color, it would be written like this: x = 3/16*y + 13/16*z. We use the above to calculate the required brightnesses a0-a7 and b0-b7. First we express the brightness of each of the colors b1-b6 through the brightness of its neighboring colors: b1 = k1*b0 + (1-k1)*b2 (2) b2 = k2*b1 + (1-k2)*b3 ...................... b6 = k6*b5 + (1-k6)*b7. From (2) it follows: b1 - k1*b0 b2 = ────────── 1 - k1 And further: b2 - k2*b1 b3 = ────────── 1 - k2 b3 - k3*b2 b4 = ────────── 1 - k3 ............... b6 - k6*b5 b7 = ────────── 1 - k6 ════════════════════════ ════════════════════════ Best regards, Ivan Roshchin.

From Ivan Roshin To All 2 October 2002

Hello, All! ═══════════════════ 10 .C ══════════════════ Thus, knowing b0 and b1, as well as k1-k6 (to be found empirically), you can sequentially calculate b2-b7. We know the value of b0 - it is 0. b1 is unknown, but we we know that b7 = 255. We can express b7 in terms of b1, then determine b1 and then calculate b2-b6. But this path is connected with cumbersome transformations. Let's do it simpler. Note that b2-b7 linearly depend on b1. This is easy to verify from the above formulas (not forgetting that b0=0). Let's take b1=1 and Let's calculate b2-b7. Then it is enough to determine how many times the resulting value of b7 was less than 255, and then multiply each of the calculated values b1-b7 by this amount, so that get their true values. After the brightnesses of colors with bright=1 are known, it remains determine the brightness of colors with bright=0 (a1-a7). For this it is enough to find experimentally for each of these colors an equivalent brightness mixture of two colors with bright=1, after why use formula (1). That was the theory, now let's move on to practice. Let's consider how I determined the brightness levels on my computer and what to used this one. First I wrote a procedure that fills the top part of the screen is one color, and the lower part is a mixture of two pixels other colors (using 4*4 texture). Here it is: LD H,1 ;original colorLD D,0 ;dark color LD E,2 ;light color LD L,4 ;texture number (0-16) ;Fill the top half of the screen: LD A,H ADD A,A ADD A,A ADD A,A ADD A,H ;If the original color is with increased brightness (bright=1), then ;the command ADD A,#40 follows, otherwise it is not needed (you can replace ;to ADD A,0): ADD A,#40 EXX LD HL,#5800 LD DE,#5801 LD BC,#180 LD(HL),A LDIR EXX ;Fill the bottom half of the screen: LD A,D ADD A,A ADD A,A ADD A,A ADD A,E ADD A,#40 EXX LD BC,#17F LD(HL),A LDIR EXX ;Texture filling: LD H,0 ADD HL,HL ADD HL,HL ;*4 LD DE,TEXTURES ADD HL,DE EX DE,HL ;DE points to the first byte of the texture. LD B,24 LD HL,#4880 M2 PUSH DE PUSH BC LD B,4 M1 LD A,(DE) PUSH BC PUSH DE PUSH HL LD D,H LD E,L LD(HL),A INC DE LD BC,#1F LDIR POP HL POP DE POP B.C. CALL DOWN_HL INC DE DJNZ M1 POP BC POP DE DJNZ M2 RET DOWN_HL INC H LD A,H AND 7 RET NZ LD A,L ADD A,#20 LD L,A RET C LD A,H SUB 8 LD H,A RET TEXTURES DB %00000000 DB %00000000 DB %00000000 DB %00000000 DB %00000000 DB %01000100 DB %00000000 DB %00000000 DB %00000000 DB %01000100 DB %00000000 DB %00010001 DB %00000000 DB %01010101 DB %00000000 DB %00010001 DB %00000000 DB %01010101 DB %00000000 DB %01010101 DB %00000000 DB %01010101 DB %00100010 DB %01010101 DB %10001000 DB %01010101 DB %00100010 DB %01010101 DB %10101010 DB %01010101 DB %00100010 DB %01010101 DB %10101010 DB %01010101 DB %10101010 DB %01010101 DB %10101010 DB %01110111 DB %10101010 DB %01010101 DB %10101010 DB %01110111 DB %10101010 DB %11011101 DB %10101010 DB %01110111 DB %10101010 DB %11111111 DB %10101010 DB %11111111 DB %10101010 DB %11111111 DB %10101010 DB %11111111 DB %11101110 DB %11111111 DB %10111011 DB %11111111 DB %11101110 DB %11111111 DB %11111111 DB %11111111 DB %11101110 DB %11111111 DB %11111111 DB %11111111 DB %11111111 DB %11111111 ════════════════════════════════════════════════ С уважением, Иван Рощин.

From Ivan Roshin To All 2 October 2002

Hello, All! ═══════════════════ 10 .C ══════════════════ Thus, knowing b0 and b1, as well as k1-k6 (to be found empirically), you can sequentially calculate b2-b7. We know the value of b0 - it is 0. b1 is unknown, but we we know that b7 = 255. We can express b7 in terms of b1, then determine b1 and then calculate b2-b6. But this path is connected with cumbersome transformations. Let's do it simpler. Note that b2-b7 linearly depend on b1. This is easy to verify from the above formulas (not forgetting that b0=0). Let's take b1=1 and Let's calculate b2-b7. Then it is enough to determine how many times the resulting value of b7 was less than 255, and then multiply each of the calculated values b1-b7 by this amount, so that get their true values. After the brightnesses of colors with bright=1 are known, it remains determine the brightness of colors with bright=0 (a1-a7). For this it is enough to find experimentally for each of these colors an equivalent brightness mixture of two colors with bright=1, after why use formula (1). That was the theory, now let's move on to practice. Let's consider how I determined the brightness levels on my computer and what to used this one. First I wrote a procedure that fills the top part of the screen is one color, and the lower part is a mixture of two pixels other colors (using 4*4 texture). Here it is: LD H,1 ;original colorLD D,0 ;dark color LD E,2 ;light color LD L,4 ;texture number (0-16) ;Fill the top half of the screen: LD A,H ADD A,A ADD A,A ADD A,A ADD A,H ;If the original color is with increased brightness (bright=1), then ;the command ADD A,#40 follows, otherwise it is not needed (you can replace ;to ADD A,0): ADD A,#40 EXX LD HL,#5800 LD DE,#5801 LD BC,#180 LD(HL),A LDIR EXX ;Fill the bottom half of the screen: LD A,D ADD A,A ADD A,A ADD A,A ADD A,E ADD A,#40 EXX LD BC,#17F LD(HL),A LDIR EXX ;Texture filling: LD H,0 ADD HL,HL ADD HL,HL ;*4 LD DE,TEXTURES ADD HL,DE EX DE,HL ;DE points to the first byte of the texture. LD B,24 LD HL,#4880 M2 PUSH DE PUSH BC LD B,4 M1 LD A,(DE) PUSH BC PUSH DE PUSH HL LD D,H LD E,L LD(HL),A INC DE LD BC,#1F LDIR POP HL POP DE POP B.C. CALL DOWN_HL INC DE DJNZ M1 POP BC POP DE DJNZ M2 RET DOWN_HL INC H LD A,H AND 7 RET NZ LD A,L ADD A,#20 LD L,A RET C LD A,H SUB 8 LD H,A RET TEXTURES DB %00000000 DB %00000000 DB %00000000 DB %00000000 DB %00000000 DB %01000100 DB %00000000 DB %00000000 DB %00000000 DB %01000100 DB %00000000 DB %00010001 DB %00000000 DB %01010101 DB %00000000 DB %00010001 DB %00000000 DB %01010101 DB %00000000 DB %01010101 DB %00000000 DB %01010101 DB %00100010 DB %01010101 DB %10001000 DB %01010101 DB %00100010 DB %01010101 DB %10101010 DB %01010101 DB %00100010 DB %01010101 DB %10101010 DB %01010101 DB %10101010 DB %01010101 DB %10101010 DB %01110111 DB %10101010 DB %01010101 DB %10101010 DB %01110111 DB %10101010 DB %11011101 DB %10101010 DB %01110111 DB %10101010 DB %11111111 DB %10101010 DB %11111111 DB %10101010 DB %11111111 DB %10101010 DB %11111111 DB %11101110 DB %11111111 DB %10111011 DB %11111111 DB %11101110 DB %11111111 DB %11111111 DB %11111111 DB %11101110 DB %11111111 DB %11111111 DB %11111111 DB %11111111 DB %11111111 ════════════════════════════════════════════════ С уважением, Иван Рощин.

From Ivan Roshin To All 2 October 2002

Hello, All! ═══════════════════ 11.C ══════════════════ To make it more convenient to compare the brightness of the halves of the screen when on one half the brightness is uniform, and on the other there is texture, I looked at the image through a translucent polyethylene film (a regular bag is suitable for this). Using the above procedure the following were obtained ratios: b1 = 9/16 b0 + 7/16 b2 b2 = 10/16 b1 + 6/16 b3 b3 = 8/16 b2 + 8/16 b4 b4 = 13/16 b3 + 3/16 b5 b5 = 9/16 b4 + 7/16 b6 b6 = 10/16 b5 + 6/16 b7 (i.e. k1=9/16, k2=10/16, k3=8/16, k4=13/16, k5=9/16, k6=10/16) a1 = 3/16 b0 + 13/16 b1 a2 = 9/16 b1 + 7/16 b2 a3 = 9/16 b2 + 7/16 b3 a4 = b3 a5 = 9/16 b4 + 7/16 b5 a6 = 11/16 b5 + 5/16 b6 a7 = 11/16 b6 + 5/16 b7 Then I wrote a program that calculated from this data required values a0-a7 and b0-b7: 10 DIM k(6): DIM a(7): DIM b(7) 20 LET k(1)=9/16: LET k(2)=10/16: LET k(3)=8/16: LET k(4)= 13/16: LET k(5)=9/16: LET k(6)=10/16 30 REM CALCULATE b(1)-b(7) 40 LET b(1)=1 50 LET b(2)=1/(1-k(1)) 60 FOR i=3 TO 7 70 LET b(i)=(b(i-1)-k(i-1)*b(i-2))/(1-k(i-1)) 80 NEXT i 90 LET n=255/b(7) 100 FOR i=1 TO 7 110 LET b(i)=b(i)*n 120 NEXT i 130 REM CALCULATE a(1)-a(7) 140 LET a(1)=13/16*b(1) 150 LET a(2)=9/16*b(1)+7/16*b(2)160 LET a(3)=9/16*b(2)+7/16*b(3) 170 LET a(4)=b(3) 180 LET a(5)=9/16*b(4)+7/16*b(5) 190 LET a(6)=11/16*b(5)+5/16*b(6) 200 LET a(7)=11/16*b(6)+5/16*b(7) 210 REM PRINT RESULT 220 PRINT "a0=0",0 230 FOR i=1 TO 7 240 PRINT "a";i;"=";a(i), INT (a(i)*256+0.5) 250 NEXT i 260 PRINT 270 PRINT "b0=0",0 280 FOR i=1 TO 7 290 PRINT "b";i;"=";b(i), INT (b(i)*256+0.5) 300 NEXT i Results of the program: in the left column - calculated brightness values, in the right - they are the same, but in 256 shares - in this format they are stored in image output procedures (see. Appendix 3). a0 = 0 0 a1 = 4.344111 1112 a2 = 8.3540597 2139 a3 = 17.233232 4412 a4 = 23.677792 6062 a5 = 56.855343 14555 a6 = 104.72922 26811 a7 = 181.85936 46556 b0 = 0 0 b1 = 5.3465982 1369 b2 = 12.220796 3129 b3 = 23.677792 6062 b4 = 35.134788 8995 b5 = 84.781772 21704 b6 = 148.61361 38045 b7 = 255 65280 And here's what it looks like on the graph: ┌─────────────────────────┐ │ bw_s_19.pcx │ │ │ │ │ │ │ │ │ │ ││ │ │ │ └─────────────────────────┘ Fig. 19 As you can see, this is different from the initial assumptions (Fig. 18). The values are distributed unevenly: the smaller brightness, the closer they are to each other. How can this be explained? Obviously, when converting a color image to black and white strive to ensure that different colors turn into good differing shades of gray. And for this brightness neighboring gradations must differ from each other by more than one and the same value, and in the same number of times - these are features of human vision. ════════════════════════ ════════════════════════ Best regards, Ivan Roshchin.

From Ivan Roshin To All 2 October 2002

Hello, All! ═══════════════════ 12 .C ══════════════════ Appendix 3 ──────────── Here are the texts of procedures for displaying images six different ways discussed in the article. Original the image (256*192, with 256 gradations of brightness) should be pre-placed in three banks of RAM, the numbers of which (more precisely, numbers output to port #7FFD for their connection) are indicated in N_BANK array (by default there are #10, #11 and #13). Information about pixels are stored "from left to right, top to bottom": in the first bank - the upper third of the image, in the second - the middle, in the third - lower Before using the procedures you must determine the brightness gradations for your computer-monitor system (see Appendix 2) and place the resulting values in the arrays BRIGHT_0 and BRIGHT_1. The default values for my system are there, which will not exactly match yours. Of course you can Leave them too, but the output quality will be worse. In procedures using multicolor, all delays designed for the Pentagon. For different computer model them, will most likely have to change. 1. Procedure for displaying an image in black and white mode with 15 gradations of brightness (as in Fig. 5). Forms an image in screen area. ORG #6000 CALL CLS_1 ;Start of the main loop. LD DE,0 MAIN PUSH DEPUSH DE ;Take the initial data of the familiarity: LD B,8 LD HL,PIX_SRC CALL GET_DATA ;We process: LD HL,PIX_SRC LD DE,PIX_DST LD B,64 LD C,9 CALL WORK_DATA ;Determine the attribute address for the current ; familiarity and place the value there: POP DE CALL GET_A_ATR LD(HL),A ;Place information about pixels ;current acquaintance: LD B,8 LD HL,PIX_DST MAIN_1 PUSH BC PUSH DE LD B,8 MAIN_2 PUSH BC LD C,(HL) INC HL LD B,(HL) INC HL CALL SET_TP_1 INC D POP B.C. DJNZ MAIN_2 POP DE INC E POP B.C. DJNZ MAIN_1 ;Move on to the next familiarity: POP DE LD A,D ADD A,8 LD D,A JR NZ,MAIN LD A,E ADD A,8 LD E,A CP 192 JR NZ,MAIN ;End of main loop. RET PIX_SRC DS 8*8 PIX_DST DS 8*8*2 ════════════════════════ ════════════════════════ Best regards, Ivan Roshchin.

From Ivan Roshin To All 2 October 2002

Hello, All! ═══════════════════ 12 .C ══════════════════ Appendix 3 ──────────── Here are the texts of procedures for displaying images six different ways discussed in the article. Original the image (256*192, with 256 gradations of brightness) should be pre-placed in three banks of RAM, the numbers of which (more precisely, numbers output to port #7FFD for their connection) are indicated in N_BANK array (by default there are #10, #11 and #13). Information about pixels are stored "from left to right, top to bottom": in the first bank - the upper third of the image, in the second - the middle, in the third - lower Before using the procedures you must determine the brightness gradations for your computer-monitor system (see Appendix 2) and place the resulting values in the arrays BRIGHT_0 and BRIGHT_1. The default values for my system are there, which will not exactly match yours. Of course you can Leave them too, but the output quality will be worse. In procedures using multicolor, all delays designed for the Pentagon. For different computer model them, will most likely have to change. 1. Procedure for displaying an image in black and white mode with 15 gradations of brightness (as in Fig. 5). Forms an image in screen area. ORG #6000 CALL CLS_1 ;Start of the main loop. LD DE,0 MAIN PUSH DEPUSH DE ;Take the initial data of the familiarity: LD B,8 LD HL,PIX_SRC CALL GET_DATA ;We process: LD HL,PIX_SRC LD DE,PIX_DST LD B,64 LD C,9 CALL WORK_DATA ;Determine the attribute address for the current ; familiarity and place the value there: POP DE CALL GET_A_ATR LD(HL),A ;Place information about pixels ;current acquaintance: LD B,8 LD HL,PIX_DST MAIN_1 PUSH BC PUSH DE LD B,8 MAIN_2 PUSH BC LD C,(HL) INC HL LD B,(HL) INC HL CALL SET_TP_1 INC D POP B.C. DJNZ MAIN_2 POP DE INC E POP B.C. DJNZ MAIN_1 ;Move on to the next familiarity: POP DE LD A,D ADD A,8 LD D,A JR NZ,MAIN LD A,E ADD A,8 LD E,A CP 192 JR NZ,MAIN ;End of main loop. RET PIX_SRC DS 8*8 PIX_DST DS 8*8*2 ════════════════════════ ════════════════════════ Best regards, Ivan Roshchin.

From Ivan Roshin To All 2 October 2002

Hello, All! ═══════════════════ 13.C ══════════════════ 2. Procedure for displaying an image with double attribute resolution through the use of multicolor (as in fig. 6). Forms the upper halves of familiarity with its attributes on the first screen, and the lower halves with their own attributes - on the second. Then, when the beam draws the upper halves of the familiarity, the first one is set as active screen, and when the lower halves are the second. Exit mode viewing - by pressing any key. ORG #6000 CALL CLS_1 CALL CLS_2 ;Start of the main loop. LD DE,0 MAIN PUSH DE PUSH DE ;Take the initial data of the 8*4 area: LD B,4 LD HL,PIX_SRC CALL GET_DATA ;We process: LD HL,PIX_SRC LD DE,PIX_DST LD B,32 LD C,9 CALL WORK_DATA ;Depending on whether the top or ;the lower half of the familiarity area is processed- ;Yes, the result should be placed on ;first or second screen. Installed ;we enter the address of the corresponding procedure: POP DE LD HL,SET_TP_1 BIT 2,E JR Z,MAIN_A LD HL,SET_TP_2 MAIN_A LD (ADR_CALL),HL ;Place the attribute: CALL GET_A_ATR BIT 2,E JR Z,MAIN_BSET 7,H EX AF,AF' LD A,#17 CALL SETPORT EX AF,AF' MAIN_B LD (HL),A ;Place pixels: LD B,4 LD HL,PIX_DST MAIN_1 PUSH BC PUSH DE LD B,8 MAIN_2 PUSH BC LD C,(HL) INC HL LD B,(HL) INC HL CALL SET_TP_1 ;or SET_TP_2 ADR_CALL EQU $-2 INC D POP B.C. DJNZ MAIN_2 POP DE INC E POP B.C. DJNZ MAIN_1 ;Move on to the next area: POP DE LD A,D ADD A,8 LD D,A JR NZ,MAIN LD A,E ADD A,4 LD E,A CP 192 JR NZ,MAIN ;End of main loop. ;Image output: every 4 ;lines change the active screen. CALL ON_IM2 VIEW_LOOP HALT LD HL,17762 CALL WAIT LD B,24 VIEW_1 LD A,#10 CALL SETPORT EXX LD HL,814 CALL WAIT EXX LD A,#18 CALL SETPORT EXX LD HL,795 CALL WAIT EXX DJNZ VIEW_1 ;Keyboard polling: XOR A IN A,(254) CPL AND #1FJR Z,VIEW_LOOP ;Exit when pressing any key: CALL OFF_IM2 RET PIX_SRC DS 8*4 PIX_DST DS 8*4*2 ════════════════════════ ════════════════════════ Best regards, Ivan Roshchin.

From Ivan Roshin To All 2 October 2002

Hello, All! ═══════════════════ 14 .C ══════════════════ 3. Procedure for displaying an image with maximum attribute resolution (as in Fig. 7). When forming an image pixel information is written to the screen area, and information about attributes (#1800 bytes - your own attribute for each line of familiarity) is recorded in the ATR array (by by default located at address #8000). Then to the area attributes attributes for the first line are placed; bye beam draws the first line, placed in the attribute area attributes of the second line, and so on. Since in 224 cycles (time to draw one line) can’t reroll 32 byte of attributes, the procedure does not display the entire image, but in a window measuring 11 familiar spaces (88 pixels) horizontally. You can use the "O" and "P" keys to move the window around the image. left/right. Exit viewing mode by pressing the space bar. ATR EQU #8000 ;Attributes (#1800). LINES EQU #7200 ;Attribute addresses ;on screen (#180). ORG #6000 LD HL,ATR LD (ATR_ADR),HL CALL CLS_1 ;Set PAPER 0: INK 7 to ;you could see the construction process ;images: LD HL,#5800 LD (HL),7 LD DE,#5801 LD BC,#2FF LDIR ;Start of the main loop.LD DE,0 MAIN PUSH DE PUSH DE ;Take the initial data of the area 8*1: LD B,1 LD HL,PIX_SRC CALL GET_DATA ;We process: LD HL,PIX_SRC LD DE,PIX_DST LD B,8 LD C,9 CALL WORK_DATA ;Place the attribute: LD HL,0 ATR_ADR EQU $-2 LD(HL),A INC HL LD (ATR_ADR),HL ;Place pixels: POP DE LD HL,PIX_DST LD B,8 MAIN_1 PUSH BC LD C,(HL) INC HL LD B,(HL) INC HL CALL SET_TP_1 INC D POP B.C. DJNZ MAIN_1 ;Move on to the next area: POP DE LD A,D ADD A,8 LD D,A JR NZ,MAIN INC E LD A,E CP 192 JR NZ,MAIN ;End of main loop. ;Image output: CALL ON_IM2 VIEW_LOOP HALT LD(SAVE_SP),SP D.I. ;Clear the attribute area: LD SP,#5B00 LD HL,0 LD B,48 CLS_ATR PUSH HL PUSH HL PUSH HL PUSH HL PUSH HL PUSH HL PUSH HL PUSH HL DJNZ CLS_ATR ════════════════════════ ════════════════════════Best regards, Ivan Roshchin.

From Ivan Roshin To All 2 October 2002

Hello, All! ═══════════════════ 13.C ══════════════════ 2. Procedure for displaying an image with double attribute resolution through the use of multicolor (as in fig. 6). Forms the upper halves of familiarity with its attributes on the first screen, and the lower halves with their own attributes - on the second. Then, when the beam draws the upper halves of the familiarity, the first one is set as active screen, and when the lower halves are the second. Exit mode viewing - by pressing any key. ORG #6000 CALL CLS_1 CALL CLS_2 ;Start of the main loop. LD DE,0 MAIN PUSH DE PUSH DE ;Take the initial data of the 8*4 area: LD B,4 LD HL,PIX_SRC CALL GET_DATA ;We process: LD HL,PIX_SRC LD DE,PIX_DST LD B,32 LD C,9 CALL WORK_DATA ;Depending on whether the top or ;the lower half of the familiarity area is processed- ;Yes, the result should be placed on ;first or second screen. Installed ;we enter the address of the corresponding procedure: POP DE LD HL,SET_TP_1 BIT 2,E JR Z,MAIN_A LD HL,SET_TP_2 MAIN_A LD (ADR_CALL),HL ;Place the attribute: CALL GET_A_ATR BIT 2,E JR Z,MAIN_BSET 7,H EX AF,AF' LD A,#17 CALL SETPORT EX AF,AF' MAIN_B LD (HL),A ;Place pixels: LD B,4 LD HL,PIX_DST MAIN_1 PUSH BC PUSH DE LD B,8 MAIN_2 PUSH BC LD C,(HL) INC HL LD B,(HL) INC HL CALL SET_TP_1 ;or SET_TP_2 ADR_CALL EQU $-2 INC D POP B.C. DJNZ MAIN_2 POP DE INC E POP B.C. DJNZ MAIN_1 ;Move on to the next area: POP DE LD A,D ADD A,8 LD D,A JR NZ,MAIN LD A,E ADD A,4 LD E,A CP 192 JR NZ,MAIN ;End of main loop. ;Image output: every 4 ;lines change the active screen. CALL ON_IM2 VIEW_LOOP HALT LD HL,17762 CALL WAIT LD B,24 VIEW_1 LD A,#10 CALL SETPORT EXX LD HL,814 CALL WAIT EXX LD A,#18 CALL SETPORT EXX LD HL,795 CALL WAIT EXX DJNZ VIEW_1 ;Keyboard polling: XOR A IN A,(254) CPL AND #1FJR Z,VIEW_LOOP ;Exit when pressing any key: CALL OFF_IM2 RET PIX_SRC DS 8*4 PIX_DST DS 8*4*2 ════════════════════════ ════════════════════════ Best regards, Ivan Roshchin.

From Ivan Roshin To All 2 October 2002

Hello, All! ═══════════════════ 14 .C ══════════════════ 3. Procedure for displaying an image with maximum attribute resolution (as in Fig. 7). When forming an image pixel information is written to the screen area, and information about attributes (#1800 bytes - your own attribute for each line of familiarity) is recorded in the ATR array (by by default located at address #8000). Then to the area attributes attributes for the first line are placed; bye beam draws the first line, placed in the attribute area attributes of the second line, and so on. Since in 224 cycles (time to draw one line) can’t reroll 32 byte of attributes, the procedure does not display the entire image, but in a window measuring 11 familiar spaces (88 pixels) horizontally. You can use the "O" and "P" keys to move the window around the image. left/right. Exit viewing mode by pressing the space bar. ATR EQU #8000 ;Attributes (#1800). LINES EQU #7200 ;Attribute addresses ;on screen (#180). ORG #6000 LD HL,ATR LD (ATR_ADR),HL CALL CLS_1 ;Set PAPER 0: INK 7 to ;you could see the construction process ;images: LD HL,#5800 LD (HL),7 LD DE,#5801 LD BC,#2FF LDIR ;Start of the main loop.LD DE,0 MAIN PUSH DE PUSH DE ;Take the initial data of the area 8*1: LD B,1 LD HL,PIX_SRC CALL GET_DATA ;We process: LD HL,PIX_SRC LD DE,PIX_DST LD B,8 LD C,9 CALL WORK_DATA ;Place the attribute: LD HL,0 ATR_ADR EQU $-2 LD(HL),A INC HL LD (ATR_ADR),HL ;Place pixels: POP DE LD HL,PIX_DST LD B,8 MAIN_1 PUSH BC LD C,(HL) INC HL LD B,(HL) INC HL CALL SET_TP_1 INC D POP B.C. DJNZ MAIN_1 ;Move on to the next area: POP DE LD A,D ADD A,8 LD D,A JR NZ,MAIN INC E LD A,E CP 192 JR NZ,MAIN ;End of main loop. ;Image output: CALL ON_IM2 VIEW_LOOP HALT LD(SAVE_SP),SP D.I. ;Clear the attribute area: LD SP,#5B00 LD HL,0 LD B,48 CLS_ATR PUSH HL PUSH HL PUSH HL PUSH HL PUSH HL PUSH HL PUSH HL PUSH HL DJNZ CLS_ATR ════════════════════════ ════════════════════════Best regards, Ivan Roshchin.

From Ivan Roshin To All 2 October 2002

Hello, All! ═══════════════════ 15.C ══════════════════ ;Create a table of attribute addresses: MAKE_LT LD HL,#5AE0 LD DE,0 X EQU $-2 ADD HL,DE LD SP,LINES+#180 LD DE,-#20 LD B,24 MAKE_LT_1 PUSH HL PUSH HL PUSH HL PUSH HL PUSH HL PUSH HL PUSH HL PUSH HL ADD HL,DE DJNZ MAKE_LT_1 ;The larger X, the larger it should be ;delay: X is greater by 1 - delay ;more by 4 bars. LD HL,(X) ADD HL,HL ADD HL,HL LD DE,9987 ADD HL,DE CALL WAIT ;We display our attributes in each line: LD A,192 LD HL,ATR X_2 EQU $-2 LD SP,LINES LD B,0 ;Execution time of the following ;section - 224 clock cycles, which is equal to time ;draws one line of the image. ONE_LINE LD C,32 ;7 POP DE ;10 LDI ;16 LDI ;16 LDI ;16 LDI ;16 LDI ;16 LDI ;16 LDI ;16 LDI ;16 LDI ;16 LDI ;16 LDI ;16ADD HL,BC ;11 INC BC ;6 (WAIT) DEC A ;4 JP NZ,ONE_LINE ;10 LD SP,0 SAVE_SP EQU $-2 EI ;Keyboard polling: LD A,#DF IN A,(254) RRA JR C,NE_P ;Pressed key "P" - shift visible ;section to the right: LD A,(X) CP 21 JR NEW_X NE_P RRA JR C,NE_O ;The "O" key is pressed - shift the visible ;section to the left: LD A,(X) SUB 1 NEW_X ADC A,0 LD(X),A LD(X_2),A JP VIEW_LOOP ;If the spacebar is pressed, exit: NE_O LD A,#7F IN A,(254) RRA JP C,VIEW_LOOP CALL OFF_IM2 RET PIX_SRC DS 8 PIX_DST DS 8*2 ════════════════════════ ════════════════════════ Best regards, Ivan Roshchin.

From Ivan Roshin To All 2 October 2002

Hello, All! ═══════════════════ 15.C ══════════════════ ;Create a table of attribute addresses: MAKE_LT LD HL,#5AE0 LD DE,0 X EQU $-2 ADD HL,DE LD SP,LINES+#180 LD DE,-#20 LD B,24 MAKE_LT_1 PUSH HL PUSH HL PUSH HL PUSH HL PUSH HL PUSH HL PUSH HL PUSH HL ADD HL,DE DJNZ MAKE_LT_1 ;The larger X, the larger it should be ;delay: X is greater by 1 - delay ;more by 4 bars. LD HL,(X) ADD HL,HL ADD HL,HL LD DE,9987 ADD HL,DE CALL WAIT ;We display our attributes in each line: LD A,192 LD HL,ATR X_2 EQU $-2 LD SP,LINES LD B,0 ;Execution time of the following ;section - 224 clock cycles, which is equal to time ;draws one line of the image. ONE_LINE LD C,32 ;7 POP DE ;10 LDI ;16 LDI ;16 LDI ;16 LDI ;16 LDI ;16 LDI ;16 LDI ;16 LDI ;16 LDI ;16 LDI ;16 LDI ;16ADD HL,BC ;11 INC BC ;6 (WAIT) DEC A ;4 JP NZ,ONE_LINE ;10 LD SP,0 SAVE_SP EQU $-2 EI ;Keyboard polling: LD A,#DF IN A,(254) RRA JR C,NE_P ;The "P" key is pressed - shift the visible ;section to the right: LD A,(X) CP 21 JR NEW_X NE_P RRA JR C,NE_O ;The "O" key is pressed - shift the visible ;section to the left: LD A,(X) SUB 1 NEW_X ADC A,0 LD(X),A LD(X_2),A JP VIEW_LOOP ;If the spacebar is pressed, exit: NE_O LD A,#7F IN A,(254) RRA JP C,VIEW_LOOP CALL OFF_IM2 RET PIX_SRC DS 8 PIX_DST DS 8*2 ════════════════════════ ════════════════════════ Best regards, Ivan Roshchin.

From Ivan Roshin To All 2 October 2002

Hello, All! ═══════════════════ 16.C ══════════════════ 4. Procedure for outputting an image with improved quality for by quickly alternating two images (as in Fig. 9). Forms one image on the first screen, another on the second, and then changes the active screen in each frame. Exit from viewing mode - by pressing any key. ORG #6000 CALL CLS_1 CALL CLS_2 ;Start of the main loop. LD DE,0 MAIN PUSH DE PUSH DE ;Take the initial data of the familiarity: LD B,8 LD HL,PIX_SRC CALL GET_DATA ;We process: LD HL,PIX_SRC LD DE,PIX_DST LD B,64 LD C,10 CALL WORK_DATA ;Write down the attribute: POP DE CALL GET_A_ATR LD(HL),A ;Output pixels: LD B,8 LD HL,PIX_DST CALL PUT_DATA ;Move on to the next familiarity: POP DE LD A,D ADD A,8 LD D,A JR NZ,MAIN LD A,E ADD A,8 LD E,A CP 192 JR NZ,MAIN ;End of main loop. CALL A_FLICKER ;Copy the attributes to the second screen: LD A,#17 CALL SETPORT LD HL,#5800LD DE,#D800 LD BC,#300 LDIR ;Switch screens every 1/50 second: LD A,#10 OUTPUT HALT XOR 8 CALL SETPORT LD B,A XOR A IN A,(254) CPL AND #1F LD A,B JR Z,OUTPUT RET PIX_SRC DS 8*8 PIX_DST DS 8*8*2 ════════════════════════ ════════════════════════ Best regards, Ivan Roshchin.

From Ivan Roshin To All 2 October 2002

Hello, All! ═══════════════════ 16.C ══════════════════ 4. Procedure for outputting an image with improved quality for by quickly alternating two images (as in Fig. 9). Forms one image on the first screen, another on the second, and then changes the active screen in each frame. Exit from viewing mode - by pressing any key. ORG #6000 CALL CLS_1 CALL CLS_2 ;Start of the main loop. LD DE,0 MAIN PUSH DE PUSH DE ;Take the initial data of the familiarity: LD B,8 LD HL,PIX_SRC CALL GET_DATA ;We process: LD HL,PIX_SRC LD DE,PIX_DST LD B,64 LD C,10 CALL WORK_DATA ;Write down the attribute: POP DE CALL GET_A_ATR LD(HL),A ;Output pixels: LD B,8 LD HL,PIX_DST CALL PUT_DATA ;Move on to the next familiarity: POP DE LD A,D ADD A,8 LD D,A JR NZ,MAIN LD A,E ADD A,8 LD E,A CP 192 JR NZ,MAIN ;End of main loop. CALL A_FLICKER ;Copy the attributes to the second screen: LD A,#17 CALL SETPORT LD HL,#5800LD DE,#D800 LD BC,#300 LDIR ;Switch screens every 1/50 second: LD A,#10 OUTPUT HALT XOR 8 CALL SETPORT LD B,A XOR A IN A,(254) CPL AND #1F LD A,B JR Z,OUTPUT RET PIX_SRC DS 8*8 PIX_DST DS 8*8*2 ════════════════════════ ════════════════════════ Best regards, Ivan Roshchin.

From Ivan Roshin To All 2 October 2002

Hello, All! ═══════════════════ 17.C ══════════════════ 5. Procedure for displaying images with fast interleave and double attribute resolution (as in Fig. 12). When records pixel information when forming an image the first image to the first screen, and the second image to to the second screen. Attributes (#600 bytes) are written to an array ATR. Further, in the first frame, when the beam draws the upper half of the familiarity, the first screen is set to active, and when the lower halves are the second. In the next frame, on the contrary, the upper halves of the familiarity are taken from the second screen, and the lower ones - from the first, and so on. While the beam draws the upper halves of the familiarity are recorded on the other screen attributes for the lower halves are familiar, and when the beam draws the lower halves, they are recorded on another screen attributes for the upper halves of the next line are familiar, and so on further. Exit viewing mode by pressing any key. ATR EQU #8000 ;Attributes (#600) ORG #6000 LD HL,ATR LD (ATR_ADR),HL LD A,#D8 LD(ATR_SCR),A CALL CLS_1 CALL CLS_2 ;Set PAPER 0: INK 7 to ;you could see the construction process ;images: LD HL,#5800 LD (HL),7 LD DE,#5801LD BC,#2FF LDIR ;Start of the main loop. LD DE,0 MAIN PUSH DE PUSH DE ;Take the initial data of half ;familiar places: LD B,4 LD HL,PIX_SRC CALL GET_DATA ;We process: LD HL,PIX_SRC LD DE,PIX_DST LD B,32 LD C,10 CALL WORK_DATA ;Write down the attribute: LD HL,0 ATR_ADR EQU $-2 LD(HL),A INC HL LD (ATR_ADR),HL ;Output pixels: POP DE LD B,4 LD HL,PIX_DST CALL PUT_DATA ;Move on to the next half ;familiar places: POP DE LD A,D ADD A,8 LD D,A JR NZ,MAIN LD A,E ADD A,4 LD E,A CP 192 JR NZ,MAIN ;End of main loop. CALL A_FLICKER ;Image output: CALL ON_IM2 LD XH,#17 VIEW_LOOP HALT LD HL,16982 CALL WAIT LD XL,#18 LD HL,ATR LD DE,0 ;#5800 or #D800 ATR_SCR EQU $-1 LD B,E ;=LD B,0 ;Display attributes on one of the screens: VIEW_4PIX PUSH DE LD C,#20 LD A,D XOR #80 LD D,A VIEW_1 LDI:LDI:LDI:LDILDI:LDI:LDI:LDI JP PE,VIEW_1 POP DE EXX LD HL,193 CALL WAIT EXX ;Make this screen active: LD A,XH CALL SETPORT ;Display attributes on another screen: LD C,#20 VIEW_2 LDI:LDI:LDI:LDI LDI:LDI:LDI:LDI JP PE,VIEW_2 EXX LD HL,246 CALL WAIT EXX ;Make this screen active: LD A,XH XOR 8 CALL SETPORT DEC XL JR NZ,VIEW_4PIX ;In the next frame the screens change ;in places: LD A,XH XOR 8 LD XH,A LD A,(ATR_SCR) XOR #80 LD(ATR_SCR),A ;Keyboard polling: XOR A IN A,(254) CPL AND #1F JR Z,VIEW_LOOP ;Exit by pressing any key: CALL OFF_IM2 RET PIX_SRC DS 8*4 PIX_DST DS 8*4*2 ════════════════════════ ════════════════════════ Best regards, Ivan Roshchin.

From Ivan Roshin To All 2 October 2002

Hello, All! ═══════════════════ 17.C ══════════════════ 5. Procedure for displaying images with fast interleave and double attribute resolution (as in Fig. 12). When records pixel information when forming an image the first image to the first screen, and the second image to to the second screen. Attributes (#600 bytes) are written to an array ATR. Further, in the first frame, when the beam draws the upper half of the familiarity, the first screen is set to active, and when the lower halves are the second. In the next frame, on the contrary, the upper halves of the familiarity are taken from the second screen, and the lower ones - from the first, and so on. While the beam draws the upper halves of the familiarity are recorded on the other screen attributes for the lower halves are familiar, and when the beam draws the lower halves, they are recorded on another screen attributes for the upper halves of the next line are familiar, and so on further. Exit viewing mode by pressing any key. ATR EQU #8000 ;Attributes (#600) ORG #6000 LD HL,ATR LD (ATR_ADR),HL LD A,#D8 LD(ATR_SCR),A CALL CLS_1 CALL CLS_2 ;Set PAPER 0: INK 7 to ;you could see the construction process ;images: LD HL,#5800 LD (HL),7 LD DE,#5801LD BC,#2FF LDIR ;Start of the main loop. LD DE,0 MAIN PUSH DE PUSH DE ;Take the initial data of half ;familiar places: LD B,4 LD HL,PIX_SRC CALL GET_DATA ;We process: LD HL,PIX_SRC LD DE,PIX_DST LD B,32 LD C,10 CALL WORK_DATA ;Write down the attribute: LD HL,0 ATR_ADR EQU $-2 LD(HL),A INC HL LD (ATR_ADR),HL ;Output pixels: POP DE LD B,4 LD HL,PIX_DST CALL PUT_DATA ;Move on to the next half ;familiar places: POP DE LD A,D ADD A,8 LD D,A JR NZ,MAIN LD A,E ADD A,4 LD E,A CP 192 JR NZ,MAIN ;End of main loop. CALL A_FLICKER ;Image output: CALL ON_IM2 LD XH,#17 VIEW_LOOP HALT LD HL,16982 CALL WAIT LD XL,#18 LD HL,ATR LD DE,0 ;#5800 or #D800 ATR_SCR EQU $-1 LD B,E ;=LD B,0 ;Display attributes on one of the screens: VIEW_4PIX PUSH DE LD C,#20 LD A,D XOR #80 LD D,A VIEW_1 LDI:LDI:LDI:LDILDI:LDI:LDI:LDI JP PE,VIEW_1 POP DE EXX LD HL,193 CALL WAIT EXX ;Make this screen active: LD A,XH CALL SETPORT ;Display attributes on another screen: LD C,#20 VIEW_2 LDI:LDI:LDI:LDI LDI:LDI:LDI:LDI JP PE,VIEW_2 EXX LD HL,246 CALL WAIT EXX ;Make this screen active: LD A,XH XOR 8 CALL SETPORT DEC XL JR NZ,VIEW_4PIX ;In the next frame the screens change ;in places: LD A,XH XOR 8 LD XH,A LD A,(ATR_SCR) XOR #80 LD(ATR_SCR),A ;Keyboard polling: XOR A IN A,(254) CPL AND #1F JR Z,VIEW_LOOP ;Exit by pressing any key: CALL OFF_IM2 RET PIX_SRC DS 8*4 PIX_DST DS 8*4*2 ════════════════════════ ════════════════════════ Best regards, Ivan Roshchin.

From Ivan Roshin To All 2 October 2002

Hello, All! ═══════════════════ 18.C ══════════════════ 6. Procedure for outputting images with fast interleave and maximum attribute resolution (as in Fig. 13). When records pixel information when forming an image the first image on the first screen, the second image on second screen, and attribute values (#1800 bytes) into an array ATR. Then, as in procedure 3, the attribute area dynamically updated. Active screen in every frame is changing. The image is displayed in a window of size 11 characters (88 pixels) horizontally. Using the "O" and "P" keys, the window can be move around the image left/right. Exit mode viewing - by pressing the space bar. ATR EQU #8000 ;Attributes (#1800). LINES EQU #7200 ;Attribute addresses ;on screen (#180). ORG #6000 LD HL,ATR LD (ATR_ADR),HL CALL CLS_1 CALL CLS_2 ;Set PAPER 0: INK 7 to ;you could see the construction process ;images: LD HL,#5800 LD (HL),7 LD DE,#5801 LD BC,#2FF LDIR ;Start of the main loop. LD DE,0 MAIN PUSH DE PUSH DE ;We take the initial data of the familiarity line: LD B,1 LD HL,PIX_SRC CALL GET_DATA ;We process:LD HL,PIX_SRC LD DE,PIX_DST LD B,8 LD C,10 CALL WORK_DATA ;Write down the attribute: LD HL,0 ATR_ADR EQU $-2 LD(HL),A INC HL LD (ATR_ADR),HL ;Output pixels: POP DE LD B,1 LD HL,PIX_DST CALL PUT_DATA ;Move on to the next familiarity line: POP DE LD A,D ADD A,8 LD D,A JR NZ,MAIN INC E LD A,E CP 192 JR NZ,MAIN ;End of main loop. CALL A_FLICKER ;Image output: CALL ON_IM2 VIEW_LOOP HALT LD(SAVE_SP),SP D.I. ;Clear the attribute area: CLS_ATR LD SP,#5B00 LD HL,0 LD B,48 CLS_ATR_1 PUSH HL PUSH HL PUSH HL PUSH HL PUSH HL PUSH HL PUSH HL PUSH HL DJNZ CLS_ATR_1 ════════════════════════ ════════════════════════ Best regards, Ivan Roshchin.

From Ivan Roshin To All 2 October 2002

Hello, All! ═══════════════════ 18.C ══════════════════ 6. Procedure for outputting images with fast interleave and maximum attribute resolution (as in Fig. 13). When records pixel information when forming an image the first image on the first screen, the second image on second screen, and attribute values (#1800 bytes) into an array ATR. Then, as in procedure 3, the attribute area dynamically updated. Active screen in every frame is changing. The image is displayed in a window of size 11 characters (88 pixels) horizontally. Using the "O" and "P" keys, the window can be move around the image left/right. Exit mode viewing - by pressing the space bar. ATR EQU #8000 ;Attributes (#1800). LINES EQU #7200 ;Attribute addresses ;on screen (#180). ORG #6000 LD HL,ATR LD (ATR_ADR),HL CALL CLS_1 CALL CLS_2 ;Set PAPER 0: INK 7 to ;you could see the construction process ;images: LD HL,#5800 LD (HL),7 LD DE,#5801 LD BC,#2FF LDIR ;Start of the main loop. LD DE,0 MAIN PUSH DE PUSH DE ;We take the initial data of the familiarity line: LD B,1 LD HL,PIX_SRC CALL GET_DATA ;We process:LD HL,PIX_SRC LD DE,PIX_DST LD B,8 LD C,10 CALL WORK_DATA ;Write down the attribute: LD HL,0 ATR_ADR EQU $-2 LD(HL),A INC HL LD (ATR_ADR),HL ;Output pixels: POP DE LD B,1 LD HL,PIX_DST CALL PUT_DATA ;Move on to the next familiarity line: POP DE LD A,D ADD A,8 LD D,A JR NZ,MAIN INC E LD A,E CP 192 JR NZ,MAIN ;End of main loop. CALL A_FLICKER ;Image output: CALL ON_IM2 VIEW_LOOP HALT LD(SAVE_SP),SP D.I. ;Clear the attribute area: CLS_ATR LD SP,#5B00 LD HL,0 LD B,48 CLS_ATR_1 PUSH HL PUSH HL PUSH HL PUSH HL PUSH HL PUSH HL PUSH HL PUSH HL DJNZ CLS_ATR_1 ════════════════════════ ════════════════════════ Best regards, Ivan Roshchin.

From Ivan Roshin To All 2 October 2002

Hello, All! ═══════════════════ 19.C ══════════════════ ;Create a table of attribute addresses: MAKE_LT LD HL,#5AE0 LD DE,0 X EQU $-2 ADD HL,DE LD SP,LINES+#180 LD DE,-#20 LD B,24 MAKE_LT_1 PUSH HL PUSH HL PUSH HL PUSH HL PUSH HL PUSH HL PUSH HL PUSH HL ADD HL,DE DJNZ MAKE_LT_1 ;The larger X, the larger it should be ;delay: X is greater by 1 - delay ;more by 4 bars. LD HL,(X) ADD HL,HL ADD HL,HL LD DE,9987 ADD HL,DE CALL WAIT ;We display our attributes in each line: LD A,192 LD HL,ATR X_2 EQU $-2 LD SP,LINES LD B,0 ;Execution time of the following ;section - 224 clock cycles, which is equal to time ;draws one line of the image. ONE_LINE LD C,32 ;7 POP DE ;10 LDI ;16 LDI ;16 LDI ;16 LDI ;16 LDI ;16 LDI ;16 LDI ;16 LDI ;16 LDI ;16 LDI ;16 LDI ;16ADD HL,BC ;11 INC BC ;6 (WAIT) DEC A ;4 JP NZ,ONE_LINE ;10 LD SP,0 SAVE_SP EQU $-2 EI ;Delay so that the beam has time to draw ;the last line of the image before ;how to set another active screen: LD HL,224 CALL WAIT ;Set another screen: LD A,#10 N_SCR EQU $-1 XOR #0F LD(N_SCR),A CALL SETPORT ;Change the starting address in the procedure ;clearing the attribute area and in the procedure ;building a table of attribute addresses: LD HL,CLS_ATR+2 LD A,(HL) XOR #80 LD(HL),A LD HL,MAKE_LT+2 LD A,(HL) XOR #80 LD(HL),A ;Keyboard polling: LD A,#DF IN A,(254) RRA JR C,NE_P ;Pressed key "P" - shift visible ;section to the right: LD A,(X) CP 21 JR NEW_X NE_P RRA JR C,NE_O ;The "O" key is pressed - shift the visible ;section to the left: LD A,(X) SUB 1 NEW_X ADC A,0 LD(X),A LD(X_2),A JP VIEW_LOOP ;If the spacebar is pressed, exit: NE_O LD A,#7F IN A,(254) RRA JP C,VIEW_LOOPCALL OFF_IM2 RET PIX_SRC DS 8 PIX_DST DS 8*2 ════════════════════════ ════════════════════════ Best regards, Ivan Roshchin.

From Ivan Roshin To All 2 October 2002

Hello, All! ═══════════════════ 19.C ══════════════════ ;Create a table of attribute addresses: MAKE_LT LD HL,#5AE0 LD DE,0 X EQU $-2 ADD HL,DE LD SP,LINES+#180 LD DE,-#20 LD B,24 MAKE_LT_1 PUSH HL PUSH HL PUSH HL PUSH HL PUSH HL PUSH HL PUSH HL PUSH HL ADD HL,DE DJNZ MAKE_LT_1 ;The larger X, the larger it should be ;delay: X is greater by 1 - delay ;more by 4 bars. LD HL,(X) ADD HL,HL ADD HL,HL LD DE,9987 ADD HL,DE CALL WAIT ;We display our attributes in each line: LD A,192 LD HL,ATR X_2 EQU $-2 LD SP,LINES LD B,0 ;Execution time of the following ;section - 224 clock cycles, which is equal to time ;draws one line of the image. ONE_LINE LD C,32 ;7 POP DE ;10 LDI ;16 LDI ;16 LDI ;16 LDI ;16 LDI ;16 LDI ;16 LDI ;16 LDI ;16 LDI ;16 LDI ;16 LDI ;16ADD HL,BC ;11 INC BC ;6 (WAIT) DEC A ;4 JP NZ,ONE_LINE ;10 LD SP,0 SAVE_SP EQU $-2 EI ;Delay so that the beam has time to draw ;the last line of the image before ;how to set another active screen: LD HL,224 CALL WAIT ;Set another screen: LD A,#10 N_SCR EQU $-1 XOR #0F LD(N_SCR),A CALL SETPORT ;Change the starting address in the procedure ;clearing the attribute area and in the procedure ;building a table of attribute addresses: LD HL,CLS_ATR+2 LD A,(HL) XOR #80 LD(HL),A LD HL,MAKE_LT+2 LD A,(HL) XOR #80 LD(HL),A ;Keyboard polling: LD A,#DF IN A,(254) RRA JR C,NE_P ;The "P" key is pressed - shift the visible ;section to the right: LD A,(X) CP 21 JR NEW_X NE_P RRA JR C,NE_O ;The "O" key is pressed - shift the visible ;section to the left: LD A,(X) SUB 1 NEW_X ADC A,0 LD(X),A LD(X_2),A JP VIEW_LOOP ;If the spacebar is pressed, exit: NE_O LD A,#7F IN A,(254) RRA JP C,VIEW_LOOPCALL OFF_IM2 RET PIX_SRC DS 8 PIX_DST DS 8*2 ════════════════════════ ════════════════════════ Best regards, Ivan Roshchin.

From Ivan Roshin To All 2 October 2002

Hello, All! ═══════════════════ 20 .C ══════════════════ General part of withdrawal procedures ─────────────────────────── GAMMA_CORR EQU 0 ;Execute ;gamma correction? ;--------------------------------------- ;Numbers of memory banks in which ;the original image is stored: N_BANK DB #10,#11,#13 ;257-byte table to indicate ;interrupt routine addresses ;(starts with an address that is a multiple of 256): INT_TAB EQU #7000 ;Interrupt routine address ;(high byte equals low): INT_ADR EQU #7171 ;Brightness gradations in 8.8 format: BRIGHT_0 DW 0.1112.2139.4412.6062 DW 14555,26811,46556 BRIGHT_1 DW 0.1369.3129.6062.8995 DW 21704,38045,65280 ;--------------------------------------- ;Screen cleaning procedures: CLS_1 LD HL,#4000 ;1st screen LD(HL),L LD DE,#4001 JR CLS CLS_2 LD A,#17 ;2nd screen CALL SETPORT LD HL,#C000 LD(HL),L LD DE,#C001 CLS LD BC,#1AFF LDIR RET ;--------------------------------------- ;Procedure GET_DATA - place in buffer ;information about the rectangular area ;images are 8 pixels wide. ; ;Input: DE - coordinates of the upper left ; area angle, ; B - area height, ; HL - buffer address.GET_DATA PUSH BC PUSH DE LD B,8 GET_DATA1 CALL GET_1R LD(HL),A INC HL INC D DJNZ GET_DATA1 POP DE INC E POP B.C. DJNZ GET_DATA RET ;--------------------------------------- ;Procedure PUT_DATA outputs pixels ;rectangular image area on ;first and second screens (for methods with ;quick change of two screens). ; ;Input: DE - coordinates of the upper left ; area angle, ; B - area height, ; HL - pixel data address. PUT_DATA PUSH BC PUSH DE LD B,8 PUT_D_1 PUSH BC LD C,(HL) INC HL LD B,(HL) INC HL ;If BC>=256, put it on the first screen ;turn on the pixel and reduce BC by ;256: INC B ;if B=0, then BC<256 DEC B JR Z,PUT_D_2 DEC B ;i.e. BC:=BC-256 CALL SET_P_1 ;Now BC is the texture number (0-256). ;Place a pixel with this on the second screen ;texture: PUT_D_2 CALL SET_TP_2 INC D POP B.C. DJNZ PUT_D_1 POP DE INC E POP B.C. DJNZ PUT_DATA RET ════════════════════════ ════════════════════════ Best regards, Ivan Roshchin.

From Ivan Roshin To All 2 October 2002

Hello, All! ═══════════════════ 20 .C ══════════════════ General part of withdrawal procedures ─────────────────────────── GAMMA_CORR EQU 0 ;Execute ;gamma correction? ;--------------------------------------- ;Numbers of memory banks in which ;the original image is stored: N_BANK DB #10,#11,#13 ;257-byte table to indicate ;interrupt routine addresses ;(starts with an address that is a multiple of 256): INT_TAB EQU #7000 ;Interrupt routine address ;(high byte equals low): INT_ADR EQU #7171 ;Brightness gradations in 8.8 format: BRIGHT_0 DW 0.1112.2139.4412.6062 DW 14555,26811,46556 BRIGHT_1 DW 0.1369.3129.6062.8995 DW 21704,38045,65280 ;--------------------------------------- ;Screen cleaning procedures: CLS_1 LD HL,#4000 ;1st screen LD(HL),L LD DE,#4001 JR CLS CLS_2 LD A,#17 ;2nd screen CALL SETPORT LD HL,#C000 LD(HL),L LD DE,#C001 CLS LD BC,#1AFF LDIR RET ;--------------------------------------- ;Procedure GET_DATA - place in buffer ;information about the rectangular area ;images are 8 pixels wide. ; ;Input: DE - coordinates of the upper left ; area angle, ; B - area height, ; HL - buffer address.GET_DATA PUSH BC PUSH DE LD B,8 GET_DATA1 CALL GET_1R LD(HL),A INC HL INC D DJNZ GET_DATA1 POP DE INC E POP B.C. DJNZ GET_DATA RET ;--------------------------------------- ;Procedure PUT_DATA outputs pixels ;rectangular image area on ;first and second screens (for methods with ;quick change of two screens). ; ;Input: DE - coordinates of the upper left ; area angle, ; B - area height, ; HL - pixel data address. PUT_DATA PUSH BC PUSH DE LD B,8 PUT_D_1 PUSH BC LD C,(HL) INC HL LD B,(HL) INC HL ;If BC>=256, put it on the first screen ;turn on the pixel and reduce BC by ;256: INC B ;if B=0, then BC<256 DEC B JR Z,PUT_D_2 DEC B ;i.e. BC:=BC-256 CALL SET_P_1 ;Now BC is the texture number (0-256). ;Place a pixel with this on the second screen ;texture: PUT_D_2 CALL SET_TP_2 INC D POP B.C. DJNZ PUT_D_1 POP DE INC E POP B.C. DJNZ PUT_DATA RET ════════════════════════ ════════════════════════ Best regards, Ivan Roshchin.

From Ivan Roshin To All 2 October 2002

Hello, All! ═══════════════════ 21.C ══════════════════ ;--------------------------------------- ;The WORK_DATA procedure determines by ;data about a certain area of pixels, ;what attribute to use when ;display, and what pseudogradation ;will be closest in brightness to ;each pixel. ; ;Gamma correction is carried out according to ;table GAMMA_T (if GAMMA_CORR=1). ; ;Input: HL - source data address ; (1 byte per pixel), ; B - number of pixels, ; C - number of pseudogradations ; (257 -> C=9; 513 -> C=10), ; DE - address of generated data ; (2 bytes per pixel). ; ;Output: A - attribute value, with DE ; data has been generated. ;Local variables (8.8): MIN_PIX DS 2 ;name original brightness MAX_PIX DS 2 ;max. original brightness MIN DS 2 ;brightness PAPER MAX DS 2 ;brightness INK ;The procedure itself went: WORK_DATA PUSH DE PUSH HL LD A,B LD(N_PIX_1),A LD A,C LD(DIV_CNT),A ;Determine the smallest and largest ;brightness values. LD DE,#FF00 ;start values WORK_ZN_1 LD A,(HL) CP D JR NC,WORK_ZN_2 LD D,A WORK_ZN_2 CP E JR C,WORK_ZN_3 LD E,A WORK_ZN_3 INC HL DJNZ WORK_ZN_1 ;D - the lowest brightness value,;E - greatest (without correction). ;We perform gamma correction and record ;adjusted values in MIN_PIX and ;MAX_PIX: IF GAMMA_CORR LD H,GAMMA_T/256 LD L,D LD B,(HL) INC H LD C,(HL) LD (MIN_PIX),BC LD L,E LD C,(HL) DEC H LD B,(HL) LD(MAX_PIX),BC ELSE LD B,D LD C,0 LD (MIN_PIX),BC LD B,E LD(MAX_PIX),BC ENDIF ;Find the smallest interval, in ;which contains the minimum and ;maximum value. ;If MAX_PIX is greater than BRIGHT_0 (7), then ;table BRIGHT_0 is definitely not ;consider: LD HL,(BRIGHT_0+14) AND A SBC HL,BC JR NC,TWO_TABL LD HL,BRIGHT_1 CALL DEF_MM LD A,1 JR OK_MINMAX ;Consider both tables: TWO_TABL LD HL,BRIGHT_1 CALL DEF_MM PUSH IX ;save on the stack EXX LD HL,BRIGHT_0 CALL DEF_MM ════════════════════════ ════════════════════════ Best regards, Ivan Roshchin.

From Ivan Roshin To All 2 October 2002

Hello, All! ═══════════════════ 21.C ══════════════════ ;--------------------------------------- ;The WORK_DATA procedure determines by ;data about a certain area of pixels, ;what attribute to use when ;display, and what pseudogradation ;will be closest in brightness to ;each pixel. ; ;Gamma correction is carried out according to ;table GAMMA_T (if GAMMA_CORR=1). ; ;Input: HL - source data address ; (1 byte per pixel), ; B - number of pixels, ; C - number of pseudogradations ; (257 -> C=9; 513 -> C=10), ; DE - address of generated data ; (2 bytes per pixel). ; ;Output: A - attribute value, with DE ; data has been generated. ;Local variables (8.8): MIN_PIX DS 2 ;name original brightness MAX_PIX DS 2 ;max. original brightness MIN DS 2 ;brightness PAPER MAX DS 2 ;brightness INK ;The procedure itself went: WORK_DATA PUSH DE PUSH HL LD A,B LD(N_PIX_1),A LD A,C LD(DIV_CNT),A ;Determine the smallest and largest ;brightness values. LD DE,#FF00 ;start values WORK_ZN_1 LD A,(HL) CP D JR NC,WORK_ZN_2 LD D,A WORK_ZN_2 CP E JR C,WORK_ZN_3 LD E,A WORK_ZN_3 INC HL DJNZ WORK_ZN_1 ;D - the lowest brightness value,;E - greatest (without correction). ;We perform gamma correction and record ;adjusted values in MIN_PIX and ;MAX_PIX: IF GAMMA_CORR LD H,GAMMA_T/256 LD L,D LD B,(HL) INC H LD C,(HL) LD (MIN_PIX),BC LD L,E LD C,(HL) DEC H LD B,(HL) LD(MAX_PIX),BC ELSE LD B,D LD C,0 LD (MIN_PIX),BC LD B,E LD(MAX_PIX),BC ENDIF ;Find the smallest interval, in ;which contains the minimum and ;maximum value. ;If MAX_PIX is greater than BRIGHT_0 (7), then ;table BRIGHT_0 is definitely not ;consider: LD HL,(BRIGHT_0+14) AND A SBC HL,BC JR NC,TWO_TABL LD HL,BRIGHT_1 CALL DEF_MM LD A,1 JR OK_MINMAX ;Consider both tables: TWO_TABL LD HL,BRIGHT_1 CALL DEF_MM PUSH IX ;save on the stack EXX LD HL,BRIGHT_0 CALL DEF_MM ════════════════════════ ════════════════════════ Best regards, Ivan Roshchin.

From Ivan Roshin To All 2 October 2002

Hello, All! ═══════════════════ 22.C ══════════════════ ;Compare HL and HL': LD(SAVE_HL),HL EXX PUSH DE PUSH HL LD DE,0 SAVE_HL EQU $-2 XOR A SBC HL,DE POP HL POP DE ADC A,0 JR NZ,OK_MM EXX POP HL ;IX is not needed on the stack JR OK_MINMAX OK_MM POP IX ;restore IX OK_MINMAX LD (MIN),DE LD(MAX),BC ;A - BRIGHT value (0 or 1) ;XH,XL - color numbers. ;Form the attribute value: RRCA ;0th bit RRCA ;becomes 6th LD B,A LD A,XH ADD A,A ADD A,A ADD A,A ;PAPER ADD A,XL ;+INK ADD A,B ;+BRIGHT ;Pixel processing: POP HL ;SOURCE POP DE ;DESTINY LD B,0 ;COUNTER N_PIX_1 EQU $-1 PUSH AF ;saved attributes PIX_LOOP PUSH HL IF GAMMA_CORR LD L,(HL) LD H,GAMMA_T/256 LD A,(HL) INC H LD L,(HL) LD H,A ELSE LD H,(HL) LD L,0 ENDIF EX (SP),HL INC HL EXX LD HL,(MAX) LD DE,(MIN) AND ASBC HL,DE ;Since MAX>MIN, flag C is cleared. LD B,H LD C,L ;BC - MAX-MIN in 256 parts. POP HL ;current brightness SBC HL,DE ;HL - current brightness-MIN in 256 parts. ;Divide HL by BC, getting inverted ;quotient (in 256 or 512 parts) in IX: LD XL,#FF LD DE,0 LD A,0 ;counter: 9 or 10 DIV_CNT EQU $-1 DIV_LOOP EX AF,AF' LD A,D SUB E LD D,A SBC HL,BC JR NC,DIV_1 LD A,D ADD A,E LD D,A ADC HL,BC DIV_1 LD A,XL ADC A,A LD XL,A LD A,XH ADC A,A LD XH,A SRL B RR C RR E EX AF,AF' DEC A JR NZ,DIV_LOOP ;Write down the result, first ;inverting it: EXX LD A,XL CPL LD(DE),A INC DE LD A,XH CPL LD(DE),A INC DE DJNZ PIX_LOOP POP AF ;attributes RET ════════════════════════ ════════════════════════ Best regards, Ivan Roshchin.

From Ivan Roshin To All 2 October 2002

Hello, All! ═══════════════════ 23.C ══════════════════ ;--------------------------------------- ;Procedure DEF_MM ; ;Input: HL points to the brightness table, ; MIN_PIX - minimum. brightness ; MAX_PIX - max. brightness. ; ;Output: XH - min brightness number, ; XL - max brightness number, ; DE - min. brightness, ; BC - max. brightness, ; HL - the difference between them. ; ;(Checking that the values of D and E should ;be <= maximum value in ;table, must be executed before ;challenge!) DEF_MM LD IX,#08FF ;XL=8, XH=-1 - initial numbers ;colors with minimum and maximum ;brightness. PUSH HL LD DE,15 ADD HL,DE ;Now HL points to the latter, ;highest value in the table. ;Look through the table from end to end ;start until MIN_PIX is greater ;or equal to the next value. LD DE,(MIN_PIX) DEF_MM_1 DEC XH LD B,(HL) DEC HL LD C,(HL) DEC HL PUSH DE EX DE,HL AND A SBC HL,BC EX DE,HL POP DE JR C,DEF_MM_1 LD H,B LD L,C ;brightness min. EX (SP),HL ;Now XH is the min brightness number. ;Looking through the table from beginning to ;end, find the first number greater ;or equal to MAX_PIX. Since the values ​​in;the table increases, it will also ;the smallest such number. LD BC,(MAX_PIX) DEF_MM_2 INC XL LD E,(HL) INC HL LD D,(HL) INC HL EX DE,HL AND A SBC HL,BC EX DE,HL JR C,DEF_MM_2 ;Calculate the difference: EX DE,HL ADD HL,BC ;brightness max. POP DE ;brightness min. PUSH HL AND A SBC HL,DE POP B.C. RET ;--------------------------------------- ;SET_TP_1, SET_TP_2 - output procedures ;points with a given texture correspond- ;specifically on the first and second screen. ; ;Input: BC - texture number (0-256), ; D - X, E - Y. ; ;Output: DE, HL - no changes. SET_TP_1 PUSH HL LD HL,SET_P_1 JR SET_TP SET_TP_2 PUSH HL LD HL,SET_P_2 SET_TP LD (SET_YES+1),HL DEC B JR Z,SET_YES ;if 256 LD B,16 CALL TEXTURE AND A JR Z,SET_NO SET_YES CALL SET_P_1 ;or SET_P_2 SET_NO POP HL RET ;--------------------------------------- ;SET_P_1 and SET_P_2 are procedures that set ;point to the first and second respectively ;screen. SET_P_1 PUSH HL CALL BYTE JR SET_P SET_P_2 PUSH HL LD A,#17 CALL SETPORTCALL BYTE SET 7,H SET_P OR (HL) LD(HL),A POP HL RET ════════════════════════ ════════════════════════ Best regards, Ivan Roshchin.

From Ivan Roshin To All 2 October 2002

Hello, All! ═══════════════════ 24 .C ══════════════════ ;--------------------------------------- ;The TEXTURE procedure determines by ;given texture and pixel coordinates ;on the screen, this pixel is turned on or ;off. ; ;Input: B - texture side length ; (number of the form 2^n), ; C - texture number, ; D,E - pixel coordinates: x,y. ; ;Output: A - pixel state: ; 0 - disabled, 1 - enabled. ; ;DE does not change. TEXTURE ;If the texture side length is 1, ;then the state of the pixel is equal to the number ;textures: SRL B ;Divide the length by 2. LD A,C ;Texture number. RET Z ;Exit if length ;was equal to 1. ; We formulate the conditions of a new, more ;simple task, for half the size ;texture being a quarter ;original. The answer to the new problem will be ;the answer to the original problem. ; The side length of the new texture is narrower ;computed and found in B. Remaining ;define the number of the new texture. He ;equal to the integer part of the division of the number ;original texture by 4, perhaps ;increased by 1 (this depends on ;the remainder obtained by dividing and from ;of which quarter it ends up in ;pixel). ;Include in register H the bit with the number ;the quarter in which the pixel appears. ;Numbering of quarters: 0 1 ; 2 3. LD HL,#0101 LD A,B AND DJR Z,TX_1 INC H ;H:=2 TX_1 LD A,B AND E JR Z,TX_2 SLA H SLA H ;Include bits with numbers in the L register ;those quarters where the texture number is 1 ;more. TX_2 LD A,C SRL C SRL C AND 3 JR Z,TEXTURE ;no such DEC A JR Z,PLUS_1 ;0 quarter SET 3,L DEC A JR Z,PLUS_1 ;0.3 quarters SET 1,L ;0,1,3 quarters ;Now we check: in the quarter where ;turned out to be a pixel, the texture number should ;to be 1 more? If yes, we increase ;him: PLUS_1 LD A,H AND L JR Z,TEXTURE INC C JR TEXTURE ;--------------------------------------- BYTE LD A,E AND A RRA SCF RRA AND A RRA XOR E AND #F8 XOR E LD H,A LD A,D RLCA RLCA RLCA XOR E AND #C7 XOR E RLCA RLCA LD L,A LD A,D AND 7 LD B,A INC B LD A,1 LOOP RRCA DJNZ LOOP RET ════════════════════════ ════════════════════════Best regards, Ivan Roshchin.

From Ivan Roshin To All 2 October 2002

Hello, All! ═══════════════════ 24 .C ══════════════════ ;--------------------------------------- ;The TEXTURE procedure determines by ;given texture and pixel coordinates ;on the screen, this pixel is turned on or ;off. ; ;Input: B - texture side length ; (number of the form 2^n), ; C - texture number, ; D,E - pixel coordinates: x,y. ; ;Output: A - pixel state: ; 0 - disabled, 1 - enabled. ; ;DE does not change. TEXTURE ;If the texture side length is 1, ;then the state of the pixel is equal to the number ;textures: SRL B ;Divide the length by 2. LD A,C ;Texture number. RET Z ;Exit if length ;was equal to 1. ; We formulate the conditions of a new, more ;simple task, for half the size ;texture being a quarter ;original. The answer to the new problem will be ;the answer to the original problem. ; The side length of the new texture is narrower ;computed and found in B. Remaining ;define the number of the new texture. He ;equal to the integer part of the division of the number ;original texture by 4, perhaps ;increased by 1 (this depends on ;the remainder obtained by dividing and from ;of which quarter it ends up in ;pixel). ;Include in register H the bit with the number ;the quarter in which the pixel appears. ;Numbering of quarters: 0 1 ; 2 3. LD HL,#0101 LD A,B AND DJR Z,TX_1 INC H ;H:=2 TX_1 LD A,B AND E JR Z,TX_2 SLA H SLA H ;Include bits with numbers in the L register ;those quarters where the texture number is 1 ;more. TX_2 LD A,C SRL C SRL C AND 3 JR Z,TEXTURE ;no such DEC A JR Z,PLUS_1 ;0 quarter SET 3,L DEC A JR Z,PLUS_1 ;0.3 quarters SET 1,L ;0,1,3 quarters ;Now we check: in the quarter where ;turned out to be a pixel, the texture number should ;to be 1 more? If yes, we increase ;him: PLUS_1 LD A,H AND L JR Z,TEXTURE INC C JR TEXTURE ;--------------------------------------- BYTE LD A,E AND A RRA SCF RRA AND A RRA XOR E AND #F8 XOR E LD H,A LD A,D RLCA RLCA RLCA XOR E AND #C7 XOR E RLCA RLCA LD L,A LD A,D AND 7 LD B,A INC B LD A,1 LOOP RRCA DJNZ LOOP RET ════════════════════════ ════════════════════════Best regards, Ivan Roshchin.

From Ivan Roshin To All 2 October 2002

Hello, All! ═══════════════════ 25 .C ══════════════════ ;--------------------------------------- ;The GET_A_ATR procedure determines the address in ;attribute areas. ; ;Input: DE - coordinates in pixels. ;Output: HL - address in the attribute area, ; the remaining registers are not changed. GET_A_ATR PUSH AF PUSH DE LD H,0 LD A,E AND %11111000 LD L,A ADD HL,HL ADD HL,HL LD A,D RRA RRA RRA AND %00011111 LD E,A LD D,#58 ADD HL,DE POP DE POP AF RET ;--------------------------------------- ;Procedure GET_1R - read value ;one pixel of the original image. ; ;Input: D - X, E - Y. ;Output: A - value, ; BC,DE,HL - no changes. GET_1R PUSH BC PUSH DE PUSH HL LD A,D ;switch places LD D,E LD E,A LD A,D RLCA RLCA AND 3 LD HL,N_BANK LD B,0 LD C,A ADD HL,BC LD A,(HL) ;installed CALL SETPORT ;necessary ;memory bank SET 7,D SET 6,D ;DE points to the address where it is stored ;pixel value.LD A,(DE) POP HL POP DE POP B.C. RET ;--------------------------------------- ;Procedure A_FLICKER - installation ;flickering pixels in antiphase. A_FLICKER LD A,#17 CALL SETPORT LD HL,#4000 ;1 image LD DE,#C000 ;2 image LD C,L FL_MAIN LD B,#80 ;mask LD A,(DE) XOR (HL) ;Now the bits in A are set, corresponding ;existing pixels that differ by ;first and second screen, i.e. flickering. FL_PIX RLA JR NC,FL_NEXT EX AF,AF' LD A,B ;The least significant bit of register C indicates ;which screen to turn on the pixel, and on ;how to turn it off. Team INC C him ;the value is reversed ;when processing each flickering ;pixels. INC C BIT 0.C JR NZ,FL_1 ;On the first screen we turn on the pixel, on ;second - turn off: OR(HL) LD(HL),A EX DE,HL LD A,B CPL AND (HL) JR FL_2 ;On the first screen we turn off the pixel, on ;second - turn on: FL_1 CPL AND (HL) LD(HL),A EX DE,HL LD A,B OR(HL) FL_2 LD (HL),A EX DE,HL EX AF,AF' FL_NEXT SRL B JR NZ,FL_PIXINC HL INC DE LD A,H CP #58 JR NZ,FL_MAIN RET ════════════════════════ ════════════════════════ Best regards, Ivan Roshchin.

From Ivan Roshin To All 2 October 2002

Hello, All! ═══════════════════ 25 .C ══════════════════ ;--------------------------------------- ;The GET_A_ATR procedure determines the address in ;attribute areas. ; ;Input: DE - coordinates in pixels. ;Output: HL - address in the attribute area, ; the remaining registers are not changed. GET_A_ATR PUSH AF PUSH DE LD H,0 LD A,E AND %11111000 LD L,A ADD HL,HL ADD HL,HL LD A,D RRA RRA RRA AND %00011111 LD E,A LD D,#58 ADD HL,DE POP DE POP AF RET ;--------------------------------------- ;Procedure GET_1R - read value ;one pixel of the original image. ; ;Input: D - X, E - Y. ;Output: A - value, ; BC,DE,HL - no changes. GET_1R PUSH BC PUSH DE PUSH HL LD A,D ;switch places LD D,E LD E,A LD A,D RLCA RLCA AND 3 LD HL,N_BANK LD B,0 LD C,A ADD HL,BC LD A,(HL) ;installed CALL SETPORT ;necessary ;memory bank SET 7,D SET 6,D ;DE points to the address where it is stored ;pixel value.LD A,(DE) POP HL POP DE POP B.C. RET ;--------------------------------------- ;Procedure A_FLICKER - installation ;flickering pixels in antiphase. A_FLICKER LD A,#17 CALL SETPORT LD HL,#4000 ;1 image LD DE,#C000 ;2 image LD C,L FL_MAIN LD B,#80 ;mask LD A,(DE) XOR (HL) ;Now the bits in A are set, corresponding ;existing pixels that differ by ;first and second screen, i.e. flickering. FL_PIX RLA JR NC,FL_NEXT EX AF,AF' LD A,B ;The least significant bit of register C indicates ;which screen to turn on the pixel, and on ;how to turn it off. Team INC C him ;the value is reversed ;when processing each flickering ;pixels. INC C BIT 0.C JR NZ,FL_1 ;On the first screen we turn on the pixel, on ;second - turn off: OR(HL) LD(HL),A EX DE,HL LD A,B CPL AND (HL) JR FL_2 ;On the first screen turn off the pixel, on ;second - turn on: FL_1 CPL AND (HL) LD(HL),A EX DE,HL LD A,B OR(HL) FL_2 LD (HL),A EX DE,HL EX AF,AF' FL_NEXT SRL B JR NZ,FL_PIXINC HL INC DE LD A,H CP #58 JR NZ,FL_MAIN RET ════════════════════════ ════════════════════════ Best regards, Ivan Roshchin.

From Ivan Roshin To All 2 October 2002

Hello, All! ═══════════════════ 26.C ══════════════════ ;--------------------------------------- SETPORT PUSH BC LD BC,#7FFD OUT(C),A POP B.C. RET IF GAMMA_CORR ;--------------------------------------- ;512-byte gamma correction table ;(for gamma=1.5), location address ;divisible by 256. The table first follows ;high bytes of all 256 values, and ;then the younger ones. DS 256-$256 ;leveling GAMMA_T db #00,#00,#00,#00,#00,#00,#00,#01 db #01,#01,#01,#02,#02,#02,#03,#03 db #04,#04,#04,#05,#05,#06,#06,#06 db #07,#07,#08,#08,#09,#09,#0A,#0A db #0B,#0B,#0C,#0C,#0D,#0E,#0E,#0F db #0F,#10,#11,#11,#12,#12,#13,#14 db #14,#15,#16,#16,#17,#18,#18,#19 db #1A,#1A,#1B,#1C,#1D,#1D,#1E,#1F db #20,#20,#21,#22,#23,#23,#24,#25 db #26,#27,#27,#28,#29,#2A,#2B,#2B db #2C,#2D,#2E,#2F,#30,#31,#31,#32 db #33,#34,#35,#36,#37,#38,#39,#39 db #3A,#3B,#3C,#3D,#3E,#3F,#40,#41 db #42,#43,#44,#45,#46,#47,#48,#49 db #4A,#4B,#4C,#4D,#4E,#4F,#50,#51 db #52,#53,#54,#55,#56,#57,#58,#59 db #5A,#5B,#5C,#5D,#5E,#60,#61,#62 db #63,#64,#65,#66,#67,#68,#69,#6B db #6C,#6D,#6E,#6F,#70,#71,#73,#74 db #75,#76,#77,#78,#7A,#7B,#7C,#7D db #7E,#7F,#81,#82,#83,#84,#85,#87 db #88,#89,#8A,#8C,#8D,#8E,#8F,#90 db #92,#93,#94,#95,#97,#98,#99,#9B db #9C,#9D,#9E,#A0,#A1,#A2,#A4,#A5 db #A6,#A7,#A9,#AA,#AB,#AD,#AE,#AF db #B1,#B2,#B3,#B5,#B6,#B7,#B9,#BA db #BB,#BD,#BE,#BF,#C1,#C2,#C4,#C5 db #C6,#C8,#C9,#CA,#CC,#CD,#CF,#D0 db #D1,#D3,#D4,#D6,#D7,#D9,#DA,#DB db #DD,#DE,#E0,#E1,#E3,#E4,#E5,#E7 db #E8,#EA,#EB,#ED,#EE,#F0,#F1,#F3 db #F4,#F6,#F7,#F9,#FA,#FC,#FD,#FF db #00,#10,#2D,#53,#80,#B3,#EC,#29 db #6B,#B1,#FB,#49,#9A,#EF,#48,#A3 db #02,#64,#C8,#30,#9A,#07,#76,#E8 db #5D,#D4,#4D,#C9,#47,#C8,#4A,#CF db #56,#DF,#6A,#F7,#87,#18,#AB,#41 db #D8,#71,#0C,#A8,#47,#E7,#8A,#2E db #D3,#7B,#24,#CF,#7B,#2A,#DA,#8B db #3E,#F3,#A9,#61,#1B,#D6,#92,#50 db #10,#D1,#94,#58,#1D,#E4,#AD,#77 db #42,#0F,#DD,#AD,#7E,#50,#24,#F9 db #CF,#A7,#80,#5A,#36,#13,#F1,#D1 db #B2,#94,#78,#5D,#43,#2A,#12,#FC db #E7,#D3,#C1,#AF,#9F,#90,#83,#76 db #6B,#61,#58,#50,#49,#44,#3F,#3C db #3A,#39,#39,#3A,#3D,#40,#45,#4B db #52,#5A,#63,#6D,#78,#84,#92,#A0 db #B0,#C0,#D2,#E5,#F9,#0D,#23,#3A db #52,#6B,#85,#A0,#BC,#D9,#F7,#16 db #36,#57,#79,#9C,#C0,#E5,#0B,#32 db #5A,#83,#AD,#D8,#04,#31,#5F,#8D db #BD,#EE,#1F,#52,#85,#BA,#EF,#25 db #5D,#95,#CE,#08,#43,#7F,#BB,#F9 db #38,#77,#B7,#F9,#3B,#7E,#C2,#07 db #4D,#93,#DB,#23,#6C,#B7,#02,#4D db #9A,#E8,#36,#86,#D6,#27,#79,#CC db #1F,#74,#C9,#20,#77,#CE,#27,#81 db #DB,#36,#92,#EF,#4D,#AC,#0B,#6B db #CC,#2E,#91,#F4,#58,#BD,#23,#8A db #F1,#5A,#C3,#2D,#97,#03,#6F,#DC db #4A,#B9,#28,#99,#0A,#7B,#EE,#61 db #D6,#4A,#C0,#37,#AE,#26,#9F,#18 db #93,#0E,#89,#06,#83,#02,#80,#00 ENDIF ════════════════════════ ════════════════════════ Best regards, Ivan Roshchin.

From Ivan Roshin To All 2 October 2002

Hello, All! ═══════════════════ 27.C ══════════════════ ;--------------------------------------- ;Procedure WAIT - delay from 188 to ;65535 cycles. Should be located with ;addresses divisible by 256. ; ;Input: HL - delay time in clock cycles ;(this already includes the execution time ;HL loading commands and procedure call). DS 256-$256 ;leveling TAB_ADR DB ADR_0256 DB ADR_1256 DB ADR_2256 DB ADR_3256 DB ADR_4256 DB ADR_5256 DB ADR_6256 DB ADR_7256 DB ADR_8256 DB ADR_9256 DB ADR_10256 DB ADR_11256 DB ADR_12256 DB ADR_13256 DB ADR_14256 DB ADR_15256 DB ADR_16256 DB ADR_17256 DB ADR_18256 DB ADR_19256 DB ADR_20256 DB ADR_21256 DB ADR_22256 DB ADR_23256 DB ADR_24256 DB ADR_25256 DB ADR_26256 DB ADR_27256 DB ADR_28256 DB ADR_29256 DB ADR_30256 DB ADR_31256 ADR_28 NOP ADR_24 NOP ADR_20 NOP ADR_16 NOP ADR_12 NOP ADR_8 NOP ADR_4 NOP ADR_0 NOP ;4 clock cycles RET ADR_29 NOP ADR_25 NOPADR_21 NOP ADR_17 NOP ADR_13 NOP ADR_9 NOP ADR_5 NOP ADR_1 RET NZ ;5 cycles RET ADR_30 NOP ADR_26 NOP ADR_22 NOP ADR_18 NOP ADR_14 NOP ADR_10 NOP ADR_6 NOP ADR_2 INC HL ;6 clock cycles RET ADR_31 NOP ADR_27 NOP ADR_23 NOP ADR_19 NOP ADR_15 NOP ADR_11 NOP ADR_7 NOP ADR_3 LD A,(HL) ;7 clock cycles RET WAIT LD DE,-156 ADD HL,DE LD A,L AND 31 LD E,A ;To divide HL by 32, it is enough ;shift HL 5 bits to the right, but ;there is a shorter and faster way: ;shift HL 3 places to the left, placing ;move the most significant bits of the result into ;battery, and then produce ;permutation: A -> H -> L. XOR A ADD HL,HL R.L.A. ADD HL,HL R.L.A. ADD HL,HL R.L.A. LD L,H LD H,A ;Loop with execution time 32 cycles: WAIT_1 DEC HL LD A,H OR L NOP ;for NOP ;delays JP NZ,WAIT_1 EX DE,HL LD H,TAB_ADR/256 LD L,(HL) JP(HL) ;--------------------------------------- ;Switching on and off procedures ;second interrupt mode: ON_IM2 LD HL,INT_TABLD (HL),INT_ADR/256 LD DE,INT_TAB+1 LD BC,#100 LDIR LD A,INT_TAB/256 LD I,A LD HL,#C9FB ;EI:RET LD (INT_ADR),HL IM 2 RET OFF_IM2 IM 1 LD A,#3F LD I,A RET ════════════════════════════════════════════════ С уважением, Иван Рощин.

From Ivan Roshin To All 2 October 2002

Hello, All! ═══════════════════ 28.C ══════════════════ Comments ─────────── Not all subroutines from the general part are used in each withdrawal procedure. To reduce the volume of unused subroutines can be deleted. Information about which subroutines are not used in each of the six output procedures, are given in the table: ┌──────────────────┬──────────── ───────────────────────────────┐ │ Number │ Subroutines, │ │ inference procedures │ not used in this procedure │ ├──────────────────┼──────────── ───────────────────────────────┤ │ 1 │ CLS_2, SET_TP_2, SET_P_2, ON_IM2, OFF_IM2,│ │ │ WAIT, PUT_DATA, A_FLICKER │ ├──────────────────┼──────────── ───────────────────────────────┤ │ 2 │ PUT_DATA, A_FLICKER │ ├──────────────────┼──────────── ───────────────────────────────┤ │ 3 │ GET_A_ATR, CLS_2, SET_TP_2, SET_P_2, │ │ │ PUT_DATA, A_FLICKER │ ├──────────────────┼──────────── ───────────────────────────────┤ │ 4 │ ON_IM2, OFF_IM2, WAIT │ ├──────────────────┼──────────── ───────────────────────────────┤ │ 5 │ GET_A_ATR │├──────────────────┼──────────── ───────────────────────────────┤ │ 6 │ GET_A_ATR │ └──────────────────┴──────────── ───────────────────────────────┘ Table 1 * * * How to display an image with magnification? If required 2x magnification (size of displayed image area then it will be 128*96), then to the beginning of the GET_1R procedure, after PUSH commands, add this fragment: LD A,D SRL A ADD A, X coordinate of the upper left corner of the area LD D,A LD A,E SRL A ADD A,Y coordinate of the upper left corner of the area LD E,A If you need an increase of 4, 8... times (the size of the output the area will then be 64*48, 32*24...), then we set not one, but two, three... SRL A teams. By the way, to double the above fragment can be optimized: first add double the coordinate, and then divide by two with RRA instead of SRL A - this will be shorter and faster. * * * How to generate a gamma correction table (GAMMA_T) for the desired gamma value? Below is the corresponding program in BASIC. This program generates a table in the same format as where it is stored in the common part of the output procedures: values informat 8.8, in the first 256 bytes - integer parts, in the next 256 - fractional. The total length of the table is therefore 512 bytes. When starting the program you need to specify the desired value scales. Simultaneously with the calculation of the table, a graph of pixel brightness depending on its value in image for a given gamma value. After graduation calculations, specify the name of the file where the table will be written, or just press "Enter" to restart the program. 10 CLEAR 32767 15 CLS 20 INPUT "Gamma: ";G 30 FOR i=0 TO 255 40 LET y=(i/255)^G 50 LET Word= INT (y*255*256+0.5) 60 LET HighByte=INT (Word/256) 70 LET LowByte= Word-HighByte*256 80 POKE 32768+i, HighByte 90 POKE 32768+256+i, LowByte 100 PLOT i*175/255,y*175 110 NEXT i 120 INPUT "File: ";a$ 130 IF a$="" THEN GO TO 15 140 RANDOMIZE USR 15619: REM :SAVE a$ CODE 32768,512 * * * When outputting an image to obtain pseudogradations of brightness 257 different 16*16 textures are used. Simple counting shows that storing them requires 257*16*16/8=8224 bytes memory, or more than 8 KB. I didn’t want to waste so much memory, and I used this technique: when you need to find out whether it is turned on or the pixel with these coordinates located incertain texture, the answer is obtained using a special algorithm based on texture properties. It appears It would be interesting to consider this algorithm in more detail. First, about the properties that must be satisfied textures used to obtain pseudo-gradations of brightness (in general case). Let l be the length of the texture side, and l is a number of the form 2^k (in this case l=16=2^4). Quantity textures N is equal to l^2+1 (in this case N=16^2+1=257). Firstly, in each subsequent texture by one included the pixel is larger than the previous one. If we number the textures from 0 to N-1, then the texture number will be equal to the number included in it pixels Secondly, any two adjacent textures differ in only one pixel. Taking into account the previous property, we obtain that each the next texture is obtained from the previous one by turning on one more pixel. Thirdly, the on and off pixels in each texture are distributed evenly. What does it mean? Let's take texture and divide it into four equal parts: ┌─────┬─────┐ │ | │ │ | │ ├-----+-----┤ │ | │ │ | │ └─────┴─────┘ Fig. 20 ════════════════════════ ════════════════════════Best regards, Ivan Roshchin.

From Ivan Roshin To All 2 October 2002

Hello, All! ═══════════════════ 28.C ══════════════════ Comments ─────────── Not all routines from the general part are used in every withdrawal procedure. To reduce the volume of unused subroutines can be deleted. Information about which subroutines are not used in each of the six output procedures, are given in the table: ┌──────────────────┬──────────── ───────────────────────────────┐ │ Number │ Subroutines, │ │ inference procedures │ not used in this procedure │ ├──────────────────┼──────────── ───────────────────────────────┤ │ 1 │ CLS_2, SET_TP_2, SET_P_2, ON_IM2, OFF_IM2,│ │ │ WAIT, PUT_DATA, A_FLICKER │ ├──────────────────┼──────────── ───────────────────────────────┤ │ 2 │ PUT_DATA, A_FLICKER │ ├──────────────────┼──────────── ───────────────────────────────┤ │ 3 │ GET_A_ATR, CLS_2, SET_TP_2, SET_P_2, │ │ │ PUT_DATA, A_FLICKER │ ├──────────────────┼──────────── ───────────────────────────────┤ │ 4 │ ON_IM2, OFF_IM2, WAIT │ ├──────────────────┼──────────── ───────────────────────────────┤ │ 5 │ GET_A_ATR │├──────────────────┼──────────── ───────────────────────────────┤ │ 6 │ GET_A_ATR │ └──────────────────┴──────────── ───────────────────────────────┘ Table 1 * * * How to display an image with magnification? If required 2x magnification (size of displayed image area then it will be 128*96), then to the beginning of the GET_1R procedure, after PUSH commands, add this fragment: LD A,D SRL A ADD A, X coordinate of the upper left corner of the area LD D,A LD A,E SRL A ADD A,Y coordinate of the upper left corner of the area LD E,A If you need an increase of 4, 8... times (the size of the output the area will then be 64*48, 32*24...), then we set not one, but two, three... SRL A teams. By the way, to double the above fragment can be optimized: first add double the coordinate, and then divide by two with RRA instead of SRL A - this will be shorter and faster. * * * How to generate a gamma correction table (GAMMA_T) for the desired gamma value? Below is the corresponding program in BASIC. This program generates a table in the same format as where it is stored in the common part of the output procedures: values informat 8.8, in the first 256 bytes - integer parts, in the next 256 - fractional. The total length of the table is therefore 512 bytes. When starting the program you need to specify the desired value scales. Simultaneously with the calculation of the table, a graph of pixel brightness depending on its value in image for a given gamma value. After graduation calculations, specify the name of the file where the table will be written, or just press "Enter" to restart the program. 10 CLEAR 32767 15 CLS 20 INPUT "Gamma: ";G 30 FOR i=0 TO 255 40 LET y=(i/255)^G 50 LET Word= INT (y*255*256+0.5) 60 LET HighByte=INT (Word/256) 70 LET LowByte= Word-HighByte*256 80 POKE 32768+i, HighByte 90 POKE 32768+256+i, LowByte 100 PLOT i*175/255,y*175 110 NEXT i 120 INPUT "File: ";a$ 130 IF a$="" THEN GO TO 15 140 RANDOMIZE USR 15619: REM :SAVE a$ CODE 32768,512 * * * When outputting an image to obtain pseudogradations of brightness 257 different 16*16 textures are used. Simple counting shows that storing them requires 257*16*16/8=8224 bytes memory, or more than 8 KB. I didn’t want to waste so much memory, and I used this technique: when you need to find out whether it is turned on or the pixel with these coordinates located incertain texture, the answer is obtained using a special algorithm based on texture properties. It appears It would be interesting to consider this algorithm in more detail. First, about the properties that must be satisfied textures used to obtain pseudo-gradations of brightness (in general case). Let l be the length of the texture side, and l is a number of the form 2^k (in this case l=16=2^4). Quantity textures N is equal to l^2+1 (in this case N=16^2+1=257). Firstly, in each subsequent texture by one included the pixel is larger than the previous one. If we number the textures from 0 to N-1, then the texture number will be equal to the number included in it pixels Secondly, any two adjacent textures differ in only one pixel. Taking into account the previous property, we obtain that each the next texture is obtained from the previous one by turning on one more pixel. Thirdly, the on and off pixels in each texture are distributed evenly. What does it mean? Let's take texture and divide it into four equal parts: ┌─────┬─────┐ │ | │ │ | │ ├-----+-----┤ │ | │ │ | │ └─────┴─────┘ Fig. 20 ════════════════════════ ════════════════════════Best regards, Ivan Roshchin.

From Ivan Roshin To All 2 October 2002

Hello, All! ═══════════════════ 29.C ══════════════════ Moreover, in any two parts the number of included (as well as turned off) pixels will differ by no more than one. If each part is again divided by four, this condition will be be carried out for the resulting smaller parts, and so on. Obviously, if the texture number (let's call it n) is a multiple of 4 (and therefore the number of included pixels is a multiple of 4), then the only option for their location is in the quarters of the texture, satisfying the above condition - n/4 pixels per every quarter. Let the texture number not be a multiple of 4, m is the remainder of the division. Then, for the uniformity condition to be satisfied, in m quarters there should be [n/4]+1 pixels, and in the remaining 4-m quarters - by [n/4] pixels. Let us assume for definiteness that the pixels are located in three possible cases (when m = 1, 2 or 3) as follows (taking into account the second property - neighboring textures differ by only one pixel!): ┌───────┬───────┐ ┌───────┬───────┐ ┌───────┬───────┐ │ | │ │ | │ │ | │ │[n/4]+1| [n/4] │ │[n/4]+1| [n/4] │ │[n/4]+1|[n/4+1]│ │ | │ │ | │ │ | │ ├-------+-------┤ ├-------+-------┤ ├-------+-------┤ │ | │ │ | │ │ | ││ [n/4] | [n/4] │ │ [n/4] |[n/4+1]│ │ [n/4] |[n/4+1]│ │ | │ │ | │ │ | │ └───────┴───────┘ └───────┴───────┘ └───────┴───────┘ a) m=1 b) m=2 c) m=3 Fig. 21 The above information is sufficient to build all N textures, and in order to determine the pixel with these coordinates located is turned on or off in a certain texture. The algorithm is very simple. Let l be the side length known textures, n - texture number, x and y - pixel coordinates on screen. You need to get a - pixel state: 0 - off, 1 - included. 1. If the texture size is 1*1, then the pixel state is texture number (i.e. if l=1, then a=n). 2. We formulate the conditions of a new, simpler problem differently, for half the texture being a quarter original (i.e. we get new l and n). New problem answer will be the answer to the original problem. 2.1. If n is a multiple of 4, then l:=l/2, n:=n/4, and solve the problem with these conditions. 2.2. Otherwise, we determine in which quarter of the texture turns out to be a pixel. If l and x = 0, then the pixel in the left half, otherwise in the right. If l and y = 0, then the pixel is in the upper half, otherwise in the lower half.2.3. Using m - the remainder of dividing n by 4 - we determine which quarters will include [n/4] pixels, and in which - [n/4]+1 (see Fig. 21). 2.4. If in that quarter of the texture where it turns out pixel, [n/4] pixels included, then l:=l/2, n:=[n/4], and solve the problem with these conditions. 2.5. Otherwise l:=l/2, n:=[n/4]+1, and solve the problem with these conditions. In the program, this is done by the TEXTURE procedure, the length of which only 46 bytes. Compare that to the original 8224 bytes! ════════════════════════ ════════════════════════ Best regards, Ivan Roshchin.

From Ivan Roshin To All 2 October 2002

Hello, All! ═══════════════════ 29.C ══════════════════ Moreover, in any two parts the number of included (as well as turned off) pixels will differ by no more than one. If each part is again divided by four, this condition will be be carried out for the resulting smaller parts, and so on. Obviously, if the texture number (let's call it n) is a multiple of 4 (and therefore the number of included pixels is a multiple of 4), then the only option for their location is in the quarters of the texture, satisfying the above condition - n/4 pixels per every quarter. Let the texture number not be a multiple of 4, m is the remainder of the division. Then, for the uniformity condition to be satisfied, in m quarters there should be [n/4]+1 pixels, and in the remaining 4-m quarters - by [n/4] pixels. Let us assume for definiteness that the pixels are located in three possible cases (when m = 1, 2 or 3) as follows (taking into account the second property - neighboring textures differ by only one pixel!): ┌───────┬───────┐ ┌───────┬───────┐ ┌───────┬───────┐ │ | │ │ | │ │ | │ │[n/4]+1| [n/4] │ │[n/4]+1| [n/4] │ │[n/4]+1|[n/4+1]│ │ | │ │ | │ │ | │ ├-------+-------┤ ├-------+-------┤ ├-------+-------┤ │ | │ │ | │ │ | ││ [n/4] | [n/4] │ │ [n/4] |[n/4+1]│ │ [n/4] |[n/4+1]│ │ | │ │ | │ │ | │ └───────┴───────┘ └───────┴───────┘ └───────┴───────┘ a) m=1 b) m=2 c) m=3 Fig. 21 The above information is sufficient to build all N textures, and in order to determine the pixel with these coordinates located is turned on or off in a certain texture. The algorithm is very simple. Let l be the side length known textures, n - texture number, x and y - pixel coordinates on screen. You need to get a - pixel state: 0 - off, 1 - included. 1. If the texture size is 1*1, then the pixel state is texture number (i.e. if l=1, then a=n). 2. We formulate the conditions of a new, simpler problem differently, for half the texture being a quarter original (i.e. we get new l and n). New problem answer will be the answer to the original problem. 2.1. If n is a multiple of 4, then l:=l/2, n:=n/4, and solve the problem with these conditions. 2.2. Otherwise, we determine in which quarter of the texture turns out to be a pixel. If l and x = 0, then the pixel in the left half, otherwise in the right. If l and y = 0, then the pixel is in the upper half, otherwise in the lower half.2.3. Using m - the remainder of dividing n by 4 - we determine which quarters will include [n/4] pixels, and in which - [n/4]+1 (see Fig. 21). 2.4. If in that quarter of the texture where it turns out pixel, [n/4] pixels included, then l:=l/2, n:=[n/4], and solve the problem with these conditions. 2.5. Otherwise l:=l/2, n:=[n/4]+1, and solve the problem with these conditions. In the program, this is done by the TEXTURE procedure, the length of which only 46 bytes. Compare that to the original 8224 bytes! ════════════════════════ ════════════════════════ Best regards, Ivan Roshchin.

From Ivan Roshin To All 2 October 2002

Hello, All! ═══════════════════ 30 .C ══════════════════ Appendix 4 ──────────── Here are the texts of procedures for working with pcx files, containing black and white images with 256 gradations of brightness. I’ll briefly tell you about the format of such files - this is necessary for understanding the logic of the procedures. ╔════════════════════════╤════════════╗ ║ File part │ Length ║ ╠════════════════════════╪════════════╣ ║ Heading │ 128 ║ ╟────────────────────────┼────────────╢ ║ Packed information │ variable ║ ║ about image pixels │ ║ ╟────────────────────────┼────────────╢ ║ Palette type │ 1 ║ ╟────────────────────────┼────────────╢ ║ Palette │ 768 ║ ╚════════════════════════╧════════════╝ Table 2 _File header_ contains size information images, number of colors, etc. In the reading procedure (READ_PCX) header is ignored because this data are assumed to be already known. In the write procedure (MAKE_PCX) The header is always written the same. _Image pixel information_ is stored in the packaged form. When packing a sequence of identical bytesis replaced by two bytes: counter and original. So that you can recognize the byte counter when unpacking, its most significant two bits are set to 1, and the length of the sequence (from 1 to 63) stored in the lower six bits. If the length of the sequence greater than 63, several counter-value pairs are recorded. If when packing, a separate byte is found, the most significant two bits which are equal to 1, so that when unpacking it is not confused with byte-counter, preceded by a byte-counter with the number repetitions equal to 1. _Palette type_ - #0A, if the palette byte values are in the range 0-63, and #0C if in the range 0-255. In procedure reading the palette type is ignored, and in the writing procedure - #0C is written. _Palette_ - it contains information about the components R, G, B each of the 256 colors of the image. In the reading procedure, the palette is ignored, and in the recording procedure it is written sequence of bytes (0,0,0, 1,1,1,..., 255,255,255). Based on the above, we can determine the maximum file length: 2 bytes per pixel - that's 256*192*2 = #18000, more #80 bytes - header, 1 byte - palette type and #300 bytes - the palette itself, total #18381 bytes. But in TR-DOS the file length is not may exceed #FF00 bytes. Therefore, in the MAKE_PCX procedure, if the file length is greater than #FF00, two file: the first with length #FF00, and the second with the remainder.So, the texts of the procedures. 1. READ_PCX - reading an image from a pcx file into three banks memory. Input: file name and extension specified in FILENAME, bank numbers memory - in N_BANK. Output: A=1 - OK, A=0 - file not found. ;Data structures: BUFER EQU #7000 ;256-byte buffer (address is a multiple of 256!) ;The procedure itself went: ORG #6000 READ_PCX LD HL,BUFER LD (GET_B_0),HL LD HL,N_BANK LD (PUT_B_1),HL LD HL,#C000 LD (PUT_B_2),HL ;Looking for file: LD HL,FILENAME LD C,#13 CALL #3D13 LD C,#0A CALL #3D13 LD A,C INC A RET Z ;no such file DEC A LD C,8; read CALL #3D13 ;descriptor ;Determine the track/sector address of the start ;file: LD HL,(#5CEB) LD (GET_B_1),HL ;Skipping the first 128 bytes of the file - ;this is the title. LD B,128 M1 CALL GET_B DJNZ M1 LD HL,#C000 ;number of pix. ;Main loop: M3 CALL GET_B ;read byte ;If this is a byte counter, then two of it ;most significant bits are set to 1, and ;lower 6 bits - quantity ;repetitions. LD B,1 LD C,A CPL AND %11000000 LD A,C JR NZ,M2════════════════════════ ════════════════════════ Best regards, Ivan Roshchin.

From Ivan Roshin To All 2 October 2002

Hello, All! ═══════════════════ 30 .C ══════════════════ Appendix 4 ──────────── Here are the texts of procedures for working with pcx files, containing black and white images with 256 gradations of brightness. I’ll briefly tell you about the format of such files - this is necessary for understanding the logic of the procedures. ╔════════════════════════╤════════════╗ ║ File part │ Length ║ ╠════════════════════════╪════════════╣ ║ Heading │ 128 ║ ╟────────────────────────┼────────────╢ ║ Packed information │ variable ║ ║ about image pixels │ ║ ╟────────────────────────┼────────────╢ ║ Palette type │ 1 ║ ╟────────────────────────┼────────────╢ ║ Palette │ 768 ║ ╚════════════════════════╧════════════╝ Table 2 _File header_ contains size information images, number of colors, etc. In the reading procedure (READ_PCX) header is ignored because this data are assumed to be already known. In the write procedure (MAKE_PCX) The header is always written the same. _Image pixel information_ is stored in the packaged form. When packing a sequence of identical bytesis replaced by two bytes: counter and original. So that you can recognize the byte counter when unpacking, its most significant two bits are set to 1, and the length of the sequence (from 1 to 63) stored in the lower six bits. If the length of the sequence greater than 63, several counter-value pairs are recorded. If when packing, a separate byte is found, the most significant two bits which are equal to 1, so that when unpacking it is not confused with byte-counter, preceded by a byte-counter with the number repetitions equal to 1. _Palette type_ - #0A, if the palette byte values are in the range 0-63, and #0C if in the range 0-255. In procedure reading the palette type is ignored, and in the writing procedure - #0C is written. _Palette_ - it contains information about the components R, G, B each of the 256 colors of the image. In the reading procedure, the palette is ignored, and in the recording procedure it is written sequence of bytes (0,0,0, 1,1,1,..., 255,255,255). Based on the above, we can determine the maximum file length: 2 bytes per pixel - that's 256*192*2 = #18000, more #80 bytes - header, 1 byte - palette type and #300 bytes - the palette itself, total #18381 bytes. But in TR-DOS the file length is not may exceed #FF00 bytes. Therefore, in the MAKE_PCX procedure, if the file length is greater than #FF00, two file: the first with length #FF00, and the second with the remainder.So, the texts of the procedures. 1. READ_PCX - reading an image from a pcx file into three banks memory. Input: file name and extension specified in FILENAME, bank numbers memory - in N_BANK. Output: A=1 - OK, A=0 - file not found. ;Data structures: BUFER EQU #7000 ;256-byte buffer (address is a multiple of 256!) ;The procedure itself went: ORG #6000 READ_PCX LD HL,BUFER LD (GET_B_0),HL LD HL,N_BANK LD (PUT_B_1),HL LD HL,#C000 LD (PUT_B_2),HL ;Looking for file: LD HL,FILENAME LD C,#13 CALL #3D13 LD C,#0A CALL #3D13 LD A,C INC A RET Z ;no such file DEC A LD C,8; read CALL #3D13 ;descriptor ;Determine the track/sector address of the start ;file: LD HL,(#5CEB) LD (GET_B_1),HL ;Skipping the first 128 bytes of the file - ;this is the title. LD B,128 M1 CALL GET_B DJNZ M1 LD HL,#C000 ;number of pix. ;Main loop: M3 CALL GET_B ;read byte ;If this is a byte counter, then two of it ;most significant bits are set to 1, and ;lower 6 bits - quantity ;repetitions. LD B,1 LD C,A CPL AND %11000000 LD A,C JR NZ,M2════════════════════════ ════════════════════════ Best regards, Ivan Roshchin.

From Ivan Roshin To All 2 October 2002

Hello, All! ═══════════════════ 31.C ══════════════════ ;Repeat the next byte specified ;number of times: LD A,%00111111 AND C LD B,A CALL GET_B M2 CALL PUT_B DEC HL DJNZ M2 LD A,H ;all #C000 pixels? OR L JR NZ,M3 INC A ;A:=1 RET ;File name: FILENAME DB "picture pcx" ;Numbers of memory banks used: N_BANK DB #10,#11,#13 ;--------------------------------------- ;Procedure GET_B - reading a byte from ;file. GET_B PUSH HL PUSH BC LD HL,0 ;address in buffer GET_B_0 EQU $-2 LD A,L AND A JR NZ,GET_B_3 ;You need to read the sector of the file: PUSH HL LD B,1 LD DE,0 GET_B_1 EQU $-2 PUSH DE LD HL,BUFER LD C,5 CALL #3D13 ;Increase the track/sector address: POP DE INC E BIT 4,E JR Z,GET_B_2 LD E,0 INC D GET_B_2 LD (GET_B_1),DE POP HL ;Read a byte from the buffer: GET_B_3 LD A,(HL) INC L LD (GET_B_0),HL POP B.C. POP HL RET ;---------------------------------------;Procedure PUT_B - placing information ;about the next pixel in memory. PUT_B PUSH AF PUSH HL PUSH AF PUSH BC LD HL,0 PUT_B_1 EQU $-2 LD A,(HL) ;N bank LD BC,#7FFD OUT(C),A POP B.C. POP AF LD HL,0 ;address PUT_B_2 EQU $-2 LD(HL),A INC HL ;increased addresses LD A,H OR L JR NZ,PUT_B_3 LD HL,(PUT_B_1) ;go to INC HL ;following LD (PUT_B_1),HL ;jar LD HL,#C000 PUT_B_3 LD (PUT_B_2),HL POP HL POP AF RET ════════════════════════ ════════════════════════ Best regards, Ivan Roshchin.

From Ivan Roshin To All 2 October 2002

Hello, All! ═══════════════════ 31.C ══════════════════ ;Repeat the next byte specified ;number of times: LD A,%00111111 AND C LD B,A CALL GET_B M2 CALL PUT_B DEC HL DJNZ M2 LD A,H ;all #C000 pixels? OR L JR NZ,M3 INC A ;A:=1 RET ;File name: FILENAME DB "picture pcx" ;Numbers of memory banks used: N_BANK DB #10,#11,#13 ;--------------------------------------- ;Procedure GET_B - reading a byte from ;file. GET_B PUSH HL PUSH BC LD HL,0 ;address in buffer GET_B_0 EQU $-2 LD A,L AND A JR NZ,GET_B_3 ;You need to read the file sector: PUSH HL LD B,1 LD DE,0 GET_B_1 EQU $-2 PUSH DE LD HL,BUFER LD C,5 CALL #3D13 ;Increase the track/sector address: POP DE INC E BIT 4,E JR Z,GET_B_2 LD E,0 INC D GET_B_2 LD (GET_B_1),DE POP HL ;Read a byte from the buffer: GET_B_3 LD A,(HL) INC L LD (GET_B_0),HL POP B.C. POP HL RET ;---------------------------------------;Procedure PUT_B - placing information ;about the next pixel in memory. PUT_B PUSH AF PUSH HL PUSH AF PUSH BC LD HL,0 PUT_B_1 EQU $-2 LD A,(HL) ;N bank LD BC,#7FFD OUT(C),A POP B.C. POP AF LD HL,0 ;address PUT_B_2 EQU $-2 LD(HL),A INC HL ;increased addresses LD A,H OR L JR NZ,PUT_B_3 LD HL,(PUT_B_1) ;go to INC HL ;following LD (PUT_B_1),HL ;jar LD HL,#C000 PUT_B_3 LD (PUT_B_2),HL POP HL POP AF RET ════════════════════════ ════════════════════════ Best regards, Ivan Roshchin.

From Ivan Roshin To All 2 October 2002

Hello, All! ═══════════════════ 32.C ══════════════════ 2. MAKE_PCX - recording images from three memory banks to pcx file. Input: file name and extension specified in NAME_EXT, bank numbers memory - in N_BANK. Output: A=1 - OK, A=0 - writing the file failed (there is no space on disk or disk directory). ;Data structures: FILE_BUFER EQU #7000 ;write buffer CAT_BUFER EQU #7100 ;disk directory ;The procedure itself went: ORG #6000 MAKE_PCX CALL INIT_GET ;First we convert "idle" so that ;find out the size of the resulting file. Into this ;time colors are displayed on the border ;stripes - to show that the computer ;not stuck. LD D,0 ;DHL - length LD HL,#381 LD BC,1 MAKE_PCX_1 CALL GET_BYTE JR C,MAKE_PCX_2 AND 7 ;Change OUT (254),A ;BORDER ADD HL,BC LD A,D ADC A,0 LD D,A JR MAKE_PCX_1 MAKE_PCX_2 LD (LEN_FILE),HL LD A,D LD(LEN_FILE+2),A ;The length in bytes has been determined, now ;get the length in sectors: LD BC,255 ADD HL,BC LD A,D ADC A,0 LD L,H LD H,A ;HL - length. PUSH HL ;Remember her... ;Reading the catalogue: LD HL,CAT_BUFER LD DE,0LD B,9 LD C,5 CALL #3D13 ;Checking free space in the area ;files: LD HL,(CAT_BUFER+#8E5) POP DE ;file length XOR A ;A:=0, flag C is cleared SBC HL,DE RET C ;No disk space! ;Correction of free space: LD (CAT_BUFER+#8E5),HL ;Now we determine how much it will be ;files: one or two? LD A,1 ;number of files EX DE,HL LD DE,255 SBC HL,DE ;flag C is reset! JR C,MAKE_PCX_7 ;1 file INC A ;2 files MAKE_PCX_7 LD (FILES),A ;Checking free space in the area ;directory: LD HL,CAT_BUFER+#8E4 LD B,(HL) ADD A,B LD (HL),A ;correction CP 128+1 LD A,0 RET NC ;No space! ;Determine the number of the first sector of the file: LD HL,(CAT_BUFER+#8E1) LD (DISK_ADR),HL ;Place information about the file in the directory ;(or about two files, if the length is greater ;#FF00): LD H,0 LD L,B ADD HL,HL ADD HL,HL ADD HL,HL ADD HL,HL ;*16 LD DE,CAT_BUFER ADD HL,DE EX DE,HL LD HL,NAME_EXT ;Title LD BC,11 LDIR LD A,(FILES) CP 2JR NZ,MAKE_PCX_A ════════════════════════ ════════════════════════ Best regards, Ivan Roshchin.

From Ivan Roshin To All 2 October 2002

Hello, All! ═══════════════════ 32.C ══════════════════ 2. MAKE_PCX - recording images from three memory banks to pcx file. Input: file name and extension specified in NAME_EXT, bank numbers memory - in N_BANK. Output: A=1 - OK, A=0 - writing the file failed (there is no space on disk or disk directory). ;Data structures: FILE_BUFER EQU #7000 ;write buffer CAT_BUFER EQU #7100 ;disk directory ;The procedure itself went: ORG #6000 MAKE_PCX CALL INIT_GET ;First we convert "idle" so that ;find out the size of the resulting file. Into this ;time colors are displayed on the border ;stripes - to show that the computer ;not stuck. LD D,0 ;DHL - length LD HL,#381 LD BC,1 MAKE_PCX_1 CALL GET_BYTE JR C,MAKE_PCX_2 AND 7 ;Change OUT (254),A ;BORDER ADD HL,BC LD A,D ADC A,0 LD D,A JR MAKE_PCX_1 MAKE_PCX_2 LD (LEN_FILE),HL LD A,D LD(LEN_FILE+2),A ;The length in bytes has been determined, now ;get the length in sectors: LD BC,255 ADD HL,BC LD A,D ADC A,0 LD L,H LD H,A ;HL - length. PUSH HL ;Remember her... ;Reading the catalogue: LD HL,CAT_BUFER LD DE,0LD B,9 LD C,5 CALL #3D13 ;Checking free space in the area ;files: LD HL,(CAT_BUFER+#8E5) POP DE ;file length XOR A ;A:=0, flag C is cleared SBC HL,DE RET C ;No disk space! ;Correction of free space: LD (CAT_BUFER+#8E5),HL ;Now we determine how much it will be ;files: one or two? LD A,1 ;number of files EX DE,HL LD DE,255 SBC HL,DE ;flag C is reset! JR C,MAKE_PCX_7 ;1 file INC A ;2 files MAKE_PCX_7 LD (FILES),A ;Checking free space in the area ;directory: LD HL,CAT_BUFER+#8E4 LD B,(HL) ADD A,B LD (HL),A ;correction CP 128+1 LD A,0 RET NC ;No space! ;Determine the number of the first sector of the file: LD HL,(CAT_BUFER+#8E1) LD (DISK_ADR),HL ;Place information about the file in the directory ;(or about two files, if the length is greater ;#FF00): LD H,0 LD L,B ADD HL,HL ADD HL,HL ADD HL,HL ADD HL,HL ;*16 LD DE,CAT_BUFER ADD HL,DE EX DE,HL LD HL,NAME_EXT ;Title LD BC,11 LDIR LD A,(FILES) CP 2JR NZ,MAKE_PCX_A ════════════════════════ ════════════════════════ Best regards, Ivan Roshchin.

From Ivan Roshin To All 2 October 2002

Hello, All! ═══════════════════ 33.C ══════════════════ ;Two files are written. ;First file: EX DE,HL LD (HL),0 ;Length: INC HL LD (HL),#FF ;#FF00 bytes, INC HL LD (HL),#FF ;#FF sectors. INC HL LD A,#FF ;Address to CALL NEW_TS ;disk. ;Second file: EX DE,HL LD HL,NAME_EXT ;Title. LD BC,8 LDIR LD A,"0" ;First character LD (DE),A ;extensions - "0" INC DE INC HL LDI LDI EX DE,HL ;Length: LD A,(LEN_FILE) ;junior LD (HL),A ;byte... INC HL PUSH HL LD HL,(LEN_FILE+1) DEC H INC HL ;-#FF00 LD A,L ;and senior POP HL ;byte. LD(HL),A PUSH HL DEC HL LD L,(HL) LD H,A INC H DEC HL LD A,H ;Length in sectors. POP HL INC HL LD(HL),A INC HL CALL NEW_TS JR MAKE_PCX_9 ;One file is written: MAKE_PCX_A EX DE,HL LD DE,(LEN_FILE) LD (HL),E ;LengthINC HL ;in bytes. LD(HL),D INC HL INC D ;Length DEC DE ;in sectors. LD(HL),D INC HL LD A,D CALL NEW_TS ;Write the directory: MAKE_PCX_9 LD HL,CAT_BUFER LD DE,0 LD B,9 LD C,6 CALL #3D13 ;Write the contents of the file: CALL OPEN_FILE ;Header (128 bytes): LD HL,HEADER LD B,128 MAKE_PCX_6 LD A,(HL) CALL PUT_BYTE INC HL DJNZ MAKE_PCX_6 ;Pixel data: CALL INIT_GET MAKE_PCX_3 CALL GET_BYTE JR C,MAKE_PCX_4 CALL PUT_BYTE JR MAKE_PCX_3 ;Palette type: MAKE_PCX_4 LD A,#0C CALL PUT_BYTE ;Palette (#300 bytes): XOR A MAKE_PCX_5 CALL PUT_BYTE CALL PUT_BYTE CALL PUT_BYTE INC A JR NZ,MAKE_PCX_5 ;Close the file: CALL CLOSE_FILE LD A,1 RET NAME_EXT DB "picture pcx" ;name LEN_FILE DS 3 ;pcx file length FILES DS 1 ;how many files there will be ════════════════════════ ════════════════════════ Best regards, Ivan Roshchin.

From Ivan Roshin To All 2 October 2002

Hello, All! ═══════════════════ 34 .C ══════════════════ ;--------------------------------------- ;The NEW_TS procedure places at the specified ;in the HL address information about the first ;free track/sector and updates ;this information is in the system sector. ; ;Input: A - file length in sectors. ;Output: HL:=HL+2. NEW_TS LD DE,(CAT_BUFER+#8E1) LD(HL),E INC HL ;Address at LD (HL),D ;disk. INC HL ;Increase the numbers of the first unoccupied ;track/sector: LD B,A ;Length in sectors AND 15 ADD A,E BIT 4.A RES 4,A LD E,A JR Z,NEW_TS_1 INC D NEW_TS_1 LD A,B RRA RRA RRA RRA AND 15 ADD A,D LD D,A LD (CAT_BUFER+#8E1),DE RET ;--------------------------------------- ;The GET_BYTE procedure returns to ;the battery has another byte packed ;pixel data. If flag C ;installed - it means the data has run out. ; ;BC,DE,HL do not change. STATUS DS 1 ;N state of proc. BYTE_B DS 1 ;stored byte ;Initialization: INIT_GET LD A,1 LD (STATUS),A CALL INIT_PIX RET ;The procedure itself went: GET_BYTE PUSH BC PUSH DE PUSH HLLD A,(STATUS) CP 2 JR Z,GET_BYTE_2 ;1st state: LD C,1 ;counter of identical CALL GET_PIX JR C,GET_EXIT LD(BYTE_B),A GET_B_3 LD A,C ;already have 63 CP 63 ;same bytes? JR Z,GET_B_1 CALL GET_PIX ;take another byte JR C,GET_B_4 LD HL,BYTE_B ;compare... CP(HL) JR NZ,GET_B_4 INC C JR GET_B_3 GET_B_4 CALL PREV_PIX ;shift back GET_B_2 LD A,(BYTE_B);byte looks like AND %11000000 ;as CP %11000000 ;byte counter? JR Z,GET_B_1 LD A,C ;one DEC A ;repeat? JR NZ,GET_B_1 LD A,(BYTE_B) AND A ;reset flag C JR GET_EXIT GET_B_1 LD A,2 LD (STATUS),A LD A,C OR %11000000 ;reset. flag C JR GET_EXIT ;2nd state: GET_BYTE_2 LD A,1 LD (STATUS),A LD A,(BYTE_B) AND A ;reset flag C GET_EXIT POP HL POP DE POP B.C. RET ════════════════════════ ════════════════════════ Best regards, Ivan Roshchin.

From Ivan Roshin To All 3 October 2002

Hello, All! ═══════════════════ 35 .C ══════════════════ ;--------------------------------------- ;Procedure GET_PIX sequentially ;returns pixel data. If ;flag C is set, which means data ;ran out. ; ;BC,DE,HL do not change. GET_ADR DS 2 ;memory bank address GET_BANK DS 1 ;bank number in the table ;Initialization: INIT_PIX LD HL,#C000-1 LD (GET_ADR),HL XOR A LD (GET_BANK),A RET ;The procedure itself went: GET_PIX PUSH HL LD HL,(GET_ADR) INC HL LD (GET_ADR),HL LD A,H OR L JR NZ,GET_PIX_1 LD HL,#C000 LD (GET_ADR),HL LD A,(GET_BANK) INC A LD (GET_BANK),A CP 3 JR NZ,GET_PIX_1 POP HL SCF RET GET_PIX_1 PUSH BC PUSH DE LD BC,#7FFD LD HL,N_BANK LD A,(GET_BANK) LD D,0 LD E,A ADD HL,DE LD A,(HL) OUT(C),A LD HL,(GET_ADR) LD A,(HL) LD D,#10 OUT(C),D POP DE POP B.C. POP HL AND A ;reset flag C RET ;Shift back one pixel: PREV_PIX PUSH HLLD HL,(GET_ADR) DEC HL LD A,H CP #BF JR NZ,PREV_PIX_1 LD A,L CP#FF JR NZ,PREV_PIX_1 LD HL,#FFFF LD A,(GET_BANK) DEC A LD (GET_BANK),A PREV_PIX_1 LD (GET_ADR),HL POP HL RET ;Data banks with information about pixels: N_BANK DB #10,#11,#13 ;--------------------------------------- ;Procedures for byte recording ;file contents with buffering. IN_BUF DS 1 ;number of bytes in ;buffer DISK_ADR DS 2 ;sector address ;OPEN_FILE - open a file. OPEN_FILE XOR A LD(IN_BUF),A RET ;PUT_BYTE - write a byte to a file. ;Input: A - value to be written. ;Output: registers not modified. PUT_BYTE PUSH AF PUSH BC PUSH DE PUSH HL LD B,A LD A,(IN_BUF) LD HL,FILE_BUFER LD D,0 LD E,A ADD HL,DE LD(HL),B INC A LD(IN_BUF),A ;If the buffer is full, write it: CALL Z,CLOSE_FILE POP HL POP DE POP B.C. POP AF RET ════════════════════════ ════════════════════════ Best regards, Ivan Roshchin.

From Ivan Roshin To All 3 October 2002

Hello, All! ═══════════════════ 36.C ══════════════════ ;CLOSE_FILE - close the file. ;The contents of the buffer are written to disk. CLOSE_FILE LD DE,(DISK_ADR) PUSH DE LD B,1 LD C,6 LD HL,FILE_BUFER CALL #3D13 POP DE INC E LD A,E AND 15 LD E,A JR NZ,CLOSE_EXIT INC D CLOSE_EXIT LD (DISK_ADR),DE RET ;--------------------------------------- ;128-byte header: HEADER db #0A,#05,#01,#08,#00,#00,#00,#00 db #FF,#00,#BF,#00,#00,#01,#C0,#00 db #60,#61,#62,#63,#64,#65,#66,#67 db #68,#69,#6A,#6B,#6C,#6D,#6E,#6F db #70,#71,#72,#73,#74,#75,#76,#77 db #78,#79,#7A,#7B,#3F,#00,#00,#00 db #50,#D6,#B0,#01,#14,#01,#00,#00 db #C5,#B9,#F7,#BF,#C4,#30,#92,#81 db #01,#01,#00,#01,#01,#00,#00,#00 db #00,#00,#00,#00,#00,#00,#00,#00 db #00,#00,#00,#00,#00,#00,#00,#00 db #00,#00,#00,#00,#00,#00,#00,#00 db #00,#00,#00,#00,#00,#00,#00,#00 db #00,#00,#00,#00,#00,#00,#00,#00 db #00,#00,#00,#00,#00,#00,#00,#00 db #00,#00,#00,#00,#00,#00,#00,#00 ════════════════════════ ════════════════════════ Best regards, Ivan Roshchin.

From Ivan Roshin To All 3 October 2002

Hello, All! ═══════════════════ 37.C ══════════════════ 3. SCR2BANK - image conversion in Spectrum format in black and white image with 256 gradations of brightness, located in three memory banks. Using the previous procedure, the resulting image can be written to a pcx file. Input: original image loaded from #4000, bank numbers memory - in N_BANK, brightness gradations - in BRIGHT_0 and BRIGHT_1. ORG #8000 SCR2BANK LD HL,N_BANK LD (PUT_B_1),HL LD HL,#C000 LD (PUT_B_2),HL LD DE,0 MAIN CALL GET_PIX LD B,A AND 7 ;indication OUT (254),A ;on the curb LD A,B CALL PUT_B INC D JR NZ,MAIN INC E LD A,E CP 192 JR NZ,MAIN RET ;Numbers of memory banks used: N_BANK DB #10,#11,#13 ;--------------------------------------- ;The GET_PIX procedure returns the brightness ;the specified pixel of the image. ; ;Input: DE - pixel coordinates. ;Output: A - brightness (0..255). GET_PIX PUSH DE ;Defining INK, PAPER, BRIGHT: LD H,0 LD A,E AND %11111000 LD L,A ADD HL,HL ADD HL,HL LD A,D RRA RRA RRA AND %00011111 LD E,A LD D,#58 ADD HL,DE LD A,(HL) RRA RRA AND %00010000 LD (BRIGHT),A LD A,(HL) AND 7 LD (INK),A LD A,(HL) RRA RRA RRA AND 7 LD (PAPER),A POP DE PUSH DE CALL BYTE AND (HL) LD A,0 PAPER EQU $-1 JR Z,GET_PIX_1 LD A,0 INK EQU $-1 GET_PIX_1 ADD A,A ADD A,0 BRIGHT EQU $-1 LD E,A LD D,0 LD HL,BRIGHT_0 ADD HL,DE LD E,(HL) INC HL LD D,(HL) LD HL,#80 ADD HL,DE LD A,H POP DE RET BYTE LD A,E AND A RRA SCF RRA AND A RRA XOR E AND #F8 XOR E LD H,A LD A,D RLCA RLCA RLCA XOR E AND #C7 XOR E RLCA RLCA LD L,A LD A,D AND 7 LD B,A INC B LD A,1 LOOP RRCA DJNZ LOOP RET ;--------------------------------------- ;Brightness gradations in 8.8 format: BRIGHT_0 DW 0.1112.2139.4412.6062 DW 14555,26811,46556 BRIGHT_1 DW 0.1369.3129.6062.8995 DW 21704,38045,65280 ;--------------------------------------- ;Procedure PUT_B - writing to memory ;information about the next pixel. ; ;Input: A - pixel value. PUT_B PUSH AF ;Set LD A,(0) ;required PUT_B_1 EQU $-2 ;bank LD BC,#7FFD ;memory. OUT(C),A POP AF LD HL,0 ;Write. PUT_B_2 EQU $-2 LD(HL),A INC HL ;Increase LD A,H ;address. OR L JR NZ,PUT_B_3 LD HL,(PUT_B_1) ;Go to INC HL ;following LD (PUT_B_1),HL ;jar. LD HL,#C000 PUT_B_3 LD (PUT_B_2),HL RET ════════════════════════ ════════════════════════ Best regards, Ivan Roshchin.

From Ivan Roshin To All 3 October 2002

Hello, All! ═══════════════════ 37.C ══════════════════ 3. SCR2BANK - image conversion in Spectrum format in black and white image with 256 gradations of brightness, located in three memory banks. Using the previous procedure, the resulting image can be written to a pcx file. Input: original image loaded from #4000, bank numbers memory - in N_BANK, brightness gradations - in BRIGHT_0 and BRIGHT_1. ORG #8000 SCR2BANK LD HL,N_BANK LD (PUT_B_1),HL LD HL,#C000 LD (PUT_B_2),HL LD DE,0 MAIN CALL GET_PIX LD B,A AND 7 ;indication OUT (254),A ;on the curb LD A,B CALL PUT_B INC D JR NZ,MAIN INC E LD A,E CP 192 JR NZ,MAIN RET ;Numbers of memory banks used: N_BANK DB #10,#11,#13 ;--------------------------------------- ;The GET_PIX procedure returns the brightness ;the specified pixel of the image. ; ;Input: DE - pixel coordinates. ;Output: A - brightness (0..255). GET_PIX PUSH DE ;Defining INK, PAPER, BRIGHT: LD H,0 LD A,E AND %11111000 LD L,A ADD HL,HL ADD HL,HL LD A,D RRA RRA RRA AND %00011111 LD E,A LD D,#58 ADD HL,DE LD A,(HL) RRA RRA AND %00010000 LD (BRIGHT),A LD A,(HL) AND 7 LD (INK),A LD A,(HL) RRA RRA RRA AND 7 LD (PAPER),A POP DE PUSH DE CALL BYTE AND (HL) LD A,0 PAPER EQU $-1 JR Z,GET_PIX_1 LD A,0 INK EQU $-1 GET_PIX_1 ADD A,A ADD A,0 BRIGHT EQU $-1 LD E,A LD D,0 LD HL,BRIGHT_0 ADD HL,DE LD E,(HL) INC HL LD D,(HL) LD HL,#80 ADD HL,DE LD A,H POP DE RET BYTE LD A,E AND A RRA SCF RRA AND A RRA XOR E AND #F8 XOR E LD H,A LD A,D RLCA RLCA RLCA XOR E AND #C7 XOR E RLCA RLCA LD L,A LD A,D AND 7 LD B,A INC B LD A,1 LOOP RRCA DJNZ LOOP RET ;--------------------------------------- ;Brightness gradations in 8.8 format: BRIGHT_0 DW 0.1112.2139.4412.6062 DW 14555,26811,46556 BRIGHT_1 DW 0.1369.3129.6062.8995 DW 21704,38045,65280 ;--------------------------------------- ;Procedure PUT_B - writing to memory ;information about the next pixel. ; ;Input: A - pixel value. PUT_B PUSH AF ;Set LD A,(0) ;required PUT_B_1 EQU $-2 ;bank LD BC,#7FFD ;memory. OUT(C),A POP AF LD HL,0 ;Write. PUT_B_2 EQU $-2 LD(HL),A INC HL ;Increase LD A,H ;address. OR L JR NZ,PUT_B_3 LD HL,(PUT_B_1) ;Go to INC HL ;following LD (PUT_B_1),HL ;jar. LD HL,#C000 PUT_B_3 LD (PUT_B_2),HL RET ════════════════════════ ════════════════════════ Best regards, Ivan Roshchin.