//////////////////////////////////////////////////////////////////////////// // // Crytek Engine Source File. // Copyright (C), Crytek Studios, 2002. // ------------------------------------------------------------------------- // File name: particledialog.cpp // Version: v1.00 // Created: 17/6/2003 by Timur. // Compilers: Visual Studio.NET // Description: // ------------------------------------------------------------------------- // History: // //////////////////////////////////////////////////////////////////////////// #include "StdAfx.h" #include "ParticleDialog.h" #include "StringDlg.h" #include "NumberDlg.h" #include "ParticleManager.h" #include "ParticleLibrary.h" #include "ParticleItem.h" #include "Objects\BrushObject.h" #include "Objects\Entity.h" #include "Objects\ObjectManager.h" #include "ViewManager.h" #include "Clipboard.h" #include //#include #include #define IDC_PARTICLES_TREE AFX_IDW_PANE_FIRST #define EDITOR_OBJECTS_PATH CString("Objects\\Editor\\") IMPLEMENT_DYNAMIC(CParticleDialog,CBaseLibraryDialog); ////////////////////////////////////////////////////////////////////////// // Particle UI structures. ////////////////////////////////////////////////////////////////////////// /* struct ParticleParams { ParticleParams() { memset(this,0,sizeof(*this)); } Vec3_tpl vPosition; // spawn position Vec3_tpl vDirection; // initial direction (normalization not important) float fFocus; // if 0 - particles go in all directions, if more than 20 - particles go mostly in vDirection Vec3_tpl vColorStart; // initial color Vec3_tpl vColorEnd; // final color float fSpeed; // initial speed ( +- 25% random factor applyed, m/sec ) Vec3_tpl vRotation; // rotation speed (degree/sec) Vec3_tpl vInitAngles; // initial rotation int nCount; // number of particles to spawn float fSize; // initial size of particles float fSizeSpeed; // particles will grow with this speed Vec3_tpl vGravity; // gravity(wind) vector float fLifeTime; // time of life of particle float fFadeInTime; // particle will fade in slowly during this time int nTexId; // texture id for body and trail (if used) ( if 0 - will be used default ball/glow texture ) int nTexAnimFramesCount; // number of frames in animated texture ( 0 if no animation ) ParticleBlendType eBlendType; // see ParticleBlendType float fTailLenght; // delay of tail ( 0 - no tail, 1 meter if speed is 1 meter/sec ) int nParticleFlags; // see particle system flags bool bRealPhysics; // use physics engine to control particles IStatObj * pStatObj; // if not 0 - this object will be used instead sprite ParticleParams * pChild; // child process definition float fChildSpawnPeriod; // if more than 0 - run child process every x seconds, if 0 - run it at collision int nDrawLast; // add this element into second list and draw this list last float fBouncenes; // if 0 - particle will not bounce from the ground, 0.5 is good in most cases float fTurbulenceSize; // radius of turbulence float fTurbulenceSpeed; // speed of rotation float fDirVecScale; //the game need to store this(Alberto) struct IEntityRender * pEntity; // spawner entity struct IShader * pShader; // shader for partice float fPosRandomOffset; // maximum distance of random offset from original position IMatInfo *pMaterial; // Override material. }; */ struct SParticleTableUI { CVariable texture; CVariable geometry; CVariable material; CVariableArray sizeTable; CVariableArray moveTable; CVariableArray rotateTable; CVariableArray visualTable; CVariableArray advancedTable; CVariableEnum type; CVariableEnum blendType; CVariable focus; CVariable focus_plane; CVariable use_gravity_direction; CVariable bind_pos_to_emitter; CVariable speed; CVariable speed_variation; CVariable speed_fadeout; CVariable speed_accel; CVariable speed_airResistance; CVariable size; CVariable size_variation; CVariable sizeSpeed; CVariable sizeLinear; CVariable sizeFadeIn; CVariable sizeFadeOut; CVariable object_scale; CVariable count; CVariable lifeTime; CVariable lifeTime_variation; CVariable fadeInTime; CVariable frameCount; CVariable tailLength; CVariable tailSteps; CVariable stretch; CVariable realPhysics; CVariable drawLast; CVariable bounciness; CVariable turbulenceSize; CVariable turbulenceSpeed; //CVariable posRandomOffset; CVariable no_underwater; CVariable rigid_body; CVariable colorStart; CVariable colorEnd; CVariable rotation; CVariable rotation_variation; CVariable angles; CVariable angles_variation; CVariable gravity; }; /** User Interface definition of particle system. */ class CParticleUIDefinition { public: enum EParticleSystemType { PRIMARY_SYSTEM = 0, CHILD_SYSTEM = 1, }; CVariableArray uiParamsArray[2]; SParticleTableUI uiParams[2]; ////////////////////////////////////////////////////////////////////////// // One per effect variables. CVariable bActive; CVariable positionOffset; CVariable randomPositionOffset; CVariable spawnDelay; CVariable spawnDelay_variation; CVariable emitterLifeTime; CVariable emitterLifeTime_variation; CVariable spawnPeriod; CVariable childSpawnPeriod; CVariable childSpawnTime; CVariableArray emitterTable; ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// // Sound variables. CVariableArray uiSound; CVariable soundFilename; CVariable soundVolume; CVariable soundMinRange; CVariable soundMaxRange; CVariable soundLoop; CVariable soundEverySpawn; ////////////////////////////////////////////////////////////////////////// CVarEnumList enumType; CVarEnumList enumBlendType; CVarBlockPtr m_vars; IVariable::OnSetCallback m_onSetCallback; ////////////////////////////////////////////////////////////////////////// CVarBlock* CreateVars() { m_vars = new CVarBlock; ////////////////////////////////////////////////////////////////////////// // Init enums. ////////////////////////////////////////////////////////////////////////// enumBlendType.AddRef(); // We not using pointer. enumBlendType.AddItem( "AlphaBlend",ParticleBlendType_AlphaBased ); enumBlendType.AddItem( "ColorBased",ParticleBlendType_ColorBased ); enumBlendType.AddItem( "Additive",ParticleBlendType_Additive ); enumBlendType.AddItem( "None",ParticleBlendType_None ); enumType.AddRef(); // We not using pointer. enumType.AddItem( "Billboard",PART_FLAG_BILLBOARD ); enumType.AddItem( "Horizontal",PART_FLAG_HORIZONTAL ); enumType.AddItem( "Underwater",PART_FLAG_UNDERWATER ); enumType.AddItem( "Line",PART_FLAG_LINEPARTICLE ); ////////////////////////////////////////////////////////////////////////// // Init tables. ////////////////////////////////////////////////////////////////////////// AddVariable( m_vars,uiParamsArray[PRIMARY_SYSTEM],"Particle Settings" ); AddVariable( m_vars,uiParamsArray[CHILD_SYSTEM],"ChildProcess Settings" ); AddVariable( m_vars,uiSound,"Sound Settings",IVariable::DT_SIMPLE ); AddVariable( uiParamsArray[PRIMARY_SYSTEM],bActive,"Active" ); AddVariable( uiParamsArray[CHILD_SYSTEM],childSpawnPeriod,"Child Spawn Period" ); AddVariable( uiParamsArray[CHILD_SYSTEM],childSpawnTime,"Child Spawn Max Time" ); AddParticleTableVars( uiParamsArray[PRIMARY_SYSTEM],uiParams[PRIMARY_SYSTEM] ); AddParticleTableVars( uiParamsArray[CHILD_SYSTEM],uiParams[CHILD_SYSTEM] ); { CVariableArray &table = uiParamsArray[PRIMARY_SYSTEM]; AddVariable( uiParams[PRIMARY_SYSTEM].moveTable,positionOffset,"Position Offset" ); AddVariable( uiParams[PRIMARY_SYSTEM].moveTable,randomPositionOffset,"Random Offset" ); emitterTable.SetFlags( IVariable::UI_BOLD ); AddVariable( table,emitterTable,"Emitter" ); AddVariable( emitterTable,spawnDelay,"Spawn Delay" ); AddVariable( emitterTable,spawnDelay_variation,"Spawn Delay Variation",IVariable::DT_PERCENT ); AddVariable( emitterTable,spawnPeriod,"Spawn Period" ); AddVariable( emitterTable,emitterLifeTime,"Emitter Life Time" ); AddVariable( emitterTable,emitterLifeTime_variation,"Emitter Life Time Variation",IVariable::DT_PERCENT ); } AddVariable( uiSound,soundFilename,"Sound",IVariable::DT_SOUND ); AddVariable( uiSound,soundLoop,"Loop" ); AddVariable( uiSound,soundEverySpawn,"On Every Spawn" ); AddVariable( uiSound,soundVolume,"Volume" ); AddVariable( uiSound,soundMinRange,"Min Range" ); AddVariable( uiSound,soundMaxRange,"Max Range" ); return m_vars; } void AddParticleTableVars( CVariableArray &table,SParticleTableUI &parts ) { parts.blendType.SetEnumList( &enumBlendType ); parts.type.SetEnumList( &enumType ); parts.sizeTable.SetFlags( IVariable::UI_BOLD ); parts.moveTable.SetFlags( IVariable::UI_BOLD ); parts.rotateTable.SetFlags( IVariable::UI_BOLD ); parts.visualTable.SetFlags( IVariable::UI_BOLD ); parts.advancedTable.SetFlags( IVariable::UI_BOLD ); parts.tailSteps.SetLimits( 0,16 ); ////////////////////////////////////////////////////////////////////////// /// Add variables. ////////////////////////////////////////////////////////////////////////// AddVariable( table,parts.texture,"Texture",IVariable::DT_TEXTURE ); AddVariable( table,parts.geometry,"Geometry",IVariable::DT_OBJECT ); AddVariable( table,parts.material,"Material",IVariable::DT_MATERIAL ); AddVariable( table,parts.type,"Type" ); AddVariable( table,parts.count,"Count" ); AddVariable( table,parts.lifeTime,"Life Time" ); AddVariable( table,parts.lifeTime_variation,"Life Time Variation",IVariable::DT_PERCENT ); ////////////////////////////////////////////////////////////////////////// // Movement table. AddVariable( table,parts.moveTable,"Movement" ); AddVariable( parts.moveTable,parts.focus,"Focus" ); AddVariable( parts.moveTable,parts.focus_plane,"Focus On Plane" ); AddVariable( parts.moveTable,parts.speed,"Speed" ); AddVariable( parts.moveTable,parts.speed_variation,"Speed Variation",IVariable::DT_PERCENT ); AddVariable( parts.moveTable,parts.speed_fadeout,"Speed FadeOut" ); AddVariable( parts.moveTable,parts.speed_accel,"Acceleration" ); AddVariable( parts.moveTable,parts.speed_airResistance,"Air Resistance" ); AddVariable( parts.moveTable,parts.gravity,"Gravity" ); AddVariable( parts.moveTable,parts.use_gravity_direction,"Speed In Gravity Direction" ); AddVariable( parts.moveTable,parts.turbulenceSize,"Turbulence Size" ); AddVariable( parts.moveTable,parts.turbulenceSpeed,"Turbulence Speed" ); AddVariable( parts.moveTable,parts.bind_pos_to_emitter,"Bind To Emitter" ); ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// // Appearance table. AddVariable( table,parts.visualTable,"Appearance" ); AddVariable( parts.visualTable,parts.blendType,"Blend Type" ); AddVariable( parts.visualTable,parts.fadeInTime,"FadeInTime" ); AddVariable( parts.visualTable,parts.colorStart,"Start Color",IVariable::DT_COLOR ); AddVariable( parts.visualTable,parts.colorEnd,"End Color",IVariable::DT_COLOR ); AddVariable( parts.visualTable,parts.no_underwater,"Not Draw Underwater" ); AddVariable( parts.visualTable,parts.frameCount,"Frames Count" ); AddVariable( parts.visualTable,parts.tailLength,"Tail" ); AddVariable( parts.visualTable,parts.tailSteps,"TailSteps" ); AddVariable( parts.visualTable,parts.stretch,"Stretch" ); AddVariable( parts.visualTable,parts.drawLast,"DrawLast" ); ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// // Size table. AddVariable( table,parts.sizeTable,"Size" ); AddVariable( parts.sizeTable,parts.size,"Size" ); AddVariable( parts.sizeTable,parts.size_variation,"Size Variation",IVariable::DT_PERCENT ); AddVariable( parts.sizeTable,parts.sizeSpeed,"Size Speed" ); AddVariable( parts.sizeTable,parts.sizeLinear,"Size Speed Linear" ); AddVariable( parts.sizeTable,parts.sizeFadeIn,"Size FadeIn" ); AddVariable( parts.sizeTable,parts.sizeFadeOut,"Size FadeOut" ); ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// // Rotate table. AddVariable( table,parts.rotateTable,"Rotate" ); AddVariable( parts.rotateTable,parts.rotation,"Rotation" ); AddVariable( parts.rotateTable,parts.rotation_variation,"Rotation Variation",IVariable::DT_PERCENT ); AddVariable( parts.rotateTable,parts.angles,"Initial Angles" ); AddVariable( parts.rotateTable,parts.angles_variation,"Initial Angles Variation",IVariable::DT_PERCENT ); ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// // Advanced table. AddVariable( table,parts.advancedTable,"Advanced" ); AddVariable( parts.advancedTable,parts.realPhysics,"Use Real Physics" ); AddVariable( parts.advancedTable,parts.rigid_body,"Rigid Body Physics" ); AddVariable( parts.advancedTable,parts.bounciness,"Bounciness" ); AddVariable( parts.advancedTable,parts.object_scale,"Object Scale" ); ////////////////////////////////////////////////////////////////////////// } ////////////////////////////////////////////////////////////////////////// void GetParticleParamsFromUI( ParticleParams ¶ms,const SParticleTableUI &ui ) { params.nParticleFlags = ui.type & (0x7); if (ui.sizeLinear) params.nParticleFlags |= PART_FLAG_SIZE_LINEAR; if (ui.focus_plane) params.nParticleFlags |= PART_FLAG_FOCUS_PLANE; if (ui.no_underwater) params.nParticleFlags |= PART_FLAG_NO_DRAW_UNDERWATER; if (ui.rigid_body) params.nParticleFlags |= PART_FLAG_RIGIDBODY; if (ui.use_gravity_direction) params.nParticleFlags |= PART_FLAG_SPEED_IN_GRAVITY_DIRECTION; if (ui.bind_pos_to_emitter) params.nParticleFlags |= PART_FLAG_BIND_POSITION_TO_EMITTER; params.eBlendType = (ParticleBlendType)((int)ui.blendType); params.fFocus = ui.focus; params.fSpeed = ui.speed; params.fSpeed.variation = ui.speed_variation; params.fSpeedFadeOut = ui.speed_fadeout; params.fSize = ui.size; params.fSize.variation = ui.size_variation; params.fSpeedAccel = ui.speed_accel; params.fAirResistance = ui.speed_airResistance; params.fSizeSpeed = ui.sizeSpeed; params.fSizeFadeIn = ui.sizeFadeIn; params.fSizeFadeOut = ui.sizeFadeOut; params.fObjectScale = ui.object_scale; params.nCount = ui.count; params.fLifeTime = ui.lifeTime; params.fLifeTime.variation = ui.lifeTime_variation; params.fFadeInTime = ui.fadeInTime; params.nTexAnimFramesCount = ui.frameCount; params.fTailLenght = ui.tailLength; params.nTailSteps = ui.tailSteps; params.fStretch = ui.stretch; params.bRealPhysics = ui.realPhysics; params.nDrawLast = ui.drawLast; params.fBouncenes = ui.bounciness; params.fTurbulenceSize = ui.turbulenceSize; params.fTurbulenceSpeed = ui.turbulenceSpeed; //params.fPosRandomOffset = ui.posRandomOffset; params.vColorStart = (Vec3)ui.colorStart; params.vColorEnd = (Vec3)ui.colorEnd; params.vRotation = (Vec3)ui.rotation; params.vRotation.variation = ui.rotation_variation; params.vInitAngles = (Vec3)ui.angles; params.vInitAngles.variation = ui.angles_variation; params.vGravity = (Vec3)ui.gravity; } ////////////////////////////////////////////////////////////////////////// void SetParticleParamsToUI( const ParticleParams ¶ms,SParticleTableUI &ui ) { ui.type = params.nParticleFlags & (0x7); if (params.nParticleFlags & PART_FLAG_SIZE_LINEAR) ui.sizeLinear = true; else ui.sizeLinear = false; if (params.nParticleFlags & PART_FLAG_FOCUS_PLANE) ui.focus_plane = true; else ui.focus_plane = false; if (params.nParticleFlags & PART_FLAG_NO_DRAW_UNDERWATER) ui.no_underwater = true; else ui.no_underwater = false; if (params.nParticleFlags & PART_FLAG_RIGIDBODY) ui.rigid_body = true; else ui.rigid_body = false; if (params.nParticleFlags & PART_FLAG_SPEED_IN_GRAVITY_DIRECTION) ui.use_gravity_direction = true; else ui.use_gravity_direction = false; if (params.nParticleFlags & PART_FLAG_BIND_POSITION_TO_EMITTER) ui.bind_pos_to_emitter = true; else ui.bind_pos_to_emitter = false; ui.blendType = params.eBlendType; ui.focus = params.fFocus; ui.speed = params.fSpeed; ui.speed_variation = params.fSpeed.variation; ui.speed_fadeout = params.fSpeedFadeOut; ui.speed_accel = params.fSpeedAccel; ui.speed_airResistance = params.fAirResistance; ui.size = params.fSize; ui.size_variation = params.fSize.variation; ui.sizeSpeed = params.fSizeSpeed; ui.sizeFadeIn = params.fSizeFadeIn; ui.sizeFadeOut = params.fSizeFadeOut; ui.object_scale = params.fObjectScale; ui.count = params.nCount; ui.lifeTime = params.fLifeTime; ui.lifeTime_variation = params.fLifeTime.variation; ui.fadeInTime = params.fFadeInTime; ui.frameCount = params.nTexAnimFramesCount; ui.tailLength = params.fTailLenght; ui.tailSteps = params.nTailSteps; ui.stretch = params.fStretch; ui.realPhysics = params.bRealPhysics; ui.drawLast = params.nDrawLast; ui.bounciness = params.fBouncenes; ui.turbulenceSize = params.fTurbulenceSize; ui.turbulenceSpeed = params.fTurbulenceSpeed; //ui.posRandomOffset = params.fPosRandomOffset; ui.colorStart = params.vColorStart; ui.colorEnd = params.vColorEnd; ui.rotation = params.vRotation; ui.rotation_variation = params.vRotation.variation; ui.angles = params.vInitAngles; ui.angles_variation = params.vInitAngles.variation; ui.gravity = params.vGravity; } ////////////////////////////////////////////////////////////////////////// void SetFromParticles( CParticleItem *pParticles ) { IParticleEffect *pEffect = pParticles->GetEffect(); if (!pEffect) return; SetParticleParamsToUI( pEffect->GetParticleParams(PRIMARY_SYSTEM),uiParams[PRIMARY_SYSTEM] ); SetParticleParamsToUI( pEffect->GetParticleParams(CHILD_SYSTEM),uiParams[CHILD_SYSTEM] ); uiParams[PRIMARY_SYSTEM].texture = pEffect->GetTexture(PRIMARY_SYSTEM); uiParams[CHILD_SYSTEM].texture = pEffect->GetTexture(CHILD_SYSTEM); uiParams[PRIMARY_SYSTEM].geometry = pEffect->GetGeometry(PRIMARY_SYSTEM); uiParams[CHILD_SYSTEM].geometry = pEffect->GetGeometry(CHILD_SYSTEM); uiParams[PRIMARY_SYSTEM].material = pEffect->GetMaterialName(PRIMARY_SYSTEM); uiParams[CHILD_SYSTEM].material = pEffect->GetMaterialName(CHILD_SYSTEM); bActive = pEffect->IsEnabled(); { ParticleParams ¶ms = pEffect->GetParticleParams(PRIMARY_SYSTEM); childSpawnPeriod = pEffect->GetParticleParams(PRIMARY_SYSTEM).fChildSpawnPeriod; childSpawnTime = pEffect->GetParticleParams(PRIMARY_SYSTEM).fChildSpawnTime; positionOffset = params.vPositionOffset; randomPositionOffset = params.vRandomPositionOffset; spawnPeriod = params.fSpawnPeriod; spawnDelay = params.fSpawnDelay; spawnDelay_variation = params.fSpawnDelay.variation; emitterLifeTime = params.fEmitterLifeTime; emitterLifeTime_variation = params.fEmitterLifeTime.variation; } IParticleEffect::SoundParams soundParams; pEffect->GetSoundParams( soundParams ); soundFilename = soundParams.szSound; soundVolume = soundParams.volume; soundMinRange = soundParams.minRadius; soundMaxRange = soundParams.maxRadius; soundLoop = soundParams.bLoop; soundEverySpawn = soundParams.bOnEverySpawn; } ////////////////////////////////////////////////////////////////////////// void SetToParticles( CParticleItem *pParticles ) { IParticleEffect *pEffect = pParticles->GetEffect(); if (!pEffect) return; GetParticleParamsFromUI( pEffect->GetParticleParams(PRIMARY_SYSTEM),uiParams[PRIMARY_SYSTEM] ); GetParticleParamsFromUI( pEffect->GetParticleParams(CHILD_SYSTEM),uiParams[CHILD_SYSTEM] ); pEffect->SetTexture( PRIMARY_SYSTEM,(CString)uiParams[PRIMARY_SYSTEM].texture ); pEffect->SetTexture( CHILD_SYSTEM,(CString)uiParams[CHILD_SYSTEM].texture ); pEffect->SetGeometry( PRIMARY_SYSTEM,(CString)uiParams[PRIMARY_SYSTEM].geometry ); pEffect->SetGeometry( CHILD_SYSTEM,(CString)uiParams[CHILD_SYSTEM].geometry ); pEffect->SetEnabled( bActive ); CString primaryMaterial = uiParams[PRIMARY_SYSTEM].material; CString childMaterial = uiParams[CHILD_SYSTEM].material; pEffect->SetMaterialName( PRIMARY_SYSTEM,(CString)uiParams[PRIMARY_SYSTEM].material ); pEffect->SetMaterialName( CHILD_SYSTEM,(CString)uiParams[CHILD_SYSTEM].material ); { ParticleParams ¶ms = pEffect->GetParticleParams(PRIMARY_SYSTEM); pEffect->GetParticleParams(PRIMARY_SYSTEM).fChildSpawnPeriod = childSpawnPeriod; pEffect->GetParticleParams(PRIMARY_SYSTEM).fChildSpawnTime = childSpawnTime; params.vPositionOffset = (Vec3)positionOffset; params.vRandomPositionOffset = (Vec3)randomPositionOffset; params.fSpawnPeriod = spawnPeriod; params.fSpawnDelay = spawnDelay; params.fSpawnDelay.variation = spawnDelay_variation; params.fEmitterLifeTime = emitterLifeTime; params.fEmitterLifeTime.variation = emitterLifeTime_variation; } IParticleEffect::SoundParams soundParams; soundParams.szSound = (CString)soundFilename; soundParams.volume = soundVolume; soundParams.minRadius = soundMinRange; soundParams.maxRadius = soundMaxRange; soundParams.bLoop = soundLoop; soundParams.bOnEverySpawn = soundEverySpawn; pEffect->SetSoundParams( soundParams ); // Update particles. pParticles->Update(); } private: ////////////////////////////////////////////////////////////////////////// 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); } }; static CParticleUIDefinition gParticleUI; ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// class CParticlePickCallback : public IPickObjectCallback { public: CParticlePickCallback() { m_bActive = true; }; //! Called when object picked. virtual void OnPick( CBaseObject *picked ) { /* m_bActive = false; CParticleItem *pParticles = picked->GetParticle(); if (pParticles) GetIEditor()->OpenParticleLibrary( pParticles ); */ 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->GetParticle()) return true; */ return false; } static bool IsActive() { return m_bActive; }; private: static bool m_bActive; }; bool CParticlePickCallback::m_bActive = false; ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// // CParticleDialog implementation. ////////////////////////////////////////////////////////////////////////// CParticleDialog::CParticleDialog( CWnd *pParent ) : CBaseLibraryDialog(IDD_DB_ENTITY, pParent) { m_pPartManager = GetIEditor()->GetParticleManager(); m_pItemManager = m_pPartManager; m_bRealtimePreviewUpdate = true; m_pGeometry = 0; m_pEntityRender = 0; m_drawType = DRAW_BOX; m_geometryFile = EDITOR_OBJECTS_PATH + "MtlBox.cgf"; m_bOwnGeometry = true; m_dragImage = 0; m_hDropItem = 0; m_hCursorDefault = AfxGetApp()->LoadStandardCursor(IDC_ARROW); m_hCursorCreate = AfxGetApp()->LoadCursor( IDC_HIT_CURSOR ); m_hCursorReplace = AfxGetApp()->LoadCursor(IDC_HAND_INTERNAL); // Immidiatly create dialog. Create( IDD_DB_ENTITY,pParent ); } CParticleDialog::~CParticleDialog() { } void CParticleDialog::DoDataExchange(CDataExchange* pDX) { CBaseLibraryDialog::DoDataExchange(pDX); } BEGIN_MESSAGE_MAP(CParticleDialog, 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,OnAssignParticleToSelection ) ON_COMMAND( ID_DB_MTL_GETFROMSELECTION,OnGetParticleFromSelection ) ON_COMMAND( ID_DB_MTL_RESETMATERIAL,OnResetParticleOnSelection ) ON_UPDATE_COMMAND_UI( ID_DB_MTL_ASSIGNTOSELECTION,OnUpdateAssignMtlToSelection ) ON_UPDATE_COMMAND_UI( ID_DB_SELECTASSIGNEDOBJECTS,OnUpdateSelected ) ON_UPDATE_COMMAND_UI( ID_DB_MTL_GETFROMSELECTION,OnUpdateObjectSelected ) ON_UPDATE_COMMAND_UI( ID_DB_MTL_RESETMATERIAL,OnUpdateObjectSelected ) ON_COMMAND( ID_DB_MTL_ADDSUBMTL,OnAddSubItem ) ON_COMMAND( ID_DB_MTL_DELSUBMTL,OnDelSubItem ) ON_UPDATE_COMMAND_UI( ID_DB_MTL_ADDSUBMTL,OnUpdateSelected ) ON_UPDATE_COMMAND_UI( ID_DB_MTL_DELSUBMTL,OnUpdateSelected ) ON_COMMAND( ID_DB_MTL_PICK,OnPickMtl ) ON_UPDATE_COMMAND_UI( ID_DB_MTL_PICK,OnUpdatePickMtl ) ON_NOTIFY(TVN_BEGINDRAG, IDC_PARTICLES_TREE, OnBeginDrag) ON_NOTIFY(NM_RCLICK , IDC_PARTICLES_TREE, OnNotifyMtlTreeRClick) ON_WM_SIZE() ON_WM_DESTROY() ON_WM_MOUSEMOVE() ON_WM_LBUTTONUP() END_MESSAGE_MAP() ////////////////////////////////////////////////////////////////////////// void CParticleDialog::OnDestroy() { int temp; int HSplitter,VSplitter; m_wndHSplitter.GetRowInfo( 0,HSplitter,temp ); m_wndVSplitter.GetColumnInfo( 0,VSplitter,temp ); AfxGetApp()->WriteProfileInt("Dialogs\\Particles","HSplitter",HSplitter ); AfxGetApp()->WriteProfileInt("Dialogs\\Particles","VSplitter",VSplitter ); //ReleaseGeometry(); CBaseLibraryDialog::OnDestroy(); } // CTVSelectKeyDialog message handlers BOOL CParticleDialog::OnInitDialog() { CBaseLibraryDialog::OnInitDialog(); InitToolbar(); CRect rc; GetClientRect(rc); //int h2 = rc.Height()/2; int h2 = 200; int HSplitter = AfxGetApp()->GetProfileInt("Dialogs\\Particles","HSplitter",200 ); int VSplitter = AfxGetApp()->GetProfileInt("Dialogs\\Particles","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_PARTICLES_TREE, 16, 1, RGB (255, 0, 255)); CMFCUtils::LoadTrueColorImageList( m_imageList,IDB_PARTICLES_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 = gParticleUI.CreateVars(); m_propsCtrl.AddVarBlock( m_vars ); m_propsCtrl.ExpandAllChilds( m_propsCtrl.GetRootItem(),false ); 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 CParticleDialog::GetDialogMenuID() { return IDR_DB_ENTITY; }; ////////////////////////////////////////////////////////////////////////// // Create the toolbar void CParticleDialog::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 CParticleDialog::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 CParticleDialog::OnNewDocument() { //ReleaseGeometry(); CBaseLibraryDialog::OnNewDocument(); }; ////////////////////////////////////////////////////////////////////////// void CParticleDialog::OnLoadDocument() { //m_pPartManager->SetCurrentParticle( 0 ); //ReleaseGeometry(); CBaseLibraryDialog::OnLoadDocument(); } ////////////////////////////////////////////////////////////////////////// void CParticleDialog::OnCloseDocument() { //m_pPartManager->SetCurrentParticle( 0 ); //ReleaseGeometry(); CBaseLibraryDialog::OnCloseDocument(); } ////////////////////////////////////////////////////////////////////////// HTREEITEM CParticleDialog::InsertItemToTree( CBaseLibraryItem *pItem,HTREEITEM hParent ) { CParticleItem *pParticles = (CParticleItem*)pItem; if (pParticles->GetParent()) { if (!hParent || hParent == TVI_ROOT || m_treeCtrl.GetItemData(hParent) == 0) return 0; } HTREEITEM hMtlItem = CBaseLibraryDialog::InsertItemToTree( pItem,hParent ); for (int i = 0; i < pParticles->GetChildCount(); i++) { CParticleItem *pSubItem = pParticles->GetChild(i); InsertItemToTree( pSubItem,hMtlItem ); } return hMtlItem; } ////////////////////////////////////////////////////////////////////////// void CParticleDialog::OnAddItem() { if (!m_pLibrary) return; CStringGroupDlg dlg( _T("New Particle 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( "Item with name %s already exist",(const char*)fullName ); return; } CParticleItem *pParticles = (CParticleItem*)m_pItemManager->CreateItem( m_pLibrary ); pParticles->SetDefaults(); // Make prototype name. SetItemName( pParticles,dlg.GetGroup(),dlg.GetString() ); pParticles->Update(); ReloadItems(); SelectItem( pParticles ); } ////////////////////////////////////////////////////////////////////////// void CParticleDialog::SetParticleVars( CParticleItem *pParticles ) { } ////////////////////////////////////////////////////////////////////////// void CParticleDialog::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_pPartManager->SetCurrentParticle( (CParticleItem*)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 CParticleItem *pParticles = GetSelectedParticle(); //AssignMtlToGeometry(); // Update variables. m_propsCtrl.EnableUpdateCallback(false); gParticleUI.SetFromParticles( pParticles ); m_propsCtrl.EnableUpdateCallback(true); //gParticleUI.m_onSetCallback = functor(*this,OnUpdateProperties); m_propsCtrl.SetUpdateCallback( functor(*this,&CParticleDialog::OnUpdateProperties) ); m_propsCtrl.EnableUpdateCallback(true); } ////////////////////////////////////////////////////////////////////////// void CParticleDialog::Update() { if (!m_bRealtimePreviewUpdate) return; // Update preview control. if (m_pEntityRender) { m_previewCtrl.Update(); } } ////////////////////////////////////////////////////////////////////////// void CParticleDialog::OnUpdateProperties( IVariable *var ) { CParticleItem *pParticles = GetSelectedParticle(); if (!pParticles) return; gParticleUI.SetToParticles( pParticles ); //AssignMtlToGeometry(); GetIEditor()->SetModifiedFlag(); } ////////////////////////////////////////////////////////////////////////// void CParticleDialog::OnPlay() { m_bRealtimePreviewUpdate = !m_bRealtimePreviewUpdate; } ////////////////////////////////////////////////////////////////////////// void CParticleDialog::OnUpdatePlay( CCmdUI* pCmdUI ) { if (m_bRealtimePreviewUpdate) pCmdUI->SetCheck(TRUE); else pCmdUI->SetCheck(FALSE); } ////////////////////////////////////////////////////////////////////////// CParticleItem* CParticleDialog::GetSelectedParticle() { CBaseLibraryItem *pItem = m_pCurrentItem; return (CParticleItem*)pItem; } ////////////////////////////////////////////////////////////////////////// IStatObj* CParticleDialog::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()) { return pEntityObj->GetIEntity()->GetIStatObj(0); } } return 0; } ////////////////////////////////////////////////////////////////////////// ICryCharInstance* CParticleDialog::GetCharacterFromObject( CBaseObject *pObject ) { if (pObject->IsKindOf(RUNTIME_CLASS(CEntity))) { CEntity *pEntityObj = (CEntity*)pObject; if (pEntityObj->GetIEntity()) { return pEntityObj->GetIEntity()->GetCharInterface()->GetCharacter(0); } } return 0; } ////////////////////////////////////////////////////////////////////////// void CParticleDialog::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 CParticleDialog::OnDrawBox() { if (m_drawType == DRAW_BOX) return; m_drawType = DRAW_BOX; //LoadGeometry( EDITOR_OBJECTS_PATH+"MtlBox.cgf" ); } ////////////////////////////////////////////////////////////////////////// void CParticleDialog::OnDrawSphere() { if (m_drawType == DRAW_SPHERE) return; m_drawType = DRAW_SPHERE; //LoadGeometry( EDITOR_OBJECTS_PATH+"MtlSphere.cgf" ); } ////////////////////////////////////////////////////////////////////////// void CParticleDialog::OnDrawTeapot() { if (m_drawType == DRAW_TEAPOT) return; m_drawType = DRAW_TEAPOT; //LoadGeometry( EDITOR_OBJECTS_PATH+"MtlTeapot.cgf" ); } //@FIXME /* ////////////////////////////////////////////////////////////////////////// void CParticleDialog::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 CParticleDialog::ReleaseGeometry() { //@FIXME 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 CParticleDialog::AssignMtlToGeometry() { if (!m_pEntityRender) return; CParticleItem *pParticles = GetSelectedParticle(); if (!pParticles) return; pParticles->AssignToEntity( m_pEntityRender ); } */ ////////////////////////////////////////////////////////////////////////// void CParticleDialog::OnAssignParticleToSelection() { CParticleItem *pParticles = GetSelectedParticle(); if (!pParticles) return; CUndo undo( "Assign ParticleEffect" ); CSelectionGroup *pSel = GetIEditor()->GetSelection(); if (!pSel->IsEmpty()) { for (int i = 0; i < pSel->GetCount(); i++) { AssignParticleToEntity( pParticles,pSel->GetObject(i) ); } } } ////////////////////////////////////////////////////////////////////////// void CParticleDialog::OnSelectAssignedObjects() { //@FIXME /* CParticleItem *pParticles = GetSelectedParticle(); if (!pParticles) return; CBaseObjectsArray objects; GetIEditor()->GetObjectManager()->GetObjects( objects ); for (int i = 0; i < objects.size(); i++) { CBaseObject *pObject = objects[i]; if (pObject->GetParticle() != pParticles) continue; if (pObject->IsHidden() || pObject->IsFrozen()) continue; GetIEditor()->GetObjectManager()->SelectObject( pObject ); } */ } ////////////////////////////////////////////////////////////////////////// void CParticleDialog::OnResetParticleOnSelection() { CUndo undo( "Reset Particle" ); //@FIXME /* CSelectionGroup *pSel = GetIEditor()->GetSelection(); if (!pSel->IsEmpty()) { for (int i = 0; i < pSel->GetCount(); i++) { pSel->GetObject(i)->SetParticle( 0 ); } } */ } ////////////////////////////////////////////////////////////////////////// void CParticleDialog::OnGetParticleFromSelection() { //@FIXME /* if (!m_pLibrary) return; CSelectionGroup *pSel = GetIEditor()->GetSelection(); if (pSel->IsEmpty()) return; for (int i = 0; i < pSel->GetCount(); i++) { CParticleItem *pParticles = pSel->GetObject(i)->GetParticle(); if (pParticles) { SelectItem( pParticles ); 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 Particle\r\nDo you want to create Particle for it?"),MB_YESNO|MB_APPLMODAL|MB_ICONQUESTION )) { return; } CStringGroupDlg dlg( _T("New Particle 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. CParticleItem *pParticles = (CParticleItem*)m_pItemManager->CreateItem( m_pLibrary ); // Make prototype name. SetItemName( pParticles,dlg.GetGroup(),dlg.GetString() ); if (pCharacter) { pParticles->AssignFromGeometry( pCharacter ); } else if (pGeometry) { pParticles->AssignFromGeometry( pGeometry ); } pParticles->Update(); pSel->GetObject(0)->SetParticle( pParticles ); ReloadItems(); SelectItem( pParticles ); */ } ////////////////////////////////////////////////////////////////////////// void CParticleDialog::AssignParticleToEntity( CParticleItem *pItem,CBaseObject *pObject ) { assert(pItem); assert(pObject); if (pObject->IsKindOf(RUNTIME_CLASS(CEntity))) { CEntity *pEntity = (CEntity*)pObject; IVariable *pVar = 0; if (pEntity->GetProperties()) pVar = pEntity->GetProperties()->FindVariable( "ParticleEffect" ); if (pVar && pVar->GetType() == IVariable::STRING) { pVar->Set( pItem->GetFullName() ); } } } ////////////////////////////////////////////////////////////////////////// void CParticleDialog::OnAddSubItem() { CParticleItem *pParticles = GetSelectedParticle(); if (!pParticles) return; //if (pParticles->GetParent()) //pParticles = pParticles->GetParent(); CUndo undo( "Add Sub Particle" ); CParticleItem *pSubItem = (CParticleItem*)m_pItemManager->CreateItem( m_pLibrary ); pSubItem->SetDefaults(); pParticles->AddChild( pSubItem ); pSubItem->SetName( m_pItemManager->MakeUniqItemName(pParticles->GetName()) ); pSubItem->Update(); ReloadItems(); SelectItem( pSubItem ); } ////////////////////////////////////////////////////////////////////////// void CParticleDialog::OnDelSubItem() { CParticleItem *pSubItem = GetSelectedParticle(); if (!pSubItem) return; CUndo undo( "Remove Sub Particle" ); CParticleItem *pParticles = pSubItem->GetParent(); if (pParticles) { pParticles->RemoveChild(pSubItem); m_pItemManager->DeleteItem( pSubItem ); ReloadItems(); SelectItem( pParticles ); } } ////////////////////////////////////////////////////////////////////////// void CParticleDialog::OnUpdateAssignMtlToSelection( CCmdUI* pCmdUI ) { if (GetSelectedParticle() && !GetIEditor()->GetSelection()->IsEmpty()) { pCmdUI->Enable( TRUE ); } else { pCmdUI->Enable( FALSE ); } } ////////////////////////////////////////////////////////////////////////// void CParticleDialog::OnUpdateObjectSelected( CCmdUI* pCmdUI ) { if (!GetIEditor()->GetSelection()->IsEmpty()) { pCmdUI->Enable( TRUE ); } else { pCmdUI->Enable( FALSE ); } } ////////////////////////////////////////////////////////////////////////// void CParticleDialog::OnBeginDrag(NMHDR* pNMHDR, LRESULT* pResult) { NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR; HTREEITEM hItem = pNMTreeView->itemNew.hItem; CParticleItem* pParticles = (CParticleItem*)m_treeCtrl.GetItemData(hItem); if (!pParticles) return; m_pDraggedMtl = pParticles; 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 CParticleDialog::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 && hit.object->IsKindOf(RUNTIME_CLASS(CEntity))) { SetCursor( m_hCursorReplace ); } } } } } CBaseLibraryDialog::OnMouseMove(nFlags, point); } ////////////////////////////////////////////////////////////////////////// void CParticleDialog::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 ); CRect treeRc; m_treeCtrl.GetClientRect(treeRc); if (treeRc.PtInRect(treepoint)) { // Droped inside tree. 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; } DropToItem( 0,m_hDraggedItem,m_pDraggedMtl ); } else { // Not droped inside tree. CWnd *wnd = WindowFromPoint( p ); CUndo undo( "Assign ParticleEffect" ); 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. CParticleItem *pParticles = m_pDraggedMtl; AssignParticleToEntity( pParticles,hit.object ); } } } } m_pDraggedMtl = 0; } m_pDraggedMtl = 0; m_hDraggedItem = 0; CBaseLibraryDialog::OnLButtonUp(nFlags, point); } ////////////////////////////////////////////////////////////////////////// void CParticleDialog::OnNotifyMtlTreeRClick(NMHDR* pNMHDR, LRESULT* pResult) { // Show helper menu. CPoint point; CParticleItem *pParticles = 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)) { pParticles = (CParticleItem*)m_treeCtrl.GetItemData(hItem); } if (!pParticles) return; SelectItem( pParticles ); // Create pop up menu. CMenu menu; menu.CreatePopupMenu(); if (pParticles) { 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 Particle" ); } GetCursorPos( &point ); menu.TrackPopupMenu( TPM_LEFTALIGN|TPM_LEFTBUTTON,point.x,point.y,this ); } ////////////////////////////////////////////////////////////////////////// void CParticleDialog::OnPickMtl() { if (!CParticlePickCallback::IsActive()) GetIEditor()->PickObject( new CParticlePickCallback,0,"Pick Object to Select Particle" ); else GetIEditor()->CancelPick(); } ////////////////////////////////////////////////////////////////////////// void CParticleDialog::OnUpdatePickMtl( CCmdUI* pCmdUI ) { if (CParticlePickCallback::IsActive()) { pCmdUI->SetCheck(1); } else { pCmdUI->SetCheck(0); } } ////////////////////////////////////////////////////////////////////////// void CParticleDialog::OnCopy() { CParticleItem *pParticles = GetSelectedParticle(); if (pParticles) { XmlNodeRef node = new CXmlNode( "Particle" ); CBaseLibraryItem::SerializeContext ctx(node,false); ctx.bCopyPaste = true; CClipboard clipboard; pParticles->Serialize( ctx ); clipboard.Put( node ); } } ////////////////////////////////////////////////////////////////////////// void CParticleDialog::OnPaste() { if (!m_pLibrary) return; CParticleItem *pItem = GetSelectedParticle(); if (!pItem) return; CClipboard clipboard; if (clipboard.IsEmpty()) return; XmlNodeRef node = clipboard.Get(); if (!node) return; if (strcmp(node->getTag(),"Particle") == 0) { bool bPasteWithChilds = false; //if (pItem->GetParent()) //bPasteWithChilds = false; node->delAttr( "Name" ); m_pPartManager->PasteToParticleItem( pItem,node,bPasteWithChilds ); ReloadItems(); SelectItem(pItem); /* CParticleItem *pParentItem = 0; CParticleItem *pSelItem = GetSelectedParticle(); if (pSelItem) { pParentItem = pSelItem->GetParent(); } // This is material node. CBaseLibrary *pLib = m_pLibrary; CParticleItem *pParticles = m_pPartManager->LoadParticleItem( (CParticleLibrary*)pLib,node,true ); if (pParticles) { pParticles->SetName( m_pItemManager->MakeUniqItemName(pParticles->GetName()) ); if (pParentItem) { pParentItem->AddChild( pParticles ); } ReloadItems(); SelectItem(pParticles); } */ } } ////////////////////////////////////////////////////////////////////////// void CParticleDialog::DropToItem( HTREEITEM hItem,HTREEITEM hSrcItem,CParticleItem *pParticles ) { pParticles->GetLibrary()->SetModified(); TSmartPtr pHolder = pParticles; // Make usre its not release while we remove and add it back. if (!hItem) { // Detach from parent. if (pParticles->GetParent()) pParticles->GetParent()->RemoveChild( pParticles ); ReloadItems(); SelectItem( pParticles ); return; } CParticleItem* pTargetItem = (CParticleItem*)m_treeCtrl.GetItemData(hItem); if (!pTargetItem) { // This is group. // Detach from parent. if (pParticles->GetParent()) pParticles->GetParent()->RemoveChild( pParticles ); // Move item to different group. CString groupName = m_treeCtrl.GetItemText(hItem); SetItemName( pParticles,groupName,pParticles->GetShortName() ); m_treeCtrl.DeleteItem( hSrcItem ); InsertItemToTree( pParticles,hItem ); return; } // Ignore itself or immidiate target. if (pTargetItem == pParticles || pTargetItem == pParticles->GetParent()) return; // Detach from parent. if (pParticles->GetParent()) pParticles->GetParent()->RemoveChild( pParticles ); // Attach to target. pTargetItem->AddChild( pParticles ); ReloadItems(); SelectItem( pParticles ); }