Game Development Community

TGEA Texture Layer code assistance

by Ronald J Nelson · in Torque Game Engine Advanced · 01/15/2008 (8:37 pm) · 22 replies

I have been working on this for a little while now and I am going to post the code here and see if someone can tell me why it isn't working. By everything that I have checked and done it should, yet it does not.

This is a TGEA conversion of this resource with a few upgrades:
www.garagegames.com/index.php?sec=mg&mod=resource&page=view&qid=12197

To even use it you at least have to have this resource installed:
www.garagegames.com/index.php?sec=mg&mod=resource&page=view&qid=10957

Starting with matInstance.h right after
Material *getMaterial(){ return mMaterial; }
add
void setMaterial(Material *newMat){ mMaterial = newMat; }//TGEA Texture Layers
void setMaterial(Material *newMat){ mMaterial = newMat; }//TGEA Texture Layers

In matInstance.cpp at the bottom add
//--------------------------------------------------------------------------------------------------------
//TGEA Texture Layers
//--------------------------------------------------------------------------------------------------------
void MatInstance::changeBitmap(GBitmap* newBitmap)
{
	for( U32 i=0; i<mPasses.size(); i++ )
	{
		GFX->replaceTextureResource(mPasses[i].tex[0], newBitmap);
	}
}
//--------------------------------------------------------------------------------------------------------
//TGEA Texture Layers
//--------------------------------------------------------------------------------------------------------

In ShapeBase.h right after
#include "lightingSystem/sgObjectShadows.h"
add
//--------------------------------------------------------------------------------------------------------
//TGEA Texture Layers
//--------------------------------------------------------------------------------------------------------
#include "materials/materialList.h"
#include "materials/matInstance.h"
#include "materials/material.h"
//--------------------------------------------------------------------------------------------------------
//TGEA Texture Layers
//--------------------------------------------------------------------------------------------------------

Then after
SoundMaskN      = Parent::NextFreeMask << 8,       ///< Extends + MaxSoundThreads bits
add
LayerMask       = Parent::NextFreeMask << 9,        //TGEA Texture Layers

Finally, right before
static bool gRenderEnvMaps; ///< Global flag which turns on or off all environment maps
add
//TGEA Texture Layers
   static const S16  TEXTURELAYERS = 30; // increase/decrease this as you need more/less slots	
   StringTableEntry	selectedMaterial;
   StringTableEntry	layerTextureName[TEXTURELAYERS]; // textures to be applied to base textures	
   Point2I pointsList[TEXTURELAYERS];
   S32 rotationList[TEXTURELAYERS];
   void setLayerTexture(U32 layer, StringHandle& materialName, StringHandle& texture, Point2I points, S32 rotation);
   void generateTexture();
   //TGEA Texture Layers

Next is Shapebase.cpp...
Page «Previous 1 2
#1
01/15/2008 (10:45 pm)
In ShapeBase.cpp

Right after
#include "renderInstance/renderInstMgr.h"
add
//TGEA Texture Layers
#include "materials/materialList.h"
#include "materials/matInstance.h"
//TGEA Texture Layers

Then in ShapeBase::ShapeBase() right after
mTypeMask |= ShapeBaseObjectType;
add
//TGEA Texture Layers
   selectedMaterial = "";
   for( U32 i = 0; i < TEXTURELAYERS; i++ )	
   {
	   rotationList[i] = 0;
	   pointsList[i].set( 1, 1 );
	   layerTextureName[i] = "";
   }
   //TGEA Texture Layers

Then in ShapeBase::packUpdate right after
U32 retMask = Parent::packUpdate(con, mask, stream);
add
//TGEA Texture Layers
   if(stream->writeFlag(mask & LayerMask))
   {
	   stream->writeString(selectedMaterial);
	   for(int x = 0; x < TEXTURELAYERS; x++)
	   {
		   stream->writeString(layerTextureName[x]);
		   stream->writeInt(pointsList[x].x, 10);
		   stream->writeInt(pointsList[x].y, 10);
		   stream->writeInt(rotationList[x], 10);
	   }
   }
   //TGEA Texture Layers

Next in ShapeBase::unpackUpdate right after
Parent::unpackUpdate(con, stream);
add
//TGEA Texture Layers
   if(stream->readFlag())
   {
	   selectedMaterial = stream->readSTString();
	   for(int x = 0; x < TEXTURELAYERS; x++)
	   {
		   layerTextureName[x] = stream->readSTString();
		   pointsList[x].x = stream->readInt(10);
		   pointsList[x].y = stream->readInt(10);
		   rotationList[x] = stream->readInt(10);
	   }
	   if(isProperlyAdded()) generateTexture();
   }
   //TGEA Texture Layers

