Mode13h
			The Beginning of 3D/2D Graphics

Intro


Lots of people want to know how to do graphics but find most APIs like
OpenGL, DirectX etc too complex for a beginner, especially as they involve GUI code which follows a different approach from the simple dos programming Here, I will present a simple graphics mode, which can be easily used via dos console programming

What I will be covering

Part 1:Introduction to Mode13h			(this part)
	Part 2:Blazing:Lets speed up and burn		(algorithms,double buffering)
	Part 3:Dangers and Protection Systems		(wait and see)
	Part 4:Bitmap Loading and Animation		(woooooo!!!!)
	Part 5:Assembler,Let's go faster			(world of supersonics,C++ code)
	Part 6:Palette fun					(let the artist live)
	Part 7:Intro to 3D					(::::::::::::::::)
	Part 8:3D Star Fields					(weee!!!!)
	Part 9:Wrapup						(end,alternate techs)

Ok, this series will take sometime or so. Maybe weekly updates. We go
slow in this article. Part 2 will be larger and contain code.

History of Mode13h

Here's a quote by a 3D programmer, Jacco Bikker (The Phantom):

In the old days, there was DOS. And in DOS, there was mode 13. Once
initialized, the unsuspecting coder could write to video memory, starting
at a fixed address, A0000 if I am correct. All this didn't block the computer, and worked on virtually every VGA card in the world. The mode allowed for output of 256 color graphics, and that was just fine, if you did it well.

But then something really bad happened. SVGA cards started to appear
everywhere, and to make things worse, computers became fast enough
to do true-color graphics. From that moment on, nothing was certain
anymore. You had 15 bit graphics (for some VERY odd reason someone
decided to ignore a whole bit), 16 bit graphics, 24 bit, 32 bit, and random
orderings of the color components in these arrays of bits. You could for
instance encounter a card that did RGB, but also BGR, or RGBA... So the
VESA standard was invented. This made things bearable again.

So, anyway Mode13h is a graphics mode from the past, with a low resolution so don't compare it with the latest stuff you see in the games. People do say Mode13h is dead, it's not true, even though no game company makes games in Mode13h anymore, it will serve as nice intro beginners, as it has done before. And btw, lots of games are still being made in mode13h by hobbyists.

Let the coding begin.....

Tools of the Trade

Mode13h does not work in the standard console mode, so you will have to change a few settings on you compiler. You will have to use DOS, Large memory model. Don't worry too much. Just getting into mode13h or getting out of it is different on different compilers the rest is quite the same. The simplicity comes from the fact that you can write to the screen pixels as if you were writing into a char array. It simple to set up x, y coordinate system in Mode13h.

You can get TurboC for Borland's site for free. It is quite good if you want an easy way to compile you programs. Remember to compile in the LARGE memory model!

To compile in Borland C: bcc -ml yourprogram.c I would still recommend that you get a C++ compiler to compile your programs as I will use stuff like classes later on. And it's much easy to code if you can use the advanced features which C++ offers over C.

Compilers

Borland C++ 	(My fav)
DJGPP		(Free,Very Good,Protected mode programs)
Dev-C++		(Dont know,heard somewhere it can do Mode13h)

Headers

Keep all functions you get in a header files. That way you won't have to modify all you programs to change something. Standard Headers to include:

#include <stdio.h>
#include <stdlib.h>
#include <dos.h>
#include <mem.h>

Borland (Should work on most compilers)

#define VIDEO_INT		0x10      /* the BIOS video interrupt. */
#define SET_MODE		0x00      /* BIOS func to set the video mode. */
#define MODE_13H		0x13      /* use to set 256-color mode. */
#define TEXT_MODE		0x03      /* use to set 80x25 text mode. */

#define SCREEN_WIDTH        320       /* width in pixels of mode 0x13 */
#define SCREEN_HEIGHT       200       /* height in pixels of mode 0x13 */

#define SCREEN_SIZE		SCREEN_WIDTH*SCREEN_HEIGHT

#define NUM_COLORS          256       /* number of colors in mode 0x13 */

byte *VGA=(byte *)0xA0000000L;        /* this points to video memory. */

void set_mode(byte mode)
{
	union REGS regs;
	
	regs.h.ah = SET_MODE;
	regs.h.al = mode;
	int86(VIDEO_INT, &regs, &regs);
}

