#include "MiniMapRenderThread.h" // rage: #include "grcore/allocscope.h" #include "grcore/quads.h" #include "scaleform/scaleform.h" #include "grcore/light.h" #if DEVICE_EQAA #include "grcore/fastquad.h" #endif // framework: #include "fwsys/gameskeleton.h" #include "fwsys/timer.h" #include "fwmaths/Rect.h" // game: #include "camera/viewports/Viewport.h" #include "Control/gps.h" #include "debug/DebugScene.h" #include "frontend/CMapMenu.h" #include "frontend/ui_channel.h" #include "frontend/Map/BlipEnums.h" #include "frontend/Scaleform/ScaleformMgr.h" #include "Network/Live/livemanager.h" #include "profile/group.h" #include "renderer/postprocessFX.h" #include "renderer/rendertargets.h" #include "renderer/sprite2d.h" #include "scene/world/GameWorldHeightMap.h" #include "script/script.h" #include "script/script_hud.h" #include "system/companion.h" #include "text/TextConversion.h" #include "timecycle/TimeCycleConfig.h" RAGE_DEFINE_CHANNEL(supertile) #define supertileAssertf(cond,fmt,...) RAGE_ASSERTF(supertile,cond,fmt,##__VA_ARGS__) #define supertileVerifyf(cond,fmt,...) RAGE_VERIFYF(supertile,cond,fmt,##__VA_ARGS__) #define supertileWarningf(fmt,...) RAGE_WARNINGF(supertile,fmt,##__VA_ARGS__) #define supertileDisplayf(fmt,...) RAGE_DISPLAYF(supertile,fmt,##__VA_ARGS__) #define supertileDebugf1(fmt,...) RAGE_DEBUGF1(supertile,fmt,##__VA_ARGS__) #define supertileDebugf2(fmt,...) RAGE_DEBUGF2(supertile,fmt,##__VA_ARGS__) #define supertileDebugf3(fmt,...) RAGE_DEBUGF3(supertile,fmt,##__VA_ARGS__) #define BLIP_LAYER_PATH "_level0.asRootContainer.asBlipLayerContainer.asBlipContainer.blipLayer" #define MINIMAP_INITIAL_SCALE (533.333333333333f) #define MINIMAP_TILE_WIDTH (MINIMAP_WORLD_SIZE_X / MINIMAP_WORLD_TILE_SIZE_X) #define MINIMAP_TILE_HEIGHT (MINIMAP_WORLD_SIZE_Y / MINIMAP_WORLD_TILE_SIZE_Y) #define DISABLE_HUD_FOR_CONTENT_CONTROLLED_BUILD 0 #define __DEBUG_SUPERTILES (0) // slightly optimises the supertiles // // we move the content of the bigmap internally so that the movie doesnt need to be moved off the edge of the screen to align with the minimap // #define __BIGMAP_INTERNAL_ADJUSTMENT_BLIP_RANGE (0.18f) // blip range offset #define __BIGMAP_INTERNAL_ADJUSTMENT_CONTAINERS (34.0f) // amount to move the containers #if DEBUG_DRAW && __BANK // because these are processed on subrender threads, we have to queue them up to the UT... to then queue back onto the RT struct debugVolume { debugVolume() : bCollides(false), type(DVVT_Sphere) {}; debugVolume(const spdSphere& sphere, Color32 color, bool bCollides_ = false) : asSphere(sphere), bCollides(bCollides_), objColor(color), type(DVVT_Sphere) {}; debugVolume(const spdOrientedBB& BB, Color32 color, bool bCollides_ = false) : asBB(BB), bCollides(bCollides_), objColor(color), type(DVVT_OBB) {}; debugVolume(Vec3V_In pt1, Vec3V_In pt2, Color32 color, Color32 color2, bool bCollides_ = false) : asLinePoint1(pt1), asLinePoint2(pt2), bCollides(bCollides_), objColor(color), objColor2(color2), type(DVVT_Line) {}; debugVolume& operator=(const debugVolume& b) { type = b.type; objColor = b.objColor; objColor2 = b.objColor2; bCollides = b.bCollides; switch(type) { case DVVT_Sphere: asSphere = b.asSphere; break; case DVVT_OBB: asBB = b.asBB; break; case DVVT_Line: asLinePoint1 = b.asLinePoint1; asLinePoint2 = b.asLinePoint2; break; } return *this; } enum volType { DVVT_Sphere, DVVT_OBB, DVVT_Line }; volType type; // union { // durango's being a jerk about this. So we'll get object bloat spdSphere asSphere; spdOrientedBB asBB; Vec3V asLinePoint1; Vec3V asLinePoint2; // }; Color32 objColor; Color32 objColor2; bool bCollides; }; static CDblBuf> s_DebugDrawVolumes; bool CMiniMap_RenderThread::sm_bDrawCollisionVolumes; void CMiniMap_RenderThread::RenderDebugVolumesOnUT() { if(!sm_bDrawCollisionVolumes) return; for( int i=0; i < s_DebugDrawVolumes.GetUpdateBuf().GetCount(); ++i ) { debugVolume& vol = s_DebugDrawVolumes.GetUpdateBuf()[i]; switch(vol.type) { case debugVolume::DVVT_OBB: { Mat34V mat(vol.asBB.m_localToWorld); grcDebugDraw::BoxOriented(vol.asBB.m_localBox.GetMin(), vol.asBB.m_localBox.GetMax(), mat, vol.objColor, vol.bCollides); break; } case debugVolume::DVVT_Line: grcDebugDraw::Line(vol.asLinePoint1, vol.asLinePoint2, vol.objColor, vol.objColor2); break; case debugVolume::DVVT_Sphere: grcDebugDraw::Sphere(vol.asSphere.GetCenter(), vol.asSphere.GetRadiusf(), vol.objColor, vol.bCollides, 1,24); break; } } s_DebugDrawVolumes.GetUpdateBuf().Reset(); } #endif // DEBUG_DRAW && BANK // // depth settings on movies: // enum { MOVIE_DEPTH_ROOT_CONTAINER = 1, MOVIE_DEPTH_ROOT_BLIP_CONTAINER, MOVIE_DEPTH_MAP, MOVIE_DEPTH_FREEWAY, MOVIE_DEPTH_INTERIOR, MOVIE_DEPTH_GOLF_COURSE, MOVIE_DEPTH_BITMAP, MOVIE_DEPTH_TILES, MOVIE_DEPTH_TERRITORY, MOVIE_DEPTH_RADIUS, MOVIE_DEPTH_STEALTH, MOVIE_DEPTH_ALTIMETER_DISPLAY, MOVIE_DEPTH_RUNWAY, MOVIE_DEPTH_GPS, MOVIE_DEPTH_MASK = MOVIE_DEPTH_GPS+GPS_NUM_SLOTS, // allow a gap here for the slots MOVIE_DEPTH_HEALTH, MOVIE_DEPTH_BLIPS_3D, MOVIE_DEPTH_BLIPS_2D, MOVIE_DEPTH_TEST_BLIP_3D, MOVIE_DEPTH_CROSSHAIR, MAX_MOVIE_DEPTHS }; // // depth of the blip and its children/siblings // enum { BLIP_DEPTH_OUTLINE_INDICATOR = 1, // outline blip BLIP_DEPTH_FRIEND_INDICATOR, // friend_blip BLIP_DEPTH_CREW_INDICATOR, // crew blip BLIP_DEPTH_MAIN_BLIP, // main_blip BLIP_DEPTH_DIRECTION_INDICATOR, // direction_blip BLIP_DEPTH_NUMBER, // number BLIP_DEPTH_TICK, // tick BLIP_DEPTH_SALE_ICON, // for sale blip BLIP_DEPTH_HIGHER_LOWER, // higher/lower blip MAX_BLIP_DEPTH_VALUES }; #if !__FINAL PARAM(minimap3d, "[code] 3D minimap"); PARAM(minimapRound, "[code] Round 2D minimap"); XPARAM(logMinimapTransitions); #endif #if __DEV extern u32 iTimeTaken; #endif // __DEV #if __BANK extern bool bDisplayInteriorInfoToLog; extern bool bDebug3DBlips; // extern float ms_fTilesAroundPlayer; // extern Vector2 ms_vTilesAroundPlayer; static Vector2 vGameScreenPos(0,0); extern float fDebugTiltValue; extern float fDebugOffsetValue; extern bool noUIAA; extern bool noUIAAOnBitMap; bool CMiniMap_RenderThread::sm_bDebugMaskDisplay = false; u8 CMiniMap_RenderThread::sm_uDebugMaskAlpha = 50; #endif // __BANK BankFloat CMiniMap_RenderThread::sm_fMultiheadEdgeFeatherPct = 0.012f; extern float fFreewayDisplayZ; #define MINIMAP_VISIBLE_TILES_NORTH (0) // these are the range of tiles which we will want to display (we ignore tiles outside this area as its unused as its just blank "sea" areas #define MINIMAP_VISIBLE_TILES_SOUTH (53) #define MINIMAP_VISIBLE_TILES_EAST (47) #define MINIMAP_VISIBLE_TILES_WEST (0) #define WEAPON_BLIP_NAME ("radar_weapon_") // i need to make these exposed to code really instead of this hack, but it will do for now since the bug is well overdue! #define HOOP_BLIP_NAME ("radar_ai") // for bug 1027418 // BankFloat extern float ALTIMETER_GROUND_LEVEL_FUDGE_FACTOR; extern float ALTIMETER_TICK_PIXEL_HEIGHT; extern float MINIMAP_GPS_DISPLAY_LIMIT; extern float MAP_BLIP_ROUND_THRESHOLD; bool bMiniMap3D = true; bool bMiniMapSquare = true; // Static member variables atArray CMiniMap_RenderThread::ms_ConesAttachedToBlips; sMiniMapRenderStateStruct CMiniMap_RenderThread::ms_MiniMapRenderState; // Blend States used when rendering the minimap grcBlendStateHandle CMiniMap_RenderThread::ms_StandardMiniMapRenderBlendStateHandle = grcStateBlock::BS_Invalid; grcBlendStateHandle CMiniMap_RenderThread::ms_ClearAlphaMiniMapRenderBlendStateHandle = grcStateBlock::BS_Invalid; grcBlendStateHandle CMiniMap_RenderThread::ms_CopyAAMiniMapRenderBlendStateHandle = grcStateBlock::BS_Invalid; grcSamplerStateHandle CMiniMap_RenderThread::ms_MinimapBitmapSamplerStateHandle = grcStateBlock::SS_Invalid; grcRasterizerStateHandle CMiniMap_RenderThread::ms_MinimapBitmapRasterizerStateHandle = grcStateBlock::RS_Invalid; #if __DEV grcSamplerStateHandle CMiniMap_RenderThread::ms_MinimapBitmapSamplerStateNearestHandle = grcStateBlock::SS_Invalid; #endif #if ENABLE_FOG_OF_WAR grcBlendStateHandle CMiniMap_RenderThread::ms_MinimapFoWBlendStateHandle = grcStateBlock::BS_Invalid; #if __D3D11 bool CMiniMap_RenderThread::ms_bUpdateFogOfWarData= false; #endif // __D3D11 #endif float CMiniMap_RenderThread::ms_MiniMapAlpha = 1.0f; EXT_PF_PAGE(MiniMap); PF_GROUP(MiniMapRenderThread); PF_LINK(MiniMap, MiniMapRenderThread); PF_TIMER(UpdateIndividualBlip, MiniMapRenderThread); PF_TIMER(AddBlipToStage, MiniMapRenderThread); PF_TIMER(RemoveBlipFromStage, MiniMapRenderThread); #if ENABLE_FOG_OF_WAR float FoWPrevX = 0.0f; float FoWPrevY = 0.0f; u32 FowLastFrameRead = 0; bank_s32 fowTileSize = 16; bank_s32 fowFrameCount = 33; #if __BANK bool DebugDrawFOW = false; float DebugFOWX1 = 0.6f; float DebugFOWY1 = 0.5f; float DebugFOWX2 = 0.8f; float DebugFOWY2 = 0.85f; int Fow_WorldX = -3447; int Fow_WorldY = -7722; int Fow_WorldW = 7647; int Fow_WorldH = 11368; #endif // __BANK Color32 fowColor(64,64,64,64); // PS3's using a signed blend because lum8 Color32 fowBleepColor(64,64,64,64); bank_s32 bleepCount = 2; bank_float fowColorSizeX = 2.5f; bank_float fowColorSizeY = 2.5f; bank_float fowBlipColorSizeX = 1.75f; bank_float fowBlipColorSizeY = 1.75f; bank_float moveStep = 0.25f; #if RSG_PC static int g_curFOWClearGPUCount = 0; static int g_curFOWRevealGPUCount = 0; #endif #endif // ENABLE_FOG_OF_WAR s32 CMiniMap_RenderThread::ms_iMovieId[MAX_MINIMAP_MOVIE_LAYERS]; Vector2 CMiniMap_RenderThread::ms_vOriginalStageSize; Vector2 CMiniMap_RenderThread::ms_vStageSize; CDblBuf CMiniMap_RenderThread::ms_LocalToScreen; GFxValue CMiniMap_RenderThread::asBitmap; GFxValue *CMiniMap_RenderThread::pRenderedBlipObject[MAX_NUM_BLIPS]; atFixedBitSet CMiniMap_RenderThread::bBlipIsOn3dLayer; GFxValue CMiniMap_RenderThread::ms_asRootContainer[MAX_MINIMAP_ROOT_LAYERS]; GFxValue CMiniMap_RenderThread::ms_asBaseLayerContainer[MAX_MINIMAP_LAYERS]; GFxValue CMiniMap_RenderThread::ms_asBaseOverlay3D[MAX_MINIMAP_LAYERS]; GFxValue CMiniMap_RenderThread::ms_asMapContainerMc; GFxValue CMiniMap_RenderThread::ms_asBlipContainerMc; GFxValue CMiniMap_RenderThread::ms_asGpsLayer[GPS_NUM_SLOTS]; GFxValue CMiniMap_RenderThread::ms_asMapObject; GFxValue CMiniMap_RenderThread::ms_asBlipLayer3D; GFxValue CMiniMap_RenderThread::ms_asInteriorMc; GFxValue CMiniMap_RenderThread::ms_asInteriorMovie; GFxValue CMiniMap_RenderThread::ms_asGolfCourseMc; GFxValue CMiniMap_RenderThread::ms_asGolfCourseMovie; GFxValue CMiniMap_RenderThread::ms_asGolfCourseHole; GFxValue CMiniMap_RenderThread::ms_asTileLayerContainer; GFxValue CMiniMap_RenderThread::ms_asBitmapLayerContainer; GFxValue CMiniMap_RenderThread::ms_asFreewayMovieClip; CMiniMap_RenderThread::AltimeterDisplay CMiniMap_RenderThread::ms_Altimeter; #if __STREAMED_SUPERTILE_FILES CSupertiles CMiniMap_RenderThread::ms_Supertiles; #endif // __STREAMED_SUPERTILE_FILES sMiniMapInterior CMiniMap_RenderThread::ms_PreviousInterior; s32 CMiniMap_RenderThread::ms_iPreviousGolfCourse = GOLF_COURSE_OFF; s32 CMiniMap_RenderThread::ms_iInteriorMovieId = -1; bool CMiniMap_RenderThread::ms_bInteriorMovieIdFullySetup = false; bool CMiniMap_RenderThread::ms_bInteriorWasSetOnPerFrame = false; s32 CMiniMap_RenderThread::ms_iGolfCourseMovieId = -1; bool CMiniMap_RenderThread::ms_bRunwayBlipsAreDisplaying = false; bool CMiniMap_RenderThread::ms_bRemoveInteriorMovie = false; bool CMiniMap_RenderThread::ms_bStreamInteriorMovie = false; bool CMiniMap_RenderThread::ms_bRemoveGolfCourseMovie = false; bool CMiniMap_RenderThread::ms_bStreamGolfCourseMovie = false; bank_bool CMiniMap_RenderThread::ms_bUseTexturedAlphaAllMovies = false; bank_bool CMiniMap_RenderThread::ms_bUseTextureAlphaBaseMovie = true; grcTexture *CMiniMap_RenderThread::ms_MaskTextureSm = NULL; grcTexture *CMiniMap_RenderThread::ms_MaskTextureLg = NULL; grcTexture *CMiniMap_RenderThread::ms_MaskTextureCnCSm = NULL; grcTexture *CMiniMap_RenderThread::ms_MaskTextureCnCLg = NULL; float CMiniMap_RenderThread::ms_fBlipMapRange = 1.0f; float CMiniMap_RenderThread::ms_fBlipMapAngle = 0.0f; #if RSG_PC CMiniMap_RenderThread::extraquad CMiniMap_RenderThread::ms_quads[MAX_FOW_TARGETS*(MAX_FOG_SCRIPT_REVEALS + 1)]; bool CMiniMap_RenderThread::ms_gotQuads = false; int CMiniMap_RenderThread::ms_iMultiGPUCount = 0; #endif #if __STREAMED_SUPERTILE_FILES // ****************************** CSupertile ****************************** void CSupertile::Init(u32 Row, u32 Column) { m_SupertileRow = Row; m_SupertileColumn = Column; m_bStreamThisSupertile = false; m_bRemoveThisSupertile = false; m_bPreviousValueOfShouldBeLoaded = false; m_bFullyLoaded = false; Remove(); // Resets everything } void CSupertile::Shutdown(unsigned shutdownMode) { if (CSystem::IsThisThreadId(SYS_THREAD_RENDER)) // only on UT { sfAssertf(0, "CSupertile::Shutdown can only be called on the UpdateThread!"); return; } if (shutdownMode == SHUTDOWN_SESSION) { supertileDebugf3("CSupertile::Shutdown releasing drawable %d", m_dwdRequest.GetRequestId().Get()); Remove(); m_bFullyLoaded = false; m_bStreamThisSupertile = false; m_bRemoveThisSupertile = false; m_bPreviousValueOfShouldBeLoaded = false; } } void CSupertile::Remove() { m_Background = NULL; m_Sea = NULL; for(int i = 0; i < HEIGHT_OF_DWD_SUPERTILE; i++) { for(int j = 0; j < WIDTH_OF_DWD_SUPERTILE; j++) { m_Foregrounds[i][j] = NULL; } } m_dwdRequest.ClearRequiredFlags(STRFLAG_DONTDELETE); m_dwdRequest.ClearMyRequestFlags(STRFLAG_DONTDELETE); m_dwdRequest.DelayedRelease(); } void CSupertile::Update(bool bShouldBeLoaded, GFxValue & UNUSED_PARAM(TileLayerContainer)) { if (m_bPreviousValueOfShouldBeLoaded != bShouldBeLoaded) { if (bShouldBeLoaded) { m_bStreamThisSupertile = true; } else { m_bRemoveThisSupertile = true; } m_bPreviousValueOfShouldBeLoaded = bShouldBeLoaded; } } bool g_RenderMinimapSea = false; bool g_RenderMinimap = true; Color32 g_MinimapSeaColor(56, 74, 80, 0xff); // for 1884099 void CSupertile::Render(int pass) { Matrix34 FlattenZ; FlattenZ.MakeScale(1.0f, 1.0f, 0.1f); FlattenZ.d.Zero(); if (m_bFullyLoaded && m_dwdRequest.IsValid()) { if (pass == 0) { PPU_ONLY(grcEffect::SetEdgeViewportCullEnable(false)); bool vectorSeaAllowed = g_RenderMinimapSea; #if __BANK if (CMiniMap_RenderThread::IsInPauseMap()) { vectorSeaAllowed = vectorSeaAllowed || CMiniMap::DrawVectorSeaPaused(); // normally false, allow switching on } else { vectorSeaAllowed = vectorSeaAllowed && CMiniMap::DrawVectorSeaMinimap(); // normally true, allow switching off } #endif if (m_Sea && vectorSeaAllowed) { m_Sea->Draw(FlattenZ, 0xFFFFFFFF, 0); } if (m_Background) { m_Background->Draw(FlattenZ, 0xFFFFFFFF, 0); } PPU_ONLY(grcEffect::SetEdgeViewportCullEnable(true)); } else { for(int row = 0; row < HEIGHT_OF_DWD_SUPERTILE; row++) { for(int col = 0; col < WIDTH_OF_DWD_SUPERTILE; col++) { if (m_Foregrounds[row][col]) { m_Foregrounds[row][col]->Draw(FlattenZ, 0xFFFFFFFF, 0); } } } } } #if __BANK if (pass == 1 && CMiniMap::DebugDrawTiles()) { spdRect superRect = CSupertiles::GetSuperTileWorldSpaceBounds(m_SupertileRow, m_SupertileColumn); Vec2V superCorners[4]; superRect.GetCorners(superCorners); grcColor(Color_black); grcBegin(drawLineStrip, 5); grcVertex2f(superCorners[0]); grcVertex2f(superCorners[1]); grcVertex2f(superCorners[2]); grcVertex2f(superCorners[3]); grcVertex2f(superCorners[0]); grcEnd(); Vec2V center = Average(superCorners[0], superCorners[1]); Vector3 center3(center.GetXf(), center.GetYf(), 0.0f); char label[64]; if (m_bFullyLoaded) { for(int row = 0; row < HEIGHT_OF_DWD_SUPERTILE; row++) { for(int col = 0; col < WIDTH_OF_DWD_SUPERTILE; col++) { spdRect rect = CSupertiles::GetMiniTileWorldSpaceBounds(m_SupertileRow, m_SupertileColumn, row, col); Vec2V corners[4]; rect.GetCorners(corners); grcColor(m_Foregrounds[row][col] == NULL ? Color_blue : Color_red); grcBegin(drawLineStrip, 8); grcVertex2f(corners[0]); grcVertex2f(corners[1]); grcVertex2f(corners[2]); grcVertex2f(corners[3]); grcVertex2f(corners[0]); grcVertex2f(corners[2]); grcVertex2f(corners[1]); grcVertex2f(corners[3]); grcEnd(); } } formatf(label, g_DwdStore.GetName(strLocalIndex(m_dwdRequest.GetRequestId()))); } else { formatf(label, "r%d, c%d", m_SupertileRow, m_SupertileColumn); } grcDrawLabel(center3, label, true); } #endif } void CSupertile::RenderFoW() { #if ENABLE_FOG_OF_WAR spdRect superRect = CSupertiles::GetSuperTileWorldSpaceBounds(m_SupertileRow, m_SupertileColumn); Vec2V superCorners[4]; superRect.GetCorners(superCorners); grcColor(Color32(0xff,0xff,0xff,0xff)); Vec2V superCornersUVs[4]; for(int i=0;i<4;i++) { Vector2 coords = CMiniMap_RenderThread::WorldToFowCoord(superCorners[i].GetXf(), superCorners[i].GetYf()); superCornersUVs[i].SetX(coords.x); superCornersUVs[i].SetY(coords.y); } grcDrawMode drawMode = drawQuads; #if __D3D11 drawMode = drawTriStrip; #endif grcBegin(drawMode, 4); grcTexCoord2f(superCornersUVs[0]); grcVertex2f(superCorners[0]); grcTexCoord2f(superCornersUVs[1]); grcVertex2f(superCorners[1]); #if __D3D11 grcTexCoord2f(superCornersUVs[3]); grcVertex2f(superCorners[3]); grcTexCoord2f(superCornersUVs[2]); grcVertex2f(superCorners[2]); #else grcTexCoord2f(superCornersUVs[2]); grcVertex2f(superCorners[2]); grcTexCoord2f(superCornersUVs[3]); grcVertex2f(superCorners[3]); #endif grcEnd(); #endif // ENABLE_FOG_OF_WAR } void CSupertile::RenderIslandFoW() { #if ENABLE_FOG_OF_WAR static dev_float ms_IslandWorldX = 2700; // TODO: customize these via overrides in GetSuperTileWorldSpaceBounds() static dev_float ms_IslandWorldY = -3150; static dev_float ms_IslandWorldW = 4000; static dev_float ms_IslandWorldH = 4000; //float superWidth = CMiniMap::sm_Tunables.Tiles.vMiniMapWorldSize.x / (float)(NUMBER_OF_SUPERTILE_COLUMNS); //float superHeight = CMiniMap::sm_Tunables.Tiles.vMiniMapWorldSize.y / (float)(NUMBER_OF_SUPERTILE_ROWS); //Vec2V superStart(CMiniMap::sm_Tunables.Tiles.vMiniMapWorldStart.x + superWidth * col, CMiniMap::sm_Tunables.Tiles.vMiniMapWorldStart.y - superHeight * row); //Vec2V superEnd(CMiniMap::sm_Tunables.Tiles.vMiniMapWorldStart.x + superWidth * (col+1), CMiniMap::sm_Tunables.Tiles.vMiniMapWorldStart.y - superHeight * (row+1)); Vec2V superStart(ms_IslandWorldX, ms_IslandWorldY); Vec2V superEnd(ms_IslandWorldX + ms_IslandWorldW, ms_IslandWorldY - ms_IslandWorldH); spdRect superRect(Min(superStart, superEnd), Max(superStart, superEnd)); Vec2V superCorners[4]; superRect.GetCorners(superCorners); grcColor(Color32(0xff,0xff,0xff,0xff)); Vec2V superCornersUVs[4]; for(int i=0;i<4;i++) { Vector2 coords = CMiniMap_RenderThread::WorldToFowCoord(superCorners[i].GetXf(), superCorners[i].GetYf()); superCornersUVs[i].SetX(coords.x); superCornersUVs[i].SetY(coords.y); } grcDrawMode drawMode = drawQuads; #if __D3D11 drawMode = drawTriStrip; #endif grcBegin(drawMode, 4); grcTexCoord2f(superCornersUVs[0]); grcVertex2f(superCorners[0]); grcTexCoord2f(superCornersUVs[1]); grcVertex2f(superCorners[1]); #if __D3D11 grcTexCoord2f(superCornersUVs[3]); grcVertex2f(superCorners[3]); grcTexCoord2f(superCornersUVs[2]); grcVertex2f(superCorners[2]); #else grcTexCoord2f(superCornersUVs[2]); grcVertex2f(superCorners[2]); grcTexCoord2f(superCornersUVs[3]); grcVertex2f(superCorners[3]); #endif grcEnd(); #endif // ENABLE_FOG_OF_WAR } void CSupertile::ProcessAtEndOfFrame(s32 UNUSED_PARAM(iParentMovieId)) { if (m_bRemoveThisSupertile) { supertileDebugf3("CSupertile::ProcessAtEndOfFrame releasing %d", m_dwdRequest.GetRequestId().Get()); m_bRemoveThisSupertile = false; m_bFullyLoaded = false; Remove(); } else if (m_bStreamThisSupertile) { char cSupertileName[20]; formatf(cSupertileName, "minimap_%u_%u", m_SupertileColumn, m_SupertileRow); supertileDebugf3("CSupertile::ProcessAtEndOfFrame streaming supertile %s", cSupertileName); strLocalIndex slot = g_DwdStore.FindSlot(cSupertileName); if (slot.Get() >= 0) { supertileDebugf3("CSupertile::ProcessAtEndOfFrame requesting drawable %s %d", cSupertileName, slot.Get()); m_dwdRequest.Request(slot, g_DwdStore.GetStreamingModuleId(), STRFLAG_FORCE_LOAD | STRFLAG_PRIORITY_LOAD | STRFLAG_DONTDELETE ); } m_bStreamThisSupertile = false; } else { // Poll for load completion bool wasLoaded = m_bFullyLoaded; m_bFullyLoaded = m_dwdRequest.HasLoaded(); if (m_bFullyLoaded) { m_dwdRequest.ClearRequiredFlags(STRFLAG_DONTDELETE); // ref counting takes over now } if (m_bPreviousValueOfShouldBeLoaded && !wasLoaded && m_bFullyLoaded) // if it's supposed to be loaded, and it just became loaded { Dwd* dict = g_DwdStore.Get(strLocalIndex(m_dwdRequest.GetRequestId())); supertileAssertf(dict, "Invalid dict?!"); char bkgName[32]; formatf(bkgName, "supertile_back_%d_%d", m_SupertileColumn, m_SupertileRow); m_Background = dict->LookupLocal(bkgName); char seaName[32]; formatf(seaName, "supertile_sea_%d_%d", m_SupertileColumn, m_SupertileRow); m_Sea = dict->LookupLocal(seaName); for(int i = 0; i < HEIGHT_OF_DWD_SUPERTILE; i++) { for(int j = 0; j < WIDTH_OF_DWD_SUPERTILE; j++) { char minitileName[64]; formatf(minitileName, "supertile_fore_%d_%d_tile_%d_%d", m_SupertileColumn, m_SupertileRow, j, i); m_Foregrounds[i][j] = dict->LookupLocal(minitileName); } } } } } void CSupertile::HandleIsLoadedCallback(const GFxValue& /*gfxVal*/) { } // ****************************** CSupertiles ****************************** void CSupertiles::Init(unsigned initMode) { if(initMode == INIT_CORE) { for (u32 row = 0; row < NUMBER_OF_SUPERTILE_ROWS; row++) { for (u32 column = 0; column < NUMBER_OF_SUPERTILE_COLUMNS; column++) { m_Supertiles[row][column].Init(row, column); } } } else if (initMode == INIT_SESSION) { m_PreviousTopTile = -1; m_PreviousBottomTile = -1; m_PreviousLeftTile = -1; m_PreviousRightTile = -1; } } void CSupertiles::Shutdown(unsigned shutdownMode) { if (CSystem::IsThisThreadId(SYS_THREAD_RENDER)) // only on UT { sfAssertf(0, "CSupertiles::Shutdown can only be called on the UpdateThread!"); return; } if (shutdownMode == SHUTDOWN_SESSION) { CScaleformMgr::AutoLock lockFore(CMiniMap::GetMovieId(MINIMAP_MOVIE_FOREGROUND)); CScaleformMgr::AutoLock lockBack(CMiniMap::GetMovieId(MINIMAP_MOVIE_BACKGROUND)); for (u32 row = 0; row < NUMBER_OF_SUPERTILE_ROWS; row++) { for (u32 column = 0; column < NUMBER_OF_SUPERTILE_COLUMNS; column++) { m_Supertiles[row][column].Shutdown(SHUTDOWN_SESSION); } } } } bool CSupertiles::Update(const Vector2 &vCurrentTile, const Vector2 &vTilesAroundPlayer, GFxValue &TileLayerContainer, bool bBitmapOnly) { #define MAX_TILES_TO_ATTACH_PER_UPDATE (10) #define MAX_TILES_TO_DETACH_PER_UPDATE (10) // Get x,y of top left and bottom right supertiles for current s32 CurrentTopTile = rage::Max((s32)(floorf(vCurrentTile.y - vTilesAroundPlayer.y)), MINIMAP_VISIBLE_TILES_NORTH); s32 CurrentBottomTile = rage::Min((s32)(ceilf(vCurrentTile.y + vTilesAroundPlayer.y)), MINIMAP_VISIBLE_TILES_SOUTH); s32 CurrentLeftTile = rage::Max((s32)(floorf(vCurrentTile.x - vTilesAroundPlayer.x)), MINIMAP_VISIBLE_TILES_WEST); s32 CurrentRightTile = rage::Min((s32)(ceilf(vCurrentTile.x + vTilesAroundPlayer.x)), MINIMAP_VISIBLE_TILES_EAST); // once all tiles have been detached, store the current tile we now are starting to attach... m_PreviousTopTile = CurrentTopTile; m_PreviousBottomTile = CurrentBottomTile; m_PreviousLeftTile = CurrentLeftTile; m_PreviousRightTile = CurrentRightTile; // Deal with loading/unloading the supertiles { s32 CurrentTopSupertile = CurrentTopTile/HEIGHT_OF_SUPERTILE; s32 CurrentBottomSupertile = CurrentBottomTile/HEIGHT_OF_SUPERTILE; s32 CurrentLeftSupertile = CurrentLeftTile/WIDTH_OF_SUPERTILE; s32 CurrentRightSupertile = CurrentRightTile/WIDTH_OF_SUPERTILE; for (s32 supertile_row = 0; supertile_row < NUMBER_OF_SUPERTILE_ROWS; supertile_row++) { for (s32 supertile_column = 0; supertile_column < NUMBER_OF_SUPERTILE_COLUMNS; supertile_column++) { bool bIsInVisibleRange = false; if (!bBitmapOnly) { if ( (supertile_row >= CurrentTopSupertile) && (supertile_row <= CurrentBottomSupertile) ) // Change to < maybe { if ( (supertile_column >= CurrentLeftSupertile) && (supertile_column <= CurrentRightSupertile) ) // Change to < maybe { bIsInVisibleRange = true; } } } m_Supertiles[supertile_row][supertile_column].Update(bIsInVisibleRange, TileLayerContainer); } } } return true; } void CSupertiles::ProcessAtEndOfFrame(s32 iParentMovieId) { if (CSystem::IsThisThreadId(SYS_THREAD_RENDER)) // only on UT { sfAssertf(0, "CSupertiles::ProcessAtEndOfFrame can only be called on the UpdateThread!"); return; } for (u32 row = 0; row < NUMBER_OF_SUPERTILE_ROWS; row++) { for (u32 column = 0; column < NUMBER_OF_SUPERTILE_COLUMNS; column++) { m_Supertiles[row][column].ProcessAtEndOfFrame(iParentMovieId); } } } void CSupertiles::HandleIsLoadedCallback(s32 Row, s32 Column, const GFxValue &gfxVal) { if (Verifyf((Row >= 0) && (Row < NUMBER_OF_SUPERTILE_ROWS), "CSupertiles::HandleIsLoadedCallback - Row %d is out of range", Row)) { if (Verifyf((Column >= 0) && (Column < NUMBER_OF_SUPERTILE_COLUMNS), "CSupertiles::HandleIsLoadedCallback - Column %d is out of range", Column)) { m_Supertiles[Row][Column].HandleIsLoadedCallback(gfxVal); } } } spdRect CSupertiles::GetMiniTileWorldSpaceBounds(s32 superTileRow, s32 superTileCol, s32 tileRow, s32 tileColumn) { spdRect superBounds = GetSuperTileWorldSpaceBounds(superTileRow, superTileCol); Vec2V superMin = superBounds.GetMin(); Vec2V superMax = superBounds.GetMax(); Vec2V superSize = superMax - superMin; Vec2V miniSize = superSize / Vec2V((float)WIDTH_OF_DWD_SUPERTILE, (float)(HEIGHT_OF_DWD_SUPERTILE)); Vec2V miniStart = AddScaled(superMin, miniSize, Vec2V((float)tileColumn, (float)(HEIGHT_OF_DWD_SUPERTILE - (tileRow)))); Vec2V miniEnd = AddScaled(superMin, miniSize, Vec2V((float)(tileColumn+1), (float)(HEIGHT_OF_DWD_SUPERTILE - (tileRow+1)))); return spdRect(miniStart, miniEnd); } spdRect CSupertiles::GetSuperTileWorldSpaceBounds(s32 row, s32 col) { float superWidth = CMiniMap::sm_Tunables.Tiles.vMiniMapWorldSize.x / (float)(NUMBER_OF_SUPERTILE_COLUMNS); float superHeight = CMiniMap::sm_Tunables.Tiles.vMiniMapWorldSize.y / (float)(NUMBER_OF_SUPERTILE_ROWS); Vec2V superStart(CMiniMap::sm_Tunables.Tiles.vMiniMapWorldStart.x + superWidth * col, CMiniMap::sm_Tunables.Tiles.vMiniMapWorldStart.y - superHeight * row); Vec2V superEnd(CMiniMap::sm_Tunables.Tiles.vMiniMapWorldStart.x + superWidth * (col+1), CMiniMap::sm_Tunables.Tiles.vMiniMapWorldStart.y - superHeight * (row+1)); return spdRect(Min(superStart, superEnd), Max(superStart, superEnd)); } void CSupertiles::Render() { for(int layer = 0; layer < 2; layer++) { // TODO - based on camera orientation, draw in one of 8 directions to do back-to-front rendering for(int row = 0; row < NUMBER_OF_SUPERTILE_ROWS; row++) { for(int col = 0; col < NUMBER_OF_SUPERTILE_COLUMNS; col++) { m_Supertiles[row][col].Render(layer); } } } } void CSupertiles::RenderFoW() { for(int row = 0; row < NUMBER_OF_SUPERTILE_ROWS; row++) { for(int col = 0; col < NUMBER_OF_SUPERTILE_COLUMNS; col++) { m_Supertiles[row][col].RenderFoW(); } } } #endif // __STREAMED_SUPERTILE_FILES #if SUPPORT_MULTI_MONITOR class MultiMonitorHudHelper { sMiniMapRenderStateStruct *m_State; Vector2 m_vPosition; Vector2 m_vSize; Vector2 m_vMaskPosition; Vector2 m_vMaskSize; Vector2 m_vBlurPosition; Vector2 m_vBlurSize; MultiMonitorHudHelper(const MultiMonitorHudHelper&); void operator= (const MultiMonitorHudHelper&); public: static void TransformPos(const GridMonitor& mon, Vector2 *v) { v->x = (mon.uLeft + mon.getWidth() * v->x) / GRCDEVICE.GetWidth(); v->y = (mon.uTop + mon.getHeight() * v->y) / GRCDEVICE.GetHeight(); } static void TransformSize(const GridMonitor& mon, Vector2 *v) { v->x = mon.getWidth() * v->x / GRCDEVICE.GetWidth(); v->y = mon.getHeight() * v->y / GRCDEVICE.GetHeight(); } MultiMonitorHudHelper(sMiniMapRenderStateStruct *state) : m_State(state) , m_vPosition(state->m_vCurrentMiniMapPosition) , m_vSize(state->m_vCurrentMiniMapSize) , m_vMaskPosition(state->m_vCurrentMiniMapMaskPosition) , m_vMaskSize(state->m_vCurrentMiniMapMaskSize) , m_vBlurPosition(state->m_vCurrentMiniMapBlurPosition) , m_vBlurSize(state->m_vCurrentMiniMapBlurSize) { const GridMonitor &mon = GRCDEVICE.GetMonitorConfig().getLandscapeMonitor(); TransformPos (mon, &state->m_vCurrentMiniMapPosition); TransformSize(mon, &state->m_vCurrentMiniMapSize); TransformPos (mon, &state->m_vCurrentMiniMapMaskPosition); TransformSize(mon, &state->m_vCurrentMiniMapMaskSize); TransformPos (mon, &state->m_vCurrentMiniMapBlurPosition); TransformSize(mon, &state->m_vCurrentMiniMapBlurSize); } ~MultiMonitorHudHelper() { m_State->m_vCurrentMiniMapPosition = m_vPosition; m_State->m_vCurrentMiniMapSize = m_vSize; m_State->m_vCurrentMiniMapMaskPosition = m_vMaskPosition; m_State->m_vCurrentMiniMapMaskSize = m_vMaskSize; m_State->m_vCurrentMiniMapBlurPosition = m_vBlurPosition; m_State->m_vCurrentMiniMapBlurSize = m_vBlurSize; } }; #endif //SUPPORT_MULTI_MONITOR void CMiniMap_RenderThread::Init(unsigned initMode) { if(initMode == INIT_CORE) { grcBlendStateDesc bsd; bsd.BlendRTDesc[0].RenderTargetWriteMask = grcRSV::COLORWRITEENABLE_ALPHA; ms_ClearAlphaMiniMapRenderBlendStateHandle = grcStateBlock::CreateBlendState(bsd); // stateblock for standard minimap render bsd.BlendRTDesc[0].RenderTargetWriteMask = grcRSV::COLORWRITEENABLE_RGB; bsd.BlendRTDesc[0].BlendEnable = true; bsd.BlendRTDesc[0].SrcBlend = grcRSV::BLEND_ONE; bsd.BlendRTDesc[0].DestBlend = grcRSV::BLEND_INVSRCALPHA; bsd.BlendRTDesc[0].BlendOp = grcRSV::BLENDOP_ADD; ms_StandardMiniMapRenderBlendStateHandle = grcStateBlock::CreateBlendState(bsd); grcSamplerStateDesc ssd; ssd.AddressU = grcSSV::TADDRESS_CLAMP; ssd.AddressV = grcSSV::TADDRESS_CLAMP; ms_MinimapBitmapSamplerStateHandle = grcStateBlock::CreateSamplerState(ssd); #if __DEV ssd.Filter = grcSSV::FILTER_MIN_MAG_MIP_POINT; ms_MinimapBitmapSamplerStateNearestHandle = grcStateBlock::CreateSamplerState(ssd); #endif grcRasterizerStateDesc rsd; rsd.CullMode = grcRSV::CULL_NONE; ms_MinimapBitmapRasterizerStateHandle = grcStateBlock::CreateRasterizerState(rsd); #if ENABLE_FOG_OF_WAR bsd.BlendRTDesc[0].RenderTargetWriteMask = grcRSV::COLORWRITEENABLE_ALPHA; bsd.BlendRTDesc[0].BlendEnable = true; bsd.BlendRTDesc[0].SrcBlend = grcRSV::BLEND_ONE; bsd.BlendRTDesc[0].DestBlend = grcRSV::BLEND_ONE; bsd.BlendRTDesc[0].BlendOp = grcRSV::BLENDOP_MIN; bsd.BlendRTDesc[0].SrcBlendAlpha = grcRSV::BLEND_ONE; bsd.BlendRTDesc[0].DestBlendAlpha = grcRSV::BLEND_ONE; bsd.BlendRTDesc[0].BlendOpAlpha = grcRSV::BLENDOP_MIN; ms_MinimapFoWBlendStateHandle = grcStateBlock::CreateBlendState(bsd); #endif // ENABLE_FOG_OF_WAR // stateblock for copying the fully composited minimap with AA to the UI buffer bsd.BlendRTDesc[0].RenderTargetWriteMask = grcRSV::COLORWRITEENABLE_ALL; bsd.BlendRTDesc[0].BlendEnable = true; bsd.BlendRTDesc[0].SrcBlend = grcRSV::BLEND_ONE; bsd.BlendRTDesc[0].DestBlend = grcRSV::BLEND_ZERO; bsd.BlendRTDesc[0].BlendOp = grcRSV::BLENDOP_ADD; bsd.BlendRTDesc[0].SrcBlendAlpha = grcRSV::BLEND_ZERO; bsd.BlendRTDesc[0].DestBlendAlpha = grcRSV::BLEND_ONE; bsd.BlendRTDesc[0].BlendOpAlpha = grcRSV::BLENDOP_ADD; ms_CopyAAMiniMapRenderBlendStateHandle = grcStateBlock::CreateBlendState(bsd); for (s32 i = 0; i < MAX_MINIMAP_MOVIE_LAYERS; i++) { ms_iMovieId[i] = -1; } #if !__FINAL if (PARAM_minimapRound.Get()) { bMiniMapSquare = false; bMiniMap3D = false; } if (PARAM_minimap3d.Get()) { bMiniMap3D = true; } #endif // !__FINAL } else if(initMode == INIT_SESSION) { ms_bRunwayBlipsAreDisplaying = false; // Will the runway movie be hidden when a new session is started? ms_asInteriorMc.SetUndefined(); ms_asInteriorMovie.SetUndefined(); ms_asGolfCourseMc.SetUndefined(); ms_asGolfCourseMovie.SetUndefined(); ms_asGolfCourseHole.SetUndefined(); ms_PreviousInterior.Clear(); ms_iPreviousGolfCourse = GOLF_COURSE_OFF; ms_iInteriorMovieId = -1; ms_bInteriorMovieIdFullySetup = false; ms_bInteriorWasSetOnPerFrame = false; ms_iGolfCourseMovieId = -1; #if ENABLE_FOG_OF_WAR FowLastFrameRead = 0; #endif // ENABLE_FOG_OF_WAR // initialise all blips: for (s32 iCount = 0; iCount < MAX_NUM_BLIPS; iCount++) { pRenderedBlipObject[iCount] = NULL; } s32 txdSlot = CShaderLib::GetTxdId(); CMiniMap_RenderThread::ms_MaskTextureSm = g_TxdStore.Get(strLocalIndex(txdSlot))->Lookup(ATSTRINGHASH("RadarMaskSm", 0x6dd9a16)); CMiniMap_RenderThread::ms_MaskTextureLg = g_TxdStore.Get(strLocalIndex(txdSlot))->Lookup(ATSTRINGHASH("RadarMaskLg", 0x91a810f0)); //CMiniMap_RenderThread::ms_MaskTextureCnCSm = g_TxdStore.Get(strLocalIndex(txdSlot))->Lookup(ATSTRINGHASH("RadarMaskCnCSm", 0xEC1F6E28)); //AssertMsg(CMiniMap_RenderThread::ms_MaskTextureCnCSm, "RadarMaskCnCSm not found!"); //CMiniMap_RenderThread::ms_MaskTextureCnCLg = g_TxdStore.Get(strLocalIndex(txdSlot))->Lookup(ATSTRINGHASH("RadarMaskCnCLg", 0x1AD26689)); //AssertMsg(CMiniMap_RenderThread::ms_MaskTextureCnCLg, "RadarMaskCnCLg not found!"); #if RSG_PC ms_gotQuads = false; for (int i = 0; i < MAX_FOW_TARGETS*(MAX_FOG_SCRIPT_REVEALS + 1); i++) { ms_quads[i].flags = 0x7; } #endif } #if __STREAMED_SUPERTILE_FILES ms_Supertiles.Init(initMode); #endif // __STREAMED_SUPERTILE_FILES } void CMiniMap_RenderThread::Shutdown(unsigned shutdownMode) { if (shutdownMode == SHUTDOWN_CORE) { } else if (shutdownMode == SHUTDOWN_SESSION) { CScaleformMgr::AutoLock lockFore(CMiniMap::GetMovieId(MINIMAP_MOVIE_FOREGROUND)); CScaleformMgr::AutoLock lockBack(CMiniMap::GetMovieId(MINIMAP_MOVIE_BACKGROUND)); // remove any additional minimap movies we have loaded in RemoveInterior(); HandleInteriorAtEndOfFrame(); // actually request the removal of the movie - fixes 1617703 RemoveGolfCourse(true); HandleGolfCourseAtEndOfFrame(); // actually request the removal of the movie - fixes 1617703 for (int loop = 0; loop < ms_ConesAttachedToBlips.GetCount(); loop++) { RemoveConeFromBlipOnStage(ms_ConesAttachedToBlips[loop].m_iActualIdOfBlip); } ms_ConesAttachedToBlips.Reset(); CMiniMap_RenderThread::ms_MaskTextureSm = NULL; CMiniMap_RenderThread::ms_MaskTextureLg = NULL; CMiniMap_RenderThread::ms_MaskTextureCnCSm = NULL; CMiniMap_RenderThread::ms_MaskTextureCnCLg = NULL; } #if __STREAMED_SUPERTILE_FILES ms_Supertiles.Shutdown(shutdownMode); #endif // __STREAMED_SUPERTILE_FILES } void CMiniMap_RenderThread::SetMiniMapRenderState(const sMiniMapRenderStateStruct &newRenderState) { // copy over the structure sysMemCpy(&ms_MiniMapRenderState, &newRenderState, sizeof(sMiniMapRenderStateStruct)); } void CMiniMap_RenderThread::PrepareForRendering() { UpdateStatesWithActionScriptOnRT(); if (ms_MiniMapRenderState.m_bShouldProcessMiniMap) // if in pause map and not in map screen then don't render { UpdateWithActionScriptOnRT(((!ms_MiniMapRenderState.m_bShouldRenderMiniMap) || ms_MiniMapRenderState.m_CurrentGolfMap != GOLF_COURSE_OFF), false); } else { // continue to update the tiles even though its not rendered since we need them to appear as soon as possible // so if they can be streaming and attaching in the background whilst the minimap isnt getting rendered, all the better // otherwise they stream in as soon as the minimap pops on screen and you see the LOD for a second or so UpdateTiles(false); } } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CMiniMap_RenderThread::SetLocalStageSize() // PURPOSE: gets the stage size and stores it locally in code ///////////////////////////////////////////////////////////////////////////////////// void CMiniMap_RenderThread::SetLocalStageSize() { GFxMovieView* pView = CScaleformMgr::GetMovieView(ms_iMovieId[MINIMAP_MOVIE_FOREGROUND]); if (uiVerifyf(pView, "CMiniMap_RenderThread: no movieview to get stage size from at init")) { ms_vOriginalStageSize = Vector2(pView->GetMovieDef()->GetWidth(), pView->GetMovieDef()->GetHeight()); // store the stage size ms_vStageSize = ms_vOriginalStageSize; } else { ms_vStageSize = Vector2(0,0); // it will be buggered! } } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CMiniMap_RenderThread::CreateRoot() // PURPOSE: sets up the main root layer ///////////////////////////////////////////////////////////////////////////////////// void CMiniMap_RenderThread::CreateRoot(s32 iId) { switch (iId) { case MINIMAP_MOVIE_BACKGROUND: { GFxValue asMovieObject1 = CScaleformMgr::GetActionScriptObjectFromRoot(ms_iMovieId[MINIMAP_MOVIE_BACKGROUND]); asMovieObject1.CreateEmptyMovieClip(&ms_asRootContainer[MINIMAP_ROOT_MAP_TRANSPARENT], "asRootContainer", MOVIE_DEPTH_ROOT_CONTAINER); break; } case MINIMAP_MOVIE_FOREGROUND: { GFxValue asMovieObject2 = CScaleformMgr::GetActionScriptObjectFromRoot(ms_iMovieId[MINIMAP_MOVIE_FOREGROUND]); asMovieObject2.CreateEmptyMovieClip(&ms_asRootContainer[MINIMAP_ROOT_LAYER_MASKED], "asRootContainer", MOVIE_DEPTH_ROOT_CONTAINER); GFxValue asMovieObject3 = CScaleformMgr::GetActionScriptObjectFromRoot(ms_iMovieId[MINIMAP_MOVIE_FOREGROUND]); asMovieObject3.CreateEmptyMovieClip(&ms_asRootContainer[MINIMAP_ROOT_LAYER_UNMASKED], "asRootContainerBlips", MOVIE_DEPTH_ROOT_BLIP_CONTAINER); break; } } } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CMiniMap_RenderThread::RemoveRoot() // PURPOSE: removes the main root layer ///////////////////////////////////////////////////////////////////////////////////// void CMiniMap_RenderThread::RemoveRoot(s32 iId) { switch (iId) { case MINIMAP_MOVIE_BACKGROUND: { if (ms_asRootContainer[MINIMAP_ROOT_MAP_TRANSPARENT].IsDefined()) { ms_asRootContainer[MINIMAP_ROOT_MAP_TRANSPARENT].Invoke("removeMovieClip"); ms_asRootContainer[MINIMAP_ROOT_MAP_TRANSPARENT].SetUndefined(); } break; } case MINIMAP_MOVIE_FOREGROUND: { if (ms_asRootContainer[MINIMAP_ROOT_LAYER_MASKED].IsDefined()) { ms_asRootContainer[MINIMAP_ROOT_LAYER_MASKED].Invoke("removeMovieClip"); ms_asRootContainer[MINIMAP_ROOT_LAYER_MASKED].SetUndefined(); } if (ms_asRootContainer[MINIMAP_ROOT_LAYER_UNMASKED].IsDefined()) { ms_asRootContainer[MINIMAP_ROOT_LAYER_UNMASKED].Invoke("removeMovieClip"); ms_asRootContainer[MINIMAP_ROOT_LAYER_UNMASKED].SetUndefined(); } break; } } } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CMiniMap_RenderThread::CreateTerritoryContainer // PURPOSE: creates a container for the territory and passes info to actionscript ///////////////////////////////////////////////////////////////////////////////////// void CMiniMap_RenderThread::CreateTerritoryContainer() { GFxValue asTerritoryContainer; ms_asBaseOverlay3D[MINIMAP_LAYER_FOREGROUND].CreateEmptyMovieClip(&asTerritoryContainer, "asTerritory3D", MOVIE_DEPTH_TERRITORY); GFxValue::DisplayInfo info; info.SetScale(MINIMAP_INITIAL_SCALE, MINIMAP_INITIAL_SCALE); asTerritoryContainer.SetDisplayInfo(info); if (uiVerifyf(asTerritoryContainer.IsDisplayObject(), "MiniMap: 'asTerritoryContainer' is not a display object at init")) { if (CScaleformMgr::BeginMethod(ms_iMovieId[MINIMAP_MOVIE_FOREGROUND], SF_BASE_CLASS_MINIMAP, "REGISTER_TERRITORY")) { CScaleformMgr::AddParamGfxValue(asTerritoryContainer); CScaleformMgr::EndMethod(true); // this is instant as we are initialising the minimap here } } } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CMiniMap_RenderThread::RemoveTerritoryContainer // PURPOSE: removes the containers ///////////////////////////////////////////////////////////////////////////////////// void CMiniMap_RenderThread::RemoveTerritoryContainer() { GFxValue asTerritoryContainer; if (ms_asBaseOverlay3D[MINIMAP_LAYER_FOREGROUND].GFxValue::GetMember("asTerritory3D", &asTerritoryContainer)) { asTerritoryContainer.Invoke("removeMovieClip"); asTerritoryContainer.SetUndefined(); } } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CMiniMap_RenderThread::CreateHealthArmourContainer // PURPOSE: creates a container for the health and armour ///////////////////////////////////////////////////////////////////////////////////// void CMiniMap_RenderThread::CreateHealthArmourContainer() { GFxValue asHealthContainer; ms_asRootContainer[MINIMAP_ROOT_LAYER_UNMASKED].CreateEmptyMovieClip(&asHealthContainer, "asHealthContainer", MOVIE_DEPTH_HEALTH); if (uiVerifyf(asHealthContainer.IsDisplayObject(), "MiniMap: 'asHealthContainer' is not a display object at init")) { if (CScaleformMgr::BeginMethod(ms_iMovieId[MINIMAP_MOVIE_FOREGROUND], SF_BASE_CLASS_MINIMAP, "REGISTER_HEALTH_ARMOUR")) { CScaleformMgr::AddParamGfxValue(asHealthContainer); CScaleformMgr::EndMethod(true); // this is instant as we are initialising the minimap here } } } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CMiniMap_RenderThread::RemoveHealthArmourContainer // PURPOSE: removes the containers ///////////////////////////////////////////////////////////////////////////////////// void CMiniMap_RenderThread::RemoveHealthArmourContainer() { GFxValue asHealthContainer; if (ms_asRootContainer[MINIMAP_ROOT_LAYER_UNMASKED].GFxValue::GetMember("asHealthContainer", &asHealthContainer)) { asHealthContainer.Invoke("removeMovieClip"); // remove the mask movie asHealthContainer.SetUndefined(); } } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CMiniMap_RenderThread::CreateAltimeter // PURPOSE: creates altimeter and hides it (it gets set to visible later when needed) ///////////////////////////////////////////////////////////////////////////////////// void CMiniMap_RenderThread::CreateAltimeter() { if(ms_asRootContainer[MINIMAP_ROOT_LAYER_MASKED].CreateEmptyMovieClip(&ms_Altimeter.m_asContainerMc, "altimeterOffset", MOVIE_DEPTH_ALTIMETER_DISPLAY ) ) { int iDepth = 1; ms_Altimeter.m_asContainerMc.AttachMovie(&ms_Altimeter.m_asGaugeMc, "altimeterVertical", "asAltimeterVertical", iDepth++); ms_Altimeter.m_asContainerMc.AttachMovie(&ms_Altimeter.m_asRollMc, "altimeterHorizontal", "asAltimeterHorizontal", iDepth++); } GFxValue::DisplayInfo info; info.SetPosition((ms_vStageSize.x * 0.5f), (ms_vStageSize.y * 0.5f));// + MINIMAP_VEHICLE_OFFSET); info.SetVisible(false); ms_Altimeter.m_asContainerMc.SetDisplayInfo(info); } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CMiniMap_RenderThread::RemoveAltimeter // PURPOSE: removes anything the altimeter has set up in AS ///////////////////////////////////////////////////////////////////////////////////// void CMiniMap_RenderThread::RemoveAltimeter() { if (ms_Altimeter.m_asGaugeMc.IsDefined()) { ms_Altimeter.m_asGaugeMc.Invoke("removeMovieClip"); ms_Altimeter.m_asGaugeMc.SetUndefined(); } if (ms_Altimeter.m_asRollMc.IsDefined()) { ms_Altimeter.m_asRollMc.Invoke("removeMovieClip"); ms_Altimeter.m_asRollMc.SetUndefined(); } if (ms_Altimeter.m_asContainerMc.IsDefined()) { ms_Altimeter.m_asContainerMc.Invoke("removeMovieClip"); ms_Altimeter.m_asContainerMc.SetUndefined(); } } void CMiniMap_RenderThread::CreateFreeway() { const char *pFreewayComponentsString = "roads_overlay"; GFxValue asFreewayLayerContainer; if (ms_asBaseOverlay3D[MINIMAP_LAYER_BACKGROUND].CreateEmptyMovieClip(&asFreewayLayerContainer, "asFreewayLayer", MOVIE_DEPTH_FREEWAY)) { if (asFreewayLayerContainer.GFxValue::AttachMovie(&ms_asFreewayMovieClip, pFreewayComponentsString, pFreewayComponentsString, 1)) { GFxValue::DisplayInfo freewayDisplayInfo; freewayDisplayInfo.SetVisible(true); freewayDisplayInfo.SetPosition(0.0f, 0.0f); freewayDisplayInfo.SetScale(100.0f, 100.0f); // MINIMAP_INITIAL_SCALE / 100.0f, MINIMAP_INITIAL_SCALE / 100.0f); ms_asFreewayMovieClip.SetDisplayInfo(freewayDisplayInfo); } } } void CMiniMap_RenderThread::RemoveFreeway() { if (ms_asFreewayMovieClip.IsDefined()) { ms_asFreewayMovieClip.Invoke("removeMovieClip"); ms_asFreewayMovieClip.SetUndefined(); } GFxValue asFreewayLayerContainer; if (ms_asBaseOverlay3D[MINIMAP_LAYER_BACKGROUND].GFxValue::GetMember("asFreewayLayer", &asFreewayLayerContainer)) { asFreewayLayerContainer.Invoke("removeMovieClip"); asFreewayLayerContainer.SetUndefined(); } } void CMiniMap_RenderThread::UpdateFreeway() { GFxValue::DisplayInfo freewayDisplayInfo; #if __BANK freewayDisplayInfo.SetPosition(CMiniMap::sm_Tunables.Overlay.vPos.x, CMiniMap::sm_Tunables.Overlay.vPos.y); freewayDisplayInfo.SetScale(CMiniMap::sm_Tunables.Overlay.vScale.x, CMiniMap::sm_Tunables.Overlay.vScale.y); #endif // __BANK if (ms_MiniMapRenderState.m_vCentrePosition.z > CMiniMap::sm_Tunables.Overlay.fDisplayZ) { freewayDisplayInfo.SetVisible(true); } else { freewayDisplayInfo.SetVisible(false); } ms_asFreewayMovieClip.SetDisplayInfo(freewayDisplayInfo); } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CMiniMap_RenderThread::CreateCrosshair // PURPOSE: creates a crosshair and hides it (it gets set to visible later when needed) ///////////////////////////////////////////////////////////////////////////////////// void CMiniMap_RenderThread::CreateCrosshair() { GFxValue asCrosshairMc; ms_asRootContainer[MINIMAP_ROOT_LAYER_UNMASKED].GFxValue::AttachMovie(&asCrosshairMc, "crosshair", "asCrosshair", MOVIE_DEPTH_CROSSHAIR); GFxValue::DisplayInfo info; info.SetVisible(false); asCrosshairMc.SetDisplayInfo(info); } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CMiniMap_RenderThread::CreateMapContainers // PURPOSE: creates a container for the vector map ///////////////////////////////////////////////////////////////////////////////////// void CMiniMap_RenderThread::CreateMapContainers() { if (ms_asRootContainer[MINIMAP_ROOT_MAP_TRANSPARENT].CreateEmptyMovieClip(&ms_asBaseLayerContainer[MINIMAP_LAYER_BACKGROUND], "asMapContainer", MOVIE_DEPTH_MAP)) { ms_asBaseLayerContainer[MINIMAP_LAYER_BACKGROUND].GFxValue::AttachMovie(&ms_asMapContainerMc, "mapContainer", "asMapContainer", 1); } if (ms_asRootContainer[MINIMAP_ROOT_LAYER_MASKED].CreateEmptyMovieClip(&ms_asBaseLayerContainer[MINIMAP_LAYER_FOREGROUND], "asBlipLayerContainer", MOVIE_DEPTH_BLIPS_3D)) { ms_asBaseLayerContainer[MINIMAP_LAYER_FOREGROUND].GFxValue::AttachMovie(&ms_asBlipContainerMc, "blipContainer", "asBlipContainer", 1); } if (ms_asMapContainerMc.CreateEmptyMovieClip(&ms_asBaseOverlay3D[MINIMAP_LAYER_BACKGROUND], "asBackgroundOverlay3D", MOVIE_DEPTH_GPS)) // { GFxValue asInteriorLayer, asGolfCourseLayer; ms_asBaseOverlay3D[MINIMAP_LAYER_BACKGROUND].CreateEmptyMovieClip(&asInteriorLayer, "asInteriorLayer", MOVIE_DEPTH_INTERIOR); ms_asBaseOverlay3D[MINIMAP_LAYER_BACKGROUND].CreateEmptyMovieClip(&asGolfCourseLayer, "asGolfCourseLayer", MOVIE_DEPTH_GOLF_COURSE); } if (ms_asBlipContainerMc.CreateEmptyMovieClip(&ms_asBaseOverlay3D[MINIMAP_LAYER_FOREGROUND], "asForegroundOverlay3D", MOVIE_DEPTH_GPS)) // { for (s32 iLayerCount = 0; iLayerCount < GPS_NUM_SLOTS; iLayerCount++) { char cLayerName[20]; formatf(cLayerName, "asGpsLayer%d", iLayerCount, NELEM(cLayerName)); ms_asBaseOverlay3D[MINIMAP_LAYER_FOREGROUND].CreateEmptyMovieClip(&ms_asGpsLayer[iLayerCount], cLayerName, MOVIE_DEPTH_GPS+iLayerCount); // init the route layers as invisible: GFxValue::DisplayInfo info; info.SetVisible(false); ms_asGpsLayer[iLayerCount].SetDisplayInfo(info); } GFxValue asRadiusBlipLayer; ms_asBaseOverlay3D[MINIMAP_LAYER_FOREGROUND].CreateEmptyMovieClip(&asRadiusBlipLayer, "asRadiusBlipLayer", MOVIE_DEPTH_RADIUS); GFxValue asSonarBlipLayer; ms_asBaseOverlay3D[MINIMAP_LAYER_FOREGROUND].CreateEmptyMovieClip(&asSonarBlipLayer, "asSonarBlipLayer", MOVIE_DEPTH_STEALTH); } if (ms_asBaseLayerContainer[MINIMAP_LAYER_BACKGROUND].GFxValue::HasMember("asMapContainer") && ms_asMapContainerMc.GFxValue::HasMember("map")) { ms_asMapContainerMc.GFxValue::GetMember("map", &ms_asMapObject); ms_asBlipContainerMc.GFxValue::GetMember("blipLayer", &ms_asBlipLayer3D); GFxValue::DisplayInfo info; info.SetScale(MINIMAP_INITIAL_SCALE, MINIMAP_INITIAL_SCALE); ms_asMapObject.SetDisplayInfo(info); if (ms_asMapContainerMc.GFxValue::HasMember("sea")) { GFxValue seaMap; ms_asMapContainerMc.GFxValue::GetMember("sea", &seaMap); info.SetVisible(false); seaMap.SetDisplayInfo(info); } g_RenderMinimapSea = true; } else { uiAssertf(0, "MiniMap: One or more required movieclips are not set up in ActionScript"); } GFxValue::DisplayInfo info; info.SetPosition((ms_vStageSize.x * 0.5f), (ms_vStageSize.y * 0.5f)); ms_asBaseLayerContainer[MINIMAP_LAYER_BACKGROUND].SetDisplayInfo(info); ms_asBaseLayerContainer[MINIMAP_LAYER_FOREGROUND].SetDisplayInfo(info); info.Clear(); // default the initial zoom value to exterior on-foot info.SetScale(CMiniMap::sm_Tunables.Camera.fExteriorFootZoom, CMiniMap::sm_Tunables.Camera.fExteriorFootZoom); ms_asMapContainerMc.SetDisplayInfo(info); ms_asBlipContainerMc.SetDisplayInfo(info); // blip 2d layer: GFxValue asBlipLayer2D; ms_asRootContainer[MINIMAP_ROOT_LAYER_UNMASKED].CreateEmptyMovieClip(&asBlipLayer2D, "asBlipLayer2D", MOVIE_DEPTH_BLIPS_2D); GFxValue asMapObjectBackground; ms_asMapContainerMc.GFxValue::GetMember("map", &asMapObjectBackground); if (uiVerifyf(asMapObjectBackground.GFxValue::HasMember("main_map"), "MiniMap: 'main_map' does not exist in 'map'")) { GFxValue mainMap; asMapObjectBackground.GFxValue::GetMember("main_map", &mainMap); GFxValue asMapLayerGfx; mainMap.GFxValue::GetMember("map_layer", &asMapLayerGfx); asMapLayerGfx.CreateEmptyMovieClip(&ms_asTileLayerContainer, "asTileLayer", MOVIE_DEPTH_TILES); asMapLayerGfx.CreateEmptyMovieClip(&ms_asBitmapLayerContainer, "asBitmapLayer", MOVIE_DEPTH_BITMAP); // // we need to scale the tiles down - not 100% sure why, it used to be done in Actionscript, triggered by MINIMAP_INITIALISED // which we no longer call, so I do it here myself. It may have something to do with AA fixes Eddie may of done but he // isnt here right now to ask... // GFxValue::DisplayInfo CurrInfo; // For drawable minimap: CurrInfo.SetVisible(false); ms_asTileLayerContainer.SetDisplayInfo(CurrInfo); ms_asBitmapLayerContainer.SetDisplayInfo(CurrInfo); if (CScaleformMgr::BeginMethod(ms_iMovieId[MINIMAP_MOVIE_BACKGROUND], SF_BASE_CLASS_MINIMAP, "REGISTER_MAP_LAYER")) { CScaleformMgr::AddParamGfxValue(ms_asBitmapLayerContainer); CScaleformMgr::EndMethod(true); // this is instant as we are initialising the minimap here } } } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CMiniMap_RenderThread::RemoveMapContainers // PURPOSE: removes a container for the vector map ///////////////////////////////////////////////////////////////////////////////////// void CMiniMap_RenderThread::RemoveMapContainers() { GFxValue asInteriorLayer, asGolfCourseLayer, asRadiusBlipLayer, asSonarBlipLayer, asBlipLayer2D; if (ms_asBaseOverlay3D[MINIMAP_LAYER_BACKGROUND].GFxValue::GetMember("asInteriorLayer", &asInteriorLayer)) { asInteriorLayer.Invoke("removeMovieClip"); } if (ms_asBaseOverlay3D[MINIMAP_LAYER_BACKGROUND].GFxValue::GetMember("asGolfCourseLayer", &asGolfCourseLayer)) { asGolfCourseLayer.Invoke("removeMovieClip"); } if (ms_asBaseOverlay3D[MINIMAP_LAYER_FOREGROUND].GFxValue::GetMember("asRadiusBlipLayer", &asRadiusBlipLayer)) { asRadiusBlipLayer.Invoke("removeMovieClip"); } if (ms_asBaseOverlay3D[MINIMAP_LAYER_FOREGROUND].GFxValue::GetMember("asSonarBlipLayer", &asSonarBlipLayer)) { asSonarBlipLayer.Invoke("removeMovieClip"); } if (ms_asRootContainer[MINIMAP_ROOT_LAYER_UNMASKED].GFxValue::GetMember("asBlipLayer2D", &asBlipLayer2D)) { asBlipLayer2D.Invoke("removeMovieClip"); } for (s32 iLayerCount = 0; iLayerCount < GPS_NUM_SLOTS; iLayerCount++) { if (ms_asGpsLayer[iLayerCount].IsDefined()) { ms_asGpsLayer[iLayerCount].Invoke("removeMovieClip"); ms_asGpsLayer[iLayerCount].SetUndefined(); } } if (ms_asMapObject.IsDefined()) { ms_asMapObject.Invoke("removeMovieClip"); ms_asMapObject.SetUndefined(); } if (ms_asBlipLayer3D.IsDefined()) { ms_asBlipLayer3D.Invoke("removeMovieClip"); ms_asBlipLayer3D.SetUndefined(); } if (ms_asBlipContainerMc.IsDefined()) { ms_asBlipContainerMc.Invoke("removeMovieClip"); ms_asBlipContainerMc.SetUndefined(); } if (ms_asMapContainerMc.IsDefined()) { ms_asMapContainerMc.Invoke("removeMovieClip"); ms_asMapContainerMc.SetUndefined(); } if (ms_asTileLayerContainer.IsDefined()) { ms_asTileLayerContainer.Invoke("removeMovieClip"); ms_asTileLayerContainer.SetUndefined(); } if (ms_asBitmapLayerContainer.IsDefined()) { ms_asBitmapLayerContainer.Invoke("removeMovieClip"); ms_asBitmapLayerContainer.SetUndefined(); } if (ms_asBaseOverlay3D[MINIMAP_LAYER_FOREGROUND].IsDefined()) { ms_asBaseOverlay3D[MINIMAP_LAYER_FOREGROUND].Invoke("removeMovieClip"); ms_asBaseOverlay3D[MINIMAP_LAYER_FOREGROUND].SetUndefined(); } if (ms_asBaseOverlay3D[MINIMAP_LAYER_BACKGROUND].IsDefined()) { ms_asBaseOverlay3D[MINIMAP_LAYER_BACKGROUND].Invoke("removeMovieClip"); ms_asBaseOverlay3D[MINIMAP_LAYER_BACKGROUND].SetUndefined(); } if (ms_asBaseLayerContainer[MINIMAP_LAYER_BACKGROUND].IsDefined()) { ms_asBaseLayerContainer[MINIMAP_LAYER_BACKGROUND].Invoke("removeMovieClip"); ms_asBaseLayerContainer[MINIMAP_LAYER_BACKGROUND].SetUndefined(); } if (ms_asBaseLayerContainer[MINIMAP_LAYER_FOREGROUND].IsDefined()) { ms_asBaseLayerContainer[MINIMAP_LAYER_FOREGROUND].Invoke("removeMovieClip"); ms_asBaseLayerContainer[MINIMAP_LAYER_FOREGROUND].SetUndefined(); } } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CMiniMap_RenderThread::SetMaskOnLayer // PURPOSE: sets or unsets the mask on a layer ///////////////////////////////////////////////////////////////////////////////////// void CMiniMap_RenderThread::SetMaskOnLayer(bool bSet, s32 iLayer) { GFxValue args[1]; // either way, delete what's here GFxValue asMask; if (ms_asRootContainer[iLayer].HasMember("asMask")) { ms_asRootContainer[iLayer].GetMember("asMask", &asMask); args[0].SetNull(); // set argument to AS as NULL ms_asRootContainer[iLayer].Invoke("setMask", NULL, args, 1); asMask.Invoke("removeMovieClip"); // remove the mask movie asMask.SetUndefined(); } if (bSet) { // create the mask: GFxValue asMaskMc; ms_asRootContainer[iLayer].CreateEmptyMovieClip(&asMask, "asMask", MOVIE_DEPTH_MASK); GFxValue::DisplayInfo dispInfo; // we're drawing the mask directly in SF, to make it tons easier to tune. // the way this works, in theory, is: // 1. Determine the aspect ratio the minimap is in natively // 2. adjust away the offsets of the on-screen map (ie, the tunings are also in screen space) // 3. scale the dimensions from 'screen space' to 'map space' (using the ratio from step 1) // 4. draw the mask and set it on the appropriate layers // because the map is drawn stretched and scaled from its original size, this series of convolutions is required to get it look right // at all resolutions Vector2 maskPos( ms_MiniMapRenderState.m_vCurrentMiniMapMaskPosition ); Vector2 maskSize( ms_MiniMapRenderState.m_vCurrentMiniMapMaskSize ); float fMapRatio = ms_vOriginalStageSize.x / ms_vOriginalStageSize.y; const float fScaler = fMapRatio/CHudTools::GetAspectRatio(); maskPos.x -= ms_MiniMapRenderState.m_vCurrentMiniMapPosition.x; maskPos.y -= ms_MiniMapRenderState.m_vCurrentMiniMapPosition.y; maskSize.x /= ms_MiniMapRenderState.m_vCurrentMiniMapSize.x; maskSize.y /= ms_MiniMapRenderState.m_vCurrentMiniMapSize.y; maskPos.x *= ms_vOriginalStageSize.x/fScaler; maskPos.y *= ms_vOriginalStageSize.y; maskSize.x *= ms_vOriginalStageSize.x/fScaler; maskSize.y *= ms_vOriginalStageSize.y; GFxValue args[2]; u8 alpha = BANK_ONLY( sm_bDebugMaskDisplay ? sm_uDebugMaskAlpha : ) 100; #define INVOKE(func, val1, val2); { args[0].SetNumber(val1); args[1].SetNumber(val2); asMask.Invoke(func, NULL, args,2); } INVOKE("beginFill", 0x00FFFFFF, alpha); // white, full alpha INVOKE("moveTo", maskPos.x, maskPos.y); INVOKE("lineTo", maskPos.x+maskSize.x, maskPos.y); INVOKE("lineTo", maskPos.x+maskSize.x, maskPos.y+maskSize.y); INVOKE("lineTo", maskPos.x, maskPos.y+maskSize.y); INVOKE("lineTo", maskPos.x, maskPos.y); asMask.Invoke("endFill"); #if __BANK if( sm_bDebugMaskDisplay ) { static float thickness = 1; static int color = 0x00FF00FF; // a nice purple static int alpha = 50; GFxValue args3[3]; args3[0].SetNumber(thickness); args3[1].SetNumber(color); args3[2].SetNumber(alpha); // alpha asMask.Invoke("lineStyle", NULL, args3, 3); INVOKE("moveTo", maskPos.x, maskPos.y); INVOKE("lineTo", maskPos.x+maskSize.x, maskPos.y); INVOKE("lineTo", maskPos.x+maskSize.x, maskPos.y+maskSize.y); INVOKE("lineTo", maskPos.x, maskPos.y+maskSize.y); INVOKE("lineTo", maskPos.x, maskPos.y); } else #endif { args[0] = asMask; // set the arguments to AS at the mask ms_asRootContainer[iLayer].Invoke("setMask", NULL, args, 1); } } else { #if !__FINAL if(CMiniMap_Common::OutputDebugTransitions()) { uiDisplayf("MINIMAP_TRANSITION: CMiniMap_RenderThread::SetMaskOnLayer. turned off mask(RT)"); } #endif } } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CMiniMap_RenderThread::SetMask // PURPOSE: create and enable or disable a mask on the minimap ///////////////////////////////////////////////////////////////////////////////////// void CMiniMap_RenderThread::SetMask(bool bSet) { for (s32 i = 0; i < MAX_MINIMAP_MOVIE_LAYERS; i++) { if (ms_iMovieId[i] == -1) continue; //s32 iLayer; if (i == MINIMAP_MOVIE_FOREGROUND) { SetMaskOnLayer(bSet, MINIMAP_ROOT_LAYER_MASKED); if (bSet) { if (ms_MiniMapRenderState.m_bIsInPauseMap && !CPauseMenu::IsNavigatingContent()) { SetMaskOnLayer(true, MINIMAP_ROOT_LAYER_UNMASKED); } else { SetMaskOnLayer(false, MINIMAP_ROOT_LAYER_UNMASKED); } } else { SetMaskOnLayer(false, MINIMAP_ROOT_LAYER_UNMASKED); } } else { SetMaskOnLayer(bSet, MINIMAP_ROOT_MAP_TRANSPARENT); } } } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CMiniMap_RenderThread::SetupContainers() // PURPOSE: sets up each ActionScript container ///////////////////////////////////////////////////////////////////////////////////// void CMiniMap_RenderThread::SetupContainers() { if (ms_iMovieId[MINIMAP_MOVIE_BACKGROUND] == -1 || ms_iMovieId[MINIMAP_MOVIE_FOREGROUND] == -1) { uiAssertf(0, "MiniMap: Minimap.gfx is not active yet - Minimap is unlikely to continue!"); return; } SetLocalStageSize(); CreateRoot(MINIMAP_MOVIE_BACKGROUND); CreateRoot(MINIMAP_MOVIE_FOREGROUND); CreateHealthArmourContainer(); CreateMapContainers(); CreateAltimeter(); CreateCrosshair(); // CreateRunway(); CreateFreeway(); CreateTerritoryContainer(); #if __DEV if (!VerifyComponents()) { uiAssertf(0, "MiniMap: Minimap.gfx is missing some vital components. Minimap is likely to be unstable!"); } #endif // _DEV SetMask(true); } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CMiniMap_RenderThread::RemoveContainers() // PURPOSE: removes the containers setup inside SetupContainers ///////////////////////////////////////////////////////////////////////////////////// void CMiniMap_RenderThread::RemoveContainers() { if (ms_iMovieId[MINIMAP_MOVIE_BACKGROUND] == -1 || ms_iMovieId[MINIMAP_MOVIE_FOREGROUND] == -1) { uiAssertf(0, "MiniMap: Minimap.gfx is not active - Minimap is unlikely to continue!"); return; } // remove in reverse order of that we created them SetMask(false); RemoveTerritoryContainer(); RemoveFreeway(); RemoveAltimeter(); RemoveMapContainers(); RemoveHealthArmourContainer(); RemoveRoot(MINIMAP_MOVIE_BACKGROUND); RemoveRoot(MINIMAP_MOVIE_FOREGROUND); } #if __DEV ///////////////////////////////////////////////////////////////////////////////////////// // NAME: CMiniMap_RenderThread::VerifyComponents() // PURPOSE: this method checks some components on the movie at initialisation that we // assume are there from now on to avoid having to check every time. This // will only fail if there is a problem on the Actionscript side. ///////////////////////////////////////////////////////////////////////////////////////// bool CMiniMap_RenderThread::VerifyComponents() { GFxValue asMovieObject = CScaleformMgr::GetActionScriptObjectFromRoot(ms_iMovieId[MINIMAP_MOVIE_FOREGROUND]); if ( ms_asMapObject.HasMember("main_map") ) { return true; } return false; } #endif // __DEV ///////////////////////////////////////////////////////////////////////////////////// // NAME: CMiniMap_RenderThread::AddSonarBlipToStage // PURPOSE: creates a self-removing "sonar" stealth blip. We do not need to keep // track of these as these blips self-remove via ActionScript ///////////////////////////////////////////////////////////////////////////////////// void CMiniMap_RenderThread::AddSonarBlipToStage(sSonarBlipStructRT *pSonarBlip) { if (!CSystem::IsThisThreadId(SYS_THREAD_RENDER)) // only on RT { sfAssertf(0, "CMiniMap_RenderThread::AddSonarBlipToStage can only be called on the RenderThread!"); return; } // if sonar layer is currently invisible, do not add any new sonar blips GFxValue asSonarBlipLayer; if (!ms_asBaseOverlay3D[MINIMAP_LAYER_FOREGROUND].GetMember("asSonarBlipLayer", &asSonarBlipLayer)) { return; } GFxValue::DisplayInfo SonarLayerDisplayInfo; asSonarBlipLayer.GetDisplayInfo(&SonarLayerDisplayInfo); if (!SonarLayerDisplayInfo.GetVisible()) { return; } char cRefName[MAX_BLIP_NAME_SIZE+10]; formatf(cRefName, "stealth_blip_%d", pSonarBlip->iId, NELEM(cRefName)); const char* cSonarBlipName = "stealth_blip_sonar_fill"; GFxValue asSonarBlipMc; asSonarBlipLayer.GetMember(cRefName, &asSonarBlipMc); if (!asSonarBlipMc.IsUndefined()) // sonar blip exists, so just set the frame back to 1 { #define __BIGGEST_VISUAL_FRAME_NUM (1) asSonarBlipMc.GotoAndPlay(__BIGGEST_VISUAL_FRAME_NUM); } else // sonar blip doesnt exist at all, so add it { if (pSonarBlip->iFramesAlive == 0) { asSonarBlipLayer.GFxValue::AttachMovie(&asSonarBlipMc, cSonarBlipName, cRefName, pSonarBlip->iId); uiDisplayf("MiniMap: SONAR_BLIP - Attaching new sonar blip %s %s %d", cSonarBlipName, cRefName, pSonarBlip->iId); } } // set it to the correct (latest) properties if (!asSonarBlipMc.IsUndefined()) // sonar blip doesnt exist at all, so add it { GFxValue::DisplayInfo info; info.SetPosition((pSonarBlip->vPos.x), -(pSonarBlip->vPos.y)); if (pSonarBlip->iFramesAlive == 0) { info.SetScale(pSonarBlip->fSize, pSonarBlip->fSize); CRGBA blipColour = CHudColour::GetRGBA(pSonarBlip->iHudColour); asSonarBlipMc.SetColorTransform(blipColour); GFxValue::DisplayInfo dispInfo; dispInfo.SetAlpha((float)blipColour.GetAlphaf() * 100.0f); asSonarBlipMc.SetDisplayInfo(dispInfo); uiDisplayf("MiniMap: SONAR_BLIP - Setting as new blip - %s %s %d - pos:%0.2f,%0.2f - size:%0.2f - alpha:%0.2f", cSonarBlipName, cRefName, pSonarBlip->iId, pSonarBlip->vPos.x, pSonarBlip->vPos.y, pSonarBlip->fSize, (float)blipColour.GetAlphaf() * 100.0f); } asSonarBlipMc.SetDisplayInfo(info); } } void CMiniMap_RenderThread::SetupGolfCourseLayout() { if (!CSystem::IsThisThreadId(SYS_THREAD_RENDER)) // only on RT { sfAssertf(0, "CMiniMap_RenderThread::SetupGolfCourseLayout can only be called on the RenderThread!"); return; } GFxValue asHealthContainer; if (uiVerifyf(ms_asRootContainer[MINIMAP_ROOT_LAYER_UNMASKED].GetMember("asHealthContainer", &asHealthContainer), "CMiniMap_RenderThread: 'asHealthContainer' cannot be found when switching to golfcoursemap")) { if (uiVerifyf(asHealthContainer.IsDisplayObject(), "CMiniMap_RenderThread: 'asHealthContainer' is not a display object when switching to golfcourse")) { GFxValue::DisplayInfo healthContainerDisplayInfo; healthContainerDisplayInfo.SetVisible(false); asHealthContainer.SetDisplayInfo(healthContainerDisplayInfo); } } UpdateSea(false); GFxValue::DisplayInfo info; info.SetVisible(false); ms_asMapObject.SetDisplayInfo(info); g_RenderMinimap = false; SetMask(false); for (s32 i = 0; i < MAX_MINIMAP_MOVIE_LAYERS; i++) { CScaleformMgr::ChangeMovieParams(ms_iMovieId[i], ms_MiniMapRenderState.m_vCurrentMiniMapPosition, ms_MiniMapRenderState.m_vCurrentMiniMapSize, GFxMovieView::SM_ExactFit); } } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CMiniMap_RenderThread::UpdateGPSDisplay // PURPOSE: updates the minimap with any gps display ///////////////////////////////////////////////////////////////////////////////////// void CMiniMap_RenderThread::UpdateGPSDisplay() { if (ms_iMovieId[MINIMAP_MOVIE_FOREGROUND] == -1) return; CGps::UpdateGpsOnMiniMapOnRT(); } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CMiniMap_RenderThread::UpdateWithActionScriptOnRT // PURPOSE: updates on the RenderThread as we alter ActionScript on the movie itself ///////////////////////////////////////////////////////////////////////////////////// void CMiniMap_RenderThread::UpdateWithActionScriptOnRT(bool bTransition, bool bClearTiles) { if (!ms_MiniMapRenderState.m_bIsActive) return; if (!CSystem::IsThisThreadId(SYS_THREAD_RENDER)) // only on RT { sfAssertf(0, "CMiniMap_RenderThread::UpdateWithActionScriptOnRT can only be called on the RenderThread!"); return; } UpdateInterior(); UpdateMapPositionAndScale(bTransition); UpdateMapVisibility(); UpdateAltimeter(); UpdateSonarSweep(); UpdateFreeway(); UpdateTiles(bClearTiles); UpdateGolfCourse(); UpdateGPSDisplay(); GFxValue asCrosshairMc; if (ms_asRootContainer[MINIMAP_ROOT_LAYER_UNMASKED].GetMember("asCrosshair", &asCrosshairMc)) { GFxValue::DisplayInfo newDisplayInfo; newDisplayInfo.SetVisible(ms_MiniMapRenderState.bDrawCrosshair); asCrosshairMc.SetDisplayInfo(newDisplayInfo); } } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CMiniMap_RenderThread::UpdateStatesWithActionScriptOnRT // PURPOSE: switches minimap state (on the RT) ///////////////////////////////////////////////////////////////////////////////////// void CMiniMap_RenderThread::UpdateStatesWithActionScriptOnRT() { if (!ms_MiniMapRenderState.m_bIsActive) return; if (!CSystem::IsThisThreadId(SYS_THREAD_RENDER)) // only on RT { sfAssertf(0, "CMiniMap_RenderThread::UpdateStatesWithActionScriptOnRT can only be called on the RenderThread!"); return; } switch (ms_MiniMapRenderState.m_MinimapModeState) { case MINIMAP_MODE_STATE_SETUP_FOR_MINIMAP: { // MinimapModeState = MINIMAP_MODE_STATE_NONE; // Graeme - Can't clear this on the RenderThread. I'm relying on it being cleared at the end of CMiniMap::UpdateStatesOnUT() #if !__FINAL if(CMiniMap_Common::OutputDebugTransitions()) uiDisplayf("MINIMAP_TRANSITION: CMiniMap_RenderThread::UpdateStatesWithActionScriptOnRT. Received MINIMAP_MODE_STATE_SETUP_FOR_MINIMAP(%d) before processed (RT)", ms_MiniMapRenderState.m_MinimapModeState); #endif SetupForMiniMap(); ms_MiniMapRenderState.m_MinimapModeState = MINIMAP_MODE_STATE_SETUP_FOR_MINIMAP_HAS_BEEN_PROCESSED_BY_RENDER_THREAD; break; } case MINIMAP_MODE_STATE_SETUP_FOR_BIGMAP: { // MinimapModeState = MINIMAP_MODE_STATE_NONE; // Graeme - Can't clear this on the RenderThread. I'm relying on it being cleared at the end of CMiniMap::UpdateStatesOnUT() #if !__FINAL if(CMiniMap_Common::OutputDebugTransitions()) uiDisplayf("MINIMAP_TRANSITION: CMiniMap_RenderThread::UpdateStatesWithActionScriptOnRT. Received MINIMAP_MODE_STATE_SETUP_FOR_BIGMAP(%d) before processed (RT)", ms_MiniMapRenderState.m_MinimapModeState); #endif SetupForBigMap(); ms_MiniMapRenderState.m_MinimapModeState = MINIMAP_MODE_STATE_SETUP_FOR_BIGMAP_HAS_BEEN_PROCESSED_BY_RENDER_THREAD; break; } case MINIMAP_MODE_STATE_SETUP_FOR_PAUSEMAP: { // MinimapModeState = MINIMAP_MODE_STATE_NONE; // Graeme - Can't clear this on the RenderThread. I'm relying on it being cleared at the end of CMiniMap::UpdateStatesOnUT() #if !__FINAL if(CMiniMap_Common::OutputDebugTransitions()) uiDisplayf("MINIMAP_TRANSITION: CMiniMap_RenderThread::UpdateStatesWithActionScriptOnRT. Received MINIMAP_MODE_STATE_SETUP_FOR_PAUSEMAP(%d) before processed (RT)", ms_MiniMapRenderState.m_MinimapModeState); #endif SetupForPauseMenu(true); ms_MiniMapRenderState.m_MinimapModeState = MINIMAP_MODE_STATE_SETUP_FOR_PAUSEMAP_HAS_BEEN_PROCESSED_BY_RENDER_THREAD; break; } case MINIMAP_MODE_STATE_SETUP_FOR_CUSTOMMAP: { #if !__FINAL if(CMiniMap_Common::OutputDebugTransitions()) uiDisplayf("MINIMAP_TRANSITION: CMiniMap_RenderThread::UpdateStatesWithActionScriptOnRT. Received MINIMAP_MODE_STATE_SETUP_FOR_CUSTOMMAP(%d) before processed (RT)", ms_MiniMapRenderState.m_MinimapModeState); #endif // MinimapModeState = MINIMAP_MODE_STATE_NONE; // Graeme - Can't clear this on the RenderThread. I'm relying on it being cleared at the end of CMiniMap::UpdateStatesOnUT() SetupForPauseMenu(false); ms_MiniMapRenderState.m_MinimapModeState = MINIMAP_MODE_STATE_SETUP_FOR_CUSTOMMAP_HAS_BEEN_PROCESSED_BY_RENDER_THREAD; break; } case MINIMAP_MODE_STATE_SETUP_FOR_GOLFMAP: { #if !__FINAL if(CMiniMap_Common::OutputDebugTransitions()) uiDisplayf("MINIMAP_TRANSITION: CMiniMap_RenderThread::UpdateStatesWithActionScriptOnRT. Received MINIMAP_MODE_STATE_SETUP_FOR_GOLFMAP(%d) before processed (RT)", ms_MiniMapRenderState.m_MinimapModeState); #endif // MinimapModeState = MINIMAP_MODE_STATE_NONE; // Graeme - Can't clear this on the RenderThread. I'm relying on it being cleared at the end of CMiniMap::UpdateStatesOnUT() SetupForMiniMap(); ms_MiniMapRenderState.m_MinimapModeState = MINIMAP_MODE_STATE_SETUP_FOR_GOLFMAP_HAS_BEEN_PROCESSED_BY_RENDER_THREAD; break; } default: { // nothing break; } } } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CMiniMap_RenderThread::ClearMatrix // PURPOSE: clears the matrix3d when going from 3D to 2D view ///////////////////////////////////////////////////////////////////////////////////// void CMiniMap_RenderThread::ClearMatrix() { if (!CSystem::IsThisThreadId(SYS_THREAD_RENDER)) // only on RT { sfAssertf(0, "CMiniMap_RenderThread::ClearMatrix can only be called on the RenderThread!"); return; } GFxValue nullValue; nullValue.SetNull(); ms_asBaseLayerContainer[MINIMAP_LAYER_BACKGROUND].SetMember("_matrix3d", nullValue); ms_asBaseLayerContainer[MINIMAP_LAYER_FOREGROUND].SetMember("_matrix3d", nullValue); } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CMiniMap_RenderThread::UpdateMapPositionAndScale // PURPOSE: update position and scale of the map ///////////////////////////////////////////////////////////////////////////////////// bool CMiniMap_RenderThread::UpdateMapPositionAndScale(bool bForceInstantRangeChange) { if (!CSystem::IsThisThreadId(SYS_THREAD_RENDER)) // only on RT { sfAssertf(0, "CMiniMap_RenderThread::UpdateMapPositionAndScale can only be called on the RenderThread!"); return true; } bool bValuesChanged = false; bool bInstantChanges = bForceInstantRangeChange; if (ms_MiniMapRenderState.m_bIsInBigMap || ms_MiniMapRenderState.m_bInsideReappearance) { bInstantChanges = true; // always instant changes if in bigmap } const float fTimeAdjustment = fwTimer::GetSystemTimeStep(); // // Tilt // GFxValue::DisplayInfo infoTilt; bValuesChanged = false; ms_asBaseLayerContainer[MINIMAP_LAYER_FOREGROUND].GetDisplayInfo(&infoTilt); float fNewPosY = (ms_vStageSize.y * 0.5f) + ms_MiniMapRenderState.m_fOffset; float fCurrentAngle = (float)infoTilt.GetXRotation(); if (infoTilt.GetY() != fNewPosY) { infoTilt.SetY(fNewPosY); bValuesChanged = true; } if (ms_MiniMapRenderState.m_bIsInPauseMap || bInstantChanges) { if (infoTilt.GetXRotation() != ms_MiniMapRenderState.m_fAngle) { infoTilt.SetXRotation(ms_MiniMapRenderState.m_fAngle); bValuesChanged = true; } } else { #define ANGLE_ADJUSTER (6.0f*30.0f) // 6 degrees every update * 30 to compensate for legacy frame-based tunings float fCurrAngle = fCurrentAngle; Approach(fCurrAngle, ms_MiniMapRenderState.m_fAngle, ANGLE_ADJUSTER, fTimeAdjustment); infoTilt.SetXRotation(fCurrAngle); } //if (bValuesChanged) { ms_asBaseLayerContainer[MINIMAP_LAYER_BACKGROUND].SetDisplayInfo(infoTilt); ms_asBaseLayerContainer[MINIMAP_LAYER_FOREGROUND].SetDisplayInfo(infoTilt); if (infoTilt.GetXRotation() == 0.0f && fCurrentAngle != 0.0f) // if new angle is 0.0f and old was not 0.0f then clear matrix { ClearMatrix(); } } // // end of Tilt // // // Position // GFxValue::DisplayInfo CurrInfo; ms_asMapObject.GetDisplayInfo(&CurrInfo); if ((float)CurrInfo.GetX() != -ms_MiniMapRenderState.m_vMiniMapPosition.x || (float)CurrInfo.GetY() != ms_MiniMapRenderState.m_vMiniMapPosition.y) { GFxValue::DisplayInfo infoPosition; infoPosition.SetPosition(-ms_MiniMapRenderState.m_vMiniMapPosition.x, ms_MiniMapRenderState.m_vMiniMapPosition.y); ms_asMapObject.SetDisplayInfo(infoPosition); ms_asBlipLayer3D.SetDisplayInfo(infoPosition); ms_asBaseOverlay3D[MINIMAP_LAYER_BACKGROUND].SetDisplayInfo(infoPosition); ms_asBaseOverlay3D[MINIMAP_LAYER_FOREGROUND].SetDisplayInfo(infoPosition); } // // End of Position // // // Range and Rotation // GFxValue::DisplayInfo infoRangeRotation; ms_asMapContainerMc.GetDisplayInfo(&CurrInfo); float fCurrRange = (float)CurrInfo.GetXScale(); bValuesChanged = false; if ( (fCurrRange != ms_MiniMapRenderState.m_fMiniMapRange) ) { float fThisRange = ms_MiniMapRenderState.m_fMiniMapRange; if (( ms_MiniMapRenderState.m_bIsInPauseMap || (ms_MiniMapRenderState.m_bIsInCustomMap && !ms_MiniMapRenderState.m_bLockedToDistanceZoom)) || bInstantChanges) { // if in pausemap and we zoom, redraw the gps so we can scale it accordingly CGps::ForceUpdateOfGpsOnMiniMap(); infoRangeRotation.SetScale(fThisRange, fThisRange); bValuesChanged = true; } else { #define RANGE_SCALER (0.07f*30.0f) // *30 to compensate for legacy frame-based tunings if( fCurrRange != fThisRange ) { float fRangeAdjuster = (RANGE_SCALER * fCurrRange); Approach(fCurrRange, fThisRange, fRangeAdjuster, fTimeAdjustment); infoRangeRotation.SetScale(fCurrRange, fCurrRange); bValuesChanged = true; } } } if ((s32)CurrInfo.GetRotation() != ms_MiniMapRenderState.m_iRotation) { infoRangeRotation.SetRotation(ms_MiniMapRenderState.m_iRotation); bValuesChanged = true; } if (bValuesChanged) { ms_asMapContainerMc.SetDisplayInfo(infoRangeRotation); ms_asBlipContainerMc.SetDisplayInfo(infoRangeRotation); } // // end of Range and Rotation // GFxMovieView* pView = CScaleformMgr::GetMovieView(ms_iMovieId[MINIMAP_MOVIE_FOREGROUND]); if (pView) { pView->FindLocalToScreenMatrix(BLIP_LAYER_PATH, ms_LocalToScreen.GetRenderBuf()); } ms_fBlipMapRange = fCurrRange; ms_fBlipMapAngle = ms_MiniMapRenderState.m_fAngle; return (bValuesChanged); } // bool CMiniMap_RenderThread::IsFlagSet(CBlipComplex *pBlip, const s32 iQueryFlag) // { // if (uiVerifyf(pBlip, "CMiniMap_RenderThread::IsFlagSet - Blip not valid!")) // { // return ((pBlip->iFlags & iQueryFlag) ? true : false); // } // // return false; // } Vector3 CMiniMap_RenderThread::GetBlipPositionValue(const CBlipComplex *pBlip) { return pBlip->vPosition; } const Vector3& CMiniMap_RenderThread::GetBlipPositionConstRef(const CBlipComplex *pBlip) { return pBlip->vPosition; } // This seems to be the same as GetBlipPositionValue Vector3 CMiniMap_RenderThread::GetBlipPositionValueOnStage(const CBlipComplex *pBlip) { if (uiVerifyf(pBlip, "Blip doesnt exist!")) { return pBlip->vPosition; } return ORIGIN; } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CMiniMap_RenderThread::CheckForHeight() // PURPOSE: Returns whether the blip is higher or lower than the player // (expressed as -1, 0, 1) ///////////////////////////////////////////////////////////////////////////////////// s32 CMiniMap_RenderThread::CheckForHeight(CBlipComplex *pBlip) { #define METRES_TO_CHECK_ABOVE_BELOW_BLIP_EXTENDED (10.0f) #define METRES_TO_CHECK_ABOVE_BELOW_BLIP_STANDARD (2.0f) #define METRES_TO_CHECK_ABOVE_BELOW_BLIP_SHORT (1.0f) if (pBlip) { float fMetresToCheck = METRES_TO_CHECK_ABOVE_BELOW_BLIP_STANDARD; if (CMiniMap::IsFlagSet(pBlip, BLIP_FLAG_USE_EXTENDED_HEIGHT_THRESHOLD) || ms_MiniMapRenderState.bInPlaneOrHeli) { fMetresToCheck = METRES_TO_CHECK_ABOVE_BELOW_BLIP_EXTENDED; } else if (CMiniMap::IsFlagSet(pBlip, BLIP_FLAG_USE_SHORT_HEIGHT_THRESHOLD)) { fMetresToCheck = METRES_TO_CHECK_ABOVE_BELOW_BLIP_SHORT; } float fBlipHeight = GetBlipPositionValue(pBlip).z; float fPlayerHeight = ms_MiniMapRenderState.m_vCentrePosition.z; if (fPlayerHeight < fBlipHeight-fMetresToCheck) { return -1; // lower } else if (fPlayerHeight > fBlipHeight+fMetresToCheck) { return 1; // higher } } return 0; // level } void CMiniMap_RenderThread::GetMiniMapCoordinatesForCone(float inputX, float inputY, float fMapRange, float &outputX, float &outputY) { if ( (ms_MiniMapRenderState.m_fPlayerVehicleSpeed == 0.0f) && (fMapRange < MAP_BLIP_ROUND_THRESHOLD) ) { outputX = floor(inputX+0.5f); outputY = floor(-inputY+0.5f); } else { outputX = inputX; outputY = -inputY; } } void DrawCone(GFxValue &coneValue, float fStartAzimuthAngle, float fEndAzimuthAngle, float fFocusRange) { GFxValue args[2]; Vector3 line(0.0f, fFocusRange, 0.0f); line.RotateZ(fStartAzimuthAngle); // Draw line from ped args[0].SetNumber(0.0f); args[1].SetNumber(0.0f); coneValue.Invoke("moveTo", NULL, args, 2); args[0].SetNumber(line.x); args[1].SetNumber(-line.y); coneValue.Invoke("lineTo", NULL, args, 2); // End of draw line from ped // Draw arc float fAngle = fStartAzimuthAngle; static float ANGLE_RENDER_DIFF = PI/32.0f; while( fAngle < fEndAzimuthAngle ) { float fNextAngle = Min(fAngle + ANGLE_RENDER_DIFF, fEndAzimuthAngle); Vector3 line2(0.0f, fFocusRange, 0.0f); line2.RotateZ(fNextAngle); args[0].SetNumber(line2.x); args[1].SetNumber(-line2.y); coneValue.Invoke("lineTo", NULL, args, 2); fAngle = fNextAngle; } // Draw line back from end of cone to origin args[0].SetNumber(0.0f); args[1].SetNumber(0.0f); coneValue.Invoke("lineTo", NULL, args, 2); } void CMiniMap_RenderThread::DrawConeForBlip(GFxValue &coneValue, CBlipCone &blipCone) { GFxValue::DisplayInfo infoForNewlyCreatedCone; GFxValue args[5]; float aAsimuthAngles[MAX_CONE_ANGLES] = { blipCone.GetVisualFieldMinAzimuthAngle(), -blipCone.GetGazeAngle(), blipCone.GetGazeAngle(), blipCone.GetVisualFieldMaxAzimuthAngle() }; // Calculate the peripheral and focus ranges to render // float fPeripheralRange = blipCone.GetPeripheralRange(); float fFocusRange = blipCone.GetFocusRange(); args[0].SetNumber(0); // thickness - 0=thinnest, 255=thickest args[3].SetBoolean(false); // pixelHinting args[4].SetString("normal"); // noScale - "normal" is the default, try "none" #if __BANK if (CMiniMap::GetDrawActualRangeCone()) { // Set colour and alpha of debug cone args[1].SetNumber(0xff0000); args[2].SetNumber(100); coneValue.Invoke("lineStyle", NULL, args, 5); // Draw debug cone. This shows the actual perception range i.e. before FocusRangeMultiplier is applied DrawCone(coneValue, aAsimuthAngles[1], aAsimuthAngles[2], fFocusRange); } #endif // __BANK // Set colour and alpha of real cone CRGBA color = CHudColour::GetRGBA(blipCone.GetColor()); s32 fillColour = color.GetRed() << 16; fillColour |= color.GetGreen() << 8; fillColour |= color.GetBlue(); s32 coneAlpha = CMiniMap_Common::ALPHA_OF_POLICE_PERCEPTION_CONES; #if __BANK if (CMiniMap::GetOverrideConeColour()) { // This isn't really thread-safe. Hopefully, it doesn't matter too much since it's debug code. fillColour = CMiniMap::GetConeColourRed() << 16; fillColour |= CMiniMap::GetConeColourGreen() << 8; fillColour |= CMiniMap::GetConeColourBlue(); coneAlpha = CMiniMap::GetConeColourAlpha(); } #endif // __BANK args[1].SetNumber(fillColour); args[2].SetNumber(coneAlpha); coneValue.Invoke("lineStyle", NULL, args, 5); #if __BANK fFocusRange *= CMiniMap::GetConeFocusRangeMultiplier(); #else fFocusRange *= 1.05f; #endif // __BANK // Graeme - I'm not drawing the peripheral cones here - maybe I'll need to add them back in later. // In the past when I was drawing them, they were so small that I couldn't actually see them on the radar. args[0].SetNumber(fillColour); args[1].SetNumber(coneAlpha); coneValue.Invoke("beginFill", NULL, args, 2); DrawCone(coneValue, aAsimuthAngles[1], aAsimuthAngles[2], fFocusRange); // float fStartAzimuthAngle = aAsimuthAngles[1]; // float fEndAzimuthAngle = aAsimuthAngles[2]; coneValue.Invoke("endFill", NULL, args, 0); infoForNewlyCreatedCone.SetVisible(true); coneValue.SetDisplayInfo(infoForNewlyCreatedCone); } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CMiniMap_RenderThread::AddOrUpdateConeToBlipOnStage // PURPOSE: adds a directional code to the blip on the stage // idea is to mimic what CPedPerception::DrawVisualField() does here // but in Scaleform ///////////////////////////////////////////////////////////////////////////////////// bool CMiniMap_RenderThread::AddOrUpdateConeToBlipOnStage(CBlipCone &blipCone) { if (ms_iMovieId[MINIMAP_MOVIE_FOREGROUND] == -1) return false; GFxValue::DisplayInfo currentDisplayInfoMc; ms_asMapContainerMc.GetDisplayInfo(¤tDisplayInfoMc); float fMapRange = (float)currentDisplayInfoMc.GetXScale(); GFxValue coneValue; bool bConeNeedsToBeDrawn = false; char cRefName[MAX_BLIP_NAME_SIZE]; s32 iActualId = blipCone.GetActualId(); formatf(cRefName, "cone_%d", iActualId, NELEM(cRefName)); bool bHasConeAttached = ms_asBlipLayer3D.GFxValue::HasMember(cRefName); if (!bHasConeAttached) { ms_asBlipLayer3D.CreateEmptyMovieClip(&coneValue, cRefName, iActualId); if (!coneValue.IsUndefined()) { sConesAttachedToBlips dataForNewCone; dataForNewCone.m_iActualIdOfBlip = iActualId; dataForNewCone.m_bConeShouldBeRemovedFromStage = false; ms_ConesAttachedToBlips.PushAndGrow(dataForNewCone); bConeNeedsToBeDrawn = true; uiDebugf2("[PEDCONES] Creating cone for Blip Actual %i", iActualId); } else { uiErrorf("[PEDCONES] Failed to create cone for Blip Actual %i (no empty movie clip)", iActualId); } } else { ms_asBlipLayer3D.GFxValue::GetMember(cRefName, &coneValue); const s32 arraySize = ms_ConesAttachedToBlips.GetCount(); s32 coneLoop = 0; bool bFound = false; while ( (coneLoop < arraySize) && !bFound) { if (ms_ConesAttachedToBlips[coneLoop].m_iActualIdOfBlip == iActualId) { ms_ConesAttachedToBlips[coneLoop].m_bConeShouldBeRemovedFromStage = false; bFound = true; } coneLoop++; } uiAssertf(bFound, "CMiniMap_RenderThread::AddOrUpdateConeToBlipOnStage - didn't find cone with ActualId of %d in the ms_ConesAttachedToBlips array", iActualId); if (blipCone.GetForceRedraw()) { if (uiVerifyf(coneValue.IsDisplayObject(), "CMiniMap_RenderThread::AddOrUpdateConeToBlipOnStage - cone is not a display object")) { coneValue.Invoke("clear"); } bConeNeedsToBeDrawn = true; } } if (!coneValue.IsUndefined()) { if (bConeNeedsToBeDrawn) { DrawConeForBlip(coneValue, blipCone); uiDebugf2("[PEDCONES] Drawing a ped cone for Blip %i with Alpha %i, Focus Range %f, Gaze Angle %f, Pos <<%.2f, %.2f>>" , iActualId, blipCone.GetAlpha(), blipCone.GetFocusRange(), blipCone.GetGazeAngle(), blipCone.GetPosX(), blipCone.GetPosY()); } GFxValue::DisplayInfo info; // ensure the cone is positioned at the coords of the blip but on the 3d layer float fPositionOnMiniMapX = 0.0f; float fPositionOnMiniMapY = 0.0f; GetMiniMapCoordinatesForCone(blipCone.GetPosX(), blipCone.GetPosY(), fMapRange, fPositionOnMiniMapX, fPositionOnMiniMapY); info.SetPosition(fPositionOnMiniMapX, fPositionOnMiniMapY); float fBlipRotation = -(blipCone.GetRotation() * RtoD); // get blip rotation info.SetRotation(fBlipRotation); info.SetAlpha(100.0f * (float)blipCone.GetAlpha()/255.0f); coneValue.SetDisplayInfo(info); return true; } return false; } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CMiniMap_RenderThread::UpdateVisualDataSettings // PURPOSE: Load visual settings tune data. ///////////////////////////////////////////////////////////////////////////////////// void CMiniMap_RenderThread::UpdateVisualDataSettings() { Assertf(g_visualSettings.GetIsLoaded(), "visual settings aren't loaded"); ms_MiniMapAlpha = g_visualSettings.Get("UI.minimap.alpha", 1.0f); } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CMiniMap_RenderThread::RemoveConeFromBlipOnStage // PURPOSE: removes the cone ///////////////////////////////////////////////////////////////////////////////////// bool CMiniMap_RenderThread::RemoveConeFromBlipOnStage(s32 iActualIdOfBlip) { if (ms_iMovieId[MINIMAP_MOVIE_FOREGROUND] == -1) return false; char cRefName[MAX_BLIP_NAME_SIZE+10]; formatf(cRefName, "cone_%d", iActualIdOfBlip, NELEM(cRefName)); bool bHasConeAttached = ms_asBlipLayer3D.GFxValue::HasMember(cRefName); if (bHasConeAttached) // already got higher blip attached, so remove this 1st { GFxValue pCone; ms_asBlipLayer3D.GFxValue::GetMember(cRefName, &pCone); if (pCone.IsDisplayObject()) { pCone.Invoke("removeMovieClip"); return true; } } return false; } void CMiniMap_RenderThread::ResetBlipConeFlags() { const s32 arraySize = ms_ConesAttachedToBlips.GetCount(); for (s32 coneLoop = 0; coneLoop < arraySize; coneLoop++) { ms_ConesAttachedToBlips[coneLoop].m_bConeShouldBeRemovedFromStage = true; } } void CMiniMap_RenderThread::RemoveUnusedBlipConesFromStage() { const s32 sizeOfArray = ms_ConesAttachedToBlips.GetCount(); s32 coneLoop = sizeOfArray - 1; while (coneLoop >= 0) { if (ms_ConesAttachedToBlips[coneLoop].m_bConeShouldBeRemovedFromStage) { uiDebugf2("[PEDCONES] Removing unused cone from Blip Actual %i", ms_ConesAttachedToBlips[coneLoop].m_iActualIdOfBlip); RemoveConeFromBlipOnStage(ms_ConesAttachedToBlips[coneLoop].m_iActualIdOfBlip); ms_ConesAttachedToBlips.Delete(coneLoop); } coneLoop--; } } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CMiniMap_RenderThread::ShouldBlipHeightIndicatorFlash // PURPOSE: decides whether this blip height indicator should flash - bug 948610 ///////////////////////////////////////////////////////////////////////////////////// bool CMiniMap_RenderThread::ShouldBlipHeightIndicatorFlash(CBlipComplex *pBlip) { if (!pBlip) return true; switch(GetBlipObjectNameId(pBlip)) { // always flash health or armour (1665263) case RADAR_TRACE_WEAPON_HEALTH: case RADAR_TRACE_WEAPON_ARMOUR: // exceptional list continues // should PROBABLY be based on if the blip is a 'circle', and if it uses the override AI_BLIP instead of the normal higher/lower case RADAR_TRACE_HOT_PROPERTY: case RADAR_TRACE_KING_OF_THE_CASTLE: case RADAR_TRACE_DEAD_DROP: case RADAR_TRACE_SM_CARGO: case RADAR_TRACE_SM_HANGAR: case RADAR_TRACE_NHP_BAG: case RADAR_TRACE_BAT_CARGO: case RADAR_TRACE_TEMP_1: case RADAR_TRACE_BAT_ASSASSINATE: return true; default: break; } eBLIP_COLOURS blipColour = GetBlipColourValue(pBlip); bool bReturnValue = false; switch (blipColour) { case BLIP_COLOUR_BLUE: case BLIP_COLOUR_GREEN: case BLIP_COLOUR_YELLOW: case BLIP_COLOUR_RED: case BLIP_COLOUR_FRIENDLY: { //uiDisplayf("BLIP '%s' WILL NOT FLASH", CMiniMap::GetBlipNameValue(pBlip)); bReturnValue = false; break; } default: { //uiDisplayf("BLIP '%s' WILL FLASH", CMiniMap::GetBlipNameValue(pBlip)); bReturnValue = true; } } return (bReturnValue); } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CMiniMap_RenderThread::ShouldBlipUseWeaponTypeArrows // PURPOSE: should the blip be overridden with a specific type of up/down arrow ///////////////////////////////////////////////////////////////////////////////////// bool CMiniMap_RenderThread::ShouldBlipUseWeaponTypeArrows(CBlipComplex const *pBlip) { if (pBlip) { BlipLinkage const c_blipId = GetBlipObjectNameId(pBlip); return ((!strncmp(WEAPON_BLIP_NAME, GetBlipObjectName(pBlip), NELEM(WEAPON_BLIP_NAME)-1)) || c_blipId == RADAR_TRACE_TESTOSTERONE || c_blipId == RADAR_TRACE_PICKUP_BEAST || c_blipId == RADAR_TRACE_PICKUP_ZONED || c_blipId == RADAR_TRACE_PICKUP_RANDOM || c_blipId == RADAR_TRACE_PICKUP_SLOW_TIME || c_blipId == RADAR_TRACE_PICKUP_SWAP || c_blipId == RADAR_TRACE_PICKUP_THERMAL || c_blipId == RADAR_TRACE_PICKUP_WEED || c_blipId == RADAR_TRACE_WEAPON_RAILGUN || c_blipId == RADAR_TRACE_BALL || c_blipId == RADAR_TRACE_HIDDEN || c_blipId == RADAR_TRACE_ROCKETS || c_blipId == RADAR_TRACE_BOOST || c_blipId == RADAR_TRACE_PICKUP_GHOST || c_blipId == RADAR_TRACE_PICKUP_ARMOURED || c_blipId == RADAR_TRACE_PICKUP_ACCELERATOR || c_blipId == RADAR_TRACE_PICKUP_SWAP || c_blipId == RADAR_TRACE_PICKUP_DETONATOR || c_blipId == RADAR_TRACE_PICKUP_BOMB || c_blipId == RADAR_TRACE_PICKUP_JUMP || c_blipId == RADAR_TRACE_PICKUP_DEADLINE || c_blipId == RADAR_TRACE_PICKUP_REPAIR || c_blipId == RADAR_TRACE_PICKUP_ROCKET_BOOST || c_blipId == RADAR_TRACE_PICKUP_HOMING_ROCKET || c_blipId == RADAR_TRACE_PICKUP_MACHINEGUN || c_blipId == RADAR_TRACE_PICKUP_PARACHUTE || c_blipId == RADAR_TRACE_PICKUP_TIME_5 || c_blipId == RADAR_TRACE_PICKUP_TIME_10 || c_blipId == RADAR_TRACE_PICKUP_TIME_15 || c_blipId == RADAR_TRACE_PICKUP_TIME_20 || c_blipId == RADAR_TRACE_PICKUP_TIME_30 || c_blipId == RADAR_TRACE_CONTRABAND || c_blipId == RADAR_TRACE_PICKUP_DTB_HEALTH || c_blipId == RADAR_TRACE_PICKUP_DTB_BOMB_INCREASE || c_blipId == RADAR_TRACE_PICKUP_DTB_BOMB_DECREASE || c_blipId == RADAR_TRACE_PICKUP_DTB_BLAST_INCREASE || c_blipId == RADAR_TRACE_PICKUP_DTB_BLAST_DECREASE); } return false; } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CMiniMap_RenderThread::ShouldBlipUseAiTypeArrows // PURPOSE: should the blip be overridden with a specific type of up/down arrow ///////////////////////////////////////////////////////////////////////////////////// bool CMiniMap_RenderThread::ShouldBlipUseAiTypeArrows(CBlipComplex const *pBlip) { if (pBlip) { BlipLinkage const c_blipId = GetBlipObjectNameId(pBlip); return (c_blipId == RADAR_TRACE_CAPTURE_THE_FLAG || c_blipId == RADAR_TRACE_CAPTURE_THE_USAFLAG || c_blipId == RADAR_TRACE_LEVEL_INSIDE || c_blipId == RADAR_TRACE_PLAYER_KING || c_blipId == RADAR_TRACE_BOUNTY_HIT_INSIDE); // fix for 1723248 & 1772239 } return false; } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CMiniMap_RenderThread::AddHigherLowerBlip // PURPOSE: adds the higher/lower blip onto the blip that is on the stage ///////////////////////////////////////////////////////////////////////////////////// bool CMiniMap_RenderThread::AddHigherLowerBlip(GFxValue *pBlipGfx, CBlipComplex *pBlip, s32 iHighLowBlipId) { if (ms_iMovieId[MINIMAP_MOVIE_FOREGROUND] == -1) return false; if (!pBlipGfx) return false; if (!pBlipGfx->IsDisplayObject()) return false; if (!pBlip) return false; GFxValue higherBlip; GFxValue lowerBlip; pBlipGfx->GFxValue::GetMember("higher_blip",&higherBlip); pBlipGfx->GFxValue::GetMember("lower_blip",&lowerBlip); GFxValue* pRecolourThis = nullptr; if (iHighLowBlipId == -1) // lower { RemoveHigherLowerBlip(pBlipGfx, 1); // remove the higher one if (!lowerBlip.IsDisplayObject()) { const char* pHigherLowerName = NULL; if (GetBlipObjectNameId(pBlip) == RADAR_TRACE_BOUNTY_HIT) // new stuff doesnt require these higher/lower blips to be in the enum but means we need to use their names here { pHigherLowerName = "radar_bounty_hit_higher"; } else { s32 iLowerBlipNameId = BLIP_LEVEL+iHighLowBlipId; if (ShouldBlipUseWeaponTypeArrows(pBlip)) { iLowerBlipNameId = BLIP_WEAPON_HIGHER; } else if (ShouldBlipUseAiTypeArrows(pBlip)) { iLowerBlipNameId = BLIP_AI_HIGHER; } else if (!strcmp(HOOP_BLIP_NAME, GetBlipObjectName(pBlip))) { iLowerBlipNameId = BLIP_AI_HIGHER; } pHigherLowerName = CMiniMap_Common::GetBlipName(iLowerBlipNameId); } pBlipGfx->GFxValue::AttachMovie(&lowerBlip, pHigherLowerName, "lower_blip", BLIP_DEPTH_HIGHER_LOWER); pRecolourThis = &lowerBlip; } else if( CMiniMap::IsFlagSet(pBlip,BLIP_FLAG_VALUE_CHANGED_COLOUR) ) { pRecolourThis = &lowerBlip; } } else if (iHighLowBlipId == 1) // higher { RemoveHigherLowerBlip(pBlipGfx, -1); // remove the lower one if (!higherBlip.IsDisplayObject()) { const char* pHigherLowerName = NULL; if (GetBlipObjectNameId(pBlip) == RADAR_TRACE_BOUNTY_HIT) // new stuff doesnt require these higher/lower blips to be in the enum but means we need to use their names here { pHigherLowerName = "radar_bounty_hit_lower"; } else { s32 iHigherBlipNameId = BLIP_LEVEL+iHighLowBlipId; if (ShouldBlipUseWeaponTypeArrows(pBlip)) { iHigherBlipNameId = BLIP_WEAPON_LOWER; } else if (ShouldBlipUseAiTypeArrows(pBlip)) { iHigherBlipNameId = BLIP_AI_LOWER; } else if (!strcmp(HOOP_BLIP_NAME, GetBlipObjectName(pBlip))) { iHigherBlipNameId = BLIP_AI_LOWER; } pHigherLowerName = CMiniMap_Common::GetBlipName(iHigherBlipNameId); } pBlipGfx->GFxValue::AttachMovie(&higherBlip, pHigherLowerName, "higher_blip", BLIP_DEPTH_HIGHER_LOWER); pRecolourThis = &higherBlip; } else if( CMiniMap::IsFlagSet(pBlip,BLIP_FLAG_VALUE_CHANGED_COLOUR) ) { pRecolourThis = &higherBlip; } } else { uiAssertf(0, "CMiniMap_RenderThread: Invalid height value"); return false; } if( pRecolourThis != nullptr ) { // apply colour onto the blip whether we created it this time or we got it from before if (pRecolourThis->IsDisplayObject()) { // since this is based on color, we should check it here too if (!ShouldBlipHeightIndicatorFlash(pBlip)) { pRecolourThis->GotoAndStop(1); // stop on frame 1 as we don't want to flash these (bug 948610) } CRGBA blipColour; if (GetBlipObjectNameId(pBlip) == RADAR_TRACE_WEAPON_HEALTH || GetBlipObjectNameId(pBlip) == RADAR_TRACE_WEAPON_ARMOUR) { // health/armour blip height indicator should be white blipColour = CHudColour::GetRGBA(HUD_COLOUR_WHITE); } else { // other blips should be same colour as the main blip blipColour = CMiniMap_Common::GetColourFromBlipSettings(GetBlipColourValue(pBlip), CMiniMap::IsFlagSet(pBlip,BLIP_FLAG_BRIGHTNESS)); } pRecolourThis->SetColorTransform(blipColour); GFxValue::DisplayInfo dispInfo; s32 iMainBlipAlpha = GetBlipAlphaValue(pBlip); dispInfo.SetAlpha((float)((iMainBlipAlpha / 255.0f) * 100.0f)); pRecolourThis->SetDisplayInfo(dispInfo); } } return true; } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CMiniMap_RenderThread::RemoveHigherLowerBlip // PURPOSE: removes the higher/lower blip ///////////////////////////////////////////////////////////////////////////////////// bool CMiniMap_RenderThread::RemoveHigherLowerBlip(GFxValue *pBlipGfx, int iHigherOrLower /* = 0 */) { if (ms_iMovieId[MINIMAP_MOVIE_FOREGROUND] == -1) return false; if (!pBlipGfx) return false; if (!pBlipGfx->IsDisplayObject()) return false; // if iHigherOrLower is -1, we wanna remove ONLY the lower blip // if it's 1, remove ONLY the higher blip // otherwise, remove any (but for some reason not both...?) GFxValue pHeightBlip; if ( (iHigherOrLower == 0 || iHigherOrLower == 1) && pBlipGfx->GFxValue::GetMember("higher_blip", &pHeightBlip)) { if (pHeightBlip.IsDisplayObject()) { pHeightBlip.Invoke("removeMovieClip"); } // some of the height blips may selectively have hidden the main blip // so we'll unhide it just in case GFxValue mainBlip; if( pBlipGfx->GetMember("main_blip", &mainBlip) ) { GFxValue::DisplayInfo di; di.SetVisible(true); mainBlip.SetDisplayInfo(di); } return true; } if ((iHigherOrLower == 0 || iHigherOrLower == -1) && pBlipGfx->GFxValue::GetMember("lower_blip", &pHeightBlip)) { if (pHeightBlip.IsDisplayObject()) { pHeightBlip.Invoke("removeMovieClip"); } // some of the height blips may selectively have hidden the main blip // so we'll unhide it just in case GFxValue mainBlip; if( pBlipGfx->GetMember("main_blip", &mainBlip) ) { GFxValue::DisplayInfo di; di.SetVisible(true); mainBlip.SetDisplayInfo(di); } return true; } return false; } /*void CMiniMap_RenderThread::SetFlag(CBlipComplex *pBlip, const int flag) { pBlip->iFlags |= flag; } void CMiniMap_RenderThread::UnsetFlag(CBlipComplex *pBlip, const int flag) { if(IsFlagSet(pBlip, flag)) { pBlip->iFlags &= ~flag; } }*/ bool CMiniMap_RenderThread::GetIsInsideInterior() { if (!CSystem::IsThisThreadId(SYS_THREAD_RENDER)) // only on RT { sfAssertf(0, "CMiniMap_RenderThread::GetIsInsideInterior can only be called on the RenderThread!"); return false; } return ms_MiniMapRenderState.bInsideInterior; } s32 CMiniMap_RenderThread::DetermineBlipStageDepth(CBlipComplex* pBlip) { eBLIP_PRIORITY priority = GetBlipPriorityValue(pBlip); if( CMiniMap::IsFlagSet(pBlip, BLIP_FLAG_HOVERED_ON_PAUSEMAP) ) priority = BLIP_PRIORITY_ONTOP_OF_EVERYTHING; // so they will always float to the top, as they DO have the player hovering directly over them, after all return ( s32(priority) * MAX_NUM_BLIPS) + pBlip->m_iActualId; // fix for 1564035 (and possibly some priority issues too) } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CMiniMap_RenderThread::AddBlipToStage // PURPOSE: creates the GFxValue object as the blip is now active on the stage ///////////////////////////////////////////////////////////////////////////////////// bool CMiniMap_RenderThread::AddBlipToStage(CBlipComplex *pBlip) { PF_FUNC(AddBlipToStage); if (ms_iMovieId[MINIMAP_MOVIE_FOREGROUND] == -1) return false; if (!pBlip) return false; s32 iActualId = pBlip->m_iActualId; if (iActualId == -1) { uiAssertf(0, "CMiniMap_RenderThread::AddBlipToStage - iActualId of blip is -1"); return false; } const char* pBlipName = GetBlipObjectName(pBlip); s32 iStageDepth = DetermineBlipStageDepth(pBlip); uiAssertf(pRenderedBlipObject[iActualId] == NULL, "CMiniMap_RenderThread::AddBlipToStage - pRenderedBlipObject in slot %d should be NULL at the beginning of this function", iActualId); // create the actual blip: pRenderedBlipObject[iActualId] = rage_new GFxValue; GFxValue *pGfxValue = pRenderedBlipObject[iActualId]; GFxValue asLayerForBlip; if(GetIsPlacedOn3dMap(pBlip)) { // override area blips' 3D linkage // on RDR we do this for RADIUS blips too, but don't want to rock the boat here if( GetBlipTypeValue(pBlip) == BLIP_TYPE_AREA ) pBlipName = CMiniMap_Common::GetBlipName(BLIP_AREA); if (!ms_asBaseOverlay3D[MINIMAP_LAYER_FOREGROUND].GetMember("asRadiusBlipLayer", &asLayerForBlip)) { uiAssertf(0, "CMiniMap_RenderThread::AddBlipToStage - cannot find 'asRadiusBlipLayer'"); return false; } } else { if( GetBlipTypeValue(pBlip) == BLIP_TYPE_AREA && CMiniMap::IsFlagSet(pBlip, BLIP_FLAG_SHORTRANGE) ) pBlipName = CMiniMap_Common::GetBlipName(RADAR_TRACE_EDGE_POINTER); if (!ms_asRootContainer[MINIMAP_ROOT_LAYER_UNMASKED].GetMember("asBlipLayer2D", &asLayerForBlip)) { uiAssertf(0, "CMiniMap_RenderThread::AddBlipToStage - cannot find 'asBlipLayer2D'"); return false; } } if (!asLayerForBlip.IsUndefined()) { char cRefName[MAX_BLIP_NAME_SIZE+10]; formatf(cRefName, "%s_%d", pBlipName, iActualId, NELEM(cRefName)); if (asLayerForBlip.CreateEmptyMovieClip(pGfxValue, cRefName, iStageDepth)) { GFxValue asTheBlip; if (pGfxValue->AttachMovie(&asTheBlip, pBlipName, "main_blip", BLIP_DEPTH_MAIN_BLIP)) { // re-init various flags: CMiniMap::SetFlag(pBlip, BLIP_FLAG_VALUE_CHANGED_COLOUR); CMiniMap::SetFlag(pBlip, BLIP_FLAG_VALUE_CHANGED_TICK); CMiniMap::SetFlag(pBlip, BLIP_FLAG_VALUE_CHANGED_GOLD_TICK); CMiniMap::SetFlag(pBlip, BLIP_FLAG_VALUE_CHANGED_FOR_SALE); CMiniMap::SetFlag(pBlip, BLIP_FLAG_VALUE_CHANGED_PULSE); CMiniMap::SetFlag(pBlip, BLIP_FLAG_VALUE_CHANGED_OUTLINE_INDICATOR); CMiniMap::SetFlag(pBlip, BLIP_FLAG_VALUE_CHANGED_FRIEND_INDICATOR); CMiniMap::SetFlag(pBlip, BLIP_FLAG_VALUE_CHANGED_CREW_INDICATOR); // re-init the number (if any) CMiniMap::SetFlag(pBlip,BLIP_FLAG_VALUE_SET_NUMBER); // re-init the flash: if (CMiniMap::IsFlagSet(pBlip,BLIP_FLAG_FLASHING)) { CMiniMap::UnsetFlag(pBlip, BLIP_FLAG_FLASHING); // unset so when we setup the flash again it starts it flashing CMiniMap::SetFlag(pBlip, BLIP_FLAG_VALUE_CHANGED_FLASH); } #if __BANK if (ms_MiniMapRenderState.m_bDisplayAllBlipNames) { CMiniMap::SetFlag(pBlip, BLIP_FLAG_VALUE_SET_LABEL); } else { if (CMiniMap::GetBlipDebugNumberValue(pBlip) != -1) { CMiniMap::SetFlag(pBlip, BLIP_FLAG_VALUE_SET_LABEL); } } #endif // __BANK uiDebugf1("CMiniMap_RenderThread: Added blip %d %s with priority %d, pos %0.2f,%0.2f onto stage at depth %d", pBlip->m_iUniqueId, GetBlipObjectName(pBlip), (s32)GetBlipPriorityValue(pBlip), GetBlipPositionValueOnStage(pBlip).x, GetBlipPositionValueOnStage(pBlip).y, iStageDepth); return true; } } } return false; } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CMiniMap_RenderThread::GetBlipNameValue // PURPOSE: gets the text name value to be shown on screen ///////////////////////////////////////////////////////////////////////////////////// const char* CMiniMap_RenderThread::GetBlipNameValue(const CBlipComplex *pBlip) { return pBlip->cLocName.GetStr(); } #if __BANK ///////////////////////////////////////////////////////////////////////////////////// // NAME: CMiniMap_RenderThread::LabelBlipOnStage // PURPOSE: calls invoke on the ActionScript object to colour a blip ///////////////////////////////////////////////////////////////////////////////////// void CMiniMap_RenderThread::LabelBlipOnStage(GFxValue *pBlipGfx, CBlipComplex *pBlip, bool bOnOff) { uiAssertf(pBlip && pBlipGfx, "blip doesnt exist"); if (pBlip && pBlipGfx && pBlipGfx->IsDisplayObject()) { if (GetBlipObjectNameId(pBlip) != BLIP_NORTH) { s8 iBlipNumber = -1; iBlipNumber = CMiniMap::GetBlipDebugNumberValue(pBlip); if (bOnOff) { if (CScaleformMgr::BeginMethod(ms_iMovieId[MINIMAP_MOVIE_FOREGROUND], SF_BASE_CLASS_MINIMAP, "SET_BLIP_LABEL")) { CScaleformMgr::AddParamGfxValue(*pBlipGfx); if (iBlipNumber == -1) { CScaleformMgr::AddParamString(GetBlipNameValue(pBlip)); } else { char cBlipString[5]; formatf(cBlipString, "%d", CMiniMap::GetBlipDebugNumberValue(pBlip), NELEM(cBlipString)); CScaleformMgr::AddParamString(cBlipString); } // Pass Scaleform the correct counter-scale for the text label it is about to create GFxValue::DisplayInfo blipDisplayInfo; pBlipGfx->GetDisplayInfo(&blipDisplayInfo); CScaleformMgr::AddParamFloat(GetBlipScalerValue(pBlip) / blipDisplayInfo.GetXScale() * 100); CScaleformMgr::EndMethod(); } } else { if (CScaleformMgr::BeginMethod(ms_iMovieId[MINIMAP_MOVIE_FOREGROUND], SF_BASE_CLASS_MINIMAP, "REMOVE_BLIP_LABEL")) { CScaleformMgr::AddParamGfxValue(*pBlipGfx); CScaleformMgr::EndMethod(); } } } } else { uiAssertf(0, "CMiniMap_RenderThread: Tried to label a blip on the stage that is no longer is a display object!"); } } #endif // __BANK ///////////////////////////////////////////////////////////////////////////////////// // NAME: CMiniMap_RenderThread::NumberBlipOnStage // PURPOSE: displays a number ontop of a blip on the stage ///////////////////////////////////////////////////////////////////////////////////// void CMiniMap_RenderThread::NumberBlipOnStage(GFxValue *pBlipGfx, CBlipComplex *pBlip) { if( uiVerifyf(pBlip, "Tried to display a number on a blip using a null blip pointer.") && uiVerifyf(pBlipGfx, "Tried to display a number on a blip that doesn't have a main_blip component.") && uiVerifyf(pBlipGfx->IsDisplayObject(), "Tried to display a number on a blip that is no longer is a display object!")) { s8 iNumberToDisplay = CMiniMap::GetBlipNumberValue(pBlip); if (iNumberToDisplay == -1) { if (pBlipGfx->GFxValue::HasMember("blipTextField")) { GFxValue pNumberClip; pBlipGfx->GFxValue::GetMember("blipTextField", &pNumberClip); if (pNumberClip.IsDisplayObject()) { pNumberClip.Invoke("removeMovieClip"); } } return; } if (iNumberToDisplay >= 0) { GFxValue gfxBlipTextFieldMc; pBlipGfx->GFxValue::AttachMovie(&gfxBlipTextFieldMc, "blipTextField", "blipTextField", BLIP_DEPTH_NUMBER); if (uiVerifyf(!gfxBlipTextFieldMc.IsUndefined(), "CMiniMap_RenderThread::NumberBlipOnStage - 'blipTextField' doesnt exist in Actionscript or is undefined")) { GFxValue gfxBlipTextField; if (uiVerifyf(gfxBlipTextFieldMc.GFxValue::GetMember("numberTF", &gfxBlipTextField), "CMiniMap_RenderThread::NumberBlipOnStage - 'numberTF' doesnt exist in Actionscript")) { char cTextFieldString[5]; formatf(cTextFieldString, "%d", iNumberToDisplay, NELEM(cTextFieldString)); gfxBlipTextField.SetText(cTextFieldString); } } } } } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CMiniMap_RenderThread::PulseBlipOnStage // PURPOSE: pulses a blip on the stage ///////////////////////////////////////////////////////////////////////////////////// void CMiniMap_RenderThread::PulseBlipOnStage(GFxValue *pBlipGfx, CBlipComplex *pBlip) { #define __PULSE_FRAME_NUM (2) if (pBlip && pBlipGfx && pBlipGfx->IsDisplayObject()) { //uiDebugf1("CMiniMap_RenderThread: Pulsing blip %d %s", pBlip->m_iUniqueId, GetBlipObjectName(pBlip)); s32 iCurrentFrame = 1; GFxValue currentFrameGfx; if (pBlipGfx->GFxValue::HasMember("_currentframe")) { pBlipGfx->GFxValue::GetMember("_currentframe", ¤tFrameGfx); if (currentFrameGfx.IsNumber()) { iCurrentFrame = (s32)currentFrameGfx.GetNumber(); } } else { uiAssertf(0, "CMiniMap_RenderThread: _currentframe is not a member of blip %s", GetBlipObjectName(pBlip)); } if (iCurrentFrame < __PULSE_FRAME_NUM) { if (!pBlipGfx->GotoAndPlay(__PULSE_FRAME_NUM)) { uiAssertf(0, "CMiniMap_RenderThread: Pulse blip didnt work on blip %s", GetBlipObjectName(pBlip)); } } } else { uiAssertf(0, "CMiniMap_RenderThread: Tried to pulse a blip on the stage that is no longer is a display object!"); } } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CMiniMap_RenderThread::UpdateTickBlipOnStage // PURPOSE: adds or removes a "tick" icon on a blip on the stage ///////////////////////////////////////////////////////////////////////////////////// void CMiniMap_RenderThread::UpdateTickBlipOnStage(GFxValue *pBlipGfx, CBlipComplex *pBlip) { UpdateBlipSecondaryIconOnStage(pBlipGfx, pBlip, BLIP_FLAG_SHOW_TICK, "radar_completed", "tick_blip", BLIP_DEPTH_TICK); } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CMiniMap_RenderThread::UpdateGoldTickBlipOnStage // PURPOSE: adds or removes a golden "tick" icon on a blip on the stage ///////////////////////////////////////////////////////////////////////////////////// void CMiniMap_RenderThread::UpdateGoldTickBlipOnStage(GFxValue *pBlipGfx, CBlipComplex *pBlip) { UpdateBlipSecondaryIconOnStage(pBlipGfx, pBlip, BLIP_FLAG_SHOW_GOLD_TICK, "radar_completed", "tick_blip", BLIP_DEPTH_TICK); } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CMiniMap_RenderThread::UpdateSaleBlipOnStage // PURPOSE: adds or removes a "for sale" icon on a blip on the stage ///////////////////////////////////////////////////////////////////////////////////// void CMiniMap_RenderThread::UpdateForSaleBlipOnStage(GFxValue *pBlipGfx, CBlipComplex *pBlip) { UpdateBlipSecondaryIconOnStage(pBlipGfx, pBlip, BLIP_FLAG_SHOW_FOR_SALE, "radar_for_sale", "sale_blip", BLIP_DEPTH_SALE_ICON); } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CMiniMap_RenderThread::UpdateBlipSecondaryIconOnStage // PURPOSE: adds or removes a secondary icon on a blip on the stage ///////////////////////////////////////////////////////////////////////////////////// void CMiniMap_RenderThread::UpdateBlipSecondaryIconOnStage(GFxValue *pBlipGfx, CBlipComplex *pBlip, eBLIP_PROPERTY_FLAGS iconFlag, const char* symbolName, const char* instanceName, int displayDepth) { if (pBlip && pBlipGfx && pBlipGfx->IsDisplayObject()) { bool bHasIconAttached = pBlipGfx->GFxValue::HasMember(instanceName); if (!CMiniMap::IsFlagSet(pBlip, iconFlag)) { const bool c_checkmarkIcon = displayDepth == BLIP_DEPTH_TICK ; const bool c_shouldRemove = c_checkmarkIcon ? !CMiniMap::IsFlagSet(pBlip, BLIP_FLAG_SHOW_TICK) && !CMiniMap::IsFlagSet(pBlip, BLIP_FLAG_SHOW_GOLD_TICK) : true; // remove the icon if it is there if (bHasIconAttached && c_shouldRemove) // already got higher blip attached, so remove this 1st { GFxValue pIcon; pBlipGfx->GFxValue::GetMember(instanceName, &pIcon); if (pIcon.IsDisplayObject()) { pIcon.Invoke("removeMovieClip"); } } } else { // add a tick blip if its not there already if (!bHasIconAttached) { GFxValue tempValue; if(uiVerifyf(pBlipGfx->GFxValue::AttachMovie(&tempValue, symbolName, instanceName, displayDepth), "Failed to attach secondary blip icon movieclip (symbolName = %s)", symbolName)) { CRGBA blipColour = iconFlag == BLIP_FLAG_SHOW_GOLD_TICK ? CHudColour::GetRGBA(HUD_COLOUR_GOLD) : CHudColour::GetRGBA(HUD_COLOUR_GREEN); tempValue.SetColorTransform(blipColour); GFxValue::DisplayInfo dispInfo; dispInfo.SetAlpha((float)blipColour.GetAlphaf() * 100.0f); tempValue.SetDisplayInfo(dispInfo); } } } } else { uiAssertf(0, "CMiniMap_RenderThread: Tried to update %s on a blip on the stage that is no longer is a display object!", instanceName); } } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CMiniMap_RenderThread::UpdateHeadingIndicatorOnBlipOnStage // PURPOSE: adds or removes and rotates a heading indicator onto the blip ///////////////////////////////////////////////////////////////////////////////////// void CMiniMap_RenderThread::UpdateHeadingIndicatorOnBlipOnStage(GFxValue *pBlipGfx, CBlipComplex *pBlip, s32 iMapRotation) { if (pBlip && pBlipGfx && pBlipGfx->IsDisplayObject()) { GFxValue pAttachmentBlip; bool bHasAttachmentBlip = pBlipGfx->GFxValue::GetMember("direction_blip", &pAttachmentBlip); if (!CMiniMap::IsFlagSet(pBlip,BLIP_FLAG_SHOW_HEADING_INDICATOR)) { // // remove the direction blip if it is there // if (bHasAttachmentBlip) // already got higher blip attached, so remove this 1st { if (pAttachmentBlip.IsDisplayObject()) { pAttachmentBlip.Invoke("removeMovieClip"); } bHasAttachmentBlip = false; } } else { // // add the direction blip if its not there already // if (!bHasAttachmentBlip) { pBlipGfx->GFxValue::AttachMovie(&pAttachmentBlip, "radar_pointer", "direction_blip", BLIP_DEPTH_DIRECTION_INDICATOR); bHasAttachmentBlip = true; } } if (bHasAttachmentBlip) { if (pAttachmentBlip.IsDisplayObject()) { // then update its rotation based on entity heading float fBlipRotation = -CMiniMap::GetBlipDirectionValue(pBlip); fBlipRotation -= iMapRotation; // ensure the value is between 0 and 359 degrees fBlipRotation = CMiniMap_Common::WrapBlipRotation(fBlipRotation); GFxValue::DisplayInfo rotationInfo; rotationInfo.SetRotation(fBlipRotation); // copy the alpha from the main blip: s32 const c_mainBlipAlpha = GetBlipAlphaValue(pBlip); rotationInfo.SetAlpha((float)((c_mainBlipAlpha / 255.0f) * 100.0f)); pAttachmentBlip.SetDisplayInfo(rotationInfo); // apply the rotation to the "direction" only } } } else { uiAssertf(0, "CMiniMap_RenderThread: Tried to update a headingIndicator on a blip on the stage that is no longer is a display object!"); } } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CMiniMap_RenderThread::UpdateOutlineIndicatorOnBlipOnStage // PURPOSE: adds or removes an outline indicator blip ///////////////////////////////////////////////////////////////////////////////////// void CMiniMap_RenderThread::UpdateOutlineIndicatorOnBlipOnStage(GFxValue *pBlipGfx, CBlipComplex *pBlip) { if (pBlip && pBlipGfx && pBlipGfx->IsDisplayObject()) { GFxValue pAttachmentBlip; bool bHasAttachmentBlip = pBlipGfx->GFxValue::GetMember("outline_blip", &pAttachmentBlip); if (!CMiniMap::IsFlagSet(pBlip,BLIP_FLAG_SHOW_OUTLINE_INDICATOR)) { // // remove the outline blip if it is there // if (bHasAttachmentBlip) // already got higher blip attached, so remove this 1st { if (pAttachmentBlip.IsDisplayObject()) { pAttachmentBlip.Invoke("removeMovieClip"); } } } else { // // add the outline blip if its not there already // if (!bHasAttachmentBlip) { const char* pAttachmentBlipName = NULL; if (GetBlipObjectNameId(pBlip) == RADAR_TRACE_CAPTURE_THE_FLAG) { // suitcase outline: pAttachmentBlipName = "radar_capture_the_flag_outline"; } else if (GetBlipObjectNameId(pBlip) == RADAR_TRACE_CAPTURE_THE_USAFLAG) { // usa flag outline: pAttachmentBlipName = "radar_capture_the_useflag_outline"; } else { // standard circle outline: pAttachmentBlipName = "RADAR_MP_FRIEND"; // not "really" friend anymore ;-) confusing I know, last minute requests etc etc } pBlipGfx->GFxValue::AttachMovie(&pAttachmentBlip, pAttachmentBlipName, "outline_blip", BLIP_DEPTH_OUTLINE_INDICATOR); } // apply colour onto the blip whether we created it this time or we got it from before if (pAttachmentBlip.IsDisplayObject()) { CRGBA blipColour = GetBlipSecondaryColourValue(pBlip); pAttachmentBlip.SetColorTransform(blipColour); GFxValue::DisplayInfo dispInfo; s32 iMainBlipAlpha = GetBlipAlphaValue(pBlip); // fix for 1584520 - use alpha of the main blip (as the friend indicator needs to fade out when they fade the blip) dispInfo.SetAlpha((float)((iMainBlipAlpha / 255.0f) * 100.0f)); pAttachmentBlip.SetDisplayInfo(dispInfo); } } } else { uiAssertf(0, "CMiniMap_RenderThread: Tried to update an outline blip on a blip on the stage that is no longer is a display object!"); } } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CMiniMap_RenderThread::UpdateFriendIndicatorOnBlipOnStage // PURPOSE: adds or removes an outline indicator blip ///////////////////////////////////////////////////////////////////////////////////// void CMiniMap_RenderThread::UpdateFriendIndicatorOnBlipOnStage(GFxValue *pBlipGfx, CBlipComplex *pBlip) { if (pBlip && pBlipGfx && pBlipGfx->IsDisplayObject()) { GFxValue pAttachmentBlip; bool bHasAttachmentBlip = pBlipGfx->GFxValue::GetMember("friend_blip", &pAttachmentBlip); if (!CMiniMap::IsFlagSet(pBlip,BLIP_FLAG_SHOW_FRIEND_INDICATOR)) { // // remove the direction blip if it is there // if (bHasAttachmentBlip) // already got higher blip attached, so remove this 1st { if (pAttachmentBlip.IsDisplayObject()) { pAttachmentBlip.Invoke("removeMovieClip"); } } } else { // // add the direction blip if its not there already // if (!bHasAttachmentBlip) { pBlipGfx->GFxValue::AttachMovie(&pAttachmentBlip, "radar_mp_friendlies", "friend_blip", BLIP_DEPTH_FRIEND_INDICATOR); } // apply colour onto the blip whether we created it this time or we got it from before if (pAttachmentBlip.IsDisplayObject()) { CRGBA blipColour = CHudColour::GetRGBA(HUD_COLOUR_FRIENDLY); pAttachmentBlip.SetColorTransform(blipColour); GFxValue::DisplayInfo dispInfo; s32 iMainBlipAlpha = GetBlipAlphaValue(pBlip); // fix for 1584520 - use alpha of the main blip (as the friend indicator needs to fade out when they fade the blip) dispInfo.SetAlpha((float)((iMainBlipAlpha / 255.0f) * 100.0f)); pAttachmentBlip.SetDisplayInfo(dispInfo); } } } else { uiAssertf(0, "CMiniMap_RenderThread: Tried to update a friend indicator on a blip on the stage that is no longer is a display object!"); } } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CMiniMap_RenderThread::UpdateCrewIndicatorOnBlipOnStage // PURPOSE: adds or removes an outline indicator blip ///////////////////////////////////////////////////////////////////////////////////// void CMiniMap_RenderThread::UpdateCrewIndicatorOnBlipOnStage(GFxValue *pBlipGfx, CBlipComplex *pBlip) { if (pBlip && pBlipGfx && pBlipGfx->IsDisplayObject()) { GFxValue pAttachmentBlip; bool bHasAttachmentBlip = pBlipGfx->GFxValue::GetMember("crew_blip", &pAttachmentBlip); if (!CMiniMap::IsFlagSet(pBlip,BLIP_FLAG_SHOW_CREW_INDICATOR)) { // // remove the direction blip if it is there // if (bHasAttachmentBlip) // already got higher blip attached, so remove this 1st { if (pAttachmentBlip.IsDisplayObject()) { pAttachmentBlip.Invoke("removeMovieClip"); } } } else { // // add the direction blip if its not there already // if (!bHasAttachmentBlip) { pBlipGfx->GFxValue::AttachMovie(&pAttachmentBlip, "radar_mp_crew", "crew_blip", BLIP_DEPTH_CREW_INDICATOR); } // apply colour onto the blip whether we created it this time or we got it from before if (pAttachmentBlip.IsDisplayObject()) { CRGBA blipColour = GetBlipSecondaryColourValue(pBlip); pAttachmentBlip.SetColorTransform(blipColour); GFxValue::DisplayInfo dispInfo; s32 iMainBlipAlpha = GetBlipAlphaValue(pBlip); // fix for 1584520 - use alpha of the main blip (as the friend indicator needs to fade out when they fade the blip) dispInfo.SetAlpha((float)((iMainBlipAlpha / 255.0f) * 100.0f)); pAttachmentBlip.SetDisplayInfo(dispInfo); } } } else { uiAssertf(0, "CMiniMap_RenderThread: Tried to update a crew indicator on a blip on the stage that is no longer is a display object!"); } } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CMiniMap_RenderThread::FadeOutDistantBlipOnStage // PURPOSE: fades out a blip as it gets further out into the distance ///////////////////////////////////////////////////////////////////////////////////// void CMiniMap_RenderThread::FadeOutDistantBlipOnStage(GFxValue *pBlipGfx, s32 iDisplayAlpha) { if (ms_iMovieId[MINIMAP_MOVIE_FOREGROUND] == -1) return; if (pBlipGfx && pBlipGfx->IsDisplayObject()) { GFxValue::DisplayInfo currentAlphaDisplayInfo; pBlipGfx->GetDisplayInfo(¤tAlphaDisplayInfo); if (currentAlphaDisplayInfo.GetAlpha() != iDisplayAlpha) { currentAlphaDisplayInfo.SetAlpha(iDisplayAlpha); pBlipGfx->SetDisplayInfo(currentAlphaDisplayInfo); } } else { uiAssertf(0, "CMiniMap_RenderThread: Tried to set alpha on the stage that is no longer is a display object!"); } } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CMiniMap_RenderThread::ColourBlipOnStage // PURPOSE: calls invoke on the ActionScript object to colour a blip ///////////////////////////////////////////////////////////////////////////////////// void CMiniMap_RenderThread::ColourBlipOnStage(GFxValue *pBlipGfx, CBlipComplex *pBlip) { if (ms_iMovieId[MINIMAP_MOVIE_FOREGROUND] == -1) return; if (pBlip && pBlipGfx && pBlipGfx->IsDisplayObject()) { GFxValue pMainBlip; if (pBlipGfx->GFxValue::GetMember("main_blip", &pMainBlip)) { if (pMainBlip.IsDisplayObject()) { CRGBA blipColour; if (GetBlipColourValue(pBlip) != BLIP_COLOUR_USE_COLOUR32) { blipColour = CMiniMap_Common::GetColourFromBlipSettings(GetBlipColourValue(pBlip), CMiniMap::IsFlagSet(pBlip,BLIP_FLAG_BRIGHTNESS)); if (GetBlipAlphaValue(pBlip) != 255) { blipColour.SetAlpha(GetBlipAlphaValue(pBlip)); // use individual alpha settings } } else { blipColour = GetBlipSecondaryColourValue(pBlip); // use actual RGBA value } // with the alpha, we set it on the blip container movieclip so it sets the alpha for all its children aswell GFxValue::DisplayInfo currentDisplayInfo; float fAlpha = blipColour.GetAlphaf() * 100; Assertf(CMiniMap::IsFlagSet(pBlip,BLIP_FLAG_UPDATE_ALPHA_ONLY) || CMiniMap::IsFlagSet(pBlip,BLIP_FLAG_VALUE_CHANGED_COLOUR), "CMiniMap_RenderThread::ColourBlipOnStage - expected either the CHANGED_COLOUR or the UPDATE_ALPHA_ONLY flag to be set"); currentDisplayInfo.SetAlpha(fAlpha); pBlipGfx->SetDisplayInfo(currentDisplayInfo); if (CMiniMap::IsFlagSet(pBlip,BLIP_FLAG_VALUE_CHANGED_COLOUR)) { // we set the colour on the "main_blip" only - as we only want to colour the blip iself (and any children) and not its siblings pMainBlip.SetColorTransform(blipColour); } if (CMiniMap::IsFlagSet(pBlip,BLIP_FLAG_VALUE_CHANGED_COLOUR) || CMiniMap::IsFlagSet(pBlip,BLIP_FLAG_UPDATE_ALPHA_ONLY)) { GFxValue::DisplayInfo dispInfo; dispInfo.SetAlpha((float)blipColour.GetAlphaf() * 100.0f); pMainBlip.SetDisplayInfo(dispInfo); } // need to copy the alpha value of the blip onto the higher/lower blip bool bHasHigherBlipAttached = pBlipGfx->GFxValue::HasMember("higher_blip"); bool bHasLowerBlipAttached = pBlipGfx->GFxValue::HasMember("lower_blip"); GFxValue pHeightBlip; if (bHasHigherBlipAttached) { pBlipGfx->GFxValue::GetMember("higher_blip", &pHeightBlip); } else if (bHasLowerBlipAttached) { pBlipGfx->GFxValue::GetMember("lower_blip", &pHeightBlip); } if (pHeightBlip.IsDisplayObject()) { // copy the alpha from the main blip: GFxValue::DisplayInfo heightBlipDisplayInfo; heightBlipDisplayInfo.SetAlpha(fAlpha); pHeightBlip.SetDisplayInfo(heightBlipDisplayInfo); } } } } else { uiAssertf(0, "CMiniMap_RenderThread: Tried to colour a blip on the stage that is no longer is a display object!"); } } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CMiniMap_RenderThread::FlashBlipOnStage // PURPOSE: calls invoke on the ActionScript object to flash/stop flashing a blip ///////////////////////////////////////////////////////////////////////////////////// bool CMiniMap_RenderThread::FlashBlipOnStage(GFxValue *pBlipGfx, CBlipComplex *pBlip) { if (pBlip && pBlipGfx && pBlipGfx->IsDisplayObject()) { if (!CMiniMap::IsFlagSet(pBlip, BLIP_FLAG_FLASHING)) { float fTimeInSeconds = ( (float)GetBlipFlashInterval(pBlip) / 1000.0f ); // convert ms into seconds to pass to ActionScript if (CScaleformMgr::BeginMethod(ms_iMovieId[MINIMAP_MOVIE_FOREGROUND], SF_BASE_CLASS_MINIMAP, "START_BLIP_FLASHING")) { CScaleformMgr::AddParamGfxValue(*pBlipGfx); CScaleformMgr::AddParamFloat(fTimeInSeconds); CScaleformMgr::EndMethod(); } } else { if (CScaleformMgr::BeginMethod(ms_iMovieId[MINIMAP_MOVIE_FOREGROUND], SF_BASE_CLASS_MINIMAP, "STOP_BLIP_FLASHING")) { CScaleformMgr::AddParamGfxValue(*pBlipGfx); CScaleformMgr::EndMethod(); } } return true; } else { uiAssertf(0, "CMiniMap_RenderThread: Tried to flash a blip on the stage that is no longer is a display object!"); } return false; } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CMiniMap_RenderThread::GetBlipGfxValue // PURPOSE: returns the gfxvalue used for this slot (in the render) ///////////////////////////////////////////////////////////////////////////////////// GFxValue* CMiniMap_RenderThread::GetBlipGfxValue(const CBlipComplex *pBlip) { if (pBlip) { if (pBlip->m_iActualId != -1) { uiAssertf((pBlip->m_iActualId >= 0) && (pBlip->m_iActualId < MAX_NUM_BLIPS), "CMiniMap_RenderThread::GetBlipGfxValue()...Accessing bad blip!"); return pRenderedBlipObject[pBlip->m_iActualId]; } } return NULL; } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CMiniMap_RenderThread::SetBlipGfxValue // PURPOSE: sets the gfx value of the blip ///////////////////////////////////////////////////////////////////////////////////// void CMiniMap_RenderThread::SetBlipGfxValue(const CBlipComplex *pBlip, GFxValue *pParam) { if (pBlip) { if (pBlip->m_iActualId != -1) { pRenderedBlipObject[pBlip->m_iActualId] = pParam; } } } bool CMiniMap_RenderThread::GetIsPlacedOn3dMap(const CBlipComplex* pBlip) { if (pBlip && pBlip->m_iActualId != -1) { uiAssertf((pBlip->m_iActualId >= 0) && (pBlip->m_iActualId < MAX_NUM_BLIPS), "CMiniMap_RenderThread::GetIsPlacedOn3dMap()...Accessing bad blip!"); return bBlipIsOn3dLayer.IsSet(pBlip->m_iActualId); } return false; } void CMiniMap_RenderThread::SetIsPlacedOn3dMap(const CBlipComplex* pBlip, bool bOnMap) { if (pBlip && pBlip->m_iActualId != -1) { bBlipIsOn3dLayer.Set(pBlip->m_iActualId, bOnMap); } } #define BLIP_SIZE_MINIMAP_GOLF_COURSE (45.0f) #define BLIP_SIZE_MINIMAP (100.0f) #define BLIP_SIZE_PAUSEMENU_MAP (24.0f) #define BLIP_SIZE_PAUSEMENU_MAP_HOVERED (30.0f) #define BLIP_SIZE_BIGMAP (45.0f) #define BLIP_SIZE_GALLERYMAP (45.0f) float CMiniMap_RenderThread::GetBlipScalerValue(const CBlipComplex* pBlip, bool bCareAboutType /* = true */) { float fBlipScaler = BLIP_SIZE_MINIMAP; if ( bCareAboutType && (GetBlipTypeValue(pBlip) == BLIP_TYPE_RADIUS || GetBlipTypeValue(pBlip) == BLIP_TYPE_AREA)) { fBlipScaler = 2.0f; } else if (ms_MiniMapRenderState.m_bIsInPauseMap) { fBlipScaler = BLIP_SIZE_PAUSEMENU_MAP; if( CMiniMap::IsFlagSet(pBlip, BLIP_FLAG_HOVERED_ON_PAUSEMAP) ) fBlipScaler = BLIP_SIZE_PAUSEMENU_MAP_HOVERED; } else if (ms_MiniMapRenderState.m_bIsInBigMap) { fBlipScaler = BLIP_SIZE_BIGMAP; } else if (ms_MiniMapRenderState.m_bIsInCustomMap) { fBlipScaler = BLIP_SIZE_GALLERYMAP; } else if (ms_MiniMapRenderState.m_CurrentGolfMap != GOLF_COURSE_OFF) { fBlipScaler = BLIP_SIZE_MINIMAP_GOLF_COURSE; } return fBlipScaler; } bool CMiniMap_RenderThread::DoesRenderedBlipExist(s32 BlipIndex) { if (uiVerifyf((BlipIndex >= 0) && (BlipIndex < MAX_NUM_BLIPS), "CMiniMap_RenderThread::DoesRenderedBlipExist - blip index is out of range")) { return (pRenderedBlipObject[BlipIndex] != NULL); } return false; } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CMiniMap_RenderThread::RemoveBlipFromStage // PURPOSE: removes the GFxValue object if the blip leaves the stage ///////////////////////////////////////////////////////////////////////////////////// bool CMiniMap_RenderThread::RemoveBlipFromStage(CBlipComplex *pBlip, bool bFromUpdateThreadInShutdownSession) { PF_FUNC(RemoveBlipFromStage); if (bFromUpdateThreadInShutdownSession) { if (CSystem::IsThisThreadId(SYS_THREAD_RENDER)) // only on UT { sfAssertf(0, "CMiniMap_RenderThread::RemoveBlipFromStage has been called with the special-case flag bFromUpdateThreadInShutdownSession so it's expected to be called on the UpdateThread"); return false; } } else { if (!CSystem::IsThisThreadId(SYS_THREAD_RENDER)) // only on RT { sfAssertf(0, "CMiniMap_RenderThread::RemoveBlipFromStage can only be called on the RenderThread!"); return false; } } if (ms_iMovieId[MINIMAP_MOVIE_FOREGROUND] == -1) return false; if (!pBlip) return false; uiDebugf1("CMiniMap_RenderThread: Removed blip %d %s from stage", pBlip->m_iUniqueId, GetBlipObjectName(pBlip)); GFxValue *pGfxValue = GetBlipGfxValue(pBlip); if (pGfxValue) { if (pGfxValue->IsDisplayObject()) { // // at this point, we need to ensure we call some "stop" methods on actionscript so it call cleans up nicely in the tweener: // if (CMiniMap::IsFlagSet(pBlip, BLIP_FLAG_FLASHING)) { if (CScaleformMgr::BeginMethod(ms_iMovieId[MINIMAP_MOVIE_FOREGROUND], SF_BASE_CLASS_MINIMAP, "STOP_BLIP_FLASHING")) { CScaleformMgr::AddParamGfxValue(*pGfxValue); CScaleformMgr::EndMethod(bFromUpdateThreadInShutdownSession); } } if(CMiniMap::IsFlagSet(pBlip, BLIP_FLAG_SHOW_HEIGHT)) { RemoveHigherLowerBlip(pGfxValue, 0); } // // finally, remove the blip: // pGfxValue->Invoke("removeMovieClip"); pGfxValue->SetUndefined(); delete (pGfxValue); CScaleformMgr::ForceCollectGarbage(ms_iMovieId[MINIMAP_MOVIE_FOREGROUND]); // perform garbage collection once the blip has been removed } else { uiAssertf(0, "MiniMap: Tried to remove a blip from the stage that is no longer is a display object!"); } SetBlipGfxValue(pBlip, NULL); } return true; } void CMiniMap_RenderThread::RenderToFoW(CBlipComplex * FOG_OF_WAR_ONLY(pBlip)) { #if ENABLE_FOG_OF_WAR Vector2 coords = WorldToFowCoord(pBlip->vPosition.x, pBlip->vPosition.y); float fowWidth = (float)CMiniMap_Common::GetFogOfWarRT()->GetWidth(); float fowHeight = (float)CMiniMap_Common::GetFogOfWarRT()->GetHeight(); const float aspectRatio = CMiniMap::AreFowCustomWorldExtentsEnabled()? (CMiniMap::GetFowCustomWorldH() / CMiniMap::GetFowCustomWorldW()) : (CMiniMap::sm_Tunables.FogOfWar.fWorldH / CMiniMap::sm_Tunables.FogOfWar.fWorldW); float xDelta = (fowBlipColorSizeX/fowWidth)*aspectRatio; float yDelta = (fowBlipColorSizeY/fowHeight); grcBindTexture(CShaderLib::LookupTexture("FoW")); for(int i=0;i