#include "pch.h" ////////////////////////////////////////////////////////////////////////////// // // DebrisGeo // ////////////////////////////////////////////////////////////////////////////// const float maxDistance = 100; class DebrisGeo : public Geo { private: class DebrisData { public: Vector m_position; Color m_color; float m_startTime; }; typedef TList DebrisDataList; DebrisDataList m_listData; TRef m_psurface; float m_time; Vector m_positionLast; Number* GetTime() { return Number::Cast(GetChild(0)); } Viewport* GetViewport() { return Viewport::Cast(GetChild(1)); } Camera* GetCamera() { return GetViewport()->GetCamera(); } RectValue* GetViewRect() { return GetViewport()->GetViewRect(); } public: DebrisGeo(Modeler* pmodeler, Number* ptime, Viewport* pviewport) : Geo(ptime, pviewport) { m_positionLast = GetCamera()->GetPosition(); m_psurface = pmodeler->LoadSurface("debris1bmp", true); } void Evaluate() { const Rect& rect = GetViewRect()->GetValue(); Camera* pcamera = GetCamera(); float focus = pcamera->GetFocus(); float rfocus = 1.0f / focus; const Vector& position = pcamera->GetPosition(); Orientation orient = pcamera->GetOrientation(); Vector forward = orient.GetForward(); Vector up = orient.GetUp(); Vector right = orient.GetRight(); // // save the current time // m_time = GetTime()->GetValue(); // // how far did we move? // float length = (m_positionLast - position).Length(); if (length > 100) { // // we jumped clear everything // m_listData.SetEmpty(); length = 0; } else { // // remove any debris that are too far away from the ship // DebrisDataList::Iterator iter(m_listData); while (!iter.End()) { DebrisData& data = iter.Value(); float time = m_time - data.m_startTime; float bright = 1.0f - 0.25f * time * time; float distance = (data.m_position - position).LengthSquared(); if (bright <= 0 || distance > 250000) { iter.Remove(); } else { iter.Next(); } } // // if we are moving add new debris // while (length > 0) { m_listData.PushFront(); DebrisData& data = m_listData.GetFront(); float angle = random(0, 2 * pi); float distance = maxDistance * sqrt(random(0, 1)); float radius = rfocus * distance * sqrt(random(0, 1)); float c = radius * cos(angle); float s = radius * sin(angle); data.m_position = position + distance * forward + c * right + s * up; data.m_color = Color( random(0.50f, 0.75f), random(0.75f, 1.00f), random(0.75f, 1.00f) ); data.m_startTime = m_time; length -= 1.0f; } } m_positionLast = position; } void Render(Context* pcontext) { const Vector& position = GetCamera()->GetPosition(); float scale = 0.1f / GetCamera()->GetFocus(); DebrisDataList::Iterator iter(m_listData); while (!iter.End()) { DebrisData& data = iter.Value(); float time = m_time - data.m_startTime; float bright = 1.0f - 0.25f * time * time; float distance = (data.m_position - position).LengthSquared(); if (distance > 400) { pcontext->DrawDecal( m_psurface, bright * data.m_color, data.m_position, Vector::GetZero(), Vector::GetZero(), scale, 0 ); } iter.Next(); } } ////////////////////////////////////////////////////////////////////////////// // // Value members // ////////////////////////////////////////////////////////////////////////////// ZString GetFunctionName() { return "DebrisGeo"; } }; TRef CreateDebrisGeo(Modeler* pmodeler, Number* ptime, Viewport* pviewport) { return new DebrisGeo(pmodeler, ptime, pviewport); }