2D graphics / KOS tutorials

If you have any questions on programming, this is the place to ask them, whether you're a newbie or an experienced programmer. Discussion on programming in general is also welcome. We will help you with programming homework, but we will not do your work for you! Any porting requests must be made in Developmental Ideas.
BlackAura
DC Developer
DC Developer
Posts: 9951
https://www.artistsworkshop.eu/meble-kuchenne-na-wymiar-warszawa-gdzie-zamowic/
Joined: Sun Dec 30, 2001 9:02 am
Has thanked: 0
Been thanked: 1 time

2D graphics / KOS tutorials

Post by BlackAura »

This is the start of a fairly simple graphics tutorial, aimed at the Dreamcast. I'll probably do a better version later, with a couple of examples, diagrams, decent formatting, and stuff like that, but this is just a quick draft of the first part.

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);
display_mode can be one of:

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
The 60Hz modes will always be 60Hz, even on a PAL Dreamcast. The 50Hz modes will always be 50Hz, even on an NTSC Dreamcast. While most PAL TVs can display a 60Hz signal, some can not, and virtually no NTSC TVs can display a 50Hz signal. So it's usually safe to use the 60Hz modes, but you might want to put in an option to use 50Hz on PAL Dreamcasts. I'll go into more detail on that later.

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)
The best mode to use on the Dreamcast is RGB565 - it provides fairly good colour quality, it's significantly faster than 24-bit mode, and it uses less memory. Just trust me on this - it's the best mode to use for pretty much everything that we're going to be doing.

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);
RGB565 colour mode
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) )
That macro uses two AND operations to mask out the unnecessary bits of the red and green components, bit shifts the values to get them into the correct place, and ORs them together. For some strange reason, that macro isn't included anywhere in KOS.

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)
So, assuming a resolution of 640x480, we can do this:

Code: Select all

location = x + (y * 640)
Now all we need to know is where the framebuffer is. KOS provides us with a pointer to this location, named vram_s. So all we need to do the get the location in memory of a single pixel on the screen is:

Code: Select all

vram_s[x + (y * 640)]
From there, it should be easy to see how to draw a single pixel - we just need to set the value of that location in memory to the colour we want the pixel to be:

Code: Select all

vram_s[x + (y * 640)] = PACK_PIXEL(r, g, b);
Clipping
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);
Now we have a safe, effective way to draw a single pixel on the screen. Of course, it'd be more convenient as a macro:

Code: Select all

#define DRAW_PIXEL(x, y, c) \
	if((x >= 0) && (x < 640) && (y >= 0) && (y < 480)) \
		vram_s[x + (y * 640)] = c;
Now, to draw a single pixel, we can just work out the colour we want to set it to using PACK_PIXEL, and the use DRAW_PIXEL to draw it.
Last edited by BlackAura on Wed Aug 20, 2003 12:22 am, edited 3 times in total.
These users thanked the author BlackAura for the post:
Kirill()Suxarev16
User avatar
finite
Insane DCEmu
Insane DCEmu
Posts: 223
Joined: Sun Jun 15, 2003 12:00 am
Location: melb.vic.au
Has thanked: 0
Been thanked: 0
Contact:

Post by finite »

Thanks a bunch, I'll be sure to save it for future reference. Just a question though, when running the PAL resolutions: would they have black borders like some of the DC PAL games? They all have the same no. pixels as the 60Hz equivalents, and as PAL has more vertical scan lines than NTSC, I'm assuming this will give those ugly black borders.
- Interesting.
BlackAura
DC Developer
DC Developer
Posts: 9951
Joined: Sun Dec 30, 2001 9:02 am
Has thanked: 0
Been thanked: 1 time

Post by BlackAura »

You do get the black borders at the top and bottom of the screen, I'm afraid. It seems to be part of the DC's hardware. The screen resolutions are otherwise identical - same number of scanlines, same number of pixels per scanline. It might be possible to create a slightly hacked graphics mode that didn't have the borders, and thus had a higher resolution, but I don't know how well the rest of KOS would handle it, especially the stuff to handle the PVR.

So I think the best way is to detect a PAL console, and pop up a "60Hz or 50Hz" screen, like most commercial games do. It's not really that hard to code, and it's the only way that you can let everybody use the program, while still letting PAL users see it in full screen.
User avatar
finite
Insane DCEmu
Insane DCEmu
Posts: 223
Joined: Sun Jun 15, 2003 12:00 am
Location: melb.vic.au
Has thanked: 0
Been thanked: 0
Contact:

