//------------------------------
	BitmapTex* MaterialCreator::createTexture( const COLLADAFW::EffectCommon& effectCommon, const COLLADAFW::Texture& texture )
	{
		BitmapTex* bitmapTexture = NewDefaultBitmapTex();
		COLLADAFW::SamplerID samplerId = texture.getSamplerId();
		const COLLADAFW::Sampler* sampler = effectCommon.getSamplerPointerArray()[ samplerId ];

		const COLLADAFW::UniqueId& imageUniqueId = sampler->getSourceImage();
		const COLLADAFW::Image* image = getFWImageByUniqueId( imageUniqueId );

		if ( !image )
			return 0;

		COLLADABU::URI imageUri( getFileInfo().absoluteFileUri, image->getImageURI().getURIString() );
		COLLADABU::NativeString imageFileName( imageUri.toNativePath().c_str(), COLLADABU::NativeString::ENCODING_UTF8 );
		bitmapTexture->SetMapName(const_cast<char*>(imageFileName.c_str()));
		bitmapTexture->LoadMapFiles(0);

		UVGen* uvGen = bitmapTexture->GetTheUVGen();
		StdUVGen* stdUVGen = (StdUVGen*)uvGen;

		// reset all flags
		//stdUVGen->SetFlag(U_WRAP|V_WRAP, 1);
		//stdUVGen->SetFlag(U_MIRROR|V_MIRROR, 0);
		int tiling = 0;
		
		if ( sampler->getWrapS() == COLLADAFW::Sampler::WRAP_MODE_WRAP )
		{
			tiling += 1<<0;
		}
		else if ( sampler->getWrapS() == COLLADAFW::Sampler::WRAP_MODE_MIRROR )
		{
			tiling += 1<<2;
		}

		if ( sampler->getWrapT() == COLLADAFW::Sampler::WRAP_MODE_WRAP )
		{
			tiling += 1<<1;
		}
		else if ( sampler->getWrapT() == COLLADAFW::Sampler::WRAP_MODE_MIRROR )
		{
			tiling += 1<<3;
		}

		stdUVGen->SetTextureTiling(tiling);


		return bitmapTexture;
	}
