PS2 Linux Programming
Processing UV Texture Coordinates With VU1
Introduction
This tutorial extends the previous tutorial and demonstrated the use of texture mapping with UV texture coordinates. The processing of the texture coordinates is undertaken by VU1 during the vertex transformation.
Example Code
The untransformed vertex data is stored in the static packet area as before. Each vertex now has UV texture coordinates, colour and position associated with it. The structure of the vertex data is given below:
VIFStaticDMA.AddVector(Vector4(0, 0, 0, 0)); // TexCoord (UV)
VIFStaticDMA.AddVector(Vector4(0x80, 0x80, 0x80, 0x80)); // Colour (RGBA)
VIFStaticDMA.AddVector(Vector4(-3.0f, 3.0f, 0.0f, 1.0f)); // Vert (xyzw)
VIFStaticDMA.AddVector(Vector4(256, 0, 0, 0)); // TexCoord (UV)
VIFStaticDMA.AddVector(Vector4(0x80, 0x80, 0x80, 0x80)); // Colour (RGBA)
VIFStaticDMA.AddVector(Vector4(3.0f, 3.0f, 0.0f, 1.0f)); // Vert (xyzw)
VIFStaticDMA.AddVector(Vector4(0, 256, 0, 0)); // TexCoord (UV)
VIFStaticDMA.AddVector(Vector4(0x80, 0x80, 0x80, 0x80)); // Colour (RGBA)
VIFStaticDMA.AddVector(Vector4(-3.0f,-3.0f, 0.0f, 1.0f)); // Vert (xyzw)
VIFStaticDMA.AddVector(Vector4(0, 256, 0, 0)); // TexCoord (UV)
VIFStaticDMA.AddVector(Vector4(0x80, 0x80, 0x80, 0x80)); // Colour (RGBA)
VIFStaticDMA.AddVector(Vector4(-3.0f,-3.0f, 0.0f, 1.0f)); // Vert (xyzw)
VIFStaticDMA.AddVector(Vector4(256, 0, 0, 0)); // TexCoord (UV)
VIFStaticDMA.AddVector(Vector4(0x80, 0x80, 0x80, 0x80)); // Colour (RGBA)
VIFStaticDMA.AddVector(Vector4(3.0f, 3.0f, 0.0f, 1.0f)); // Vert (xyzw)
VIFStaticDMA.AddVector(Vector4(256 ,256, 0, 0)); // TexCoord (UV)
VIFStaticDMA.AddVector(Vector4(0x80, 0x80, 0x80, 0x80)); // Colour (RGBA)
VIFStaticDMA.AddVector(Vector4(3.0f, -3.0f, 0.0f, 1.0f)); // Vert (xyzw)
Notice that all of the vertex data is now being specified in floating point format.
The VU1 code being used is repeated below from clarity. Much of it is similar to that used in the previous tutorial and only the additional extensions will be described here. (notice that some of the equates have changed to reflect the new structure of the vertex data).
; These are equates, they work exactly like #define in C
; We use them here for the locations of the various data in VU memory
ProjMat .equ 0
Scale .equ 4
GIFTag .equ 5
StartUV .equ 6
StartRGBA .equ 7
StartVert .equ 8
NumVerts .equ 6
; This is a file full of macros that comes with VCL
.include "vcl_sml.i"
; Tell VCL that we want to be able to use all vf, and vi registers
.init_vf_all
.init_vi_all
.syntax new
.vu
; This is the entry point, and is where execution will start on VU1
--enter
--endenter
iaddiu iVert, vi00, 0 ; Start vertex counter
iaddiu iVertPtr, vi00, 0 ; Point to the first vert
iaddiu iNumVerts, vi00, NumVerts ; Load the loop end condition
iaddiu iADC, vi00, 0 ; Load an ADC value (draw = true)
lq fScales, Scale(vi00) ; A scale vector that we will add
; to and scale the vertices by after
; projecting them
; Load the transformation matrix
lq fTransform[0], ProjMat+0(vi00)
lq fTransform[1], ProjMat+1(vi00)
lq fTransform[2], ProjMat+2(vi00)
lq fTransform[3], ProjMat+3(vi00)
loop: ; For each vertex
lq Vert, StartVert(iVertPtr) ; Load the vector (currently in object space
; and floating point format)
; Transform the vertex by the projection matrix we passed in (this is a macro from
; vcl_sml.i)
MatrixMultiplyVertex Vert, fTransform, Vert
div q, vf00[w], Vert[w] ; Work out 1.0f / w
mul.xyz Vert, Vert, q ; Project the vertex by dividing by W
mula.xyz acc, fScales, vf00[w] ; Move fScales to the accumulator
madd.xyz Vert, Vert, fScales ; (Vert = Vert * fScales + fScales)
ftoi4.xyz Vert, Vert ; Convert the vertex to 12:4 fixed point
sq.xyz Vert, StartVert(iVertPtr) ; Write the vertex back to VU memory
isw.w iADC, StartVert(iVertPtr) ; Set the ADC bit to 0 to draw vertex
lq.xy UV, StartUV(iVertPtr) ; Load the UV Texture coordinates
ftoi4.xy UV, UV ; Convert to 12:4 fixed point
sq.xy UV, StartUV(iVertPtr) ; Write back to VU Memory
lq RGBA, StartRGBA(iVertPtr) ; Load the RGBA colour
ftoi0 RGBA, RGBA ; Convert to integer
sq RGBA, StartRGBA(iVertPtr) ; Write back to VU Memory
iaddiu iVert, iVert, 1 ; Increment the vertex counter
iaddiu iVertPtr, iVertPtr, 3 ; Increment the vertex pointer
ibne iVert, iNumVerts, loop ; Branch back to "loop" label if
; iVert and iNumVerts are not equal
iaddiu iGIFTag, vi00, GIFTag ; Load the position of the giftag
xgkick iGIFTag ; and tell the PS2 to send that to the GS
--exit
--endexit
The first new section of code converts the UV texture coordinates into the correct format for the GIF.
lq.xy UV, StartUV(iVertPtr) ; Load the UV Texture coordinates
ftoi4.xy UV, UV ; Convert to 12:4 fixed point
sq.xy UV, StartUV(iVertPtr) ; Write back to VU Memory
It can be seen the UV texture coordinates are loaded from VU memory into a floating point register then converted into 12:4 fixed point as required by the PACKED format. The data is then written back into memory.
The second new piece of code converts the RGBA colour from the floating point values provided into the integer format required by the GIF.
lq RGBA, StartRGBA(iVertPtr) ; Load the RGBA colour
ftoi0 RGBA, RGBA ; Convert to integer
sq RGBA, StartRGBA(iVertPtr) ; Write back to VU Memory
Note that some changes have also been made to the format of the GIFTag to accommodate the use of UV texture coordinates and the extra register being used to specify each vertex.
Conclusions
This tutorial has demonstrated the use of UV texture coordinates. Look closely at the rotating quad and you will observe that the texture distorts as the quad rotates. This is called perspective texture distortion. The distortion can be fixed using STQ texture coordinates and this technique will be discussed in the next tutorial.
Dr Henry S Fortuna
University of Abertay Dundee