b3d file mipmap flag setter

Post those lines of code you feel like sharing or find what you require for your project here; or simply use them as tutorials.
Post Reply
xDan
Competition winner
Posts: 673
Joined: Thu Mar 30, 2006 1:23 pm
Location: UK
Contact:

b3d file mipmap flag setter

Post by xDan »

Hello, this is a simple program that takes a .b3d file and enables all "generate mipmaps" flags in it.

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 :) as a quick hack and to avoid having to recompile Irrlicht. Maybe a future Irrlicht version will have this as a setting?

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;
}
Eigen
Competition winner
Posts: 375
Joined: Fri Jan 27, 2006 2:01 pm
Location: Estonia
Contact:

Post by Eigen »

I believe Irrlicht already has this setting : )

Code: Select all

SceneManager->getParameters()->setAttribute(scene::B3D_LOADER_IGNORE_MIPMAP_FLAG, true);
But thanks for the snippet anyway!
xDan
Competition winner
Posts: 673
Joined: Thu Mar 30, 2006 1:23 pm
Location: UK
Contact:

Post by xDan »

Well, that's good to know :shock:

But still, it's not in the current release. *waits for 1.6*
Post Reply