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

h.s.fortuna@abertay.ac.uk