void SoundSource::Update(float timeStep) { if (!audio_ || !IsEnabledEffective()) return; // If there is no actual audio output, perform fake mixing into a nonexistent buffer to check stopping/looping if (!audio_->IsInitialized()) MixNull(timeStep); // Free the stream if playback has stopped if (soundStream_ && !position_) StopLockless(); // Check for autoremove if (autoRemove_) { if (!IsPlaying()) { autoRemoveTimer_ += timeStep; if (autoRemoveTimer_ > AUTOREMOVE_DELAY) { Remove(); // Note: this object is now deleted, so only returning immediately is safe return; } } else autoRemoveTimer_ = 0.0f; } }
void CollisionShape::NotifyRigidBody(bool updateMass) { btCompoundShape* compound = GetParentCompoundShape(); if (node_ && shape_ && compound) { // Remove the shape first to ensure it is not added twice compound->removeChildShape(shape_); if (IsEnabledEffective()) { // Then add with updated offset Vector3 position = position_; // For terrains, undo the height centering performed automatically by Bullet if (shapeType_ == SHAPE_TERRAIN && geometry_) { HeightfieldData* heightfield = static_cast<HeightfieldData*>(geometry_.Get()); position.y_ += (heightfield->minHeight_ + heightfield->maxHeight_) * 0.5f; } btTransform offset; offset.setOrigin(ToBtVector3(node_->GetWorldScale() * position)); offset.setRotation(ToBtQuaternion(rotation_)); compound->addChildShape(offset, shape_); } // Finally tell the rigid body to update its mass if (updateMass) rigidBody_->UpdateMass(); } }
void Constraint2D::OnSetEnabled() { if (IsEnabledEffective()) CreateJoint(); else ReleaseJoint(); }
void Light::DrawDebugGeometry(DebugRenderer* debug, bool depthTest) { Color color = GetEffectiveColor(); if (debug && IsEnabledEffective()) { switch (lightType_) { case LIGHT_DIRECTIONAL: { Vector3 start = node_->GetWorldPosition(); Vector3 end = start + node_->GetWorldDirection() * 10.f; for (int i = -1; i < 2; ++i) { for (int j = -1; j < 2; ++j) { Vector3 offset = Vector3::UP * (5.f * i) + Vector3::RIGHT * (5.f * j); debug->AddSphere(Sphere(start + offset, 0.1f), color, depthTest); debug->AddLine(start + offset, end + offset, color, depthTest); } } } break; case LIGHT_SPOT: debug->AddFrustum(GetFrustum(), color, depthTest); break; case LIGHT_POINT: debug->AddSphere(Sphere(node_->GetWorldPosition(), range_), color, depthTest); break; } } }
void SoundSource::Update(float timeStep) { if (!audio_ || !IsEnabledEffective()) return; // If there is no actual audio output, perform fake mixing into a nonexistent buffer to check stopping/looping if (!audio_->IsInitialized()) MixNull(timeStep); // Free the stream if playback has stopped if (soundStream_ && !position_) StopLockless(); bool playing = IsPlaying(); if (!playing && sendFinishedEvent_) { sendFinishedEvent_ = false; // Make a weak pointer to self to check for destruction during event handling WeakPtr<SoundSource> self(this); soundFinished(node_,this,sound_); //TODO: verify same semantics as original : node_->SendEvent(E_SOUNDFINISHED, eventData); if (self.Expired()) return; DoAutoRemove(autoRemove_); } }
void Zone::OnSetEnabled() { // When a Zone is disabled, clear the cached zone from all drawables inside bounding box before removing from octree if (!IsEnabledEffective()) OnMarkedDirty(node_); Drawable::OnSetEnabled(); }
void RigidBody::OnSetEnabled() { bool enabled = IsEnabledEffective(); if (enabled && !inWorld_) AddBodyToWorld(); else if (!enabled && inWorld_) RemoveBodyFromWorld(); }
void NavArea::DrawDebugGeometry(DebugRenderer* debug, bool depthTest) { if (debug && IsEnabledEffective()) { Matrix3x4 mat; mat.SetTranslation(node_->GetWorldPosition()); debug->AddBoundingBox(boundingBox_, mat, Color::GREEN, depthTest); } }
void CrowdAgent::OnSetEnabled() { bool enabled = IsEnabledEffective(); if (enabled && !inCrowd_) AddAgentToCrowd(); else if (!enabled && inCrowd_) RemoveAgentFromCrowd(); }
void Drawable2D::OnSetEnabled() { bool enabled = IsEnabledEffective(); if (enabled && renderer_) renderer_->AddDrawable(this); else if (!enabled && renderer_) renderer_->RemoveDrawable(this); }
void SoundSource::Mix(int* dest, unsigned samples, int mixRate, bool stereo, bool interpolation) { if (!position_ || (!sound_ && !soundStream_) || !IsEnabledEffective()) return; int streamFilledSize, outBytes; if (soundStream_ && streamBuffer_) { int streamBufferSize = streamBuffer_->GetDataSize(); // Calculate how many bytes of stream sound data is needed int neededSize = (int)((float)samples * frequency_ / (float)mixRate); // Add a little safety buffer. Subtract previous unused data neededSize += STREAM_SAFETY_SAMPLES; neededSize *= soundStream_->GetSampleSize(); neededSize -= unusedStreamSize_; neededSize = Clamp(neededSize, 0, streamBufferSize - unusedStreamSize_); // Always start play position at the beginning of the stream buffer position_ = streamBuffer_->GetStart(); // Request new data from the stream signed char* destination = streamBuffer_->GetStart() + unusedStreamSize_; outBytes = neededSize ? soundStream_->GetData(destination, (unsigned)neededSize) : 0; destination += outBytes; // Zero-fill rest if stream did not produce enough data if (outBytes < neededSize) memset(destination, 0, (size_t)(neededSize - outBytes)); // Calculate amount of total bytes of data in stream buffer now, to know how much went unused after mixing streamFilledSize = neededSize + unusedStreamSize_; } // If streaming, play the stream buffer. Otherwise play the original sound Sound* sound = soundStream_ ? streamBuffer_ : sound_; if (!sound) return; // Update the time position. In stream mode, copy unused data back to the beginning of the stream buffer if (soundStream_) { timePosition_ += ((float)samples / (float)mixRate) * frequency_ / soundStream_->GetFrequency(); unusedStreamSize_ = std::max(streamFilledSize - (int)(size_t)(position_ - streamBuffer_->GetStart()), 0); if (unusedStreamSize_) memcpy(streamBuffer_->GetStart(), (const void*)position_, (size_t)unusedStreamSize_); // If stream did not produce any data, stop if applicable if (!outBytes && soundStream_->GetStopAtEnd()) { position_ = nullptr; return; } } else if (sound_) timePosition_ = ((float)(int)(size_t)(position_ - sound_->GetStart())) / (sound_->GetSampleSize() * sound_->GetFrequency()); }
void Drawable::OnSetEnabled() { bool enabled = IsEnabledEffective(); if (enabled && !octant_) AddToOctree(); else if (!enabled && octant_) RemoveFromOctree(); }
void Constraint::DrawDebugGeometry(DebugRenderer* debug, bool depthTest) { if (debug && physicsWorld_ && constraint_ && IsEnabledEffective()) { physicsWorld_->SetDebugRenderer(debug); physicsWorld_->SetDebugDepthTest(depthTest); physicsWorld_->GetWorld()->debugDrawConstraint(constraint_); physicsWorld_->SetDebugRenderer(0); } }
void Drawable2D::OnSetEnabled() { if (!drawableProxy_) return; if (IsEnabledEffective()) drawableProxy_->AddDrawable(this); else drawableProxy_->RemoveDrawable(this); }
void RigidBody2D::OnSetEnabled() { bool enabled = IsEnabledEffective(); bodyDef_.active = enabled; if (body_) body_->SetActive(enabled); MarkNetworkUpdate(); }
void RigidBody::DrawDebugGeometry(DebugRenderer* debug, bool depthTest) { if (debug && physicsWorld_ && body_ && IsEnabledEffective()) { physicsWorld_->SetDebugRenderer(debug); physicsWorld_->SetDebugDepthTest(depthTest); btDiscreteDynamicsWorld* world = physicsWorld_->GetWorld(); world->debugDrawObject(body_->getWorldTransform(), shiftedCompoundShape_, IsActive() ? btVector3(1.0f, 1.0f, 1.0f) : btVector3(0.0f, 1.0f, 0.0f)); physicsWorld_->SetDebugRenderer(0); } }
void CrowdAgent::OnMarkedDirty(Node* node) { if (!ignoreTransformChanges_ && IsEnabledEffective()) { dtCrowdAgent* agent = const_cast<dtCrowdAgent*>(GetDetourCrowdAgent()); if (agent) { memcpy(agent->npos, node->GetWorldPosition().Data(), sizeof(float) * 3); // If the node has been externally altered, provide the opportunity for DetourCrowd to reevaluate the crowd agent if (agent->state == CROWD_AGENT_INVALID) agent->state = CROWD_AGENT_READY; } } }
void CollisionShape2D::OnSetEnabled() { if (IsEnabledEffective()) { CreateFixture(); if (rigidBody_) rigidBody_->AddCollisionShape2D(this); } else { if (rigidBody_) rigidBody_->RemoveCollisionShape2D(this); ReleaseFixture(); } }
void CrowdAgent::OnMarkedDirty(Node* node) { if (inCrowd_ && crowdManager_ && !ignoreTransformChanges_ && IsEnabledEffective()) { dtCrowdAgent* agt = crowdManager_->GetCrowd()->getEditableAgent(agentCrowdId_); if (agt) { memcpy(agt->npos, node->GetWorldPosition().Data(), sizeof(float) * 3); // If the node has been externally altered, provide the opportunity for DetourCrowd to reevaluate the crowd agent if (agt->state == CROWD_AGENT_INVALID) agt->state = CROWD_AGENT_READY; } } }
void Drawable2D::OnNodeSet(Node* node) { Drawable::OnNodeSet(node); if (node) { Scene* scene = GetScene(); if (scene) { materialCache_ = scene->GetOrCreateComponent<MaterialCache2D>(); drawableProxy_ = scene->GetOrCreateComponent<DrawableProxy2D>(); if (IsEnabledEffective()) drawableProxy_->AddDrawable(this); } } }
void Drawable2D::OnSceneSet(Scene* scene) { // Do not call Drawable::OnSceneSet(node), as 2D drawable components should not be added to the octree // but are instead rendered through Renderer2D if (scene) { renderer_ = scene->GetOrCreateComponent<Renderer2D>(); if (IsEnabledEffective()) renderer_->AddDrawable(this); } else { if (renderer_) renderer_->RemoveDrawable(this); } }
void Drawable::AddToOctree() { // Do not add to octree when disabled if (!IsEnabledEffective()) return; Scene* scene = GetScene(); if (scene) { Octree* octree = scene->GetComponent<Octree>(); if (octree) octree->InsertDrawable(this); else LOGERROR("No Octree component in scene, drawable will not render"); } else { // We have a mechanism for adding detached nodes to an octree manually, so do not log this error //LOGERROR("Node is detached from scene, drawable will not render"); } }
void SplinePath::DrawDebugGeometry(DebugRenderer* debug, bool depthTest) { if (debug && node_ && IsEnabledEffective()) { if (spline_.GetKnots().Size() > 1) { Vector3 a = spline_.GetPoint(0.f).GetVector3(); for (float f = 0.01f; f <= 1.0f; f = f + 0.01f) { Vector3 b = spline_.GetPoint(f).GetVector3(); debug->AddLine(a, b, Color::GREEN); a = b; } } for (Vector<WeakPtr<Node> >::ConstIterator i = controlPoints_.Begin(); i != controlPoints_.End(); ++i) debug->AddNode(*i); if (controlledNode_) debug->AddNode(controlledNode_); } }
void Drawable2D::OnNodeSet(Node* node) { // Do not call Drawable::OnNodeSet(node) if (node) { Scene* scene = GetScene(); if (scene) { renderer_ = scene->GetOrCreateComponent<Renderer2D>(); if (IsEnabledEffective()) renderer_->AddDrawable(this); } node->AddListener(this); } else { if (renderer_) renderer_->RemoveDrawable(this); } }
void SoundSource::MixNull(float timeStep) { if (!position_ || !sound_ || !IsEnabledEffective()) return; // Advance only the time position timePosition_ += timeStep * frequency_ / sound_->GetFrequency(); if (sound_->IsLooped()) { // For simulated playback, simply reset the time position to zero when the sound loops if (timePosition_ >= sound_->GetLength()) timePosition_ -= sound_->GetLength(); } else { if (timePosition_ >= sound_->GetLength()) { position_ = nullptr; timePosition_ = 0.0f; } } }
void CollisionShape::DrawDebugGeometry(DebugRenderer* debug, bool depthTest) { if (debug && physicsWorld_ && shape_ && node_ && IsEnabledEffective()) { physicsWorld_->SetDebugRenderer(debug); physicsWorld_->SetDebugDepthTest(depthTest); // Use the rigid body's world transform if possible, as it may be different from the rendering transform Matrix3x4 worldTransform; RigidBody* body = GetComponent<RigidBody>(); bool bodyActive = false; if (body) { worldTransform = Matrix3x4(body->GetPosition(), body->GetRotation(), node_->GetWorldScale()); bodyActive = body->IsActive(); } else worldTransform = node_->GetWorldTransform(); Vector3 position = position_; // For terrains, undo the height centering performed automatically by Bullet if (shapeType_ == SHAPE_TERRAIN && geometry_) { HeightfieldData* heightfield = static_cast<HeightfieldData*>(geometry_.Get()); position.y_ += (heightfield->minHeight_ + heightfield->maxHeight_) * 0.5f; } Vector3 worldPosition(worldTransform * position); Quaternion worldRotation(worldTransform.Rotation() * rotation_); btDiscreteDynamicsWorld* world = physicsWorld_->GetWorld(); world->debugDrawObject(btTransform(ToBtQuaternion(worldRotation), ToBtVector3(worldPosition)), shape_, bodyActive ? WHITE : GREEN); physicsWorld_->SetDebugRenderer(0); } }
void SoundSource3D::DrawDebugGeometry(DebugRenderer* debug, bool depthTest) { if (!debug || !node_ || !IsEnabledEffective()) return; const Matrix3x4& worldTransform = node_->GetWorldTransform(); Vector3 worldPosition = worldTransform.Translation(); Quaternion worldRotation = worldTransform.Rotation(); // Draw cones for directional sounds, or spheres for non-directional if (innerAngle_ < DEFAULT_ANGLE && outerAngle_ > 0.0f) { const Quaternion rotation = worldRotation * Quaternion(Vector3::UP, Vector3::FORWARD); debug->AddSphereSector(Sphere(worldPosition, nearDistance_), rotation, innerAngle_, false, INNER_COLOR, depthTest); debug->AddSphereSector(Sphere(worldPosition, nearDistance_), rotation, outerAngle_, false, OUTER_COLOR, depthTest); debug->AddSphereSector(Sphere(worldPosition, farDistance_), rotation, innerAngle_, true, INNER_COLOR, depthTest); debug->AddSphereSector(Sphere(worldPosition, farDistance_), rotation, outerAngle_, true, OUTER_COLOR, depthTest); } else { debug->AddSphere(Sphere(worldPosition, nearDistance_), INNER_COLOR, depthTest); debug->AddSphere(Sphere(worldPosition, farDistance_), OUTER_COLOR, depthTest); } }
void Constraint::CreateConstraint() { PROFILE(CreateConstraint); cachedWorldScale_ = node_->GetWorldScale(); ReleaseConstraint(); ownBody_ = GetComponent<RigidBody>(); btRigidBody* ownBody = ownBody_ ? ownBody_->GetBody() : 0; btRigidBody* otherBody = otherBody_ ? otherBody_->GetBody() : 0; // If no physics world available now mark for retry later if (!physicsWorld_ || !ownBody) { retryCreation_ = true; return; } if (!otherBody) otherBody = &btTypedConstraint::getFixedBody(); Vector3 ownBodyScaledPosition = position_ * cachedWorldScale_ - ownBody_->GetCenterOfMass(); Vector3 otherBodyScaledPosition = otherBody_ ? otherPosition_ * otherBody_->GetNode()->GetWorldScale() - otherBody_->GetCenterOfMass() : otherPosition_; switch (constraintType_) { case CONSTRAINT_POINT: { constraint_ = new btPoint2PointConstraint(*ownBody, *otherBody, ToBtVector3(ownBodyScaledPosition), ToBtVector3(otherBodyScaledPosition)); } break; case CONSTRAINT_HINGE: { btTransform ownFrame(ToBtQuaternion(rotation_), ToBtVector3(ownBodyScaledPosition)); btTransform otherFrame(ToBtQuaternion(otherRotation_), ToBtVector3(otherBodyScaledPosition)); constraint_ = new btHingeConstraint(*ownBody, *otherBody, ownFrame, otherFrame); } break; case CONSTRAINT_SLIDER: { btTransform ownFrame(ToBtQuaternion(rotation_), ToBtVector3(ownBodyScaledPosition)); btTransform otherFrame(ToBtQuaternion(otherRotation_), ToBtVector3(otherBodyScaledPosition)); constraint_ = new btSliderConstraint(*ownBody, *otherBody, ownFrame, otherFrame, false); } break; case CONSTRAINT_CONETWIST: { btTransform ownFrame(ToBtQuaternion(rotation_), ToBtVector3(ownBodyScaledPosition)); btTransform otherFrame(ToBtQuaternion(otherRotation_), ToBtVector3(otherBodyScaledPosition)); constraint_ = new btConeTwistConstraint(*ownBody, *otherBody, ownFrame, otherFrame); } break; default: break; } if (constraint_) { constraint_->setUserConstraintPtr(this); constraint_->setEnabled(IsEnabledEffective()); ownBody_->AddConstraint(this); if (otherBody_) otherBody_->AddConstraint(this); ApplyLimits(); physicsWorld_->GetWorld()->addConstraint(constraint_, disableCollision_); } recreateConstraint_ = false; framesDirty_ = false; retryCreation_ = false; }
void Constraint::OnSetEnabled() { if (constraint_) constraint_->setEnabled(IsEnabledEffective()); }
void Zone::DrawDebugGeometry(DebugRenderer* debug, bool depthTest) { if (debug && IsEnabledEffective()) debug->AddBoundingBox(boundingBox_, node_->GetWorldTransform(), Color::GREEN, depthTest); }