This is useful as since Irrlicht 1.5 the flag is taken into account, and not all b3d exporters seem to set this flag, so often the loaded model's textures look horrible.
It searches for the appropriate chunks in the b3d file by looking for the chunk name "TEXS", so there could be problems if those characters are present anywhere else in the file (for example in a texture filename). But it is good enough for some purposes
Windows binary: http://xzist.org/temp/b3dtwiddler.exe
(just pass the filename as an argument or drag the b3d onto the exe)
Code: Select all
#include <stdio.h>
#include <string.h>
#include <vector> // let's have a sprinkling of C++
// from Irrlicht
// Irrlicht does byteswapping so I guess I should... :S
// I hope this is the correct macro...
#define bswap_32(X) ( (((X)&0x000000FF)<<24) | (((X)&0xFF000000) >> 24) | (((X)&0x0000FF00) << 8) | (((X) &0x00FF0000) >> 8))
// store the found flags and flag locations here...
std::vector<long int> flags;
std::vector<long int> flagPositions;
long int read_chunk_length(FILE *fp)
{
long int length;
fread(&length, 4,1, fp);
#ifdef __BIG_ENDIAN__
length = bswap_32(length);
#endif
return length;
}
void parse_texs_chunk_contents(FILE *fp)
{
printf("Reading chunk contents... ");
// Read texture filename. (null terminated string)
// Prints it out on console for info
char c;
while ( (c = fgetc(fp)) != 0)
printf("%c", c);
printf("\n");
// HERE IT IS!! THE FLAG!!
long int flagPos = ftell(fp);
long int flag;
fread(&flag, 4,1, fp);
#ifdef __BIG_ENDIAN__
flag = bswap_32(flag);
#endif
// Save flag info for later
flags.push_back(flag);
flagPositions.push_back(flagPos);
// Now read the rest of the chunk contents... (in case of multiple content blocks)
// Another int32 and 5 floats = 4*6 = 24 bytes
char stuff[24];
fread(stuff, 24,1, fp);
}
void found_texs(FILE *fp)
{
long int end_pos = ftell(fp) + read_chunk_length(fp);
// Now TEXS header has been read. Read contents of chunk. (may be several chunks???)
while (ftell(fp) < end_pos)
parse_texs_chunk_contents(fp);
}
int main(int argc, char **argv)
{
if (argc < 2)
{
printf("Error: please supply a B3D file as an argument!\n");
return 0;
}
char *fileName = argv[1];
printf("Parsing file %s...\n", fileName);
FILE *fp = fopen(fileName, "rb");
char chunkName[5];
chunkName[4] = 0;
// Find "TEXS" indicating the start of the texture chunk.
// Note that if the file contains anything else with those characters in
// e.g. as part of a texture filename, then there would be problems...
int i = 0;
while (fread(chunkName, 4, 1, fp) != 0)
{
// First four bytes of the header are the characters "TEXS"
if (strcmp(chunkName, "TEXS") == 0)
found_texs(fp);
}
fclose(fp);
// Now all flags and flag positions in the binary file have been found, update them!
fp = fopen(fileName, "rb+");
for (int i = 0; i < flags.size(); i ++)
{
fseek(fp, flagPositions[i], SEEK_SET);
long int flag = flags[i];
// Set the flag!
// (enable mipmap generation)
flag |= 0x8;
#ifdef __BIG_ENDIAN__
// I assume I'm meant to do this here?
// I don't know much about endianness...
flag = bswap_32(flag);
#endif
printf("Setting flag... %i to %i %s\n", flags[i], flag,
flags[i] == flag ? "(no change)" : "");
fwrite(&flag, 4,1, fp);
}
fclose(fp);
printf("Done!");
return 0;
}