Merge branch 'protocol_changes' into sound

This commit is contained in:
HifiExperiments 2024-04-05 23:22:22 -07:00 committed by GitHub
commit aa5e8e635e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 130 additions and 75 deletions

View file

@ -1123,37 +1123,7 @@ void ModelEntityRenderer::onRemoveFromSceneTyped(const TypedEntityPointer& entit
entity->setModel({}); entity->setModel({});
} }
void ModelEntityRenderer::animate(const TypedEntityPointer& entity, const ModelPointer& model) { void ModelEntityRenderer::updateJointData(const QVector<glm::vec3>& translations, const QVector<glm::quat>& rotations, const TypedEntityPointer& entity, const ModelPointer& model) {
if (!_animation || !_animation->isLoaded()) {
return;
}
QVector<EntityJointData> jointsData;
const QVector<HFMAnimationFrame>& frames = _animation->getFramesReference(); // NOTE: getFrames() is too heavy
int frameCount = frames.size();
if (frameCount <= 0) {
return;
}
{
float currentFrame = fmod(entity->getAnimationCurrentFrame(), (float)(frameCount));
if (currentFrame < 0.0f) {
currentFrame += (float)frameCount;
}
int currentIntegerFrame = (int)(glm::floor(currentFrame));
if (currentIntegerFrame == _lastKnownCurrentFrame) {
return;
}
_lastKnownCurrentFrame = currentIntegerFrame;
}
if (_jointMapping.size() != model->getJointStateCount()) {
qCWarning(entitiesrenderer) << "RenderableModelEntityItem::getAnimationFrame -- joint count mismatch"
<< _jointMapping.size() << model->getJointStateCount();
return;
}
QStringList animationJointNames = _animation->getHFMModel().getJointNames(); QStringList animationJointNames = _animation->getHFMModel().getJointNames();
auto& hfmJoints = _animation->getHFMModel().joints; auto& hfmJoints = _animation->getHFMModel().joints;
@ -1162,10 +1132,7 @@ void ModelEntityRenderer::animate(const TypedEntityPointer& entity, const ModelP
bool allowTranslation = entity->getAnimationAllowTranslation(); bool allowTranslation = entity->getAnimationAllowTranslation();
const QVector<glm::quat>& rotations = frames[_lastKnownCurrentFrame].rotations; QVector<EntityJointData> jointsData(_jointMapping.size());
const QVector<glm::vec3>& translations = frames[_lastKnownCurrentFrame].translations;
jointsData.resize(_jointMapping.size());
for (int j = 0; j < _jointMapping.size(); j++) { for (int j = 0; j < _jointMapping.size(); j++) {
int index = _jointMapping[j]; int index = _jointMapping[j];
@ -1206,6 +1173,58 @@ void ModelEntityRenderer::animate(const TypedEntityPointer& entity, const ModelP
entity->copyAnimationJointDataToModel(); entity->copyAnimationJointDataToModel();
} }
void ModelEntityRenderer::animate(const TypedEntityPointer& entity, const ModelPointer& model) {
if (!_animation || !_animation->isLoaded()) {
return;
}
const QVector<HFMAnimationFrame>& frames = _animation->getFramesReference(); // NOTE: getFrames() is too heavy
int frameCount = frames.size();
if (frameCount <= 0) {
return;
}
float currentFrame = fmod(entity->getAnimationCurrentFrame(), (float)(frameCount));
if (currentFrame < 0.0f) {
currentFrame += (float)frameCount;
}
const bool smoothFrames = entity->getAnimationSmoothFrames();
const int currentIntegerFrame = (int)(glm::floor(currentFrame));
if (!smoothFrames && currentIntegerFrame == _lastKnownCurrentIntegerFrame) {
return;
}
_lastKnownCurrentIntegerFrame = currentIntegerFrame;
if (_jointMapping.size() != model->getJointStateCount()) {
qCWarning(entitiesrenderer) << "RenderableModelEntityItem::getAnimationFrame -- joint count mismatch"
<< _jointMapping.size() << model->getJointStateCount();
return;
}
if (smoothFrames) {
QVector<glm::quat> rotations = frames[_lastKnownCurrentIntegerFrame].rotations;
QVector<glm::vec3> translations = frames[_lastKnownCurrentIntegerFrame].translations;
const int nextIntegerFrame = entity->getAnimationNextFrame(_lastKnownCurrentIntegerFrame, frameCount);
const QVector<glm::quat>& nextRotations = frames[nextIntegerFrame].rotations;
const QVector<glm::vec3>& nextTranslations = frames[nextIntegerFrame].translations;
const float frac = glm::fract(currentFrame);
for (int i = 0; i < translations.size(); i++) {
translations[i] = glm::mix(translations[i], nextTranslations[i], frac);
}
for (int i = 0; i < rotations.size(); i++) {
rotations[i] = glm::slerp(rotations[i], nextRotations[i], frac);
}
updateJointData(translations, rotations, entity, model);
} else {
updateJointData(frames[_lastKnownCurrentIntegerFrame].translations, frames[_lastKnownCurrentIntegerFrame].rotations, entity, model);
}
}
bool ModelEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const { bool ModelEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const {
if (entity->blendshapesChanged()) { if (entity->blendshapesChanged()) {
return true; return true;

View file

@ -175,6 +175,7 @@ protected:
private: private:
void animate(const TypedEntityPointer& entity, const ModelPointer& model); void animate(const TypedEntityPointer& entity, const ModelPointer& model);
void updateJointData(const QVector<glm::vec3>& translations, const QVector<glm::quat>& rotations, const TypedEntityPointer& entity, const ModelPointer& model);
void mapJoints(const TypedEntityPointer& entity, const ModelPointer& model); void mapJoints(const TypedEntityPointer& entity, const ModelPointer& model);
// Transparency is handled in ModelMeshPartPayload // Transparency is handled in ModelMeshPartPayload
@ -184,7 +185,7 @@ private:
ModelPointer _model; ModelPointer _model;
QString _textures; QString _textures;
bool _texturesLoaded { false }; bool _texturesLoaded { false };
int _lastKnownCurrentFrame { -1 }; int _lastKnownCurrentIntegerFrame { -1 };
#ifdef MODEL_ENTITY_USE_FADE_EFFECT #ifdef MODEL_ENTITY_USE_FADE_EFFECT
bool _hasTransitioned{ false }; bool _hasTransitioned{ false };
#endif #endif

View file

@ -32,20 +32,8 @@ bool operator==(const AnimationPropertyGroup& a, const AnimationPropertyGroup& b
(a._lastFrame == b._lastFrame) && (a._lastFrame == b._lastFrame) &&
(a._fps == b._fps) && (a._fps == b._fps) &&
(a._allowTranslation == b._allowTranslation) && (a._allowTranslation == b._allowTranslation) &&
(a._url == b._url); (a._url == b._url) &&
} (a._smoothFrames == b._smoothFrames);
bool operator!=(const AnimationPropertyGroup& a, const AnimationPropertyGroup& b) {
return
(a._currentFrame != b._currentFrame) ||
(a._running != b._running) ||
(a._loop != b._loop) ||
(a._hold != b._hold) ||
(a._firstFrame != b._firstFrame) ||
(a._lastFrame != b._lastFrame) ||
(a._fps != b._fps) ||
(a._allowTranslation != b._allowTranslation) ||
(a._url != b._url);
} }
@ -66,6 +54,8 @@ bool operator!=(const AnimationPropertyGroup& a, const AnimationPropertyGroup& b
* it isn't. * it isn't.
* @property {boolean} hold=false - <code>true</code> if the rotations and translations of the last frame played are * @property {boolean} hold=false - <code>true</code> if the rotations and translations of the last frame played are
* maintained when the animation stops playing, <code>false</code> if they aren't. * maintained when the animation stops playing, <code>false</code> if they aren't.
* @property {boolean} smoothFrames=true - <code>true</code> if the frames of the animation should be linearly interpolated to
* create smoother movement, <code>false</code> if the frames should not be interpolated.
*/ */
void AnimationPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValue& properties, ScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const { void AnimationPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValue& properties, ScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const {
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_ANIMATION_URL, Animation, animation, URL, url); COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_ANIMATION_URL, Animation, animation, URL, url);
@ -77,6 +67,7 @@ void AnimationPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desire
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_ANIMATION_FIRST_FRAME, Animation, animation, FirstFrame, firstFrame); COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_ANIMATION_FIRST_FRAME, Animation, animation, FirstFrame, firstFrame);
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_ANIMATION_LAST_FRAME, Animation, animation, LastFrame, lastFrame); COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_ANIMATION_LAST_FRAME, Animation, animation, LastFrame, lastFrame);
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_ANIMATION_HOLD, Animation, animation, Hold, hold); COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_ANIMATION_HOLD, Animation, animation, Hold, hold);
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_ANIMATION_SMOOTH_FRAMES, Animation, animation, SmoothFrames, smoothFrames);
} }
@ -96,6 +87,7 @@ void AnimationPropertyGroup::copyFromScriptValue(const ScriptValue& object, cons
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(animation, firstFrame, float, setFirstFrame); COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(animation, firstFrame, float, setFirstFrame);
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(animation, lastFrame, float, setLastFrame); COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(animation, lastFrame, float, setLastFrame);
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(animation, hold, bool, setHold); COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(animation, hold, bool, setHold);
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(animation, smoothFrames, bool, setSmoothFrames);
// legacy property support // legacy property support
COPY_PROPERTY_FROM_QSCRIPTVALUE_GETTER(animationFPS, float, setFPS, getFPS); COPY_PROPERTY_FROM_QSCRIPTVALUE_GETTER(animationFPS, float, setFPS, getFPS);
@ -113,6 +105,7 @@ void AnimationPropertyGroup::merge(const AnimationPropertyGroup& other) {
COPY_PROPERTY_IF_CHANGED(firstFrame); COPY_PROPERTY_IF_CHANGED(firstFrame);
COPY_PROPERTY_IF_CHANGED(lastFrame); COPY_PROPERTY_IF_CHANGED(lastFrame);
COPY_PROPERTY_IF_CHANGED(hold); COPY_PROPERTY_IF_CHANGED(hold);
COPY_PROPERTY_IF_CHANGED(smoothFrames);
} }
void AnimationPropertyGroup::setFromOldAnimationSettings(const QString& value) { void AnimationPropertyGroup::setFromOldAnimationSettings(const QString& value) {
@ -120,19 +113,23 @@ void AnimationPropertyGroup::setFromOldAnimationSettings(const QString& value) {
// if it includes fps, currentFrame, or running, those values will be parsed out and // if it includes fps, currentFrame, or running, those values will be parsed out and
// will over ride the regular animation settings // will over ride the regular animation settings
bool allowTranslation = getAllowTranslation();
float fps = getFPS(); float fps = getFPS();
float currentFrame = getCurrentFrame(); float currentFrame = getCurrentFrame();
bool running = getRunning(); bool running = getRunning();
bool loop = getLoop();
float firstFrame = getFirstFrame(); float firstFrame = getFirstFrame();
float lastFrame = getLastFrame(); float lastFrame = getLastFrame();
bool loop = getLoop();
bool hold = getHold(); bool hold = getHold();
bool allowTranslation = getAllowTranslation();
QJsonDocument settingsAsJson = QJsonDocument::fromJson(value.toUtf8()); QJsonDocument settingsAsJson = QJsonDocument::fromJson(value.toUtf8());
QJsonObject settingsAsJsonObject = settingsAsJson.object(); QJsonObject settingsAsJsonObject = settingsAsJson.object();
QVariantMap settingsMap = settingsAsJsonObject.toVariantMap(); QVariantMap settingsMap = settingsAsJsonObject.toVariantMap();
if (settingsMap.contains("allowTranslation")) {
allowTranslation = settingsMap["allowTranslation"].toBool();
}
if (settingsMap.contains("fps")) { if (settingsMap.contains("fps")) {
fps = settingsMap["fps"].toFloat(); fps = settingsMap["fps"].toFloat();
} }
@ -150,30 +147,25 @@ void AnimationPropertyGroup::setFromOldAnimationSettings(const QString& value) {
firstFrame = settingsMap["firstFrame"].toFloat(); firstFrame = settingsMap["firstFrame"].toFloat();
} }
if (settingsMap.contains("loop")) {
loop = settingsMap["loop"].toBool();
}
if (settingsMap.contains("lastFrame")) { if (settingsMap.contains("lastFrame")) {
lastFrame = settingsMap["lastFrame"].toFloat(); lastFrame = settingsMap["lastFrame"].toFloat();
} }
if (settingsMap.contains("loop")) {
running = settingsMap["loop"].toBool();
}
if (settingsMap.contains("hold")) { if (settingsMap.contains("hold")) {
running = settingsMap["hold"].toBool(); hold = settingsMap["hold"].toBool();
} }
if (settingsMap.contains("allowTranslation")) {
allowTranslation = settingsMap["allowTranslation"].toBool();
}
setAllowTranslation(allowTranslation); setAllowTranslation(allowTranslation);
setFPS(fps); setFPS(fps);
setCurrentFrame(currentFrame); setCurrentFrame(currentFrame);
setRunning(running); setRunning(running);
setLoop(loop);
setFirstFrame(firstFrame); setFirstFrame(firstFrame);
setLastFrame(lastFrame); setLastFrame(lastFrame);
setLoop(loop);
setHold(hold); setHold(hold);
} }
@ -213,6 +205,9 @@ void AnimationPropertyGroup::listChangedProperties(QList<QString>& out) {
if (holdChanged()) { if (holdChanged()) {
out << "animation-hold"; out << "animation-hold";
} }
if (smoothFramesChanged()) {
out << "animation-smoothFrames";
}
} }
@ -234,6 +229,7 @@ bool AnimationPropertyGroup::appendToEditPacket(OctreePacketData* packetData,
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FIRST_FRAME, getFirstFrame()); APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FIRST_FRAME, getFirstFrame());
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_LAST_FRAME, getLastFrame()); APPEND_ENTITY_PROPERTY(PROP_ANIMATION_LAST_FRAME, getLastFrame());
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_HOLD, getHold()); APPEND_ENTITY_PROPERTY(PROP_ANIMATION_HOLD, getHold());
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_SMOOTH_FRAMES, getSmoothFrames());
return true; return true;
} }
@ -253,6 +249,7 @@ bool AnimationPropertyGroup::decodeFromEditPacket(EntityPropertyFlags& propertyF
READ_ENTITY_PROPERTY(PROP_ANIMATION_FIRST_FRAME, float, setFirstFrame); READ_ENTITY_PROPERTY(PROP_ANIMATION_FIRST_FRAME, float, setFirstFrame);
READ_ENTITY_PROPERTY(PROP_ANIMATION_LAST_FRAME, float, setLastFrame); READ_ENTITY_PROPERTY(PROP_ANIMATION_LAST_FRAME, float, setLastFrame);
READ_ENTITY_PROPERTY(PROP_ANIMATION_HOLD, bool, setHold); READ_ENTITY_PROPERTY(PROP_ANIMATION_HOLD, bool, setHold);
READ_ENTITY_PROPERTY(PROP_ANIMATION_SMOOTH_FRAMES, bool, setSmoothFrames);
DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_ANIMATION_URL, URL); DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_ANIMATION_URL, URL);
DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_ANIMATION_ALLOW_TRANSLATION, AllowTranslation); DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_ANIMATION_ALLOW_TRANSLATION, AllowTranslation);
@ -263,6 +260,7 @@ bool AnimationPropertyGroup::decodeFromEditPacket(EntityPropertyFlags& propertyF
DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_ANIMATION_FIRST_FRAME, FirstFrame); DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_ANIMATION_FIRST_FRAME, FirstFrame);
DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_ANIMATION_LAST_FRAME, LastFrame); DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_ANIMATION_LAST_FRAME, LastFrame);
DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_ANIMATION_HOLD, Hold); DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_ANIMATION_HOLD, Hold);
DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_ANIMATION_SMOOTH_FRAMES, SmoothFrames);
processedBytes += bytesRead; processedBytes += bytesRead;
@ -281,6 +279,7 @@ void AnimationPropertyGroup::markAllChanged() {
_firstFrameChanged = true; _firstFrameChanged = true;
_lastFrameChanged = true; _lastFrameChanged = true;
_holdChanged = true; _holdChanged = true;
_smoothFramesChanged = true;
} }
EntityPropertyFlags AnimationPropertyGroup::getChangedProperties() const { EntityPropertyFlags AnimationPropertyGroup::getChangedProperties() const {
@ -295,6 +294,7 @@ EntityPropertyFlags AnimationPropertyGroup::getChangedProperties() const {
CHECK_PROPERTY_CHANGE(PROP_ANIMATION_FIRST_FRAME, firstFrame); CHECK_PROPERTY_CHANGE(PROP_ANIMATION_FIRST_FRAME, firstFrame);
CHECK_PROPERTY_CHANGE(PROP_ANIMATION_LAST_FRAME, lastFrame); CHECK_PROPERTY_CHANGE(PROP_ANIMATION_LAST_FRAME, lastFrame);
CHECK_PROPERTY_CHANGE(PROP_ANIMATION_HOLD, hold); CHECK_PROPERTY_CHANGE(PROP_ANIMATION_HOLD, hold);
CHECK_PROPERTY_CHANGE(PROP_ANIMATION_SMOOTH_FRAMES, smoothFrames);
return changedProperties; return changedProperties;
} }
@ -309,6 +309,7 @@ void AnimationPropertyGroup::getProperties(EntityItemProperties& properties) con
COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Animation, FirstFrame, getFirstFrame); COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Animation, FirstFrame, getFirstFrame);
COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Animation, LastFrame, getLastFrame); COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Animation, LastFrame, getLastFrame);
COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Animation, Hold, getHold); COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Animation, Hold, getHold);
COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Animation, SmoothFrames, getSmoothFrames);
} }
bool AnimationPropertyGroup::setProperties(const EntityItemProperties& properties) { bool AnimationPropertyGroup::setProperties(const EntityItemProperties& properties) {
@ -323,6 +324,7 @@ bool AnimationPropertyGroup::setProperties(const EntityItemProperties& propertie
SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Animation, FirstFrame, firstFrame, setFirstFrame); SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Animation, FirstFrame, firstFrame, setFirstFrame);
SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Animation, LastFrame, lastFrame, setLastFrame); SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Animation, LastFrame, lastFrame, setLastFrame);
SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Animation, Hold, hold, setHold); SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Animation, Hold, hold, setHold);
SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Animation, SmoothFrames, smoothFrames, setSmoothFrames);
return somethingChanged; return somethingChanged;
} }
@ -338,6 +340,7 @@ EntityPropertyFlags AnimationPropertyGroup::getEntityProperties(EncodeBitstreamP
requestedProperties += PROP_ANIMATION_FIRST_FRAME; requestedProperties += PROP_ANIMATION_FIRST_FRAME;
requestedProperties += PROP_ANIMATION_LAST_FRAME; requestedProperties += PROP_ANIMATION_LAST_FRAME;
requestedProperties += PROP_ANIMATION_HOLD; requestedProperties += PROP_ANIMATION_HOLD;
requestedProperties += PROP_ANIMATION_SMOOTH_FRAMES;
return requestedProperties; return requestedProperties;
} }
@ -361,6 +364,7 @@ void AnimationPropertyGroup::appendSubclassData(OctreePacketData* packetData, En
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FIRST_FRAME, getFirstFrame()); APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FIRST_FRAME, getFirstFrame());
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_LAST_FRAME, getLastFrame()); APPEND_ENTITY_PROPERTY(PROP_ANIMATION_LAST_FRAME, getLastFrame());
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_HOLD, getHold()); APPEND_ENTITY_PROPERTY(PROP_ANIMATION_HOLD, getHold());
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_SMOOTH_FRAMES, getSmoothFrames());
} }
int AnimationPropertyGroup::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, int AnimationPropertyGroup::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
@ -380,6 +384,7 @@ int AnimationPropertyGroup::readEntitySubclassDataFromBuffer(const unsigned char
READ_ENTITY_PROPERTY(PROP_ANIMATION_FIRST_FRAME, float, setFirstFrame); READ_ENTITY_PROPERTY(PROP_ANIMATION_FIRST_FRAME, float, setFirstFrame);
READ_ENTITY_PROPERTY(PROP_ANIMATION_LAST_FRAME, float, setLastFrame); READ_ENTITY_PROPERTY(PROP_ANIMATION_LAST_FRAME, float, setLastFrame);
READ_ENTITY_PROPERTY(PROP_ANIMATION_HOLD, bool, setHold); READ_ENTITY_PROPERTY(PROP_ANIMATION_HOLD, bool, setHold);
READ_ENTITY_PROPERTY(PROP_ANIMATION_SMOOTH_FRAMES, bool, setSmoothFrames);
return bytesRead; return bytesRead;
} }

