Model* RenderableModelEntityItem::getModel(EntityTreeRenderer* renderer) { Model* result = NULL; // make sure our renderer is setup if (!_myRenderer) { _myRenderer = renderer; } assert(_myRenderer == renderer); // you should only ever render on one renderer _needsModelReload = false; // this is the reload // if we have a URL, then we will want to end up returning a model... if (!getModelURL().isEmpty()) { // if we have a previously allocated model, but it's URL doesn't match // then we need to let our renderer update our model for us. if (_model && QUrl(getModelURL()) != _model->getURL()) { result = _model = _myRenderer->updateModel(_model, getModelURL()); _needsInitialSimulation = true; } else if (!_model) { // if we don't yet have a model, then we want our renderer to allocate one result = _model = _myRenderer->allocateModel(getModelURL()); _needsInitialSimulation = true; } else { // we already have the model we want... result = _model; } } else { // if our desired URL is empty, we may need to delete our existing model if (_model) { _myRenderer->releaseModel(_model); result = _model = NULL; _needsInitialSimulation = true; } } return result; }
ModelPointer RenderableModelEntityItem::getModel(EntityTreeRenderer* renderer) { if (!renderer) { return nullptr; } // make sure our renderer is setup if (!_myRenderer) { _myRenderer = renderer; } assert(_myRenderer == renderer); // you should only ever render on one renderer if (!_myRenderer || QThread::currentThread() != _myRenderer->thread()) { return _model; } _needsModelReload = false; // this is the reload // If we have a URL, then we will want to end up returning a model... if (!getModelURL().isEmpty()) { // If we don't have a model, allocate one *immediately* if (!_model) { _model = _myRenderer->allocateModel(getModelURL(), getCompoundShapeURL()); _needsInitialSimulation = true; // If we need to change URLs, update it *after rendering* (to avoid access violations) } else if ((QUrl(getModelURL()) != _model->getURL() || QUrl(getCompoundShapeURL()) != _model->getCollisionURL())) { QMetaObject::invokeMethod(_myRenderer, "updateModel", Qt::QueuedConnection, Q_ARG(ModelPointer, _model), Q_ARG(const QString&, getModelURL()), Q_ARG(const QString&, getCompoundShapeURL())); _needsInitialSimulation = true; } // Else we can just return the _model // If we have no URL, then we can delete any model we do have... } else if (_model) {
bool RenderableModelEntityItem::setProperties(const EntityItemProperties& properties, bool forceCopy) { QString oldModelURL = getModelURL(); bool somethingChanged = ModelEntityItem::setProperties(properties, forceCopy); if (somethingChanged && oldModelURL != getModelURL()) { _needsModelReload = true; } return somethingChanged; }
int RenderableModelEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args, EntityPropertyFlags& propertyFlags, bool overwriteLocalData) { QString oldModelURL = getModelURL(); int bytesRead = ModelEntityItem::readEntitySubclassDataFromBuffer(data, bytesLeftToRead, args, propertyFlags, overwriteLocalData); if (oldModelURL != getModelURL()) { _needsModelReload = true; } return bytesRead; }
void ModelEntityItem::setAnimationSettings(const QString& value) { // the animations setting is a JSON string that may contain various animation settings. // if it includes fps, currentFrame, or running, those values will be parsed out and // will over ride the regular animation settings QJsonDocument settingsAsJson = QJsonDocument::fromJson(value.toUtf8()); QJsonObject settingsAsJsonObject = settingsAsJson.object(); QVariantMap settingsMap = settingsAsJsonObject.toVariantMap(); if (settingsMap.contains("fps")) { float fps = settingsMap["fps"].toFloat(); setAnimationFPS(fps); } // old settings used frameIndex if (settingsMap.contains("frameIndex")) { float currentFrame = settingsMap["frameIndex"].toFloat(); #ifdef WANT_DEBUG if (isAnimatingSomething()) { qCDebug(entities) << "ModelEntityItem::setAnimationSettings() calling setAnimationFrameIndex()..."; qCDebug(entities) << " model URL:" << getModelURL(); qCDebug(entities) << " animation URL:" << getAnimationURL(); qCDebug(entities) << " settings:" << value; qCDebug(entities) << " settingsMap[frameIndex]:" << settingsMap["frameIndex"]; qCDebug(entities" currentFrame: %20.5f", currentFrame); } #endif setAnimationCurrentFrame(currentFrame); } if (settingsMap.contains("running")) { bool running = settingsMap["running"].toBool(); if (running != getAnimationIsPlaying()) { setAnimationIsPlaying(running); } } if (settingsMap.contains("firstFrame")) { float firstFrame = settingsMap["firstFrame"].toFloat(); setAnimationFirstFrame(firstFrame); } if (settingsMap.contains("lastFrame")) { float lastFrame = settingsMap["lastFrame"].toFloat(); setAnimationLastFrame(lastFrame); } if (settingsMap.contains("loop")) { bool loop = settingsMap["loop"].toBool(); setAnimationLoop(loop); } if (settingsMap.contains("hold")) { bool hold = settingsMap["hold"].toBool(); setAnimationHold(hold); } _dirtyFlags |= Simulation::DIRTY_UPDATEABLE; }
void ModelEntityItem::debugDump() const { qCDebug(entities) << "ModelEntityItem id:" << getEntityItemID(); qCDebug(entities) << " edited ago:" << getEditedAgo(); qCDebug(entities) << " position:" << getPosition(); qCDebug(entities) << " dimensions:" << getDimensions(); qCDebug(entities) << " model URL:" << getModelURL(); qCDebug(entities) << " compound shape URL:" << getCompoundShapeURL(); }
void ModelItem::debugDump() const { qDebug("ModelItem id :%u", _id); qDebug(" edited ago:%f", getEditedAgo()); qDebug(" should die:%s", debug::valueOf(getShouldDie())); qDebug(" position:%f,%f,%f", _position.x, _position.y, _position.z); qDebug(" radius:%f", getRadius()); qDebug(" color:%d,%d,%d", _color[0], _color[1], _color[2]); qDebug() << " modelURL:" << qPrintable(getModelURL()); }
void ModelEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, EntityTreeElementExtraEncodeData* entityTreeElementExtraEncodeData, EntityPropertyFlags& requestedProperties, EntityPropertyFlags& propertyFlags, EntityPropertyFlags& propertiesDidntFit, int& propertyCount, OctreeElement::AppendState& appendState) const { bool successPropertyFits = true; APPEND_ENTITY_PROPERTY(PROP_COLOR, appendColor, getColor()); APPEND_ENTITY_PROPERTY(PROP_MODEL_URL, appendValue, getModelURL()); APPEND_ENTITY_PROPERTY(PROP_ANIMATION_URL, appendValue, getAnimationURL()); APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FPS, appendValue, getAnimationFPS()); APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FRAME_INDEX, appendValue, getAnimationFrameIndex()); APPEND_ENTITY_PROPERTY(PROP_ANIMATION_PLAYING, appendValue, getAnimationIsPlaying()); APPEND_ENTITY_PROPERTY(PROP_TEXTURES, appendValue, getTextures()); APPEND_ENTITY_PROPERTY(PROP_ANIMATION_SETTINGS, appendValue, getAnimationSettings()); }
void ModelEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, EntityTreeElementExtraEncodeData* entityTreeElementExtraEncodeData, EntityPropertyFlags& requestedProperties, EntityPropertyFlags& propertyFlags, EntityPropertyFlags& propertiesDidntFit, int& propertyCount, OctreeElement::AppendState& appendState) const { bool successPropertyFits = true; APPEND_ENTITY_PROPERTY(PROP_COLOR, getColor()); APPEND_ENTITY_PROPERTY(PROP_MODEL_URL, getModelURL()); APPEND_ENTITY_PROPERTY(PROP_COMPOUND_SHAPE_URL, getCompoundShapeURL()); APPEND_ENTITY_PROPERTY(PROP_TEXTURES, getTextures()); _animationProperties.appendSubclassData(packetData, params, entityTreeElementExtraEncodeData, requestedProperties, propertyFlags, propertiesDidntFit, propertyCount, appendState); APPEND_ENTITY_PROPERTY(PROP_SHAPE_TYPE, (uint32_t)getShapeType()); }
void RenderableModelEntityItem::update(const quint64& now) { if (!_dimensionsInitialized && _model && _model->isActive()) { EntityItemProperties properties; auto extents = _model->getMeshExtents(); properties.setDimensions(extents.maximum - extents.minimum); qCDebug(entitiesrenderer) << "Autoresizing:" << (!getName().isEmpty() ? getName() : getModelURL()); QMetaObject::invokeMethod(DependencyManager::get<EntityScriptingInterface>().data(), "editEntity", Qt::QueuedConnection, Q_ARG(QUuid, getEntityItemID()), Q_ARG(EntityItemProperties, properties)); } ModelEntityItem::update(now); }
// NOTE: this only renders the "meta" portion of the Model, namely it renders debugging items, and it handles // the per frame simulation/update that might be required if the models properties changed. void RenderableModelEntityItem::render(RenderArgs* args) { PerformanceTimer perfTimer("RMEIrender"); assert(getType() == EntityTypes::Model); if (hasModel()) { if (_model) { if (getModelURL() != _model->getURL().toString()) { qDebug() << "Updating model URL: " << getModelURL(); _model->setURL(getModelURL()); } render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene(); // check to see if when we added our models to the scene they were ready, if they were not ready, then // fix them up in the scene if (_model->needsFixupInScene()) { render::PendingChanges pendingChanges; _model->removeFromScene(scene, pendingChanges); render::Item::Status::Getters statusGetters; makeEntityItemStatusGetters(this, statusGetters); _model->addToScene(scene, pendingChanges, statusGetters); scene->enqueuePendingChanges(pendingChanges); } // FIXME: this seems like it could be optimized if we tracked our last known visible state in // the renderable item. As it stands now the model checks it's visible/invisible state // so most of the time we don't do anything in this function. _model->setVisibleInScene(getVisible(), scene); } remapTextures(); { // float alpha = getLocalRenderAlpha(); if (!_model || _needsModelReload) { // TODO: this getModel() appears to be about 3% of model render time. We should optimize PerformanceTimer perfTimer("getModel"); EntityTreeRenderer* renderer = static_cast<EntityTreeRenderer*>(args->_renderer); getModel(renderer); } if (_model) { // handle animations.. if (hasAnimation()) { if (!jointsMapped()) { QStringList modelJointNames = _model->getJointNames(); mapJoints(modelJointNames); } if (jointsMapped()) { bool newFrame; QVector<glm::quat> frameDataRotations; QVector<glm::vec3> frameDataTranslations; getAnimationFrame(newFrame, frameDataRotations, frameDataTranslations); assert(frameDataRotations.size() == frameDataTranslations.size()); if (newFrame) { for (int i = 0; i < frameDataRotations.size(); i++) { _model->setJointState(i, true, frameDataRotations[i], frameDataTranslations[i], 1.0f); } } } } bool movingOrAnimating = isMoving() || isAnimatingSomething(); if ((movingOrAnimating || _needsInitialSimulation) && _model->isActive() && _dimensionsInitialized) { _model->setScaleToFit(true, getDimensions()); _model->setSnapModelToRegistrationPoint(true, getRegistrationPoint()); _model->setRotation(getRotation()); _model->setTranslation(getPosition()); // make sure to simulate so everything gets set up correctly for rendering { PerformanceTimer perfTimer("_model->simulate"); _model->simulate(0.0f); } _needsInitialSimulation = false; } } } } else { glm::vec4 greenColor(0.0f, 1.0f, 0.0f, 1.0f); RenderableDebugableEntityItem::renderBoundingBox(this, args, 0.0f, greenColor); } RenderableDebugableEntityItem::render(this, args); }