Merge pull request #901 from demlow/animate_meshes

Animate meshes
This commit is contained in:
Alessandro Muntoni 2023-08-29 12:14:25 +02:00 committed by GitHub
commit 12ea457e13
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 322 additions and 2 deletions

View File

@ -82,18 +82,31 @@ LayerDialog::LayerDialog(QWidget *parent )
// The following connection is used to associate the click with the switch between raster and mesh view.
connect(ui->rasterTreeWidget, SIGNAL(itemClicked(QTreeWidgetItem * , int )) , this, SLOT(rasterItemClicked(QTreeWidgetItem * , int ) ) );
// state buttons
// state and animation buttons
isRecording = false;
viewState[0] = viewState[1] = viewState[2] = viewState[3] = "";
connect(ui->bW1, SIGNAL(clicked()), this, SLOT(clickW1()));
connect(ui->bW2, SIGNAL(clicked()), this, SLOT(clickW2()));
connect(ui->bW3, SIGNAL(clicked()), this, SLOT(clickW3()));
connect(ui->bW4, SIGNAL(clicked()), this, SLOT(clickW4()));
connect(ui->animSlower, SIGNAL(clicked()), this, SLOT(clickAnimSlower()));
connect(ui->animStepBackward, SIGNAL(clicked()), this, SLOT(clickAnimStepBackward()));
connect(ui->animPlay, SIGNAL(clicked()), this, SLOT(clickAnimPlay()));
connect(ui->animStepForward, SIGNAL(clicked()), this, SLOT(clickAnimStepForward()));
connect(ui->animFaster, SIGNAL(clicked()), this, SLOT(clickAnimFaster()));
connect(ui->bV1, SIGNAL(clicked()), this, SLOT(clickV1()));
connect(ui->bV2, SIGNAL(clicked()), this, SLOT(clickV2()));
connect(ui->bV3, SIGNAL(clicked()), this, SLOT(clickV3()));
connect(ui->bV4, SIGNAL(clicked()), this, SLOT(clickV4()));
animIndex = -1;
animMsecDelay = 500;
animTimer = new QTimer(this);
resetAnim();
connect(animTimer, SIGNAL(timeout()), this, SLOT(updateAnim()));
// Make wide enough to accommodate alternate text ("||") from clickAnimPlay()
ui->animPlay->setMinimumSize(ui->animPlay->size().width() + 6, ui->animPlay->size().height());
this->setContextMenuPolicy(Qt::CustomContextMenu);
ui->meshTreeWidget->setContextMenuPolicy(Qt::CustomContextMenu);
ui->rasterTreeWidget->setContextMenuPolicy(Qt::CustomContextMenu);
@ -219,6 +232,61 @@ void LayerDialog::clickW4()
mw->meshDoc()->Log.log(0, "No View to Restore");
}
void LayerDialog::clickAnimSlower()
{
if (animMsecDelay < 3000)
{
animMsecDelay = int(animMsecDelay * 1.2);
}
}
void LayerDialog::clickAnimStepBackward()
{
pauseAnim();
stepAnim(-1);
}
void LayerDialog::clickAnimPlay()
{
if (!animTimer->isActive() && startAnim())
{
ui->animPlay->setText(tr("||"));
ui->animPlay->setToolTip(tr("Pause animation"));
stepAnim(1);
animTimer->start(animMsecDelay);
}
else
{
pauseAnim();
}
}
void LayerDialog::clickAnimStepForward()
{
pauseAnim();
stepAnim(1);
}
void LayerDialog::clickAnimFaster()
{
if (animMsecDelay > 10)
{
animMsecDelay = int(animMsecDelay / 1.2f);
}
}
void LayerDialog::updateAnim()
{
if (stepAnim(1) > 1)
{
animTimer->start(animMsecDelay); // Restart in case animMsecDelay changed
}
else
{
pauseAnim();
}
}
void LayerDialog::clickV1()
{
MeshDocument *md = mw->meshDoc();
@ -406,6 +474,13 @@ void LayerDialog::meshItemClicked (QTreeWidgetItem * item , int col)
mw->GLA()->meshSetVisibility(*md->getMesh(clickedId), !md->getMesh(clickedId)->isVisible());
}
updatePerMeshItemVisibility();
// If not animating, or a mesh in the animation set was clicked, reset the animation
if (!ui->animPlay->isChecked() ||
std::find(animMeshIDs.begin(), animMeshIDs.end(), clickedId) != animMeshIDs.end())
{
resetAnim();
}
} break;
case 1 :
@ -676,6 +751,28 @@ void LayerDialog::updateTable(const MLSceneGLSharedDataContext::PerMeshRendering
}
_docitem->addChildren(itms);
// Delete any animation IDs no longer in the layer dialog
for (auto animIter = animMeshIDs.begin(); animIter != animMeshIDs.end(); )
{
bool foundInMeshList = false;
for(MeshModel& m : md->meshIterator())
{
if (m.id() == *animIter)
{
foundInMeshList = true;
break;
}
}
if (foundInMeshList)
{
++animIter;
}
else
{
animIter = animMeshIDs.erase(animIter);
}
}
updateTreeWidgetSizes(ui->meshTreeWidget);
updatePerMeshItemVisibility();
updatePerMeshItemSelectionStatus();
@ -861,6 +958,114 @@ void LayerDialog::actionActivated(MLRenderingAction* ract)
_tabw->switchTab(ract->meshId(),ract->text());
}
bool LayerDialog::startAnim()
{
if (animMeshIDs.size() > 1)
{
return true;
}
MeshDocument *md = mw->meshDoc();
bool canAnimate = md->meshNumber() > 1;
if (canAnimate)
{
int visibleCount = 0;
for(MeshModel& m : md->meshIterator())
{
if (m.isVisible())
{
++visibleCount;
}
}
// If fewer than two meshes were visible select all meshes, else select only the visible ones
animIndex = -1;
animMeshIDs.clear();
for(MeshModel& m : md->meshIterator())
{
if (m.isVisible() && animIndex < 0)
{
animIndex = animMeshIDs.size(); // Remember first visible mesh
}
if (m.isVisible() || visibleCount < 2)
{
animMeshIDs.push_back(m.id());
}
}
if (animIndex >= 0)
{
--animIndex;
}
ui->animStepBackward->setEnabled(true);
ui->animStepForward->setEnabled(true);
}
return canAnimate;
}
// Advance the animation by the specified offset (1 = forward, -1 = backward)
int LayerDialog::stepAnim(int offset)
{
bool foundVisible = false;
int animatingCount = 0;
MeshDocument *md = mw->meshDoc();
if (md->meshNumber() > 1)
{
MeshModel* lastMP = nullptr;
while (!foundVisible && animMeshIDs.size() > 1)
{
animIndex = (animMeshIDs.size() + animIndex + offset) % animMeshIDs.size();
animatingCount = 0;
for (const auto& id : animMeshIDs)
{
for(MeshModel& m : md->meshIterator())
{
if (m.id() == id)
{
bool makeVisible = m.id() == animMeshIDs[animIndex];
mw->GLA()->meshSetVisibility(m, makeVisible);
foundVisible |= makeVisible;
++animatingCount;
lastMP = &m;
}
}
}
if (!foundVisible)
{
// The mesh being animated to was deleted; remove it from the list and try again
animMeshIDs.erase(animMeshIDs.begin() + animIndex);
animIndex -= offset;
}
}
if (animMeshIDs.size() == 1 && lastMP != nullptr)
{
mw->GLA()->meshSetVisibility(*lastMP, true);
}
updatePerMeshItemVisibility();
updatePerMeshItemSelectionStatus();
mw->GLA()->update();
}
return animatingCount;
}
void LayerDialog::pauseAnim()
{
animTimer->stop();
ui->animPlay->setChecked(false);
ui->animPlay->setText(tr(">"));
ui->animPlay->setToolTip(tr("Resume animation"));
}
void LayerDialog::resetAnim()
{
pauseAnim();
animMeshIDs.clear();
ui->animStepBackward->setEnabled(false);
ui->animStepForward->setEnabled(false);
ui->animPlay->setToolTip(tr("Animate visible meshes, or all if < 2 are visible"));
}
LayerDialog::~LayerDialog()
{
delete ui;

View File

@ -30,6 +30,7 @@
#include <QTabWidget>
#include <QGroupBox>
#include <QCheckBox>
#include <QTimer>
#include <common/parameters/rich_parameter_list.h>
#include <common/ml_shared_data_context/ml_shared_data_context.h>
#include "ml_render_gui.h"
@ -140,6 +141,12 @@ public slots:
void clickW2();
void clickW3();
void clickW4();
void clickAnimSlower();
void clickAnimStepBackward();
void clickAnimPlay();
void clickAnimStepForward();
void clickAnimFaster();
void updateAnim();
void clickV1();
void clickV2();
void clickV3();
@ -177,6 +184,16 @@ private:
QString viewState[4];
QMap<int, bool> visibilityState[4];
int animIndex;
std::vector<int> animMeshIDs;
int animMsecDelay;
QTimer* animTimer;
bool startAnim();
int stepAnim(int offset);
void pauseAnim();
void resetAnim();
QTreeWidgetItem* _docitem;
int _previd;
QGroupBox* _renderingtabcontainer;

View File

@ -139,7 +139,105 @@
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<width>1</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QToolButton" name="animSlower">
<property name="font">
<font>
<pointsize>9</pointsize>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="toolTip">
<string>Decrease animation speed</string>
</property>
<property name="text">
<string>-</string>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="animStepBackward">
<property name="font">
<font>
<pointsize>9</pointsize>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="toolTip">
<string>Animate one step backward</string>
</property>
<property name="text">
<string>-1</string>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="animPlay">
<property name="font">
<font>
<pointsize>9</pointsize>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>&gt;</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="animStepForward">
<property name="font">
<font>
<pointsize>9</pointsize>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="toolTip">
<string>Animate one step forward</string>
</property>
<property name="text">
<string>+1</string>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="animFaster">
<property name="font">
<font>
<pointsize>9</pointsize>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="toolTip">
<string>Increase animation speed</string>
</property>
<property name="text">
<string>+</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>1</width>
<height>20</height>
</size>
</property>