Finally at the bottom of the file add
//--------------------------------------------------------------------------------------------------------
//TGEA Texture Layers
//--------------------------------------------------------------------------------------------------------
ConsoleMethod( ShapeBase, setLayerTexture, void, 8, 8, "(layer_index, materialName, layer_texture_path, pointx, pointy, rotation)")
{	
	object->setLayerTexture(dAtoi(argv[2]), StringHandle(argv[3]), StringHandle(argv[4]), Point2I(dAtoi(argv[5]), dAtoi(argv[6])), dAtof(argv[7]));
}

void ShapeBase::setLayerTexture(U32 layer, StringHandle& sMaterialName, StringHandle& textureName, Point2I points, S32 rotation)
{
	if(layer < 0 || layer > TEXTURELAYERS) return;

	if (textureName.isValidString() && sMaterialName.isValidString())	
	{
		layerTextureName[layer] = textureName.getString();
		selectedMaterial = sMaterialName.getString();
	}
	else
		return;

	pointsList[layer] = points;
	rotationList[layer] = rotation;
	setMaskBits(LayerMask);
}

void ShapeBase::generateTexture()
{
	GBitmap* baseBitmap;

	const char* fullpath = "";
	Material* currentMaterial;
	MatInstance * matInst;
	const char* matName = NULL;
	const char* baseName = NULL;

	// If materiallist is not cloned, clone it ( need to do this so we dont
	// change the material for all instances of this shape
	if(!mShapeInstance->ownMaterialList())
	{
		mShapeInstance->cloneMaterialList();
	}

	TSMaterialList* pMatList = mShapeInstance->getMaterialList();
	S32 pMatPos = -1;
	
	for (S32 j = 0; j < pMatList->mMaterialNames.size(); j++)
	{
		matInst = pMatList->getMaterialInst(j);
		currentMaterial = matInst->getMaterial();

		matName = currentMaterial->getName();
		baseName = pMatList->mMaterialNames[j];	

		//Will need to set up a test to detect Material or CustomMaterial here
		//so that we can get the texture path from CustomMaterials too
		fullpath = currentMaterial->baseTexFilename[0];

		if (dStrstr(baseName, selectedMaterial))
		{
			pMatPos = j;
			break;
		}
	}

	baseBitmap = (GBitmap*)ResourceManager->loadInstance( fullpath );

	if((fullpath != NULL) && (fullpath != "") && (pMatPos != -1))
	{
		if( baseBitmap->getFormat() != GFXFormatR8G8B8 ) {
			Con::errorf(ConsoleLogEntry::General, "material texture not RGB format");
			return;
		}
		
		for( U32 i = 0; i < TEXTURELAYERS; i++ )
		{
			if( layerTextureName[i] != NULL && dStrlen(layerTextureName[i])>0 )
			{
				GBitmap* layerBitmap = (GBitmap*)ResourceManager->loadInstance( layerTextureName[i] );

				if( layerBitmap == NULL ) {
					Con::errorf(ConsoleLogEntry::General, "layerTextureName (%s) invalid file", layerTextureName[i]);
					continue;
				}
				if( layerBitmap->getFormat() != GFXFormatR8G8B8A8  ) {
					Con::errorf(ConsoleLogEntry::General, "layerTextureName (%s) not RGBA", layerTextureName[i]);
					continue;
				}
				baseBitmap->blitBitmap(layerBitmap, pointsList[i], rotationList[i]);

				delete layerBitmap;
			}
		}

		char newMatName[50] = "[[6281be1024ce9]]";
		dSprintf(newMatName, sizeof(newMatName), "unique_material_name_%s", this->getIdString());

		Material* newMaterial = currentMaterial;
		
		if (pMatPos > -1)
		{
			newMaterial->assignName(newMatName);
			pMatList->getMaterialInst(pMatPos)->setMaterial(newMaterial);
			pMatList->getMaterialInst(pMatPos)->changeBitmap(baseBitmap);
			pMatList->getMaterialInst(pMatPos)->reInit();
		}
	}
	else
	{
		Con::errorf(ConsoleLogEntry::General, "Attempted to load file from an invalid path");
	}
}
//--------------------------------------------------------------------------------------------------------
//TGEA Texture Layers
//--------------------------------------------------------------------------------------------------------
#2
01/17/2008 (10:14 pm)
In gBitmap.h, right after
void extrudeMipLevelsDetail();
add
void blitBitmap(GBitmap* layer, Point2I pt, F32 rot );//TGEA Texture Layers

