############################################################################# # # # #### #### ### # ##### #### # # # # # # # # # # # # ### # ##### # ### # # # # # # # # # # # # # # #### #### # # ##### ##### #### # # # # #### ##### ##### ##### ### #### #### # # # # # # # # # # # # # # # # #### # # # # # ##### #### ### # # # # # # # # # # # # # # # #### ##### # # # # # # # #### # # # # Trainer # # # # by # # # # Tumblin / Bodies In Motion # # # ############################################################################# Hello there, this doc file is intended to be a trainer for doing scaled bitmaps. The routines accompanying this file are not meant to be as fast as possible, but clear and easy to learn what is going on when doing this effect. With this in mind, lets put on our thinking caps and get our hands dirty! Okay, first a little bit of background theory. The basic algorithm that my implementation of scaled bitmaps is based on is the infamous Bresenham's Algorithm. This is the favoured technique for drawing lines very quickly. But for scaled bitmaps, we modify it a little so that we can take a column of pixels and stretch them out or squash them down. Lets go through an example that we could use to draw a scaled bitmap, in the form of a vertical column of pixels on the screen by taking pixel colors from a one dimensional array. The following pseudo code example will *stretch* a source bitmap to a larger destination bitmap (a 64 pixel bitmap to a 124 pixel bitmap): ----------------------------------------------------------------------------- source_height = 64 start_y = 0 end_y = 123 destination_height = end_y - start_y error_term = 0 source_index = 0 screen_x = 0 screen_y = start_y do { color=bitmap[source_index] draw_pixel(screen_x,screen_y) error_term = error_term + source_height if error_term > destination_height error_term = error_term - destination_height source_index = source_index + 1 endif screen_y = screen_y + 1 } while screen_y < end_y ----------------------------------------------------------------------------- Here's the explanation. In the do loop, you start out by grabbing a color from the source bitmap that you want to scale onto the screen. You then draw that color on the screen at the current screen coordinates. Then there is this error_term thingy. What it is used for is to help us decide when it will be time to change the index into the source bitmap so that we can pull out the next color. What you do is you add the height of the source bitmap to the error term, then you do a test to see if the error term has exceeded the size of the destination bitmap. If it did, then you subtract the size of the destination bitmap from the error term and also increase the index into the source bitmap. After this decision is done, you increase the screen coordinate. You keep repeating this do loop until the screen coordinate is equal to the ending coordinate that you specified at the beginning. The whole gist of scaling a small source bitmap to a larger destination bitmap is to always increment the screen coordinate through each time through the loop and only increment the index to the source bitmap when it is necessary to. Every pixel in the source bitmap will be drawn at least once, even repeated if need be. Just think in your mind that you are "stretching" the bitmap. Pretty simple really. Now here is what it would look like if you wanted to *shrink* a source bitmap to a smaller destination bitmap (a 101 pixel bitmap to a 74 pixel bitmap): ----------------------------------------------------------------------------- source_height = 101 start_y = 0 end_y = 73 destination_height = end_y - start_y error_term = 0 source_index = 0 screen_x = 0 screen_y = start_y do { color=bitmap[source_index] draw_pixel(screen_x,screen_y) error_term = error_term + destination_height if error_term > source_height error_term = error_term - source_height screen_y = screen_y + 1 endif source_index = source_index + 1 } while screen_y < end_y ----------------------------------------------------------------------------- This is the same idea as before but with a few changes. In this one, you grab a color from the source bitmap and draw it on the screen like in the previous example. Then you add the size of the destination bitmap to the error term. If the error term exceeds the size of the source bitmap then you just subtract the size of the source bitmap from the error term and also increment the screen coordinate. After the if statement, you manditorialy increment the index into the source bitmap. So the gist of scaling a larger source bitmap to a smaller destination bitmap is to always increment the index into the source bitmap, but only drawing the pixels that are necessary. This means that some of the pixels in the source bitmap will be skipped. Now then, how do you scale a whole rectangular source bitmap to a rectangular destination bitmap??? Well, you have to combine the techniques above to take care both cases of drawing vertically stretched single columns of pixels. Okay, so that takes care of drawing scaled vertical lines, but what about the horizontal dimension? You basically use the same routines explained above, but switch the x's with y's and use the index into the source bitmap to select which column of the source bitmap you want to work with and then use the very same routines that we used before. Actually scaled bitmaps are nested Bresenham loops. Just remember that when you are doing your routines, make sure you cover the two types of vertical scaling (large to smaller, and small to larger), and the two types of horizontal scaling (large to smaller and small to larger). Oops, actually there is one more additional case, I forgot to mention the case where the source and destination bitmaps are equal in size! But that is *easily* accounted for. All you have to do is let one of the four cases also include an equality in the sizes of both dimensions of the source and destination bitmaps. Another thing to remember is that when you are done doing a vertical line, reset the index to the source bitmap back to zero and reset the screen y coordinate to the top again. All of this will be clear when you see the complete source code ;-) =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= Here are some tips for getting the code compiled: My system consists of a 486DX 33MHz, Trident 8900 SVGA 1MB, 120MB hard drive, Sound Blaster Pro, and I use Turbo C++ 3.0. First you need a copy of XLIB06.ZIP Unzip this file into a directory and then edit MAKEFILE to change the line that says MODEL=s to MODEL=l (I used the large memory model to compile this demo). This is what might have caused some people some confusion when they tried to compile my previous release VECTBALL.ZIP. I included the VECTBALL.PRJ file with it and I had the memmory model on the Large setting. XLib 6 was released with the memory model set to Small. Please make sure that the memory models match! I might also mention that I also had to change the line that says CC=bcc to CC=tcc (I compiled it with my Turbo C++ 3.0 and worked fine). Next type MAKE and watch XLib 6 get compiled before your very eyes. When I did it myself, I noticed some strange warnings fly up the screen, but they didn't hurt anything one bit. I guess one of the demo programs didn't get compiled, but the most important thing is that the XLIB6L.LIB file got compiled okay. Now you create a project file by typing BC BMSCALER.PRJ if you have the Borland C++ 3.1 compiler or TC BMSCALER.PRJ if you have the Turbo C++ 3.0 compiler. Next you add the BMSCALER.CPP and XLIB6L.LIB files into your project. Use the Options/Code Generations option and select the Large memory model. When you are done that, you should be all ready to compile the BMSCALER.CPP by using Complile/Make, or compile it and run it in the IDE by doing a Compile/Run. Play around with the call to the bmscaler function and use some strange coordinate combinations, they can make some pretty interesting visual effects. =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= I guess that about wraps up my discussion on scaled bitmaps. If you have any questions or comments, email me. If you use this code in any demos you write, greet me, or send me a cool post card from your country. Tumblin / Bodies In Motion