Use it as:

set_mode(MODE_13H);		//to get into mode13h
set_mode(TEXT_MODE);	//to get back into the normal mode

DJGPP

void set_mode(byte mode)
{
	union REGS regs;
	
	regs.x.ax = mode;
	int86(VIDEO_INT, &regs, &regs);
}

Properties of Mode13h

It's 320 pixels wide and 200 pixels high. There are 256 colors available, and their values fit in 1 byte, i.e. the size of a char. I mentioned earlier that putting a pixel was as simple as putting a char in an array. The VGA memory is 64000 (320 * 200) bytes in size. Location(0,0) is at the top left hand corner of the screen. So Mode13h is simple to implement and it is fast.

Drawing In Mode13h

Ah the section you been all waiting for. Here we will just discuss putting a pixel and clearing the screen. Later on I will talk about algorithms for drawing lines, circles, boxes etc. They all require you to be able to put a pixel any way.

void pixel(int x,int y,byte color)	//Puts a pixel by writing directly to memory
{
	VGA[y*SCREEN_WIDTH+x]=color;
}

void clear(int color)
{
	memset(VGA,color,SCREEN_SIZE);
}

Really simple,eh? Look at the function for putting a pixel to the screen. We are simply writing to the VGA memory as if it was just a char array.

Go ahead, try something,anything!You should be able to draw straight lines with simple functions.

void line_horz(int x,int y,int len,byte color)	//Draw horizontal lines
{
	for(int i=0;i<len;i++)
	{
		pixel(x+i,y,color)
	}
}

Stuff for You to do

  1. Of course, make a function to draw vertical lines.
  2. funtion(s) to draw square,rectancles.
  3. Do benchmark tests.(findout how fast the system is)

Ending Notes

Next edition, we will talk about double buffering and speeding up our drawing. Yea, blazing fast. Also you will get a few algorithms (line, circle) and some good stuff.

Have fun.

/*
	A Little help with the benchmarking.(C++)
	benchmark.h
	
	Notes:
	None too perfect,not even tested.This was just to give you an
	idea as to how you could go about making a benchmarking system
	Btw,It should work :).
	
	The class need not be used,only important and tested thing is the
	GetTickCountM13();Use it to make your own system.We will need this
	from part II.
*/

word *clock=(word *)0x0000046C;

double GetTickCoutM13()
{
	return (double)*clock;
}

Class Benchmark_system
{
	private:
	ofstream log;
	double tick;
	
	public:
	Benchmark_system();
	~Benchmark_system();
	void init(char*);
	void start();
	void end();
};

Benchmark_system::Benchmark_system()
{
	tick = 0;
}

Benchmark_system::~Benchmark_system()
{
	log.close();
}

void Benchmark_system::init(char* file)
{
	log.open(file,ios::trunc);
	log<<"\nBenchmarking  System 0.1, by Firenet\nhttp://xlock.hostcubix.com\n\n";
}

void start()
{
	tick = GetTickCoutM13();
}

void end()
{
	log<<"\nTicks taken: "<<(tick-GetTickCoutM13());
}

Firenet,
thanks for this post, i really have learnt from it, but please can u make it a little easier for beginners like me to catch with little ease?
thanks for ur cooperation and please send the other parts.
marvis

Well,I have done the second part but still doing the code examples.About making it easier,I dont really know,but just simply follow the stuff like the bios calls,like you followed cout<<.Later when you progress you will learn about them.No use confusing yourself now.

Then again maybe I might do a section covering bios calls and stuff very lightly and drop that assembler section.

Hey I am not a know it all,but learned it from here and there, and still learning.

(P.S:I forgot a small bit in the code, the byte datatype is an unsigned char)
(just add a typedef unsigned char byte;)

Dev-C++ wont do 13h without serious effort. I tried making it work for 2 years and found out something simple but fatally flawed and everyone MUST check this before doing mode 13h.

