::[
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; ctr++) {
y += deltay;
if (y >= deltax)
{ y -= deltax;
ploty += sdy;
}
plotx += sdx;
pixel_highcolor(plotx, ploty, color);
}
} else
{ for(ctr=0; ctr<deltay; ctr++) {
x += deltax;
if (x >= 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:
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 <DOS.H>
#include <MEM.H>
#include <STDLIB.H>
#include <STDIO.H>
//--[ 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...:)\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...:)\n");
printf("\n email: [ willietang@hehe.com ]\n");
}
}
}
This tutorial was written on: 10.22.2001 | Updated: 12.01.2001