1049 lines
32 KiB
C++
1049 lines
32 KiB
C++
// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
|
|
// Copyright (C) 2010 Winch Gate Property Limited
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU Affero General Public License as
|
|
// published by the Free Software Foundation, either version 3 of the
|
|
// License, or (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU Affero General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Affero General Public License
|
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
#include "std_afx.h"
|
|
#include "object_viewer.h"
|
|
#include "start_stop_particle_system.h"
|
|
#include "located_properties.h"
|
|
#include "select_string.h"
|
|
//
|
|
#include "nel/3d/particle_system.h"
|
|
#include "nel/3d/ps_located.h"
|
|
#include "nel/3d/ps_sound.h"
|
|
#include "nel/3d/ps_emitter.h"
|
|
#include "nel/3d/particle_system_model.h"
|
|
#include "particle_dlg.h"
|
|
|
|
|
|
#include <algorithm>
|
|
|
|
/*static char trace_buf[200];
|
|
#define NL_TRACE sprintf(trace_buf, "%d", __LINE__); \
|
|
::MessageBox(NULL, trace_buf, NULL, MB_OK);
|
|
*/
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CStartStopParticleSystem dialog
|
|
|
|
//******************************************************************************************************
|
|
CStartStopParticleSystem::CStartStopParticleSystem(CParticleDlg *particleDlg,
|
|
CAnimationDlg *animationDLG)
|
|
: CDialog(CStartStopParticleSystem::IDD, particleDlg),
|
|
_ParticleDlg(particleDlg),
|
|
_State(Stopped),
|
|
_LastCurrNumParticles(-1),
|
|
_LastMaxNumParticles(-1),
|
|
_LastNumWantedFaces(-1),
|
|
_LastSystemDate(-1.f),
|
|
_AutoRepeat(false),
|
|
_AnimationDLG(animationDLG),
|
|
_LastSceneAnimFrame(0.f),
|
|
_ActiveNode(NULL)
|
|
{
|
|
nlassert(particleDlg && particleDlg->getObjectViewer());
|
|
particleDlg->getObjectViewer()->registerMainLoopCallBack(this);
|
|
//{{AFX_DATA_INIT(CStartStopParticleSystem)
|
|
m_DisplayBBox = TRUE;
|
|
m_SpeedSliderPos = 100;
|
|
m_DisplayHelpers = FALSE;
|
|
m_LinkPlayToScenePlay = FALSE;
|
|
m_TriggerAnim = _T("");
|
|
//}}AFX_DATA_INIT
|
|
}
|
|
|
|
//******************************************************************************************************
|
|
CStartStopParticleSystem::~CStartStopParticleSystem()
|
|
{
|
|
nlassert(_ParticleDlg && _ParticleDlg->getObjectViewer());
|
|
_ParticleDlg->getObjectViewer()->removeMainLoopCallBack(this);
|
|
}
|
|
|
|
//******************************************************************************************************
|
|
bool CStartStopParticleSystem::isBBoxDisplayEnabled()
|
|
{
|
|
UpdateData();
|
|
return m_DisplayBBox ? true : false;
|
|
}
|
|
|
|
//******************************************************************************************************
|
|
void CStartStopParticleSystem::DoDataExchange(CDataExchange* pDX)
|
|
{
|
|
CDialog::DoDataExchange(pDX);
|
|
//{{AFX_DATA_MAP(CStartStopParticleSystem)
|
|
DDX_Control(pDX, IDC_START_MULTIPLE_PICTURE, m_StartMultiplePicture);
|
|
DDX_Control(pDX, IDC_PAUSE_PICTURE, m_PausePicture);
|
|
DDX_Control(pDX, IDC_STOP_PICTURE, m_StopPicture);
|
|
DDX_Control(pDX, IDC_START_PICTURE, m_StartPicture);
|
|
DDX_Check(pDX, IDC_DISPLAY_BBOX, m_DisplayBBox);
|
|
DDX_Slider(pDX, IDC_ANIM_SPEED, m_SpeedSliderPos);
|
|
DDX_Check(pDX, IDC_DISPLAY_HELPERS, m_DisplayHelpers);
|
|
DDX_Check(pDX, IDC_LINK_PLAY_TO_SCENE_PLAY, m_LinkPlayToScenePlay);
|
|
DDX_Text(pDX, IDC_TRIGGER_ANIM, m_TriggerAnim);
|
|
//}}AFX_DATA_MAP
|
|
|
|
|
|
}
|
|
|
|
|
|
BEGIN_MESSAGE_MAP(CStartStopParticleSystem, CDialog)
|
|
//{{AFX_MSG_MAP(CStartStopParticleSystem)
|
|
ON_BN_CLICKED(IDC_START_PICTURE, OnStartSystem)
|
|
ON_BN_CLICKED(IDC_STOP_PICTURE, OnStopSystem)
|
|
ON_BN_CLICKED(IDC_PAUSE_PICTURE, OnPause)
|
|
ON_NOTIFY(NM_RELEASEDCAPTURE, IDC_ANIM_SPEED, OnReleasedcaptureAnimSpeed)
|
|
ON_BN_CLICKED(IDC_DISPLAY_HELPERS, OnDisplayHelpers)
|
|
ON_BN_CLICKED(IDC_ENABLE_AUTO_COUNT, OnEnableAutoCount)
|
|
ON_BN_CLICKED(IDC_RESET_COUNT, OnResetCount)
|
|
ON_BN_CLICKED(IDC_AUTOREPEAT, OnAutoRepeat)
|
|
ON_BN_CLICKED(IDC_LINK_PLAY_TO_SCENE_PLAY, OnLinkPlayToScenePlay)
|
|
ON_BN_CLICKED(IDC_LINK_TO_SKELETON, OnLinkToSkeleton)
|
|
ON_BN_CLICKED(IDC_UNLINK_FROM_SKELETON, OnUnlinkFromSkeleton)
|
|
ON_BN_CLICKED(IDC_START_MULTIPLE_PICTURE, OnStartMultipleSystem)
|
|
ON_BN_CLICKED(IDC_BROWSE_ANIM, OnBrowseAnim)
|
|
ON_BN_CLICKED(IDC_CLEAR_ANIM, OnClearAnim)
|
|
ON_BN_CLICKED(IDC_RESTICK_ALL, OnRestickAll)
|
|
//}}AFX_MSG_MAP
|
|
END_MESSAGE_MAP()
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CStartStopParticleSystem message handlers
|
|
|
|
//******************************************************************************************************
|
|
BOOL CStartStopParticleSystem::OnInitDialog()
|
|
{
|
|
CDialog::OnInitDialog();
|
|
HBITMAP bm[4];
|
|
bm[0] = LoadBitmap(::AfxGetInstanceHandle(), MAKEINTRESOURCE(IDB_START_SYSTEM));
|
|
bm[1] = LoadBitmap(::AfxGetInstanceHandle(), MAKEINTRESOURCE(IDB_STOP_SYSTEM));
|
|
bm[2] = LoadBitmap(::AfxGetInstanceHandle(), MAKEINTRESOURCE(IDB_PAUSE_SYSTEM));
|
|
bm[3] = LoadBitmap(::AfxGetInstanceHandle(), MAKEINTRESOURCE(IDB_START_MULTIPLE_SYSTEM));
|
|
m_StartPicture.SendMessage(BM_SETIMAGE, IMAGE_BITMAP, (LPARAM) bm[0]);
|
|
m_StopPicture.SendMessage(BM_SETIMAGE, IMAGE_BITMAP, (LPARAM) bm[1]);
|
|
m_PausePicture.SendMessage(BM_SETIMAGE, IMAGE_BITMAP, (LPARAM) bm[2]);
|
|
m_StartMultiplePicture.SendMessage(BM_SETIMAGE, IMAGE_BITMAP, (LPARAM) bm[3]);
|
|
CSliderCtrl *sl = (CSliderCtrl *) GetDlgItem(IDC_ANIM_SPEED);
|
|
sl->SetRange(0, 100);
|
|
setSpeedSliderValue(1.f);
|
|
forceActiveNode(NULL);
|
|
return TRUE; // return TRUE unless you set the focus to a control
|
|
// EXCEPTION: OCX Property Pages should return FALSE
|
|
}
|
|
|
|
//******************************************************************************************************
|
|
void CStartStopParticleSystem::OnStartSystem()
|
|
{
|
|
start();
|
|
}
|
|
|
|
//******************************************************************************************************
|
|
void CStartStopParticleSystem::OnStartMultipleSystem()
|
|
{
|
|
startMultiple();
|
|
}
|
|
|
|
//******************************************************************************************************
|
|
void CStartStopParticleSystem::OnStopSystem()
|
|
{
|
|
stop();
|
|
}
|
|
|
|
//******************************************************************************************************
|
|
void CStartStopParticleSystem::OnPause()
|
|
{
|
|
pause();
|
|
}
|
|
|
|
|
|
//******************************************************************************************************
|
|
void CStartStopParticleSystem::updateUIFromState()
|
|
{
|
|
// update actions buttons
|
|
switch(_State)
|
|
{
|
|
case Stopped:
|
|
m_StartPicture.EnableWindow(_ActiveNode != NULL);
|
|
m_PausePicture.EnableWindow(FALSE);
|
|
m_StopPicture.EnableWindow(FALSE);
|
|
m_StartMultiplePicture.EnableWindow(TRUE);
|
|
break;
|
|
case RunningSingle:
|
|
m_StartPicture.EnableWindow(FALSE);
|
|
m_PausePicture.EnableWindow(TRUE);
|
|
m_StopPicture.EnableWindow(TRUE);
|
|
m_StartMultiplePicture.EnableWindow(FALSE);
|
|
break;
|
|
case RunningMultiple:
|
|
m_StartPicture.EnableWindow(FALSE);
|
|
m_PausePicture.EnableWindow(TRUE);
|
|
m_StopPicture.EnableWindow(TRUE);
|
|
m_StartMultiplePicture.EnableWindow(FALSE);
|
|
break;
|
|
case PausedSingle:
|
|
m_StartPicture.EnableWindow(TRUE);
|
|
m_PausePicture.EnableWindow(FALSE);
|
|
m_StopPicture.EnableWindow(TRUE);
|
|
m_StartMultiplePicture.EnableWindow(FALSE);
|
|
break;
|
|
case PausedMultiple:
|
|
m_StartPicture.EnableWindow(FALSE);
|
|
m_PausePicture.EnableWindow(FALSE);
|
|
m_StopPicture.EnableWindow(TRUE);
|
|
m_StartMultiplePicture.EnableWindow(TRUE);
|
|
break;
|
|
default:
|
|
nlassert(0);
|
|
break;
|
|
}
|
|
if (!getCurrPS())
|
|
{
|
|
GetDlgItem(IDC_ACTIVE_PS)->SetWindowText(getStrRsc(IDS_NO_ACTIVE_PS));
|
|
GetDlgItem(IDC_STICK_BONE)->SetWindowText("");
|
|
GetDlgItem(IDC_ENABLE_AUTO_COUNT)->EnableWindow(FALSE);
|
|
GetDlgItem(IDC_RESET_COUNT)->EnableWindow(FALSE);
|
|
((CButton *) GetDlgItem(IDC_ENABLE_AUTO_COUNT))->SetCheck(0);
|
|
// hide display of particle numbers
|
|
GetDlgItem(IDC_NUM_PARTICLES)->ShowWindow(SW_HIDE);
|
|
GetDlgItem(IDC_NUM_ASKED_FACES)->ShowWindow(SW_HIDE);
|
|
GetDlgItem(IDC_SYSTEM_DATE)->ShowWindow(SW_HIDE);
|
|
GetDlgItem(IDC_DISPLAY_BBOX)->EnableWindow(FALSE);
|
|
GetDlgItem(IDC_LINK_TO_SKELETON)->EnableWindow(FALSE);
|
|
GetDlgItem(IDC_UNLINK_FROM_SKELETON)->EnableWindow(FALSE);
|
|
GetDlgItem(IDC_ACTIVE_PS)->EnableWindow(FALSE);
|
|
GetDlgItem(IDC_BROWSE_ANIM)->EnableWindow(FALSE);
|
|
GetDlgItem(IDC_DISPLAY_HELPERS)->EnableWindow(FALSE);
|
|
GetDlgItem(IDC_CLEAR_ANIM)->EnableWindow(FALSE);
|
|
m_TriggerAnim = "";
|
|
}
|
|
else
|
|
{
|
|
if (!_ActiveNode->getParentSkelName().empty())
|
|
{
|
|
GetDlgItem(IDC_STICK_BONE)->SetWindowText((_ActiveNode->getParentBoneName() + "." + _ActiveNode->getParentBoneName()).c_str());
|
|
}
|
|
else
|
|
{
|
|
GetDlgItem(IDC_STICK_BONE)->SetWindowText("");
|
|
}
|
|
GetDlgItem(IDC_ACTIVE_PS)->SetWindowText(_ActiveNode->getFilename().c_str());
|
|
GetDlgItem(IDC_ENABLE_AUTO_COUNT)->EnableWindow(TRUE);
|
|
((CButton *) GetDlgItem(IDC_ENABLE_AUTO_COUNT))->SetCheck(getCurrPS()->getAutoCountFlag() ? 1 : 0);
|
|
GetDlgItem(IDC_RESET_COUNT)->EnableWindow((_ActiveNode->getPSPointer()->getAutoCountFlag() && !_ActiveNode->getResetAutoCountFlag()) ? TRUE : FALSE);
|
|
GetDlgItem(IDC_NUM_PARTICLES)->ShowWindow(SW_SHOW);
|
|
GetDlgItem(IDC_NUM_ASKED_FACES)->ShowWindow(SW_SHOW);
|
|
GetDlgItem(IDC_SYSTEM_DATE)->ShowWindow(SW_SHOW);
|
|
GetDlgItem(IDC_DISPLAY_BBOX)->EnableWindow(TRUE);
|
|
GetDlgItem(IDC_LINK_TO_SKELETON)->EnableWindow(TRUE);
|
|
GetDlgItem(IDC_UNLINK_FROM_SKELETON)->EnableWindow(TRUE);
|
|
GetDlgItem(IDC_ACTIVE_PS)->EnableWindow(TRUE);
|
|
GetDlgItem(IDC_BROWSE_ANIM)->EnableWindow(TRUE);
|
|
GetDlgItem(IDC_DISPLAY_HELPERS)->EnableWindow(isRunning());
|
|
GetDlgItem(IDC_CLEAR_ANIM)->EnableWindow(!_ActiveNode->getTriggerAnim().empty());
|
|
m_TriggerAnim = _ActiveNode->getTriggerAnim().c_str();
|
|
}
|
|
UpdateData(FALSE);
|
|
}
|
|
|
|
//******************************************************************************************************
|
|
void CStartStopParticleSystem::start()
|
|
{
|
|
UpdateData();
|
|
switch(_State)
|
|
{
|
|
case Stopped:
|
|
if (_ActiveNode)
|
|
{
|
|
if (checkHasLoop(*_ActiveNode)) return;
|
|
play(*_ActiveNode);
|
|
nlassert(_PlayingNodes.empty());
|
|
_PlayingNodes.push_back(_ActiveNode);
|
|
}
|
|
GetDlgItem(IDC_RESET_COUNT)->EnableWindow(TRUE);
|
|
break;
|
|
case RunningSingle:
|
|
// no-op
|
|
return;
|
|
break;
|
|
case RunningMultiple:
|
|
stop();
|
|
start();
|
|
break;
|
|
case PausedSingle:
|
|
if (_ActiveNode)
|
|
{
|
|
unpause(*_ActiveNode);
|
|
}
|
|
break;
|
|
case PausedMultiple:
|
|
for(uint k = 0; k < _PlayingNodes.size(); ++k)
|
|
{
|
|
if (_PlayingNodes[k])
|
|
{
|
|
unpause(*_PlayingNodes[k]);
|
|
}
|
|
}
|
|
stop();
|
|
start();
|
|
break;
|
|
default:
|
|
nlassert(0);
|
|
break;
|
|
}
|
|
_State = RunningSingle;
|
|
updateUIFromState();
|
|
if (m_LinkPlayToScenePlay) // is scene animation subordinated to the fx animation
|
|
{
|
|
// start animation for the scene too
|
|
if (_AnimationDLG)
|
|
{
|
|
_AnimationDLG->Playing = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
//******************************************************************************************************
|
|
void CStartStopParticleSystem::startMultiple()
|
|
{
|
|
UpdateData();
|
|
switch(_State)
|
|
{
|
|
case Stopped:
|
|
{
|
|
CParticleWorkspace *pws = _ParticleDlg->getParticleWorkspace();
|
|
if (!pws) return;
|
|
nlassert(_PlayingNodes.empty());
|
|
for(uint k = 0; k < pws->getNumNode(); ++k)
|
|
{
|
|
if (pws->getNode(k)->isLoaded())
|
|
{
|
|
if (checkHasLoop(*pws->getNode(k))) return;
|
|
}
|
|
}
|
|
for(uint k = 0; k < pws->getNumNode(); ++k)
|
|
{
|
|
if (pws->getNode(k)->isLoaded())
|
|
{
|
|
// really start the node only if there's no trigger anim
|
|
if (pws->getNode(k)->getTriggerAnim().empty())
|
|
{
|
|
play(*pws->getNode(k));
|
|
}
|
|
_PlayingNodes.push_back(pws->getNode(k));
|
|
}
|
|
}
|
|
GetDlgItem(IDC_RESET_COUNT)->EnableWindow(TRUE);
|
|
}
|
|
break;
|
|
case PausedSingle:
|
|
case RunningSingle:
|
|
stop();
|
|
startMultiple();
|
|
break;
|
|
case RunningMultiple:
|
|
// no-op
|
|
return;
|
|
break;
|
|
case PausedMultiple:
|
|
for(uint k = 0; k < _PlayingNodes.size(); ++k)
|
|
{
|
|
if (_PlayingNodes[k])
|
|
{
|
|
unpause(*_PlayingNodes[k]);
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
nlassert(0);
|
|
break;
|
|
}
|
|
_State = RunningMultiple;
|
|
updateUIFromState();
|
|
if (m_LinkPlayToScenePlay) // is scene animation subordinated to the fx animation
|
|
{
|
|
// start animation for the scene too
|
|
if (_AnimationDLG)
|
|
{
|
|
_AnimationDLG->Playing = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
//******************************************************************************************************
|
|
void CStartStopParticleSystem::stop()
|
|
{
|
|
switch(_State)
|
|
{
|
|
case Stopped:
|
|
// no-op
|
|
return;
|
|
case RunningSingle:
|
|
case RunningMultiple:
|
|
case PausedSingle:
|
|
case PausedMultiple:
|
|
for(uint k = 0; k < _PlayingNodes.size(); ++k)
|
|
{
|
|
if (_PlayingNodes[k])
|
|
{
|
|
stop(*_PlayingNodes[k]);
|
|
}
|
|
}
|
|
_PlayingNodes.clear();
|
|
break;
|
|
default:
|
|
nlassert(0);
|
|
break;
|
|
}
|
|
_State = Stopped;
|
|
if (IsWindow(*this)) updateUIFromState();
|
|
if (m_LinkPlayToScenePlay) // is scene animation subordinated to the fx animation
|
|
{
|
|
// start animation for the scene too
|
|
if (_AnimationDLG)
|
|
{
|
|
_AnimationDLG->Playing = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
//******************************************************************************************************
|
|
void CStartStopParticleSystem::pause()
|
|
{
|
|
switch(_State)
|
|
{
|
|
case Stopped:
|
|
// no-op
|
|
return;
|
|
case RunningSingle:
|
|
if (_ActiveNode)
|
|
{
|
|
pause(*_ActiveNode);
|
|
}
|
|
_State = PausedSingle;
|
|
updateUIFromState();
|
|
break;
|
|
case RunningMultiple:
|
|
for(uint k = 0; k < _PlayingNodes.size(); ++k)
|
|
{
|
|
if (_PlayingNodes[k])
|
|
{
|
|
pause(*_PlayingNodes[k]);
|
|
}
|
|
}
|
|
_State = PausedMultiple;
|
|
updateUIFromState();
|
|
break;
|
|
case PausedSingle:
|
|
case PausedMultiple:
|
|
// no-op
|
|
return;
|
|
default:
|
|
nlassert(0);
|
|
break;
|
|
}
|
|
if (m_LinkPlayToScenePlay) // is scene animation subordinated to the fx animation
|
|
{
|
|
// start animation for the scene too
|
|
if (_AnimationDLG)
|
|
{
|
|
_AnimationDLG->Playing = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
//******************************************************************************************************
|
|
void CStartStopParticleSystem::toggle()
|
|
{
|
|
switch(_State)
|
|
{
|
|
case Stopped:
|
|
break;
|
|
case RunningSingle:
|
|
pause();
|
|
break;
|
|
case RunningMultiple:
|
|
pause();
|
|
break;
|
|
case PausedSingle:
|
|
start();
|
|
break;
|
|
case PausedMultiple:
|
|
startMultiple();
|
|
break;
|
|
default:
|
|
nlassert(0);
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
///////////////////////////////////
|
|
|
|
//******************************************************************************************************
|
|
void CStartStopParticleSystem::setSpeedSliderValue(float value)
|
|
{
|
|
m_SpeedSliderPos = (int) (value * 100);
|
|
UpdateData(FALSE);
|
|
}
|
|
|
|
//******************************************************************************************************
|
|
void CStartStopParticleSystem::OnReleasedcaptureAnimSpeed(NMHDR* pNMHDR, LRESULT* pResult)
|
|
{
|
|
UpdateData();
|
|
CSliderCtrl *sl = (CSliderCtrl *) GetDlgItem(IDC_ANIM_SPEED);
|
|
setEllapsedTimeRatio(m_SpeedSliderPos * 0.01f);
|
|
*pResult = 0;
|
|
}
|
|
|
|
|
|
//******************************************************************************************************
|
|
void CStartStopParticleSystem::OnDisplayHelpers()
|
|
{
|
|
UpdateData();
|
|
if (!_ActiveNode) return;
|
|
}
|
|
|
|
//******************************************************************************************************
|
|
void CStartStopParticleSystem::OnEnableAutoCount()
|
|
{
|
|
nlassert(_ActiveNode);
|
|
stop();
|
|
bool autoCount = ((CButton *) GetDlgItem(IDC_ENABLE_AUTO_COUNT))->GetCheck() != 0;
|
|
if (autoCount)
|
|
{
|
|
CString caption;
|
|
CString mess;
|
|
caption.LoadString(IDS_PARTICLE_SYSTEM_EDITOR);
|
|
mess.LoadString(IDS_ENABLE_AUTOCOUNT);
|
|
if (MessageBox((LPCTSTR) mess, (LPCTSTR) caption, MB_OKCANCEL) != IDOK)
|
|
{
|
|
((CButton *) GetDlgItem(IDC_ENABLE_AUTO_COUNT))->SetCheck(0);
|
|
return;
|
|
}
|
|
resetAutoCount(_ActiveNode);
|
|
}
|
|
enableAutoCount(autoCount);
|
|
}
|
|
|
|
//******************************************************************************************************
|
|
void CStartStopParticleSystem::resetAutoCount(CParticleWorkspace::CNode *node, bool reset /* = true */)
|
|
{
|
|
if (!node) return;
|
|
if (node->getResetAutoCountFlag() == reset) return;
|
|
node->setResetAutoCountFlag(reset);
|
|
if (node == _ActiveNode)
|
|
{
|
|
GetDlgItem(IDC_RESET_COUNT)->EnableWindow((_ActiveNode->getPSPointer()->getAutoCountFlag() && !reset) ? TRUE : FALSE);
|
|
}
|
|
node->setModified(true);
|
|
}
|
|
|
|
//******************************************************************************************************
|
|
void CStartStopParticleSystem::OnResetCount()
|
|
{
|
|
stop();
|
|
resetAutoCount(_ActiveNode);
|
|
}
|
|
|
|
//******************************************************************************************************
|
|
void CStartStopParticleSystem::enableAutoCount(bool enable)
|
|
|
|
{
|
|
if (!_ActiveNode) return;
|
|
if (enable == _ActiveNode->getPSPointer()->getAutoCountFlag()) return;
|
|
nlassert(getCurrPS());
|
|
((CButton *) GetDlgItem(IDC_ENABLE_AUTO_COUNT))->SetCheck(enable ? 1 : 0);
|
|
_ActiveNode->getPSPointer()->setAutoCountFlag(enable);
|
|
_ActiveNode->setModified(true);
|
|
GetDlgItem(IDC_RESET_COUNT)->EnableWindow(FALSE);
|
|
CLocatedProperties *lp =dynamic_cast<CLocatedProperties *>(_ParticleDlg->getRightPane());
|
|
if (lp)
|
|
{
|
|
lp->getParticleCountDlg()->EnableWindow(enable ? FALSE : TRUE);
|
|
}
|
|
}
|
|
|
|
//******************************************************************************************************
|
|
void CStartStopParticleSystem::restartAllFX()
|
|
{
|
|
if (_State == RunningMultiple || _State == PausedMultiple)
|
|
{
|
|
for(uint k = 0; k < _PlayingNodes.size(); ++k)
|
|
{
|
|
if (_PlayingNodes[k])
|
|
{
|
|
stop(*_PlayingNodes[k]);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for(uint k = 0; k < _PlayingNodes.size(); ++k)
|
|
{
|
|
if (_PlayingNodes[k])
|
|
{
|
|
stop(*_PlayingNodes[k]);
|
|
play(*_PlayingNodes[k]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//******************************************************************************************************
|
|
void CStartStopParticleSystem::goPreRender()
|
|
{
|
|
if (!_ActiveNode) return;
|
|
NL3D::CParticleSystem *ps = _ActiveNode->getPSPointer();
|
|
sint currNumParticles = (sint) ps->getCurrNumParticles();
|
|
sint maxNumParticles = (sint) ps->getMaxNumParticles();
|
|
// if linked with scene animation, restart if animation ends
|
|
if (m_LinkPlayToScenePlay) // is scene animation subordinated to the fx animation
|
|
{
|
|
// start animation for the scene too
|
|
if (_AnimationDLG && isRunning())
|
|
{
|
|
if (_LastSceneAnimFrame > _AnimationDLG->CurrentFrame) // did animation restart ?
|
|
{
|
|
restartAllFX();
|
|
}
|
|
_LastSceneAnimFrame = _AnimationDLG->CurrentFrame;
|
|
}
|
|
}
|
|
else
|
|
if (_AutoRepeat && !m_LinkPlayToScenePlay) // auto repeat feature
|
|
{
|
|
if (isRunning())
|
|
{
|
|
bool allFXFinished = true;
|
|
bool fxStarted = false;
|
|
for(uint k = 0; k < _PlayingNodes.size(); ++k)
|
|
{
|
|
if (_PlayingNodes[k])
|
|
{
|
|
if (isRunning(_PlayingNodes[k]))
|
|
{
|
|
fxStarted = true;
|
|
if (_PlayingNodes[k]->getPSPointer()->getSystemDate() <= _PlayingNodes[k]->getPSPointer()->evalDuration())
|
|
{
|
|
allFXFinished = false;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
if (_PlayingNodes[k]->getPSPointer()->getCurrNumParticles() != 0)
|
|
{
|
|
allFXFinished = false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (fxStarted && allFXFinished)
|
|
{
|
|
restartAllFX();
|
|
}
|
|
}
|
|
}
|
|
if (_State == RunningMultiple || _State == PausedMultiple)
|
|
{
|
|
std::set<std::string> currAnims;
|
|
CObjectViewer *ov = _ParticleDlg->getObjectViewer();
|
|
for(uint k = 0; k < ov->getNumInstance(); ++k)
|
|
{
|
|
CInstanceInfo *ci = ov->getInstance(k);
|
|
uint animIndex = ci->Playlist.getAnimation(0);
|
|
if (animIndex != NL3D::CAnimationSet::NotFound)
|
|
{
|
|
std::string animName = ci->AnimationSet.getAnimationName(animIndex);
|
|
if (!animName.empty())
|
|
{
|
|
currAnims.insert(animName);
|
|
}
|
|
}
|
|
}
|
|
// check fx that have a trigger anim
|
|
for(uint k = 0; k < _PlayingNodes.size(); ++k)
|
|
{
|
|
if (_PlayingNodes[k])
|
|
{
|
|
if (!isRunning(_PlayingNodes[k]) || !_PlayingNodes[k]->getPSModel()->hasActiveEmitters())
|
|
{
|
|
// see if chosen anim is currently running
|
|
if (_PlayingNodes[k]->getTriggerAnim().empty() || currAnims.count(_PlayingNodes[k]->getTriggerAnim()))
|
|
{
|
|
// if the fx was shutting down, stop then restart it
|
|
if (!_PlayingNodes[k]->getPSModel()->hasActiveEmitters())
|
|
{
|
|
nlassert(isRunning(_PlayingNodes[k]));
|
|
stop(*_PlayingNodes[k]);
|
|
}
|
|
// yes -> trigger the fx
|
|
play(*_PlayingNodes[k]);
|
|
}
|
|
else if (!_PlayingNodes[k]->getPSPointer()->hasParticles()) // fx is being shut down, stop it when necessary
|
|
{
|
|
stop(*_PlayingNodes[k]); // no more particles so stop the system
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!_PlayingNodes[k]->getTriggerAnim().empty())
|
|
{
|
|
if (_PlayingNodes[k]->getPSModel()->hasActiveEmitters())
|
|
{
|
|
// see if anim if already playing. If this is not the case then shutdown the emitters
|
|
if (!currAnims.count(_PlayingNodes[k]->getTriggerAnim()))
|
|
{
|
|
_PlayingNodes[k]->getPSModel()->activateEmitters(false);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (_ActiveNode)
|
|
{
|
|
// display number of particles for the currently active node
|
|
if (currNumParticles != _LastCurrNumParticles || maxNumParticles != _LastMaxNumParticles)
|
|
{
|
|
CString numParts;
|
|
numParts.LoadString(IDS_NUM_PARTICLES);
|
|
numParts += CString(NLMISC::toString("%d / %d",(int) currNumParticles, (int) maxNumParticles).c_str());
|
|
GetDlgItem(IDC_NUM_PARTICLES)->SetWindowText((LPCTSTR) numParts);
|
|
_LastCurrNumParticles = currNumParticles;
|
|
_LastMaxNumParticles = maxNumParticles;
|
|
}
|
|
// display max number of wanted faces
|
|
NLMISC::CMatrix camMat = ps->getScene()->getCam()->getMatrix();
|
|
sint numWantedFaces = (uint) ps->getWantedNumTris((ps->getSysMat().getPos() - camMat.getPos()).norm());
|
|
if (numWantedFaces != _LastNumWantedFaces)
|
|
{
|
|
CString numWF;
|
|
numWF.LoadString(IDS_NUM_WANTED_FACES);
|
|
numWF += CString(NLMISC::toString("%d",(int) numWantedFaces).c_str());
|
|
GetDlgItem(IDC_NUM_ASKED_FACES)->SetWindowText((LPCTSTR) numWF);
|
|
_LastNumWantedFaces = numWantedFaces;
|
|
}
|
|
// display system date
|
|
if (ps->getSystemDate() != _LastSystemDate)
|
|
{
|
|
_LastSystemDate = ps->getSystemDate();
|
|
CString sysDate;
|
|
sysDate.LoadString(IDS_SYSTEM_DATE);
|
|
sysDate += CString(NLMISC::toString("%.2f s",_LastSystemDate).c_str());
|
|
GetDlgItem(IDC_SYSTEM_DATE)->SetWindowText((LPCTSTR) sysDate);
|
|
}
|
|
}
|
|
if (_ParticleDlg)
|
|
{
|
|
CParticleWorkspace *pws = _ParticleDlg->getParticleWorkspace();
|
|
if (pws)
|
|
{
|
|
for(uint k = 0; k < pws->getNumNode(); ++k)
|
|
{
|
|
if (pws->getNode(k)->isLoaded())
|
|
{
|
|
if (pws->getNode(k) == _ActiveNode)
|
|
{
|
|
pws->getNode(k)->getPSModel()->enableDisplayTools(!isRunning(pws->getNode(k)) || m_DisplayHelpers);
|
|
}
|
|
else
|
|
{
|
|
pws->getNode(k)->getPSModel()->enableDisplayTools(false);
|
|
}
|
|
// hide / show the node
|
|
if (_State == RunningMultiple || _State == PausedMultiple)
|
|
{
|
|
if (isRunning(pws->getNode(k)))
|
|
{
|
|
pws->getNode(k)->getPSModel()->show();
|
|
}
|
|
else
|
|
{
|
|
pws->getNode(k)->getPSModel()->hide();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (pws->getNode(k) == _ActiveNode)
|
|
{
|
|
pws->getNode(k)->getPSModel()->show();
|
|
}
|
|
else
|
|
{
|
|
pws->getNode(k)->getPSModel()->hide();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//******************************************************************************************************
|
|
void CStartStopParticleSystem::OnAutoRepeat()
|
|
{
|
|
_AutoRepeat = ((CButton *) GetDlgItem(IDC_AUTOREPEAT))->GetCheck() != 0;
|
|
}
|
|
|
|
//******************************************************************************************************
|
|
void CStartStopParticleSystem::OnLinkPlayToScenePlay()
|
|
{
|
|
// There are 2 play buttons : - one to activate play for the scene animation.
|
|
// - one to activate play for the fxs.
|
|
// When this method is called, the 'play' button of the scene is controlled by the 'play' button of the particle editor
|
|
// and thus is not accessible.
|
|
|
|
UpdateData(TRUE);
|
|
stop();
|
|
_AnimationDLG->setCurrentFrame(_AnimationDLG->Start);
|
|
_LastSceneAnimFrame = _AnimationDLG->Start;
|
|
_AnimationDLG->Playing = false;
|
|
_AnimationDLG->Loop = TRUE;
|
|
_AnimationDLG->UpdateData(FALSE);
|
|
_AnimationDLG->EnableWindow(!m_LinkPlayToScenePlay);
|
|
GetDlgItem(IDC_ANIM_SPEED)->EnableWindow(!m_LinkPlayToScenePlay);
|
|
if (m_LinkPlayToScenePlay)
|
|
{
|
|
m_SpeedSliderPos = 100;
|
|
setEllapsedTimeRatio(1.f);
|
|
}
|
|
UpdateData(FALSE);
|
|
}
|
|
|
|
//******************************************************************************************************
|
|
void CStartStopParticleSystem::OnLinkToSkeleton()
|
|
{
|
|
if (!_ActiveNode) return;
|
|
CObjectViewer *ov = _ParticleDlg->getObjectViewer();
|
|
if (!ov->isSkeletonPresent())
|
|
{
|
|
CString caption;
|
|
CString mess;
|
|
caption.LoadString(IDS_ERROR);
|
|
mess.LoadString(IDS_NO_SKELETON_IN_SCENE);
|
|
MessageBox((LPCTSTR) mess, (LPCTSTR) caption, MB_ICONEXCLAMATION);
|
|
return;
|
|
}
|
|
CString chooseBoneForPS;
|
|
chooseBoneForPS.LoadString(IDS_CHOOSE_BONE_FOR_PS);
|
|
NL3D::CSkeletonModel *skel;
|
|
uint boneIndex;
|
|
std::string parentSkelName;
|
|
std::string parentBoneName;
|
|
if (ov->chooseBone((LPCTSTR) chooseBoneForPS, skel, boneIndex, &parentSkelName, &parentBoneName))
|
|
{
|
|
_ParticleDlg->stickPSToSkeleton(_ActiveNode, skel, boneIndex, parentSkelName, parentBoneName);
|
|
}
|
|
updateUIFromState();
|
|
}
|
|
|
|
//******************************************************************************************************
|
|
void CStartStopParticleSystem::OnUnlinkFromSkeleton()
|
|
{
|
|
if (!_ActiveNode) return;
|
|
if (!_ParticleDlg->isPSStickedToSkeleton())
|
|
{
|
|
CString caption;
|
|
CString mess;
|
|
caption.LoadString(IDS_WARNING);
|
|
mess.LoadString(IDS_NOT_STICKED_TO_SKELETON);
|
|
return;
|
|
}
|
|
_ParticleDlg->unstickPSFromSkeleton(_ActiveNode);
|
|
updateUIFromState();
|
|
}
|
|
|
|
//******************************************************************************************************
|
|
void CStartStopParticleSystem::setActiveNode(CParticleWorkspace::CNode *activeNode)
|
|
{
|
|
if (activeNode == _ActiveNode) return;
|
|
forceActiveNode(activeNode);
|
|
}
|
|
|
|
//******************************************************************************************************
|
|
void CStartStopParticleSystem::forceActiveNode(CParticleWorkspace::CNode *activeNode)
|
|
{
|
|
UpdateData();
|
|
bool wasRunning = _State == RunningSingle;
|
|
if (wasRunning)
|
|
{
|
|
stop();
|
|
}
|
|
_ActiveNode = activeNode;
|
|
updateUIFromState();
|
|
if (wasRunning && _ActiveNode)
|
|
{
|
|
start();
|
|
}
|
|
}
|
|
|
|
//******************************************************************************************************
|
|
void CStartStopParticleSystem::setEllapsedTimeRatio(float value)
|
|
{
|
|
CParticleWorkspace *pw = _ParticleDlg->getParticleWorkspace();
|
|
if (!pw) return;
|
|
for(uint k = 0; k < pw->getNumNode(); ++k)
|
|
{
|
|
if (pw->getNode(k)->isLoaded())
|
|
{
|
|
pw->getNode(k)->getPSModel()->setEllapsedTimeRatio(value);
|
|
}
|
|
}
|
|
}
|
|
|
|
//******************************************************************************************************
|
|
bool CStartStopParticleSystem::checkHasLoop(CParticleWorkspace::CNode &node)
|
|
{
|
|
nlassert(node.isLoaded());
|
|
if (!node.getPSPointer()->hasLoop()) return false;
|
|
MessageBox(CString(node.getFilename().c_str()) + " : " + getStrRsc(IDS_FX_HAS_LOOP), getStrRsc(IDS_WARNING), MB_ICONEXCLAMATION);
|
|
return true;
|
|
}
|
|
|
|
//******************************************************************************************************
|
|
void CStartStopParticleSystem::play(CParticleWorkspace::CNode &node)
|
|
{
|
|
if (isRunning(&node)) return;
|
|
// NB : node must be stopped, no check is done
|
|
nlassert(node.isLoaded());
|
|
// if node not started, start it
|
|
node.memorizeState();
|
|
// enable the system to take the right date from the scene
|
|
node.getPSModel()->enableAutoGetEllapsedTime(true);
|
|
node.getPSPointer()->setSystemDate(0.f);
|
|
node.getPSPointer()->reactivateSound();
|
|
node.getPSModel()->activateEmitters(true);
|
|
if (node.getPSPointer()->getAutoCountFlag())
|
|
{
|
|
if (node.getResetAutoCountFlag())
|
|
{
|
|
// reset particle size arrays
|
|
node.getPSPointer()->matchArraySize();
|
|
}
|
|
resetAutoCount(&node, false);
|
|
}
|
|
CSliderCtrl *sl = (CSliderCtrl *) GetDlgItem(IDC_ANIM_SPEED);
|
|
node.getPSModel()->setEllapsedTimeRatio(m_SpeedSliderPos * 0.01f);
|
|
_ParticleDlg->ParticleTreeCtrl->suppressLocatedInstanceNbItem(node, 0);
|
|
}
|
|
|
|
//******************************************************************************************************
|
|
void CStartStopParticleSystem::unpause(CParticleWorkspace::CNode &node)
|
|
{
|
|
if (!isRunning(&node)) return;
|
|
nlassert(node.isLoaded());
|
|
node.getPSModel()->enableAutoGetEllapsedTime(true);
|
|
}
|
|
|
|
//******************************************************************************************************
|
|
void CStartStopParticleSystem::pause(CParticleWorkspace::CNode &node)
|
|
{
|
|
if (!isRunning(&node)) return;
|
|
nlassert(node.isLoaded());
|
|
node.getPSModel()->enableAutoGetEllapsedTime(false);
|
|
node.getPSModel()->setEllapsedTime(0.f);
|
|
}
|
|
|
|
//******************************************************************************************************
|
|
void CStartStopParticleSystem::stop(CParticleWorkspace::CNode &node)
|
|
{
|
|
if (!isRunning(&node)) return;
|
|
nlassert(node.isLoaded());
|
|
node.restoreState();
|
|
_ParticleDlg->ParticleTreeCtrl->rebuildLocatedInstance(node);
|
|
node.getPSModel()->enableAutoGetEllapsedTime(false);
|
|
node.getPSModel()->setEllapsedTime(0.f);
|
|
node.getPSModel()->activateEmitters(true);
|
|
node.getPSPointer()->stopSound();
|
|
}
|
|
|
|
//******************************************************************************************************
|
|
bool CStartStopParticleSystem::isRunning(CParticleWorkspace::CNode *node)
|
|
{
|
|
nlassert(node);
|
|
return node->isStateMemorized();
|
|
}
|
|
|
|
//******************************************************************************************************
|
|
void CStartStopParticleSystem::OnBrowseAnim()
|
|
{
|
|
/*
|
|
nlassert(_ActiveNode);
|
|
CChooseAnimation ca;
|
|
std::set<std::string> animSet;
|
|
CObjectViewer *ov = _ParticleDlg->getObjectViewer();
|
|
for(uint k = 0; k < ov->getNumInstance(); ++k)
|
|
{
|
|
CInstanceInfo *ii = ov->getInstance(k);
|
|
for(uint l = 0; l < ii->AnimationSet.getNumAnimation(); ++l)
|
|
{
|
|
animSet.insert(ii->AnimationSet.getAnimationName(l));
|
|
}
|
|
}
|
|
std::vector<std::string> animList(animSet.begin(), animSet.end());
|
|
ca.init(animList);
|
|
if (ca.DoModal() == IDOK)
|
|
{
|
|
m_TriggerAnim =ca.getSelectedAnim().c_str();
|
|
_ActiveNode->setTriggerAnim((LPCTSTR) m_TriggerAnim);
|
|
GetDlgItem(IDC_CLEAR_ANIM)->EnableWindow(!_ActiveNode->getTriggerAnim().empty());
|
|
}
|
|
_ParticleDlg->ParticleTreeCtrl->updateCaption(*_ActiveNode);
|
|
UpdateData(FALSE);
|
|
*/
|
|
nlassert(_ActiveNode);
|
|
std::set<std::string> animSet;
|
|
CObjectViewer *ov = _ParticleDlg->getObjectViewer();
|
|
for(uint k = 0; k < ov->getNumInstance(); ++k)
|
|
{
|
|
CInstanceInfo *ii = ov->getInstance(k);
|
|
for(uint l = 0; l < ii->AnimationSet.getNumAnimation(); ++l)
|
|
{
|
|
animSet.insert(ii->AnimationSet.getAnimationName(l));
|
|
}
|
|
}
|
|
std::vector<std::string> animList(animSet.begin(), animSet.end());
|
|
CSelectString st(animList, (LPCTSTR) getStrRsc(IDS_SELECT_ANIMATION), this, false);
|
|
if (st.DoModal() == IDOK && st.Selection != -1)
|
|
{
|
|
m_TriggerAnim = animList[st.Selection].c_str();
|
|
_ActiveNode->setTriggerAnim((LPCTSTR) m_TriggerAnim);
|
|
GetDlgItem(IDC_CLEAR_ANIM)->EnableWindow(!_ActiveNode->getTriggerAnim().empty());
|
|
}
|
|
_ParticleDlg->ParticleTreeCtrl->updateCaption(*_ActiveNode);
|
|
UpdateData(FALSE);
|
|
}
|
|
|
|
|
|
//******************************************************************************************************
|
|
void CStartStopParticleSystem::OnClearAnim()
|
|
{
|
|
// TODO: Add your control notification handler code here
|
|
m_TriggerAnim = "";
|
|
_ActiveNode->setTriggerAnim("");
|
|
_ParticleDlg->ParticleTreeCtrl->updateCaption(*_ActiveNode);
|
|
UpdateData(FALSE);
|
|
}
|
|
|
|
//******************************************************************************************************
|
|
void CStartStopParticleSystem::OnRestickAll()
|
|
{
|
|
if (_ParticleDlg->getParticleWorkspace())
|
|
{
|
|
_ParticleDlg->getParticleWorkspace()->restickAllObjects(_ParticleDlg->getObjectViewer());
|
|
}
|
|
}
|