! COMPILE IN 16 BIT ! --> Dev-c++ is 32 bit and so requires MASSIVE amounts of asm before you can do anything in 13h and requires a bit of VBE code to get it working, if you have DJGPP however it can compile in 16 bit and so the code works fine. CHECK YOUR COMPLILERS i found out the hard way after a LONG time and a LOT of hard coding :(

typedef unsigned char bye;

byte *VGA=(byte *)0xA0000000L;        /* this points to video memory. */

it has an error saying: Illegal initializatioin

i'm using turbo c++ v1.01

the code:

unsigned char *VGA = (unsigned char *)0xA0000000L;

doesn't work for me, but this one does...

unsigned char far *VGA = (unsigned char far *)0xA0000000L;

why? what's with far?

unsigned char far *VGA = (unsigned char far *)0xA0000000L;

UNLESS you are compiling in 16 bit you CANNOT initialise a pointer to base VGA. Base VGA also is NOT 0xA000 in VBE systems (for 32bit ) as it varies and you need to get a pointer to it using asm statements. DJGPP is a classic one to use for 16 bit applications and you could use the pointer method, OR make use of the DOS functions which are MUCH better :)

FireNet a good way to benchmark using the tutorial you just wrote would be to time a complete screen fill of pixels followed by some lines. Make it complex enough to differentiate between computer speeds.

Hi,

I've tried your code with dev-C++ , winXP and when I compile i get the error storage size of regs is unknown.

Any suggestion?

Thanks,
erfan

Mode13h
			The Beginning of 3D/2D Graphics

Introduction
------------
Lots of people want to know how to do graphics but find most APIs like
OpenGL, DirectX etc too complex for a beginner, especially as they involve
GUI code which follows a different approach from the simple dos programming
Here, I will present a simple graphics mode, which can be easily used via dos
console programming

What I will be covering
----------------------

Part 1:Introduction to Mode13h			(this part)
	Part 2:Blazing:Lets speed up and burn		(algorithms,double buffering)
	Part 3:Dangers and Protection Systems		(wait and see)
	Part 4:Bitmap Loading and Animation		(woooooo!!!!)
	Part 5:Assembler,Let's go faster			(world of supersonics,C++ code)
	Part 6:Palette fun					(let the artist live)
	Part 7:Intro to 3D					(::::::::::::::::)
	Part 8:3D Star Fields					(weee!!!!)
	Part 9:Wrapup						(end,alternate techs)

Ok, this series will take sometime or so. Maybe weekly updates. We go
slow in this article. Part 2 will be larger and contain code.

History of Mode13h
-------------------
Here's a quote by a 3D programmer, Jacco Bikker (The Phantom):


So, anyway Mode13h is a graphics mode from the past, with a low resolution
so don't compare it with the latest stuff you see in the games. People do say
Mode13h is dead, it's not true, even though no game company makes games
in Mode13h anymore, it will serve as nice intro beginners, as it has done
before. And btw, lots of games are still being made in mode13h by hobbyists.
Let the coding begin.....

Tools of the Trade
------------------
Mode13h does not work in the standard console mode, so you will have to change
a few settings on you compiler. You will have to use DOS, Large memory model.
Don't worry too much. Just getting into mode13h or getting out of it is different
on different compilers the rest is quite the same.
The simplicity comes from the fact that you can write to the screen pixels as if
you were writing into a char array. It simple to set up x, y coordinate system in
Mode13h.

You can get TurboC for Borland's site for free. It is quite good if you want an easy
way to compile you programs. Remember to compile in the LARGE memory model!
To compile in Borland C: bcc -ml yourprogram.c

I would still recommend that you get a C++ compiler to compile your programs
as I will use stuff like classes later on. And it's much easy to code if you can
use the advanced features which C++ offers over C.

Compilers
---------

Borland C++ 	(My fav)
DJGPP		(Free,Very Good,Protected mode programs)
Dev-C++		(Dont know,heard somewhere it can do Mode13h)

Headers
--------
Keep all functions you get in a header files. That way you won't have to modify
all you programs to change something. Standard Headers to include:

#include <stdio.h>
#include <stdlib.h>
#include <dos.h>
#include <mem.h>

Borland (Should work on most compilers)
----------------------------------------

#define VIDEO_INT		0x10      /* the BIOS video interrupt. */
#define SET_MODE		0x00      /* BIOS func to set the video mode. */
#define MODE_13H		0x13      /* use to set 256-color mode. */
#define TEXT_MODE		0x03      /* use to set 80x25 text mode. */

#define SCREEN_WIDTH        320       /* width in pixels of mode 0x13 */
#define SCREEN_HEIGHT       200       /* height in pixels of mode 0x13 */

#define SCREEN_SIZE		SCREEN_WIDTH*SCREEN_HEIGHT

