virtual void GetInterpolatedPosition2D(float frameOffset, float& x, float& z, float& rotY) { if (!m_InWorld) { LOGERROR(L"CCmpPosition::GetInterpolatedPosition2D called on entity when IsInWorld is false"); return; } x = Interpolate(m_LastX.ToFloat(), m_X.ToFloat(), frameOffset); z = Interpolate(m_LastZ.ToFloat(), m_Z.ToFloat(), frameOffset); rotY = m_InterpolatedRotY; }
virtual CMatrix3D GetInterpolatedTransform(float frameOffset, bool forceFloating) { if (!m_InWorld) { LOGERROR(L"CCmpPosition::GetInterpolatedTransform called on entity when IsInWorld is false"); CMatrix3D m; m.SetIdentity(); return m; } float x, z, rotY; GetInterpolatedPosition2D(frameOffset, x, z, rotY); float baseY = 0; if (m_RelativeToGround) { CmpPtr<ICmpTerrain> cmpTerrain(GetSimContext(), SYSTEM_ENTITY); if (cmpTerrain) baseY = cmpTerrain->GetExactGroundLevel(x, z); if (m_Floating || forceFloating) { CmpPtr<ICmpWaterManager> cmpWaterManager(GetSimContext(), SYSTEM_ENTITY); if (cmpWaterManager) baseY = std::max(baseY, cmpWaterManager->GetExactWaterLevel(x, z)); } } float y = baseY + m_YOffset.ToFloat(); // TODO: do something with m_AnchorType CMatrix3D m; CMatrix3D mXZ; float Cos = cosf(rotY); float Sin = sinf(rotY); m.SetIdentity(); m._11 = -Cos; m._13 = -Sin; m._31 = Sin; m._33 = -Cos; mXZ.SetIdentity(); mXZ.SetXRotation(m_RotX.ToFloat()); mXZ.RotateZ(m_RotZ.ToFloat()); // TODO: is this all done in the correct order? mXZ = m * mXZ; mXZ.Translate(CVector3D(x, y, z)); return mXZ; }
virtual void HandleMessage(const CMessage& msg, bool UNUSED(global)) { switch (msg.GetType()) { case MT_RenderSubmit: { // Don't actually do rendering here, but tell the renderer how to draw water if (CRenderer::IsInitialised()) g_Renderer.GetWaterManager()->m_WaterHeight = m_WaterHeight.ToFloat(); break; } } }
virtual CMatrix3D GetInterpolatedTransform(float frameOffset, bool forceFloating) { if (!m_InWorld) { LOGERROR(L"CCmpPosition::GetInterpolatedTransform called on entity when IsInWorld is false"); CMatrix3D m; m.SetIdentity(); return m; } float x, z, rotY; GetInterpolatedPosition2D(frameOffset, x, z, rotY); float baseY = 0; if (m_RelativeToGround) { CmpPtr<ICmpTerrain> cmpTerrain(GetSimContext(), SYSTEM_ENTITY); if (cmpTerrain) baseY = cmpTerrain->GetExactGroundLevel(x, z); if (m_Floating || forceFloating) { CmpPtr<ICmpWaterManager> cmpWaterManager(GetSimContext(), SYSTEM_ENTITY); if (cmpWaterManager) baseY = std::max(baseY, cmpWaterManager->GetExactWaterLevel(x, z)); } } float y = baseY + m_YOffset.ToFloat(); CMatrix3D m; // linear interpolation is good enough (for RotX/Z). // As you always stay close to zero angle. m.SetXRotation(Interpolate(m_LastInterpolatedRotX, m_InterpolatedRotX, frameOffset)); m.RotateZ(Interpolate(m_LastInterpolatedRotZ, m_InterpolatedRotZ, frameOffset)); m.RotateY(rotY + (float)M_PI); m.Translate(CVector3D(x, y, z)); return m; }
void GetInterpolatedPositions(CVector3D& pos0, CVector3D& pos1) { float baseY0 = 0; float baseY1 = 0; float x0 = m_LastX.ToFloat(); float z0 = m_LastZ.ToFloat(); float x1 = m_X.ToFloat(); float z1 = m_Z.ToFloat(); if (m_RelativeToGround) { CmpPtr<ICmpTerrain> cmpTerrain(GetSimContext(), SYSTEM_ENTITY); if (cmpTerrain) { baseY0 = cmpTerrain->GetExactGroundLevel(x0, z0); baseY1 = cmpTerrain->GetExactGroundLevel(x1, z1); } if (m_Floating || m_ActorFloating) { CmpPtr<ICmpWaterManager> cmpWaterManager(GetSimContext(), SYSTEM_ENTITY); if (cmpWaterManager) { baseY0 = std::max(baseY0, cmpWaterManager->GetExactWaterLevel(x0, z0)); baseY1 = std::max(baseY1, cmpWaterManager->GetExactWaterLevel(x1, z1)); } } } float y0 = baseY0 + m_Y.ToFloat() + m_LastYDifference.ToFloat(); float y1 = baseY1 + m_Y.ToFloat(); pos0 = CVector3D(x0, y0, z0); pos1 = CVector3D(x1, y1, z1); pos0.Y += GetConstructionProgressOffset(pos0); pos1.Y += GetConstructionProgressOffset(pos1); }
virtual CMatrix3D GetInterpolatedTransform(float frameOffset) { if (m_TurretParent != INVALID_ENTITY) { CmpPtr<ICmpPosition> cmpPosition(GetSimContext(), m_TurretParent); if (!cmpPosition) { LOGERROR("Turret with parent without position component"); CMatrix3D m; m.SetIdentity(); return m; } if (!cmpPosition->IsInWorld()) { LOGERROR("CCmpPosition::GetInterpolatedTransform called on turret entity when IsInWorld is false"); CMatrix3D m; m.SetIdentity(); return m; } else { CMatrix3D parentTransformMatrix = cmpPosition->GetInterpolatedTransform(frameOffset); CMatrix3D ownTransformation = CMatrix3D(); ownTransformation.SetYRotation(m_InterpolatedRotY); ownTransformation.Translate(-m_TurretPosition.X.ToFloat(), m_TurretPosition.Y.ToFloat(), -m_TurretPosition.Z.ToFloat()); return parentTransformMatrix * ownTransformation; } } if (!m_InWorld) { LOGERROR("CCmpPosition::GetInterpolatedTransform called on entity when IsInWorld is false"); CMatrix3D m; m.SetIdentity(); return m; } float x, z, rotY; GetInterpolatedPosition2D(frameOffset, x, z, rotY); float baseY = 0; if (m_RelativeToGround) { CmpPtr<ICmpTerrain> cmpTerrain(GetSystemEntity()); if (cmpTerrain) baseY = cmpTerrain->GetExactGroundLevel(x, z); if (m_Floating || m_ActorFloating) { CmpPtr<ICmpWaterManager> cmpWaterManager(GetSystemEntity()); if (cmpWaterManager) baseY = std::max(baseY, cmpWaterManager->GetExactWaterLevel(x, z)); } } float y = baseY + m_Y.ToFloat() + Interpolate(-1 * m_LastYDifference.ToFloat(), 0.f, frameOffset); CMatrix3D m; // linear interpolation is good enough (for RotX/Z). // As you always stay close to zero angle. m.SetXRotation(Interpolate(m_LastInterpolatedRotX, m_InterpolatedRotX, frameOffset)); m.RotateZ(Interpolate(m_LastInterpolatedRotZ, m_InterpolatedRotZ, frameOffset)); CVector3D pos(x, y, z); pos.Y += GetConstructionProgressOffset(pos); m.RotateY(rotY + (float)M_PI); m.Translate(pos); return m; }
virtual float GetExactWaterLevel(float UNUSED(x), float UNUSED(z)) { return m_WaterHeight.ToFloat(); }
virtual void HandleMessage(const CMessage& msg, bool UNUSED(global)) { switch (msg.GetType()) { case MT_Interpolate: { if (!m_Active) break; const CMessageInterpolate& msgData = static_cast<const CMessageInterpolate&> (msg); CmpPtr<ICmpPosition> cmpPosition(GetSimContext(), GetEntityId()); if (!cmpPosition || !cmpPosition->IsInWorld()) { // If there's no position (this usually shouldn't happen), destroy the unit immediately GetSimContext().GetComponentManager().DestroyComponentsSoon(GetEntityId()); break; } // Compute the depth the first time this is called // (This is a bit of an ugly place to do it but at least we'll be sure // the actor component was loaded already) if (m_TotalSinkDepth < 0.f) { m_TotalSinkDepth = 1.f; // minimum so we always sink at least a little CmpPtr<ICmpVisual> cmpVisual(GetSimContext(), GetEntityId()); if (cmpVisual) { CBoundingBoxAligned bound = cmpVisual->GetBounds(); m_TotalSinkDepth = std::max(m_TotalSinkDepth, bound[1].Y - bound[0].Y); } // If this is a floating unit, we want it to sink all the way under the terrain, // so find the difference between its current position and the terrain CFixedVector3D pos = cmpPosition->GetPosition(); CmpPtr<ICmpTerrain> cmpTerrain(GetSimContext(), SYSTEM_ENTITY); if (cmpTerrain) { fixed ground = cmpTerrain->GetGroundLevel(pos.X, pos.Z); m_TotalSinkDepth += std::max(0.f, (pos.Y - ground).ToFloat()); } // Sink it further down if it sinks like a ship, as it will rotate. if (m_ShipSink) m_TotalSinkDepth += 10.f; // probably 0 in both cases but we'll remember it anyway. m_InitialXRotation = cmpPosition->GetRotation().X; m_InitialZRotation = cmpPosition->GetRotation().Z; } m_CurrentTime += msgData.deltaSimTime; if (m_CurrentTime >= m_DelayTime) { float t = m_CurrentTime - m_DelayTime; float depth = (m_SinkRate * t) + (m_SinkAccel * t * t); if (m_ShipSink) { // exponential sinking with tilting float tilt_time = t > 5.f ? 5.f : t; float tiltSink = tilt_time * tilt_time / 5.f; entity_pos_t RotX = entity_pos_t::FromFloat(((m_InitialXRotation.ToFloat() * (5.f - tiltSink)) + (1.5f * tiltSink)) / 5.f); entity_pos_t RotZ = entity_pos_t::FromFloat(((m_InitialZRotation.ToFloat() * (3.f - tilt_time)) + (-0.3f * tilt_time)) / 3.f); cmpPosition->SetXZRotation(RotX,RotZ); depth = m_SinkRate * (exp(t - 1.f) - 0.54881163609f) + (m_SinkAccel * exp(t - 4.f) - 0.01831563888f); if (depth < 0.f) depth = 0.f; } cmpPosition->SetHeightOffset(entity_pos_t::FromFloat(-depth)); if (depth > m_TotalSinkDepth) GetSimContext().GetComponentManager().DestroyComponentsSoon(GetEntityId()); } break; } } }