//////////////////////////////////////////////////////////////////////////// // // Crytek Engine Source File. // Copyright (C), Crytek Studios, 2002. // ------------------------------------------------------------------------- // File name: MaterialDialog.cpp // Version: v1.00 // Created: 22/1/2003 by Timur. // Compilers: Visual Studio.NET // Description: // ------------------------------------------------------------------------- // History: // //////////////////////////////////////////////////////////////////////////// #include "StdAfx.h" #include "MaterialDialog.h" #include "StringDlg.h" #include "NumberDlg.h" #include "MaterialManager.h" #include "MaterialLibrary.h" #include "Material.h" #include "Objects\BrushObject.h" #include "Objects\Entity.h" #include "Objects\ObjectManager.h" #include "ViewManager.h" #include "Clipboard.h" #include "Controls\PropertyItem.h" #include //#include #include #define IDC_MATERIAL_TREE AFX_IDW_PANE_FIRST #define EDITOR_OBJECTS_PATH CString("Objects\\Editor\\") IMPLEMENT_DYNAMIC(CMaterialDialog,CBaseLibraryDialog); ////////////////////////////////////////////////////////////////////////// // Material structures. ////////////////////////////////////////////////////////////////////////// static struct { int texId; const char *name; } sUsedTextures[] = { { EFTT_DIFFUSE, "Diffuse" }, { EFTT_GLOSS, "Specular" }, { EFTT_BUMP, "Bumpmap" }, { EFTT_NORMALMAP, "Normalmap" }, { EFTT_CUBEMAP, "Cubemap" }, { EFTT_DETAIL_OVERLAY,"Detail" }, { EFTT_OPACITY, "Opacity" }, { EFTT_DECAL_OVERLAY, "Decal" }, { EFTT_SUBSURFACE, "SubSurface" }, }; #ifndef _countof #define _countof(array) (sizeof(array)/sizeof(array[0])) #endif struct STextureVars { CVariable texture; CVariable amount; CVariable is_tile[2]; CVariableEnum etcgentype; CVariableEnum etcmrotatetype; CVariableEnum etcmumovetype; CVariableEnum etcmvmovetype; CVariableEnum etextype; CVariable is_tcgprojected; CVariable tiling[3]; CVariable rotate[3]; CVariable offset[3]; CVariable tcmuoscrate; CVariable tcmvoscrate; CVariable tcmuoscamplitude; CVariable tcmvoscamplitude; CVariable tcmuoscphase; CVariable tcmvoscphase; CVariable tcmrotoscrate[3]; CVariable tcmrotoscamplitude[3]; CVariable tcmrotoscphase[3]; CVariable tcmrotosccenter[3]; CVariableArray tableTiling; CVariableArray tableOscillator; CVariableArray tableRotator; }; /** User Interface definition of material. */ struct CMaterialUI { CVariable shader; CVariable bLighting; CVariable bCastShadow; CVariable bAdditive; CVariable bAdditiveDecal; CVariable bWire; CVariable b2Sided; CVariable opacity; CVariable alphaTest; CVariable bAlwaysExport; ////////////////////////////////////////////////////////////////////////// // Lighting ////////////////////////////////////////////////////////////////////////// CVariable ambient; CVariable diffuse; CVariable specular; CVariable emissive; CVariable shininess; //!< Specular shininess. ////////////////////////////////////////////////////////////////////////// // Textures. ////////////////////////////////////////////////////////////////////////// CVariableArray textureVars[EFTT_MAX]; STextureVars textures[EFTT_MAX]; CVariableArray tableShader; CVariableArray tableOpacity; CVariableArray tableLighting; CVariableArray tableTexture; CVarEnumList enumTexType; CVarEnumList enumTexGenType; CVarEnumList enumTexModRotateType; CVarEnumList enumTexModUMoveType; CVarEnumList enumTexModVMoveType; ////////////////////////////////////////////////////////////////////////// int texUsageMask; CVarBlockPtr m_vars; IVariable::OnSetCallback m_onSetCallback; ////////////////////////////////////////////////////////////////////////// void SetFromMaterial( CMaterial *mtl ); void SetToMaterial( CMaterial *mtl ); void SetTextureNames( CMaterial *mtl ); void SetShaderResources( const SInputShaderResources &sr ); void GetShaderResources( SInputShaderResources &sr ); ////////////////////////////////////////////////////////////////////////// CVarBlock* CreateVars() { m_vars = new CVarBlock; ////////////////////////////////////////////////////////////////////////// // Init enums. ////////////////////////////////////////////////////////////////////////// enumTexType.AddRef(); // We not using pointer. enumTexType.AddItem( "Base",eTT_Base ); enumTexType.AddItem( "Cube-Map",eTT_Cubemap ); enumTexType.AddItem( "Auto Cube-Map",eTT_AutoCubemap ); enumTexType.AddItem( "Bumpmap",eTT_Bumpmap ); enumTexType.AddItem( "DUDVBumpmap",eTT_DSDTBump ); enumTexType.AddItem( "Rectangle",eTT_Rectangle ); enumTexGenType.AddRef(); // We not using pointer. enumTexGenType.AddItem( "Stream",ETG_Stream ); enumTexGenType.AddItem( "World",ETG_World ); enumTexGenType.AddItem( "Camera",ETG_Camera ); enumTexGenType.AddItem( "World Environment Map",ETG_WorldEnvMap ); enumTexGenType.AddItem( "Camera Environment Map",ETG_CameraEnvMap ); enumTexGenType.AddItem( "Normal Map",ETG_NormalMap ); enumTexGenType.AddItem( "Sphere Map",ETG_SphereMap ); enumTexModRotateType.AddRef(); // We not using pointer. enumTexModRotateType.AddItem( "No Change",ETMR_NoChange ); enumTexModRotateType.AddItem( "Fixed Rotation",ETMR_Fixed ); enumTexModRotateType.AddItem( "Constant Rotation",ETMR_Constant ); enumTexModRotateType.AddItem( "Oscillated Rotation",ETMR_Oscillated ); enumTexModUMoveType.AddRef(); // We not using pointer. enumTexModUMoveType.AddItem( "No Change",ETMM_NoChange ); enumTexModUMoveType.AddItem( "Fixed Moving",ETMM_Fixed ); enumTexModUMoveType.AddItem( "Constant Moving",ETMM_Constant ); enumTexModUMoveType.AddItem( "Jitter Moving",ETMM_Jitter ); enumTexModUMoveType.AddItem( "Pan Moving",ETMM_Pan ); enumTexModUMoveType.AddItem( "Stretch Moving",ETMM_Stretch ); enumTexModUMoveType.AddItem( "Stretch-Repeat Moving",ETMM_StretchRepeat ); enumTexModVMoveType.AddRef(); // We not using pointer. enumTexModVMoveType.AddItem( "No Change",ETMM_NoChange ); enumTexModVMoveType.AddItem( "Fixed Moving",ETMM_Fixed ); enumTexModVMoveType.AddItem( "Constant Moving",ETMM_Constant ); enumTexModVMoveType.AddItem( "Jitter Moving",ETMM_Jitter ); enumTexModVMoveType.AddItem( "Pan Moving",ETMM_Pan ); enumTexModVMoveType.AddItem( "Stretch Moving",ETMM_Stretch ); enumTexModVMoveType.AddItem( "Stretch-Repeat Moving",ETMM_StretchRepeat ); ////////////////////////////////////////////////////////////////////////// // Init tables. ////////////////////////////////////////////////////////////////////////// AddVariable( m_vars,tableShader,"Material Settings",IVariable::DT_SIMPLE ); AddVariable( m_vars,tableOpacity,"Opacity Settings",IVariable::DT_SIMPLE ); AddVariable( m_vars,tableLighting,"Lighting Settings",IVariable::DT_SIMPLE ); AddVariable( m_vars,tableTexture,"Texture Maps",IVariable::DT_SIMPLE ); ////////////////////////////////////////////////////////////////////////// // Shader. ////////////////////////////////////////////////////////////////////////// AddVariable( tableShader,shader,"Shader",IVariable::DT_SHADER ); AddVariable( tableShader,bAdditive,"Additive",IVariable::DT_SIMPLE ); AddVariable( tableShader,bWire,"Wireframe",IVariable::DT_SIMPLE ); AddVariable( tableShader,b2Sided,"2 Sided",IVariable::DT_SIMPLE ); AddVariable( tableShader,bCastShadow,"Cast Shadow",IVariable::DT_SIMPLE ); AddVariable( tableShader,bAlwaysExport,"Export Always" ); ////////////////////////////////////////////////////////////////////////// // Opacity. ////////////////////////////////////////////////////////////////////////// AddVariable( tableOpacity,opacity,"Opacity",IVariable::DT_PERCENT ); AddVariable( tableOpacity,alphaTest,"AlphaTest",IVariable::DT_PERCENT ); ////////////////////////////////////////////////////////////////////////// // Lighting. ////////////////////////////////////////////////////////////////////////// AddVariable( tableLighting,bLighting,"Enable Lighting",IVariable::DT_SIMPLE ); AddVariable( tableLighting,ambient,"Ambient",IVariable::DT_COLOR ); AddVariable( tableLighting,diffuse,"Diffuse",IVariable::DT_COLOR ); AddVariable( tableLighting,specular,"Specular",IVariable::DT_COLOR ); AddVariable( tableLighting,emissive,"Emissive",IVariable::DT_COLOR ); AddVariable( tableLighting,shininess,"Shininess",IVariable::DT_SIMPLE ); shininess.SetLimits( 0,1000 ); ////////////////////////////////////////////////////////////////////////// // Init texture variables. ////////////////////////////////////////////////////////////////////////// for (int i = 0; i < _countof(sUsedTextures); i++) { InitTextureVars( sUsedTextures[i].texId,sUsedTextures[i].name ); } return m_vars; } private: ////////////////////////////////////////////////////////////////////////// void InitTextureVars( int id,const CString &name ) { textureVars[id].SetFlags( IVariable::UI_BOLD ); AddVariable( tableTexture,textureVars[id],name,IVariable::DT_SIMPLE ); // Add variables from STextureVars structure. AddVariable( textureVars[id],textures[id].texture,"Texture",IVariable::DT_TEXTURE ); if (id == EFTT_BUMP || id == EFTT_CUBEMAP) { AddVariable( textureVars[id],textures[id].amount,"Amount" ); textures[id].amount.SetLimits( 0,255 ); } AddVariable( textureVars[id],textures[id].etextype,"TexType",IVariable::DT_SIMPLE ); if (id == EFTT_DECAL_OVERLAY) { AddVariable( textureVars[id],bAdditiveDecal,"Additive Decal",IVariable::DT_SIMPLE ); } AddVariable( textureVars[id],textures[id].is_tcgprojected,"IsProjectedTexGen",IVariable::DT_SIMPLE ); AddVariable( textureVars[id],textures[id].etcgentype,"TexGenType",IVariable::DT_SIMPLE ); ////////////////////////////////////////////////////////////////////////// // Tiling table. AddVariable( textureVars[id],textures[id].tableTiling,"Tiling" ); { CVariableArray& table = textures[id].tableTiling; table.SetFlags( IVariable::UI_BOLD ); AddVariable( table,textures[id].is_tile[0],"IsTileU" ); AddVariable( table,textures[id].is_tile[1],"IsTileV" ); AddVariable( table,textures[id].tiling[0],"TileU" ); AddVariable( table,textures[id].tiling[1],"TileV" ); AddVariable( table,textures[id].offset[0],"OffsetU" ); AddVariable( table,textures[id].offset[1],"OffsetV" ); AddVariable( table,textures[id].rotate[0],"RotateU" ); AddVariable( table,textures[id].rotate[1],"RotateV" ); AddVariable( table,textures[id].rotate[2],"RotateW" ); } ////////////////////////////////////////////////////////////////////////// // Rotator tables. AddVariable( textureVars[id],textures[id].tableRotator,"Rotator" ); { CVariableArray& table = textures[id].tableRotator; table.SetFlags( IVariable::UI_BOLD ); AddVariable( table,textures[id].etcmrotatetype,"Type" ); AddVariable( table,textures[id].tcmrotoscrate[0],"RateU" ); AddVariable( table,textures[id].tcmrotoscrate[1],"RateV" ); AddVariable( table,textures[id].tcmrotoscrate[2],"RateW" ); AddVariable( table,textures[id].tcmrotoscphase[0],"PhaseU" ); AddVariable( table,textures[id].tcmrotoscphase[1],"PhaseV" ); AddVariable( table,textures[id].tcmrotoscphase[2],"PhaseW" ); AddVariable( table,textures[id].tcmrotoscamplitude[0],"AmplitudeU" ); AddVariable( table,textures[id].tcmrotoscamplitude[1],"AmplitudeV" ); AddVariable( table,textures[id].tcmrotoscamplitude[2],"AmplitudeW" ); AddVariable( table,textures[id].tcmrotosccenter[0],"CenterU" ); AddVariable( table,textures[id].tcmrotosccenter[1],"CenterV" ); AddVariable( table,textures[id].tcmrotosccenter[2],"CenterW" ); } ////////////////////////////////////////////////////////////////////////// // Oscillator table AddVariable( textureVars[id],textures[id].tableOscillator,"Oscillator" ); { CVariableArray& table = textures[id].tableOscillator; table.SetFlags( IVariable::UI_BOLD ); AddVariable( table,textures[id].etcmumovetype,"TypeU" ); AddVariable( table,textures[id].etcmvmovetype,"TypeV" ); AddVariable( table,textures[id].tcmuoscrate,"RateU" ); AddVariable( table,textures[id].tcmvoscrate,"RateV" ); AddVariable( table,textures[id].tcmuoscphase,"PhaseU" ); AddVariable( table,textures[id].tcmvoscphase,"PhaseV" ); AddVariable( table,textures[id].tcmuoscamplitude,"AmplitudeU" ); AddVariable( table,textures[id].tcmvoscamplitude,"AmplitudeV" ); } ////////////////////////////////////////////////////////////////////////// // Assign enums tables to variable. ////////////////////////////////////////////////////////////////////////// textures[id].etextype.SetEnumList( &enumTexType ); textures[id].etcgentype.SetEnumList( &enumTexGenType ); textures[id].etcmrotatetype.SetEnumList( &enumTexModRotateType ); textures[id].etcmumovetype.SetEnumList( &enumTexModUMoveType ); textures[id].etcmvmovetype.SetEnumList( &enumTexModVMoveType ); } ////////////////////////////////////////////////////////////////////////// void AddVariable( CVariableArray &varArray,CVariableBase &var,const char *varName,unsigned char dataType=IVariable::DT_SIMPLE ) { var.AddRef(); // Variables are local and must not be released by CVarBlock. if (varName) var.SetName(varName); var.SetDataType(dataType); if (m_onSetCallback) var.AddOnSetCallback(m_onSetCallback); varArray.AddChildVar(&var); } ////////////////////////////////////////////////////////////////////////// void AddVariable( CVarBlock *vars,CVariableBase &var,const char *varName,unsigned char dataType=IVariable::DT_SIMPLE ) { var.AddRef(); // Variables are local and must not be released by CVarBlock. if (varName) var.SetName(varName); var.SetDataType(dataType); if (m_onSetCallback) var.AddOnSetCallback(m_onSetCallback); vars->AddVariable(&var); } void SetTextureResources( const SInputShaderResources &sr,int texid ); void GetTextureResources( SInputShaderResources &sr,int texid ); Vec3 ToVec3( const CFColor &col ) { return Vec3(col.r,col.g,col.b); } CFColor ToCFColor( const Vec3 &col ) { return CFColor(col); } }; ////////////////////////////////////////////////////////////////////////// void CMaterialUI::SetShaderResources( const SInputShaderResources &sr ) { opacity = sr.m_Opacity; alphaTest = sr.m_AlphaRef; ambient = ToVec3(sr.m_LMaterial->Front.m_Ambient); diffuse = ToVec3(sr.m_LMaterial->Front.m_Diffuse); specular = ToVec3(sr.m_LMaterial->Front.m_Specular); emissive = ToVec3(sr.m_LMaterial->Front.m_Emission); shininess = sr.m_LMaterial->Front.m_SpecShininess; if (!bLighting) { ambient.SetFlags( ambient.GetFlags()|IVariable::UI_DISABLED ); diffuse.SetFlags( diffuse.GetFlags()|IVariable::UI_DISABLED ); specular.SetFlags( specular.GetFlags()|IVariable::UI_DISABLED ); emissive.SetFlags( emissive.GetFlags()|IVariable::UI_DISABLED ); shininess.SetFlags( shininess.GetFlags()|IVariable::UI_DISABLED ); } else { ambient.SetFlags( ambient.GetFlags()&(~IVariable::UI_DISABLED) ); diffuse.SetFlags( diffuse.GetFlags()&(~IVariable::UI_DISABLED) ); specular.SetFlags( specular.GetFlags()&(~IVariable::UI_DISABLED) ); emissive.SetFlags( emissive.GetFlags()&(~IVariable::UI_DISABLED) ); shininess.SetFlags( shininess.GetFlags()&(~IVariable::UI_DISABLED) ); } for (int i = 0; i < _countof(sUsedTextures); i++) { SetTextureResources( sr,sUsedTextures[i].texId ); } } ////////////////////////////////////////////////////////////////////////// void CMaterialUI::GetShaderResources( SInputShaderResources &sr ) { sr.m_Opacity = opacity; sr.m_AlphaRef = alphaTest; sr.m_LMaterial->Front.m_Ambient = ToCFColor(ambient); sr.m_LMaterial->Front.m_Diffuse = ToCFColor(diffuse); sr.m_LMaterial->Front.m_Specular = ToCFColor(specular); sr.m_LMaterial->Front.m_Emission = ToCFColor(emissive); sr.m_LMaterial->Front.m_SpecShininess = shininess; for (int i = 0; i < _countof(sUsedTextures); i++) { GetTextureResources( sr,sUsedTextures[i].texId ); } } inline float RoundDegree( float val ) { //double v = floor(val*100.0f); //return v*0.01f; return (float)((int)(val*100+0.5f)) * 0.01f; } ////////////////////////////////////////////////////////////////////////// void CMaterialUI::SetTextureResources( const SInputShaderResources &sr,int tex ) { // Enable/Disable texture map, depending on the mask. int flags = textureVars[tex].GetFlags(); if ((1 << tex) & texUsageMask) flags &= ~IVariable::UI_DISABLED; else flags |= IVariable::UI_DISABLED; textureVars[tex].SetFlags( flags ); CString texFilename = sr.m_Textures[tex].m_Name.c_str(); textureVars[tex].Set( texFilename ); textures[tex].texture = texFilename; textures[tex].amount = sr.m_Textures[tex].m_Amount; textures[tex].is_tile[0] = sr.m_Textures[tex].m_bUTile; textures[tex].is_tile[1] = sr.m_Textures[tex].m_bVTile; textures[tex].tiling[0] = sr.m_Textures[tex].m_TexModificator.m_Tiling[0]; textures[tex].tiling[1] = sr.m_Textures[tex].m_TexModificator.m_Tiling[1]; textures[tex].offset[0] = sr.m_Textures[tex].m_TexModificator.m_Offs[0]; textures[tex].offset[1] = sr.m_Textures[tex].m_TexModificator.m_Offs[1]; textures[tex].etextype = sr.m_Textures[tex].m_TU.m_eTexType; textures[tex].etcgentype = sr.m_Textures[tex].m_TexModificator.m_eTGType; textures[tex].etcmumovetype = sr.m_Textures[tex].m_TexModificator.m_eUMoveType; textures[tex].etcmvmovetype = sr.m_Textures[tex].m_TexModificator.m_eVMoveType; textures[tex].etcmrotatetype = sr.m_Textures[tex].m_TexModificator.m_eRotType; textures[tex].is_tcgprojected = sr.m_Textures[tex].m_TexModificator.m_bTexGenProjected; textures[tex].tcmuoscrate = sr.m_Textures[tex].m_TexModificator.m_UOscRate; textures[tex].tcmuoscphase = sr.m_Textures[tex].m_TexModificator.m_UOscPhase; textures[tex].tcmuoscamplitude = sr.m_Textures[tex].m_TexModificator.m_UOscAmplitude; textures[tex].tcmvoscrate = sr.m_Textures[tex].m_TexModificator.m_VOscRate; textures[tex].tcmvoscphase = sr.m_Textures[tex].m_TexModificator.m_VOscPhase; textures[tex].tcmvoscamplitude = sr.m_Textures[tex].m_TexModificator.m_VOscAmplitude; for (int i=0; i<3; i++) { textures[tex].rotate[i] = RoundDegree(Word2Degr(sr.m_Textures[tex].m_TexModificator.m_Rot[i])); textures[tex].tcmrotoscrate[i] = RoundDegree(Word2Degr(sr.m_Textures[tex].m_TexModificator.m_RotOscRate[i])); textures[tex].tcmrotoscphase[i] = RoundDegree(Word2Degr(sr.m_Textures[tex].m_TexModificator.m_RotOscPhase[i])); textures[tex].tcmrotoscamplitude[i] = RoundDegree(Word2Degr(sr.m_Textures[tex].m_TexModificator.m_RotOscAmplitude[i])); textures[tex].tcmrotosccenter[i] = sr.m_Textures[tex].m_TexModificator.m_RotOscCenter[i]; } } ////////////////////////////////////////////////////////////////////////// void CMaterialUI::GetTextureResources( SInputShaderResources &sr,int tex ) { CString texName = textures[tex].texture; sr.m_Textures[tex].m_Name = (const char*)texName; sr.m_Textures[tex].m_Amount = textures[tex].amount; sr.m_Textures[tex].m_bUTile = textures[tex].is_tile[0]; sr.m_Textures[tex].m_bVTile = textures[tex].is_tile[1] ; sr.m_Textures[tex].m_TexModificator.m_bTexGenProjected = textures[tex].is_tcgprojected; sr.m_Textures[tex].m_TexModificator.m_Tiling[0] = textures[tex].tiling[0]; sr.m_Textures[tex].m_TexModificator.m_Tiling[1] = textures[tex].tiling[1]; sr.m_Textures[tex].m_TexModificator.m_Offs[0] = textures[tex].offset[0]; sr.m_Textures[tex].m_TexModificator.m_Offs[1] = textures[tex].offset[1]; sr.m_Textures[tex].m_TU.m_eTexType = textures[tex].etextype; sr.m_Textures[tex].m_TexModificator.m_eRotType = textures[tex].etcmrotatetype; sr.m_Textures[tex].m_TU.m_eTexType = textures[tex].etextype; sr.m_Textures[tex].m_TexModificator.m_eTGType = textures[tex].etcgentype; sr.m_Textures[tex].m_TexModificator.m_eUMoveType = textures[tex].etcmumovetype; sr.m_Textures[tex].m_TexModificator.m_eVMoveType = textures[tex].etcmvmovetype; sr.m_Textures[tex].m_TexModificator.m_UOscRate = textures[tex].tcmuoscrate; sr.m_Textures[tex].m_TexModificator.m_UOscPhase = textures[tex].tcmuoscphase; sr.m_Textures[tex].m_TexModificator.m_UOscAmplitude = textures[tex].tcmuoscamplitude; sr.m_Textures[tex].m_TexModificator.m_VOscRate = textures[tex].tcmvoscrate; sr.m_Textures[tex].m_TexModificator.m_VOscPhase = textures[tex].tcmvoscphase; sr.m_Textures[tex].m_TexModificator.m_VOscAmplitude = textures[tex].tcmvoscamplitude; for (int i=0; i<3; i++) { sr.m_Textures[tex].m_TexModificator.m_Rot[i] = Degr2Word(textures[tex].rotate[i]); sr.m_Textures[tex].m_TexModificator.m_RotOscRate[i] = Degr2Word(textures[tex].tcmrotoscrate[i]); sr.m_Textures[tex].m_TexModificator.m_RotOscPhase[i] = Degr2Word(textures[tex].tcmrotoscphase[i]); sr.m_Textures[tex].m_TexModificator.m_RotOscAmplitude[i] = Degr2Word(textures[tex].tcmrotoscamplitude[i]); sr.m_Textures[tex].m_TexModificator.m_RotOscCenter[i] = textures[tex].tcmrotosccenter[i]; } } void CMaterialUI::SetFromMaterial( CMaterial *mtl ) { shader = mtl->GetShaderName(); int mtlFlags = mtl->GetMaterialFlags(); bLighting = mtlFlags & CMaterial::MF_LIGHTING; bCastShadow = !(mtlFlags & CMaterial::MF_NOSHADOW); bAdditive = (mtlFlags & CMaterial::MF_ADDITIVE); bAdditiveDecal = (mtlFlags & CMaterial::MF_ADDITIVE_DECAL); bWire = (mtlFlags & CMaterial::MF_WIRE); b2Sided = (mtlFlags & CMaterial::MF_2SIDED); bAlwaysExport = mtlFlags & CMaterial::MF_ALWAYS_USED; texUsageMask = mtl->GetTexmapUsageMask(); // Detail and decal textures are always active. texUsageMask |= 1 << EFTT_DETAIL_OVERLAY; texUsageMask |= 1 << EFTT_DECAL_OVERLAY; if ((texUsageMask & (1<GetShaderResources() ); } void CMaterialUI::SetToMaterial( CMaterial *mtl ) { int mtlFlags = 0; if (bLighting) mtlFlags |= CMaterial::MF_LIGHTING; if (bAlwaysExport) mtlFlags |= CMaterial::MF_ALWAYS_USED; if (!bCastShadow) mtlFlags |= CMaterial::MF_NOSHADOW; if (bAdditive) mtlFlags |= CMaterial::MF_ADDITIVE; if (bAdditiveDecal) mtlFlags |= CMaterial::MF_ADDITIVE_DECAL; if (bWire) mtlFlags |= CMaterial::MF_WIRE; if (b2Sided) mtlFlags |= CMaterial::MF_2SIDED; mtl->SetMaterialFlags(mtlFlags); // If shader name is different reload shader. mtl->SetShaderName( shader ); GetShaderResources( mtl->GetShaderResources() ); mtl->Update(); } void CMaterialUI::SetTextureNames( CMaterial *mtl ) { SInputShaderResources &sr = mtl->GetShaderResources(); for (int i = 0; i < _countof(sUsedTextures); i++) { int tex = sUsedTextures[i].texId; CString texFilename = sr.m_Textures[tex].m_Name.c_str(); textureVars[tex].Set( texFilename ); } } static CMaterialUI gMatVars; ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// class CMtlPickCallback : public IPickObjectCallback { public: CMtlPickCallback() { m_bActive = true; }; //! Called when object picked. virtual void OnPick( CBaseObject *picked ) { m_bActive = false; CMaterial *pMtl = picked->GetMaterial(); if (pMtl) GetIEditor()->OpenDataBaseLibrary( EDB_MATERIAL_LIBRARY,pMtl ); delete this; } //! Called when pick mode cancelled. virtual void OnCancelPick() { m_bActive = false; delete this; } //! Return true if specified object is pickable. virtual bool OnPickFilter( CBaseObject *filterObject ) { // Check if object have material. if (filterObject->GetMaterial()) return true; else return false; } static bool IsActive() { return m_bActive; }; private: static bool m_bActive; }; bool CMtlPickCallback::m_bActive = false; ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// // CMaterialDialog implementation. ////////////////////////////////////////////////////////////////////////// CMaterialDialog::CMaterialDialog( CWnd *pParent ) : CBaseLibraryDialog(IDD_DB_ENTITY, pParent) { m_pMatManager = GetIEditor()->GetMaterialManager(); m_pItemManager = m_pMatManager; m_bRealtimePreviewUpdate = true; m_pGeometry = 0; m_pEntityRender = 0; m_publicVarsItems = 0; m_shaderGenParamsVars = 0; m_shaderGenParamsVarsItem = 0; m_drawType = DRAW_BOX; m_geometryFile = EDITOR_OBJECTS_PATH + "MtlBox.cgf"; m_bOwnGeometry = true; m_dragImage = 0; m_hDropItem = 0; // Immidiatly create dialog. Create( IDD_DB_ENTITY,pParent ); } CMaterialDialog::~CMaterialDialog() { } void CMaterialDialog::DoDataExchange(CDataExchange* pDX) { CBaseLibraryDialog::DoDataExchange(pDX); } BEGIN_MESSAGE_MAP(CMaterialDialog, CBaseLibraryDialog) ON_COMMAND( ID_DB_ADD,OnAddItem ) ON_COMMAND( ID_DB_PLAY,OnPlay ) ON_COMMAND( ID_DB_MTL_DRAWSELECTED,OnDrawSelection ) ON_COMMAND( ID_DB_MTL_DRAWBOX,OnDrawBox ) ON_COMMAND( ID_DB_MTL_DRAWSPHERE,OnDrawSphere ) ON_COMMAND( ID_DB_MTL_DRAWTEAPOT,OnDrawTeapot ) ON_UPDATE_COMMAND_UI( ID_DB_PLAY,OnUpdatePlay ) ON_COMMAND( ID_DB_SELECTASSIGNEDOBJECTS,OnSelectAssignedObjects ) ON_COMMAND( ID_DB_MTL_ASSIGNTOSELECTION,OnAssignMaterialToSelection ) ON_COMMAND( ID_DB_MTL_GETFROMSELECTION,OnGetMaterialFromSelection ) ON_COMMAND( ID_DB_MTL_RESETMATERIAL,OnResetMaterialOnSelection ) ON_UPDATE_COMMAND_UI( ID_DB_MTL_ASSIGNTOSELECTION,OnUpdateAssignMtlToSelection ) ON_UPDATE_COMMAND_UI( ID_DB_SELECTASSIGNEDOBJECTS,OnUpdateMtlSelected ) ON_UPDATE_COMMAND_UI( ID_DB_MTL_GETFROMSELECTION,OnUpdateObjectSelected ) ON_UPDATE_COMMAND_UI( ID_DB_MTL_RESETMATERIAL,OnUpdateObjectSelected ) ON_COMMAND( ID_DB_MTL_ADDSUBMTL,OnAddSubMtl ) ON_COMMAND( ID_DB_MTL_DELSUBMTL,OnDelSubMtl ) ON_UPDATE_COMMAND_UI( ID_DB_MTL_ADDSUBMTL,OnUpdateMtlSelected ) ON_UPDATE_COMMAND_UI( ID_DB_MTL_DELSUBMTL,OnUpdateMtlSelected ) ON_COMMAND( ID_DB_MTL_PICK,OnPickMtl ) ON_UPDATE_COMMAND_UI( ID_DB_MTL_PICK,OnUpdatePickMtl ) ON_COMMAND( ID_DB_MTL_GENCUBEMAP,OnGenCubemap ) ON_NOTIFY(TVN_BEGINDRAG, IDC_MATERIAL_TREE, OnBeginDrag) ON_NOTIFY(NM_RCLICK , IDC_MATERIAL_TREE, OnNotifyMtlTreeRClick) ON_WM_SIZE() ON_WM_DESTROY() ON_WM_MOUSEMOVE() ON_WM_LBUTTONUP() END_MESSAGE_MAP() ////////////////////////////////////////////////////////////////////////// void CMaterialDialog::OnDestroy() { int temp; int HSplitter,VSplitter; m_wndHSplitter.GetRowInfo( 0,HSplitter,temp ); m_wndVSplitter.GetColumnInfo( 0,VSplitter,temp ); AfxGetApp()->WriteProfileInt("Dialogs\\Materials","HSplitter",HSplitter ); AfxGetApp()->WriteProfileInt("Dialogs\\Materials","VSplitter",VSplitter ); ReleaseGeometry(); CBaseLibraryDialog::OnDestroy(); } // CTVSelectKeyDialog message handlers BOOL CMaterialDialog::OnInitDialog() { CBaseLibraryDialog::OnInitDialog(); InitToolbar(); CRect rc; GetClientRect(rc); //int h2 = rc.Height()/2; int h2 = 200; int HSplitter = AfxGetApp()->GetProfileInt("Dialogs\\Materials","HSplitter",200 ); int VSplitter = AfxGetApp()->GetProfileInt("Dialogs\\Materials","VSplitter",200 ); m_wndVSplitter.CreateStatic( this,1,2,WS_CHILD|WS_VISIBLE ); m_wndHSplitter.CreateStatic( &m_wndVSplitter,2,1,WS_CHILD|WS_VISIBLE ); //m_imageList.Create(IDB_MATERIAL_TREE, 16, 1, RGB (255, 0, 255)); CMFCUtils::LoadTrueColorImageList( m_imageList,IDB_MATERIAL_TREE,16,RGB(255,0,255) ); // TreeCtrl must be already created. m_treeCtrl.SetParent( &m_wndVSplitter ); m_treeCtrl.SetImageList(&m_imageList,TVSIL_NORMAL); m_previewCtrl.Create( &m_wndHSplitter,rc,WS_CHILD|WS_VISIBLE ); m_previewCtrl.SetGrid(true); m_previewCtrl.EnableUpdate( true ); m_propsCtrl.Create( WS_VISIBLE|WS_CHILD|WS_BORDER,rc,&m_wndHSplitter,2 ); m_vars = gMatVars.CreateVars(); m_propsCtrl.AddVarBlock( m_vars ); m_propsCtrl.EnableWindow(FALSE); m_wndHSplitter.SetPane( 0,0,&m_previewCtrl,CSize(100,HSplitter) ); m_wndHSplitter.SetPane( 1,0,&m_propsCtrl,CSize(100,HSplitter) ); m_wndVSplitter.SetPane( 0,0,&m_treeCtrl,CSize(VSplitter,100) ); m_wndVSplitter.SetPane( 0,1,&m_wndHSplitter,CSize(VSplitter,100) ); RecalcLayout(); ReloadLibs(); return TRUE; // return TRUE unless you set the focus to a control // EXCEPTION: OCX Property Pages should return FALSE } ////////////////////////////////////////////////////////////////////////// UINT CMaterialDialog::GetDialogMenuID() { return IDR_DB_ENTITY; }; ////////////////////////////////////////////////////////////////////////// // Create the toolbar void CMaterialDialog::InitToolbar() { VERIFY( m_toolbar.CreateEx(this, TBSTYLE_FLAT|TBSTYLE_WRAPABLE, WS_CHILD|WS_VISIBLE|CBRS_TOP|CBRS_TOOLTIPS|CBRS_FLYBY|CBRS_SIZE_DYNAMIC) ); VERIFY( m_toolbar.LoadToolBar24(IDR_DB_MATERIAL_BAR) ); // Resize the toolbar CRect rc; GetClientRect(rc); m_toolbar.SetWindowPos(NULL, 0, 0, rc.right, 70, SWP_NOZORDER); CSize sz = m_toolbar.CalcDynamicLayout(TRUE,TRUE); m_toolbar.SetButtonStyle( m_toolbar.CommandToIndex(ID_DB_PLAY),TBBS_CHECKBOX ); CBaseLibraryDialog::InitToolbar(); } ////////////////////////////////////////////////////////////////////////// void CMaterialDialog::OnSize(UINT nType, int cx, int cy) { // resize splitter window. if (m_wndVSplitter.m_hWnd) { CRect rc; GetClientRect(rc); m_wndVSplitter.MoveWindow(rc,FALSE); } CBaseLibraryDialog::OnSize(nType, cx, cy); } ////////////////////////////////////////////////////////////////////////// void CMaterialDialog::OnNewDocument() { ReleaseGeometry(); CBaseLibraryDialog::OnNewDocument(); }; ////////////////////////////////////////////////////////////////////////// void CMaterialDialog::OnLoadDocument() { ReleaseGeometry(); CBaseLibraryDialog::OnLoadDocument(); } ////////////////////////////////////////////////////////////////////////// void CMaterialDialog::OnCloseDocument() { ReleaseGeometry(); CBaseLibraryDialog::OnCloseDocument(); } ////////////////////////////////////////////////////////////////////////// HTREEITEM CMaterialDialog::InsertItemToTree( CBaseLibraryItem *pItem,HTREEITEM hParent ) { CMaterial *pMtl = (CMaterial*)pItem; if (pMtl->GetParent()) { if (!hParent || hParent == TVI_ROOT || m_treeCtrl.GetItemData(hParent) == 0) return 0; } HTREEITEM hMtlItem = CBaseLibraryDialog::InsertItemToTree( pItem,hParent ); for (int i = 0; i < pMtl->GetSubMaterialCount(); i++) { CMaterial *pSubMtl = pMtl->GetSubMaterial(i); CBaseLibraryDialog::InsertItemToTree( pSubMtl,hMtlItem ); } return hMtlItem; } ////////////////////////////////////////////////////////////////////////// void CMaterialDialog::OnAddItem() { if (!m_pLibrary) return; CStringGroupDlg dlg( _T("New Material Name"),this ); dlg.SetGroup( m_selectedGroup ); //dlg.SetString( entityClass ); if (dlg.DoModal() != IDOK || dlg.GetString().IsEmpty()) { return; } CString fullName = m_pItemManager->MakeFullItemName( m_pLibrary,dlg.GetGroup(),dlg.GetString() ); if (m_pItemManager->FindItemByName( fullName )) { Warning( "Material with name %s already exist",(const char*)fullName ); return; } CMaterial *mtl = (CMaterial*)m_pItemManager->CreateItem( m_pLibrary ); // Make prototype name. SetItemName( mtl,dlg.GetGroup(),dlg.GetString() ); mtl->Update(); ReloadItems(); SelectItem( mtl ); } ////////////////////////////////////////////////////////////////////////// void CMaterialDialog::SetMaterialVars( CMaterial *mtl ) { } ////////////////////////////////////////////////////////////////////////// void CMaterialDialog::SelectItem( CBaseLibraryItem *item,bool bForceReload ) { bool bChanged = item != m_pCurrentItem || bForceReload; CBaseLibraryDialog::SelectItem( item,bForceReload ); if (!bChanged) return; // Empty preview control. m_previewCtrl.SetEntity(0); m_pMatManager->SetCurrentMaterial( (CMaterial*)item ); if (!item) { m_propsCtrl.EnableWindow(FALSE); return; } if (!m_pEntityRender) { LoadGeometry( m_geometryFile ); } if (m_pEntityRender) m_previewCtrl.SetEntity( m_pEntityRender ); m_propsCtrl.EnableWindow(TRUE); m_propsCtrl.EnableUpdateCallback(false); // Render preview geometry with current material CMaterial *mtl = GetSelectedMaterial(); AssignMtlToGeometry(); // Update variables. m_propsCtrl.EnableUpdateCallback(false); gMatVars.SetFromMaterial( mtl ); m_propsCtrl.EnableUpdateCallback(true); //gMatVars.m_onSetCallback = functor(*this,OnUpdateProperties); ////////////////////////////////////////////////////////////////////////// if (m_publicVarsItems) { m_propsCtrl.DeleteItem( m_publicVarsItems ); m_publicVarsItems = 0; } m_publicVars = mtl->GetPublicVars(); if (m_publicVars) { m_publicVarsItems = m_propsCtrl.AddVarBlock( m_publicVars,"Shader Params" ); } ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// // Set Shader Gen Params. ////////////////////////////////////////////////////////////////////////// if (m_shaderGenParamsVarsItem) m_propsCtrl.DeleteItem(m_shaderGenParamsVarsItem); m_shaderGenParamsVarsItem = 0; m_shaderGenParamsVars = mtl->GetShaderGenParamsVars(); if (m_shaderGenParamsVars) m_shaderGenParamsVarsItem = m_propsCtrl.AddVarBlock( m_shaderGenParamsVars,"Shader Generation Params" ); ////////////////////////////////////////////////////////////////////////// m_propsCtrl.ExpandAllChilds( m_propsCtrl.GetRootItem(),false ); m_propsCtrl.SetUpdateCallback( functor(*this, &CMaterialDialog::OnUpdateProperties) ); m_propsCtrl.EnableUpdateCallback(true); } ////////////////////////////////////////////////////////////////////////// void CMaterialDialog::Update() { if (!m_bRealtimePreviewUpdate) return; // Update preview control. if (m_pEntityRender) { m_previewCtrl.Update(); } } ////////////////////////////////////////////////////////////////////////// void CMaterialDialog::OnUpdateProperties( IVariable *var ) { CMaterial *mtl = GetSelectedMaterial(); if (!mtl) return; bool bLightingOnChanged = &gMatVars.bLighting == var; bool bShaderChanged = (var == &gMatVars.shader); bool bShaderGenMaskChanged = false; ////////////////////////////////////////////////////////////////////////// // Assign modified Shader Gen Params to shader. ////////////////////////////////////////////////////////////////////////// if (m_shaderGenParamsVarsItem != NULL && m_shaderGenParamsVars != NULL && !bShaderChanged) { unsigned int mask = mtl->GetShaderGenMask(); mtl->SetShaderGenParamsVars(m_shaderGenParamsVars); if (mask != mtl->GetShaderGenMask()) { // If mask changed new shader have been created. bShaderGenMaskChanged = true; } } ////////////////////////////////////////////////////////////////////////// // Assign new public vars to material. if (m_publicVarsItems != NULL && m_publicVars != NULL) { if (!bShaderChanged && !bShaderGenMaskChanged) { // No need to change public vars. mtl->SetPublicVars( m_publicVars ); } } gMatVars.SetToMaterial( mtl ); if (bShaderChanged || bLightingOnChanged || bShaderGenMaskChanged) { gMatVars.SetFromMaterial( mtl ); } gMatVars.SetTextureNames( mtl ); AssignMtlToGeometry(); // When shader changed. if (bShaderChanged || bShaderGenMaskChanged) { // Delete old public params and add new ones. if (m_publicVarsItems) { m_propsCtrl.DeleteItem( m_publicVarsItems ); m_publicVarsItems = 0; } m_publicVars = mtl->GetPublicVars(); if (m_publicVars) { m_publicVarsItems = m_propsCtrl.AddVarBlock( m_publicVars,"Shader Params" ); m_propsCtrl.Expand( m_publicVarsItems,true ); } ////////////////////////////////////////////////////////////////////////// // Set Shader Gen Params. ////////////////////////////////////////////////////////////////////////// if (!bShaderGenMaskChanged) { if (m_shaderGenParamsVarsItem) m_propsCtrl.DeleteItem(m_shaderGenParamsVarsItem); m_shaderGenParamsVarsItem = 0; m_shaderGenParamsVars = mtl->GetShaderGenParamsVars(); if (m_shaderGenParamsVars) m_shaderGenParamsVarsItem = m_propsCtrl.AddVarBlock( m_shaderGenParamsVars,"Shader Generation Params" ); } ////////////////////////////////////////////////////////////////////////// } if (bLightingOnChanged || bShaderGenMaskChanged || bShaderChanged) m_propsCtrl.Invalidate(); GetIEditor()->SetModifiedFlag(); } ////////////////////////////////////////////////////////////////////////// void CMaterialDialog::OnPlay() { m_bRealtimePreviewUpdate = !m_bRealtimePreviewUpdate; } ////////////////////////////////////////////////////////////////////////// void CMaterialDialog::OnUpdatePlay( CCmdUI* pCmdUI ) { if (m_bRealtimePreviewUpdate) pCmdUI->SetCheck(TRUE); else pCmdUI->SetCheck(FALSE); } ////////////////////////////////////////////////////////////////////////// CMaterial* CMaterialDialog::GetSelectedMaterial() { CBaseLibraryItem *pItem = m_pCurrentItem; return (CMaterial*)pItem; } ////////////////////////////////////////////////////////////////////////// IStatObj* CMaterialDialog::GetGeometryFromObject( CBaseObject *pObject ) { assert( pObject ); if (pObject->IsKindOf(RUNTIME_CLASS(CBrushObject))) { CBrushObject *pBrushObj = (CBrushObject*)pObject; return pBrushObj->GetPrefabGeom(); } if (pObject->IsKindOf(RUNTIME_CLASS(CEntity))) { CEntity *pEntityObj = (CEntity*)pObject; if (pEntityObj->GetIEntity()) { IEntity *pGameEntity = pEntityObj->GetIEntity(); for (int i = 0; i < pGameEntity->GetNumObjects(); i++) { IStatObj *pStatObj = pGameEntity->GetIStatObj(i); if (pStatObj) return pStatObj; } } } return 0; } ////////////////////////////////////////////////////////////////////////// ICryCharInstance* CMaterialDialog::GetCharacterFromObject( CBaseObject *pObject ) { if (pObject->IsKindOf(RUNTIME_CLASS(CEntity))) { CEntity *pEntityObj = (CEntity*)pObject; if (pEntityObj->GetIEntity()) { IEntity *pGameEntity = pEntityObj->GetIEntity(); ICryCharInstance *pCharacter = pGameEntity->GetCharInterface()->GetCharacter(0); if (pCharacter) return pCharacter; pCharacter = pGameEntity->GetCharInterface()->GetCharacter(1); if (pCharacter) return pCharacter; /* for (int i = 0; i < pGameEntity->GetNumObjects(); i++) { ICryCharInstance *pCharacter = pGameEntity->GetCharInterface()->GetCharacter(i); if (pCharacter) return pCharacter; } */ } } return 0; } ////////////////////////////////////////////////////////////////////////// void CMaterialDialog::OnDrawSelection() { //if (m_drawType == DRAW_SELECTION) //return; m_drawType = DRAW_SELECTION; m_geometryFile = ""; ReleaseGeometry(); m_bOwnGeometry = false; CSelectionGroup *pSel = GetIEditor()->GetSelection(); if (!pSel->IsEmpty()) { IStatObj *pGeometry = GetGeometryFromObject( pSel->GetObject(0) ); if (pGeometry) { LoadGeometry( pGeometry->GetFileName() ); } AssignMtlToGeometry(); } } ////////////////////////////////////////////////////////////////////////// void CMaterialDialog::OnDrawBox() { if (m_drawType == DRAW_BOX) return; m_drawType = DRAW_BOX; LoadGeometry( EDITOR_OBJECTS_PATH+"MtlBox.cgf" ); } ////////////////////////////////////////////////////////////////////////// void CMaterialDialog::OnDrawSphere() { if (m_drawType == DRAW_SPHERE) return; m_drawType = DRAW_SPHERE; LoadGeometry( EDITOR_OBJECTS_PATH+"MtlSphere.cgf" ); } ////////////////////////////////////////////////////////////////////////// void CMaterialDialog::OnDrawTeapot() { if (m_drawType == DRAW_TEAPOT) return; m_drawType = DRAW_TEAPOT; LoadGeometry( EDITOR_OBJECTS_PATH+"MtlTeapot.cgf" ); } ////////////////////////////////////////////////////////////////////////// void CMaterialDialog::LoadGeometry( const CString &filename ) { m_geometryFile = filename; ReleaseGeometry(); m_bOwnGeometry = true; m_pGeometry = GetIEditor()->Get3DEngine()->MakeObject( m_geometryFile ); if (m_pGeometry) { m_pEntityRender = GetIEditor()->Get3DEngine()->CreateEntityRender(); m_pEntityRender->SetEntityStatObj( 0,m_pGeometry ); m_previewCtrl.SetEntity( m_pEntityRender ); AssignMtlToGeometry(); } } ////////////////////////////////////////////////////////////////////////// void CMaterialDialog::ReleaseGeometry() { m_previewCtrl.SetEntity(0); if (m_pEntityRender) { GetIEditor()->Get3DEngine()->DeleteEntityRender(m_pEntityRender); m_pEntityRender = 0; } if (m_pGeometry) { // Load test geometry. GetIEditor()->Get3DEngine()->ReleaseObject( m_pGeometry ); } m_pGeometry = 0; } ////////////////////////////////////////////////////////////////////////// void CMaterialDialog::AssignMtlToGeometry() { if (!m_pEntityRender) return; CMaterial *mtl = GetSelectedMaterial(); if (!mtl) return; mtl->AssignToEntity( m_pEntityRender ); } ////////////////////////////////////////////////////////////////////////// void CMaterialDialog::OnAssignMaterialToSelection() { CMaterial *pMtl = GetSelectedMaterial(); if (!pMtl) return; // Only assign most parent material. if (pMtl->GetParent()) pMtl = pMtl->GetParent(); CUndo undo( "Assign Material" ); CSelectionGroup *pSel = GetIEditor()->GetSelection(); if (!pSel->IsEmpty()) { for (int i = 0; i < pSel->GetCount(); i++) { pSel->GetObject(i)->SetMaterial( pMtl ); } } } ////////////////////////////////////////////////////////////////////////// void CMaterialDialog::OnSelectAssignedObjects() { CMaterial *pMtl = GetSelectedMaterial(); if (!pMtl) return; CBaseObjectsArray objects; GetIEditor()->GetObjectManager()->GetObjects( objects ); for (int i = 0; i < objects.size(); i++) { CBaseObject *pObject = objects[i]; if (pObject->GetMaterial() != pMtl) continue; if (pObject->IsHidden() || pObject->IsFrozen()) continue; GetIEditor()->GetObjectManager()->SelectObject( pObject ); } } ////////////////////////////////////////////////////////////////////////// void CMaterialDialog::OnResetMaterialOnSelection() { CUndo undo( "Reset Material" ); CSelectionGroup *pSel = GetIEditor()->GetSelection(); if (!pSel->IsEmpty()) { for (int i = 0; i < pSel->GetCount(); i++) { pSel->GetObject(i)->SetMaterial( 0 ); } } } ////////////////////////////////////////////////////////////////////////// void CMaterialDialog::OnGetMaterialFromSelection() { if (!m_pLibrary) return; CSelectionGroup *pSel = GetIEditor()->GetSelection(); if (pSel->IsEmpty()) return; for (int i = 0; i < pSel->GetCount(); i++) { CMaterial *pMtl = pSel->GetObject(i)->GetMaterial(); if (pMtl) { SelectItem( pMtl ); return; } } IStatObj *pGeometry = GetGeometryFromObject( pSel->GetObject(0) ); ICryCharInstance* pCharacter = GetCharacterFromObject( pSel->GetObject(0) ); if (!pGeometry && !pCharacter) return; // If nothing was selected. if (IDNO == AfxMessageBox( _T("Selected Object does not have Material\r\nDo you want to create Material for it?"),MB_YESNO|MB_APPLMODAL|MB_ICONQUESTION )) { return; } CStringGroupDlg dlg( _T("New Material Name"),this ); dlg.SetGroup( m_selectedGroup ); CString uniqName; if (pCharacter) { uniqName = m_pItemManager->MakeUniqItemName(Path::GetFileName(pCharacter->GetModel()->GetFileName())); } else if (pGeometry) { uniqName = m_pItemManager->MakeUniqItemName(Path::GetFileName(pGeometry->GetFileName())); } dlg.SetString( uniqName ); if (dlg.DoModal() != IDOK || dlg.GetString().IsEmpty()) { return; } // Make new material from this object. CMaterial *mtl = (CMaterial*)m_pItemManager->CreateItem( m_pLibrary ); // Make prototype name. SetItemName( mtl,dlg.GetGroup(),dlg.GetString() ); if (pCharacter) { mtl->AssignFromGeometry( pCharacter ); } else if (pGeometry) { mtl->AssignFromGeometry( pGeometry ); } mtl->Update(); pSel->GetObject(0)->SetMaterial( mtl ); ReloadItems(); SelectItem( mtl ); } ////////////////////////////////////////////////////////////////////////// void CMaterialDialog::OnAddSubMtl() { CMaterial *pMtl = GetSelectedMaterial(); if (!pMtl) return; if (pMtl->GetParent()) pMtl = pMtl->GetParent(); CUndo undo( "Add Sub Material" ); CString mtlName; mtlName.Format( "[%d]",pMtl->GetSubMaterialCount()+1 ); //CMaterial *pSubMtl = m_pItemManager->CreateMaterial( m_selectedLib ); CMaterial *pSubMtl = new CMaterial; pSubMtl->GenerateId(); pMtl->AddSubMaterial( pSubMtl ); pSubMtl->SetName( mtlName ); pSubMtl->Update(); ReloadItems(); SelectItem( pSubMtl ); } ////////////////////////////////////////////////////////////////////////// void CMaterialDialog::OnDelSubMtl() { CMaterial *pSubMtl = GetSelectedMaterial(); if (!pSubMtl) return; CUndo undo( "Remove Sub Material" ); CMaterial *pMtl = pSubMtl->GetParent(); if (pMtl) { pMtl->RemoveSubMaterial(pSubMtl); m_pItemManager->DeleteItem( pSubMtl ); ReloadItems(); SelectItem( pMtl ); } } ////////////////////////////////////////////////////////////////////////// void CMaterialDialog::DeleteItem( CBaseLibraryItem *pItem ) { CMaterial* pMtl = (CMaterial*)pItem; CMaterial *pParentMtl = pMtl->GetParent(); if (pParentMtl) { CUndo undo( "Remove Sub Material" ); pParentMtl->RemoveSubMaterial(pMtl); m_pItemManager->DeleteItem( pMtl ); } else { CUndo undo( "Remove Material" ); m_pItemManager->DeleteItem( pItem ); } } ////////////////////////////////////////////////////////////////////////// void CMaterialDialog::OnUpdateMtlSelected( CCmdUI* pCmdUI ) { if (GetSelectedMaterial()) { pCmdUI->Enable( TRUE ); } else { pCmdUI->Enable( FALSE ); } } ////////////////////////////////////////////////////////////////////////// void CMaterialDialog::OnUpdateAssignMtlToSelection( CCmdUI* pCmdUI ) { if (GetSelectedMaterial() && !GetIEditor()->GetSelection()->IsEmpty()) { pCmdUI->Enable( TRUE ); } else { pCmdUI->Enable( FALSE ); } } ////////////////////////////////////////////////////////////////////////// void CMaterialDialog::OnUpdateObjectSelected( CCmdUI* pCmdUI ) { if (!GetIEditor()->GetSelection()->IsEmpty()) { pCmdUI->Enable( TRUE ); } else { pCmdUI->Enable( FALSE ); } } ////////////////////////////////////////////////////////////////////////// void CMaterialDialog::OnBeginDrag(NMHDR* pNMHDR, LRESULT* pResult) { NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR; HTREEITEM hItem = pNMTreeView->itemNew.hItem; CMaterial* pMtl = (CMaterial*)m_treeCtrl.GetItemData(hItem); if (!pMtl) return; m_pDraggedMtl = pMtl; m_treeCtrl.Select( hItem,TVGN_CARET ); m_hDropItem = 0; m_dragImage = m_treeCtrl.CreateDragImage( hItem ); if (m_dragImage) { m_hDraggedItem = hItem; m_hDropItem = hItem; m_dragImage->BeginDrag(0, CPoint(-10, -10)); CRect rc; AfxGetMainWnd()->GetWindowRect( rc ); CPoint p = pNMTreeView->ptDrag; ClientToScreen( &p ); p.x -= rc.left; p.y -= rc.top; m_dragImage->DragEnter( AfxGetMainWnd(),p ); SetCapture(); GetIEditor()->EnableUpdate( false ); } *pResult = 0; } ////////////////////////////////////////////////////////////////////////// void CMaterialDialog::OnMouseMove(UINT nFlags, CPoint point) { if (m_dragImage) { CPoint p; p = point; ClientToScreen( &p ); m_treeCtrl.ScreenToClient( &p ); TVHITTESTINFO hit; ZeroStruct(hit); hit.pt = p; HTREEITEM hHitItem = m_treeCtrl.HitTest( &hit ); if (hHitItem) { if (m_hDropItem != hHitItem) { if (m_hDropItem) m_treeCtrl.SetItem( m_hDropItem,TVIF_STATE,0,0,0,0,TVIS_DROPHILITED,0 ); // Set state of this item to drop target. m_treeCtrl.SetItem( hHitItem,TVIF_STATE,0,0,0,TVIS_DROPHILITED,TVIS_DROPHILITED,0 ); m_hDropItem = hHitItem; m_treeCtrl.Invalidate(); } } CRect rc; AfxGetMainWnd()->GetWindowRect( rc ); p = point; ClientToScreen( &p ); p.x -= rc.left; p.y -= rc.top; m_dragImage->DragMove( p ); SetCursor( m_hCursorDefault ); // Check if can drop here. { CPoint p; GetCursorPos( &p ); CViewport* viewport = GetIEditor()->GetViewManager()->GetViewportAtPoint( p ); if (viewport) { CPoint vp = p; viewport->ScreenToClient(&vp); ObjectHitInfo hit( viewport,vp ); if (viewport->HitTest( vp,hit,0 )) { if (hit.object) { SetCursor( m_hCursorReplace ); } } } } } CBaseLibraryDialog::OnMouseMove(nFlags, point); } ////////////////////////////////////////////////////////////////////////// void CMaterialDialog::OnLButtonUp(UINT nFlags, CPoint point) { //CXTResizeDialog::OnLButtonUp(nFlags, point); if (m_hDropItem) { m_treeCtrl.SetItem( m_hDropItem,TVIF_STATE,0,0,0,0,TVIS_DROPHILITED,0 ); m_hDropItem = 0; } if (m_dragImage) { CPoint p; GetCursorPos( &p ); GetIEditor()->EnableUpdate( true ); m_dragImage->DragLeave( AfxGetMainWnd() ); m_dragImage->EndDrag(); delete m_dragImage; m_dragImage = 0; ReleaseCapture(); CPoint treepoint = p; m_treeCtrl.ScreenToClient( &treepoint ); TVHITTESTINFO hit; ZeroStruct(hit); hit.pt = treepoint; HTREEITEM hHitItem = m_treeCtrl.HitTest( &hit ); if (hHitItem) { DropToItem( hHitItem,m_hDraggedItem,m_pDraggedMtl ); m_hDraggedItem = 0; m_pDraggedMtl = 0; return; } CWnd *wnd = WindowFromPoint( p ); CUndo undo( "Assign Material" ); CViewport* viewport = GetIEditor()->GetViewManager()->GetViewportAtPoint( p ); if (viewport) { CPoint vp = p; viewport->ScreenToClient(&vp); // Drag and drop into one of views. // Start object creation. ObjectHitInfo hit( viewport,vp ); if (viewport->HitTest( vp,hit,0 )) { if (hit.object) { // Only parent can be assigned. CMaterial *pMtl = m_pDraggedMtl; if (pMtl->GetParent()) { pMtl = pMtl->GetParent(); } hit.object->SetMaterial(pMtl); } } } m_pDraggedMtl = 0; } m_hDraggedItem = 0; CBaseLibraryDialog::OnLButtonUp(nFlags, point); } ////////////////////////////////////////////////////////////////////////// void CMaterialDialog::OnNotifyMtlTreeRClick(NMHDR* pNMHDR, LRESULT* pResult) { // Show helper menu. CPoint point; CMaterial *pMtl = 0; // Find node under mouse. GetCursorPos( &point ); m_treeCtrl.ScreenToClient( &point ); // Select the item that is at the point myPoint. UINT uFlags; HTREEITEM hItem = m_treeCtrl.HitTest(point,&uFlags); if ((hItem != NULL) && (TVHT_ONITEM & uFlags)) { pMtl = (CMaterial*)m_treeCtrl.GetItemData(hItem); } if (!pMtl) return; SelectItem( pMtl ); // Create pop up menu. CMenu menu; menu.CreatePopupMenu(); if (pMtl) { CClipboard clipboard; bool bNoPaste = clipboard.IsEmpty(); int pasteFlags = 0; if (bNoPaste) pasteFlags |= MF_GRAYED; menu.AppendMenu( MF_STRING,ID_DB_CUT,"Cut" ); menu.AppendMenu( MF_STRING,ID_DB_COPY,"Copy" ); menu.AppendMenu( MF_STRING|pasteFlags,ID_DB_PASTE,"Paste" ); menu.AppendMenu( MF_STRING,ID_DB_CLONE,"Clone" ); menu.AppendMenu( MF_SEPARATOR,0,"" ); menu.AppendMenu( MF_STRING,ID_DB_RENAME,"Rename" ); menu.AppendMenu( MF_STRING,ID_DB_REMOVE,"Delete" ); menu.AppendMenu( MF_SEPARATOR,0,"" ); menu.AppendMenu( MF_STRING,ID_DB_MTL_ASSIGNTOSELECTION,"Assign to Selected Objects" ); menu.AppendMenu( MF_STRING,ID_DB_SELECTASSIGNEDOBJECTS,"Select Assigned Objects" ); menu.AppendMenu( MF_STRING,ID_DB_MTL_ADDSUBMTL,"Add Sub Material" ); } GetCursorPos( &point ); menu.TrackPopupMenu( TPM_LEFTALIGN|TPM_LEFTBUTTON,point.x,point.y,this ); } ////////////////////////////////////////////////////////////////////////// void CMaterialDialog::OnPickMtl() { if (!CMtlPickCallback::IsActive()) GetIEditor()->PickObject( new CMtlPickCallback,0,"Pick Object to Select Material" ); else GetIEditor()->CancelPick(); } ////////////////////////////////////////////////////////////////////////// void CMaterialDialog::OnUpdatePickMtl( CCmdUI* pCmdUI ) { if (CMtlPickCallback::IsActive()) { pCmdUI->SetCheck(1); } else { pCmdUI->SetCheck(0); } } ////////////////////////////////////////////////////////////////////////// void CMaterialDialog::OnCopy() { CMaterial *pMtl = GetSelectedMaterial(); if (pMtl) { CClipboard clipboard; XmlNodeRef node = new CXmlNode( "Material" ); CBaseLibraryItem::SerializeContext ctx( node,false ); ctx.bCopyPaste = true; pMtl->Serialize( ctx ); clipboard.Put( node ); } } ////////////////////////////////////////////////////////////////////////// void CMaterialDialog::OnPaste() { if (!m_pLibrary) return; CClipboard clipboard; if (clipboard.IsEmpty()) return; XmlNodeRef node = clipboard.Get(); if (!node) return; if (strcmp(node->getTag(),"Material") == 0) { CMaterial *pParentMtl = 0; CMaterial *pSelMtl = GetSelectedMaterial(); if (pSelMtl) { pParentMtl = pSelMtl->GetParent(); } // This is material node. CBaseLibrary *pLib = m_pLibrary; CMaterial *pMtl = m_pMatManager->LoadMaterial( (CMaterialLibrary*)pLib,node,true ); if (pMtl) { if (pParentMtl) { pParentMtl->AddSubMaterial( pMtl ); } ReloadItems(); SelectItem(pMtl); } } } ////////////////////////////////////////////////////////////////////////// void CMaterialDialog::OnGenCubemap() { CMaterial *pMtl = GetSelectedMaterial(); if (!pMtl) return; CBaseObject *pObject = GetIEditor()->GetSelectedObject(); if (!pObject) { AfxMessageBox( "Select One Object to Generate Cubemap",MB_OK|MB_APPLMODAL|MB_ICONWARNING ); return; } CString filename; if (!CFileUtil::SelectSaveFile( "*.*","dds","Textures",filename )) return; filename = GetIEditor()->GetRelativePath(filename); if (filename.IsEmpty()) { AfxMessageBox( _T("Texture Must be inside MasterCD folder!"),MB_OK|MB_APPLMODAL|MB_ICONWARNING ); return; } CNumberDlg dlg( this,256,"Enter Cubemap Resolution" ); dlg.SetInteger( true ); if (dlg.DoModal() != IDOK) return; int res = 1; int size = dlg.GetValue(); // Make size power of 2. for (int i = 0; i < 16; i++) { if (res*2 > size) break; res *= 2; } if (res > 4096) { AfxMessageBox( "Bad texture resolution.\nMust be power of 2 and less or equal to 4096",MB_OK|MB_APPLMODAL|MB_ICONWARNING ); return; } // Hide object before Cubemap generation. pObject->SetHidden( true ); GetIEditor()->GetRenderer()->EF_ScanEnvironmentCM( filename,res,pObject->GetWorldPos() ); pObject->SetHidden( false ); CString texname = Path::GetFileName(filename); CString path = Path::GetPath(filename); texname = Path::Make( path,texname+"_posx.jpg" ); // Assign this texname to current material. pMtl->GetShaderResources().m_Textures[EFTT_CUBEMAP].m_Name = texname; pMtl->Update(); // Update variables. m_propsCtrl.EnableUpdateCallback(false); gMatVars.SetFromMaterial( pMtl ); m_propsCtrl.EnableUpdateCallback(true); } ////////////////////////////////////////////////////////////////////////// void CMaterialDialog::DropToItem( HTREEITEM hItem,HTREEITEM hSrcItem,CMaterial *pMtl ) { pMtl->GetLibrary()->SetModified(); CMaterial* pTargetMtl = (CMaterial*)m_treeCtrl.GetItemData(hItem); if (!pTargetMtl) { // Only root materials can be inserted at group level. if (pMtl->GetParent()) return; // Only move material to different group. CString groupName = m_treeCtrl.GetItemText(hItem); SetItemName( pMtl,groupName,pMtl->GetShortName() ); //ReloadItems(); //SelectItem( pMtl ); m_treeCtrl.DeleteItem( hSrcItem ); InsertItemToTree( pMtl,hItem ); return; } // Ignore itself. if (pTargetMtl == pMtl) return; CMaterial *pTargetParent = pTargetMtl->GetParent(); CMaterial *pSourceParent = pMtl->GetParent(); if (pTargetParent && pSourceParent && pTargetParent == pSourceParent) { int slot = pTargetParent->FindSubMaterial( pTargetMtl ); assert(slot>=0); if (slot < 0) return; TSmartPtr pSourceMtl = pMtl; // Make usre its not release while we remove and add it back. pTargetParent->RemoveSubMaterial( pMtl ); pTargetParent->InsertSubMaterial( slot,pMtl ); ReloadItems(); SelectItem( pMtl ); } if (pTargetParent == pMtl || pSourceParent == pTargetMtl) { // Swap contents of theose 2 materials... pMtl->SwapContent( pTargetMtl ); SelectItem( pMtl,true ); } }