Post by finite »

Strange, could have sworn some of my DC games ran fullscreen at 50Hz. Maybe it's only certain resolutions? *shrug* I'll have a look later. I'll be opting for a 60/50 selection screen in any case.
- Interesting.
Ian Micheal
Soul Sold for DCEmu
Soul Sold for DCEmu
Posts: 4865
Joined: Fri Jul 11, 2003 9:56 pm
Has thanked: 2 times
Been thanked: 4 times

Post by Ian Micheal »

Rather neat if any one wants i could do the same thing in SDL.
Dreamcast forever!!!
BlackAura
DC Developer
DC Developer
Posts: 9951
Joined: Sun Dec 30, 2001 9:02 am
Has thanked: 0
Been thanked: 1 time

Post by BlackAura »

As I said, there might be a tweaked resolution that doesn't have borders - as with most things that connect to a TV instead of a monitor, you have a lot of control over the way the signal's generated. But if there is such a resolution, KOS doesn't have it.

IM(r)eaper - Go for it. The more, the merrier.

I'm currently writing code for lines (horizontal, vertical, and arbitrary angled lines) and circles (filled and hollow), along with boxes (filled and hollow). The next tutorial will probably cover that lot. The hollow circles and the arbitrary angle lines are the hardest to do - they others are basically just simple loops combined with pixel plotting.
User avatar
finite
Insane DCEmu
Insane DCEmu
Posts: 223
Joined: Sun Jun 15, 2003 12:00 am
Location: melb.vic.au
Has thanked: 0
Been thanked: 0
Contact:

Post by finite »

I'm guessing you can't create hardware anti-aliased vectors on the DC? I suppose it shouldn't be too hard to write a basic software AA algorithm. Eh, nevermind me, just thinking out loud again.
- Interesting.
BlackAura
DC Developer
DC Developer
Posts: 9951
Joined: Sun Dec 30, 2001 9:02 am
Has thanked: 0
Been thanked: 1 time

Post by BlackAura »

I think you can actually, but you need to be rendering everything using the PVR hardware. And I don't know how to enable hardware AA on the DC. It can do it, I just don't know how. Oh wait... the PVR hardware can't actually do lines - you have to fake them using triangles. Should still be possible though.

I think that you could do anti-aliased lines in software. It shouldn't really be that hard - it's basically an extension of standard line drawing. But you'd have to be using double-buffering of some kind.
Ian Micheal
Soul Sold for DCEmu
Soul Sold for DCEmu
Posts: 4865
Joined: Fri Jul 11, 2003 9:56 pm
Has thanked: 2 times
Been thanked: 4 times

Post by Ian Micheal »

Ok With SDL ill try do the same thing as you in kos but with it. just working on my port having problems patching sdl when i get it fixed ill start writting the tuts. after that.
Dreamcast forever!!!
BlackAura
DC Developer
DC Developer
Posts: 9951
Joined: Sun Dec 30, 2001 9:02 am
Has thanked: 0
Been thanked: 1 time

Post by BlackAura »

Line drawing's nearly finished - horizontal and vertical lines are done, and I'm working on the general line drawing, using Bresenham's algorithm. It's not the fastest, but it's at least comprehensible. And, as an added bonus, I found an anti-aliased variant of it which I can use to do anti-aliased vectors. But that'll have to wait until I get to blending, which should be a real pain in the backside in 16-bit mode.

So, without further ado...

Horizontal Lines
Drawing pixels is probably getting kinda boring by now, so let's draw something more interesting. As a start, we'll draw a simple horizontal line, which is about the simplest shape you can do. A line is basically a load of pixels, arranged in a line. So they shouldn't be that hard to draw - we just need to draw a load of pixels in a line:

Code: Select all

void draw_hline(int x1, int x2, int y, uint16 c)
{
	int cx;
		// Draw the line
	for(cx = x1; cx <= x2; cx++)
		DRAW_PIXEL(cx, y, c);
}
One problem there - what if x2 is smaller than x1? The line won't be drawn. So, if x2 is smaller than x1, we should swap them around:

Code: Select all

