#include "AdeptHeaders.hpp" #include "VideoHeaders.hpp" #include "Interface.hpp" #include "Mission.hpp" #include #include #include // // Shared Data Support // Component::ClassData* CameraComponent::DefaultData = NULL; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // InitializeClass // void CameraComponent::InitializeClass() { Verify(!DefaultData); DefaultData = new ClassData( CameraComponentClassID, "Adept::CameraComponent", BaseClass::DefaultData, 0, NULL ); Register_Object(DefaultData); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void CameraComponent::TerminateClass() { Unregister_Object(DefaultData); delete DefaultData; DefaultData = NULL; } //############################################################################# // Constructors and destructors // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ElementRenderer::CameraElement* CameraComponent::AllocateCamera() { gos_PushCurrentHeap(ElementRenderer::g_Heap); ElementRenderer::StateChange *states = new ElementRenderer::StateChange; Register_Object(states); ElementRenderer::CameraElement *camera = new ElementRenderer::CameraElement(states); Register_Object(camera); gos_PopCurrentHeap(); return camera; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // CameraComponent // CameraComponent::CameraComponent( ClassData *class_data, MemoryStream *stream, VideoComponentWeb *owning_web, Interface * intface ): GroupComponent( class_data, stream, owning_web, AllocateCamera() ) { ElementRenderer::CameraElement *camera = GetElement(); Check_Object(camera); // //----------------------- // Read the viewing state //----------------------- // ElementRenderer::StateChange *view_states = camera->GetViewingStateChange(); Check_Object(view_states); view_states->Load(stream, ElementRenderer::ReadERFVersion(stream)); // //------------------------ // Set the clipping planes //------------------------ // Scalar angle; *stream >> angle; Check_Object(Mission::GetInstance()); const Mission::GameModel *model = Mission::GetInstance()->GetGameModel(); Check_Object(model); // //------------------ // Set the view port //------------------ // Scalar x_position; Scalar y_position; Scalar width; Scalar height; *stream >> x_position; *stream >> y_position; *stream >> width; *stream >> height; SetViewPort(x_position, y_position, width, height); SetPerspective(model->m_nearClip, model->m_farClip, angle, (height/width)*0.75f); // //------------------- // Load up the lights //------------------- // ChainIteratorOf lights(&Mission::GetInstance()->m_staticLights); gosFX::Light *light; int i=0; while ((light = lights.ReadAndNext()) != NULL) { Verify(i < ELEMENTS(view_states->m_lights)); view_states->m_lights[i++] = light->m_light; } view_states->m_lights[i] = NULL; // //--------------------------------------- // Set up the sky element if there is one //--------------------------------------- // #if 0 const Mission::GameModel *mission_model = Mission::GetInstance()->GetGameModel(); Check_Object(mission_model); #endif *stream >> m_isMainSceneCamera; *stream >> m_drawSky; *stream >> m_LODOffset; if(m_drawSky) { camera->DrawSky(true); if(Mission::GetInstance()->m_isNightMission) { if(Mission::GetInstance()->m_nightSky.GetCurrent()) camera->AdoptSkyElement(Mission::GetInstance()->m_nightSky.GetCurrent()); } else { if(Mission::GetInstance()->m_sky.GetCurrent()) camera->AdoptSkyElement(Mission::GetInstance()->m_sky.GetCurrent()); } } else { camera->DrawSky(false); } // //------------------------------------------ // Attach the camera to the renderer's scene //------------------------------------------ // VideoRenderer *renderer = Cast_Object(VideoRenderer*, owning_web->GetRenderer()); if(m_isMainSceneCamera) { Element *root = renderer->GetSceneRoot(); Check_Object(root); camera->SetScene(root); renderer->SetCamera(const_cast(this)); } else { renderer->AddSecondaryCamera(const_cast(this)); camera->SetSecondaryCamera(); } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // CameraComponent* CameraComponent::Make( MemoryStream *stream, VideoComponentWeb *owning_web, Replicator *replicator ) { CameraComponent *camera = new CameraComponent( DefaultData, stream, owning_web, Cast_Object(Interface*, replicator) ); return camera; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // CameraComponent::~CameraComponent() { if (m_isMainSceneCamera && m_drawSky) { ElementRenderer::CameraElement *camera = GetElement(); Check_Object(camera); camera->DeleteSky(); } Check_Object(VideoRenderer::Instance); if (VideoRenderer::Instance->GetSceneCamera() == this) VideoRenderer::Instance->SetCamera(NULL); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void CameraComponent::Execute() { // //------------------------------------------------------- // Get the camera and display, then clear the back buffer //------------------------------------------------------- // ElementRenderer::LODElement::s_Offset -= m_LODOffset; Check_Object(this); ElementRenderer::CameraElement *camera = GetElement(); Check_Object(camera); camera->DrawScene(); ElementRenderer::LODElement::s_Offset += m_LODOffset; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void CameraComponent::TestInstance() { Verify(IsDerivedFrom(DefaultData)); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void CameraComponent::ComputeEyeLine( Line3D *eye_line, const Vector2DOf &cursor ) { Check_Object(this); Check_Pointer(eye_line); Check_Object(&cursor); Verify( cursor.x >= 0.0f && cursor.x <= 1.0f && cursor.y >= 0.0f && cursor.y <= 1.0f ); // //---------------------------------- // Figure out the near plane borders //---------------------------------- // ElementRenderer::CameraElement *camera = GetElement(); Check_Object(camera); Scalar left, right, up, down, n, f; camera->GetNearPlaneBorders(&left, &right, &up, &down, &n, &f); Verify(n > SMALL); // //---------------------------------------------------------------------- // Figure out the point the near plane where the eye hits, the normalize // the direction //---------------------------------------------------------------------- // Vector3D eye_to_plane; eye_to_plane.x = Lerp(left, right, cursor.x); eye_to_plane.y = Lerp(up, down, cursor.y); eye_to_plane.z = n; UnitVector3D local_d(eye_to_plane); // //------------------------------------ // Transform this into the world space //------------------------------------ // const LinearMatrix4D &eye_to_world = camera->GetLocalToWorld(); eye_line->m_origin = eye_to_world; eye_line->m_direction.Multiply(local_d, eye_to_world); eye_line->m_length = f / local_d.z; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // bool CameraComponent::ComputeCursor( Vector2DOf *cursor, const Point3D &location ) { Check_Object(this); Check_Pointer(cursor); Check_Object(&location); // //---------------------------------- // Figure out the near plane borders //---------------------------------- // ElementRenderer::CameraElement *camera = GetElement(); Check_Object(camera); Scalar left, right, up, down, n, f; camera->GetNearPlaneBorders(&left, &right, &up, &down, &n, &f); Verify(n > SMALL); // //------------------------------------------------------------------------- // Transform the world point into camera space and project it unto the near // viewing plane. If there is nothing to project, just take the points as // they are //------------------------------------------------------------------------- // LinearMatrix4D world_to_eye; world_to_eye.Invert(camera->GetLocalToWorld()); Point3D local_point; local_point.Multiply(location, world_to_eye); if (!Small_Enough(local_point.z)) { Scalar scale = n / local_point.z; local_point.x *= scale; local_point.y *= scale; } // //--------------------------------------------------------------- // Now figure out how far they are between the edges of the scene //--------------------------------------------------------------- // cursor->x = (local_point.x - left) / (right - left); cursor->y = (local_point.y - up) / (down - up); // //--------------------------------------- // Return true if the cursor is on screen //--------------------------------------- // return cursor->x >= 0.0f && cursor->x <= 1.0f && cursor->y >= 0.0f && cursor->y <= 1.0f; }