Example #2
0
void UtilTest::SetEnvironmentMap()
{
    // Make a bitmap texture map.
    BitmapTex *map = NewDefaultBitmapTex();

    // Get the UVGen
    StdUVGen *uvGen = map->GetUVGen();

    // Set up the coords. to be screen environment.
    uvGen->SetCoordMapping(UVMAP_SCREEN_ENV);

    // Set the bitmap file.
    map->SetMapName(_T("A_MAX.TGA"));

    // Make this the new environment map.
    ip->SetEnvironmentMap(map);
}
Example #3
0
void    plLayerConverter::IProcessUVGen( plPlasmaMAXLayer *srcLayer, plLayer *destLayer, 
                                        plBitmapData *bitmapData, bool preserveUVOffset )
{
    hsGuardBegin( "plPlasmaMAXLayer::IProcessUVGen" );

    StdUVGen *uvGen = (StdUVGen *)srcLayer->GetTheUVGen();

    int tiling = uvGen->GetTextureTiling();

    // If set this indicates the texture map is tiled in U
    if (!(tiling & U_WRAP))
    {
        destLayer->SetClampFlags( destLayer->GetClampFlags() | hsGMatState::kClampTextureU );
        if( bitmapData != nil )
            bitmapData->clampFlags |= plBitmapData::kClampU;
    }

    // If set this indicates the texture map is tiled in V
    if (!(tiling & V_WRAP))
    {
        destLayer->SetClampFlags( destLayer->GetClampFlags() | hsGMatState::kClampTextureV );
        if( bitmapData != nil )
            bitmapData->clampFlags |= plBitmapData::kClampV;
    }

    // UVW Src
    int32_t uvwSrc = srcLayer->GetMapChannel() - 1;

    if( fErrorMsg->Set( !( fWarned & kWarnedTooManyUVs ) &&
                        ( ( uvwSrc < 0 ) || ( uvwSrc >= plGeometrySpan::kMaxNumUVChannels ) ),
                        destLayer->GetKeyName().c_str(), "Only %d UVW channels (1-%d) currently supported",
        plGeometrySpan::kMaxNumUVChannels, plGeometrySpan::kMaxNumUVChannels).CheckAskOrCancel() )
        fWarned |= kWarnedTooManyUVs;
    fErrorMsg->Set( false );

    destLayer->SetUVWSrc( uvwSrc );

    // Get the actual texture transform
    hsMatrix44 hsTopX;
    if (uvGen && (hsControlConverter::Instance().StdUVGenToHsMatrix44(&hsTopX, uvGen, preserveUVOffset == true)))
        destLayer->SetTransform( hsTopX );

    // All done!
    hsGuardEnd;
}
Example #4
0
static void setLayerTex( GmMaterial::TextureLayer& layer, BitmapTex* bmptex,
	const String& materialName )
{
	int mapChannel = bmptex->GetMapChannel();
	if ( mapChannel > 8 )
		throw IOException( Format("Too large Map Channel ({1}) in material {0}", materialName, mapChannel) );

	layer.filename = bmptex->GetMapName();
	layer.coordset = mapChannel - 1;
	layer.filter = (FILTER_NADA != bmptex->GetFilterType());

	layer.env = GmMaterial::ENV_NONE;
	StdUVGen* uvgen = bmptex->GetUVGen();
	if ( uvgen && uvgen->GetSlotType() == MAPSLOT_ENVIRON )
	{
		int type = uvgen->GetCoordMapping(0);
		switch ( type )
		{
		case UVMAP_EXPLICIT:	layer.env = GmMaterial::ENV_NONE; break;
		case UVMAP_SPHERE_ENV:	layer.env = GmMaterial::ENV_SPHERICAL; break;
		case UVMAP_CYL_ENV:		layer.env = GmMaterial::ENV_CYLINDRICAL; break;
		case UVMAP_SHRINK_ENV:	layer.env = GmMaterial::ENV_SHRINKWRAP; break;
		case UVMAP_SCREEN_ENV:	layer.env = GmMaterial::ENV_SCREEN; break;
		}

		TimeValue time = 0;
		layer.uoffs = 0.5f + uvgen->GetUOffs(time);
		layer.voffs = 0.5f - uvgen->GetVOffs(time);
		layer.uscale = 0.5f * uvgen->GetUScl(time);
		layer.vscale = -0.5f * uvgen->GetVScl(time);
	}
}
Example #5
0
CVertexCandidate *CMaxMesh::GetVertexCandidate(CSkeletonCandidate *pSkeletonCandidate, int faceId, int faceVertexId)
{
    // check for valid mesh and physique modifier
    if((m_pIMesh == 0))
    {
        theExporter.SetLastError("Invalid handle.", __FILE__, __LINE__);
        return 0;
    }

    // check if face id is valid
    if((faceId < 0) || (faceId >= m_pIMesh->getNumFaces()))
    {
        theExporter.SetLastError("Invalid face id found.", __FILE__, __LINE__);
        return 0;
    }

    // check if face vertex id is valid
    if((faceVertexId < 0) || (faceVertexId >= 3))
    {
        theExporter.SetLastError("Invalid face vertex id found.", __FILE__, __LINE__);
        return 0;
    }

    // allocate a new vertex candidate
    CVertexCandidate *pVertexCandidate;
    pVertexCandidate = new CVertexCandidate();
    if(pVertexCandidate == 0)
    {
        theExporter.SetLastError("Memory allocation failed.", __FILE__, __LINE__);
        return 0;
    }

    // create the new vertex candidate
    if(!pVertexCandidate->Create())
    {
        delete pVertexCandidate;
        return 0;
    }

    // get vertex id
    int vertexId;
    vertexId = m_pIMesh->faces[faceId].v[faceVertexId];

    // get the absolute vertex position
    Point3 vertex;
    vertex = m_pIMesh->getVert(vertexId) * m_tm;

    // set the vertex candidate position
    pVertexCandidate->SetPosition(vertex.x, vertex.y, vertex.z);
    pVertexCandidate->SetUniqueId(vertexId);

    // get the absolute vertex normal
    Point3 normal;
    normal = GetVertexNormal(faceId, vertexId);
    normal = normal * Inverse(Transpose(m_tm));
    normal = normal.Normalize();

    // set the vertex candidate normal
    pVertexCandidate->SetNormal(normal.x, normal.y, normal.z);
 
  if(m_pIMesh->numCVerts > 0)
  { 
        VertColor vc;
        vc = m_pIMesh->vertCol[m_pIMesh->vcFace[faceId].t[faceVertexId]];
    CalVector vcCal(vc.x, vc.y, vc.z);
    pVertexCandidate->SetVertColor(vcCal);
  }  
 
    // get the vertex weight array
    float *pVertexWeights;
    pVertexWeights = m_pIMesh->getVertexWeights();
  //if( pVertexWeights == NULL ) {
    //    delete pVertexCandidate;
    //    theExporter.SetLastError("Mesh has no vertex weights", __FILE__, __LINE__);
    //    return 0;
  //}

    // get the vertex weight (if possible)
    float weight;
    if(pVertexWeights != 0)
    {
        weight = pVertexWeights[vertexId];
    }
    else
    {
        weight = 0.0f;
    }

    // another 3ds max weird behaviour:
    // zero out epsilon weights
    if(weight < 0.0005f) weight = 0.0f;

    // set the vertex candidate weight
    pVertexCandidate->SetPhysicalProperty(weight);

    // get the material id of the face
    int materialId;
    materialId = GetFaceMaterialId(faceId);

    if((materialId < 0) || (materialId >= (int)m_vectorStdMat.size()))
    {
        delete pVertexCandidate;
        theExporter.SetLastError("Invalid material id found.", __FILE__, __LINE__);
        return 0;
    }

    // get the material of the face
    StdMat *pStdMat;
    pStdMat = m_vectorStdMat[materialId];

    // loop through all the mapping channels and extract texture coordinates
    int mapId;
    for(mapId = 0; mapId < pStdMat->NumSubTexmaps(); mapId++)
    {
        // get texture map
        Texmap *pTexMap;
        pTexMap = pStdMat->GetSubTexmap(mapId);

        // check if map is valid
        if((pTexMap != 0) && (pStdMat->MapEnabled(mapId)))
        {
            // get the mapping channel
            int channel;
            channel = pTexMap->GetMapChannel();

            bool bValidUV;
            bValidUV = false;

            // extract the texture coordinate
            UVVert uvVert;
            if(m_pIMesh->mapSupport(channel))
            {
                TVFace *pTVFace;
                pTVFace = m_pIMesh->mapFaces(channel);

                UVVert *pUVVert;
                pUVVert = m_pIMesh->mapVerts(channel);

                uvVert = pUVVert[pTVFace[faceId].t[faceVertexId]];
                bValidUV = true;
            }
            else if(m_pIMesh->numTVerts > 0)
            {
                uvVert = m_pIMesh->tVerts[m_pIMesh->tvFace[faceId].t[faceVertexId]];
                bValidUV = true;
            }

            // if we found valid texture coordinates, add them to the vertex candidate
            if(bValidUV)
            {
                // apply a possible uv generator
                StdUVGen *pStdUVGen;
                pStdUVGen = (StdUVGen *)pTexMap->GetTheUVGen();
                if(pStdUVGen != 0)
                {
                    Matrix3 tmUV;
                    pStdUVGen->GetUVTransform(tmUV);
                    uvVert = uvVert * tmUV;
                }

                // add texture coordinate to the vertex candidate, inverting the y coordinate
                pVertexCandidate->AddTextureCoordinate(uvVert.x, 1.0f - uvVert.y);
            }
        }
    }

    // check for physique modifier
    if(m_modifierType == MODIFIER_PHYSIQUE)
    {
        // create a physique export interface
        IPhysiqueExport *pPhysiqueExport;
        pPhysiqueExport = (IPhysiqueExport *)m_pModifier->GetInterface(I_PHYINTERFACE);
        if(pPhysiqueExport == 0)
        {
            delete pVertexCandidate;
            theExporter.SetLastError("Physique modifier interface not found.", __FILE__, __LINE__);
            return 0;
        }

        // create a context export interface
        IPhyContextExport *pContextExport;
        pContextExport = (IPhyContextExport *)pPhysiqueExport->GetContextInterface(m_pINode);
        if(pContextExport == 0)
        {
            m_pModifier->ReleaseInterface(I_PHYINTERFACE, pPhysiqueExport);
            delete pVertexCandidate;
            theExporter.SetLastError("Context export interface not found.", __FILE__, __LINE__);
            return 0;
        }

        // set the flags in the context export interface
        pContextExport->ConvertToRigid(TRUE);
        pContextExport->AllowBlending(TRUE);

        // get the vertex export interface
        IPhyVertexExport *pVertexExport;
        pVertexExport = (IPhyVertexExport *)pContextExport->GetVertexInterface(vertexId);
        if(pVertexExport == 0)
        {
            pPhysiqueExport->ReleaseContextInterface(pContextExport);
            m_pModifier->ReleaseInterface(I_PHYINTERFACE, pPhysiqueExport);
            delete pVertexCandidate;
            theExporter.SetLastError("Vertex export interface not found.", __FILE__, __LINE__);
            return 0;
        }

        // get the vertex type
        int vertexType;
        vertexType = pVertexExport->GetVertexType();

        // handle the specific vertex type
        if(vertexType == RIGID_TYPE)
        {
            // typecast to rigid vertex
            IPhyRigidVertex *pTypeVertex;
            pTypeVertex = (IPhyRigidVertex *)pVertexExport;

                // add the influence to the vertex candidate
            // get the influencing bone
            if(!AddBoneInfluence(pSkeletonCandidate, pVertexCandidate, pTypeVertex->GetNode(), 1.0f))
            {
                pPhysiqueExport->ReleaseContextInterface(pContextExport);
                m_pModifier->ReleaseInterface(I_PHYINTERFACE, pPhysiqueExport);
                delete pVertexCandidate;
                theExporter.SetLastError("Invalid bone assignment.", __FILE__, __LINE__);
                return 0;
            }
        }
        else if(vertexType == RIGID_BLENDED_TYPE)
        {
            // typecast to blended vertex
            IPhyBlendedRigidVertex *pTypeVertex;
            pTypeVertex = (IPhyBlendedRigidVertex *)pVertexExport;

            // loop through all influencing bones
            int nodeId;
            for(nodeId = 0; nodeId < pTypeVertex->GetNumberNodes(); nodeId++)
            {
                // add the influence to the vertex candidate
                if(!AddBoneInfluence(pSkeletonCandidate, pVertexCandidate, pTypeVertex->GetNode(nodeId), pTypeVertex->GetWeight(nodeId)))
                {
                    pPhysiqueExport->ReleaseContextInterface(pContextExport);
                    m_pModifier->ReleaseInterface(I_PHYINTERFACE, pPhysiqueExport);
                    delete pVertexCandidate;
                    theExporter.SetLastError("Invalid bone assignment.", __FILE__, __LINE__);
                    return 0;
                }
            }
        }

        // release all interfaces
        pPhysiqueExport->ReleaseContextInterface(pContextExport);
        m_pModifier->ReleaseInterface(I_PHYINTERFACE, pPhysiqueExport);
    }
#if MAX_RELEASE >= 4000
    // check for skin modifier
    else if(m_modifierType == MODIFIER_SKIN)
    {
        // create a skin interface
        ISkin *pSkin;
        pSkin = (ISkin*)m_pModifier->GetInterface(I_SKIN);
        if(pSkin == 0)
        {
            delete pVertexCandidate;
            theExporter.SetLastError("Skin modifier interface not found.", __FILE__, __LINE__);
            return 0;
        }

        // create a skin context data interface
        ISkinContextData *pSkinContextData;
        pSkinContextData = (ISkinContextData *)pSkin->GetContextInterface(m_pINode);
        if(pSkinContextData == 0)
        {
            m_pModifier->ReleaseInterface(I_SKIN, pSkin);
            delete pVertexCandidate;
            theExporter.SetLastError("Skin context data interface not found.", __FILE__, __LINE__);
            return 0;
        }

        // loop through all influencing bones
        int nodeId;
        for(nodeId = 0; nodeId < pSkinContextData->GetNumAssignedBones(vertexId); nodeId++)
        {
            // get the bone id
            int boneId;
            boneId = pSkinContextData->GetAssignedBone(vertexId, nodeId);
            if(boneId < 0) continue;

            // add the influence to the vertex candidate
            if(!AddBoneInfluence(pSkeletonCandidate, pVertexCandidate, pSkin->GetBone(boneId), pSkinContextData->GetBoneWeight(vertexId, nodeId)))
            {
                m_pModifier->ReleaseInterface(I_SKIN, pSkin);
                delete pVertexCandidate;
                theExporter.SetLastError("Invalid bone assignment.", __FILE__, __LINE__);
                return 0;
            }
        }

        // release all interfaces
        m_pModifier->ReleaseInterface(I_SKIN, pSkin);
    }
#endif
        else if( m_modifierType == MODIFIER_MORPHER || m_modifierType == MODIFIER_NONE ) {
        }
        else 
    {
          theExporter.SetLastError("No physique/skin/morpher modifier found.", __FILE__, __LINE__);
          return 0;
    }

    return pVertexCandidate;
}
// --[  Method  ]---------------------------------------------------------------
//
//  - Class     : CStravaganzaMaxTools
//
//  - prototype : bool BuildShaders()
//
//  - Purpose   : Builds the shader list from MAX's materials.
//                Preview mode requires texture files to be stored with full
//                path in order to load them. When we export, we only store the
//                filename. Another thing is that in the export mode, we copy
//                all textures into the path specified by the user if that
//                option is checked.
//
// -----------------------------------------------------------------------------
bool CStravaganzaMaxTools::BuildShaders()
{
	std::vector<Mtl*>::iterator it;

	assert(m_vecShaders.empty());

	if(!m_bPreview && m_bCopyTextures && m_strTexturePath == "")
	{
		CLogger::NotifyWindow("Textures won't be copied\nSpecify a valid output texture path first");
	}

	LOG.Write("\n\n-Building shaders: ");

	for(it = m_vecMaterials.begin(); it != m_vecMaterials.end(); ++it)
	{
		Mtl* pMaxMaterial = *it;
		assert(pMaxMaterial);

		LOG.Write("\n    %s", pMaxMaterial->GetName().data());
		CShaderStandard* pShaderStd = new CShaderStandard;
		pShaderStd->SetName(pMaxMaterial->GetName().data());

		// Properties

		StdMat2 *pMaxStandardMtl = NULL;
		StdMat2 *pMaxBakedMtl    = NULL;

		float fAlpha;

		if(pMaxMaterial->ClassID() == Class_ID(DMTL_CLASS_ID, 0))
		{
			pMaxStandardMtl = (StdMat2 *)pMaxMaterial;
		}
		else if(pMaxMaterial->ClassID() == Class_ID(BAKE_SHELL_CLASS_ID, 0))
		{
			pMaxStandardMtl = (StdMat2 *)pMaxMaterial->GetSubMtl(0);
			pMaxBakedMtl    = (StdMat2 *)pMaxMaterial->GetSubMtl(1);
		}

		if(pMaxStandardMtl)
		{
			// Standard material

			fAlpha = pMaxStandardMtl->GetOpacity(0);

			Shader* pMaxShader = pMaxStandardMtl->GetShader();

			CVector4 v4Specular = ColorToVector4(pMaxStandardMtl->GetSpecular(0), 0.0f) * pMaxShader->GetSpecularLevel(0, 0);

			pShaderStd->SetAmbient  (ColorToVector4(pMaxStandardMtl->GetAmbient(0),  0.0f));
			pShaderStd->SetDiffuse  (ColorToVector4(pMaxStandardMtl->GetDiffuse(0),  fAlpha));
			pShaderStd->SetSpecular (v4Specular);
			pShaderStd->SetShininess(pMaxShader->GetGlossiness(0, 0) * 128.0f);

			if(pMaxStandardMtl->GetTwoSided() == TRUE)
			{
				pShaderStd->SetTwoSided(true);
			}

			// Need to cast to StdMat2 in order to get access to IsFaceted().
			// ¿Is StdMat2 always the interface for standard materials?
			if(((StdMat2*)pMaxStandardMtl)->IsFaceted())
			{
				pShaderStd->SetFaceted(true);
			}

			if(pMaxStandardMtl->GetWire() == TRUE)
			{
				pShaderStd->SetPostWire(true);
				pShaderStd->SetWireLineThickness(pMaxStandardMtl->GetWireSize(0));
			}
		}
		else
		{
			// Material != Standard

			fAlpha = 1.0f; // pMaxMaterial->GetXParency();

			pShaderStd->SetAmbient  (ColorToVector4(pMaxMaterial->GetAmbient(),  0.0f));
			pShaderStd->SetDiffuse  (ColorToVector4(pMaxMaterial->GetDiffuse(),  fAlpha));
			pShaderStd->SetSpecular (CVector4(0.0f, 0.0f, 0.0f, 0.0f));
			pShaderStd->SetShininess(0.0f);
		}

		// Layers

		if(!pMaxStandardMtl)
		{
			m_vecShaders.push_back(pShaderStd);
			continue;
		}

		bool bDiffuseMap32Bits = false;
		StdMat2 *pStandardMtl;

		for(int i = 0; i < 3; i++)
		{
			int nMap;

			pStandardMtl = pMaxStandardMtl;

			// 0 = diffuse, 1 == bump, 2 = lightmap (self illumination slot) or envmap (reflection slot)

			if(i == 0)
			{
				nMap = ID_DI;
			}
			else if(i == 1)
			{
				nMap = ID_BU;

				// If its a baked material, get the bump map from there

				if(pMaxBakedMtl)
				{
					pStandardMtl = pMaxBakedMtl;
				}
			}
			else if(i == 2)
			{
				bool bBaked = false;

				// If its a baked material, get the map2 (lightmap) from there

				if(pMaxBakedMtl)
				{
					if(pMaxBakedMtl->GetMapState(ID_SI) == MAXMAPSTATE_ENABLED)
					{
						bBaked       = true;
						nMap         = ID_SI;
						pStandardMtl = pMaxBakedMtl;
					}
				}

				if(!bBaked)
				{
					if(pStandardMtl->GetMapState(ID_SI) == MAXMAPSTATE_ENABLED)
					{
						nMap = ID_SI;
					}
					else
					{
						nMap = ID_RL;
					}
				}
			}

			// Check validity

			if(pStandardMtl->GetMapState(nMap) != MAXMAPSTATE_ENABLED)
			{
				if(i == 0)
				{
					LOG.Write("\n        No diffuse. Skipping.");
					break;
				}

				continue;
			}

			Texmap* pMaxTexmap = pStandardMtl->GetSubTexmap(nMap);

			if(!pMaxTexmap)
			{
				if(i == 0)
				{
					LOG.Write("\n        No diffuse. Skipping.");
					break;
				}

				continue;
			}

			// Get texmaps

			std::vector<std::string> vecTextures, vecPaths;

			CShaderStandard::SLayerInfo  layerInfo;
			CShaderStandard::SBitmapInfo bitmapInfo;

			if(pMaxTexmap->ClassID() == Class_ID(BMTEX_CLASS_ID, 0))
			{
				BitmapTex* pMaxBitmapTex = (BitmapTex*)pMaxTexmap;
				Bitmap*    pMaxBitmap    = pMaxBitmapTex->GetBitmap(SECONDS_TO_TICKS(m_fStartTime));
				StdUVGen*  pMaxUVGen     = pMaxBitmapTex->GetUVGen();

				if(!pMaxBitmap)
				{
					if(i == 0)
					{
						LOG.Write("\n        Invalid diffuse. Skipping.");
						break;
					}
					continue;
				}

				assert(pMaxUVGen);

				BitmapInfo bi = pMaxBitmap->Storage()->bi;

				// bi.Name() returns the full path
				// bi.Filename() returns just the filename

				vecTextures.push_back(bi.Filename());
				vecPaths.   push_back(bi.Name());

				LOG.Write("\n        Bitmap %s", vecTextures[0].data());

				// Check if diffuse texture has alpha channel

				if(i == 0)
				{
					CBitmap    bitmap;
					CInputFile bitmapFile;

					if(!bitmapFile.Open(bi.Name(), false))
					{
						CLogger::NotifyWindow("WARNING - CStravaganzaMaxTools::BuildShaders():\nUnable to load file %s", bi.Name());
					}
					else
					{
						if(!bitmap.Load(&bitmapFile, GetFileExt(bi.Name())))
						{
							CLogger::NotifyWindow("WARNING - CStravaganzaMaxTools::BuildShaders():\nUnable to load bitmap %s", bi.Name());
						}
						else
						{
							if(bitmap.GetBpp() == 32)
							{
								bDiffuseMap32Bits = true;
								LOG.Write(" (with alpha channel)");
							}
							bitmap.Free();
						}
						bitmapFile.Close();
					}
				}

				// Ok, copy properties

				layerInfo.texInfo.bLoop        = false;
				layerInfo.texInfo.eTextureType = UtilGL::Texturing::CTexture::TEXTURE2D;

				bitmapInfo.strFile         = m_bPreview ? bi.Name() : bi.Filename();
				bitmapInfo.bTile           = ((pMaxUVGen->GetTextureTiling() & (U_WRAP | V_WRAP)) == (U_WRAP | V_WRAP)) ? true : false;
				bitmapInfo.fSeconds        = 0.0f;
				bitmapInfo.bForceFiltering = false;
				bitmapInfo.eFilter         = UtilGL::Texturing::FILTER_TRILINEAR; // won't be used (forcefiltering = false)
				
				layerInfo.texInfo.m_vecBitmaps.push_back(bitmapInfo);

				layerInfo.eTexEnv          = nMap == ID_RL ? CShaderStandard::TEXENV_ADD : CShaderStandard::TEXENV_MODULATE;
				layerInfo.eUVGen           = pMaxUVGen->GetCoordMapping(0) == UVMAP_SPHERE_ENV ? CShaderStandard::UVGEN_ENVMAPPING : CShaderStandard::UVGEN_EXPLICITMAPPING;
				layerInfo.uMapChannel      = pMaxUVGen->GetMapChannel();
				layerInfo.v3ScrollSpeed    = CVector3(0.0f, 0.0f, 0.0f);
				layerInfo.v3RotationSpeed  = CVector3(0.0f, 0.0f, 0.0f);
				layerInfo.v3ScrollOffset   = CVector3(pMaxUVGen->GetUOffs(0), pMaxUVGen->GetVOffs(0), 0.0f);
				layerInfo.v3RotationOffset = CVector3(pMaxUVGen->GetUAng(0),  pMaxUVGen->GetVAng(0),  pMaxUVGen->GetWAng(0));
			}
			else if(pMaxTexmap->ClassID() == Class_ID(ACUBIC_CLASS_ID, 0))
			{
				ACubic*       pMaxCubic  = (ACubic*)pMaxTexmap;
				IParamBlock2* pBlock     = pMaxCubic->pblock;
				Interval      validRange = m_pMaxInterface->GetAnimRange();

				for(int nFace = 0; nFace < 6; nFace++)
				{
					int nMaxFace;

					switch(nFace)
					{
					case 0: nMaxFace = 3; break;
					case 1: nMaxFace = 2; break;
					case 2: nMaxFace = 1; break;
					case 3: nMaxFace = 0; break;
					case 4: nMaxFace = 5; break;
					case 5: nMaxFace = 4; break;
					}

					TCHAR *name;
					pBlock->GetValue(acubic_bitmap_names, TICKS_TO_SECONDS(m_fStartTime), name, validRange, nMaxFace);

					vecPaths.push_back(name);

					CStr path, file, ext;
					SplitFilename(CStr(name), &path, &file, &ext);

					std::string strFile = std::string(file.data()) + ext.data();

					vecTextures.push_back(strFile);

					bitmapInfo.strFile         = m_bPreview ? name : strFile;
					bitmapInfo.bTile           = false;
					bitmapInfo.fSeconds        = 0.0f;
					bitmapInfo.bForceFiltering = false;
					bitmapInfo.eFilter         = UtilGL::Texturing::FILTER_TRILINEAR;
					
					layerInfo.texInfo.m_vecBitmaps.push_back(bitmapInfo);
				}

				layerInfo.texInfo.bLoop        = false;
				layerInfo.texInfo.eTextureType = UtilGL::Texturing::CTexture::TEXTURECUBEMAP;

				layerInfo.eTexEnv          = nMap == ID_RL ? CShaderStandard::TEXENV_ADD : CShaderStandard::TEXENV_MODULATE;
				layerInfo.eUVGen           = CShaderStandard::UVGEN_ENVMAPPING;
				layerInfo.uMapChannel      = 0;
				layerInfo.v3ScrollSpeed    = CVector3(0.0f, 0.0f, 0.0f);
				layerInfo.v3RotationSpeed  = CVector3(0.0f, 0.0f, 0.0f);
				layerInfo.v3ScrollOffset   = CVector3(0.0f, 0.0f, 0.0f);
				layerInfo.v3RotationOffset = CVector3(0.0f, 0.0f, 0.0f);
			}
			else
			{
				if(i == 0)
				{
					LOG.Write("\n        No diffuse. Skipping.");
					break;
				}
				continue;
			}

			if(!m_bPreview && m_bCopyTextures && m_strTexturePath != "")
			{
				for(int nTex = 0; nTex != vecTextures.size(); nTex++)
				{
					// Copy textures into the specified folder

					std::string strDestPath = m_strTexturePath;

					if(strDestPath[strDestPath.length() - 1] != '\\')
					{
						strDestPath.append("\\", 1);
					}

					strDestPath.append(vecTextures[nTex]);

					if(!CopyFile(vecPaths[nTex].data(), strDestPath.data(), FALSE))
					{
						CLogger::NotifyWindow("Unable to copy %s to\n%s", vecPaths[i], strDestPath.data());
					}
				}
			}

			if(layerInfo.eUVGen == CShaderStandard::UVGEN_ENVMAPPING && i == 1)
			{
				CLogger::NotifyWindow("%s : Bump with spheremapping not supported", pShaderStd->GetName().data());
			}
			else
			{
				// Add layer

				switch(i)
				{
				case 0: pShaderStd->SetLayer(CShaderStandard::LAYER_DIFF, layerInfo); break;
				case 1: pShaderStd->SetLayer(CShaderStandard::LAYER_BUMP, layerInfo); break;
				case 2: pShaderStd->SetLayer(CShaderStandard::LAYER_MAP2, layerInfo); break;
				}
			}
		}

		// ¿Do we need blending?

		if(ARE_EQUAL(fAlpha, 1.0f) && !bDiffuseMap32Bits)
		{
			pShaderStd->SetBlendSrcFactor(UtilGL::States::BLEND_ONE);
			pShaderStd->SetBlendDstFactor(UtilGL::States::BLEND_ZERO);
		}
		else
		{
			pShaderStd->SetBlendSrcFactor(UtilGL::States::BLEND_SRCALPHA);
			pShaderStd->SetBlendDstFactor(UtilGL::States::BLEND_INVSRCALPHA);
		}

		// Add shader

		m_vecShaders.push_back(pShaderStd);
	}

	return true;
}
bool SGP_MaxInterface::GetMtlAnim( StdMat* pStdMtl, ColorTrack& track, int nChannel )
{
	if( pStdMtl == NULL )
	{
		assert( false && "std mtl is NULL" );
		return false;
	}

	int nFrameCount = 0;
	TimeValue nStartTick = GetStartTick();
	TimeValue nEndTick = GetEndTick();
	int nTickPerFrame = GetTickPerFrame();



	track.bTiling = false;

	StdUVGen *uv = NULL;

	Texmap *tx = pStdMtl->GetSubTexmap(nChannel);
	if( tx )
	{
		if( tx->ClassID() == Class_ID( BMTEX_CLASS_ID, 0 ) )
		{
			BitmapTex *bmt = (BitmapTex*)tx;
			uv = bmt->GetUVGen();
			if( uv )
			{
				track.nUTile = (int)uv->GetUScl(0);
				track.nVTile = (int)uv->GetVScl(0);
				if( track.nUTile == 1 && track.nVTile == 1 )
					track.bTiling = false;
				else
					track.bTiling = true;
				track.nStartFrame = bmt->GetStartTime();
				track.fPlaybackRate = bmt->GetPlaybackRate();
				track.nLoopMode = bmt->GetEndCondition();

				if( uv->GetUAng( 0 ) != 0.0f ||
					uv->GetVAng( 0 ) != 0.0f )
				{
					track.fUSpeed = uv->GetUAng( 0 ) / piOver180;
					track.fVSpeed = uv->GetVAng( 0 ) / piOver180;
					track.bUVMoving = true;
				}
				else
					track.bUVMoving = false;
			}
		}
	}


	TimeValue t;
	for( t = nStartTick; t <= nEndTick; t += nTickPerFrame )
		nFrameCount++;


	track.ColorKeyFrame.resize( nFrameCount );

	t = nStartTick;
	for( int i = 0; i < nFrameCount; i++, t += nTickPerFrame )
	{
		SGP_ColorKey key;
		memset( &key, 0x00, sizeof( key ) );
		Color diffuse	= pStdMtl->GetDiffuse( t );
		Color ambient	= pStdMtl->GetAmbient( t );
		Color specular	= pStdMtl->GetSpecular( t );

		Color filter	= pStdMtl->GetFilter( t );
		float alpha		= pStdMtl->GetOpacity( t );
		float shinstr	= pStdMtl->GetShinStr(t);
		float selfillum = pStdMtl->GetSelfIllum( t );

		float uoffset	= 0;
		float voffset	= 0;
		if( uv )
		{
			uoffset	= uv->GetUOffs( t );
			voffset	= uv->GetVOffs( t );
		}
/*
		int	nTransparencyType = pStdMtl->GetTransparencyType();

		key.dwBlendMode = 0;
		switch( nTransparencyType )
		{
		case TRANSP_SUBTRACTIVE:
			key.dwBlendMode |= HR3D_MDX2_MODULATE;
			break;
		case TRANSP_ADDITIVE:
			key.dwBlendMode |= HR3D_MDX2_ADD;
			break;
		case TRANSP_FILTER:
			key.dwBlendMode |= HR3D_MDX2_MODULATE2X;
			break;
		default:
			break;
		};
*/
		key.dr = diffuse.r;
		key.dg = diffuse.g;
		key.db = diffuse.b;

		key.da = alpha;


		if( uv )
		{
			key.uoffset = uv->GetUOffs( t );
			key.voffset = uv->GetVOffs( t );
		}
		else
		{
			key.uoffset = 0;
			key.voffset = 0;
		}

		track.ColorKeyFrame.getReference(i) = key;
	}

	return true;
}
//----------------------------------------------------------------------------------
// dump material textures
void DumpTexture(m_material *pMat, IGameMaterial *pGMaxMat)
{
	std::vector<tex_channel>		bk_tex_channel;
	std::vector<unsigned int>		bk_tex_idx;
    std::vector<MatTextureInfo>		TexInfos;

	int texCount = pGMaxMat->GetNumberOfTextureMaps();

	for (int i = 0; i < texCount; ++i)
	{
		IGameTextureMap * pGMaxTex = pGMaxMat->GetIGameTextureMap(i);

		int tex_type = pGMaxTex->GetStdMapSlot();

		if (pGMaxTex->IsEntitySupported() && tex_type >= 0)	//its a bitmap texture
		{
			MatTextureInfo TexInfo;
			tex_channel tc;

			TexInfo.mat_id = pMat->id;

			m_texture * pTex = new m_texture;

			std::string pathname = pGMaxTex->GetBitmapFileName();

			int idx = (int)pathname.rfind('\\');
			if (idx == INDEX_NONE){
				idx = (int)pathname.rfind('/');
			}
			
			std::string filename = pathname.substr(idx + 1, INDEX_NONE);

			pTex->name = filename;

			// set the texture xform...
			IGameUVGen *pUVGen = pGMaxTex->GetIGameUVGen();
			GMatrix UVMat = pUVGen->GetUVTransform();
            TexInfo.tex_mat = pTex->tex_mat = (scalar*)UVMat.GetAddr(); // save mapping matrix

          	// get the uv channel to use...
			Texmap *pTMap = pGMaxTex->GetMaxTexmap();
			BitmapTex *pBTex = (BitmapTex*)pTMap;
			StdUVGen *pStdUVGen = pBTex->GetUVGen();

			if (pStdUVGen){
				tc.channel = pStdUVGen->GetMapChannel() - 1;
			}

			IParamBlock2 *pUVWCropParam = (IParamBlock2*)(pBTex->GetReference(1));

			if (pUVWCropParam)
			{
				 pUVWCropParam->GetValue(0, ExporterMAX::GetExporter()->GetStaticFrame(), TexInfo.uv_offset.x, FOREVER);
				 pUVWCropParam->GetValue(1, ExporterMAX::GetExporter()->GetStaticFrame(), TexInfo.uv_offset.y, FOREVER);
				 pUVWCropParam->GetValue(2, ExporterMAX::GetExporter()->GetStaticFrame(), TexInfo.uv_scale.x,  FOREVER);
				 pUVWCropParam->GetValue(3, ExporterMAX::GetExporter()->GetStaticFrame(), TexInfo.uv_scale.y,  FOREVER);
			}

			// set the type of texture...
			pTex->type = texture_type[tex_type];

 			// if we have a bump map, we create a normal map with the convention
 			// that the filename will be the same name as the bump map + "_normal" 
 			// appended to it.
  			if (pTex->type == m_texture::BUMP)
 			{
 				std::string normal_map = pTex->name;
 				std::string::size_type pos = normal_map.rfind(".");
 				normal_map.insert(pos, "_normal");
 
 				m_texture  *pTexNormal = new m_texture;
 				*pTexNormal = *pTex;
 
 				pTexNormal->name = normal_map;
 				pTexNormal->type = m_texture::NORMAL;
 
 				tc.pTex = pTexNormal;
 
 				bk_tex_channel.push_back(tc);	// add the new texture to the local TOC
 				TexInfos.push_back(TexInfo);
 			}

			 tc.pTex = pTex;
						 
			 bk_tex_channel.push_back(tc);	// add the new texture to the local TOC
			 TexInfos.push_back(TexInfo);
		}
	}

	// lets check if we don't have them already in our global TOC...
	for (size_t index = 0; index < bk_tex_channel.size(); ++index)
	{
		m_texture * pTex = bk_tex_channel[index].pTex;

		unsigned int idx = ExporterMAX::GetExporter()->FindTexture(pTex);
		
		if (idx == INDEX_NONE){	
			idx = ExporterMAX::GetExporter()->AddTexture(pTex); // add the new texture to the TOC
		}

		bk_tex_idx.push_back(idx);

		pMat->tex_channel.push_back(bk_tex_channel[index].channel);

		TexInfos[index].base_channel = bk_tex_channel[index].channel;

		bk_texs.insert(IdxBKTexMapPair(idx, TexInfos[index]));
	}

	// set the texture indices...
	for (size_t index = 0; index < bk_tex_idx.size(); ++index){
		pMat->textures.push_back(bk_tex_idx[index]);
	}
}
Texmap* NifImporter::CreateTexture(TexDesc& desc)
{
   BitmapManager *bmpMgr = TheManager;
   if (NiSourceTextureRef texSrc = desc.source){
      string filename = texSrc->GetTextureFileName();
      if (bmpMgr->CanImport(filename.c_str())){
         BitmapTex *bmpTex = NewDefaultBitmapTex();
         string name = texSrc->GetName();
         if (name.empty()) {
            TCHAR buffer[MAX_PATH];
            _tcscpy(buffer, PathFindFileName(filename.c_str()));
            PathRemoveExtension(buffer);
            name = buffer;
         }         
         bmpTex->SetName(name.c_str());
         bmpTex->SetMapName(const_cast<TCHAR*>(FindImage(filename).c_str()));
         bmpTex->SetAlphaAsMono(TRUE);
         bmpTex->SetAlphaSource(ALPHA_DEFAULT);

         switch (desc.filterMode)
         {
         case FILTER_TRILERP: bmpTex->SetFilterType(FILTER_PYR); break;
         case FILTER_BILERP:  bmpTex->SetFilterType(FILTER_SAT); break;
         case FILTER_NEAREST: bmpTex->SetFilterType(FILTER_NADA); break;
         }

         if (UVGen *uvGen = bmpTex->GetTheUVGen()){
            if (uvGen && uvGen->IsStdUVGen()) {
               StdUVGen *uvg = (StdUVGen*)uvGen;
               uvg->SetMapChannel(desc.uvSet + 1);
            }

            switch (desc.clampMode)
            {
            case WRAP_S_WRAP_T : uvGen->SetTextureTiling(3); break;
            case WRAP_S_CLAMP_T: uvGen->SetTextureTiling(1); break;
            case CLAMP_S_WRAP_T: uvGen->SetTextureTiling(2); break;
            case CLAMP_S_CLAMP_T:uvGen->SetTextureTiling(0); break;
            }

            if (desc.hasTextureTransform) {
               if (RefTargetHandle ref = uvGen->GetReference(0)){
                  TexCoord trans = desc.translation;
                  TexCoord tiling = desc.tiling;
                  float wangle = TODEG(desc.wRotation);

                  setMAXScriptValue(ref, "U_Offset", 0, trans.u);
                  setMAXScriptValue(ref, "V_Offset", 0, trans.v);
                  setMAXScriptValue(ref, "U_Tiling", 0, tiling.u);
                  setMAXScriptValue(ref, "V_Tiling", 0, tiling.v);
                  setMAXScriptValue(ref, "W_Angle", 0, wangle);
               }
            }
         }
		 if (showTextures) {
			 bmpTex->SetMtlFlag(MTL_TEX_DISPLAY_ENABLED, TRUE);
			 bmpTex->ActivateTexDisplay(TRUE);
			 bmpTex->NotifyDependents(FOREVER, PART_ALL, REFMSG_CHANGE);
		 }

         return bmpTex;
      }
   }
   return NULL;
}