It's aimed mostly at people who have a little bit of graphics knowledge, and have already got all the DC development kit set up, and know how to compile stuff. Anyway, here it goes. Any feedback would be appreciated.
Setting up a video mode
The first thing you should do when doing any kind of graphics programming is set up a video mode. On the Dreamcast, this isn't really that important - KallistiOS will automatically set the video hardware up into 640x480, 16 bit 60Hz mode. However, it's still a good idea to set the video mode manually, in case they change something.
This couldn't really be much simpler - we just need to call the function vid_set_mode, giving it our desired resolution and colour mode, and it'll do the rest:
Code: Select all
vid_set_mode(display_mode, pixel_mode);
Code: Select all
DM_320x240 320 x 240, 60Hz (or VGA)
DM_640x480 640 x 480, 60Hz (or VGA)
DM_800x608 800 x 608, 60Hz (or VGA)
DM_256x256 256 x 256, 60Hz (or VGA)
DM_768x480 768 x 480, 60Hz (or VGA)
DM_768x576 768 x 576, 60Hz (or VGA)
DM_640x480_PAL_IL 640 x 480, 50Hz
DM_256x256_PAL_IL 256 x 256, 50Hz
DM_768x480_PAL_IL 768 x 480, 50Hz
DM_768x576_PAL_IL 768 x 576, 50Hz
One rather strange omission that is worth taking note of - there is no 320x240 50Hz mode. I don't know why this is, because it's certainly not too difficult to do - it was just never included in KOS. If anyone really needs it, there is a patch to add that mode (DM_320x240_PAL) to KOS 1.2.0
pixel_mode can be one of:
Code: Select all
PM_RGB555 15-bit (xRRRRRGGGGGBBBBB)
PM_RGB565 16-bit (RRRRRGGGGGGBBBBB)
PM_RGB888 24-bit (RRRRRRRR GGGGGGGG BBBBBBBB)
So, to initialise the screen to 640x480 60Hz, in RGB565 colour mode, we'd use the following line:
Code: Select all
vid_set_mode(DM_640x480, PM_RGB565);
In RGB565 mode, the three colour components are packed into two bytes. The upper 5 bits contain the red data, the next 6 contain the green data, and the last 5 contain the blue data. Red and blue range from 0 to 31, and green ranges from 0 to 63. The reason that green is given more space is because the human eye is more sensitive to green.
Colours on a computer are typically represented using three bytes - one each for red, green and blue, ranging from 0 to 255. There's an easy way to convert from this format to the 16-bit RGB565 format that we need - we just use a macro:
Code: Select all
#define PACK_PIXEL(r, g, b) ( ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3) )
Drawing a single pixel
No matter how complex the graphics we're trying to make, no matter how many complex formulae and techniques we're using, no matter how long it's taken to draw our artwork, ALL 2D graphics come down to this - drawing a single pixel. For many things, where we need to plot multiple pixels at once, we can modify this routime to make it faster, but it'll still just be a variation on this. So how exactly do we draw a single pixel?
On the Dreamcast, the image currently being displayed on the screen is stored in an area of video memory called the framebuffer. The pixels are stored in order, from left to right, then from top to bottom, each as a single 16-bit value. So in order to find the location in the framebuffer of a single pixel, we can use this formula:
Code: Select all
location = x_coordinate + (y_coordinate * width)
Code: Select all
location = x + (y * 640)
Code: Select all
vram_s[x + (y * 640)]
Code: Select all
vram_s[x + (y * 640)] = PACK_PIXEL(r, g, b);
Now that all works fine, until we come across one additional problem - clipping. What happens if we were to try to write to negative X or Y coordinates, or write off the bottom or the right of the screen? We'd be writing either to the wrong part of the screen, or an area of memory that we aren't allowed to write to. We could cause all kinds of problems. So we just don't do it - we have to add some checking to make sure we aren't trying to draw outside the screen:
Code: Select all
if((x >= 0) && (x < 640) && (y >= 0) && (y < 480))
vram_s[x + (y * 640)] = PACK_PIXEL(r, g, b);
Code: Select all
#define DRAW_PIXEL(x, y, c) \
if((x >= 0) && (x < 640) && (y >= 0) && (y < 480)) \
vram_s[x + (y * 640)] = c;