View file

@ -92,10 +92,11 @@ public:
DEFINE_PROPERTY(PROP_ANIMATION_LAST_FRAME, LastFrame, lastFrame, float, MAXIMUM_POSSIBLE_FRAME); // was animationSettings.lastFrame DEFINE_PROPERTY(PROP_ANIMATION_LAST_FRAME, LastFrame, lastFrame, float, MAXIMUM_POSSIBLE_FRAME); // was animationSettings.lastFrame
DEFINE_PROPERTY(PROP_ANIMATION_HOLD, Hold, hold, bool, false); // was animationSettings.hold DEFINE_PROPERTY(PROP_ANIMATION_HOLD, Hold, hold, bool, false); // was animationSettings.hold
DEFINE_PROPERTY(PROP_ANIMATION_ALLOW_TRANSLATION, AllowTranslation, allowTranslation, bool, true); DEFINE_PROPERTY(PROP_ANIMATION_ALLOW_TRANSLATION, AllowTranslation, allowTranslation, bool, true);
DEFINE_PROPERTY(PROP_ANIMATION_SMOOTH_FRAMES, SmoothFrames, smoothFrames, bool, true);
protected: protected:
friend bool operator==(const AnimationPropertyGroup& a, const AnimationPropertyGroup& b); friend bool operator==(const AnimationPropertyGroup& a, const AnimationPropertyGroup& b);
friend bool operator!=(const AnimationPropertyGroup& a, const AnimationPropertyGroup& b); friend bool operator!=(const AnimationPropertyGroup& a, const AnimationPropertyGroup& b) { return !(a == b); }
void setFromOldAnimationSettings(const QString& value); void setFromOldAnimationSettings(const QString& value);
}; };