void draw_hline(int x1, int x2, int y, uint16 c)
{
	int cx;

	// Swap x1 and x2 if necessary
	if(x1 > x2)
	{
		cx = x1;
		x1 = x2;
		x2 = cx;
	}

	// Draw the line
	for(cx = x1; cx <= x2; cx++)
		DRAW_PIXEL(cx, y, c);
}
And that's it... Or is it? The more observant of you may notice that this code is actually very bloated. Remember that DRAW_PIXEL is checking if the pixel is on the screen for every pixel we draw. But, since this is just a horizontal line, we know that if both points are on the screen, the whole line is on the screen. If the line's off the screen entirely, we can just ignore it. If the line is on the screen, we can tell how much of the line is on the screen, and adjust the left and right coordinates appropriately. So we can do this:

Code: Select all

void draw_hline(int x1, int x2, int y, uint16 c)
{
	int cx;

	// Swap x1 and x2 if necessary
	if(x1 > x2)
	{
		cx = x1;
		x1 = x2;
		x2 = cx;
	}

	// Don't bother if the line's off the screen
	if( (y < 0) || (y > 479) || (x1 > 639) || (x2 < 0) )
		return;

	// Clip the line to the edge of the screen
	if(x1 < 0)
		x1 = 0;
	if(x2 > 639)
		x2 = 639;

	// Draw the line
	for(cx = x1; cx <= x2; cx++)
		vram_s[cx + (y*640)] = c;
}
That's a bit better, but there's still one problem - for each pixel, we're doing y*640, which will be the same for each and every pixel. In face, since we're drawing from left to right, each pixel will be next to the previous pixel. So we can do something like this:

Code: Select all

void draw_hline(int x1, int x2, int y, uint16 c)
{
	int cx;
	uint16 *line_buffer;

	// Swap x1 and x2 if necessary
	if(x1 > x2)
	{
		cx = x1;
		x1 = x2;
		x2 = cx;
	}

	// Don't bother if the line's off the screen
	if( (y < 0) || (y > 479) || (x1 > 639) || (x2 < 0) )
		return;

	// Clip the line to the edge of the screen
	if(x1 < 0)
		x1 = 0;
	if(x2 > 639)
		x2 = 639;

	// Set line_buffer to the beginning of the line
	line_buffer = vram_s + x1 + (y * 640);

	// Draw the line
	for(cx = x1; cx <= x2; cx++)
		*line_buffer++ = c;
}
That probably won't make a lot of sense unless you know something about pointers in C - line_buffer is set to the location of the first pixel of the line we're drawing. We then draw the pixel, and increment line_buffer by one pixel, so it now points to the location of the next pixel.

A horizontal line is actually far more useful than it would first appear. A horizontal line is very useful for drawing filled shapes - you just draw a horizontal line from the left-most point of the shape on a given line, to the right-most point of the shape. Then you repeat that for each line. That's how most software rendered 3D games fill polygons.

Vertical Lines
These are pretty much exactly the same as horizontal lines. However, we're now drawing down instead of right. Basically, we swap the X and Y coordinates around, and we skip 640 pixels instead of 1 - we jump down one pixel instead of right one pixel:

Code: Select all

void draw_vline(int x, int y1, int y2, uint16 c)
{
	int cy;
	uint16 *line_buffer;

	// Swap y1 and y2 if necessary
	if(y1 > y2)
	{
		cy = y1;
		y1 = y2;
		y2 = cy;
	}

	// Don't bother if the line's off the screen
	if( (x < 0) || (x > 639) || (y1 > 479) || (y2 < 0) )
		return;

	// Clip the line to the edge of the screen
	if(y1 < 0)
		y1 = 0;
	if(y2 > 479)
		y2 = 479;

	// Set line_buffer to the beginning of the line
	line_buffer = vram_s + x + (y1 * 640);

	// Draw the line
	for(cy = y1; cy <= y2; cy++)
	{
		*line_buffer = c;
		line_buffer += 640;
	}
}
Hollow Boxes
Now that we have the code to draw horizontal and vertical lines, drawing a hollow box should be very easy - we just draw tow horizontal lines, and two vertical lines:

Code: Select all

void draw_hbox(int x1, int y1, int x2, int y2, uint16 c)
{
	draw_hline(x1, x2, y1, c);
	draw_hline(x1, x2, y2, c);
	draw_vline(x1, y1, y2, c);
	draw_vline(x2, y1, y2, c);
}
Filled Boxes
All we do here is draw a series of horizontal lines, which will fill an area of the screen. We know what the left and right coordinates of the box are on each scanline, and we know how far up and down the box goes. So we can just do:

Code: Select all