#define NUM_COLORS          256       /* number of colors in mode 0x13 */

byte *VGA=(byte *)0xA0000000L;        /* this points to video memory. */

void set_mode(byte mode)
{
	union REGS regs;
	
	regs.h.ah = SET_MODE;
	regs.h.al = mode;
	int86(VIDEO_INT, &regs, &regs);
}

Use it as:

set_mode(MODE_13H);		//to get into mode13h
set_mode(TEXT_MODE);	//to get back into the normal mode

DJGPP
------

void set_mode(byte mode)
{
	union REGS regs;
	
	regs.x.ax = mode;
	int86(VIDEO_INT, &regs, &regs);
}

Properties of Mode13h
----------------------
It's 320 pixels wide and 200 pixels high. There are 256 colors available, and their
values fit in 1 byte, i.e. the size of a char. I mentioned earlier that putting a pixel
was as simple as putting a char in an array. The VGA memory is 64000 (320 * 200)
bytes in size. Location(0,0) is at the top left hand corner of the screen. So Mode13h
is simple to implement and it is fast.

Drawing In Mode13h
--------------------
Ah the section you been all waiting for. Here we will just discuss putting a pixel
and clearing the screen. Later on I will talk about algorithms for drawing lines,circles,boxes
etc. They all require you to be able to put a pixel any way.

void pixel(int x,int y,byte color)	//Puts a pixel by writing directly to memory
{
	VGA[y*SCREEN_WIDTH+x]=color;
}

void clear(int color)
{
	memset(VGA,color,SCREEN_SIZE);
}

Really simple,eh? Look at the function for putting a pixel to the screen. We are simply
writing to the VGA memory as if it was just a char array.

Go ahead, try something,anything!You should be able to draw straight lines with
simple functions.

void line_horz(int x,int y,int len,byte color)	//Draw horizontal lines
{
	for(int i=0;i<len;i++)
	{
		pixel(x+i,y,color)
	}
}

Stuff for You to do
-------------------
1.Of course, make a function to draw vertical lines.
2.funtion(s) to draw square,rectancles.
3.Do benchmark tests.(findout how fast the system is)

Ending Notes
-------------
Next edition, we will talk about double buffering and speeding up our drawing. Yea,
blazing fast. Also you will get a few algorithms (line, circle) and some good stuff.
Have fun.

Aaron,(a.k.a. FireNet)
[url]http://xlock.hostcubix.com[/url]

[P.S You are most welcome to give suggestions or ask for help if you run into trouble,and please do give feedback]

[This is just to get you started with your compilers,next time will be real work]

i also tried the the codes in dev c++ and it doesn't work. use another compiler.

i also tried the the codes in dev c++ and it doesn't work. use another compiler.

I have not tried the code in DevC++, but there should be an option under traget settings to compile in large memory mode..........
1o0oBhP seems to know about it, I will ask him about it.

My advice, use DJGPP, and you can compile with no problems.And DJGPP is much better than using Borland too.DPMI (DOS Protected Mode Interface) sure has a lot of advantages one which making your life easier and the other protecting you from screwing up your comp ;)

Lost times of how many times i have said this (it is posted 3 or 4 times ABOVE people!) but just to refresh...

THE MODE 13H CODE USES 16 BIT ASSEMBLY COMMANDS (16 bit interrupts is the problem)

This WONT compile on a 32 bit compiler

DevC++ uses th mingw32 -> note the 32 -> compiler, so it wont work

Unless someone knows how to setup mingw32 for 16 bit mode you cant do it. I use DJGPP for the 16 bit anyway. This can also be linked into the DevC++ IDE so you can chose to compile with DJGPP or mingw32 although you may need to update DevC++ for this feature. DJGPP is FREE and was used to compile the first installment of ID's Quake series, so it's fair to assume it's a competent compiler. The Twin Compiler DevC++ trick is probably the best solution. Mode 13h is nice, but dont forget that graphics look prettier in more than 16 bits! If you want to go one step further from mode 13 h try VBE (VESA BIOS extensions). THIS IS 32 BIT code but is harder to setup. The Descent source code is a good reference for VBE as is google. Up from that there is Hardware accelerated graphics, which can get complicated in assembly, which is what DirectX and OpenGL are for! Hope this helps

This article has been dead for over six months. Start a new discussion instead.