In gBitmap.cpp at the very bottom add
//--------------------------------------------------------------------------------------------------------
//TGEA Texture Layers
//--------------------------------------------------------------------------------------------------------
void GBitmap::blitBitmap(GBitmap* layer, Point2I pt, F32 rot)
{
	const U32 halfWidth  = layer->getWidth() / 2;//0; 
	const U32 halfHeight = layer->getHeight() / 2;//0;

	U32 xCoord = 0;
	U32 yCoord = 0;

	ColorI basePixel;
	ColorI layerPixel;

	// TODO: add condition to check to make sure it is ok with rotation taken into account
	if( pt.x + halfWidth > getWidth() || pt.x - halfWidth < 0 ||
		pt.y + halfHeight > getHeight() ||	pt.y - halfHeight < 0  )
	{
		Con::errorf(ConsoleLogEntry::General, "rotation/size check failed");
		return;
	}

	for ( U32 w = 0; w < layer->getWidth(); w++ ) {
		for ( U32 h = 0; h < layer->getHeight(); h++ ) {
			if( rot == 0 ) {
				xCoord = pt.x - halfWidth + w;
				yCoord = pt.y - halfHeight + h;
				if(!getColor(xCoord, yCoord, basePixel))
					Con::errorf(ConsoleLogEntry::General, "get base pixel color rotating failed");
			} 
			else 
			{
				F32 angle = mDegToRad( rot );
				xCoord = (S32)(((S32)w - (S32)halfWidth)*cos(angle) - ((S32)h - (S32)halfHeight)*sin(angle)) + pt.x;
				yCoord = (S32)(((S32)w - (S32)halfWidth)*sin(angle) + ((S32)h - (S32)halfHeight)*cos(angle)) + pt.y;
				if(!getColor(xCoord, yCoord, basePixel))
					Con::errorf(ConsoleLogEntry::General, "get base pixel color non-rotating failed");
			}

			if(!layer->getColor(w, h, layerPixel))
					Con::errorf(ConsoleLogEntry::General, "get layer pixel color failed");
			const float alpha = layerPixel.alpha/255.0;
			basePixel.red = ((alpha * layerPixel.red) + ((1-alpha) * basePixel.red));
			basePixel.green = ((alpha * layerPixel.green) + ((1-alpha) * basePixel.green));
			basePixel.blue = ((alpha * layerPixel.blue) + ((1-alpha) * basePixel.blue));
			if(!setColor(xCoord, yCoord, basePixel))
					Con::errorf(ConsoleLogEntry::General, "set base pixel color failed");
		}
	}
	return;
}
//--------------------------------------------------------------------------------------------------------
//TGEA Texture Layers
//--------------------------------------------------------------------------------------------------------

To test these you would use something like this AFTER YOU USE THE UPDATED SETSKINNAME
%vehicle.setLayerTexture(2, "yourBaseMaterial", "main/data/shapes/vehicles/car/test2.png", 0, 0, "0 0 0");
#3
01/17/2008 (10:32 pm)
OK I updated all of the code above to what I have now. I had to make a lot of adjustments to it because even though I thought I had everything right I was terribly wrong.

I have now managed to get a working blit function. As you can see above I moved it to the gBitmap files for ease of use. I also made some important changes to the way generateTexture was working because it was overwriting the original material and anything you managed to get done with it would stay stuck that way in memory.

What I have done instead is create a new material that is a copy of the material set in setSkinName Then I change the name of that material to make it unique and allow setSkinName to work properly when you respawn. Additionally I made a function that I believed would swap the texture in the new material and then allow me to set that material.

That is the point that I believe is broken now. As you will be able to see I have temporarily added a texture export system to generate texture to test whether or not the code had worked up to that point.

It will leave a jpg in your executable's directory named testShot.jpg. You will beable to see from this that I have indeed succeeded up to that point because it exports your layered texture.

I am sure now that whatever is currently wrong with the code to right now is directly after that.