void draw_fbox(int x1, int y1, int x2, int y2, uint16 c)
{
	int cy;
	for(cy = y1; cy <= y2; cy++)
		draw_hline(x1, x2, cy, c);
}
User avatar
BlueCrab
The Crabby Overlord
The Crabby Overlord
Posts: 5652
Joined: Mon May 27, 2002 11:31 am
Location: Sailing the Skies of Arcadia
Has thanked: 9 times
Been thanked: 69 times
Contact:

Post by BlueCrab »

I figured I'd throw some knowledge in the ring, especially since I just started working with PVR code in my game again. So, without further ado, a PVRized version of the lines tutorial.

Initialization:

Just a few little differences between regular, and PVR init. First of all, set your video mode, like BlackAura stated above. Immediately after this, you need to initialize the PVR, if you'd like to use it. This can be done most simply like this:

Code: Select all

pvr_init_defaults();
This will set up the PVR with reasonable defaults for all settings. I've never had to muck around with the settings, and I find the defaults to be pretty good.

Scene Drawing:

When using the PVR, one needs to tell it when beginning a new scene, and what polygon lists will be used. This is done as follows. (You also must close everything when you're done with it!)

Code: Select all

pvr_scene_begin();
pvr_list_begin(PVR_LIST_OP_POLY);
// Do opaque drawing here!
pvr_list_finish();
pvr_list_begin(PVR_LIST_TR_POLY);
// Do Translucent drawing here
pvr_list_finish();
pvr_scene_finish();
Horizontal Lines:

Horizontal lines are fun, aren't they! Anyway, here's a method I use to draw horizontal lines of any color on the screen.

Code: Select all

void hline_tr(float x1, float x2, float y, uint8 a, uint8 r, uint8 g, uint8 b)	{
	pvr_poly_hdr_t hdr;
	pvr_poly_cxt_t cxt;
	pvr_vertex_t vert;
	float cx;
	if(x1 > x2)	{
		cx = x1;
		x1 = x2;
		x2 = cx;
	}

	pvr_poly_cxt_col(&cxt, PVR_LIST_TR_POLY);
	pvr_poly_compile(&hdr, &cxt);

	pvr_prim(&hdr, sizeof(hdr));
	vert.flags = PVR_CMD_VERTEX;
	vert.x = x1;
	vert.y = y + 1;
	vert.z = 5.0f;
	vert.u = 0;
	vert.v = 0;
	vert.argb = PVR_PACK_COLOR(a / 255, r / 255, g / 255, b / 255);
	vert.oargb = 0;
	pvr_prim(&vert, sizeof(vert));

	vert.y = y;
	pvr_prim(&vert, sizeof(vert));

	vert.x = x2;
	vert.y = y + 1;
	pvr_prim(&vert, sizeof(vert));

	vert.flags = PVR_CMD_VERTEX_EOL;
	vert.y = y;
	pvr_prim(&vert, sizeof(vert));
}
Simple enough, eh? For this function, you can pass in values between 0 and 255 for each color (r, g, and b) and how opaque it is (a).

Vertical Lines:

Once again, the wonderful vertical line. Here's my method of drawing vertical lines:

Code: Select all

void vline_tr(float x, float y1, float y2, uint8 a, uint8 r, uint8 g, uint8 b)	{
	pvr_poly_hdr_t hdr;
	pvr_poly_cxt_t cxt;
	pvr_vertex_t vert;
	float cy;
	if(y1 > y2)	{
		cy = y1;
		y1 = y2;
		y2 = cy;
	}

	pvr_poly_cxt_col(&cxt, PVR_LIST_TR_POLY);
	pvr_poly_compile(&hdr, &cxt);

	pvr_prim(&hdr, sizeof(hdr));
	vert.flags = PVR_CMD_VERTEX;
	vert.x = x /* - 1 */;
	vert.y = y2;
	vert.z = 5.0f;
	vert.u = 0;
	vert.v = 0;
	vert.argb = PVR_PACK_COLOR(a / 255, r / 255, g / 255, b / 255);
	vert.oargb = 0;
	pvr_prim(&vert, sizeof(vert));

	vert.y = y1;
	pvr_prim(&vert, sizeof(vert));

	vert.x = x + 1;
	vert.y = y2;
	pvr_prim(&vert, sizeof(vert));

	vert.flags = PVR_CMD_VERTEX_EOL;
	vert.y = y1;
	pvr_prim(&vert, sizeof(vert));
}
Arrows (AKA Triangles):

Just a short note about triangles. All verteces need to be submitted clockwise. The same goes for the diagonal line function later. These functions have no protection for if someone submits them in the wrong order, and most likely, there will be no triangle on the screen if you do.

Code: Select all

void arrow(float x1, float y1, float x2, float y2, float x3, float y3, uint8 a, uint8 r, uint8 g, uint8 b)	{
	pvr_poly_hdr_t hdr;
	pvr_poly_cxt_t cxt;
	pvr_vertex_t vert;

	pvr_poly_cxt_col(&cxt, PVR_LIST_TR_POLY);
	pvr_poly_compile(&hdr, &cxt);
	pvr_prim(&hdr, sizeof(hdr));

	vert.flags = PVR_CMD_VERTEX;
	vert.x = x1;
	vert.y = y1;
	vert.z = 5.0f;
	vert.u = 0;
	vert.v = 0;
	vert.argb = PVR_PACK_COLOR(a / 255, r / 255, g / 255, b / 255);
	vert.oargb = 0;
	pvr_prim(&vert, sizeof(vert));

	vert.x = x2;
	vert.y = y2;
	pvr_prim(&vert, sizeof(vert));

	vert.flags = PVR_CMD_VERTEX_EOL;
	vert.x = x3;
	vert.y = y3;
	pvr_prim(&vert, sizeof(vert));
}
Diagonal Lines:

The last thing I'll be covering, at least today, is diagonal lines. Remember Coordinates must be put in in a certain order. (see note below code)

Code: Select all

void line_tr(float x1, float y1, float x2, float y2, uint8 a, uint8 r, uint8 g, uint8 b)	{
	pvr_poly_hdr_t hdr;
	pvr_poly_cxt_t cxt;
	pvr_vertex_t vert;

	pvr_poly_cxt_col(&cxt, PVR_LIST_TR_POLY);
	pvr_poly_compile(&hdr, &cxt);
	pvr_prim(&hdr, sizeof(hdr));

	vert.flags = PVR_CMD_VERTEX;
	vert.x = x1;
	vert.y = y1;
	vert.z = 5.0f;
	vert.u = 0;
	vert.v = 0;
	vert.argb = PVR_PACK_COLOR(a / 255, r / 255, g / 255, b / 255);
	vert.oargb = 0;
	pvr_prim(&vert, sizeof(vert));

	vert.x = x2;
	vert.y = y2;
	pvr_prim(&vert, sizeof(vert));

	vert.x = x1 + 1;
	vert.y = y1;
	pvr_prim(&vert, sizeof(vert));

	vert.flags = PVR_CMD_VERTEX_EOL;
	vert.x = x2 + 1;
	vert.y = y2;
	pvr_prim(&vert, sizeof(vert));
}
This diagonal line code should be able to handle any kind of line, I just use the horizontal and vertical line routines above. Anyway, here's the note I mentioned above:

Code: Select all

line_tr(32, 48, 48, 32, 255, 255, 255, 255);
Will draw a line like this slash: / that is white, and completely opaque.

Code: Select all

line_tr(48, 288, 32, 272, 255, 255, 255, 255);
Will draw a completely opaque, white line that looks similar to this slash: \

That's all for today, let me know if you see any improvements, or problems with this tutorial lesson.
Last edited by BlueCrab on Thu Aug 07, 2003 9:48 am, edited 1 time in total.
Phantom
DC Developer
DC Developer
Posts: 1753
Joined: Thu Jan 16, 2003 4:01 am
Location: The Netherlands
Has thanked: 0
Been thanked: 0
Contact:

Re: 2D graphics tutorial

Post by Phantom »

BlackAura wrote: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
It's indeed weird that that mode was missing. Anyway, I talked about that with Mekanaizer on #dreamcastdev a few months ago. He had a text file which explained the video registers and he submitted a patch to add that mode. It's now included in CVS, so it will be included in KOS 1.2.1 as well when it comes out.

But I always use CVS anyway. ;)
User avatar
az_bont
Administrator
Administrator
Posts: 13567
Joined: Sat Mar 09, 2002 8:35 am
Location: Swansea, Wales
Has thanked: 0
Been thanked: 0
Contact:

