Game Development Community

dev|Pro Game Development Curriculum

TGEA Material Loading Enhancement

by Jeremiah Fulbright · 01/31/2007 (2:39 pm) · 6 comments

Download Code File

This patch was created from TGEA MS4 and barring significant changes, should work with future versions of TGEA, although there will probably need to be finetuning...

The current Material system implementation leaves alot to be desired in certain cases and this is an attempt to help alleviate one issue which can affect those projects with large numbers of Materials.

With the current system, when a Material is created -

new Material(wall_light)
{
   baseTex[0] = "wall_light";

   emissive[0] = true;
   glow[0] = true;
};

The engine will load any and all textures referenced in the Material datablock, as the example above would just be the one texture. This isn't a major problem, but you multiply this a 100 or 1000 times and your initial load times will skyrocket. This does not include the time needed during MaterialList texture setting which also has to do some texture referencing.

My changes to the system allow materials to be created, but not do texture loading until they're actually referenced by the MaterialList for whatever object is doing texture setup. This means you have can have 1000 Materials and you will experience very little loss in application startup time and as long as you aren't trying to use all 1000 materials in one mission, very little loss in actual mission startup.

If you have custom classes that use Materials, then you may have to do some retrofitting, but it is 100% compatible with the current example scripts.

There is also an option "preload" that can be added to Materials -

new Material(wall_light)
{
   baseTex[0] = "wall_light";

   emissive[0] = true;
   glow[0] = true;

  preload = true;
};

Preload will force the Material to be fully loaded upon creation of itself (original behavior). CustomMaterials are already set to do this, since most of the default ones are important for Water, Atlas, etc. You can disable this behavior if you so desire in customMaterial.cpp.

There are some improvements that can be made including duplicating the same load functionality to do purging of Materials, so you could do semi-cleanup as needed, but that isn't included yet. I have preliminary work for it done, but haven't had time to finish it, due to work on Ascension.

No known bugs, so if you find something, let me know! :) As I'd like to eventually submit this for inclusion in TGEA by default, so need to make sure its solid, which for us it has been...

Enjoy!

#1
02/01/2007 (6:54 am)
Gotta try this one right away! This will probably help reducing the memory usage due to unused materials being loaded during creation.

It also makes it easier to do multi-mission games without having to modify the material loading scripts in order to only load the materials needed by the mission. That was a huge setback for me.
#2
02/01/2007 (9:54 am)
GREAT RESOURCE!
ill have to learn how to use patches then it never works for me :(
#3
09/15/2007 (3:05 pm)
Hi Jeremiah, really nice addon :)
This doesnt seem to work with "setSkinName()" though, looks like the materials aren't loaded dynamically then... I couldnt find the right spot yet where to add the loading of "swapped" materials.... do you have any pointers maybe? Thanks, Stefan
#4
09/15/2007 (3:33 pm)
Nevermind, solved it! :)
Just add a call to Material::loadMaterial() here:
void TSShapeInstance::reSkin(StringHandle& oldMaterial, StringHandle& newMaterial)
{
	const char* MatName = NULL;
	const char* newMatName = NULL;

	if (oldMaterial.isValidString() && newMaterial.isValidString())
	{
		MatName = oldMaterial.getString();
		newMatName = newMaterial.getString();
	}

	if (MatName == NULL || newMatName == NULL)
		return;

	if (ownMaterialList() == false)
		cloneMaterialList();

	// Cycle through the materials.
	TSMaterialList* pMatList = getMaterialList();
	for (S32 j = 0; j < pMatList->mMaterialNames.size(); j++)
	{
		const char* pName = pMatList->mMaterialNames[j];
		if (pName == NULL)
			continue;
		if(!dStricmp(pName,MatName))
		{
			Material::loadMaterial(newMatName);
			MatInstance * matInst = pMatList->getMaterialInst(j);
			if(!matInst->swapMaterial(newMatName))
				Con::errorf("reSkin failed. Material %s not found.",newMatName);
		}
	}
}
Again, thanks for sharing! :)
#5
12/28/2007 (1:36 pm)
IS this already present in 1.0.3? I was going to add it and see that alot of the code is already there. If not, has someone gotten it to work with 1.0.3 that would be willing to share the update?
#6
12/28/2007 (5:45 pm)
This exists in 1.03, not in the same form and there may be some parts missing, but for the most part, Brian implemented it very closely to same setup