Loading an image for an effect

In ColladaRt, we use the following code to add a texture to the effect:

				if(textureElement)
				{
					CrtImage * image = NULL;
					const CrtChar *samplerName = textureElement->getTexture();
					const CrtChar *imageName = samplerName;
					char *target = new char[ strlen( samplerName ) + 3 ];
					strcpy( target, "./" );
					strcat( target, samplerName );
					daeSIDResolver sidRes( EffectElement, target );
					delete[] target;
					target = NULL;
					if ( sidRes.getElement() != NULL )...

Why do we add a “./” to the target?

The code that is inside the if ( sidRes.getElement() != NULL ) code, is more complex than its else:


if ( sidRes.getElement() != NULL )
{
//More complex code
}
else
{
						daeIDRef ref(samplerName);
						ref.setContainer(textureElement);
						ref.resolveElement();
						daeElement * element = ref.getElement();
						domImage * domimage = (domImage *) element;
						image = ReadImage(domimage);
//						image = ReadImage((domImage *) (daeElement*) ref.getElement());
//						image = GetImage(samplerName, textureElement->getDocumentURI()->getURI());
						if ( image )
						{
							CrtPrint( "Direct Image Linking!! Your Data is WRONG!! But I'm nice and will load it anyways!" );
							imageName = samplerName;
						}
}


But both of if and else attempt to load the image. Isn’t it?( But inside the else we don’t add a “./” to the filename ). What do we do in if statement exactly?Here’s the “if” code:

					if ( sidRes.getElement() != NULL )
					{
						daeElement *samp = sidRes.getElement();
						daeElement *surf = NULL;
						if ( CrtCmp( samp->getTypeName(), "fx_newparam_common" ) )
						{
							domFx_newparam_common *npc = (domFx_newparam_common *)samp;
							if ( npc->getFx_basic_type_common()->getSampler2D() != NULL )
							{
								const char *str = npc->getFx_basic_type_common()->getSampler2D()->getSource()->getValue();
								target = new char[ strlen( str ) + 3 ];
								strcpy( target, "./" );
								strcat( target, str );
                                sidRes.setTarget( target );
								delete []target;
								target = NULL;
								surf = sidRes.getElement();
							}
						}
						else if ( CrtCmp( samp->getTypeName(), "common_newparam_type" ) )
						{
							domCommon_newparam_type *cnp = (domCommon_newparam_type *)samp;
							if ( cnp->getSampler2D() != NULL )
							{
								const char *str = cnp->getSampler2D()->getSource()->getValue();
								target = new char[ strlen( str ) + 3 ];
								strcpy( target, "./" );
								strcat( target, str );
                                sidRes.setTarget( target );
								delete []target;
								target = NULL;
								surf = sidRes.getElement();
							}
						}
						if ( surf != NULL )
						{
							if ( CrtCmp( surf->getTypeName(), "fx_newparam_common" ) )
							{
								domFx_newparam_common *npc = (domFx_newparam_common *)samp;
								if ( npc->getFx_basic_type_common()->getSurface() != NULL )
								{
									domFx_surface_common *sc = npc->getFx_basic_type_common()->getSurface();
									if ( sc->getFx_surface_init_common() != NULL && 
										sc->getFx_surface_init_common()->getInit_from_array().getCount() > 0 )
									{
										daeIDRef & ref = sc->getFx_surface_init_common()->getInit_from_array()[0]->getValue();
										ref.resolveElement();
										daeElement * element = ref.getElement();
										domImage * domimage = (domImage *) element;
										image = ReadImage(domimage);
//										imageName = sc->getFx_surface_init_common()->getInit_from_array()[0]->getValue().getID();
//										image = GetImage(imageName, textureElement->getDocumentURI()->getURI());
									}
								}
							}
							else if ( CrtCmp( surf->getTypeName(), "common_newparam_type" ) )
							{
								domCommon_newparam_type *cnp = (domCommon_newparam_type *)surf;
								if ( cnp->getSurface() != NULL )
								{
									domFx_surface_common *sc = cnp->getSurface();
									if ( sc->getFx_surface_init_common() != NULL && 
										sc->getFx_surface_init_common()->getInit_from_array().getCount() > 0 )
									{
										daeIDRef & ref = sc->getFx_surface_init_common()->getInit_from_array()[0]->getValue();
										ref.resolveElement();
										daeElement * element = ref.getElement();
										domImage * domimage = (domImage *) element;
										image = ReadImage(domimage);
//										imageName = sc->getFx_surface_init_common()->getInit_from_array()[0]->getValue().getID();
//										image = GetImage(imageName, textureElement->getDocumentURI()->getURI());
									}
																		
								}
							}
						}
					}

Why do we add a “./” to the target?
What that code is doing is trying to resolve a sid reference. You can read more about sid references in the Collada spec, and there are some updates to how sid references work in the release notes.

The ./ is needed for historical reasons. Originally in Collada there was only one type of sid reference. This reference started with an ID, then was followed by “/” and a sid (repeated any number of times), and then a member selector like “.X” or “(2)”. Here’s a complete example: “myNode/sid1/trans.X”. These types of sid references are used heavily for things like animation in Collada. The Collada DOM sid resolver was originally written to work with these types of sid references.

Then in Collada 1.4 a new type of sid reference was introduced for Collada FX. This sid reference didn’t have the form “ID/sid1/sid2…” like the original sid reference used in Collada. Instead, it was just the name of a sid, e.g. “mySampler”. An example of this type of reference is the “texture” attribute on the <texture> element:

<texture texture="mySampler" texcoord="UVSET0"/>

Unfortunately the sid resolver in the Collada DOM doesn’t work with these types of sid references properly. You have to trick the DOM by asking it to resolve “./mySampler” instead. Then the DOM thinks it’s an old-style sid reference that begins with an ID (the ‘.’ means “the ID of the container element”) and resolves it correctly.

It sucks that you need to manually add the ./, but there’s good news! Your post reminded me of this problem, so in revision 202 I updated the DOM to resolve the new-style sid references correctly. So if you check out the latest code in SourceForge, you no longer need to manually add ./. Old code that added the ./ will continue to work correctly of course.

The code that is inside the if ( sidRes.getElement() != NULL ) code, is more complex than its else:

But both of if and else attempt to load the image. Isn’t it?( But inside the else we don’t add a “./” to the filename ). What do we do in if statement exactly?
Yes, the if and the else are both attempting to load the image, using two different mechanisms. This is also for historical reasons. Starting with Collada 1.4, textures worked by linking a <texture> to a <sampler> to a <surface> to an <image> (this is explained in detail in the Collada release notes). However, some applications incorrectly wrote Collada data that linked a <texture> directly to an <image>. RT attempts to load that data anyway with the code in the else statement. The more complex code is loading textures the correct way.

So I guess the question is, do you need to put the hack into your code to load textures that are stored the wrong way? I can’t say for certain if many apps these days are still getting basic Collada texturing wrong. If I had to guess I’d say there are probably very few apps that still have that problem, so you can probably ignore it.