void RenderableLightEntityItem::updateRenderItemFromEntity(LightPayload& lightPayload) { auto entity = this; lightPayload.setVisible(entity->getVisible()); auto light = lightPayload.editLight(); light->setPosition(entity->getPosition()); light->setOrientation(entity->getRotation()); bool success; lightPayload.editBound() = entity->getAABox(success); if (!success) { lightPayload.editBound() = render::Item::Bound(); } glm::vec3 dimensions = entity->getDimensions(); float largestDiameter = glm::compMax(dimensions); light->setMaximumRadius(largestDiameter / 2.0f); light->setColor(toGlm(entity->getXColor())); float intensity = entity->getIntensity();//* entity->getFadingRatio(); light->setIntensity(intensity); light->setFalloffRadius(entity->getFalloffRadius()); float exponent = entity->getExponent(); float cutoff = glm::radians(entity->getCutoff()); if (!entity->getIsSpotlight()) { light->setType(model::Light::POINT); } else { light->setType(model::Light::SPOT); light->setSpotAngle(cutoff); light->setSpotExponent(exponent); } }
float EntityItem::getDistanceToBottomOfEntity() const { glm::vec3 minimumPoint = getAABox().getMinimumPoint(); return getPosition().y - minimumPoint.y; }
void EntityItem::update(const quint64& updateTime) { bool wantDebug = false; if (_lastUpdated == 0) { _lastUpdated = updateTime; } float timeElapsed = (float)(updateTime - _lastUpdated) / (float)(USECS_PER_SECOND); if (wantDebug) { qDebug() << "********** EntityItem::update()"; qDebug() << " entity ID=" << getEntityItemID(); qDebug() << " updateTime=" << updateTime; qDebug() << " _lastUpdated=" << _lastUpdated; qDebug() << " timeElapsed=" << timeElapsed; qDebug() << " hasVelocity=" << hasVelocity(); qDebug() << " hasGravity=" << hasGravity(); qDebug() << " isRestingOnSurface=" << isRestingOnSurface(); qDebug() << " hasAngularVelocity=" << hasAngularVelocity(); qDebug() << " getAngularVelocity=" << getAngularVelocity(); qDebug() << " isMortal=" << isMortal(); qDebug() << " getAge()=" << getAge(); qDebug() << " getLifetime()=" << getLifetime(); if (hasVelocity() || (hasGravity() && !isRestingOnSurface())) { qDebug() << " MOVING...="; qDebug() << " hasVelocity=" << hasVelocity(); qDebug() << " hasGravity=" << hasGravity(); qDebug() << " isRestingOnSurface=" << isRestingOnSurface(); qDebug() << " hasAngularVelocity=" << hasAngularVelocity(); qDebug() << " getAngularVelocity=" << getAngularVelocity(); } if (hasAngularVelocity()) { qDebug() << " CHANGING...="; qDebug() << " hasAngularVelocity=" << hasAngularVelocity(); qDebug() << " getAngularVelocity=" << getAngularVelocity(); } if (isMortal()) { qDebug() << " MORTAL...="; qDebug() << " isMortal=" << isMortal(); qDebug() << " getAge()=" << getAge(); qDebug() << " getLifetime()=" << getLifetime(); } } _lastUpdated = updateTime; if (wantDebug) { qDebug() << " ********** EntityItem::update() .... SETTING _lastUpdated=" << _lastUpdated; } if (hasAngularVelocity()) { glm::quat rotation = getRotation(); glm::vec3 angularVelocity = glm::radians(getAngularVelocity()); float angularSpeed = glm::length(angularVelocity); if (angularSpeed < EPSILON_VELOCITY_LENGTH) { setAngularVelocity(NO_ANGULAR_VELOCITY); } else { float angle = timeElapsed * angularSpeed; glm::quat dQ = glm::angleAxis(angle, glm::normalize(angularVelocity)); rotation = dQ * rotation; setRotation(rotation); // handle damping for angular velocity if (getAngularDamping() > 0.0f) { glm::vec3 dampingResistance = getAngularVelocity() * getAngularDamping(); glm::vec3 newAngularVelocity = getAngularVelocity() - (dampingResistance * timeElapsed); setAngularVelocity(newAngularVelocity); if (wantDebug) { qDebug() << " getDamping():" << getDamping(); qDebug() << " dampingResistance:" << dampingResistance; qDebug() << " newAngularVelocity:" << newAngularVelocity; } } } } if (hasVelocity() || hasGravity()) { glm::vec3 position = getPosition(); glm::vec3 velocity = getVelocity(); glm::vec3 newPosition = position + (velocity * timeElapsed); if (wantDebug) { qDebug() << " EntityItem::update()...."; qDebug() << " timeElapsed:" << timeElapsed; qDebug() << " old AACube:" << getMaximumAACube(); qDebug() << " old position:" << position; qDebug() << " old velocity:" << velocity; qDebug() << " old getAABox:" << getAABox(); qDebug() << " getDistanceToBottomOfEntity():" << getDistanceToBottomOfEntity() * (float)TREE_SCALE << " in meters"; qDebug() << " newPosition:" << newPosition; qDebug() << " glm::distance(newPosition, position):" << glm::distance(newPosition, position); } position = newPosition; // handle bounces off the ground... We bounce at the distance to the bottom of our entity if (position.y <= getDistanceToBottomOfEntity()) { velocity = velocity * glm::vec3(1,-1,1); // if we've slowed considerably, then just stop moving if (glm::length(velocity) <= EPSILON_VELOCITY_LENGTH) { velocity = NO_VELOCITY; } position.y = getDistanceToBottomOfEntity(); } // handle gravity.... if (hasGravity() && !isRestingOnSurface()) { velocity += getGravity() * timeElapsed; } // handle resting on surface case, this is definitely a bit of a hack, and it only works on the // "ground" plane of the domain, but for now it if (hasGravity() && isRestingOnSurface()) { velocity.y = 0.0f; position.y = getDistanceToBottomOfEntity(); } // handle damping for velocity glm::vec3 dampingResistance = velocity * getDamping(); if (wantDebug) { qDebug() << " getDamping():" << getDamping(); qDebug() << " dampingResistance:" << dampingResistance; qDebug() << " dampingResistance * timeElapsed:" << dampingResistance * timeElapsed; } velocity -= dampingResistance * timeElapsed; if (wantDebug) { qDebug() << " velocity AFTER dampingResistance:" << velocity; qDebug() << " glm::length(velocity):" << glm::length(velocity); qDebug() << " EPSILON_VELOCITY_LENGTH:" << EPSILON_VELOCITY_LENGTH; } // round velocity to zero if it's close enough... if (glm::length(velocity) <= EPSILON_VELOCITY_LENGTH) { velocity = NO_VELOCITY; } setPosition(position); // this will automatically recalculate our collision shape setVelocity(velocity); if (wantDebug) { qDebug() << " new position:" << position; qDebug() << " new velocity:" << velocity; qDebug() << " new AACube:" << getMaximumAACube(); qDebug() << " old getAABox:" << getAABox(); } } }
bool EntityEditFilters::filter(glm::vec3& position, EntityItemProperties& propertiesIn, EntityItemProperties& propertiesOut, bool& wasChanged, EntityTree::FilterType filterType, EntityItemID& itemID, EntityItemPointer& existingEntity) { // get the ids of all the zones (plus the global entity edit filter) that the position // lies within auto zoneIDs = getZonesByPosition(position); for (auto id : zoneIDs) { if (!itemID.isInvalidID() && id == itemID) { continue; } // get the filter pair, etc... _lock.lockForRead(); FilterData filterData = _filterDataMap.value(id); _lock.unlock(); if (filterData.valid()) { if (filterData.rejectAll) { return false; } // check to see if this filter wants to filter this message type if ((!filterData.wantsToFilterEdit && filterType == EntityTree::FilterType::Edit) || (!filterData.wantsToFilterPhysics && filterType == EntityTree::FilterType::Physics) || (!filterData.wantsToFilterDelete && filterType == EntityTree::FilterType::Delete) || (!filterData.wantsToFilterAdd && filterType == EntityTree::FilterType::Add)) { wasChanged = false; return true; // accept the message } auto oldProperties = propertiesIn.getDesiredProperties(); auto specifiedProperties = propertiesIn.getChangedProperties(); propertiesIn.setDesiredProperties(specifiedProperties); QScriptValue inputValues = propertiesIn.copyToScriptValue(filterData.engine, false, true, true); propertiesIn.setDesiredProperties(oldProperties); auto in = QJsonValue::fromVariant(inputValues.toVariant()); // grab json copy now, because the inputValues might be side effected by the filter. QScriptValueList args; args << inputValues; args << filterType; // get the current properties for then entity and include them for the filter call if (existingEntity && filterData.wantsOriginalProperties) { auto currentProperties = existingEntity->getProperties(filterData.includedOriginalProperties); QScriptValue currentValues = currentProperties.copyToScriptValue(filterData.engine, false, true, true); args << currentValues; } // get the zone properties if (filterData.wantsZoneProperties) { auto zoneEntity = _tree->findEntityByEntityItemID(id); if (zoneEntity) { auto zoneProperties = zoneEntity->getProperties(filterData.includedZoneProperties); QScriptValue zoneValues = zoneProperties.copyToScriptValue(filterData.engine, false, true, true); if (filterData.wantsZoneBoundingBox) { bool success = true; AABox aaBox = zoneEntity->getAABox(success); if (success) { QScriptValue boundingBox = filterData.engine->newObject(); QScriptValue bottomRightNear = vec3ToScriptValue(filterData.engine, aaBox.getCorner()); QScriptValue topFarLeft = vec3ToScriptValue(filterData.engine, aaBox.calcTopFarLeft()); QScriptValue center = vec3ToScriptValue(filterData.engine, aaBox.calcCenter()); QScriptValue boundingBoxDimensions = vec3ToScriptValue(filterData.engine, aaBox.getDimensions()); boundingBox.setProperty("brn", bottomRightNear); boundingBox.setProperty("tfl", topFarLeft); boundingBox.setProperty("center", center); boundingBox.setProperty("dimensions", boundingBoxDimensions); zoneValues.setProperty("boundingBox", boundingBox); } } // If this is an add or delete, or original properties weren't requested // there won't be original properties in the args, but zone properties need // to be the fourth parameter, so we need to pad the args accordingly int EXPECTED_ARGS = 3; if (args.length() < EXPECTED_ARGS) { args << QScriptValue(); } assert(args.length() == EXPECTED_ARGS); // we MUST have 3 args by now! args << zoneValues; } } QScriptValue result = filterData.filterFn.call(_nullObjectForFilter, args); if (filterData.uncaughtExceptions()) { return false; } if (result.isObject()) { // make propertiesIn reflect the changes, for next filter... propertiesIn.copyFromScriptValue(result, false); // and update propertiesOut too. TODO: this could be more efficient... propertiesOut.copyFromScriptValue(result, false); // Javascript objects are == only if they are the same object. To compare arbitrary values, we need to use JSON. auto out = QJsonValue::fromVariant(result.toVariant()); wasChanged |= (in != out); } else if (result.isBool()) { // if the filter returned false, then it's authoritative if (!result.toBool()) { return false; } // otherwise, assume it wants to pass all properties propertiesOut = propertiesIn; wasChanged = false; } else { return false; } } } // if we made it here, return true; }