How to write your own C1 PIX pack
(and thus prepare your custom textures)
With this article, you should be able to /write/ your own pix pack for Carmageddon 1 (C1) from scratch, and then include your bitmaps easily with CarmagEdit.
Prior to reading and trying to go on with this article. Be sure that you have a hex editor installed (Hex Workshop, FrHed, 010 Editor, etc.).
This stuff is only useful for C1 modders or for people who would like to start modding C1. It is useless for any C2 editing!
I highly recommend you totaly read this article before attempting to create a pix pack for the first time. This way you'll have a global idea of what is awaiting you.
Updated in August 2011!
Examples: 16d is your usual friendly sixteen, 16h however equals twentytwo in decimals.
(In this case) a byte will be represented by two hexadecimal characters together like 00, 6B, 1A or FF (examples). I'll often speak about them in the following.
Four bytes are called a 'word'. Data isn't always organized as formatted words though.
OK... hang on to your helmet...
So launch your /favorite/ hex editor and create a new binary file. C1 pix packs always start with two words: a type one (always 12h) then a lenght one (as in C1/C2 these first two words are always followed by eight bytes, value is always 8h). The following eight bytes are made of two words: the file type (in our case 02h) and then the last word of the header is always 02h for any file.
1. THE PIX PACK HEADER
If you didn't understand what I explained, don't worry and just write the following in the hexadecimal part of your editor (not ascii part thus!):
00000012 00000008 00000002 00000002 (don't pay attention to the spaces ofcourse)
This part must only be written once per pix pack file (at the very start thus). The rest of the file will be the texture entries.
You'll notice that the word values are always written starting with the last byte. It will always be like that for any C1/C2 file.
You'll also notice that this header has no value as to how many texture entries the pix pack has. This means you'll be able to add/remove entries easily without having to change the header or any value.
This was the header, thank you very much, see you next week!
What I mean by 'entries' is the textures. These entries are divided in two parts: the texture infos and the actual texture data.
2. THE ACTUAL PIX ENTRIES
The texture infos is the most important part and will probably make you rage from time to time. This part always start with two words. The first is always the same and its value is 03h. The second one is a length value. It defines the amount of bytes between this word and the word after the name. So it will always be 11d + the amount of bytes for the filename + 1d. In this case, if the texture is named TEST1.PIX, the amount of bytes will be 11d + 9d (one byte per char) + 1d so 21d and thus 15h.
So now (directly after the header) write this:
Now the entry isn't organized in words anymore. What comes next is a 'pix type' byte followed by a series of integers using two bytes each.
In order: pix type byte, rowsize, width, height, half of the width, half of the height.
In C1 the pix type is always 03h (it means 8bit color depth). Width and height are ofcourse the ones of the texture we are writting the entry for. They will most probably not be the same for every texture so the entries will have to be rewritten (or at least modified) for the other textures. The rowsize is the width*pixelsize. The pixelsize for C1 textures is always 1, so the rowsize here will always equal the width.
You must pay attention to the dimensions of your textures! Even if C1 seems to be able to support weirdo sizes ala 51*76px, these can get very complicated to calculate (in order to write the correct values in each entry I mean). Power of two are the best bet (32*32px, 128*256px, 2*1024px, 16*64px, etc.), but if you want very specific dimension here's what I suggest: the half of the dimension shouldn't finish with five (example: don't choose 70d because its half is 35d) ; what's even better is to choose a dimension that can be divided by four and still be an integer (like 12d) or then choosing two dimensions whose multiplication can be divided by sixteen (56*26px for example) but then the width must always be the one divisible by four at least. So you guessed it, stay with even numbers and make sure they can be divided by two a few times (if the first dimension can only be divided by two one time, the second dimension must be divisible by two three times and chosen as width, etc.).
Let's try to resume that: the width must be the most divisible dimension, avoid a dimension whose half ends with five (or then choose it as height), the multiplication of both dimensions must be divisible by sixteen.
Ok so let's get back at writing that chunk. In this article I'll use 56*26px as dimensions. What is their equal in hexadecimal?...
In order the chunk is thus:
03 0038 0038 001A 001C 000D
If your dimension is larger even in hexadecimal simply fill the two bytes. If your decimal dimension is 1234d for example, hex is 4D2h so write 04D2h. Got it?
Now what directly follows this chunk is the texture name, I suggest you write it in the ascii part of your editor. Here I choosed to name the file TEST1.PIX. There's probably the same name lenght limit as in C2 (14 chars) but I highly recommend sticking to the good ol' 8.3 format maximum and in all caps!
The filename is always followed by a null byte (the game uses it to notice when the name ends). In my case the hexadecimal chunk looks like this:
We are almost done! The final part of the texture infos starts with a word whose value is always 21h (it's the section type). Then two similar words respectively containing (pixelsize*pixelcount)+8d (section size) and (width*height) (the pixelcount). And finally the last word always 01h, this is the pixelsize I talked about before.
It is easy to calculate the pixelcount as it's just (width*height), in this case 56dx26d=1456d=5B0h. The section size is rather easy as the pixelsize is always 1d for these textures, so it's like pixelcount+8d, in this case 1456d+8d=5B0h+8h=5B8h.
If I had the first and last words it looks like this:
00000021 000005B8 000005B0 00000001 (I guess it's explicit enough)
Feww! I'll write everything again to have a good look at it:
00000012 00000008 00000002 00000002 (pix pack header)
00000003 00000015 (texture entry header)
03 0038 0038 001A 001C 000D (pix type and dimensions)
54455354312E504958 00 (name.ext and null byte)
00000021 000005B8 000005B0 00000001 (size of the bitmap etc)
This all without spaces or carriage return obviously. The hardest part is done. Let's put the bytes CarmagEdit will later edit. To achieve that simply get back the multiplication of the width and height (the pixelcount, in this case 1456d) and insert the same amount of bytes. Yes, your hex editor is supposed to have this feature. Make sure you place your cursor at the end (in the hex part, not ascii!), use the insert function, make sure that this tool will read the amount of bytes to insert as a decimal value (hex workshop might insert 1456h bytes (=5206d!) instead of 1456d for example), and if you can set the byte value choose/write FFh (this way you can easily see where the texture bitmap data starts and ends). And finally insert eight null bytes (00000000 00000000) to finish this entry.
At this point you should have the header and one complete entry. I suggest you save your file (as PACKTEST.PIX for example, don't forget the extension uh) and try to open it in CarmagEdit. If everything went well it should display one white texture with the correct dimensions ready to import your 8bit bitmap!
Ok so you got the file header right and one first entry to insert your texture. Ofcourse your car/track is probably not made out of one single texture. There are few chances that all your textures have different sizes. Logically you should even stick with as many power of two dimensions as possible (btw using these dimensions speeds up the loading a little). So imagine we have five 32*64px textures, one 64*64px, one 128*64px and one non-power of two ala 216*68px. Well you'll write the first texture entry with the correct dimensions etc., fill it with the right amount of FFh bytes to insert the bitmap and finish it with the eight null bytes. Now select the hex part of the chunk starting with 00000003h and stop after the eight null bytes. This is a complete chunk, copy it and paste it four more times (in the hex part, remember to never work in the ascii part of your editor but for text editing). Your five 32*64px texture entries are already there! You just have to change their name, remember that the name lenght doesn't matter much, just try not to have filenames longer than eight characters (the extension not counting) and don't forget to finish it with a null byte. Pay attention that if you change the length of the filename, you must also change the dimensions+name length value (15h in this example) accordingly. Now write your 64*64px entry but stop right before inserting the lot of FFh bytes. Select your new chunk from 00000003h and stop after the closing 00000001h word, and copy it. Insert the correct amount of FFh bytes and then the eight null bytes. The 64*64px texture is done. Now paste your previous hex selection, change the height, then the half of the height, the name and finaly the kind of ratio. Fill in the right amount of FFh bytes again (should be double as last time) then the eight bytes and so your 64*128px texture is done. Now for that bigger texture with unusual dimensions it's better to start the last chunk from scratch again just to make sure you don't miss a thing.
3. MAKING THE PROCESS EASIER
I suggest you save your file often and test it with CarmagEdit (chunks must be complete uh! including the eight null bytes).
When you are done there's nothing to add at the end of the file. The last texture entry will finish the file with its eight null bytes.
You'll notice that I started with the smaller textures and ended up with the bigger ones. This is a more convenient order as the bigger the textures will be the more bitmap data (the FFh bytes) they'll require, and thus it becomes easier to get lost in your file. At some point if you have too much big textures it'd be wise to skip the FFh bytes filling and do it when you're done creating all the entries.
Voilà! Seems like we are done! Good luck!