#include "MW4Headers.hpp" #include "AI_DebugRenderer.hpp" #include #include #include #include "CombatAI.hpp" #include "MWDamageObject.hpp" #include #include #include "AIUtils.hpp" #include "MWPlayer.hpp" #include "VehicleInterface.hpp" #include #include "rail_move.hpp" #include "Flag.hpp" #include using namespace MW4AI; using namespace MechWarrior4; extern MW4AI::CPathManager *g_PathManager; const Stuff::Scalar max_distance_from_camera_to_draw = 500.0f; const Stuff::Scalar max_distance_from_camera_to_draw_squared = max_distance_from_camera_to_draw * max_distance_from_camera_to_draw; const int max_line_cloud_points = 500; const int wheel_move_pixels = 32; const int max_wheel_move_pixels = 1000; const unsigned int max_spew_files = 2000; DebugRenderer* DebugRenderer::m_Instance = 0; MechWarrior4::CombatAI* GetCombatAI(MechWarrior4::MWObject& v) { Verify(&v != 0); if ((v.GetAI() == 0) || (v.GetAI()->IsDerivedFrom(CombatAI::DefaultData) == false)) { return (0); } CombatAI* combat_ai = Cast_Object(CombatAI*,v.GetAI()); Check_Object(combat_ai); return (combat_ai); } MechWarrior4::CombatAI* GetCombatAI() { if (Adept::Player::GetInstance() == 0) { return (0); } MechWarrior4::MWPlayer* p = Cast_Object(MechWarrior4::MWPlayer*,Adept::Player::GetInstance()); if (p == 0) { return (0); } Check_Object(p); if ((p->GetInterface() == 0) || (p->GetInterface()->vehicle == 0)) { return (0); } return (GetCombatAI(*(p->GetInterface()->vehicle))); } DebugRenderer::DebugRenderer() : m_AIStatsRendering(STATS_NONE) , m_DrawingMovementLines(false) , m_DrawingMovementPaths(false) , m_DamageInfoRendering(false) , m_PointCount(0) , m_DeadReckoningRenderTime(0) , m_ShowNumPathRequests(false) , m_WheelDelta(0) , m_LastDiagnosticSpewFileIndex(0) { Verify(m_Instance == 0); m_Instance = this; gos_PushCurrentHeap(ElementRenderer::g_Heap); m_LineCloud = new ElementRenderer::LineCloudElement(max_line_cloud_points); gos_PopCurrentHeap(); m_LineCloud->SetDataPointers(&m_PointCount, m_PointData, m_ColorData); m_LineCloud->m_localOBB.localToParent = LinearMatrix4D::Identity; m_LineCloud->m_localOBB.sphereRadius = -1; Mission::GetInstance()->GetElement()->AttachChild(m_LineCloud); } DebugRenderer::~DebugRenderer() { Verify(m_Instance != 0); m_Instance = 0; } void DebugRenderer::Execute() { #ifdef _ARMOR try { #endif ResetLinesToDraw(); if ((GetAIStatsRendering() != STATS_NONE) || (GetDamageInfoRendering() == true)) { DrawAIStatsAndDamageInfo(); } if ((GetMovementLineRendering() == true) || (GetDeadReckoningRendering() == true)) { DrawLines(); } if (GetMovementPathRendering() == true) { DrawMovementPaths(); } if (GetShowNumPathRequests() == true) { DrawNumPathRequests(); } if (GetDiagnosticsRendering() == true) { DrawDiagnostics(); } #ifdef _ARMOR } catch (...) { } #endif } void DebugRenderer::DrawAIStatsAndDamageInfo() { Verify((GetAIStatsRendering() != STATS_NONE) || (GetDamageInfoRendering() == true)); #ifdef LAB_ONLY if ((Adept::EntityManager::GetInstance() == 0) || (Adept::VideoRenderer::Instance == 0)) { return; } Check_Object(Adept::EntityManager::GetInstance()); Check_Object(Adept::VideoRenderer::Instance); CameraComponent* camera = Adept::VideoRenderer::Instance->GetSceneCamera(); if ((camera == 0) || (camera->GetElement() == 0)) { return; } Check_Object(camera); Point3D camera_pos = (Point3D)camera->GetElement()->GetLocalToWorld(); HGOSFONT3D font = gos_LoadFont("Assets\\Graphics\\arial8.tga", 0); gos_TextSetAttributes(font,0x8FFF0000,1.0f,false,true,false,false); std::vector entities_to_consider; NameTable *table = NameTable::GetInstance(); int size(table->nameTableArray[NameTable::VehicleArray].GetLength()); {for (int i = 0; i < size; ++i) { NameTableEntry *data = &table->nameTableArray [NameTable::VehicleArray][i]; Adept::Entity* ent = data->dataPointer->GetCurrent (); if ((ent != 0) && (ent->IsDerivedFrom(MWObject::DefaultData) == true)) { entities_to_consider.push_back(Cast_Object(MWObject*,ent)); } }} if (Adept::NameTable::GetInstance() != 0) { { int last = Adept::NameTable::GetInstance()->GetLength(Adept::NameTable::BuildingArray); {for (int i = 0; i < last; ++i) { NameTableEntry* entry = Adept::NameTable::GetInstance()->FindEntry(Adept::NameTable::BuildingArray,i); if ((entry != 0) && (entry->dataPointer->GetCurrent() != 0)) { Adept::Entity* entity = entry->dataPointer->GetCurrent(); if (entity->IsDerivedFrom(MWObject::DefaultData) == true) { MWObject* mwobject = Cast_Object(MWObject*,entity); if (mwobject->GetAI() != 0) { entities_to_consider.push_back(mwobject); } } } }} } { int last = Adept::NameTable::GetInstance()->GetLength(Adept::NameTable::TurretArray); {for (int i = 0; i < last; ++i) { NameTableEntry* entry = Adept::NameTable::GetInstance()->FindEntry(Adept::NameTable::TurretArray,i); if ((entry != 0) && (entry->dataPointer->GetCurrent() != 0)) { Adept::Entity* entity = entry->dataPointer->GetCurrent(); if (entity->IsDerivedFrom(MWObject::DefaultData) == true) { entities_to_consider.push_back(entity); } } }} } } { int size(Adept::NameTable::GetInstance()->nameTableArray[NameTable::FlagArray].GetLength()); {for (int i = 0; i < size; ++i) { NameTableEntry *data = &Adept::NameTable::GetInstance()->nameTableArray [NameTable::FlagArray][i]; Adept::Entity* ent = data->dataPointer->GetCurrent(); if ((ent != 0) && (ent->IsDerivedFrom(Flag::DefaultData) == true)) { entities_to_consider.push_back(ent); } }} } {for (std::vector::const_iterator i = entities_to_consider.begin(); i != entities_to_consider.end(); ++i) { Point3D pos = (Point3D)(*i)->GetLocalToWorld(); Vector3D delta_from_camera; delta_from_camera.Subtract(pos,camera_pos); delta_from_camera.y = 0; if (delta_from_camera.GetLengthSquared() > max_distance_from_camera_to_draw_squared) { continue; } Stuff::Vector2DOf screen_pos; if (WorldToScreenCoords(pos,screen_pos) == false) { continue; } screen_pos.x *= Environment.screenWidth; screen_pos.y *= Environment.screenHeight; if ((screen_pos.x >= Environment.screenWidth) || (screen_pos.y >= Environment.screenHeight)) { continue; } if (PositionIsInFrontOfCamera(pos) == false) { continue; } int alpha = 0xFF000000 - ((int)((DistanceFromCamera(pos) * 200.0f) / max_distance_from_camera_to_draw) << 24); int color = 0; switch ((*i)->objectID & 0x00000007) { case 1: color = 0x008F8F8F; break; case 2: color = 0x0000008F; break; case 3: color = 0x00008F00; break; case 4: color = 0x008F0000; break; case 5: color = 0x008F008F; break; case 6: color = 0x00008F8F; break; case 7: color = 0x008F8F00; break; } gos_TextSetAttributes(font,alpha + color,1.0f,false,true,false,false); gos_TextSetRegion((int)screen_pos.x,(int)screen_pos.y,Environment.screenWidth,Environment.screenHeight); gos_TextSetPosition((int)screen_pos.x,(int)screen_pos.y); std::string s; if ((*i)->IsDerivedFrom(MWObject::DefaultData) == true) { MWObject* mwobject = Cast_Object(MWObject*,*i); if ((GetAIStatsRendering() == STATS_ALL) || ((GetAIStatsRendering() == STATS_CURRENT_VEHICLE) && (mwobject->GetAI() == GetCombatAI()))) { mwobject->AddStatsToString(s); if (mwobject->GetAI() != 0) { mwobject->GetAI()->AddStatsToString(s); } } if (GetDamageInfoRendering() == true) { mwobject->AddDamageInfoToString(s); } } else { if ((*i)->IsDerivedFrom(Flag::DefaultData) == true) { Flag* flag = Cast_Object(Flag*,*i); flag->AddStatsToString(s); } } gos_TextDraw(s.c_str()); gos_TextSetAttributes(font,0xFFFF0000,1.0f,false,true,false,false); }} gos_DeleteFont(font); #endif } void DebugRenderer::DrawNumPathRequests() { #ifdef LAB_ONLY Verify(GetShowNumPathRequests() == true); HGOSFONT3D font = gos_LoadFont("Assets\\Graphics\\arial8.tga", 0); gos_TextSetAttributes(font,0xFFFFFFFF,1.0f,false,true,false,false); gos_TextSetRegion(0,0,Environment.screenWidth,Environment.screenHeight); gos_TextSetPosition(10,2); std::string s = "Path Requests: "; s += IntToString(MW4AI::g_PathManager->GetNumPathRequests()); gos_TextDraw(s.c_str()); gos_DeleteFont(font); #endif } bool DebugRenderer::PositionIsInFrontOfCamera(const Stuff::Point3D& pos) const { if (Adept::VideoRenderer::Instance == 0) { return (false); } CameraComponent* camera = Adept::VideoRenderer::Instance->GetSceneCamera(); if ((camera == 0) || (camera->GetElement() == 0)) { return (false); } Check_Object(camera); Stuff::LinearMatrix4D matrix = camera->GetElement()->GetLocalToWorld(); if (pos == (Stuff::Point3D)matrix) { return (true); } return (GetSquaredDistToMatrixForward(pos,matrix) < GetSquaredDistToMatrixBackward(pos,matrix)); } Stuff::Scalar DebugRenderer::DistanceFromCamera(const Stuff::Point3D& pos) const { if (Adept::VideoRenderer::Instance == 0) { return (false); } CameraComponent* camera = Adept::VideoRenderer::Instance->GetSceneCamera(); if ((camera == 0) || (camera->GetElement() == 0)) { return (false); } Check_Object(camera); Stuff::Vector3D delta; delta.Subtract((Stuff::Point3D)camera->GetElement()->GetLocalToWorld(),pos); return (delta.GetApproximateLength()); } void DebugRenderer::DrawLines() { Verify(GetMovementLineRendering() == true); #ifdef LAB_ONLY NameTable *table = NameTable::GetInstance(); int size(table->nameTableArray[NameTable::VehicleArray].GetLength()); {for (int i = 0; i < size; ++i) { NameTableEntry *data = &table->nameTableArray [NameTable::VehicleArray][i]; Adept::Entity* ent = data->dataPointer->GetCurrent (); if ((ent != 0) && (ent->IsDestroyed() == false) && (ent->IsDerivedFrom(MWObject::DefaultData) == true)) { MWObject* v = Cast_Object(MWObject*,ent); Verify(v != 0); Check_Object(v); if ((GetMovementLineRendering() == true) && (GetCombatAI(*v) != 0)) { std::vector points; GetCombatAI(*v)->GetDirectPath(points); if (points.size() > 0) { // points[0].y += 8.0f; // points[1].y += 8.0f; AddPointsToLinesToDraw(points,Stuff::RGBAColor(0xFF,0,0,0)); } } if (GetDeadReckoningRendering() == true) { std::vector points; points.push_back((Stuff::Point3D)v->GetLocalToWorld()); Stuff::Point3D temp; points.push_back(v->EstimateFuturePosition(&temp, (Scalar)m_DeadReckoningRenderTime)); points[0].y += 6.0f; points[1].y += 6.0f; AddPointsToLinesToDraw(points,Stuff::RGBAColor(0,0,0xFF,0)); } } }} DrawLineCloud(); #endif } void DebugRenderer::DrawLineCloud() { #ifdef LAB_ONLY gos_PushCurrentHeap(ElementRenderer::g_Heap); if (m_PointCount > 0) { {for (int i = 0; i < m_PointCount; ++i) { Scalar length = m_PointData[i].GetLengthSquared(); if (length > m_LineCloud->m_localOBB.sphereRadius) { m_LineCloud->m_localOBB.sphereRadius = length; } }} m_LineCloud->NeedNewBounds(); m_LineCloud->NeedMatrixSync(); ElementRenderer::StateChange *state = new ElementRenderer::StateChange(); Check_Object(state); state->DisableZBufferCompare(); m_LineCloud->AdoptStateChange(state); m_LineCloud->Sync(); } gos_PopCurrentHeap(); #endif } void DebugRenderer::DrawMovementPaths() { Verify(GetMovementPathRendering() == true); #ifdef LAB_ONLY NameTable *table = NameTable::GetInstance(); int size(table->nameTableArray[NameTable::VehicleArray].GetLength()); {for (int i = 0; i < size; ++i) { NameTableEntry *data = &table->nameTableArray [NameTable::VehicleArray][i]; Adept::Entity* ent = data->dataPointer->GetCurrent (); if ((ent != 0) && (ent->IsDerivedFrom(Vehicle::DefaultData) == true)) { Check_Object(ent); Vehicle* v = Cast_Object(Vehicle*,ent); Verify(v != 0); Check_Object(v); if (GetCombatAI(*v) != 0) { MW4AI::CRailPath* cur_path = GetCombatAI(*v)->getCurPath(); if (cur_path != 0) { Stuff::Point3D my_pos(v->GetLocalToWorld()); std::vector path; cur_path->PointList(path); if (path.size () == 0) continue; path.insert(path.begin(),my_pos); {for (int i = 1; i < path.size(); ++i) { std::vector path2; path2.push_back(path[i-1]); path2.push_back(path[i]); path2[0].y = my_pos.y + 7.0f; path2[1].y = my_pos.y + 7.0f; AddPointsToLinesToDraw(path2,Stuff::RGBAColor(0,0xFF,0,0)); }} } } } }} DrawLineCloud(); #endif } DebugRenderer::STATS_RENDERING DebugRenderer::GetAIStatsRendering() const { return (m_AIStatsRendering); } void DebugRenderer::SetAIStatsRendering(DebugRenderer::STATS_RENDERING fDrawStats) { m_AIStatsRendering = fDrawStats; } bool DebugRenderer::GetDamageInfoRendering() const { return (m_DamageInfoRendering); } void DebugRenderer::SetDamageInfoRendering(bool fDrawDamageInfo) { m_DamageInfoRendering = fDrawDamageInfo; } bool DebugRenderer::GetMovementLineRendering() const { return (m_DrawingMovementLines); } void DebugRenderer::SetMovementLineRendering(bool fDrawMovementLines) { m_DrawingMovementLines = fDrawMovementLines; } bool DebugRenderer::GetMovementPathRendering() const { return (m_DrawingMovementPaths); } void DebugRenderer::SetMovementPathRendering(bool fDrawMovementPaths) { m_DrawingMovementPaths = fDrawMovementPaths; } DebugRenderer* DebugRenderer::GetInstance() { return (m_Instance); } bool DebugRenderer::WorldToScreenCoords(const Stuff::Point3D& world_coords, Stuff::Vector2DOf& screen_coords) const { if (Adept::VideoRenderer::Instance == 0) { return (false); } CameraComponent* camera = Adept::VideoRenderer::Instance->GetSceneCamera(); if ((camera == 0) || (camera->GetElement() == 0)) { return (false); } Check_Object(camera); camera->ComputeCursor(&screen_coords,world_coords); return (true); } void DebugRenderer::ResetLinesToDraw() { m_PointCount = 0; } void DebugRenderer::AddPointsToLinesToDraw(const std::vector& points, const Stuff::RGBAColor& color) { if (m_PointCount >= max_line_cloud_points) { return; } {for (std::vector::const_iterator i = points.begin(); i != points.end(); ++i) { m_PointData[m_PointCount] = *i; // m_PointData[m_PointCount].y += 8.0f; m_ColorData[m_PointCount] = color; ++m_PointCount; if (m_PointCount >= max_line_cloud_points) { return; } }} } void DebugRenderer::SetDeadReckoningRenderTime(Stuff::Time time) { m_DeadReckoningRenderTime = time; } Stuff::Time DebugRenderer::GetDeadReckoningRenderTime() const { return (m_DeadReckoningRenderTime); } bool DebugRenderer::GetDeadReckoningRendering() const { return (m_DeadReckoningRenderTime > 0); } bool DebugRenderer::GetShowNumPathRequests() const { return (m_ShowNumPathRequests); } void DebugRenderer::SetShowNumPathRequests(bool fShow) { m_ShowNumPathRequests = fShow; } bool DebugRenderer::GetDiagnosticsRendering() const { if ((MWMission::GetInstance() == 0) || (MWMission::GetInstance()->IsDerivedFrom(MWMission::DefaultData) == false)) { return (false); } Check_Object(MWMission::GetInstance()); MWMission *mission = Cast_Object(MWMission*,MWMission::GetInstance()); return (mission->GetDiagnosticsInterface().GetEnabled()); } bool EraseSpewFile(unsigned int index) { std::string s = "AISpew\\spew."; std::string suffix = IntToString(index); while (suffix.size() < 4) { suffix = "0" + suffix; } s += suffix; if (gos_DoesFileExist(s.c_str()) == true) { gos_DeleteFile(s.c_str()); return (true); } return (false); } void EraseExistingSpewFiles() { bool erased0 = EraseSpewFile(0); bool erasedmax = EraseSpewFile(max_spew_files); if ((erased0 == false) && (erasedmax == false)) { return; } unsigned int i = 1; bool previous = false; while (i < max_spew_files) { previous = EraseSpewFile(i); ++i; } if (erasedmax == true) { ++i; } if (previous == true) { while (EraseSpewFile(i) == true) { ++i; } } } void SpewEntityInfo(Adept::Entity& entity, std::string& string, bool include_geometry_info = false) { string += "ObjectID: "; string += IntToString(entity.objectID); string += "; Name: "; string += entity.instanceName; if (include_geometry_info == true) { string += "\n Position: ("; Stuff::Point3D pos(entity.GetLocalToWorld()); string += ScalarToString(pos.x); string += ","; string += ScalarToString(pos.y); string += ","; string += ScalarToString(pos.z); string += ")"; if (entity.IsDerivedFrom(MechWarrior4::Vehicle::DefaultData) == true) { MechWarrior4::Vehicle* v = Cast_Object(MechWarrior4::Vehicle*,&entity); Check_Object(v); string += "; Velocity: "; string += ScalarToString(v->currentSpeedMPS); string += " mps"; } else { string += "; [not a vehicle]"; } } } void SpewToDiagnosticFile(const std::string& spew_output, unsigned int index) { std::string text_to_spew = "Last Compile Date/Time: "; text_to_spew += __DATE__; text_to_spew += ", "; text_to_spew += __TIME__; text_to_spew += "\nSpewed at gos_GetElapsedTime() = "; text_to_spew += ScalarToString((Stuff::Scalar)gos_GetElapsedTime()); text_to_spew += "\n"; CombatAI* combat_ai = GetCombatAI(); if (combat_ai != 0) { text_to_spew += "Vehicle AI "; SpewEntityInfo(*combat_ai,text_to_spew); text_to_spew += "\n\nVehicle "; SpewEntityInfo(combat_ai->GetSelf(),text_to_spew,true); text_to_spew += "\n\n"; combat_ai->AddStatsToString(text_to_spew); if (combat_ai->Target() != 0) { text_to_spew += "\n\nTarget "; SpewEntityInfo(*(combat_ai->Target()),text_to_spew,true); } else { text_to_spew += "\nNo target."; } } text_to_spew += "\n\n"; text_to_spew += spew_output; std::string s = "AISpew\\spew."; std::string suffix = IntToString(index); while (suffix.size() < 4) { suffix = "0" + suffix; } s += suffix; HGOSFILE hGOSfile; gos_OpenFile(&hGOSfile,s.c_str(),READWRITE); gos_WriteFile(hGOSfile,text_to_spew.c_str(),text_to_spew.size()); gos_CloseFile(hGOSfile); } void DebugRenderer::DrawDiagnostics() { #ifdef LAB_ONLY if ((MWMission::GetInstance() == 0) || (MWMission::GetInstance()->IsDerivedFrom(MWMission::DefaultData) == false)) { return; } int wheelDelta = 0; gos_GetMouseInfo(0,0,0,0,&wheelDelta,0); if (wheelDelta != 0) { if (wheelDelta < 0) { m_WheelDelta += wheel_move_pixels; if (m_WheelDelta > max_wheel_move_pixels) { m_WheelDelta = max_wheel_move_pixels; } } else { m_WheelDelta -= wheel_move_pixels; if (m_WheelDelta < 0) { m_WheelDelta = 0; } } } Check_Object(MWMission::GetInstance()); MWMission *mission = Cast_Object(MWMission*,MWMission::GetInstance()); std::string s; mission->GetDiagnosticsInterface().GetSpew(s); if (s.size() == 0) { return; } if (DiagnosticsInterface::GetInstance().GetFileSpewing() == true) { if (m_LastDiagnosticSpewFileIndex == 0) { EraseExistingSpewFiles(); gos_CreateDirectory("AISpew"); } if (m_LastDiagnosticSpewFileIndex >= max_spew_files) { EraseSpewFile(m_LastDiagnosticSpewFileIndex - max_spew_files); } if (s != m_LastDiagnosticSpew) { SpewToDiagnosticFile(s,m_LastDiagnosticSpewFileIndex); ++m_LastDiagnosticSpewFileIndex; } } HGOSFONT3D font = gos_LoadFont("Assets\\Graphics\\arial8.tga", 0); gos_TextSetAttributes(font,0xFF000000,1.0f,false,true,false,false); gos_TextSetRegion(10,10,Environment.screenWidth,Environment.screenHeight); gos_TextSetPosition(10,10 - m_WheelDelta); gos_TextDraw(s.c_str()); gos_DeleteFont(font); m_LastDiagnosticSpew = s; #endif }