Now that we've got ourselves an image uploaded, let's use it as a texture. If you've skipped ahead to this lesson without knowing how to upload images to the GS, go back to 9: Uploading Image data and come back when you're ready.
You'll be relieved to know that the hard work has already been done, in getting the textures uploaded in the first place. Now it's just a case of telling the GS how to use those textures to draw primitives. Follow the code below, then experiment with the settings to see what effect they have!
The necessary registers to set are TEXA, TEX0, and TEX1. If you haven't done so since you uploaded the textures, you need to access the TEXFLUSH register to let the GS know that new textures have arrived. Then, if you're using Mipmapping, you need to set the MIPTBP1 and MIPTBP2 registers. We'll ignore those for the moment, because I've never used Mipmapping before!
Study this piece of code:
qword_t reg; //as before
gifpacket_addgsdata(&gifpacket, GIF_SET_TAG(NLOOP(4), EOP(1), PRE(0), 0, GIF_PACKED, NREG(1)));
gifpacket_addgsdata(&gifpacket, AD_REG);
reg.ul64[0] = GS_SET_TEXFLUSH();
reg.ul64[1] = TEXFLUSH_REG;
gifpacket_addgspacked(&gifpacket, reg.ul128);
reg.ul64[0] = GS_SET_TEXA(0x80, TEXA_AEM_NORMAL, 0x80);
reg.ul64[1] = TEXA_REG;
gifpacket_addgspacked(&gifpacket, reg.ul128);
reg.ul64[0] = GS_SET_TEX0(0x118 << 5, 1, PSMCT32, 3, 3, TEX0_TCC_RGB, TEX0_TFX_MODULATE, 0, 0, 0, 0, 0);
reg.ul64[1] = TEX0_1_REG;
gifpacket_addgspacked(&gifpacket, reg.ul128);
reg.ul64[0] = GS_SET_TEX1(TEX1_LCM_K, 0, TEX1_MMAG_NEAREST, TEX1_MMIN_NEAREST, TEX1_MTBA_NOAUTO, 0, 0);
reg.ul64[1] = TEX1_1_REG;
gifpacket_addgspacked(&gifpacket, reg.ul128);
A couple of notes about the above code before I discuss the parameters. Firstly, GS_SET_TEXFLUSH takes no parameters! This is absolutely deliberate, the GS detects when something is written to it, it really doesn't matter what. Secondly, I'm writing to the TEX0_1 and TEX1_1 registers. These registers are the first we've met which have a context. It's possible to write a different set of texture settings to TEX0_2 and TEX1_2. How is it possible to tell the GS which context setting to use? That finally answers the question of what the CTXT field of the PRIM register is for. This enables you to switch between two different settings for rendering textures without constantly having to reload the TEX0 and TEX1 registers. Good, eh?
So, what's actually going into those registers? Well, TEXA is only used when Alpha blending, and it tells the GS what to do if you've asked for alpha blending, but the pixel format we're using has only 1 alpha bit. For now, we set the 2 alpha values to a moderate 0x80, and set the alpha calculation to a normal mode.
Then, on to the beast that is TEX0. There are lots of parameters here, the easiest to deal with is the five zeros at the end, you only need them if your texture is using a CLUT, i.e. is in a colour mode of 8-bits or less. Now, the first parameter is the start of the texture buffer (which hopefully you'll notice is the same as the address we used for the image upload in 9: Uploading Image data.) That's followed by the texture buffer width, which again is the same as used in the upload. The pixel storage mode is next, followed by the width and height of the actual texture. Hang on, it isn't 3x3, I thought it was 8x8?
The answer there, is that textures must have a width and a height that are both powers of 2. So, they can be 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, or 1024 texels high. It would be wasteful to store those numbers in the registers to denote width and height, so instead we notice that 8 is 2 to the power of 3, and store the 3 instead. Thus, if our texture was 16x16, height and width would each be 4. If the texture was 1024 x 4, the width would be 10, and the height would be 2, and so on.
Finally, we specify whether or not the texels are given an alpha component, and what texture function we're going to use. Then we move on to tex1, where we set lots of registers to do with level of detail settings and Mipmapping. The above setting will completely ignore the LOD calculations, but for more information, see P63 of the GS manual for Mipmapping, and P64 for LOD calculations. Look at pages 125 to 127 to see what goes into the TEX0 and TEX1 registers, or alternatively look up the comments in the defines.h file. (The updated one at my project page that is.)
That's got the texturing setting set up, all that's left is to specify texture co-ordinates in the primitives themselves. Before, we specified the RGBAQ and XYZ2 register settings, all we need to do is add a line (and updated the NLOOP and NREG fields of the GIFtag accordingly) to allow for a write to the ST register. STQ form a set of 2D homogeneous texture co-ordinates, which means that if you keep Q at 1.0f all the time, then (S,T) = (0.0f, 0.0f) denotes the top left corner of the texture, and (1.0f, 1.0f) denotes the bottom left corner of the texture.
Hopefully, you'll be able to figure out how to put together this and the last lesson for yourself, to upload a texture and use it to texture map a primitive or set of primitives. That's you're homework. Firstly, put two triangles together to make a square in the middle of the screen, and make their texture co-ordinates such that you see the whole texture. Then, change the texture co-ordinates to go past 1.0f, say to 2.0g, and see what happens. For a laugh, go up to 4.0f.
This is going to be the final standalone lesson for a moment, at least until I can think of something worthwhile to add. I have two directions to head in from here, to go back through the lessons so far and supply homework answers and sample code that uses them, and to go forwards and put all of our knowledge together to form a complete demo. First up will be an analysis of my demo dedicated to my girlfriend, entered into the DevStation 2003 competition. Bjt has graciously allowed me to dissect the source code for his VU game Plasmaroids, and that will be next up for dissection. Between those tasks, and writing my own demo for the competition, all the time between now and the deadline should be taken up! So, I hope it's been a worthwhile journey for you, and I want to see a demo entered from each of you reading this into the competition! Putting a hello in the .hlp file that makes part of your entry would really go down well too :)
Until next time, happy microcoding! Please see the comments and suggestions page to give me your feedback so far!
Prev - 9: Uploading Image data Next - 11: Putting it all together