PS2 Linux Programming
Render Cube With STQ, Colour, Position
Introduction
This tutorial will illustrate the rendering of a simple 3 dimensional object. A cube will be rendered and will be used in future tutorials to demonstrate additional features such as movement, clipping and lighting.
Example code
The code used in this tutorial is very similar to that of the previous tutorial with the addition of the following features. Firstly the faces of a cube are specified with the AddCube() function which adds the vertex data of a cube to the static packet area. The cube is specified in terms of individual triangles. Notice that the cube does not have a top or a bottom face – try to add a top and bottom face to the cube.
void AddCube()
{
// Front face
VIFStaticDMA.AddVector(Vector4(0, 0, 1, 0)); // TexCoord (STQ)
VIFStaticDMA.AddVector(Vector4(0x80, 0x80, 0x80, 0x80)); // Colour (RGBA)
VIFStaticDMA.AddVector(Vector4(-1.0f, 1.0f, 1.0f, 1.0f)); // Vert (xyzw)
VIFStaticDMA.AddVector(Vector4(1, 0, 1, 0)); // TexCoord (STQ)
VIFStaticDMA.AddVector(Vector4(0x80, 0x80, 0x80, 0x80)); // Colour (RGBA)
VIFStaticDMA.AddVector(Vector4(1.0f, 1.0f, 1.0f, 1.0f)); // Vert (xyzw)
VIFStaticDMA.AddVector(Vector4(0, 1, 1, 0)); // TexCoord (STQ)
VIFStaticDMA.AddVector(Vector4(0x80, 0x80, 0x80, 0x80)); // Colour (RGBA)
VIFStaticDMA.AddVector(Vector4(-1.0f,-1.0f, 1.0f, 1.0f)); // Vert (xyzw)
VIFStaticDMA.AddVector(Vector4(0, 1, 1, 0)); // TexCoord (STQ)
VIFStaticDMA.AddVector(Vector4(0x80, 0x80, 0x80, 0x80)); // Colour (RGBA)
VIFStaticDMA.AddVector(Vector4(-1.0f,-1.0f, 1.0f, 1.0f)); // Vert (xyzw)
VIFStaticDMA.AddVector(Vector4(1, 0, 1, 0)); // TexCoord (STQ)
VIFStaticDMA.AddVector(Vector4(0x80, 0x80, 0x80, 0x80)); // Colour (RGBA)
VIFStaticDMA.AddVector(Vector4(1.0f, 1.0f, 1.0f, 1.0f)); // Vert (xyzw)
VIFStaticDMA.AddVector(Vector4(1 , 1, 1, 0)); // TexCoord (STQ)
VIFStaticDMA.AddVector(Vector4(0x80, 0x80, 0x80, 0x80)); // Colour (RGBA)
VIFStaticDMA.AddVector(Vector4(1.0f, -1.0f, 1.0f, 1.0f)); // Vert (xyzw)
// Right face
VIFStaticDMA.AddVector(Vector4(0, 0, 1, 0)); // TexCoord (STQ)
VIFStaticDMA.AddVector(Vector4(0x80, 0x80, 0x80, 0x80)); // Colour (RGBA)
VIFStaticDMA.AddVector(Vector4(1.0f, 1.0f, 1.0f, 1.0f)); // Vert (xyzw)
VIFStaticDMA.AddVector(Vector4(1, 0, 1, 0)); // TexCoord (STQ)
VIFStaticDMA.AddVector(Vector4(0x80, 0x80, 0x80, 0x80)); // Colour (RGBA)
VIFStaticDMA.AddVector(Vector4(1.0f, 1.0f, -1.0f, 1.0f)); // Vert (xyzw)
VIFStaticDMA.AddVector(Vector4(0, 1, 1, 0)); // TexCoord (STQ)
VIFStaticDMA.AddVector(Vector4(0x80, 0x80, 0x80, 0x80)); // Colour (RGBA)
VIFStaticDMA.AddVector(Vector4(1.0f,-1.0f, 1.0f, 1.0f)); // Vert (xyzw)
VIFStaticDMA.AddVector(Vector4(0, 1, 1, 0)); // TexCoord (STQ)
VIFStaticDMA.AddVector(Vector4(0x80, 0x80, 0x80, 0x80)); // Colour (RGBA)
VIFStaticDMA.AddVector(Vector4(1.0f,-1.0f, 1.0f, 1.0f)); // Vert (xyzw)
VIFStaticDMA.AddVector(Vector4(1, 0, 1, 0)); // TexCoord (STQ)
VIFStaticDMA.AddVector(Vector4(0x80, 0x80, 0x80, 0x80)); // Colour (RGBA)
VIFStaticDMA.AddVector(Vector4(1.0f, 1.0f, -1.0f, 1.0f)); // Vert (xyzw)
VIFStaticDMA.AddVector(Vector4(1 , 1, 1, 0)); // TexCoord (STQ)
VIFStaticDMA.AddVector(Vector4(0x80, 0x80, 0x80, 0x80)); // Colour (RGBA)
VIFStaticDMA.AddVector(Vector4(1.0f, -1.0f, -1.0f, 1.0f)); // Vert (xyzw)
// Back face
VIFStaticDMA.AddVector(Vector4(1, 0, 1, 0)); // TexCoord (STQ)
VIFStaticDMA.AddVector(Vector4(0x80, 0x80, 0x80, 0x80)); // Colour (RGBA)
VIFStaticDMA.AddVector(Vector4(-1.0f, 1.0f, -1.0f, 1.0f)); // Vert (xyzw)
VIFStaticDMA.AddVector(Vector4(1, 1, 1, 0)); // TexCoord (STQ)
VIFStaticDMA.AddVector(Vector4(0x80, 0x80, 0x80, 0x80)); // Colour (RGBA)
VIFStaticDMA.AddVector(Vector4(-1.0f,-1.0f, -1.0f, 1.0f)); // Vert (xyzw)
VIFStaticDMA.AddVector(Vector4(0, 0, 1, 0)); // TexCoord (STQ)
VIFStaticDMA.AddVector(Vector4(0x80, 0x80, 0x80, 0x80)); // Colour (RGBA)
VIFStaticDMA.AddVector(Vector4(1.0f, 1.0f, -1.0f, 1.0f)); // Vert (xyzw)
VIFStaticDMA.AddVector(Vector4(1, 1, 1, 0)); // TexCoord (STQ)
VIFStaticDMA.AddVector(Vector4(0x80, 0x80, 0x80, 0x80)); // Colour (RGBA)
VIFStaticDMA.AddVector(Vector4(-1.0f,-1.0f, -1.0f, 1.0f)); // Vert (xyzw)
VIFStaticDMA.AddVector(Vector4(0 , 1, 1, 0)); // TexCoord (STQ)
VIFStaticDMA.AddVector(Vector4(0x80, 0x80, 0x80, 0x80)); // Colour (RGBA)
VIFStaticDMA.AddVector(Vector4(1.0f, -1.0f, -1.0f, 1.0f)); // Vert (xyzw)
VIFStaticDMA.AddVector(Vector4(0, 0, 1, 0)); // TexCoord (STQ)
VIFStaticDMA.AddVector(Vector4(0x80, 0x80, 0x80, 0x80)); // Colour (RGBA)
VIFStaticDMA.AddVector(Vector4(1.0f, 1.0f, -1.0f, 1.0f)); // Vert (xyzw)
// Left face
VIFStaticDMA.AddVector(Vector4(1, 0, 1, 0)); // TexCoord (STQ)
VIFStaticDMA.AddVector(Vector4(0x80, 0x80, 0x80, 0x80)); // Colour (RGBA)
VIFStaticDMA.AddVector(Vector4(-1.0f, 1.0f, 1.0f, 1.0f)); // Vert (xyzw)
VIFStaticDMA.AddVector(Vector4(0, 0, 1, 0)); // TexCoord (STQ)
VIFStaticDMA.AddVector(Vector4(0x80, 0x80, 0x80, 0x80)); // Colour (RGBA)
VIFStaticDMA.AddVector(Vector4(-1.0f, 1.0f, -1.0f, 1.0f)); // Vert (xyzw)
VIFStaticDMA.AddVector(Vector4(1, 1, 1, 0)); // TexCoord (STQ)
VIFStaticDMA.AddVector(Vector4(0x80, 0x80, 0x80, 0x80)); // Colour (RGBA)
VIFStaticDMA.AddVector(Vector4(-1.0f,-1.0f, 1.0f, 1.0f)); // Vert (xyzw)
VIFStaticDMA.AddVector(Vector4(1, 1, 1, 0)); // TexCoord (STQ)
VIFStaticDMA.AddVector(Vector4(0x80, 0x80, 0x80, 0x80)); // Colour (RGBA)
VIFStaticDMA.AddVector(Vector4(-1.0f,-1.0f, 1.0f, 1.0f)); // Vert (xyzw)
VIFStaticDMA.AddVector(Vector4(0, 0, 1, 0)); // TexCoord (STQ)
VIFStaticDMA.AddVector(Vector4(0x80, 0x80, 0x80, 0x80)); // Colour (RGBA)
VIFStaticDMA.AddVector(Vector4(-1.0f, 1.0f, -1.0f, 1.0f)); // Vert (xyzw)
VIFStaticDMA.AddVector(Vector4(0 , 1, 1, 0)); // TexCoord (STQ)
VIFStaticDMA.AddVector(Vector4(0x80, 0x80, 0x80, 0x80)); // Colour (RGBA)
VIFStaticDMA.AddVector(Vector4(-1.0f, -1.0f, -1.0f, 1.0f)); // Vert (xyzw)
}
Within the main program, the cube is positioned at (0,0,-6) in world space and the camera is positioned at the origin looking directly down the negative world z axis. The number of vertices to process in now passed to the VU program in the w component of the scale vector as shown below:
Vector4(2048.0f, 2048.0f, ((float)0xFFFFFF) / 32.0f, *((float *)&iVerts))
iVerts is the number of vertices to process. *((float *)&iVerts) “fools” the compiler by putting the integer value for iVerts into the floating point w component of the vector.
The only change to the VU code is that the number of vertices to be processed is now loaded for the w component of the scale vector, rather from a .equ statement. This is achieved with the following code which is executed during the initialisation phase:
ilw.w iNumVerts, NumVertsMem(vi00) ; We now load the number of verts from
; memory instead of using a .equ
On execution of the program, a textured cube is displayed on screen which rotates around it’s local Y-axis.
Conclusions
This tutorial has demonstrated the rendering of a solid 3D object. The number of vertices to be processed by the VU has been passes from the main program to the VU within the packet data.
Dr Henry S Fortuna
University of Abertay Dundee