#include "munga.h" #pragma hdrstop #include "caminst.h" #include "notation.h" //########################################################################## //############################# CameraInstance ####################### //########################################################################## //########################################################################## // Construction and Destruction // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // CameraInstance::CameraInstance( int camera_ID, const Origin &camera_origin, Enumeration camera_type ) { Str_Copy(cameraName, "camera", sizeof(cameraName)); itoa(camera_ID, cameraName+6, 10); cameraID = camera_ID; cameraDataType = camera_type; SetLocalOrigin(camera_origin); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // CameraInstance::CameraInstance(StreamedInstance *model) { cameraID = model->cameraID; localOrigin = model->localOrigin; cameraToWorld = localOrigin; cameraDataType = model->cameraType; for (int i=0; i<4; ++i) { clampValues[i] = model->clampValues[i]; } Str_Copy(cameraName, "camera", sizeof(cameraName)); itoa(cameraID, cameraName+6, 10); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // #define READ_CAMERA_ENTRY(name,value)\ if (\ !cam_file->GetEntry(\ camera_page_name,\ name,\ &value\ )\ )\ { \ DEBUG_STREAM << camera_page_name << " missing " name "!\n" << std::flush;\ Fail("Bad cameras!");\ } CameraInstance::CameraInstance( NotationFile *cam_file, const char *camera_page_name ) { Check(this); Check(cam_file); Check_Pointer(camera_page_name); // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // PageName represents the cameraName //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Str_Copy(cameraName, camera_page_name, sizeof(cameraName)); // //~~~~~~~~~~~~~~~~~~~~~ // Read in the position //~~~~~~~~~~~~~~~~~~~~~ // READ_CAMERA_ENTRY("tranx", localOrigin.linearPosition.x); READ_CAMERA_ENTRY("trany", localOrigin.linearPosition.y); READ_CAMERA_ENTRY("tranz", localOrigin.linearPosition.z); // //~~~~~~~~~~~~~~~~~~~~~~~~ // Read in the Orientation //~~~~~~~~~~~~~~~~~~~~~~~~ // READ_CAMERA_ENTRY("quatx", localOrigin.angularPosition.x); READ_CAMERA_ENTRY("quaty", localOrigin.angularPosition.y); READ_CAMERA_ENTRY("quatz", localOrigin.angularPosition.z); READ_CAMERA_ENTRY("quatw", localOrigin.angularPosition.w); cameraToWorld = localOrigin; // //--------------------- // Read in camera clamp //--------------------- // clampValues[0] = -PI; cam_file->GetEntry( camera_page_name, "minYawClamp", &clampValues[0].angle ); clampValues[1] = PI; cam_file->GetEntry( camera_page_name, "maxYawClamp", &clampValues[1].angle ); clampValues[2] = -PI_OVER_2; cam_file->GetEntry( camera_page_name, "minPitchClamp", &clampValues[2].angle ); clampValues[3] = PI_OVER_2; cam_file->GetEntry( camera_page_name, "maxPitchClamp", &clampValues[3].angle ); // // Overwrite default cameraID // const char *camera_data_entry; if( !cam_file->GetEntry( camera_page_name, "cameraType", &camera_data_entry ) ) { cameraDataType = DefaultCameraType; } else { Check_Pointer(camera_data_entry); cameraDataType = FindCameraType(camera_data_entry); } READ_CAMERA_ENTRY("cameraID", cameraID); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // CameraInstance::~CameraInstance() { } //########################################################################## // Data Access Funtions // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // int CameraInstance::FindCameraType(const char *camera_data_type) { if(strcmp("DefaultCameraType", camera_data_type) == 0) { return DefaultCameraType; } else if(strcmp("AlwaysSeesCameraType", camera_data_type) == 0) { return AlwaysSeesCameraType; } return ErrorCameraType; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void CameraInstance::GetCameraTypeString(char *camera_type_string) { switch(cameraDataType) { case DefaultCameraType: Str_Copy( camera_type_string, "DefaultCameraType", (sizeof(char) * 128) ); break; case AlwaysSeesCameraType: Str_Copy( camera_type_string, "AlwaysSeesCameraType", (sizeof(char) * 128) ); break; default: Tell(cameraDataType); Warn(" Invalid cameraType !\n"); break; } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void CameraInstance::CalculateCameraRotation( YawPitchRoll *result, const Point3D &world ) { // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Given a Vector this function finds a rotation involving only // pitch and yaw, roll will not be affected. In addition the rotation // chosed will always be in the direction of least rotation //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Check(this); Check(result); Check(&world); // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // find the vector from where we are to where we want to point //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Point3D local; local.MultiplyByInverse(world, cameraToWorld); if (Small_Enough(local.LengthSquared())) { *result = YawPitchRoll::Identity; return; } // //~~~~~~~~~~~~~~~~~~~~~ // Calculate the angles //~~~~~~~~~~~~~~~~~~~~~ // result->yaw = Radian::Normalize(Arctan(-local.x, -local.z)); Scalar xz_direction = Sqrt((local.x * local.x) + (local.z *local.z)); result->pitch = Radian::Normalize(Arctan(local.y, xz_direction)); result->roll = 0.0f; Check_Fpu(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void CameraInstance::SetLocalOrigin( const Origin &new_origin ) { Check(this); Check(&new_origin); YawPitchRoll ypr; ypr = new_origin.angularPosition; clampValues[0] = clampValues[1] = 0.0f; clampValues[2] = clampValues[3] = ypr.pitch; ypr.pitch = 0.0f; localOrigin.linearPosition = new_origin.linearPosition; localOrigin.angularPosition = ypr; cameraToWorld = localOrigin; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void CameraInstance::LookAt( Origin *result, const Point3D &world_point ) { result->linearPosition = localOrigin.linearPosition; YawPitchRoll first,local; first = localOrigin.angularPosition; CalculateCameraRotation(&local, world_point); Clamp(local.yaw, clampValues[0], clampValues[1]); Clamp(local.pitch, clampValues[2], clampValues[3]); first.yaw += local.yaw; first.pitch = local.pitch; result->angularPosition = first; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void CameraInstance::AllowLookingAt(const Point3D &world) { YawPitchRoll local; CalculateCameraRotation(&local, world); if (local.yaw < clampValues[0]) { clampValues[0] = local.yaw; } else if (local.yaw > clampValues[1]) { clampValues[1] = local.yaw; } if (local.pitch < clampValues[2]) { clampValues[2] = local.pitch; } else if (local.pitch > clampValues[3]) { clampValues[3] = local.pitch; } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // #define YAW_SLOP (PI/12.0) #define PITCH_SLOP (0.75*(YAW_SLOP)) Logical CameraInstance::CanCameraSee(const Point3D &world_point) { YawPitchRoll ypr; CalculateCameraRotation(&ypr, world_point); return clampValues[0]-YAW_SLOP <= ypr.yaw && clampValues[1]+YAW_SLOP >= ypr.yaw && clampValues[2]-PITCH_SLOP <= ypr.pitch && clampValues[3]+PITCH_SLOP >= ypr.pitch; } //########################################################################## // Test Support // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Logical CameraInstance::TestInstance() const { return True; } //########################################################################## // Tool Support // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void CameraInstance::WriteNotationPage(NotationFile *camera_stream) { // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Output this camera's information to the given notation file //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Check(this); Check(camera_stream); camera_stream->SetEntry( cameraName, "cameraID", cameraID ); char camera_type[128]; GetCameraTypeString(camera_type); camera_stream->SetEntry( cameraName, "cameraType", camera_type ); camera_stream->SetEntry( cameraName, "tranx", localOrigin.linearPosition.x ); camera_stream->SetEntry( cameraName, "trany", localOrigin.linearPosition.y ); camera_stream->SetEntry( cameraName, "tranz", localOrigin.linearPosition.z ); camera_stream->SetEntry( cameraName, "quatx", localOrigin.angularPosition.x ); camera_stream->SetEntry( cameraName, "quaty", localOrigin.angularPosition.y ); camera_stream->SetEntry( cameraName, "quatz", localOrigin.angularPosition.z ); camera_stream->SetEntry( cameraName, "quatw", localOrigin.angularPosition.w ); camera_stream->SetEntry( cameraName, "minYawClamp", clampValues[0] ); camera_stream->SetEntry( cameraName, "maxYawClamp", clampValues[1] ); camera_stream->SetEntry( cameraName, "minPitchClamp", clampValues[2] ); camera_stream->SetEntry( cameraName, "maxPitchClamp", clampValues[3] ); camera_stream->AppendEntry(cameraName, NULL, (char *)NULL); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // #undef READ_CAMERA_ENTRY #define READ_CAMERA_ENTRY(name,value)\ if (\ !cam_file->GetEntry(\ camera_page_name,\ name,\ &value\ )\ )\ { \ DEBUG_STREAM << camera_page_name << " missing " name "!\n" << std::flush;\ return False;\ } Logical CameraInstance::CreateStreamedInstance( StreamedInstance *model, NotationFile *cam_file, const char *camera_page_name ) { Check_Pointer(model); Check(cam_file); Check_Pointer(camera_page_name); // //~~~~~~~~~~~~~~~~~~~~~ // Read in the position //~~~~~~~~~~~~~~~~~~~~~ // READ_CAMERA_ENTRY("tranx", model->localOrigin.linearPosition.x); READ_CAMERA_ENTRY("trany", model->localOrigin.linearPosition.y); READ_CAMERA_ENTRY("tranz", model->localOrigin.linearPosition.z); // //~~~~~~~~~~~~~~~~~~~~~~~~ // Read in the Orientation //~~~~~~~~~~~~~~~~~~~~~~~~ // READ_CAMERA_ENTRY("quatx", model->localOrigin.angularPosition.x); READ_CAMERA_ENTRY("quaty", model->localOrigin.angularPosition.y); READ_CAMERA_ENTRY("quatz", model->localOrigin.angularPosition.z); READ_CAMERA_ENTRY("quatw", model->localOrigin.angularPosition.w); // //--------------------- // Read in camera clamp //--------------------- // model->clampValues[0] = -PI; cam_file->GetEntry( camera_page_name, "minYawClamp", &model->clampValues[0].angle ); model->clampValues[1] = PI; cam_file->GetEntry( camera_page_name, "maxYawClamp", &model->clampValues[1].angle ); model->clampValues[2] = -PI_OVER_2; cam_file->GetEntry( camera_page_name, "minPitchClamp", &model->clampValues[2].angle ); model->clampValues[3] = PI_OVER_2; cam_file->GetEntry( camera_page_name, "maxPitchClamp", &model->clampValues[3].angle ); // // Overwrite default cameraID // const char *camera_data_entry; if( !cam_file->GetEntry( camera_page_name, "cameraType", &camera_data_entry ) ) { model->cameraType = DefaultCameraType; } else { Check_Pointer(camera_data_entry); model->cameraType = FindCameraType(camera_data_entry); } READ_CAMERA_ENTRY("cameraID", model->cameraID); model->instanceSize = sizeof(*model); return True; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // AlwaysSeesCameraInstance::AlwaysSeesCameraInstance( int camera_ID, const Origin &camera_origin, Enumeration camera_type ): CameraInstance(camera_ID, camera_origin, camera_type) { } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // AlwaysSeesCameraInstance::AlwaysSeesCameraInstance(StreamedInstance *model): CameraInstance(model) { } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // AlwaysSeesCameraInstance::AlwaysSeesCameraInstance( NotationFile *cam_file, const char *camera_page_name ): CameraInstance(cam_file, camera_page_name) { } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Logical AlwaysSeesCameraInstance::CanCameraSee(const Point3D &) { return True; }