View file

@ -2905,6 +2905,7 @@ bool EntityItemProperties::getPropertyInfo(const QString& propertyName, EntityPr
ADD_GROUP_PROPERTY_TO_MAP(PROP_ANIMATION_FIRST_FRAME, Animation, animation, FirstFrame, firstFrame); ADD_GROUP_PROPERTY_TO_MAP(PROP_ANIMATION_FIRST_FRAME, Animation, animation, FirstFrame, firstFrame);
ADD_GROUP_PROPERTY_TO_MAP(PROP_ANIMATION_LAST_FRAME, Animation, animation, LastFrame, lastFrame); ADD_GROUP_PROPERTY_TO_MAP(PROP_ANIMATION_LAST_FRAME, Animation, animation, LastFrame, lastFrame);
ADD_GROUP_PROPERTY_TO_MAP(PROP_ANIMATION_HOLD, Animation, animation, Hold, hold); ADD_GROUP_PROPERTY_TO_MAP(PROP_ANIMATION_HOLD, Animation, animation, Hold, hold);
ADD_GROUP_PROPERTY_TO_MAP(PROP_ANIMATION_SMOOTH_FRAMES, Animation, animation, SmoothFrames, smoothFrames);
} }
// Light // Light

View file

@ -237,6 +237,7 @@ enum EntityPropertyList {
PROP_ANIMATION_FIRST_FRAME = PROP_DERIVED_16, PROP_ANIMATION_FIRST_FRAME = PROP_DERIVED_16,
PROP_ANIMATION_LAST_FRAME = PROP_DERIVED_17, PROP_ANIMATION_LAST_FRAME = PROP_DERIVED_17,
PROP_ANIMATION_HOLD = PROP_DERIVED_18, PROP_ANIMATION_HOLD = PROP_DERIVED_18,
PROP_ANIMATION_SMOOTH_FRAMES = PROP_DERIVED_19,
// Light // Light
PROP_IS_SPOTLIGHT = PROP_DERIVED_0, PROP_IS_SPOTLIGHT = PROP_DERIVED_0,

View file

@ -2892,6 +2892,11 @@ bool EntityTree::readFromMap(QVariantMap& map, const bool isImport) {
} }
} }
// Before, animations weren't smoothed
if (contentVersion < (int)EntityVersion::AnimationSmoothFrames && properties.getType() == EntityTypes::EntityType::Model) {
properties.getAnimation().setSmoothFrames(false);
}
EntityItemPointer entity = addEntity(entityItemID, properties, isImport); EntityItemPointer entity = addEntity(entityItemID, properties, isImport);
if (!entity) { if (!entity) {
qCDebug(entities) << "adding Entity failed:" << entityItemID << properties.getType(); qCDebug(entities) << "adding Entity failed:" << entityItemID << properties.getType();

View file

@ -34,12 +34,10 @@ EntityItemPointer ModelEntityItem::factory(const EntityItemID& entityID, const E
} }
ModelEntityItem::ModelEntityItem(const EntityItemID& entityItemID) : EntityItem(entityItemID), ModelEntityItem::ModelEntityItem(const EntityItemID& entityItemID) : EntityItem(entityItemID),
_blendshapeCoefficientsVector((int)Blendshapes::BlendshapeCount, 0.0f) _blendshapeCoefficientsVector((int)Blendshapes::BlendshapeCount, 0.0f),
_lastAnimated(usecTimestampNow())
{ {
_lastAnimated = usecTimestampNow();
// set the last animated when interface (re)starts
_type = EntityTypes::Model; _type = EntityTypes::Model;
_lastKnownCurrentFrame = -1;
_visuallyReady = false; _visuallyReady = false;
} }
@ -643,6 +641,22 @@ bool ModelEntityItem::isAnimatingSomething() const {
}); });
} }
bool ModelEntityItem::getAnimationSmoothFrames() const {
return resultWithReadLock<bool>([&] {
return _animationProperties.getSmoothFrames();
});
}
int ModelEntityItem::getAnimationNextFrame(int currentFrame, int frameCount) const {
return resultWithReadLock<int>([&] {
int result = currentFrame + 1;
if (result > _animationProperties.getLastFrame() || result > (frameCount - 1)) {
result = _animationProperties.getFirstFrame();
}
return std::max(result, 0);
});
}
bool ModelEntityItem::applyNewAnimationProperties(AnimationPropertyGroup newProperties) { bool ModelEntityItem::applyNewAnimationProperties(AnimationPropertyGroup newProperties) {
// call applyNewAnimationProperties() whenever trying to update _animationProperties // call applyNewAnimationProperties() whenever trying to update _animationProperties
// because there is some reset logic we need to do whenever the animation "config" properties change // because there is some reset logic we need to do whenever the animation "config" properties change

View file

@ -56,8 +56,6 @@ public:
void setShapeType(ShapeType type) override; void setShapeType(ShapeType type) override;
virtual ShapeType getShapeType() const override; virtual ShapeType getShapeType() const override;
// TODO: Move these to subclasses, or other appropriate abstraction
// getters/setters applicable to models and particles
glm::u8vec3 getColor() const; glm::u8vec3 getColor() const;
void setColor(const glm::u8vec3& value); void setColor(const glm::u8vec3& value);
@ -89,6 +87,8 @@ public:
float getAnimationCurrentFrame() const; float getAnimationCurrentFrame() const;
bool getAnimationAllowTranslation() const; bool getAnimationAllowTranslation() const;
bool isAnimatingSomething() const; bool isAnimatingSomething() const;
bool getAnimationSmoothFrames() const;
int getAnimationNextFrame(int currentFrame, int frameCount) const;
void setRelayParentJoints(bool relayJoints); void setRelayParentJoints(bool relayJoints);
bool getRelayParentJoints() const; bool getRelayParentJoints() const;
@ -148,7 +148,6 @@ protected:
}; };
QVector<ModelJointData> _localJointData; QVector<ModelJointData> _localJointData;
int _lastKnownCurrentFrame{-1};
glm::u8vec3 _color; glm::u8vec3 _color;
glm::vec3 _modelScale { 1.0f }; glm::vec3 _modelScale { 1.0f };

View file

@ -294,6 +294,7 @@ enum class EntityVersion : PacketVersion {
EntityTags, EntityTags,
WantsKeyboardFocus, WantsKeyboardFocus,
AudioZones, AudioZones,
AnimationSmoothFrames,
SoundEntities, SoundEntities,
// Add new versions above here // Add new versions above here

View file

@ -215,6 +215,9 @@
"animation.fps": { "animation.fps": {
"tooltip": "The speed of the animation." "tooltip": "The speed of the animation."
}, },
"animation.smoothFrames": {
"tooltip": "If enabled, the frames of the animation will be linearly interpolated to create smoother movement."
},
"textures": { "textures": {
"tooltip": "A JSON string containing a texture. Use a name from the Original Texture property to override it." "tooltip": "A JSON string containing a texture. Use a name from the Original Texture property to override it."
}, },

View file

@ -729,6 +729,11 @@ const GROUPS = [
type: "number-draggable", type: "number-draggable",
propertyID: "animation.fps", propertyID: "animation.fps",
}, },
{
label: "Smooth Animation",
type: "bool",
propertyID: "animation.smoothFrames",
},
{ {
label: "Texture", label: "Texture",
type: "textarea", type: "textarea",