I have even tried using swapMaterial for the material instance that was provided in the setSkinName update (using the new material's name) to replace this portion of the code:
matInst->setMaterial(newMaterial);
matInst->reInit();

It didn't work.

This tells me that the problem must be in my creation of the material, likely in the function I used to try changing the base texture of the file.

As I stated before in an early version of this thread, I am just trying to modify the texture that is loaded into memory. Anything else would make this not work in multiplayer. So far everything should work just fine in multiplayer, I just need to test it once I get that far.

I would really just like someone to look at this and try to give me something to try with the last portion of generateTexture.

Obviously this code will become a resource for everyone with TGEA to use since I am already sharing everything I have done so far.

Thanks in advance for any help you can give me.
#4
01/18/2008 (12:03 am)
Do you try pMatList->setMaterial(pMatPos, texName) in generateTexture method(inside the if (pMatPos > -1) statement) before?

What I mean is that you really need to create a new MatInstance and reInit? Or just reassign the texture pathname.
#5
01/18/2008 (4:45 am)
Thanks Steven, tried that. No I think ,my problem is in my method to change the material's texture.
#6
01/18/2008 (8:31 am)
So, what's the effect of the setMaterial method you've tried?
#7
01/18/2008 (3:21 pm)
Well I have been able to use both methods to adjust the lighting characterisitics of the material so I know that I can do this with one or the other. My method is based upon the setSkinName update and the method it used. Since it works, I believe that my current method would as well.

No, I am pretty sure the problem lies in the fact that I need to figure why my code that should change the material's texture, is not working.
#8
01/18/2008 (7:13 pm)
Well I have confirmed that it is in fact my method for trying to change the material's texture and apparently the name. You see I tried something else which was trying to map the material to the shapeinstance base material with the following changes to the code at the end of generateTexture:

***CODE REMOVED***

When I called my setTextureLayer function I got an interesting error.

"Warning, misunderstood material parameter: unique_texture_name_2831 in materialEntry base.elminator"
#9
01/18/2008 (7:23 pm)
I have figured out why it does not work too. As it turns out my method to change the texture would work if

I actually had this for the variable "texture":

"main/data/shapes/unique_texture_name_2831.png". Since that is not going to happen with the blit texture in memory, this technique will not work this way.

Now if this was a single player game, sure I would be able to finsih here by exporting the texture to a cache folder, setting the material texture with my method by adding that directory information. This would also mean you would have one guy running around with a totally unique material. Not exactly conducive to a multiplayer environment.

So It looks like I need to construct a new method. Most of the code that I added to the material and material instace files will be going away. I will give you an update soon.
#10
01/19/2008 (12:32 am)
I have updated the code above again. I have tested my material creation portion of it for the new material and it and its renaming work just fine.

Now I have also removed the material files code because it just didn't work. There is now a new function in the matInstance files that is what I need to get working.

What I have figured out is that the bitmap change does have to take place ant the material instance level because you have access to the render and shader data at that level. Within that data is access to the bitmap that is rendered.

The function I have right now crashes the game. Obviously I am still trying to figure this one out because while I have figured out what I need to access, I am having troubles getting to it without serious complications.

With my current method, modifying the bitmap for the material is just fine because you will reset the material when you respawn using setSkinName. The new material has a unique name basedupon the object instance so it will be safe.

I would really appreciate it if someone could have a look at my matInstance function named "changeBitmap". Hopefully someone can give me some insight on the next step I should go with.
#11
01/19/2008 (2:43 pm)
FINALLY SOME SUCCESS!!!

I updated the matInstance.cpp changeBitmap function above to what I have now.

Here is the newly added code.

In gfxDevice.h right after
void reloadTextureResource( const char *filename ){ mTextureManager->reloadTextureResource( filename ); }
add
//--------------------------------------------------------------------------------------------------------
   //TGEA Texture Layers
   //--------------------------------------------------------------------------------------------------------
   void replaceTextureResource( GFXTextureObject *obj, GBitmap* newBitmap )
   {
	   mTextureManager->replaceTextureResource( obj, newBitmap ); 
   }
   //--------------------------------------------------------------------------------------------------------
   //TGEA Texture Layers
   //--------------------------------------------------------------------------------------------------------

Next in gfxTextureManager.h right after
void reloadTextureResource( const char *filename );
add
void replaceTextureResource( GFXTextureObject *obj, GBitmap* newBitmap );//TGEA Texture Layers

Then in gfxTextureManager.cpp add this at the bottom
//--------------------------------------------------------------------------------------------------------
//TGEA Texture Layers
//--------------------------------------------------------------------------------------------------------
void GFXTextureManager::replaceTextureResource( GFXTextureObject *obj, GBitmap* newBitmap )
{
   if( newBitmap )
   {
      if( obj )
      {
         _loadTexture( obj, newBitmap );
      }
   }
}
//--------------------------------------------------------------------------------------------------------
//TGEA Texture Layers
//--------------------------------------------------------------------------------------------------------

I have managed to get a almost working system in place. It has two bugs that need to be fixed though. I will continue to work on them but I could really use some help.

BUG 1: It is still replacing the material you set in setSkinName, no idea why yet.
BUG 2: The new layered texture no longer uses the meshes UV Mapping.

Here are some pictures to illustrate what I am saying.

First this is the texture for my car the word HOOD added for UV Mapping testing.
i72.photobucket.com/albums/i192/DTDA/baseelminator.png
This is the layer texture
i72.photobucket.com/albums/i192/DTDA/test2.png
This is what the layered texture looks like
i72.photobucket.com/albums/i192/DTDA/testShot.jpg
Now here is the vehicle in game before the layer is added, pay attention to the word HOOD.
i72.photobucket.com/albums/i192/DTDA/bug1.jpg
Now according to the pictures above the word HOOD should be covered with the added layer. This is what really happens.
i72.photobucket.com/albums/i192/DTDA/bug2.jpg
OK I have really gotten a long way with this. I could really use some help with these bugs.
#12
01/19/2008 (6:28 pm)
BUG1: I am still trying to find out a way to make a new material based upon the old one and make the changes required.

So far all of my ideas have ended up with it still effecting the original material. Anyone have an idea on how to properly clone the material IN CODE so it doesn't effect the original?
#13
01/19/2008 (6:41 pm)
%stryng = "new CustomMaterial(" @ %newmaterialname @ ":" @  %origionalmaterial "){" @
			"texture[0] = \"some/path/to/the/proceedural/texture/" @ %proceeduraltexture\";" @
		"};";
		eval(%stryng);
could be misunderstanding the question there of course, but that'd give you a new mat def based on the origional template with whatever line you need changed changed... (presupposes you've speified a mapto of course)

