Believe it or not, the simplest way to create a data file, once you know what you're going to put in it, is to use a hex editor. Textpad on Windows can do it, and I'm reliably informed that emacs on the PS2Linux kit can too.
However, putting something meaningful in the data file can be a little trickier. You can use any means to make your data file generation easier, the basic sample happens to use a C program. To start with, we'll explore what we can change in the data file of the basic sample, so we'll stick with editing that C program. I'm just trying to impress on you that this decision is arbitrary... I'll show other ways of creating the file later.
(Note: This lesson is about creating a data file containing a GIFpacket ready to be drawn. If you need more knowledge on GIFtags and GIFpackets themselves, see 2: A brief overview of the basic sample)
Load up gen_data.c in your favourite text editor. The comments at the start of the file detail the GIFpacket we're going to create, but I'd just like to point out that when we're actually in the VU code, we normally refer to the first QWord of memory as QW0, not QW1. Therefore, the last QWord of memory is QW1023.
All the program does is open a file to write to and write out a GIFpacket, consisting of a single GIFtag followed by 3 vertices worth of RGBAQ and XYZ2 information, followed by as many zeroes as necessary to make a 16kb file. 16kb incidentally is the size of VU data memory. Half the trick of this competition is to get what you want to do done, in only 16kb of data memory!
The qword_t typedef is quite interesting, let's look at that.
(Thanks to jse for pointing out a small error in the basic sample code... u_long isn't actually 64 bits! To fix that, just change that u_long to a u_long64 as above, which I believe is what the programmer originally intended. Alternatively, grab my fixed gen_data.c from my project page. According to Hikey, u_long is 64 bits on the native PS2, but PS2Linux makes it 32 bits - just some trivia for those interested)
If you need to know more about unions, go to your favourite C programming book or web site. What this qword_t typedef does is allow us to reference a QWord as one big 128-bit unsigned integer, or 2 64-bit unsigned integers, or 4 32-bit unsigned integers, or 4 32-bit floats. Different uses of QWords require different references, but we're mainly concerned with 32-bit breakdowns, as the VU references each QWord as 4 32-bit fields, called x, y, z, and w. More on that in 4: Making your code file.
The gifpacket_* functions and gifpacket_t type are all defined in packet.c and packet.h, and I strongly suggest that you don't modify these files, they do their job perfectly well.
Writing out the data
Firstly, we initialise our gifpacket_t with gifpacket_init(). Then we create the GIFtag we described in 2: A brief overview of the basic sample. Note that several macros are defined for us to make this job easier. Our end result has to be a 128-bit GIFtag, but we can use the GS_SET_TAG macro to set up the first 64 bits of the GIFtag (everything except the REGS field), GS_SET_PRIM to set up the PRIM field in the GIFtag, and finally fill in the REGS field ourselves.
Once upon a time, looking around various projects, I came across a more complete defines.h file and though, wow, that'd be useful someday! So, I copied it to my home directory, and it's now available from my project page. Unfortunately, I can't remember which project it came from in the first place! Download the new defines.h file, and it will come in handy as we expand the basic sample in all sorts of new directions. It's also more fully commented...
After the GIFtag comes the colour and co-ordinate information. This is where the qword_t type comes in handy. 2 qword_t temporary variables are set, called colour and vertex. Now, we can split a colour down into 4 parts, RGBA, and we can split a qword_t into 4 32-bit unsigned integers. Guess what? color.ui32[0] refers to the red component of colour, color.ui32[1] refers to the green component, color.ui32[2] refers to the blue component, and color.ui32[3] to the A component (Don't worry about the Q part, there's some trickery going on to get the Q co-ordinate to the right place, but we don't deal with texture mapping yet, so we don't need to worry where it went)
Similarly, vertex is split into 4 ui32 components, one each for X, Y and Z, then a mysterious 4th component which contains the ADC bit. Don't worry about this 4th component for now, leave it as 1 and everything will behave normally. We'll come back to the ADC bit later.
Hang on a minute! There's a couple of stray << 4 operations that have mysteriously appeared in the X and Y co-ordinates. If you've read 2: A brief overview of the basic sample, you'll know what the 2048s are doing in there, but what about the << 4? For those of you unused to binary, << 4 means "Shift your number left 4 times". So 1<<4 = 10000 and 10010 << 4 = 100100000. Why do this? If we look at the description of the XYZ2 register on P137 of the GS manual, we see that the data in the X and Y registers is expected in 12:4 fixed point format. That means that there's an imaginary binary point before the last 4 bits of the number.
Basically, we want to write the number 1948 to the X register. 1948 = 11110011100 in binary, so when it's shifted left 4 times we get 111100111000000. However when we send it to the GS, the GS reads it as 11110011100.0000, which is 1948.0 decimal which is what we wanted. Had we left out the <<4, the GS would have read 1111001.1100 which is 121.75, giving us an X co-ordinate way off screen.
Notice that after assigning a value to the temporary variables colour and vertex, they still have to actually be inserted into our GIFpacket using the gifpacket_addgspacked() function. Finally the packet is terminated with gifpacket_terminate, and the 16kb file is written to disk.
Homework
OK, think you understand gen_data.c? Then change it! Now's the time to implement the changes that you thought about doing back in 2: A brief overview of the basic sample. (Note: You might need to have VCL installed here to avoid any errors, even though we haven't fiddled with any VU code yet! See the start of 4: Making your code file to see how to install VCL, if you haven't already.)
2) Change the vertex.ui32[ ] values to make the triangle fill the top-right half of the screen, assuming the screen is 640x224 pixels large (Positive X is to the right, positive Y is *down*). Tip: Leave the 2048 and the <<4 in place, and just change the other numbers.
3) Change the NLOOP field of the GIFtag to allow for a second triangle, and add code to draw this somewhere in the bottom-left half of the screen.
4) Create a second GIFsegment that allows for the drawing of a single blue point at (-50, 50) relative to the centre of the screen.
5) Modify Q4 to draw 5 green points in a horizontal line, starting at (-50, 50), spaced 10 pixels apart.
The answers to Q2 and Q3 can be checked by recompiling the basic sample after your alterations, then running the harness program as before. However, the basic sample VU code is only set up to draw one GIFpacket. To test your answers to Q4 and Q5, you'll have to make sure that the first GIFsegment and second GIFsegment are part of the same packet. In other words, the first GIFtag must have EOP=0, and the second EOP=1.
I want to emphasise again that the basic.dat file that is generated by this program is the only thing of importance. The gen_data program is not part of the competition entry, it could have been written in Perl, Ruby, on the PS2, on a PC, and doesn't even need to exist at all. If you're really interested, I'll show you how to generate basic.dat by hand, using nothing more than pen and paper. If you're saner than me, and just want to get on with your VU demo, move along to 4: Making your code file
Now, what you have to bear in mind when writing numbers is that we write the most significant bit first, i.e. bit 127, but we think of the least significant bit, i.e. bit 0 first. So, we must remember to put our fields in the other way round, starting with REGS, then NREG, etc. etc.
Looking at the GIFtag specification on P151 of the EE User's Manual, we have our GIFtag is (all 128 bits!) (I've split up the fields with hyphens, REGS - NREG - FLG - PRIM (FIX, CTXT, FST, AA1, ABE, FGE, TME, IIP, PRIM) - PRE - some garbage - EOP - NLOOP)
It's much easier to write that down in Hex, thankfully translating from binary to hex is easy, just take 4 digits at a time.
00000000000000512005EAAAAAAA8003
That's a GIFtag that still says I'm going to send 3 set of RGBAQ and XYZ2 vertex information, and I expect a triangle to be drawn.
Then follows the colour and co-ordinates of the first vertex - remember the colour is specified in ABGR format, and the co-ordinates in ZYX format (see P153 of the EE User's Manual for more info on packed data)
Put that all together, and you've got your GIFpacket, which could be typed into a hex editor without a C program in sight. Of course, I don't recommend you actually do this, I'm just trying to prove a point to myself :) We're done here, move along now to 4: Making your code file.