[ Nomad Programming, Graphics, and Algorithms Tutorial ] [ Compiler : Borland C++ 3.0/3.1 ] [ Part 5 - Line Plotting ] [ http://nomad.openglforums.com ] <<------------------------------------------------------>> [ DISCLAIMER ] I will hold no responsibility to whatever happens to you, your computer, your sanity, your pet, or whatever that may happen to your existence for your reading these texts and for the outcome of the various source code(s) given in each tutorial. So in short, read at your own risk! [ INTRODUCTION ] Now that we know how to display pixels on various screen resolutions and bit-depths, we would want to learn the next important thing: LINES! Obviously, if you've played a computer game or two, you'll know immediately why lines are important in computer graphics. Just imagine being an architect trying to create a masterpiece without using any lines...difficult huh?...;). SideNote: One of the nice concepts I learned in our university is to use codes / methods that are available already. They are tested and tend to be better than the ones that will be created from scratch... I hope this way of thinking would show from now on...:). [ TUTORIAL ] There're various ways you could draw a line on a 2D surface. I'll discuss to you guys just one (SLOW) way today...plus one (FAST) 'bonus' algorithm courtesy of Bresenham...:). One way to draw a line is through the use of sine/cosine. Let's refresh ourselves with both of them first (Oh yeah, using sine and cosine is SLOWWww, so avoid them...I'm using it here just as an introduction...:) ): cosine(angle) = X / R sine (angle) = Y / R where: Y is the length of our line vertically X is the length of our line horizontally R is the length of our line from endpoint(x1,y1) to endpoint(x2,y2) We get R through the Pythagorean Theorem: R = square root(X^2 + Y^2) And the angle through either one of these: angle = ArcCosine(X / R) or angle = ArcSine (Y / R) Getting the length of X and Y is easy. Just subtract x2 to x1 for X, and y2 to y1 for Y. But what we're interested is X and Y because those are what we will use as our coordinates to plot to the screen. So through algebra, we manipulate our original equation to: X = cosine(angle) * R Y = sine (angle) * R Check also if (x2-x1) is negative (as well as (y2-y1)) because you'll be looping through them (if you choose to implement it). I won't bother implementing what I just said above since it's not a good way to draw lines (but it WILL work, trust me). Another way would be through the equation: Y = mX + B If you don't know this equation, try finding someone who does. I believe many people have heard about this equation in their lifetime? Now the 'bonus' algorithm I was telling you about is based on this equation. If you're clever enough, you'll be able to create a line routine from the above equation without any division and multiplications, and you'll be using only integer variables...something quite hard to do, but was achieved by a guy name Bresenham already...:). Here's the code for Bresenham's algorithm: //----8<----[ CODE BEGIN ]--------// void line_bres(int x1,int y1, int x2,int y2, unsigned int color) { int ctr,sdx,sdy; int deltax,deltay,x,y; int plotx = x1, ploty = y1; deltax = abs(x2-x1); deltay = abs(y2-y1); if(x2-x1 < 0) sdx = -1; else if(x2-x1 > 0) sdx = 1; else sdx = 0; if(y2-y1 < 0) sdy = -1; else if(y2-y1 > 0) sdy = 1; else sdy = 0; x=deltay>>1; y=deltax>>1; pixel_highcolor(plotx, ploty, color); if (deltax >= deltay) { for(ctr=0; ctr= deltax) { y -= deltax; ploty += sdy; } plotx += sdx; pixel_highcolor(plotx, ploty, color); } } else { for(ctr=0; ctr= deltay) { x -= deltay; plotx += sdx; } ploty += sdy; pixel_highcolor(plotx, ploty, color); } } } //----8<----[ CODE END ]--------// As you can see, there's no multiplication nor division in Bresenham's Line Algorithm. It may look long and slow, but upon closer scrutiny, you'll notice that not all of the codes are executed...the if-statements controls which lines are executed...if deltax >= deltay, execute these set of codes, else execute another set of codes...:). [ ENDING ] And that's that! Not hard eh? If there is anything that's not clear to you, your mind, or to that part of you that lets you comprehend the things here, you may email me at (according to priority): willietang@hehe.com or willietang@yahoo.com Part 6 we abandon DOS and move to MS Windows! We'll learn how to create a window under MS Windows and how "messages" are handled. We will be dealing with the Win32 API. This parting from DOS is good for us because we won't be very productive staying inside a cave are we? And after learning how to create windows and stuffs, we'll learn the basics of the OpenGL API. After that, maybe we'll probe some nitty-gritty stuffs (such as generating and walking through landscapes, loading 3D model files, etc....all in due time...;) ). Briefly...uhh, no, there's no 'briefly' section here, you can't make a 'brief' summary about the Win32 API...:). [ NOMAD.C ] #include #include #include #include //--[ VESA STRUCTURE ]---------------------// typedef struct { unsigned char VESAsignature[4]; unsigned char VersionMinor; unsigned char VersionMajor; unsigned char far *OEM; long int Capabilities; unsigned int far *VideoModes; unsigned int TotalMemory; unsigned char Reserved[235]; } VESA_STRUCT; //--[ MODE STRUCTURE ]---------------------// typedef struct { unsigned int ModeAttribute; unsigned char WindowA; unsigned char WindowB; unsigned int Granularity; // Granularity and WinSize are unsigned int WinSize; // used to calc bankmult unsigned int WinAseg; // Window A's starting segment unsigned int WinBseg; // Window B's starting segment void (far *bankSwitch)(void); unsigned int Bytesperline; // Bytes per line unsigned int Xres; // Width of the mode unsigned int Yres; // Height of the mode unsigned char charWidth; // For VESA text-modes only unsigned char charHeight; // For VESA text-modes only unsigned char bitplanes; unsigned char bitsperpixel; // If 8 then 256 colors unsigned char banks; unsigned char memorymodel; unsigned char banksize; unsigned char imagepages; unsigned char reserved1; unsigned char redmasksize; // For 15/16-bit modes unsigned char redfieldposition; // For 15/16-bit modes unsigned char greenmasksize; // For 15/16-bit modes unsigned char greenfieldposition; // For 15/16-bit modes unsigned char bluemasksize; // For 15/16-bit modes unsigned char bluefieldposition; // For 15/16-bit modes unsigned char rsvdmasksize; // For 15/16-bit modes unsigned char rsvdfieldposition; // For 15/16-bit modes unsigned char directcolormode; unsigned char Reserved[216]; // Reserved } MODE_STRUCT; static int current_bank; static int bankmult; VESA_STRUCT VesaINFO; MODE_STRUCT ModeINFO; //--[ SETS SCREEN TO GIVEN MODE ]---------// int setGFXMODE(int mode_num) { _AH = 0x4F; _AL = 0x02; // VBE FUNCTION 0x02!!! _BX = mode_num; geninterrupt(0x10); //--[ INITIALIZE GLOBAL VARIABLES ]--// current_bank = 0; bankmult = ModeINFO.WinSize / ModeINFO.Granularity; return _AX; // zero if successful } //--[ SETS SCREEN TO TEXT MODE ]----------// void setTXTMODE() { _AX = 0x0003; geninterrupt(0x10); } //--[ SETS BANK USING BIOS ]--------------// void setbank_SLOW(int bank_num) { bank_num = bank_num * bankmult; if (current_bank == bank_num) return; _AH = 0x4F; _AL = 0x05; // VBE FUNCTION 0x05!!! _BX = 0x0; _DX = bank_num; geninterrupt(0x10); if (_AX==0x4F) // SUCCESS current_bank = bank_num; } //--[ GETS VESA INFO ]--------------------// char getVesaInfo(VESA_STRUCT *vesainfo) { _AH = 0x4F; _AL = 0x00; // VBE FUNCTION 00!!! asm les di,[vesainfo] geninterrupt(0x10); if(_AX==0x4F) return(1); return(0); } //--[ GETS MODE INFO ]--------------------// char getVesaModeInfo(unsigned int mode, MODE_STRUCT *modeinfo) { _AH = 0x4F; _AL = 0x01; // VBE FUNCTION 01!!! _CX = mode; asm les di,[modeinfo] geninterrupt(0x10); if(_AX==0x4F) { return(1); } return(0); } //--[ PACKS RGB TO AN UNSIGNED INT ]------// unsigned int RGB15bit(unsigned char R, unsigned char G, unsigned char B) { unsigned int Red,Green,Blue; unsigned int Final_Color = 0; R = R >> 1; Red = R << 10; G = G >> 1; Green = G << 5; B = B >> 1; Blue = B << 0; Final_Color = Final_Color + Red + Green + Blue; return(Final_Color); } //--[ PLOTS PIXEL DIRECTLY TO MEMORY ]---// void pixel_highcolor(int x, int y, unsigned int colornum) { long int offset = (long)y*ModeINFO.Bytesperline + x + x; unsigned int temp = colornum << 8; unsigned char ch1; unsigned char ch2; ch1 = temp >> 8; ch2 = colornum >> 8; setbank_SLOW(offset >> 16); memset(MK_FP(0xA000,offset), ch1, 1); memset(MK_FP(0xA000,offset+1), ch2, 1); } //--[ BRESENHAM'S LINE PLOTTING ALGO ]---// void line_bres(int x1,int y1, int x2,int y2, unsigned int color) { int ctr,sdx,sdy; int deltax,deltay,x,y; int plotx = x1, ploty = y1; deltax = abs(x2-x1); deltay = abs(y2-y1); if(x2-x1 < 0) sdx = -1; else if(x2-x1 > 0) sdx = 1; else sdx = 0; if(y2-y1 < 0) sdy = -1; else if(y2-y1 > 0) sdy = 1; else sdy = 0; x=deltay>>1; y=deltax>>1; pixel_highcolor(plotx, ploty, color); if (deltax >= deltay) { for(ctr=0; ctr= deltax) { y -= deltax; ploty += sdy; } plotx += sdx; pixel_highcolor(plotx, ploty, color); } } else { for(ctr=0; ctr= deltay) { x -= deltay; plotx += sdx; } ploty += sdy; pixel_highcolor(plotx, ploty, color); } } } void main() { unsigned int *runner; unsigned int found = 0; long int ctr; setTXTMODE(); printf("\n\nNOMAD GRAPHICS TUTORIAL - [ PART 5 ]\n"); printf("\n This is a sample code included with GFXTUT5.TXT"); printf("\n to show how to implement the sample codes that"); printf("\n were given in the said tutorial.\n"); printf("\n [ Press Any Key to Begin ]"); (void)getch(); if(getVesaInfo(&VesaINFO)==1) { runner = VesaINFO.VideoModes; while((*runner)!=0xFFFF) { if((*runner)==0x110) found = 1; runner++; } if(found==1) { getVesaModeInfo(0x110,&ModeINFO); setGFXMODE(0x110); for(ctr=0; ctr<100000; ctr++) line_bres(random(640), random(480), random(640), random(480), RGB15bit(random(63),random(63),random(63))) setTXTMODE(); printf("\n\nNOMAD GRAPHICS TUTORIAL - [ PART 5 ]\n"); printf("\n That's all for now. See you in GFXTUT6.TXT!...:)\n"); printf("\n email: [ willietang@hehe.com ]\n"); } else { setTXTMODE(); printf("\n\nNOMAD GRAPHICS TUTORIAL - [ PART 5 ]\n"); printf("\n SORRY! It seems your monitor doesn't support the"); printf("\n screen mode 640x480-15bit through VESA.\n"); printf("\n That's all for now. See you in GFXTUT5.TXT!...:)\n"); printf("\n email: [ willietang@hehe.com ]\n"); } } } <<------------------------------------------------------>> [ Written By: Willie Tang ] [ Written On: 10.22.2001 ] [ Updated On: 12.01.2001 ]