basic logic theres not dissimilar fromt he way a datablock works in terms of the whole
new datablocktype(oveerride:origionaltemplate)
{
entrytooverride = foo;
}
setup.

*if* thats what you're going for there, hit me up, and i'll walk you through the relevant materialdefs file portion if the aboves less than clear. (also the major reason for the material swapping as opposed to trying to change the *texture it'sself*)

fraid beyond that, still working the way through the void ShapeBase::generateTexture() func (mostly custommaterials this end, so getting that part scalable is a req before i can throw you any more in the way of an assist)
#14
01/19/2008 (10:00 pm)
Thanks Kirk but I need this to work in code rather than by script based upon the fact that I am not just looking to make a new material but alter the texture with different layers that can be added up to 30 as I have it right now without any more stress on video memory than the original texture itself provided.

What I am trying to do in code is actually copy the settings from the original material to the new one, then modify the new one without affecting the old.

Any ideas on the UV mapping bug?

As for the custom materials portion, I will just have to make an adjustment to my code where it gets fullpath = currentMaterial->baseTexFilename[0]; and branch this method to get custom material texture paths as well. That part should be just as easy as this once I get to that point since CustomMaterial is based off of Material and much of the conversion I would require for looking that up is already in material.cpp and matInstance.cpp.
#15
01/20/2008 (1:55 am)
Ok. trying again. just to make sure were not looking at this from angles so far apart that were talking past each other here:

img213.imageshack.us/img213/5407/walkthroughtg9.jpg^that'd be what you're going for as you've described it to date, right?
#16
01/20/2008 (3:24 pm)
That looks about right.
#17
01/22/2008 (4:29 pm)
Anyone else trying to get his working? I was away for most of the weekend.
#18
01/22/2008 (5:41 pm)
Why?
With the stuff mentioned to be fixed and working correctly again in TGEA Jugernaut there is little sense in implementing that "deep down" stuff at the moment ... at least untils its known down to which level the merges had a straight impact.
#19
01/22/2008 (5:52 pm)
Ah interesting point. I guess I can hold off on this portion for a bit.
#20
01/27/2008 (1:41 am)
Any idea why this code is screwwing up my object's lighting? The textures appear too bright after I call it.

This is just a change to the end of generateTexture();

It should make no difference in the appearance of the object in that it is simply creating a new MatInstance of the material of the original MatInstance and replacing it. For all intents it should make no difference at all.

MatInstance * newInst = new MatInstance(*currentMaterial);
		
		if (pMatPos > -1)
		{
			pMatList->setMaterialInst(newInst, pMatPos);
			//newInst->changeBitmap(baseBitmap);
			newInst->reInit();
			//matInst->changeBitmap(baseBitmap);
			//matInst->reInit();
		}

Yes, despite Marc's demotivational comment, I am still going to plug away at this until the darned thing works. That is unless of course someone from GG with knowledge of Juggernaut's updates to the GFX/Shader code can tell me that it would be easier to implement what I am trying using the updates in Juggernaut.
Page «Previous 1 2