Re: 2D graphics tutorial

Post by az_bont »

BlackAura wrote:While most PAL TVs can display a 50Hz signal, some can not, and virtually no NTSC TVs can display a 50Hz signal.
Shouldn't that bit say 60Hz? 50Hz is the PAL standard, and so all PAL TVs will display 50Hz, with most displaying 60Hz.
BlackAura
DC Developer
DC Developer
Posts: 9951
Joined: Sun Dec 30, 2001 9:02 am
Has thanked: 0
Been thanked: 1 time

Post by BlackAura »

Yeah, it should... I'll just go back and edit it. Thanks for pointing that out.

BlueCrab - Nice job.
User avatar
BlueCrab
The Crabby Overlord
The Crabby Overlord
Posts: 5652
Joined: Mon May 27, 2002 11:31 am
Location: Sailing the Skies of Arcadia
Has thanked: 9 times
Been thanked: 69 times
Contact:

Post by BlueCrab »

Thanks, thought it'd make a good addition when I saw this topic.
BlackAura
DC Developer
DC Developer
Posts: 9951
Joined: Sun Dec 30, 2001 9:02 am
Has thanked: 0
Been thanked: 1 time

Post by BlackAura »

Those lines are being draws as a quad, yes? It might have been a better idea to cover drawing triangles first, since they're slightly simpler than quads. And, while you're at it, you could have done a filled rectangle quite simply too.

