PowerVR Introduction
Introduction by BlackAura
This tutorial was written by BlueCrab and BlackAura. It covers using the PowerVR hardware of the Dreamcast to do pretty much the same thing as my first four 2D graphics tutorials, so it might be a good idea to have a look at those first - much of it, especially in the first part about Dreamcast video modes, still applies when using the PowerVR hardware. I also added a couple of comments to clarify the usage of some of the code. Those notes are written in italics. Anyway, over to BlueCrab...
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:
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!)
The Dreamcast uses display lists when it's drawing the screen, and it expects all the opaque drawing instructions to be in one part of the list, followed by all the transparent parts. So if something's going to be transparent, make sure you draw it into the transparent display list!
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.
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)); }
Since these lines can be transparent, you have to draw lines into the transparent display list. If you try to draw it into the opaque list, nothing will happen.
Vertical lines
Once again, the wonderful vertical line. Here's my method of drawing vertical lines:
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)); }
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.
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)
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:
line_tr(32, 48, 48, 32, 255, 255, 255, 255);
Will draw a line like tihs slash: / that is white, and completely opaque.
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.