Re: A few questions about NEIL
- Posted by David Cuny <dcuny at LANSET.COM> May 20, 1999
- 525 views
Tor Bernhard Gausen wrote some questions about Neil. I'll take a stab at answering them, but I don't guarantee the answers are correct, since I'm too lazy to actually verify many of the answers. >1) What is a blit ? blit: /blit/ vt. 1. To copy a large array of bits from one part of a computer's memory to another part, particularly when the emory is being used to determine what is shown on a display screen. "The storage allocator picks through the table and copies the good parts up into high memory, and then blits it all back down again." See bitblt, BLT, dd, cat, blast, snarf. More generally, to perform some operation (such as toggling) on a large array of bits while moving them. 2. Sometimes all-capitalized as `BLIT': an early experimental bit-mapped terminal designed by Rob Pike at Bell Labs, later commercialized as the AT&T 5620. (The folk etymology from `Bell Labs Intelligent Terminal' is incorrect. Its creators liked to claim that "Blit" stood for the Bacon, Lettuce, and Interactive Tomato.) bitblt: /bit'blit/ n. [from BLT, q.v.] 1. Any of a family of closely related algorithms for moving and copying rectangles of bits between main and display memory on a bit-mapped device, or between two areas of either main or display memory (the requirement to do the Right Thing in the case of overlapping source and destination rectangles is what makes BitBlt tricky). 2. Synonym for blit or BLT. Both uses are borderline techspeak. >2) Exactly what does these different blit kinds : Blit, Clear_blit, >Mixer_blit, Screen_blit, and Wait_retrace When you blit an image, it involved two sets of pixels: a source and a destination. You can specify various ways in which the source and destination pixels are mixed. Not looking at Neil, I'll make the *wild* guess that: Blit = replaces the destination with the source copy Clear_blt = treat some color in the source as transparent, for sprites Mixer_blt = allow color transparency, so you can see through the image Wait_retrace = wait till the screen's fully drawn before updating, to avoid flickering Smart money says I'm dead wrong.Why so many types of options? That's *nothing* - Win32 has 256 different codes! >4) What are Run Length Encoded sprites? "Run Length Encoding" (RLE) is a means of compression. It takes advantage of the fact that certain kinds of data has strings of repeating values, such as: AAAABBBBAABBBBC which could be RLE encoded as: 5 'A's, 4 'B's, 2 'A's, 4 'B's, 1 'C' or in a sequence as: { 5, 'A', 4, 'B', 2, 'A', 4, 'B', 1, 'C' } Pete's got routines that use RLE to great effect on text. Consider the letter 'F': XXXXXX X XXX X X X X X If it were stored as a bitmap, it might be encoded as: constant F = { {11111100}, {10000000}, {11100000}, {10000000}, {10000000}, {10000000}, {10000000}, {10000000} } The '1' is the foreground "color", and the '0' is the background color. If we moved the whole bitmap to the screen, it would display an 'F' - but any background pattern would be obscured: procedure renderLetter( integer x, integer y, integer color, sequence letter ) display_image( {x,y}, letter * color ) end procedure One way around this would be to write a routine that would know that the color '0' was transparent: procedure render( integer x, integer y, integer color, sequence letter ) -- convert to offsets x -= 1 y -= 1 for y1 = 1 to length( letter ) do for x1 = 1 to length( letter[y0] ) do if letter[y0][x0] != 0 then pixel( {x+x1, y+y1}, {color} ) end if end for end for end procedure This is obviously a lot more expensive to perform, and is essentially what Clear_bit (whatever) does. Another method of performing transparency is to take advantage of some of those 256 ROP codes that some blitters support. For example, in Windows: ...a common method of implementing transparency with bitmaps is to have a color bitmap, and an associated monochrome bitmap containing a mask. The mask bitmap is combined with the target bitmap using the SRCAND operation. All white pixels leave the destination untouched, all black pixels zero the destination - effectivly cutting a black hole in the target. The color bitmap is then combined with the destination using the SRCPAINT raster operation. This operation ORs each color pixel from the color image with a blacked out pixel in the destination. The source image itself is black where the destination has been left, leaving the non-transparent pixels untouched - the transparent pixles now contain the image. (The above paragraph was stolen from an author other than myself) Aren't you glad you didn't ask? Anyhoo, it's because of stuff like that that blitters tend to have so many ROP (raster operation) codes. It may seem inefficient, but computers are *very* fast at performing boolean operations, so it's faster than you thing. But I digress - on to RLEs: You could apply RLE to the letter, storing it in tuples of the form: { x, y, repetition } So the 'F' would become: { { 0, 0, 6 }, { 0, 1, 1 }, { 0, 2, 3 }, { 0, 3, 1 }, { 0, 4, 1 } { 0, 5, 1 }, { 0, 6, 1 }, { 0, 7, 1 } } Or you could place them in a list like this: { 0, 0, 8, 0, 1, 1, 0, 2, 3, 0, 3, 1, 0, 4, 1, 0, 5, 1, 0, 6, 1, 0, 7, 1 } The flat representation is better, for reasons I get into a bit later. You can recreate the letter with a procedure like this: procedure render( integer x, integer y, integer color, sequence rle ) integer x1, y1, rep for i = 1 to length( rle ) by 3 do -- get a tuple x1 = x + rle[i] y1 = y + rle[i+1] rep = rle[i+2] -- output pixel( {x,y}, repeat( color, rep ) end for end procedure Using RLEs to encode the letter gets rid of the "problem" of transparency. In addition, it's an efficient method for working with the video display, since video memory is organized into horizontal scanlines anyway. OK, now onto sprites. Let's imagine that you had a sprite that looked like this: 00011000 00122100 01233210 12300321 12300321 01233210 00122100 00011000 Here, '0' represents transparency. Note that it's transparent in the center. To render it, you could use the Clear_bit option (or whatever that flag is), or you could turn it into an RLE Sprite in the form: { x, y, color1, color2 ... } The encoded sprite would look like this: constant RLE_SPRITE = { 3, 0, 1, 1 } { 2, 1, 1, 2, 2, 1 }, { 1, 2, 1, 2, 3, 3, 2, 1 }, { 0, 3, 1, 2, 3 }, { 5, 3, 3, 2, 1 }, { 0, 4, 1, 2, 3 }, { 5, 4, 3, 2, 1 }, { 1, 5, 1, 2, 3, 3, 2, 1 }, { 2, 6, 1, 2, 2, 1 }, { 3, 7, 1, 1 } } Sequences are not only memory expensive - Neil's assembly routines can't access them! So first we add the length of each line to the data, in the form: { x, y, count of colors, color1, color2 ... } The sprite is now encoded as: constant RLE_SPRITE = { 3, 0, 2, 1, 1 } { 2, 1, 4, 1, 2, 2, 1 }, { 1, 2, 6, 1, 2, 3, 3, 2, 1 }, { 0, 3, 3, 1, 2, 3 }, { 5, 3, 3, 3, 2, 1 }, { 0, 4, 3, 1, 2, 3 }, { 5, 4, 3, 3, 2, 1 }, { 1, 5, 6, 1, 2, 3, 3, 2, 1 }, { 2, 6, 4, 1, 2, 2, 1 }, { 3, 7, 2, 1, 1 } } Same data as before, but with additional length information. With the length information encoded, we can flatten the data to a single sequence. I have to add add one more value to the head of the sequence - the length of the sequence. That's because the sprite renderer needs to know where to stop. It could also be accomplished by placing a -1 at the end of the data, or some other scheme: constant RLE_SPRITE = { 66, 3, 0, 2, 1, 1, 2, 1, 4, 1, 2, 2, 1, 1, 2, 6, 1, 2, 3, 3, 2, 1, 0, 3, 3, 1, 2, 3, 5, 3, 3, 3, 2, 1, 0, 4, 3, 1, 2, 3, 5, 4, 3, 3, 2, 1, 1, 5, 6, 1, 2, 3, 3, 2, 1, 2, 6, 4, 1, 2, 2, 1, 3, 7, 2, 1, 1 } I don't guarantee that Neil actually encodes sprites this way, but that's the concept. I'll leave the details of displaying the RLE Sprite as an exercise for the reader.
>5) What is a sub screen ? How is a sub screen different from >other virtual screens? A "sub screen" lets you address a portion of a virtual screen as if it were an virtual screen all by itself. Here's an example: imagine you are writing a DOOM(tm) clone. One portion of the window displays what the player sees; it's a 100x100 located at (50, 200). Another window displays the player's health in the corner; it's a 100x32 in the upper right hand corner at (0,0). One way to do this would be to create a virtual screen for each window (view, health, etc.), and then composite the image by blitting the seperate virtual screens onto the video screen. Another way to do it would be to create *one* virtual screen the size of the video display, and create several subscreens on that. Each subscreen would work as if it were a seperate virtual screen, but they would all share the same virtual screen, so you could update the video with a single blit. Another example might be that you stored the letters of some cool font into a single bitmap. You could then load the bitmap into a virtual screen, and then create seperate "sub screens" for each letter, storing the handles in an array. That way, it might be easier to retrieve and display the letters when you are creating messages with them. Hoping not *all* of my answers miss completely miss the mark... -- David Cuny