I've been converting the stuff I've got into HTML, writing some examples for each tutorial (up to part 4 now) and preparing to put it up as a webpage. D'ya mind if I put that up too?
User avatar
BlueCrab
The Crabby Overlord
The Crabby Overlord
Posts: 5652
Joined: Mon May 27, 2002 11:31 am
Location: Sailing the Skies of Arcadia
Has thanked: 9 times
Been thanked: 69 times
Contact:

Post by BlueCrab »

Well, I have drawing triangles in there too! I'll add some stuff with more general filled quads in a bit. And sure, you can include the tutorial, just make sure I get the proper credit, ok? And feel free to rearrange the stuff in the HTML page...
User avatar
BlueCrab
The Crabby Overlord
The Crabby Overlord
Posts: 5652
Joined: Mon May 27, 2002 11:31 am
Location: Sailing the Skies of Arcadia
Has thanked: 9 times
Been thanked: 69 times
Contact:

Post by BlueCrab »

Drawing Filled Rectangles with the PVR:

Drawing filled rectangles with the PVR is just as easy as drawing those lines earlier.

Code: Select all

void frect_tr(float x1, float y1, float x2, float y2, uint8 a, uint8 r, uint8 g, uint8 b)	{
	pvr_poly_hdr_t hdr;
	pvr_poly_cxt_t cxt;
	pvr_vertex_t vert;
	float cx, cy;
	if(x1 > x2)	{
		cx = x1;
		x1 = x2;
		x2 = cx;
	}
	if(y1 > y2)	{
		cy = y1;
		y1 = y2;
		y2 = cy;
	}

	pvr_poly_cxt_col(&cxt, PVR_LIST_OP_POLY);
	pvr_poly_compile(&hdr, &cxt);

	pvr_prim(&hdr, sizeof(hdr));
	vert.flags = PVR_CMD_VERTEX;
	vert.x = x1;
	vert.y = y2;
	vert.z = 5.0f;
	vert.u = 0.0f;
	vert.v = 0.0f;
	vert.argb = PVR_PACK_COLOR(a / 255, r / 255, g / 255, b / 255);
	vert.oargb = 0;
	pvr_prim(&vert, sizeof(vert));

	vert.y = y1;
	pvr_prim(&vert, sizeof(vert));

	vert.x = x2;
	vert.y = y2;
	pvr_prim(&vert, sizeof(vert));

	vert.flags = PVR_CMD_VERTEX_EOL;
	vert.y = y1;
	pvr_prim(&vert, sizeof(vert));
}
And that's how you draw filled rectangles with the PVR.
BlackAura
DC Developer
DC Developer
Posts: 9951
Joined: Sun Dec 30, 2001 9:02 am
Has thanked: 0
Been thanked: 1 time

Post by BlackAura »

Cool, thanks! I'll put it up there when I get around to it - I'm still working on converting my own ones and writing some examples to go with them. Line clipping is proving to be more of a pain in the neck than I thought...
Pyrosurfer
DCEmu Nutter
DCEmu Nutter
Posts: 964
Joined: Sun Aug 11, 2002 5:07 pm
Has thanked: 0
Been thanked: 0

Post by Pyrosurfer »

I am using visual c++ and kos 1.9, and the following "vram_s[x + (y * 640)] = PACK_PIXEL(r, g, b); " would not work for me. Is this method not supported in 1.9?
Post Reply