Files
GTASource/game/frontend/MiniMapRenderThread.cpp
expvintl 419f2e4752 init
2025-02-23 17:40:52 +08:00

8605 lines
277 KiB
C++

#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<atArray<debugVolume>> 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<sConesAttachedToBlips> 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<GMatrix3D> CMiniMap_RenderThread::ms_LocalToScreen;
GFxValue CMiniMap_RenderThread::asBitmap;
GFxValue *CMiniMap_RenderThread::pRenderedBlipObject[MAX_NUM_BLIPS];
atFixedBitSet<MAX_NUM_BLIPS> 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(&currentDisplayInfoMc);
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", &currentFrameGfx);
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(&currentAlphaDisplayInfo);
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<bleepCount;i++)
{
grcDrawSingleQuadf(coords.x-xDelta,coords.y-yDelta,coords.x+xDelta,coords.y+yDelta, 0.0f, 0.0f , 0.0f , 1.0f , 1.0f , fowBleepColor);
}
#endif // ENABLE_FOG_OF_WAR
}
#define SCALEFORM_SCALE_VALUE (100.0f) // flash uses 100 as a base scale value instead of the sane 1.0.
#define ADJUST_SCALEFORM_SCALAR(scalar) (SCALEFORM_SCALE_VALUE/scalar) // a scalar of 50 means 2x 'zoom'
#define SCALEFORM_SCALE_TO_PERCENT(scalar) (scalar/SCALEFORM_SCALE_VALUE) // a scalar of 50 means 50% (.5)
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap_RenderThread::UpdateIndividualBlip
// PURPOSE: updates an individual blip
/////////////////////////////////////////////////////////////////////////////////////
bool CMiniMap_RenderThread::UpdateIndividualBlip(CBlipComplex *pBlip, s32 iMapRotation, bool bRangeCheckOnly)
{
PF_FUNC(UpdateIndividualBlip);
if (!CSystem::IsThisThreadId(SYS_THREAD_RENDER)) // only on RT
{
sfAssertf(0, "CMiniMap_RenderThread::UpdateIndividualBlip can only be called on the RenderThread!");
return false;
}
if (ms_iMovieId[MINIMAP_MOVIE_FOREGROUND] == -1)
return false;
if (!pBlip)
return false;
iMapRotation = -ms_MiniMapRenderState.m_iRotation;
Vector2 vMapCentrePosition(ms_MiniMapRenderState.m_vCentrePosition.x, ms_MiniMapRenderState.m_vCentrePosition.y);
CMiniMap::BlipFlagBitset flags(false);
CMiniMap::GetAllFlags(flags, pBlip);
if (!bRangeCheckOnly)
{
if (flags.IsSet(BLIP_FLAG_VALUE_REMOVE_FROM_STAGE))
{
RemoveBlipFromStage(pBlip, false);
return false;
}
if (flags.IsSet(BLIP_FLAG_VALUE_REINIT_STAGE))
{
ReInitBlipOnStage(pBlip);
CMiniMap::GetAllFlags(flags, pBlip); // Flags may have changed, get new ones
}
}
//
// update this individual blip
//
Vec3f vBlipPos(RCC_VEC3F(GetBlipPositionConstRef(pBlip))); // Stay out of the vector registers
Vector2 vNewBlipPos = Vector2(vBlipPos.GetX(), -vBlipPos.GetY());
const eBLIP_DISPLAY_TYPE c_blipDisplayType = GetBlipDisplayValue(pBlip);
bool bOnEdgeOfRadar = false;
bool bOnRadar = true;
bool bOn3dMap = GetBlipTypeValue(pBlip) == BLIP_TYPE_AREA || GetBlipTypeValue(pBlip) == BLIP_TYPE_RADIUS;
//
// depending on the display value of this blip, we need to decide whether to have this displayed on
// the current map (either in the pausemap or on the ingame minimap)
//
// no POI when in golf (bug 1319054) or creator (1702753)
if (GetBlipObjectNameId(pBlip) == RADAR_TRACE_POI)
{
if ( (ms_MiniMapRenderState.m_CurrentGolfMap != GOLF_COURSE_OFF) ||
(ms_MiniMapRenderState.bInCreator) )
{
bOnRadar = false;
}
}
// fix for 1690613 - no mission creator blips should be shown when script are hiding the exterior map
// except sometimes
if ((c_blipDisplayType != BLIP_DISPLAY_BOTH) &&
(flags.IsSet(BLIP_FLAG_MISSION_CREATOR)) &&
((ms_MiniMapRenderState.m_bIsInPauseMap && ms_MiniMapRenderState.bInsideInterior) ||
((!ms_MiniMapRenderState.m_bShowMainMap) && (!ms_MiniMapRenderState.m_bShowPrologueMap) && (!ms_MiniMapRenderState.m_bShowIslandMap))))
{
bOnRadar = false;
}
// probably dont want to do this now this has been changed to high and low detail - but design is sketchy, leaving out to begin with
/*if (bOnRadar && ((!CMiniMap::GetBlipVisibilityHighDetail()) && (flags.IsSet(BLIP_FLAG_HIGH_DETAIL))) ) // 1190959 wants legend blips hidden on minimap too
{
bOnRadar = false;
}*/
// if minimap is not being rendered, then lets not add any blips to the stage, rather lets remove them (optimisation to help fix 1708020)
if ( (!ms_MiniMapRenderState.m_bShouldRenderMiniMap) && // minimap isnt getting rendered
(!ms_MiniMapRenderState.m_bIsInPauseMap) && // and we are not in the pausemap
(!ms_MiniMapRenderState.m_bIsInCustomMap)) // and we are not in a custom map
{
bOnRadar = false;
}
if (bOnRadar)
{
//
// if in-game minimap:
//
if (!ms_MiniMapRenderState.m_bIsInPauseMap && !ms_MiniMapRenderState.m_bIsInCustomMap)
{
if (ms_MiniMapRenderState.m_bIsInCustomMap)
{
if (c_blipDisplayType != BLIP_DISPLAY_CUSTOM_MAP_ONLY)
{
bOnRadar = false;
}
}
else
{
if (c_blipDisplayType == BLIP_DISPLAY_PAUSEMAP ||
c_blipDisplayType == BLIP_DISPLAY_MARKERONLY ||
c_blipDisplayType == BLIP_DISPLAY_NEITHER)
{
bOnRadar = false;
}
if (ms_MiniMapRenderState.m_bIsInBigMap)
{
if (c_blipDisplayType == BLIP_DISPLAY_MINIMAP)
{
bOnRadar = false;
}
if (!ms_MiniMapRenderState.m_bBigMapFullZoom)
{
if (c_blipDisplayType == BLIP_DISPLAY_BIGMAP_FULL_ONLY)
{
bOnRadar = false;
}
}
}
else
{
if (c_blipDisplayType == BLIP_DISPLAY_BIGMAP_FULL_ONLY)
{
bOnRadar = false;
}
}
}
}
else if (ms_MiniMapRenderState.m_bIsInCustomMap)
{
if (c_blipDisplayType != BLIP_DISPLAY_CUSTOM_MAP_ONLY && c_blipDisplayType != BLIP_DISPLAY_BLIPONLY)
bOnRadar = false;
else
bOnRadar = true;
}
else
//
// frontend map:
//
{
if (((CMiniMap::GetBlipVisibilityHighDetail()) && (!flags.IsSet(BLIP_FLAG_HIGH_DETAIL))) ||
c_blipDisplayType == BLIP_DISPLAY_MINIMAP ||
c_blipDisplayType == BLIP_DISPLAY_MINIMAP_OR_BIGMAP ||
c_blipDisplayType == BLIP_DISPLAY_MARKERONLY ||
c_blipDisplayType == BLIP_DISPLAY_BIGMAP_FULL_ONLY ||
c_blipDisplayType == BLIP_DISPLAY_NEITHER)
{
bOnRadar = false;
}
if ( (bOnRadar && ms_MiniMapRenderState.bInsideInterior) && (!ms_MiniMapRenderState.m_Interior.vBoundMin.IsZero()) && (!ms_MiniMapRenderState.m_Interior.vBoundMax.IsZero()) )
{
if (GetBlipTypeValue(pBlip) == BLIP_TYPE_COORDS)
{
if (vBlipPos.GetX() < ms_MiniMapRenderState.m_Interior.vBoundMin.x ||
vBlipPos.GetX() > ms_MiniMapRenderState.m_Interior.vBoundMax.x ||
vBlipPos.GetY() < ms_MiniMapRenderState.m_Interior.vBoundMin.y ||
vBlipPos.GetY() > ms_MiniMapRenderState.m_Interior.vBoundMax.y)
{
bOnRadar = false;
}
}
}
}
}
Vector2 vNewBlipPosInMiniMap(0,0);
bool bBlipWithin15mOfPlayer = true;
s32 iDisplayAlpha = 100;
int iQuadrant = -1; // used solely for edgey blips
if (bOnRadar)
{
/* if (asBlipTestObject.IsDisplayObject())
{
GFxValue::DisplayInfo displayInfo;
if ( (!ms_MiniMapRenderState.m_bIsInPauseMap) && (pLocalPlayer && (!pLocalPlayer->GetVehiclePedInside())) && (GetRange() < MAP_BLIP_ROUND_THRESHOLD) )
{
displayInfo.SetPosition(floor(vNewBlipPos.x+0.5f), floor(vNewBlipPos.y+0.5f));
}
else
{
displayInfo.SetPosition(vNewBlipPos.x, vNewBlipPos.y);
}
asBlipTestObject.SetDisplayInfo(displayInfo);
}*/
//
// check the position of the blip in "2D space"
//
GPointF blipPoint, screenPoint;
//
// because of the way scaleform returns the screen position of the 3D blip, we need to limit the range so we only ever check coords
// that are close to the edge of the minimap ring. We first work out the height of the blip onscreen in 3D space not relative to the
// current rotation of the map, then from that we scale the distance we check for. This means the range that is checked against is
// further away if you can see further away into the distance, but the range is less if the blip is at the bottom of the minimap and
// there isnt a lot of map visible.
//
bool bAdjustPosForDistance = true;
if( GetBlipTypeValue(pBlip) == BLIP_TYPE_AREA )
{
// Extended area checks necessary for Square blips (and radius blips, if we did this [which we don't for V])
// Only take into account distance adjustments if the area is outside the bounds of the map
// If we run these calculations for area blips within map bounds, the area position glitches about
// when the center extends outside of the map
bAdjustPosForDistance = IsAreaBlipOutsideMapBounds(*pBlip);
}
if ( (!ms_MiniMapRenderState.m_bIsInPauseMap && !ms_MiniMapRenderState.m_bIsInCustomMap) && (ms_MiniMapRenderState.m_CurrentGolfMap == GOLF_COURSE_OFF) &&
bAdjustPosForDistance)
{
if (GetBlipTypeValue(pBlip) != BLIP_TYPE_RADIUS /*&& GetBlipTypeValue(pBlip) != BLIP_TYPE_AREA*/)
{
Vector2 vTestBlipForDistance(Vector2(vBlipPos.GetX(), vBlipPos.GetY())-vMapCentrePosition);
float fMaxDistance = 0.0f;
// do we need to re-adjust the range based on a 3D view....?
if (ms_fBlipMapAngle != 0.0f) // if we have an angle
{
// work out the angle of the blip relative to the centre blip:
float fAngle = atan2(vMapCentrePosition.y - vBlipPos.GetY(), vMapCentrePosition.x - vBlipPos.GetX());
if (fAngle < 0)
fAngle += (2*PI);
fAngle = ((fAngle * RtoD) - 270.0f) + (float)iMapRotation;
// ensure its between 0 to 360 degrees
fAngle = rage::Wrap(fAngle, 0.0f, 360.0f);
// work out the max distance we want to check for based on how much range is visible (may also want to add 3D angle in here too)
fMaxDistance = MINIMAP_DISTANCE_SCALER_3D * (MIN_MINIMAP_RANGE/ms_fBlipMapRange); // more zoomed out you are, the less we need to restrict the check
if (fAngle > 180.0f)
fAngle = 180.0f-(fAngle-180.0f); // get a 0 to 180 degree range across the top to bottom of the minimap, regardless of which side of the minimap the blip is on
float fHeightScaler = Max(0.15f, 1.0f-(fAngle / 180.0f)); // convert that to 0-1 space
if (fHeightScaler > 0.5f) // if the blip is high up on the minimap then its in the area that is more visible, so gradually give it more range
{
fHeightScaler *= (1.0f+((fHeightScaler-0.5f)*MINIMAP_HEIGHT_SCALER));
}
fMaxDistance *= fHeightScaler; // apply the scaler to the max distance
}
else // ... or a 2D view?
{
fMaxDistance = MINIMAP_DISTANCE_SCALER_2D * (MIN_MINIMAP_RANGE/ms_fBlipMapRange);
}
float fDistance = vTestBlipForDistance.Mag(); // get the distance
if (fDistance > 15.0f) // check to see if its 15m
{
bBlipWithin15mOfPlayer = false;
}
if (fDistance > fMaxDistance)
{
float fScale = fMaxDistance / fDistance;
vTestBlipForDistance.x *= fScale;
vTestBlipForDistance.y *= fScale;
vNewBlipPos = Vector2(vTestBlipForDistance.x + vMapCentrePosition.x, -(vTestBlipForDistance.y + vMapCentrePosition.y));
}
}
}
blipPoint.x = vNewBlipPos.x;
blipPoint.y = vNewBlipPos.y;
Vector2 vPosInMiniMap(0,0);
ms_LocalToScreen.GetRenderBuf().Transform(&screenPoint, blipPoint, true);
#if SUPPORT_MULTI_MONITOR
// ms_LocalToScreen is built from the scaleform viewport, which is already adjusted for multihead
// other values here are not aware yet, hence we transform it back into the original space
const GridMonitor &mon = GRCDEVICE.GetMonitorConfig().getLandscapeMonitor();
screenPoint.x = SCREEN_WIDTH * (screenPoint.x - mon.uLeft) / mon.getWidth();
screenPoint.y = SCREEN_HEIGHT * (screenPoint.y - mon.uTop) / mon.getHeight();
#endif //SUPPORT_MULTI_MONITOR
#if 0 // Sanity check the new transform code
{
GFxMovieView* pView = CScaleformMgr::GetMovieView(ms_iMovieId);
GPointF oldScreenPoint;
if (pView && pView->TranslateLocalToScreen(BLIP_LAYER_PATH, blipPoint, &oldScreenPoint))
{
Assertf(oldScreenPoint.DistanceSquared(screenPoint) < 0.001f, "FindLocalToScreen didn't work!");
}
}
#endif
// if(...) was removed
{
// convert "screen space" to "minimap space":
vPosInMiniMap = Vector2(screenPoint.x / SCREEN_WIDTH, screenPoint.y / SCREEN_HEIGHT);
/*#if __BANK
if (bDebug3DBlips)
{
if (CMiniMap::GetUniqueBlipUsed(pBlip) == CMiniMap::GetUniqueCentreBlipId())
{
vGameScreenPos = vPosInMiniMap;
}
}
#endif // __BANK*/
if ( (!ms_MiniMapRenderState.m_bIsInPauseMap) && (ms_MiniMapRenderState.m_CurrentGolfMap != GOLF_COURSE_OFF) )
{
vPosInMiniMap.x -= ms_MiniMapRenderState.m_vCurrentMiniMapPosition.x;
vPosInMiniMap.y -= ms_MiniMapRenderState.m_vCurrentMiniMapPosition.y;
// work out if the blip is in the range of the visible map on the screen (the stage):
if (vPosInMiniMap.x >= 0.0f && vPosInMiniMap.y >= 0.0f &&
vPosInMiniMap.x <= ms_MiniMapRenderState.m_vCurrentMiniMapSize.x && vPosInMiniMap.y <= ms_MiniMapRenderState.m_vCurrentMiniMapSize.y)
{
vPosInMiniMap.x = (vPosInMiniMap.x / ms_MiniMapRenderState.m_vCurrentMiniMapSize.x) * ms_vStageSize.x; // reposition into "stage space"
vPosInMiniMap.y = (vPosInMiniMap.y / ms_MiniMapRenderState.m_vCurrentMiniMapSize.y) * ms_vStageSize.y;
}
else
{
bOnRadar = false;
}
}
else
{
vPosInMiniMap.x -= ms_MiniMapRenderState.m_vCurrentMiniMapPosition.x;
vPosInMiniMap.y -= ms_MiniMapRenderState.m_vCurrentMiniMapPosition.y;
vPosInMiniMap.x /= ms_MiniMapRenderState.m_vCurrentMiniMapSize.x;
vPosInMiniMap.y /= ms_MiniMapRenderState.m_vCurrentMiniMapSize.y;
}
vNewBlipPosInMiniMap = Vector2(vPosInMiniMap.x - 0.5f, vPosInMiniMap.y - 0.5f);
/*#if __BANK // cant access GetActiveWaypointId() anympore from RT
if (bDebug3DBlips)
{
if (CMiniMap::GetUniqueBlipUsed(pBlip) == CMiniMap::GetUniqueCentreBlipId())
{
Displayf("Debug blip pos - %d (%d) - %0.2f,%0.2f vorig %0.2f,%0.2f", CMiniMap::GetUniqueBlipUsed(pBlip), CMiniMap::GetActualBlipUsed(pBlip), vNewBlipPosInMiniMap.x, vNewBlipPosInMiniMap.y, vBlipPos.x, vBlipPos.y);
}
}
#endif // __BANK*/
// BIG NASTY SORTA HACK
// Counter-scale area blips so they don't appear too big on the screen
// because script is currently using these to spoof a line
// if we ever need them to be an ACTUAL area, this won't work
if( GetBlipTypeValue(pBlip) == BLIP_TYPE_AREA && pBlip->vScale.y <= 5.0f )// assumption, if it's kinda small, always counterscale
{
GFxValue::DisplayInfo infoRangeRotation;
ms_asMapContainerMc.GetDisplayInfo(&infoRangeRotation);
float fCurrRange = ADJUST_SCALEFORM_SCALAR((float)infoRangeRotation.GetXScale());
pBlip->vScale.y = Min(pBlip->vScale.y, fCurrRange * pBlip->vScale.y);
// we could scale the values entirely, but it looks really weird very zoomed out, so we'll just prevent it from getting too fat
}
// we now have the 2D blip position in the minimap space
// check the range so we can lock blips to the edge of the radar in the 2D space:
if ( (ms_MiniMapRenderState.m_bIsInPauseMap) || (ms_MiniMapRenderState.m_CurrentGolfMap == GOLF_COURSE_OFF) )
{
#define MAX_2D_RADAR_DISTANCE_RADIUS_CIRCLE (0.39f)
#define MAX_2D_RADAR_DISTANCE_RADIUS_SQUARE (0.8f)
float fMaxDistance = MAX_2D_RADAR_DISTANCE_RADIUS_CIRCLE;
if (bMiniMapSquare)
{
fMaxDistance = MAX_2D_RADAR_DISTANCE_RADIUS_SQUARE;
}
float f2DDistance = vNewBlipPosInMiniMap.Mag();
if (GetBlipTypeValue(pBlip) != BLIP_TYPE_RADIUS && GetBlipTypeValue(pBlip) != BLIP_TYPE_AREA)
{
if (f2DDistance > fMaxDistance)
{
// if these are short range blips and isnt flashing then dont lock to the edge (they dissapear off the radar)
if (flags.IsSet(BLIP_FLAG_SHORTRANGE) && ( (flags.IsClear(BLIP_FLAG_FLASHING)) && (flags.IsClear(BLIP_FLAG_VALUE_CHANGED_FLASH)) ))
{
if (!bMiniMapSquare)
{
bOnRadar = false;
}
}
float fScale = fMaxDistance / f2DDistance;
vNewBlipPosInMiniMap.x *= fScale;
vNewBlipPosInMiniMap.y *= fScale;
if (!bMiniMapSquare)
{
bOnEdgeOfRadar = true;
}
}
}
if (bMiniMapSquare)
{
float fCentreOffsetX = 0.0f;
Vector2 vMax2dRadarDistanceSquare(0.459f, 0.42f);
if (ms_MiniMapRenderState.m_bIsInPauseMap)
{
vMax2dRadarDistanceSquare = Vector2(0.5f, 0.5f);
}
else if (ms_MiniMapRenderState.m_bIsInCustomMap)
{
float x = 0.225000009f;
float y = 0.5972222f;
vMax2dRadarDistanceSquare = Vector2(x, y);
}
else if (ms_MiniMapRenderState.m_bIsInBigMap)
{
fCentreOffsetX = __BIGMAP_INTERNAL_ADJUSTMENT_BLIP_RANGE;
vMax2dRadarDistanceSquare = Vector2(0.305f, 0.448f);
}
if( GetBlipTypeValue(pBlip) != BLIP_TYPE_RADIUS && (GetBlipTypeValue(pBlip) != BLIP_TYPE_AREA || flags.IsClear(BLIP_FLAG_SHORTRANGE)) )
{
if (vNewBlipPosInMiniMap.x > vMax2dRadarDistanceSquare.x-fCentreOffsetX)
{
iQuadrant = 0;
vNewBlipPosInMiniMap.x = vMax2dRadarDistanceSquare.x-fCentreOffsetX;
bOnEdgeOfRadar = true;
}
if (vNewBlipPosInMiniMap.y > vMax2dRadarDistanceSquare.y)
{
iQuadrant = 1;
vNewBlipPosInMiniMap.y = vMax2dRadarDistanceSquare.y;
bOnEdgeOfRadar = true;
}
if (vNewBlipPosInMiniMap.x < -(vMax2dRadarDistanceSquare.x+fCentreOffsetX))
{
iQuadrant = 2;
vNewBlipPosInMiniMap.x = -(vMax2dRadarDistanceSquare.x+fCentreOffsetX);
bOnEdgeOfRadar = true;
}
if (vNewBlipPosInMiniMap.y < -vMax2dRadarDistanceSquare.y)
{
iQuadrant = 3;
vNewBlipPosInMiniMap.y = -vMax2dRadarDistanceSquare.y;
bOnEdgeOfRadar = true;
}
if( GetBlipTypeValue(pBlip) == BLIP_TYPE_AREA )
{
// Extended area checks necessary for Square blips (and radius blips, if we did this [which we don't for V])
bOnEdgeOfRadar = IsAreaBlipOutsideMapBounds(*pBlip);
}
// if these are short range blips and isnt flashing then dont lock to the edge (they dissapear off the radar)
if (bOnEdgeOfRadar)
{
if (ms_MiniMapRenderState.m_bIsInPauseMap || ms_MiniMapRenderState.m_bIsInCustomMap)
{
bOnRadar = false;
}
else
{
if (flags.IsSet(BLIP_FLAG_SHORTRANGE) && (flags.IsClear(BLIP_FLAG_FLASHING)) && (flags.IsClear(BLIP_FLAG_VALUE_CHANGED_FLASH)))
{
bOnRadar = false;
}
}
//blips on the edge cannot be drawn in the 3d format because they override vNewBlipPosInMiniMap
bOn3dMap = false;
}
// fade out short range blips when in 3D mode and on standard minimap: (fixes todo 1166607)
if ( (!ms_MiniMapRenderState.m_bIsInPauseMap) && (!ms_MiniMapRenderState.m_bIsInBigMap) && (!ms_MiniMapRenderState.m_bIsInCustomMap) && (ms_MiniMapRenderState.m_fAngle != 0.0f) )
{
if ( (bOnRadar) && (flags.IsSet(BLIP_FLAG_SHORTRANGE)) && (flags.IsClear(BLIP_FLAG_FLASHING)) && (flags.IsClear(BLIP_FLAG_ROUTE)) && (flags.IsClear(BLIP_FLAG_VALUE_CHANGED_FLASH)) )
{
if (vNewBlipPosInMiniMap.y < -0.4f)
{
bOnRadar = false;
}
else if (vNewBlipPosInMiniMap.y < -0.3f)
{
iDisplayAlpha = (s32)floor((0.4f-(-vNewBlipPosInMiniMap.y)) * 1000.0f);
}
}
}
}
}
// set the 2D blip final position:
vNewBlipPosInMiniMap.x *= ms_vStageSize.x;
vNewBlipPosInMiniMap.y *= ms_vStageSize.y;
vNewBlipPosInMiniMap.x += (ms_vStageSize.x * 0.5f);
vNewBlipPosInMiniMap.y += (ms_vStageSize.y * 0.5f);
}
}
}
//
// now we know if we are visible or not on the minimap, we can return
//
if (bRangeCheckOnly)
{
return (bOnEdgeOfRadar);
}
const bool bLayerChanged = bOn3dMap!=GetIsPlacedOn3dMap(pBlip);
//layer changed? refresh stage
if( bLayerChanged )
{
SetIsPlacedOn3dMap(pBlip, bOn3dMap);
ReInitBlipOnStage(pBlip);
CMiniMap::GetAllFlags(flags, pBlip); // Flags may have changed, get new ones
}
GFxValue *pGfxValue = GetBlipGfxValue(pBlip);
if (bOnRadar)
{
if (!pGfxValue)
{
if (AddBlipToStage(pBlip)) // add object to stage
{
pGfxValue = GetBlipGfxValue(pBlip);
CMiniMap::GetAllFlags(flags, pBlip); // Flags may have changed, get the new ones
}
}
}
else
{
if (pGfxValue)
{
if (RemoveBlipFromStage(pBlip, false)) // remove object from stage
{
return false; // we have now removed the blip so exit out early
}
}
}
if (bOnRadar && pGfxValue)
{
//
// update the blip if it is on the stage:
//
uiAssertf(pGfxValue->IsDisplayObject(), "CMiniMap_RenderThread: Blip is not display object!");
float fBlipRotation = -(GetBlipDirectionValue(pBlip)); // get blip rotation
if (fBlipRotation == -DEFAULT_BLIP_ROTATION) // if blip has no rotation...
{
if (bOn3dMap)
{
fBlipRotation = static_cast<float>(iMapRotation); // ... then counter rotate by the map rotation to keep it upright
}
}
// 3D blips don't get rotated
else if(!bOn3dMap)
{
fBlipRotation -= iMapRotation;
}
// ensure the value is between 0 and 359 degrees (Note: This actually wraps between 0 and 360)
fBlipRotation = rage::Wrap(fBlipRotation, 0.0f, 360.0f);
// 3D, edge-shrunked blips disregard their rotation, and instead put it on a quadrant
if( bOnEdgeOfRadar && GetBlipTypeValue(pBlip) == BLIP_TYPE_AREA && flags.IsClear(BLIP_FLAG_SHORTRANGE))
{
fBlipRotation = 90.0f * (iQuadrant+1);
}
/*
if (CMiniMap::GetUniqueBlipUsed(pBlip) == CMiniMap::GetUniqueCentreBlipId())
{
Displayf("new centre blip rot: %d (map %d) blip orig %d", iBlipRotation, iMapRotation, GetBlipDirectionValue(pBlip));
}
*/
GFxValue pMainBlip;
if (pGfxValue->GFxValue::GetMember("main_blip", &pMainBlip))
{
// 3D blips don't rotate their sub blip, they need to rotate the parent object
// otherwise 2D shapes get weird (this may come up for other blips too)
if(!GetIsPlacedOn3dMap(pBlip) && flags.IsClear(BLIP_FLAG_SHOW_HEADING_INDICATOR))
{
if (pMainBlip.IsDisplayObject())
{
GFxValue::DisplayInfo rotationInfo;
rotationInfo.SetRotation(fBlipRotation);
pMainBlip.SetDisplayInfo(rotationInfo); // apply the rotation to the "main_blip" only
}
}
}
GFxValue::DisplayInfo info;
if (GetIsPlacedOn3dMap(pBlip))
{
// need to rotate 3D blips' main blip instead of the subblip above
info.SetRotation(fBlipRotation);
// fMapRange was computed in the first "if (bOnRadar)" block
if (ms_fBlipMapRange < MAP_BLIP_ROUND_THRESHOLD)
{
info.SetPosition(floor(vNewBlipPos.x+0.5f), floor(vNewBlipPos.y+0.5f));
}
else
{
info.SetPosition(vNewBlipPos.x, vNewBlipPos.y);
}
}
else
{
info.SetPosition(vNewBlipPosInMiniMap.x, vNewBlipPosInMiniMap.y);
}
Vector2 vBlipFinalSize;
float fBlipScaler = GetBlipScalerValue(pBlip);
if(GetBlipTypeValue(pBlip) == BLIP_TYPE_AREA )
{
if (bOnEdgeOfRadar)
{
//minimized radius edge blips shouldn't inherit alpha
// and this is OKAY to do, because all the blips are currently copied to be rendered
// so the original's data is untouched
pBlip->iAlpha = 0xFF;
fBlipScaler = GetBlipScalerValue(pBlip, false);
vBlipFinalSize.Set( fBlipScaler, fBlipScaler); // if on the edge, shrink it to match what others look like
}
else
{
vBlipFinalSize.Set( GetBlipScaleValue(pBlip) );
}
}
else if (GetBlipTypeValue(pBlip) == BLIP_TYPE_RADIUS)
{
vBlipFinalSize.Set( GetBlipScaleValue(pBlip) * 2.0f ); // radius needs to be diameter for SetScale
}
else
{
vBlipFinalSize.Set( GetBlipScaleValue(pBlip) * fBlipScaler );
// if blip is a player blip then reduce to 50% on edge of minimap
// if blip is considered "dead" then 50% size
if ((flags.IsSet(BLIP_FLAG_DEAD)) ||
(bOnEdgeOfRadar && flags.IsSet(BLIP_FLAG_MINIMISE_ON_EDGE)))
{
vBlipFinalSize *= 0.5f;
}
}
if (GetBlipObjectNameId(pBlip) == BLIP_LEVEL && !bOn3dMap)
{
vBlipFinalSize *= 0.8f; // these blips are always 80% of the original size
}
info.SetScale(vBlipFinalSize.x, vBlipFinalSize.y);
if(pGfxValue->GFxValue::HasMember("textLabel"))
{
GFxValue gfxTextLabel;
if (pGfxValue->GFxValue::GetMember("textLabel", &gfxTextLabel))
{
// Counter-scale text label so the size remains consistent
GFxValue::DisplayInfo textLabelInfo;
float fTextLabelScale = fBlipScaler / vBlipFinalSize.x * 100;
textLabelInfo.SetScale(fTextLabelScale, fTextLabelScale);
gfxTextLabel.SetDisplayInfo(textLabelInfo);
}
}
pGfxValue->SetDisplayInfo(info); // apply the changes
if (flags.IsSet(BLIP_FLAG_UPDATE_STAGE_DEPTH))
{
GFxValue newDepth;
newDepth.SetNumber( DetermineBlipStageDepth(pBlip) );
pGfxValue->Invoke("swapDepths", nullptr, &newDepth, 1);
}
//
// now check for anything that requires an invoke (a flag must be checked before invoking):
//
if (flags.IsSet(BLIP_FLAG_VALUE_CHANGED_COLOUR) || flags.IsSet(BLIP_FLAG_UPDATE_ALPHA_ONLY) )
{
ColourBlipOnStage(pGfxValue, pBlip);
}
//if (flags.IsSet(BLIP_FLAG_SHOW_HEADING_INDICATOR))
{
UpdateHeadingIndicatorOnBlipOnStage(pGfxValue, pBlip, iMapRotation);
}
if (flags.IsSet(BLIP_FLAG_VALUE_CHANGED_OUTLINE_INDICATOR))
{
UpdateOutlineIndicatorOnBlipOnStage(pGfxValue, pBlip);
}
if (flags.IsSet(BLIP_FLAG_VALUE_CHANGED_FRIEND_INDICATOR))
{
UpdateFriendIndicatorOnBlipOnStage(pGfxValue, pBlip);
}
if (flags.IsSet(BLIP_FLAG_VALUE_CHANGED_CREW_INDICATOR))
{
UpdateCrewIndicatorOnBlipOnStage(pGfxValue, pBlip);
}
if (flags.IsSet(BLIP_FLAG_VALUE_CHANGED_TICK))
{
UpdateTickBlipOnStage(pGfxValue, pBlip);
}
if( flags.IsSet(BLIP_FLAG_VALUE_CHANGED_GOLD_TICK))
{
UpdateGoldTickBlipOnStage(pGfxValue, pBlip);
}
if (flags.IsSet(BLIP_FLAG_VALUE_CHANGED_FOR_SALE))
{
UpdateForSaleBlipOnStage(pGfxValue, pBlip);
}
if (flags.IsSet(BLIP_FLAG_VALUE_CHANGED_PULSE))
{
PulseBlipOnStage(&pMainBlip, pBlip);
}
if (flags.IsSet(BLIP_FLAG_VALUE_CHANGED_FLASH))
{
FlashBlipOnStage(pGfxValue, pBlip);
}
#if __BANK
if (flags.IsSet(BLIP_FLAG_VALUE_SET_LABEL))
{
LabelBlipOnStage(pGfxValue, pBlip, true);
}
if (flags.IsSet(BLIP_FLAG_VALUE_REMOVE_LABEL))
{
LabelBlipOnStage(pGfxValue, pBlip, false);
}
#endif // __BANK
if (flags.IsSet(BLIP_FLAG_VALUE_SET_NUMBER))
{
NumberBlipOnStage(&pMainBlip, pBlip);
}
FadeOutDistantBlipOnStage(pGfxValue, iDisplayAlpha);
if (GetBlipCategoryValue(pBlip) == BLIP_CATEGORY_PLAYER) // only blips that are in the player category
{
ProcessPlayerNameDisplayOnBlip(pGfxValue, pBlip, bOnEdgeOfRadar);
}
//
// check for changing the height display of a blip:
//
if (flags.IsSet(BLIP_FLAG_SHOW_HEIGHT))
{
bool bShowHeight = false;
s32 iBlipHeight = 0;
if (GetBlipTypeValue(pBlip) != BLIP_TYPE_RADIUS && GetBlipTypeValue(pBlip) != BLIP_TYPE_AREA)
{
if ( (bOnRadar) && (!ms_MiniMapRenderState.m_bIsInPauseMap)/* && (!ms_MiniMapRenderState.m_bIsInBigMap)*/) // bug 623508 requests no height shown in pausemenu map
{
if (CMiniMap::IsFlagSet(pBlip, BLIP_FLAG_USE_HEIGHT_ON_EDGE))
{
bShowHeight = true;
}
else
{
// we only show the height indicator if the blip is inside the radar area or the player is in a vehicle that has a large change of height (ie a plane), or inside an interior
if ((!bOnEdgeOfRadar) || (ms_MiniMapRenderState.bInsideInterior))
{
// always show height if inside the radar area
bShowHeight = true;
}
else
{
// check if in a plane/heli
if (ms_MiniMapRenderState.bInPlaneOrHeli || ms_MiniMapRenderState.bIsInParachute) // fix for 1430446
{
bShowHeight = true;
}
}
}
}
}
// if its a weapon blip then only show it if its within 15m (for bug 980784)
if (bShowHeight) // only if we are already wanting to show height
{
if (!strncmp(WEAPON_BLIP_NAME, GetBlipObjectName(pBlip), NELEM(WEAPON_BLIP_NAME)-1))
{
bShowHeight = bBlipWithin15mOfPlayer;
}
}
if (bShowHeight) // height indicator only happens when the blip is inside the radar ring
{
iBlipHeight = CheckForHeight(pBlip); // whether this blip is above, below, level to the player
}
if (iBlipHeight != 0)
{
AddHigherLowerBlip(pGfxValue, pBlip, iBlipHeight);
}
else
{
RemoveHigherLowerBlip(pGfxValue);
}
}
else if (flags.IsSet(BLIP_FLAG_VALUE_TURNED_OFF_SHOW_HEIGHT))
{
RemoveHigherLowerBlip(pGfxValue);
flags.Set(BLIP_FLAG_VALUE_TURNED_OFF_SHOW_HEIGHT, false);
}
}
return true;
}
// Returns whether the area blip is outside of minimap bounds
bool CMiniMap_RenderThread::IsAreaBlipOutsideMapBounds(const CBlipComplex& rBlip)
{
// NOTE: Unlike on RDR, all the world positions had to be inverted
// Not sure why, but... didn't work otherwise.
// construct box also in world space, which is easy
ScalarV boxRotate( ScalarVFromF32(GetBlipDirectionValue(&rBlip) * DtoR) );
Mat34V boxLocalRotate;
// translation inverted so the box can transform stuff into its local space
// Removed the - from the positions....I don't know why they were in there but it didn't work with them....B*2173220
Mat34VFromZAxisAngle( boxLocalRotate, boxRotate, Vec3V(-GetBlipPositionConstRef(&rBlip).x, -GetBlipPositionConstRef(&rBlip).y, 0.0f) );
const float boxHeight = 0.0f;
const float fRadarSizeScalarForEdgeBlips = 0.95f; // give it a LITTLE bit of gimme room, so we don't have tiny pixels hanging out off screen
const float diameterScalar = 0.5f * fRadarSizeScalarForEdgeBlips;
const Vec3V vBoxHalfDims(GetBlipScaleValue(&rBlip).x*diameterScalar, GetBlipScaleValue(&rBlip).y*diameterScalar, boxHeight);
const spdAABB aabb(-vBoxHalfDims, vBoxHalfDims);
const spdOrientedBB oriRect( aabb, boxLocalRotate );
ScalarV mapRotate( ScalarVFromF32(ms_MiniMapRenderState.m_iRotation * DtoR) );
#if SUPPORT_MULTI_MONITOR
MultiMonitorHudHelper helper(&ms_MiniMapRenderState);
#endif // SUPPORT_MULTI_MONITOR
Vec3V mapPosition(ms_MiniMapRenderState.m_vMiniMapPosition.x, ms_MiniMapRenderState.m_vMiniMapPosition.y, 0.0f);
Vec3V offsetInWorld(0.0f, ADJUST_SCALEFORM_SCALAR(ms_MiniMapRenderState.m_fMiniMapRange) * ms_MiniMapRenderState.m_fOffset, 0.0f);
Vec3V offsetRotated( RotateAboutZAxis( offsetInWorld, mapRotate ) );
mapPosition += offsetRotated;
Mat34V mapLocalRotate;
Mat34VFromZAxisAngle( mapLocalRotate, mapRotate, -mapPosition );
GFxValue curXTilt;
if( ms_asBaseLayerContainer[MINIMAP_LAYER_FOREGROUND].GetMember("_xrotation", &curXTilt) )
{
Mat34VRotateLocalX(mapLocalRotate, ScalarVFromF32( float(-curXTilt.GetNumber()) * DtoR ) );
}
// We need this in 'world' units. The map is 1:1 pixels to meters, so if we found out how big the map is in pixels, we're all set!
//
// lifted from SetMaskOnLayer, because we need how it clips this to match
Vector2 maskSize( ms_MiniMapRenderState.m_vCurrentMiniMapMaskSize );
float fMapRatio = ms_vOriginalStageSize.x / ms_vOriginalStageSize.y;
const float fScaler = fMapRatio/CHudTools::GetAspectRatio();
maskSize.x /= ms_MiniMapRenderState.m_vCurrentMiniMapSize.x; maskSize.y /= ms_MiniMapRenderState.m_vCurrentMiniMapSize.y;
maskSize.x *= ms_vOriginalStageSize.x/fScaler; maskSize.y *= ms_vOriginalStageSize.y;
// then, now that we have it in 'map meters', we just adjust it by the scalar to see how big the area is in world meters!
const Vec3V vMapHalfDims( ADJUST_SCALEFORM_SCALAR(ms_MiniMapRenderState.m_fMiniMapRange) * maskSize.x * 0.5f
, ADJUST_SCALEFORM_SCALAR(ms_MiniMapRenderState.m_fMiniMapRange) * maskSize.y * 0.5f
, 1000.0f ); // fake a frustum by picking a rather large (?) value
const spdAABB mapAABB(-vMapHalfDims, vMapHalfDims);
const spdOrientedBB mapRect( mapAABB, mapLocalRotate );
bool bOnEdgeOfRadar = !oriRect.IntersectsOrientedBB(mapRect);
#if DEBUG_DRAW && __BANK
// if this the first one, push the minimap's settings
if( CMiniMap_RenderThread::sm_bDrawCollisionVolumes )
{
if( s_DebugDrawVolumes.GetRenderBuf().empty() )
s_DebugDrawVolumes.GetRenderBuf().PushAndGrow(debugVolume(mapRect, Color_WhiteSmoke), 4);
Color32 blipColor = CMiniMap_Common::GetColourFromBlipSettings(GetBlipColourValue(&rBlip), CMiniMap::IsFlagSet(&rBlip,BLIP_FLAG_BRIGHTNESS));
s_DebugDrawVolumes.GetRenderBuf().PushAndGrow(debugVolume(oriRect, blipColor, !bOnEdgeOfRadar), 4);
}
#endif
return bOnEdgeOfRadar;
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap_RenderThread::ProcessPlayerNameDisplayOnBlip
// PURPOSE: whether to attach or remove the player name display on a blip
/////////////////////////////////////////////////////////////////////////////////////
void CMiniMap_RenderThread::ProcessPlayerNameDisplayOnBlip(GFxValue *pBlipGfx, CBlipComplex *pBlip, bool bOnEdgeOfRadar)
{
if (!pBlip) // safeguard against invalid blips
{
return;
}
//
// check to see if we need to display the blip name against the blip (ie player blips)
//
bool bSetBlipLabelThisFrame = false;
bool bRemoveBlipLabelThisFrame = false;
bool bHasNameBeenAttachedPreviously = false;
if (pBlipGfx)
{
bHasNameBeenAttachedPreviously = pBlipGfx->GFxValue::HasMember("textLabel");
}
if ( (ms_MiniMapRenderState.m_bDisplayPlayerNames) && (!ms_MiniMapRenderState.m_bIsInPauseMap) && (ms_MiniMapRenderState.m_bIsInBigMap) )
{
if (bHasNameBeenAttachedPreviously)
{
if (!bOnEdgeOfRadar)
{
if (!IsBlipNameTagWithinBounds(pBlipGfx, pBlip))
{
bRemoveBlipLabelThisFrame = true;
}
}
else
{
bRemoveBlipLabelThisFrame = true;
}
}
else
{
if (!bOnEdgeOfRadar) // if within the zone, not already attached then flag to add
{
bSetBlipLabelThisFrame = true;
}
}
}
else
{
bRemoveBlipLabelThisFrame = bHasNameBeenAttachedPreviously; // if no longer needing names at all, then flag to remove it it has been previously added
}
if (pBlipGfx)
{
// if flagged to be added, then invoke scaleform
if (bSetBlipLabelThisFrame)
{
if (CScaleformMgr::BeginMethod(ms_iMovieId[MINIMAP_MOVIE_FOREGROUND], SF_BASE_CLASS_MINIMAP, "SET_BLIP_LABEL"))
{
CScaleformMgr::AddParamGfxValue(*pBlipGfx);
CScaleformMgr::AddParamString(GetBlipNameValue(pBlip));
GFxValue::DisplayInfo blipDisplayInfo;
pBlipGfx->GetDisplayInfo(&blipDisplayInfo);
CScaleformMgr::AddParamFloat(GetBlipScalerValue(pBlip) / blipDisplayInfo.GetXScale() * 100);
CScaleformMgr::EndMethod();
}
if (!IsBlipNameTagWithinBounds(pBlipGfx, pBlip))
{
if (CScaleformMgr::BeginMethod(ms_iMovieId[MINIMAP_MOVIE_FOREGROUND], SF_BASE_CLASS_MINIMAP, "REMOVE_BLIP_LABEL"))
{
CScaleformMgr::AddParamGfxValue(*pBlipGfx);
CScaleformMgr::EndMethod();
}
}
}
// if flagged to be removed, then invoke scaleform
if (bRemoveBlipLabelThisFrame)
{
if (CScaleformMgr::BeginMethod(ms_iMovieId[MINIMAP_MOVIE_FOREGROUND], SF_BASE_CLASS_MINIMAP, "REMOVE_BLIP_LABEL"))
{
CScaleformMgr::AddParamGfxValue(*pBlipGfx);
CScaleformMgr::EndMethod();
}
}
}
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap_RenderThread::IsBlipNameTagWithinBounds
// PURPOSE: is the blip name tag within the bounds of the minimap zone
/////////////////////////////////////////////////////////////////////////////////////
bool CMiniMap_RenderThread::IsBlipNameTagWithinBounds(GFxValue *pBlipGfx, CBlipComplex *pBlip)
{
if ( (!pBlip) || (!pBlipGfx) )
return false;
GFxValue::DisplayInfo displayInfo;
pBlipGfx->GetDisplayInfo(&displayInfo);
Vector2 vPosOnStage = Vector2((float)displayInfo.GetX(), (float)displayInfo.GetY());
GFxValue gfxTextLabel;
if (pBlipGfx->GFxValue::GetMember("textLabel", &gfxTextLabel))
{
GFxValue gfxTextLabelBG;
if (gfxTextLabel.GetMember("bg", &gfxTextLabelBG))
{
float fNameLength = 0.0f;
GFxValue nameTagWidth;
gfxTextLabelBG.GetMember("_width", &nameTagWidth);
if(nameTagWidth.IsDefined())
{
#define GAP_BETWEEN_BLIP_AND_BORDER (20.0f)
// need to convert from "actionscript space" to the minimap scaled space:
fNameLength = static_cast<float>(( (nameTagWidth.GetNumber() + GAP_BETWEEN_BLIP_AND_BORDER) / (float)ACTIONSCRIPT_STAGE_SIZE_X) * MINIMAP_INITIAL_SCALE);
// deal with adjusting this length to the correct scaled side:
fNameLength *= GetBlipScaleValue(pBlip).x; // scale for blip scaling
if (GetBlipObjectNameId(pBlip) == BLIP_LEVEL)
{
fNameLength *= 0.8f; // these blips are always 80% of the original size
}
}
// these values match the position in the AS stage where the name shouldnt display
if ((vPosOnStage.x-fNameLength) < 8.0f || // check if within bounds
vPosOnStage.y < 17.0f ||
vPosOnStage.x > 112.0f ||
vPosOnStage.y > 119.0f)
{
return false;
}
else
{
return true; // within bounds
}
}
}
return false;
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap_RenderThread::ReInitBlipOnStage
// PURPOSE: re-initialises the blips that are currently on the stage
/////////////////////////////////////////////////////////////////////////////////////
void CMiniMap_RenderThread::ReInitBlipOnStage(CBlipComplex *pBlip)
{
if (!CSystem::IsThisThreadId(SYS_THREAD_RENDER)) // only on RT
{
sfAssertf(0, "CMiniMap_RenderThread::ReInitBlipOnStage can only be called on the RenderThread!");
return;
}
if (pBlip)
{
if (GetBlipGfxValue(pBlip))
{
if (RemoveBlipFromStage(pBlip, false))
{
AddBlipToStage(pBlip);
}
else
{
uiAssertf(0, "CMiniMap_RenderThread: Reinit blip on stage couldnt complete!");
}
}
}
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap_RenderThread::UpdateAltimeter
// PURPOSE: updates the altimeter
/////////////////////////////////////////////////////////////////////////////////////
void CMiniMap_RenderThread::UpdateAltimeter()
{
if (!CSystem::IsThisThreadId(SYS_THREAD_RENDER)) // only on RT
{
sfAssertf(0, "CMiniMap_RenderThread::UpdateAltimeter can only be called on the RenderThread!");
return;
}
if (ms_iMovieId[MINIMAP_MOVIE_FOREGROUND] == -1)
return;
// bool bSwitchOff = true;
bool bDrawAltimeter = (ms_MiniMapRenderState.m_AltimeterMode != ALTIMETER_OFF);
if( bDrawAltimeter )
{
// remember that -Y is UP, so the TOP is actually the lower value
// whereas the bottom is a higher value
const float fHeight = (ms_MiniMapRenderState.m_vCentrePosition.z + ALTIMETER_GROUND_LEVEL_FUDGE_FACTOR);
//
// Background
//
const float fFloorLevel = ms_MiniMapRenderState.m_fMinAltimeterHeight;
const float fCeilingLevel = ms_MiniMapRenderState.m_fMaxAltimeterHeight;
const float fPercent = ms_MiniMapRenderState.m_AltimeterMode == ALTIMETER_SWIMMING ? rage::Range(fHeight, fCeilingLevel, fFloorLevel) : rage::Range(fHeight, fFloorLevel, fCeilingLevel);
GFxValue::DisplayInfo infoGauge;
const float fPercentPixels = (fPercent - 0.5f) * ALTIMETER_TICK_PIXEL_HEIGHT;// 0.5f to adjust for the registration point being centered
infoGauge.SetY( fPercentPixels );
ms_Altimeter.m_asGaugeMc.SetDisplayInfo(infoGauge);
GFxValue altimeter_colour_mc;
if (ms_Altimeter.m_asGaugeMc.GFxValue::GetMember("altimeter_colour", &altimeter_colour_mc))
{
GFxValue::DisplayInfo visibilityDisplayInfo;
visibilityDisplayInfo.SetVisible(ms_MiniMapRenderState.m_bColourAltimeter);
altimeter_colour_mc.SetDisplayInfo(visibilityDisplayInfo);
GFxValue ColorArg[1];
GFxValue result;
ColorArg[0].SetNumber((int)(ms_MiniMapRenderState.m_AltimeterColor));
altimeter_colour_mc.Invoke("Recolor", &result, ColorArg, COUNTOF(ColorArg));
}
//
// asAltimeterRoll:
//
GFxValue::DisplayInfo infoRoll;
infoRoll.SetVisible( ms_MiniMapRenderState.m_AltimeterMode != ALTIMETER_OFF );
infoRoll.SetRotation(ms_MiniMapRenderState.fRoll * RtoD);
ms_Altimeter.m_asRollMc.SetDisplayInfo(infoRoll);
}
// determine visibility for the whole shebang
{
GFxValue::DisplayInfo drawInfo;
drawInfo.SetVisible(bDrawAltimeter);
drawInfo.SetPosition((ms_vStageSize.x * 0.5f), (ms_vStageSize.y * 0.5f) + ms_MiniMapRenderState.m_fOffset);
ms_Altimeter.m_asContainerMc.SetDisplayInfo(drawInfo);
}
// Show/Hide all four runways
if( ms_MiniMapRenderState.bInPlaneOrHeli != ms_bRunwayBlipsAreDisplaying )
{
ms_bRunwayBlipsAreDisplaying = ms_MiniMapRenderState.bInPlaneOrHeli;
if (CScaleformMgr::BeginMethod(ms_iMovieId[MINIMAP_MOVIE_BACKGROUND], SF_BASE_CLASS_MINIMAP, "SHOW_AIRCRAFT_COMPONENTS"))
{
CScaleformMgr::AddParamBool(ms_bRunwayBlipsAreDisplaying);
CScaleformMgr::EndMethod();
}
}
}
void CMiniMap_RenderThread::UpdateSonarSweep()
{
if (!CSystem::IsThisThreadId(SYS_THREAD_RENDER)) // only on RT
{
sfAssertf(0, "CMiniMap_RenderThread::UpdateSonarSweep can only be called on the RenderThread!");
return;
}
if (ms_iMovieId[MINIMAP_MOVIE_FOREGROUND] == -1)
return;
if(ms_MiniMapRenderState.m_bShowSonarSweep)
{
const bool bHideSonarSweep = ms_MiniMapRenderState.m_bIsInBigMap;
const bool bShowSonarSweep = ms_MiniMapRenderState.m_bShowSonarSweep && !bHideSonarSweep;
if (CScaleformMgr::BeginMethod(ms_iMovieId[MINIMAP_MOVIE_FOREGROUND], SF_BASE_CLASS_MINIMAP, "SHOW_SONAR_SWEEP"))
{
CScaleformMgr::AddParamBool(bShowSonarSweep);
CScaleformMgr::EndMethod();
}
}
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap_RenderThread::UpdateMapVisibility
// PURPOSE: makes sure the prologue map is displayed instead of the standard one
// when script set it, or the main map is turned off
/////////////////////////////////////////////////////////////////////////////////////
void CMiniMap_RenderThread::UpdateMapVisibility()
{
if (ms_iMovieId[MINIMAP_MOVIE_FOREGROUND] == -1)
return;
GFxValue mainMap;
GFxValue::DisplayInfo currentMainMapDisplayInfo;
ms_asMapObject.GFxValue::GetMember("main_map", &mainMap);
mainMap.GetDisplayInfo(&currentMainMapDisplayInfo);
// show/hide the prologue map:
if (ms_MiniMapRenderState.m_bShowPrologueMap)
{
#if COMPANION_APP
CCompanionData::GetInstance()->SetMapDisplay(eMapDisplay::MAP_DISPLAY_PROLOGUE);
#endif // COMPANION_APP
}
// show/hide the island map:
if (ms_MiniMapRenderState.m_bShowIslandMap)
{
#if COMPANION_APP
CCompanionData::GetInstance()->SetMapDisplay(eMapDisplay::MAP_DISPLAY_ISLAND);
#endif // COMPANION_APP
}
//
// show/hide the main map:
//
if (ms_MiniMapRenderState.m_bShowMainMap)
{
#if COMPANION_APP
CCompanionData::GetInstance()->SetMapDisplay(eMapDisplay::MAP_DISPLAY_NORMAL);
#endif // COMPANION_APP
if (!currentMainMapDisplayInfo.GetVisible())
{
GFxValue::DisplayInfo newDisplayInfo;
newDisplayInfo.SetVisible(true);
mainMap.SetDisplayInfo(newDisplayInfo);
g_RenderMinimap = true;
if ( (!ms_MiniMapRenderState.m_bIsInPauseMap) && (!ms_MiniMapRenderState.m_bIsInCustomMap) )
{
g_RenderMinimapSea = true;
}
}
}
else
{
if (currentMainMapDisplayInfo.GetVisible())
{
GFxValue::DisplayInfo newDisplayInfo;
newDisplayInfo.SetVisible(false);
mainMap.SetDisplayInfo(newDisplayInfo);
g_RenderMinimap = false;
g_RenderMinimapSea = false;
}
}
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap_RenderThread::CheckIncomingFunctions
// PURPOSE: checks for incoming functions from ActionScript
/////////////////////////////////////////////////////////////////////////////////////
void CMiniMap_RenderThread::CheckIncomingFunctions(atHashWithStringBank methodName, const GFxValue* args)
{
// INTERIOR_IS_LOADED
if (methodName == ATSTRINGHASH("INTERIOR_IS_LOADED",0xad2c4c8))
{
if (ms_asInteriorMc.IsDisplayObject()) // ignore this until its been invoked with LoadMovie - where ms_asInteriorMc is attached
{
ms_asInteriorMovie = args[1];
}
return;
}
// GOLF_COURSE_IS_LOADED
if (methodName == ATSTRINGHASH("GOLF_COURSE_IS_LOADED",0x9a61c818))
{
if (ms_asGolfCourseMc.IsDisplayObject()) // ignore this until its been invoked with LoadMovie - where ms_asGolfCourseMc is attached
{
ms_asGolfCourseMovie = args[1];
}
return;
}
#if __STREAMED_SUPERTILE_FILES
if (methodName == ATSTRINGHASH("SUPERTILE_IS_LOADED",0xc72454db))
{
ms_Supertiles.HandleIsLoadedCallback((s32)args[1].GetNumber(), (s32)args[2].GetNumber(), args[3]);
return;
}
#endif // __STREAMED_SUPERTILE_FILES
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap_RenderThread::RemoveInterior
// PURPOSE: creates the GFxValue object as the interior is now active on the stage
/////////////////////////////////////////////////////////////////////////////////////
void CMiniMap_RenderThread::RemoveInterior()
{
if (ms_iMovieId[MINIMAP_MOVIE_FOREGROUND] == -1)
return;
ms_bInteriorMovieIdFullySetup = false;
ms_bInteriorWasSetOnPerFrame = false;
if (ms_asInteriorMc.IsDisplayObject())
{
ms_asInteriorMc.Invoke("removeMovieClip");
}
ms_asInteriorMc.SetUndefined();
ms_asInteriorMovie.SetUndefined();
ms_PreviousInterior.iLevel = sMiniMapInterior::INVALID_LEVEL;
if (ms_iInteriorMovieId != -1)
{
ms_bRemoveInteriorMovie = true;
}
uiDebugf1("MiniMap: Interior removed from stage");
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap_RenderThread::UpdateInterior
// PURPOSE: updates the minimap with any information interiors/exteriors
/////////////////////////////////////////////////////////////////////////////////////
void CMiniMap_RenderThread::UpdateInterior()
{
if (!CSystem::IsThisThreadId(SYS_THREAD_RENDER)) // only on RT
{
uiAssertf(0, "CMiniMap_RenderThread::UpdateInterior can only be called on the RenderThread!");
return;
}
if (ms_iMovieId[MINIMAP_MOVIE_FOREGROUND] == -1)
return;
if (ms_PreviousInterior.ResolveDifferentHash(ms_MiniMapRenderState.m_Interior))
{
if (ms_MiniMapRenderState.m_Interior.uHash != 0)
{
#if __BANK && __DEV
if (bDisplayInteriorInfoToLog)
{
Displayf("Interior info for minimap is: %u (%d)", ms_MiniMapRenderState.m_Interior.uHash, ms_MiniMapRenderState.m_Interior.uHash);
}
#endif // __BANK && __DEV
RemoveInterior();
ms_bStreamInteriorMovie = true;
}
else
{
RemoveInterior();
}
}
if (ms_bStreamInteriorMovie || ms_bRemoveInteriorMovie)
return;
GFxValue asInteriorLayer;
if (!ms_asBaseOverlay3D[MINIMAP_LAYER_BACKGROUND].GetMember("asInteriorLayer", &asInteriorLayer))
{
uiAssertf(0, "CMiniMap_RenderThread::UpdateInterior cannot find member 'asInteriorLayer'");
return;
}
//
// no interior map should be shown when not in an interior:
//
GFxValue::DisplayInfo displayInfo;
asInteriorLayer.GetDisplayInfo(&displayInfo);
if (ms_MiniMapRenderState.m_Interior.uHash == 0 || ms_MiniMapRenderState.m_bHideInteriorMap)
{
// hide
if (displayInfo.GetVisible())
{
GFxValue::DisplayInfo newInteriorDisplayInfo;
newInteriorDisplayInfo.SetVisible(false);
asInteriorLayer.SetDisplayInfo(newInteriorDisplayInfo);
}
}
else
{
// show
if (!displayInfo.GetVisible())
{
GFxValue::DisplayInfo newInteriorDisplayInfo;
newInteriorDisplayInfo.SetVisible(true);
asInteriorLayer.SetDisplayInfo(newInteriorDisplayInfo);
}
}
if (CScaleformMgr::IsMovieActive(ms_iInteriorMovieId))
{
if ((!ms_asInteriorMovie.IsDisplayObject()) || (ms_asInteriorMovie.IsDisplayObject() && (!ms_asInteriorMovie.HasMember("interior"))))
{
char cHashName[20];
formatf(cHashName, "INT%u", ms_MiniMapRenderState.m_Interior.uHash, NELEM(cHashName));
if (ms_asInteriorMc.IsUndefined())
{
// invoke the load here
GFxValue result, params[1];
params[0].SetString(cHashName);
asInteriorLayer.CreateEmptyMovieClip(&ms_asInteriorMc, "INTERIOR_LINK", MOVIE_DEPTH_INTERIOR);
ms_asInteriorMc.Invoke("loadMovie", &result, params, 1);
}
if (ms_asInteriorMc.IsDisplayObject())
{
if (ms_asInteriorMovie.IsDisplayObject())
{
if (ms_asInteriorMovie.GotoAndStop(cHashName))
{
if (ms_asInteriorMovie.HasMember("interior"))
{
Vector3 vPos(0,0,0);
float fRot = 0.0f;
#if __BANK
if (!ms_MiniMapRenderState.m_bHasDebugInterior)
#endif // __BANK
{
// get current interior rotation and position:
vPos = ms_MiniMapRenderState.m_Interior.vPos;
fRot = ms_MiniMapRenderState.m_Interior.fRot;
}
// set the position:
GFxValue::DisplayInfo currentDisplayInfo;
currentDisplayInfo.SetPosition((vPos.x), -(vPos.y));
currentDisplayInfo.SetRotation(fRot);
if (ms_MiniMapRenderState.m_bShowPrologueMap) // fix for 986642
{
currentDisplayInfo.SetScale(400.0f, 400.0f);
}
else if (ms_MiniMapRenderState.m_bShowIslandMap)
{
currentDisplayInfo.SetScale(100.0f, 100.0f);
}
else
{
currentDisplayInfo.SetScale(100.0f, 100.0f);
}
ms_asInteriorMovie.SetDisplayInfo(currentDisplayInfo);
ms_bInteriorMovieIdFullySetup = true;
uiDebugf1("CMiniMap_RenderThread: Interior %s added to stage", cHashName);
}
else
{
uiDebugf1("CMiniMap_RenderThread: Interior data for %s is invalid - unable to set up Interior on stage (probably movieclip is missing member 'interior')", cHashName);
RemoveInterior(); // remove anything that was setup
return;
}
}
else
{
uiDebugf1("CMiniMap_RenderThread: Interior %s is invalid - probably doesnt exist (gotoandstop(%s) failed)", cHashName, cHashName);
}
}
}
}
//
// make current level in the interior visible and hide the previous interior level:
//
if (ms_asInteriorMovie.IsDisplayObject() && ms_asInteriorMovie.HasMember("interior"))
{
GFxValue theinterior;
ms_asInteriorMovie.GetMember("interior", &theinterior);
s32 iCurrentInteriorLevel = ms_MiniMapRenderState.m_Interior.iLevel;
s32 iPreviousInteriorLevel = ms_PreviousInterior.iLevel;
if(ms_PreviousInterior.ResolveDifferentOrientation(ms_MiniMapRenderState.m_Interior))
{
GFxValue::DisplayInfo currentDisplayInfo;
currentDisplayInfo.SetPosition(ms_MiniMapRenderState.m_Interior.vPos.x, -(ms_MiniMapRenderState.m_Interior.vPos.y));
currentDisplayInfo.SetRotation(ms_MiniMapRenderState.m_Interior.fRot);
ms_asInteriorMovie.SetDisplayInfo(currentDisplayInfo);
}
if( ms_PreviousInterior.ResolveDifferentLevels(ms_MiniMapRenderState.m_Interior) )
{
char cCurrentLevelString[50];
if (iCurrentInteriorLevel >= 0)
formatf(cCurrentLevelString, "level_%d", iCurrentInteriorLevel, NELEM(cCurrentLevelString));
else
formatf(cCurrentLevelString, "level_u%d", -iCurrentInteriorLevel, NELEM(cCurrentLevelString));
if (ms_PreviousInterior.iLevel != sMiniMapInterior::INVALID_LEVEL) // if we have a previous level
{
char cPreviousLevelString[50];
if (iPreviousInteriorLevel >= 0)
formatf(cPreviousLevelString, "level_%d", iPreviousInteriorLevel, NELEM(cPreviousLevelString));
else
formatf(cPreviousLevelString, "level_u%d", -iPreviousInteriorLevel, NELEM(cPreviousLevelString));
if (theinterior.HasMember(cPreviousLevelString))
{
GFxValue thisLevel;
theinterior.GFxValue::GetMember(cPreviousLevelString, &thisLevel);
GFxValue::DisplayInfo info;
info.SetAlpha(0);
thisLevel.SetDisplayInfo(info);
uiDebugf1("CMiniMap_RenderThread: Removed interior '%s'", cPreviousLevelString);
}
#if __DEV
else
{
uiDebugf1("CMiniMap_RenderThread: Tried to remove interior '%s' but it doesnt exist", cPreviousLevelString);
}
#endif // __DEV
}
if (theinterior.HasMember(cCurrentLevelString))
{
GFxValue thisLevel;
theinterior.GFxValue::GetMember(cCurrentLevelString, &thisLevel);
GFxValue::DisplayInfo info;
info.SetAlpha(100);
thisLevel.SetDisplayInfo(info);
uiDebugf1("CMiniMap_RenderThread: Activated interior '%s'", cCurrentLevelString);
}
#if __DEV
else
{
uiDebugf1("CMiniMap_RenderThread: Tried to activate interior '%s' but it doesnt exist", cCurrentLevelString);
}
#endif // __DEV
}
}
}
}
void CMiniMap_RenderThread::HandleInteriorAtEndOfFrame()
{
if (CSystem::IsThisThreadId(SYS_THREAD_RENDER)) // only on UT
{
sfAssertf(0, "CMiniMap_RenderThread::HandleInteriorsAtEndOfFrame can only be called on the UpdateThread!");
return;
}
//
// removal/stream of interior movie
//
if (ms_bRemoveInteriorMovie || ms_bStreamInteriorMovie)
{
if (ms_iInteriorMovieId != -1)
{
if (CScaleformMgr::IsMovieActive(ms_iInteriorMovieId))
{
CScaleformMgr::RequestRemoveMovie(ms_iInteriorMovieId);
}
ms_iInteriorMovieId = -1;
}
ms_bRemoveInteriorMovie = false;
}
if (ms_bStreamInteriorMovie)
{
char cInteriorFilename[64];
formatf(cInteriorFilename, "INT%u", ms_MiniMapRenderState.m_Interior.uHash, NELEM(cInteriorFilename));
if (CScaleformMgr::DoesMovieExistInImage(cInteriorFilename))
{
ms_bInteriorWasSetOnPerFrame = CScriptHud::FakeInterior.bActive;
ms_iInteriorMovieId = CScaleformMgr::CreateMovie(cInteriorFilename, Vector2(0.0f, 0.0f), Vector2(1.0f, 1.0f), true, -1, -1, false);
}
else
{
uiDebugf1("CMiniMap: Interior %s is invalid - movie doesnt exist in RPF", cInteriorFilename);
}
ms_bStreamInteriorMovie = false;
}
CMiniMap_Common::SetInteriorMovieActive(ms_iInteriorMovieId != -1 && ms_bInteriorMovieIdFullySetup); // flag the interior movie as on/off
}
void CMiniMap_RenderThread::ProcessAtEndOfFrame()
{
#if __STREAMED_SUPERTILE_FILES
ms_Supertiles.ProcessAtEndOfFrame(ms_iMovieId[MINIMAP_MOVIE_FOREGROUND]);
#endif // __STREAMED_SUPERTILE_FILES
HandleInteriorAtEndOfFrame();
HandleGolfCourseAtEndOfFrame();
}
bool CMiniMap_RenderThread::HasRenderThreadProcessedThisMinimapModeState(eSETUP_STATE StateToCheck)
{
switch (StateToCheck)
{
case MINIMAP_MODE_STATE_NONE :
return false;
case MINIMAP_MODE_STATE_SETUP_FOR_MINIMAP :
if (MINIMAP_MODE_STATE_SETUP_FOR_MINIMAP_HAS_BEEN_PROCESSED_BY_RENDER_THREAD == ms_MiniMapRenderState.m_MinimapModeState)
{
#if !__FINAL
if(CMiniMap_Common::OutputDebugTransitions())
uiDisplayf("MINIMAP_TRANSITION: CMiniMap_RenderThread::HasRenderThreadProcessedThisMinimapModeState. Processed MINIMAP_MODE_STATE_SETUP_FOR_MINIMAP(%d) this frame (RT)", StateToCheck);
#endif
return true;
}
break;
case MINIMAP_MODE_STATE_SETUP_FOR_PAUSEMAP :
if (MINIMAP_MODE_STATE_SETUP_FOR_PAUSEMAP_HAS_BEEN_PROCESSED_BY_RENDER_THREAD == ms_MiniMapRenderState.m_MinimapModeState)
{
#if !__FINAL
if(CMiniMap_Common::OutputDebugTransitions())
uiDisplayf("MINIMAP_TRANSITION: CMiniMap_RenderThread::HasRenderThreadProcessedThisMinimapModeState. Processed MINIMAP_MODE_STATE_SETUP_FOR_PAUSEMAP(%d) this frame (RT)", StateToCheck);
#endif
return true;
}
break;
case MINIMAP_MODE_STATE_SETUP_FOR_BIGMAP :
if (MINIMAP_MODE_STATE_SETUP_FOR_BIGMAP_HAS_BEEN_PROCESSED_BY_RENDER_THREAD == ms_MiniMapRenderState.m_MinimapModeState)
{
#if !__FINAL
if(CMiniMap_Common::OutputDebugTransitions())
uiDisplayf("MINIMAP_TRANSITION: CMiniMap_RenderThread::HasRenderThreadProcessedThisMinimapModeState. Processed MINIMAP_MODE_STATE_SETUP_FOR_BIGMAP(%d) this frame (RT)", StateToCheck);
#endif
return true;
}
break;
case MINIMAP_MODE_STATE_SETUP_FOR_CUSTOMMAP :
if (MINIMAP_MODE_STATE_SETUP_FOR_CUSTOMMAP_HAS_BEEN_PROCESSED_BY_RENDER_THREAD == ms_MiniMapRenderState.m_MinimapModeState)
{
#if !__FINAL
if(CMiniMap_Common::OutputDebugTransitions())
uiDisplayf("MINIMAP_TRANSITION: CMiniMap_RenderThread::HasRenderThreadProcessedThisMinimapModeState. Processed MINIMAP_MODE_STATE_SETUP_FOR_CUSTOMMAP(%d) this frame (RT)", StateToCheck);
#endif
return true;
}
break;
case MINIMAP_MODE_STATE_SETUP_FOR_GOLFMAP :
if (MINIMAP_MODE_STATE_SETUP_FOR_GOLFMAP_HAS_BEEN_PROCESSED_BY_RENDER_THREAD == ms_MiniMapRenderState.m_MinimapModeState)
{
#if !__FINAL
if(CMiniMap_Common::OutputDebugTransitions())
uiDisplayf("MINIMAP_TRANSITION: CMiniMap_RenderThread::HasRenderThreadProcessedThisMinimapModeState. Processed MINIMAP_MODE_STATE_SETUP_FOR_GOLFMAP(%d) this frame (RT)", StateToCheck);
#endif
return true;
}
break;
default :
Assertf(0, "CMiniMap_RenderThread::HasRenderThreadProcessedThisMinimapModeState - setup state %d not handled by this function", StateToCheck);
break;
}
return false;
}
bool CMiniMap_RenderThread::IsInGameMiniMapDisplaying()
{
return ms_MiniMapRenderState.m_bShouldRenderMiniMap &&
( ms_MiniMapRenderState.m_bIsInBigMap ||
(!ms_MiniMapRenderState.m_bIsInCustomMap && !ms_MiniMapRenderState.m_bIsInPauseMap) );
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap_RenderThread::UpdateTiles
// PURPOSE: switches on/off tiles based on current player position
/////////////////////////////////////////////////////////////////////////////////////
void CMiniMap_RenderThread::UpdateTiles(bool bClearAll)
{
if (!CSystem::IsThisThreadId(SYS_THREAD_RENDER)) // only on RT
{
sfAssertf(0, "CMiniMap_RenderThread::UpdateTiles can only be called on the RenderThread!");
return;
}
Vector2 vTilesAroundPlayer;
bool bBitmapOnly = false;
if (bClearAll)
{
bBitmapOnly = true;
vTilesAroundPlayer = Vector2(0.0f, 0.0f);
}
else
{
bBitmapOnly = ms_MiniMapRenderState.m_bBitmapOnly;
vTilesAroundPlayer = ms_MiniMapRenderState.m_vTilesAroundPlayer;
}
Vector2 vCurrentTile = ms_MiniMapRenderState.m_vCentreTileForPlayer;
bool bAllTilesAreVisible = ms_Supertiles.Update(vCurrentTile, vTilesAroundPlayer, ms_asTileLayerContainer, bBitmapOnly);
bool bBitmapVisible = false;
#if __STREAMED_SUPERTILE_FILES
if ( (ms_MiniMapRenderState.m_bIsInPauseMap) && (!ms_MiniMapRenderState.bInsideInterior) )
{
if (!bAllTilesAreVisible)
{
bBitmapVisible = (ms_MiniMapRenderState.m_fMiniMapRange < 22.0f); // only have bitmap if we are zoomed out enough
}
else
{
bBitmapVisible = (ms_MiniMapRenderState.m_fMiniMapRange < 8.0f);
}
}
else
{
bBitmapVisible = true;
}
// turn bitmap on/off as desired
static bool bPreviouslyVisible = !bBitmapVisible;
if (bPreviouslyVisible != bBitmapVisible)
{
bPreviouslyVisible = bBitmapVisible;
GFxValue txd_mc;
if (uiVerifyf(ms_asBitmapLayerContainer.GFxValue::GetMember("TXD_MC", &txd_mc), "cannot find 'TXD_MC' member"))
{
GFxValue::DisplayInfo bitmapDisplayInfo;
if (bBitmapVisible)
bitmapDisplayInfo.SetVisible(true);
else
bitmapDisplayInfo.SetVisible(false);
txd_mc.SetDisplayInfo(bitmapDisplayInfo);
}
}
#else // __STREAMED_SUPERTILE_FILES
static Vector2 vPreviousTile(-1.0f,-1.0f);
static Vector2 vPreviousTilesAroundPlayer = vTilesAroundPlayer;
// if tile player is on hasnt changed and the amount of tiles to display hasnt changed, then no point in processing any further
if ( (!bClearAll) && (vPreviousTile == vCurrentTile && vPreviousTilesAroundPlayer == vTilesAroundPlayer) )
{
return;
}
char cLinkageName[30];
Vector2 vTile;
#if __DEV
s32 iDebugTileSwap = 0;
#endif // __DEV
if ( (vPreviousTile.x != -1.0f && vPreviousTile.y != -1.0f) || (vPreviousTilesAroundPlayer != vTilesAroundPlayer) )
{
for (vTile.x = vPreviousTile.x - vPreviousTilesAroundPlayer.x; vTile.x <= vPreviousTile.x + vPreviousTilesAroundPlayer.x; vTile.x++)
{
if (vTile.x < 0.0f || vTile.x > MINIMAP_WORLD_TILE_SIZE_X) // ignore tiles out of the map bounds
continue;
for (vTile.y = vPreviousTile.y - vPreviousTilesAroundPlayer.y; vTile.y <= vPreviousTile.y + vPreviousTilesAroundPlayer.y; vTile.y++)
{
if (vTile.y < 0.0f || vTile.y > MINIMAP_WORLD_TILE_SIZE_Y) // ignore tiles out of the map bounds
continue;
formatf(cLinkageName, "MAP_high_r%d_col%d", (s32)vTile.y, (s32)vTile.x, NELEM(cLinkageName));
if (vPreviousTile != vCurrentTile && vTile == vPreviousTile)
{
// Displayf("REMOVING TILE (centre) %s", cLinkageName);
}
else
{
// no need to turn off tiles that we still want to display this time round
if ((!bBitmapOnly) &&
vTile.x >= vCurrentTile.x - vTilesAroundPlayer.x &&
vTile.x <= vCurrentTile.x + vTilesAroundPlayer.x &&
vTile.y >= vCurrentTile.y - vTilesAroundPlayer.y &&
vTile.y <= vCurrentTile.y + vTilesAroundPlayer.y)
{
continue;
}
// Displayf("REMOVING TILE %s", cLinkageName);
}
if (ms_asTileLayerContainer.HasMember(cLinkageName))
{
GFxValue tile;
ms_asTileLayerContainer.GFxValue::GetMember(cLinkageName, &tile);
if (tile.IsDisplayObject())
{
tile.Invoke("removeMovieClip");
#if __DEV
// uiDebugf1("REMOVING TILE %s %d", cLinkageName, iDebugTileSwap);
iDebugTileSwap++;
#endif // __DEV
}
}
}
}
}
if (!bBitmapOnly)
{
for (vTile.x = vCurrentTile.x - vTilesAroundPlayer.x; vTile.x <= vCurrentTile.x + vTilesAroundPlayer.x; vTile.x++)
{
if (vTile.x < 0.0f || vTile.x > MINIMAP_WORLD_TILE_SIZE_X) // ignore tiles out of the map bounds
continue;
for (vTile.y = vCurrentTile.y - vTilesAroundPlayer.y; vTile.y <= vCurrentTile.y + vTilesAroundPlayer.y; vTile.y++)
{
if (vTile.y < 0.0f || vTile.y > MINIMAP_WORLD_TILE_SIZE_Y) // ignore tiles out of the map bounds
continue;
formatf(cLinkageName, "MAP_high_r%d_col%d", (s32)vTile.y, (s32)vTile.x, NELEM(cLinkageName));
if (vTile != vCurrentTile)
{
// no need to turn on tiles that we already know are active from last time
if (vTile != vPreviousTile &&
vTile.x >= vPreviousTile.x - vPreviousTilesAroundPlayer.x &&
vTile.x <= vPreviousTile.x + vPreviousTilesAroundPlayer.x &&
vTile.y >= vPreviousTile.y - vPreviousTilesAroundPlayer.y &&
vTile.y <= vPreviousTile.y + vPreviousTilesAroundPlayer.y)
{
continue;
}
}
if (!ms_asTileLayerContainer.HasMember(cLinkageName))
{
GFxValue tile;
static s32 iTileDepth = 1;
if (iTileDepth > (MINIMAP_WORLD_TILE_SIZE_X * MINIMAP_WORLD_TILE_SIZE_Y) + 1 )
{
iTileDepth = 1; // wrap around back to depth 1
}
else
{
iTileDepth++;
}
// #if __DEV
// uiDebugf1("TRYING TO ADD TILE %s (%0.0f %0.0f)", cLinkageName, vTile.x, vTile.y);
// #endif // __DEV
if (vTile.x >= MINIMAP_VISIBLE_TILES_WEST && vTile.y >= MINIMAP_VISIBLE_TILES_NORTH && vTile.x <= MINIMAP_VISIBLE_TILES_EAST && vTile.y <= MINIMAP_VISIBLE_TILES_SOUTH)
{
if (ms_asTileLayerContainer.GFxValue::AttachMovie(&tile, cLinkageName, cLinkageName, iTileDepth))
{
Vector2 vWorldTilePosition((vTile.x * MINIMAP_TILE_WIDTH) - (MINIMAP_WORLD_SIZE_X * 0.5f), ((MINIMAP_WORLD_TILE_SIZE_Y-vTile.y) * MINIMAP_TILE_HEIGHT) - (MINIMAP_WORLD_SIZE_Y * 0.5f));
GFxValue::DisplayInfo tileDisplayInfo;
tileDisplayInfo.SetPosition(vWorldTilePosition.x, -vWorldTilePosition.y);
tile.SetDisplayInfo(tileDisplayInfo);
#if __DEV
// uiDebugf1("ADDED TILE %s (%0.2f,%0.2f) %d %d", cLinkageName, vWorldTilePosition.x,vWorldTilePosition.y, iDebugTileSwap, iTileDepth);
iDebugTileSwap++;
#endif // __DEV
}
}
}
}
}
}
#if __DEV
// uiDebugf1("Had to change %d tiles this frame", iDebugTileSwap);
#endif // __DEV
vPreviousTile = vCurrentTile;
vPreviousTilesAroundPlayer = vTilesAroundPlayer;
#endif // __STREAMED_SUPERTILE_FILES
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap_RenderThread::RemoveGolfCourse
// PURPOSE:
/////////////////////////////////////////////////////////////////////////////////////
void CMiniMap_RenderThread::RemoveGolfCourse(bool bFromUpdateThreadInShutdownSession)
{
if (ms_iMovieId[MINIMAP_MOVIE_FOREGROUND] == -1)
return;
if (ms_asGolfCourseMc.IsDisplayObject())
{
ms_asGolfCourseMc.Invoke("removeMovieClip");
}
ms_asGolfCourseMc.SetUndefined();
ms_asGolfCourseMovie.SetUndefined();
ms_asGolfCourseHole.SetUndefined();
// remove the movie gfx
if (ms_iGolfCourseMovieId != -1)
{
ms_bRemoveGolfCourseMovie = true;
}
if (!bFromUpdateThreadInShutdownSession && !ms_MiniMapRenderState.m_bIsInPauseMap && !ms_MiniMapRenderState.m_bIsInCustomMap)
{
// Graeme - I'm not sure if this will work. MinimapModeState on the Update Thread is cleared every frame
// Can I call SetupForMiniMap() directly here?
// ms_MiniMapRenderState.m_MinimapModeState = MINIMAP_MODE_STATE_SETUP_FOR_MINIMAP;
SetupForMiniMap();
}
uiDebugf1("MiniMap: golf course removed from stage");
}
void CMiniMap_RenderThread::UpdateSea(bool bOn)
{
// turn the sea on/off
if (ms_asMapContainerMc.GFxValue::HasMember("sea"))
{
GFxValue seaMap;
ms_asMapContainerMc.GFxValue::GetMember("sea", &seaMap);
GFxValue::DisplayInfo info;
info.SetVisible(false);
seaMap.SetDisplayInfo(info);
}
g_RenderMinimapSea = bOn;
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap_RenderThread::UpdateGolfCourse
// PURPOSE: updates the minimap with any information golf courses
/////////////////////////////////////////////////////////////////////////////////////
void CMiniMap_RenderThread::UpdateGolfCourse()
{
if (!CSystem::IsThisThreadId(SYS_THREAD_RENDER)) // only on RT
{
sfAssertf(0, "CMiniMap_RenderThread::UpdateGolfCourse can only be called on the RenderThread!");
return;
}
if (ms_iMovieId[MINIMAP_MOVIE_FOREGROUND] == -1)
return;
eGOLF_COURSE_HOLES iCurrentGolfCourse = ms_MiniMapRenderState.m_CurrentGolfMap;
if (ms_iPreviousGolfCourse != iCurrentGolfCourse)
{
UpdateSea(iCurrentGolfCourse == GOLF_COURSE_OFF && !ms_MiniMapRenderState.m_bIsInPauseMap && !ms_MiniMapRenderState.m_bIsInCustomMap);
if (iCurrentGolfCourse != GOLF_COURSE_OFF)
{
if (ms_iPreviousGolfCourse != GOLF_COURSE_OFF)
{
ms_iPreviousGolfCourse = iCurrentGolfCourse;
RemoveGolfCourse(false);
}
ms_iPreviousGolfCourse = iCurrentGolfCourse;
ms_bStreamGolfCourseMovie = true;
}
else
{
ms_iPreviousGolfCourse = iCurrentGolfCourse;
RemoveGolfCourse(false);
}
}
if (ms_bStreamGolfCourseMovie || ms_bRemoveGolfCourseMovie)
return;
if (ms_iGolfCourseMovieId != -1)
{
if (CScaleformMgr::IsMovieActive(ms_iGolfCourseMovieId))
{
if ((!ms_asGolfCourseMovie.IsDisplayObject()) || (ms_asGolfCourseMovie.IsDisplayObject() && (ms_asGolfCourseHole.IsUndefined())))
{
if (ms_asGolfCourseMc.IsUndefined())
{
// invoke the load here
GFxValue result, asGolfCourseLayer, params[1];
params[0].SetString("golf_courses");
if (uiVerifyf(ms_asBaseOverlay3D[MINIMAP_LAYER_BACKGROUND].GetMember("asGolfCourseLayer", &asGolfCourseLayer), "cannot find 'asGolfCourseLayer' member"))
{
asGolfCourseLayer.CreateEmptyMovieClip(&ms_asGolfCourseMc, "GOLF_LINK", MOVIE_DEPTH_INTERIOR);
ms_asGolfCourseMc.Invoke("loadMovie", &result, params, 1);
ms_asGolfCourseHole.SetUndefined();
}
}
if (ms_asGolfCourseMc.IsDisplayObject())
{
if (ms_asGolfCourseMovie.IsDisplayObject())
{
eGOLF_COURSE_HOLES iCurrentGolfCourse = ms_MiniMapRenderState.m_CurrentGolfMap;
char cHashName[20];
if (iCurrentGolfCourse == GOLF_COURSE_HOLE_ALL)
{
formatf(cHashName, "hole_all");
}
else
{
formatf(cHashName, "hole_%u", iCurrentGolfCourse);
}
if (ms_asGolfCourseMovie.HasMember("golf_course"))
{
ms_asGolfCourseMovie.GetMember("golf_course", &ms_asGolfCourseHole);
ms_asGolfCourseHole.GotoAndStop(cHashName);
Vector2 vPos(-1170.0f, 50.0f);
// set the position:
GFxValue::DisplayInfo currentDisplayInfo;
currentDisplayInfo.SetPosition((vPos.x), -(vPos.y));
ms_asGolfCourseMovie.SetDisplayInfo(currentDisplayInfo);
if(!ms_MiniMapRenderState.m_bIsInPauseMap && !ms_MiniMapRenderState.m_bIsInCustomMap)
SetupGolfCourseLayout();
uiDebugf1("CMiniMap_RenderThread: golf course %s added to stage", cHashName);
}
else
{
uiDebugf1("CMiniMap_RenderThread: golf course data for %s is invalid - unable to set up golf course on stage", cHashName);
RemoveGolfCourse(false); // remove anything that was setup
ms_iPreviousGolfCourse = GOLF_COURSE_OFF;
}
}
else
{
uiDebugf1("CMiniMap_RenderThread: golf course movie is invalid!");
}
}
}
}
}
}
void CMiniMap_RenderThread::HandleGolfCourseAtEndOfFrame()
{
if (CSystem::IsThisThreadId(SYS_THREAD_RENDER)) // only on UT
{
sfAssertf(0, "CMiniMap_RenderThread::HandleGolfCourseAtEndOfFrame can only be called on the UpdateThread!");
return;
}
//
// removal/stream of golf course movie
//
if (ms_bRemoveGolfCourseMovie || ms_bStreamGolfCourseMovie)
{
if (ms_iGolfCourseMovieId != -1)
{
if (CScaleformMgr::IsMovieActive(ms_iGolfCourseMovieId))
{
CScaleformMgr::RequestRemoveMovie(ms_iGolfCourseMovieId);
}
ms_iGolfCourseMovieId = -1;
}
ms_bRemoveGolfCourseMovie = false;
}
if (ms_bStreamGolfCourseMovie)
{
ms_iGolfCourseMovieId = CScaleformMgr::CreateMovie(ms_MiniMapRenderState.m_CurrentMiniMapFilename, Vector2(0.0f, 0.0f), Vector2(1.0f, 1.0f), true, -1, -1, false);
ms_bStreamGolfCourseMovie = false;
}
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap_RenderThread::RenderNavPath
// PURPOSE: renders the nav path onto the minimap. This only needs to be called once
// as it adds the route on but doesnt need to be set every frame
/////////////////////////////////////////////////////////////////////////////////////
void CMiniMap_RenderThread::RenderNavPath(s32 iRouteNum, s32 iNumPoints, Vector3 *vPoints, rage::Color32 colour, float fOffsetX, float fOffsetY, bool bClipFirstLine, float fClipX, float fClipY, float fRoadWidthMiniMap, float fRoadWidthPauseMap)
{
// DMP
if (!CSystem::IsThisThreadId(SYS_THREAD_RENDER)) // only on RT
{
sfAssertf(0, "CMiniMap_RenderThread::RenderNavPath can only be called on the RenderThread!");
return;
}
if (ms_iMovieId[MINIMAP_MOVIE_FOREGROUND] == -1)
return;
static float PAUSE_MAP_INITIAL_SCALER = 0.01f;
// only render the route once its invisible:
GFxValue::DisplayInfo info;
ms_asGpsLayer[iRouteNum].GetDisplayInfo(&info);
if (info.GetVisible())
{
ms_asGpsLayer[iRouteNum].Invoke("clear");
info.SetVisible(false);
ms_asGpsLayer[iRouteNum].SetDisplayInfo(info);
}
uiDebugf1("CMiniMap_RenderThread: Redrawing GPS route %d", iRouteNum);
GFxValue args[3];
if (!ms_MiniMapRenderState.m_bIsInPauseMap && !ms_MiniMapRenderState.m_bIsInCustomMap) // different road widths (due to scale) when in minimap or pausemap
{
args[0].SetNumber(fRoadWidthMiniMap);
}
else
{
args[0].SetNumber((fRoadWidthPauseMap * PAUSE_MAP_INITIAL_SCALER) * (CMiniMap_Common::GetScaleFromZoomLevel(ZOOM_LEVEL_4)-rage::Min(30.0f,ms_MiniMapRenderState.m_fPauseMapScale)));
}
args[1].SetNumber(colour.GetColor());
args[2].SetNumber(colour.GetAlphaf()*100.0f);
//uiDebugf1("lineStyle %0.2f, %0.2f, %0.2f", args[0].GetNumber(), args[1].GetNumber(), args[2].GetNumber());
ms_asGpsLayer[iRouteNum].Invoke("lineStyle", NULL, args, 3);
int iLastValidNode = 0;
if (iNumPoints > 0)
{
for (s32 i = 1; i < iNumPoints; i++)
{
if ((*(int*)&vPoints[i].w) == GNI_IGNORE_FOR_NAV)
continue;
Vector2 vMain = Vector2(vPoints[i].x+fOffsetX, vPoints[i].y+fOffsetY);
if (iLastValidNode == 0)
{
iLastValidNode = i;
Vector2 vLink(vPoints[0].x+fOffsetX, vPoints[0].y+fOffsetY);
if (bClipFirstLine)
{
Vector2 diff = vLink - vMain;
float length = diff.Mag();
Vector2 diffClip = Vector2(fClipX, fClipY) - vMain;
float lengthAlongLine = (diffClip.x * diff.x + diffClip.y * diff.y) / length;
lengthAlongLine = rage::Max(0.0f, lengthAlongLine);
if (lengthAlongLine < length)
{
// reduced line segment.
vLink = vMain + diff * (lengthAlongLine / length);
}
}
if ((*(int*)&vPoints[0].w) == GNI_PLAYER_TRAIL_POS) // Adding extra point
{
args[0].SetNumber(fClipX+fOffsetX);
args[1].SetNumber(-(fClipY+fOffsetY));
ms_asGpsLayer[iRouteNum].Invoke("moveTo", NULL, args, 2);
args[0].SetNumber(vLink.x);
args[1].SetNumber(-vLink.y);
//uiDebugf1("0 moveTo %0.2f, %0.2f", vLink.x, -vLink.y);
ms_asGpsLayer[iRouteNum].Invoke("lineTo", NULL, args, 2);
}
else
{
args[0].SetNumber(vLink.x);
args[1].SetNumber(-vLink.y);
//uiDebugf1("0 moveTo %0.2f, %0.2f", vLink.x, -vLink.y);
ms_asGpsLayer[iRouteNum].Invoke("moveTo", NULL, args, 2);
}
args[0].SetNumber(vMain.x);
args[1].SetNumber(-vMain.y);
//uiDebugf1("1 lineTo %0.2f, %0.2f", vMain.x, -vMain.y);
ms_asGpsLayer[iRouteNum].Invoke("lineTo", NULL, args, 2);
}
else
{
args[0].SetNumber(vMain.x);
args[1].SetNumber(-vMain.y);
ms_asGpsLayer[iRouteNum].Invoke("lineTo", NULL, args, 2);
if ((*(int*)&vPoints[i].w) == GNI_PLAYER_TRAIL_POS) // Adding extra point
{
args[0].SetNumber(vPoints[i+1].x+fOffsetX);
args[1].SetNumber(-(vPoints[i+1].y+fOffsetY));
ms_asGpsLayer[iRouteNum].Invoke("lineTo", NULL, args, 2);
}
//uiDebugf1("%d lineTo %0.2f, %0.2f", i, vMain.x, -vMain.y);
}
}
}
// make the layer visible again now the route has been drawn
info.SetVisible(true);
ms_asGpsLayer[iRouteNum].SetDisplayInfo(info);
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap_RenderThread::ClearNavPath
// PURPOSE: clears any nav path from the minimap
/////////////////////////////////////////////////////////////////////////////////////
void CMiniMap_RenderThread::ClearNavPath(s32 iRouteNum)
{
if (!CSystem::IsThisThreadId(SYS_THREAD_RENDER)) // only on RT
{
sfAssertf(0, "CMiniMap_RenderThread::ClearNavPath can only be called on the RenderThread!");
return;
}
if (ms_iMovieId[MINIMAP_MOVIE_FOREGROUND] == -1)
return;
// only invoke "clear" when the route is visible:
GFxValue::DisplayInfo info;
ms_asGpsLayer[iRouteNum].GetDisplayInfo(&info);
if (info.GetVisible())
{
// set to invisible and clear and dont set visible again (render will do this if a new route is set)
info.SetVisible(false);
ms_asGpsLayer[iRouteNum].SetDisplayInfo(info);
uiDebugf1("CMiniMap_RenderThread: Clearing GPS route %d", iRouteNum);
ms_asGpsLayer[iRouteNum].Invoke("clear");
}
}
Mat34V ToMat34V(GMatrix3D mtx)
{
return Mat34V(V_COL_MAJOR,
mtx[0], mtx[1], mtx[2],
mtx[4], mtx[5], mtx[6],
mtx[8], mtx[9], mtx[10],
mtx[12], mtx[13], mtx[14]
);
}
Mat44V ToMat44V(GMatrix3D mtx)
{
return Mat44V(V_COL_MAJOR,
mtx[0], mtx[1], mtx[2], mtx[3],
mtx[4], mtx[5], mtx[6], mtx[7],
mtx[8], mtx[9], mtx[10], mtx[11],
mtx[12], mtx[13], mtx[14], mtx[15]
);
}
void MakeOrthoMtx(Mat44V_InOut outMtx, float left, float right, float bottom, float top, float znear, float zfar)
{
// Stole
float oorl = 1.0f / (right - left);
float ootb = 1.0f / (top - bottom);
float oolr = 1.0f / (left - right);
float oobt = 1.0f / (bottom - top);
float cz, dz;
// D3DXMatrixOrthoOffCenterRH
cz = 1 / (znear-zfar);
dz = znear / (znear - zfar);
//
// taken from the D3D documentation
//
// 2/(r-l) 0 0 0
// 0 2/(t-b) 0 0
// 0 0 1/(zn-zf) 0
// (l+r)/(l-r) (t+b)/(b-t) zn/(zn-zf) l
//
// shearing sets it off in the x direction and / or in the y direction
// scaling makes it bigger in the x or y direction
//
Vector2 scale = grcViewport::GetCurrent()->GetWidthHeightScale();
Vector2 shear = grcViewport::GetCurrent()->GetPerspectiveShear();
Mat44V projection;
projection.SetCol0f(2 * oorl * scale.x, 0.0f, 0.0f, 0.0f);
projection.SetCol1f(0.0f, 2 * ootb * scale.y, 0.0f, 0.0f);
projection.SetCol2f(shear.x, shear.y, cz, 0.0f);
projection.SetCol3f((left + right) * oolr,(top + bottom) * oobt, dz, 1.0f);
outMtx = projection;
}
void CMiniMap_RenderThread::SetupStateForSupertileRender(Vector2 vBackgroundPos, Vector2 vBackgroundSize)
{
const float Drawable_zFar = 13.0f;
const float Drawable_zNear = -13.0f;
const bool Scissor = true;
GFxMovieView* pView = CScaleformMgr::GetMovieView(ms_iMovieId[MINIMAP_MOVIE_BACKGROUND]);
if (pView)
{
int clipX = 0;
int clipY = 0;
int clipW = VideoResManager::GetUIWidth();
int clipH = VideoResManager::GetUIHeight();
int totalWidth = clipW;
int totalHeight = clipH;
float mapWidth = (float)totalWidth;
float mapHeight = (float)totalHeight;
int offsetX = 0;
int offsetY = 0;
bool doMiniMapAlpha = ( (!ms_MiniMapRenderState.m_bIsInPauseMap) && (!ms_MiniMapRenderState.m_bIsInCustomMap) && (ms_MiniMapAlpha < 1.0f) && (ms_MiniMapRenderState.m_CurrentGolfMap == GOLF_COURSE_OFF) );
if (doMiniMapAlpha)
{
Vector2 maskPos,maskSize;
if( ms_bUseTexturedAlphaAllMovies || ms_bUseTextureAlphaBaseMovie )
{
maskPos = ms_MiniMapRenderState.m_vCurrentMiniMapBlurPosition;
maskSize = ms_MiniMapRenderState.m_vCurrentMiniMapBlurSize;
}
else
{
maskPos = ms_MiniMapRenderState.m_vCurrentMiniMapMaskPosition;
maskSize = ms_MiniMapRenderState.m_vCurrentMiniMapMaskSize;
}
clipX = Clamp(rage::round((maskPos.x)*mapWidth) - 1 + offsetX, 0, totalWidth);
clipY = Clamp(rage::round((maskPos.y)*mapHeight) - 1 + offsetY, 0, totalHeight);
clipW = Clamp(rage::round((maskSize.x)*mapWidth) + 1, 0, totalWidth - clipX);
clipH = Clamp(rage::round((maskSize.y)*mapHeight) + 1, 0, totalHeight - clipY);
}
else if (vBackgroundSize.x > 0.0f && vBackgroundSize.y > 0.0f)
{
// the in-game map seems to be already adjusted, fixing the pause map here
#if SUPPORT_MULTI_MONITOR
if(ms_MiniMapRenderState.m_bIsInPauseMap )
{
const GridMonitor &mon = GRCDEVICE.GetMonitorConfig().getLandscapeMonitor();
mapWidth = (float)mon.getWidth();
mapHeight = (float)mon.getHeight();
offsetX = mon.uLeft;
offsetY = mon.uTop;
}
#endif //SUPPORT_MULTI_MONITOR
if (Scissor)
{
clipX = Clamp(rage::round(mapWidth * vBackgroundPos.x) + offsetX, 0, totalWidth);
clipY = Clamp(rage::round(mapHeight * vBackgroundPos.y) + offsetY, 0, totalHeight);
clipW = Clamp(rage::round(mapWidth * vBackgroundSize.x), 0, totalWidth - clipX);
clipH = Clamp(rage::round(mapHeight * vBackgroundSize.y), 0, totalHeight - clipY);
}
}
grcBindTexture(NULL);
grcWorldIdentity();
GRCDEVICE.SetDefaultEffect(false,false);
GRCDEVICE.SetScissor(clipX, clipY, clipW, clipH);
if (g_RenderMinimapSea)
{
// bug in repeated ClearRenderTargetView calls so use ClearRect
GRCDEVICE.ClearRect(clipX, clipY, clipW, clipH, true, g_MinimapSeaColor, false, 0.0f, false, 0, true); // fix for 1763187
}
Mat34V camera(V_IDENTITY);
grcViewport::GetCurrent()->SetCameraMtx(camera);
// Set the projection matrix to the scaleform world-to-screen projection matrix, concatenated with
// the rage ortho screen matrix.
GMatrix3D worldToScreen = ms_LocalToScreen.GetRenderBuf();
{
GMatrix3D flipY;
flipY.Scaling(1.0f, -1.0f, 1.0f);
worldToScreen.Prepend(flipY);
}
Mat44V worldToScreenRage = ToMat44V(worldToScreen);
Mat44V orthoScreen;
MakeOrthoMtx(orthoScreen, 0.0, (float)totalWidth, (float)totalHeight, 0.0, Drawable_zNear, Drawable_zFar);
#if SUPPORT_MULTI_MONITOR && 0
// this is already taken care of
if (GRCDEVICE.GetMonitorConfig().isMultihead())
{
const GridMonitor &mon = GRCDEVICE.GetMonitorConfig().getLandscapeMonitor();
// computing the center difference of the preferred monitor versus the whole screen
const float ox = (mon.uLeft + mon.uRight)/mapWidth - 1.f;
const float oy = 1.f - (mon.uTop + mon.uBottom)/mapHeight;
Mat44V monMx(
mon.getWidth() / mapWidth, 0.0, 0.0, 0.0,
0.0, mon.getHeight() / mapHeight, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
ox, oy, 0.0, 1.0
);
Mat44V old = orthoScreen;
Multiply(orthoScreen, monMx, old);
}
#endif //SUPPORT_MULTI_MONITOR
// Now one additional transform to move from screen space to render target space
Mat44V proj;
Multiply(proj, orthoScreen, worldToScreenRage);
grcViewport::GetCurrent()->SetNearFarClip(Drawable_zNear, Drawable_zFar);
grcViewport::GetCurrent()->SetProjection(proj);
CShaderLib::SetGlobalToneMapScalers(Vector4(1.0, 1.0, 1.0, 1.0));
CShaderLib::SetGlobalAlpha(1.0f);
grcLightState::SetEnabled(false);
grcStateBlock::SetDepthStencilState(grcStateBlock::DSS_IgnoreDepth);
grcStateBlock::SetBlendState(grcStateBlock::BS_Normal);
grcStateBlock::SetRasterizerState(grcStateBlock::RS_NoBackfaceCull);
}
}
namespace rage
{
extern grcEffect *g_DefaultEffect;
extern grcEffectVar g_DefaultSampler;
}
void CMiniMap_RenderThread::RenderBitmaps()
{
#if 0 // Causes asserts since this is on the render thread
TUNE_GROUP_FLOAT(MINIMAP, AdjustBitmapX, 0.0f, -100.0f, 100.0f, 0.01f);
TUNE_GROUP_FLOAT(MINIMAP, AdjustBitmapY, 0.0f, -100.0f, 100.0f, 0.01f);
TUNE_GROUP_FLOAT(MINIMAP, AdjustBitmapWidth, 1.0f, 0.0f, 2.0f, 0.0001f);
TUNE_GROUP_FLOAT(MINIMAP, AdjustBitmapHeight, 1.0f, 0.0f, 2.0f, 0.0001f);
TUNE_GROUP_BOOL(MINIMAP, PointSampler, false);
#else
#if __DEV
const bool PointSampler = false;
#endif
// I found these values experimentally, but what are they? Maybe related to texel size (and zooming up by 1/1024)?
const float AdjustBitmapX = 0.0f;
const float AdjustBitmapY = 0.0f;
const float AdjustBitmapWidth = 1.0f;
const float AdjustBitmapHeight = 1.0f;
#endif
grcSamplerStateHandle oldSampler = g_DefaultEffect->GetSamplerState(g_DefaultSampler);
#if __DEV
if (PointSampler)
{
g_DefaultEffect->SetSamplerState(g_DefaultSampler, ms_MinimapBitmapSamplerStateNearestHandle);
}
else
#endif
{
g_DefaultEffect->SetSamplerState(g_DefaultSampler, ms_MinimapBitmapSamplerStateHandle);
}
grcStateBlock::SetRasterizerState(ms_MinimapBitmapRasterizerStateHandle);
strLocalIndex iLodTxdId = strLocalIndex(CMiniMap::ms_BitmapSuperLowRes.iDrawIdx.GetReadBuf());
if (iLodTxdId.Get() >= 0)
{
Vector2 bitmapPos = CMiniMap::sm_Tunables.Bitmap.vBitmapStart;
fwTxd* txd = g_TxdStore.Get(iLodTxdId);
if (uiVerifyf(txd, "Couldn't find a txd but we're in an active state. %d", iLodTxdId.Get()))
{
// grab the first texture in the dict (cause we don't know the name)
grcTexture* tex = txd->GetEntry(0);
if (uiVerifyf(tex, "Empty texture dictionary? %d", iLodTxdId.Get()))
{
grcBindTexture(tex);
CSprite2d::Draw(
bitmapPos + Vector2(0.0f, -CMiniMap::sm_Tunables.Bitmap.vBitmapTileSize.y * CMiniMap::sm_Tunables.Bitmap.iBitmapTilesY),
bitmapPos + Vector2(0.0f, 0.0f),
bitmapPos + Vector2(CMiniMap::sm_Tunables.Bitmap.vBitmapTileSize.x * CMiniMap::sm_Tunables.Bitmap.iBitmapTilesX, -CMiniMap::sm_Tunables.Bitmap.vBitmapTileSize.y * CMiniMap::sm_Tunables.Bitmap.iBitmapTilesY),
bitmapPos + Vector2(CMiniMap::sm_Tunables.Bitmap.vBitmapTileSize.x * CMiniMap::sm_Tunables.Bitmap.iBitmapTilesX, 0.0f),
Color_white);
}
}
}
for (s32 a = 0; a < MM_BITMAP_VERSION_NUM_ENUMS; a++)
{
float BitmapTileSizeX, BitmapTileSizeY, BitmapStartX, BitmapStartY;
BitmapTileSizeX = CMiniMap::sm_Tunables.Bitmap.vBitmapTileSize.x * AdjustBitmapWidth;
BitmapTileSizeY = CMiniMap::sm_Tunables.Bitmap.vBitmapTileSize.y * AdjustBitmapHeight;
BitmapStartX = CMiniMap::sm_Tunables.Bitmap.vBitmapStart.x + AdjustBitmapX;
BitmapStartY = CMiniMap::sm_Tunables.Bitmap.vBitmapStart.y + AdjustBitmapY;
Vector2 corners[4];
corners[0].Set(0.0f, -BitmapTileSizeY);
corners[1].Set(0.0f, 0.0f);
corners[2].Set(BitmapTileSizeX, -BitmapTileSizeY);
corners[3].Set(BitmapTileSizeX, 0.0f);
for (s32 i = 0; i < CMiniMap::sm_Tunables.Bitmap.iBitmapTilesX; i++)
{
for (s32 j = 0; j < CMiniMap::sm_Tunables.Bitmap.iBitmapTilesY; j++)
{
strLocalIndex iTxdId = strLocalIndex(CMiniMap::ms_BitmapBackground(a,i,j).iDrawIdx.GetReadBuf());
if (iTxdId.Get() >= 0)
{
Vector2 bitmapPos(BitmapStartX + i * BitmapTileSizeX, BitmapStartY - j * BitmapTileSizeY);
fwTxd* txd = g_TxdStore.Get(iTxdId);
if (uiVerifyf(txd, "Couldn't find a txd but we're in an active state. %d", iTxdId.Get()))
{
// grab the first texture in the dict (cause we don't know the name)
grcTexture* tex = txd->GetEntry(0);
if (uiVerifyf(tex, "Empty texture dictionary? %d", iTxdId.Get()))
{
grcBindTexture(tex);
CSprite2d::Draw(
bitmapPos + corners[0],
bitmapPos + corners[1],
bitmapPos + corners[2],
bitmapPos + corners[3],
Color_white
);
}
}
}
}
}
}
g_DefaultEffect->SetSamplerState(g_DefaultSampler, oldSampler);
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap_RenderThread::Render
// PURPOSE: renders the minimap
/////////////////////////////////////////////////////////////////////////////////////
void CMiniMap_RenderThread::RenderMiniMap(s32 iId, Vector2 vBackgroundPos, Vector2 vBackgroundSize, float fAlpha, float fSizeScalar)
{
if (!ms_MiniMapRenderState.m_bIsActive)
return;
if (ms_iMovieId[iId] == -1)
return;
PF_AUTO_PUSH_TIMEBAR(iId == MINIMAP_MOVIE_BACKGROUND ? "RenderMiniMap - background" : "RenderMiniMap - foreground");
#if RSG_PC
if (GRCDEVICE.IsStereoEnabled() && GRCDEVICE.CanUseStereo())
{
//float fVal = 0.0f;
//if (iId == MINIMAP_MOVIE_BACKGROUND)
// fVal = 1.0f;
GRCDEVICE.SetStereoScissor(false);
CShaderLib::SetStereoParams(Vector4(1.0f,0.0f,0.0f,0.0f));
}
#endif
if (BANK_ONLY(CMiniMap::ms_bRenderMiniMapBackground &&) iId == MINIMAP_MOVIE_BACKGROUND)
{
if ( (g_RenderMinimap) &&
( (ms_MiniMapRenderState.m_CurrentGolfMap == GOLF_COURSE_OFF) ||
(ms_MiniMapRenderState.m_bIsInPauseMap || ms_MiniMapRenderState.m_bIsInCustomMap) ) )
{
grcViewport oldVP = *grcViewport::GetCurrent();
SetupStateForSupertileRender(vBackgroundPos, vBackgroundSize);
RenderBitmaps();
ms_Supertiles.Render();
#if ENABLE_FOG_OF_WAR
if( ms_MiniMapRenderState.m_bShowFow && !CTheScripts::GetIsInDirectorMode())
{
CSprite2d fowRender;
grcRenderTarget *fow = CMiniMap_Common::GetFogOfWarCopyRT();
grcStateBlock::SetBlendState(ms_MinimapFoWBlendStateHandle);
fowRender.SetGeneralParams(Vector4(1.0f, 0.0f, 0.0f, 0.0f), Vector4(CMiniMap::sm_Tunables.FogOfWar.fBaseAlpha, CMiniMap::sm_Tunables.FogOfWar.fTopAlpha, 0.0, 0.0));
fowRender.SetTexelSize(Vector2(1.0f/((float)fow->GetWidth()),1.0f/((float)fow->GetHeight())));
fowRender.BeginCustomList(CSprite2d::CS_BLIT_TO_ALPHA_BLUR, fow);
ms_Supertiles.RenderFoW();
fowRender.EndCustomList();
grcStateBlock::SetBlendState(grcStateBlock::BS_Default);
}
#endif // ENABLE_FOG_OF_WAR
*grcViewport::GetCurrent() = oldVP;
}
}
#if __BANK
if ((CMiniMap::ms_bRenderMiniMapBackground && iId == MINIMAP_MOVIE_BACKGROUND) || (CMiniMap::ms_bRenderMiniMapForeground && iId == MINIMAP_MOVIE_FOREGROUND))
#endif
{
if( iId == MINIMAP_MOVIE_BACKGROUND ) // Disable AA only for the map itself
{
CScaleformMgr::GetMovieMgr()->SetEdgeAAEnable(false);
}
const float fTimeStep = CLiveManager::IsSystemUiShowing() ? -1.0f : fwTimer::GetTimeStep_NonPausedNonScaledClipped();
if (ms_MiniMapRenderState.m_bIsInPauseMap/* || ms_MiniMapRenderState.m_bIsInCustomMap*/) // fix for 1503078
{
CScaleformMgr::AffectRenderSizeOnly(ms_iMovieId[iId], fSizeScalar);
}
CScaleformMgr::RenderMovie(ms_iMovieId[iId], fTimeStep, true, false, fAlpha);
if( iId == MINIMAP_MOVIE_BACKGROUND )
{
CScaleformMgr::GetMovieMgr()->SetEdgeAAEnable(true);
}
#if ENABLE_FOG_OF_WAR
// NOTES: only enable this when rendering the island minimap
if( iId == MINIMAP_MOVIE_BACKGROUND && ms_MiniMapRenderState.m_bShowFow && !CTheScripts::GetIsInDirectorMode())
{
grcViewport oldVP = *grcViewport::GetCurrent();
SetupStateForSupertileRender(vBackgroundPos, vBackgroundSize);
{
CSprite2d fowRender;
grcRenderTarget *fow = CMiniMap_Common::GetFogOfWarCopyRT();
grcStateBlock::SetBlendState(ms_MinimapFoWBlendStateHandle);
fowRender.SetGeneralParams(Vector4(1.0f, 0.0f, 0.0f, 0.0f), Vector4(CMiniMap::sm_Tunables.FogOfWar.fBaseAlpha, CMiniMap::sm_Tunables.FogOfWar.fTopAlpha, 0.0, 0.0));
fowRender.SetTexelSize(Vector2(1.0f/((float)fow->GetWidth()),1.0f/((float)fow->GetHeight())));
fowRender.BeginCustomList(CSprite2d::CS_BLIT_TO_ALPHA_BLUR, fow);
CSupertile::RenderIslandFoW(); // 1 tile over whole Island map
fowRender.EndCustomList();
grcStateBlock::SetBlendState(grcStateBlock::BS_Default);
}
*grcViewport::GetCurrent() = oldVP;
}
#endif // ENABLE_FOG_OF_WAR
}
#if RSG_PC
if (GRCDEVICE.IsStereoEnabled() && GRCDEVICE.CanUseStereo())
{
//float fVal = 0.0f;
//if (iId == MINIMAP_MOVIE_BACKGROUND)
// fVal = 1.0f;
GRCDEVICE.SetStereoScissor(true);
CShaderLib::SetStereoParams(Vector4(0.0f,0.0f,0.0f,0.0f));
}
#endif
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap_RenderThread::CanDisplayGpsLine
// PURPOSE: returns whether the gps line can be displayed based on current minimap
// settings (zoom etc)
/////////////////////////////////////////////////////////////////////////////////////
bool CMiniMap_RenderThread::CanDisplayGpsLine(bool bHideWhenZoomed)
{
if (!CSystem::IsThisThreadId(SYS_THREAD_RENDER)) // only on RT
{
sfAssertf(0, "CMiniMap_RenderThread::CanDisplayGpsLine can only be called on the RenderThread!");
return true;
}
if (ms_MiniMapRenderState.m_iScriptZoomValue != 0 || ms_MiniMapRenderState.m_bLockedToDistanceZoom) // always display GPS line regardless of zoom level if script are setting it as its assumed they are in control of the value they are passing
return true;
if ( (ms_MiniMapRenderState.m_fAngle == 0.0f) && (!ms_MiniMapRenderState.m_bIsInBigMap) && (!ms_MiniMapRenderState.m_bIsInPauseMap) && (!ms_MiniMapRenderState.m_bIsInCustomMap) ) // no gps when at no angle and not in pausemap
return false;
if (ms_asMapContainerMc.IsDisplayObject())
{
if(bHideWhenZoomed)
{
GFxValue::DisplayInfo CurrInfo;
ms_asMapContainerMc.GetDisplayInfo(&CurrInfo);
if ((float)CurrInfo.GetXScale() <= MINIMAP_GPS_DISPLAY_LIMIT)
{
return true;
}
}
else
{
return true;
}
}
return false;
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap_RenderThread::SetupHealthArmourOnStage
// PURPOSE: sets up the health and armour containers if required
/////////////////////////////////////////////////////////////////////////////////////
void CMiniMap_RenderThread::SetupHealthArmourOnStage(bool bBigMapProperties)
{
GFxValue asHealthContainer;
if (uiVerifyf(ms_asRootContainer[MINIMAP_ROOT_LAYER_UNMASKED].GetMember("asHealthContainer", &asHealthContainer), "CMiniMap_RenderThread: 'asHealthContainer' cannot be found when switching to minimap"))
{
if (uiVerifyf(asHealthContainer.IsDisplayObject(), "CMiniMap_RenderThread: 'asHealthContainer' is not a display object when switching to minimap"))
{
GFxValue::DisplayInfo healthContainerDisplayInfo;
healthContainerDisplayInfo.SetVisible(true);
asHealthContainer.SetDisplayInfo(healthContainerDisplayInfo);
if (CScaleformMgr::BeginMethod(ms_iMovieId[MINIMAP_MOVIE_FOREGROUND], SF_BASE_CLASS_MINIMAP, "REGISTER_HEALTH_ARMOUR"))
{
CScaleformMgr::AddParamGfxValue(asHealthContainer);
CScaleformMgr::EndMethod(true);
}
if (CScaleformMgr::BeginMethod(ms_iMovieId[MINIMAP_MOVIE_FOREGROUND], SF_BASE_CLASS_MINIMAP, "SETUP_HEALTH_ARMOUR"))
{
if (bBigMapProperties)
{
CScaleformMgr::AddParamInt(2);
}
else
{
CScaleformMgr::AddParamInt(1);
}
CScaleformMgr::EndMethod(true);
}
CNewHud::ForceUpdateHealthInfoWithExistingValuesOnRT(); // fixes 1829470 (need to update health/armour bars straight away, instead of next frame)
#if !__FINAL
if(CMiniMap_Common::OutputDebugTransitions())
{
if (bBigMapProperties)
uiDisplayf("MINIMAP_TRANSITION: CMiniMap_RenderThread::SetupHealthArmourOnStage. Setup actionscript for BIGMAP properties(RT)");
else
uiDisplayf("MINIMAP_TRANSITION: CMiniMap_RenderThread::SetupHealthArmourOnStage. Setup actionscript for MINIMAP properties(RT)");
}
#endif
}
}
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap_RenderThread::SetupForGalleryMap
// PURPOSE: sets the map to be in "gallery" mode
/////////////////////////////////////////////////////////////////////////////////////
void CMiniMap_RenderThread::SetupForGalleryMap()
{
if (!CSystem::IsThisThreadId(SYS_THREAD_RENDER)) // only on RT
{
sfAssertf(0, "CMiniMap_RenderThread::SetupForGalleryMap can only be called on the RenderThread!");
return;
}
#if __DEV
iTimeTaken = fwTimer::GetSystemTimeInMilliseconds();
#endif // __DEV
// Graeme - we can't call SetCurrentGolfMap() on the RenderThread so instead MiniMapUpdateState.m_CurrentGolfMap is set to GOLF_COURSE_OFF in CMiniMap::UpdateStatesOnUT() if IsInBigMap()
// turn off the golf course if it has been set:
// if (ms_MiniMapRenderState.m_CurrentGolfMap != GOLF_COURSE_OFF) // ensure golf course is turned off if bigmap becomes active
// {
// SetCurrentGolfMap(GOLF_COURSE_OFF);
// }
SetupHealthArmourOnStage(true);
// default the intial zoom value to starting pausemap scale
GFxValue::DisplayInfo info;
info.SetScale(ms_MiniMapRenderState.m_fPauseMapScale, ms_MiniMapRenderState.m_fPauseMapScale);
ms_asMapContainerMc.SetDisplayInfo(info);
ms_asBlipContainerMc.SetDisplayInfo(info);
SetMask(true);
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);
}
// re-init the nav (so it changes for pausemap vs radar)
CGps::ForceUpdateOfGpsOnMiniMap();
UpdateSea(false);
UpdateWithActionScriptOnRT(true, false);
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap_RenderThread::SetupForPauseMenu
// PURPOSE: sets the map to be in "pausemap" mode
/////////////////////////////////////////////////////////////////////////////////////
void CMiniMap_RenderThread::SetupForPauseMenu(bool bFullScreen)
{
if (!CSystem::IsThisThreadId(SYS_THREAD_RENDER)) // only on RT
{
sfAssertf(0, "CMiniMap_RenderThread::SetupForPauseMenu can only be called on the RenderThread!");
return;
}
AdjustVisualStageSpaceWithinMovie(0.0f);
#if __DEV
iTimeTaken = fwTimer::GetSystemTimeInMilliseconds();
#endif // __DEV
ms_vStageSize = ms_vOriginalStageSize;
float fScaler = 100.0f;
if (bFullScreen)
{
float fMapRatio = ms_vOriginalStageSize.x / ms_vOriginalStageSize.y;
fScaler *= fMapRatio/CHudTools::GetAspectRatio();
ms_vStageSize.x /= (fScaler/100.0f);
GFxValue asCrosshairMc;
if( ms_asRootContainer[MINIMAP_ROOT_LAYER_UNMASKED].GetMember("asCrosshair", &asCrosshairMc) )
{
GFxValue::DisplayInfo dispInfo;
dispInfo.SetPosition(ms_vStageSize.x*0.5f, ms_vStageSize.y*0.5f);
asCrosshairMc.SetDisplayInfo(dispInfo);
}
}
for (s32 i = 0; i < MAX_MINIMAP_ROOT_LAYERS; i++)
{
GFxValue::DisplayInfo dispInfo;
dispInfo.SetScale(fScaler, 100.0f);
ms_asRootContainer[i].SetDisplayInfo(dispInfo);
}
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);
CScaleformMgr::ResetMeshCache();
// default the intial zoom value to starting pausemap scale
GFxValue::DisplayInfo info2;
info2.SetScale(ms_MiniMapRenderState.m_fPauseMapScale, ms_MiniMapRenderState.m_fPauseMapScale);
ms_asMapContainerMc.SetDisplayInfo(info2);
ms_asBlipContainerMc.SetDisplayInfo(info2);
GFxValue asHealthContainer;
if (uiVerifyf(ms_asRootContainer[MINIMAP_ROOT_LAYER_UNMASKED].GetMember("asHealthContainer", &asHealthContainer), "CMiniMap_RenderThread: 'asHealthContainer' cannot be found when switching to pausemap"))
{
if (uiVerifyf(asHealthContainer.IsDisplayObject(), "CMiniMap_RenderThread: 'asHealthContainer' is not a display object when switching to pausemenu"))
{
GFxValue::DisplayInfo healthContainerDisplayInfo;
healthContainerDisplayInfo.SetVisible(false);
asHealthContainer.SetDisplayInfo(healthContainerDisplayInfo);
}
}
GFxValue mainMap;
ms_asMapObject.GFxValue::GetMember("main_map", &mainMap);
GFxValue::DisplayInfo mapDisplayInfo;
mapDisplayInfo.SetVisible(true);
mainMap.SetDisplayInfo(mapDisplayInfo);
g_RenderMinimap = true;
GFxValue asSonarBlipLayer;
if (ms_asBaseOverlay3D[MINIMAP_LAYER_FOREGROUND].GetMember("asSonarBlipLayer", &asSonarBlipLayer))
{
GFxValue::DisplayInfo SonarLayerDisplayInfo;
SonarLayerDisplayInfo.SetVisible(false);
asSonarBlipLayer.SetDisplayInfo(SonarLayerDisplayInfo);
}
SetMask(true);
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); // make it fill the screen in 4:3
}
// re-init the nav (so it changes for pausemap vs radar)
CGps::ForceUpdateOfGpsOnMiniMap();
UpdateSea(false);
UpdateWithActionScriptOnRT(true, false);
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap_RenderThread::AdjustVisualStageSpaceWithinMovie
// PURPOSE: adjusts the contents of the movie by X amount of pixels in order for
// it to appear in the correct place onscreen even though it has a huge
// mask
/////////////////////////////////////////////////////////////////////////////////////
void CMiniMap_RenderThread::AdjustVisualStageSpaceWithinMovie(float fAmount)
{
// move the map across
GFxValue::DisplayInfo rootContainerDisplayInfo6;
rootContainerDisplayInfo6.SetX(-fAmount);
ms_asRootContainer[MINIMAP_ROOT_LAYER_MASKED].SetDisplayInfo(rootContainerDisplayInfo6);
GFxValue::DisplayInfo rootContainerDisplayInfo5;
rootContainerDisplayInfo5.SetX(-fAmount);
ms_asRootContainer[MINIMAP_ROOT_MAP_TRANSPARENT].SetDisplayInfo(rootContainerDisplayInfo5);
// move the health container (frame) across
GFxValue asHealthContainer;
if (uiVerifyf(ms_asRootContainer[MINIMAP_ROOT_LAYER_UNMASKED].GetMember("asHealthContainer", &asHealthContainer), "CMiniMap_RenderThread: 'asHealthContainer' cannot be found when adjustingVisualSpace"))
{
if (uiVerifyf(asHealthContainer.IsDisplayObject(), "CMiniMap_RenderThread: 'asHealthContainer' is not a display object when adjustingVisualSpace"))
{
GFxValue::DisplayInfo healthContainerDisplayInfo;
healthContainerDisplayInfo.SetX(-fAmount);
asHealthContainer.SetDisplayInfo(healthContainerDisplayInfo);
}
}
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap_RenderThread::SetupForMiniMap
// PURPOSE: sets the map to be in "minimap" mode
/////////////////////////////////////////////////////////////////////////////////////
void CMiniMap_RenderThread::SetupForMiniMap()
{
SetupMiniMapProperties(false); // no bigmap
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap_RenderThread::SetupForBigMap
// PURPOSE: sets the map to be in "bigmap" mode
/////////////////////////////////////////////////////////////////////////////////////
void CMiniMap_RenderThread::SetupForBigMap()
{
SetupMiniMapProperties(true); // minimap with bigmap style
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap_RenderThread::SetupMiniMapProperties
// PURPOSE: sets the map properties
/////////////////////////////////////////////////////////////////////////////////////
void CMiniMap_RenderThread::SetupMiniMapProperties(bool bBigMapProperties)
{
if (!CSystem::IsThisThreadId(SYS_THREAD_RENDER)) // only on RT
{
sfAssertf(0, "CMiniMap_RenderThread::SetupForMiniMap can only be called on the RenderThread!");
return;
}
if (bBigMapProperties)
{
#if !__FINAL
if(CMiniMap_Common::OutputDebugTransitions())
uiDisplayf("MINIMAP_TRANSITION: CMiniMap_RenderThread::SetupMiniMapProperties. bBigMapProperties = TRUE (RT)");
#endif
AdjustVisualStageSpaceWithinMovie(__BIGMAP_INTERNAL_ADJUSTMENT_CONTAINERS); // we need to move the bigmap 34 pixels to avoid putting the movie offscreen whilst making it appear to be the same position of the minimap onscreen
}
else
{
#if !__FINAL
if(CMiniMap_Common::OutputDebugTransitions())
uiDisplayf("MINIMAP_TRANSITION: CMiniMap_RenderThread::SetupMiniMapProperties. bBigMapProperties = FALSE (RT)");
#endif
AdjustVisualStageSpaceWithinMovie(0.0f);
}
#if __DEV
iTimeTaken = fwTimer::GetSystemTimeInMilliseconds();
#endif // __DEV
ms_vStageSize = ms_vOriginalStageSize;
for (s32 i = 0; i < MAX_MINIMAP_ROOT_LAYERS; i++)
{
GFxValue::DisplayInfo dispInfo;
dispInfo.SetScale(100.0f, 100.0f);
ms_asRootContainer[i].SetDisplayInfo(dispInfo);
}
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);
CScaleformMgr::ResetMeshCache();
SetupHealthArmourOnStage(bBigMapProperties);
GFxValue mainMap;
ms_asMapObject.GFxValue::GetMember("main_map", &mainMap);
GFxValue::DisplayInfo mapDisplayInfo;
mapDisplayInfo.SetVisible(true);
mainMap.SetDisplayInfo(mapDisplayInfo);
g_RenderMinimap = true;
GFxValue asSonarBlipLayer;
if (ms_asBaseOverlay3D[MINIMAP_LAYER_FOREGROUND].GetMember("asSonarBlipLayer", &asSonarBlipLayer))
{
GFxValue::DisplayInfo SonarLayerDisplayInfo;
SonarLayerDisplayInfo.SetVisible(true);
asSonarBlipLayer.SetDisplayInfo(SonarLayerDisplayInfo);
}
SetMask(true);
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);
}
uiDebugf3("CMiniMap_RenderThread::SetupMiniMapProperties -- Minimap Position = %.2f, %.2f", ms_MiniMapRenderState.m_vCurrentMiniMapPosition.x, ms_MiniMapRenderState.m_vCurrentMiniMapPosition.y);
uiDebugf3("CMiniMap_RenderThread::SetupMiniMapProperties -- Minimap Size = %.2f, %.2f", ms_MiniMapRenderState.m_vCurrentMiniMapSize.x, ms_MiniMapRenderState.m_vCurrentMiniMapSize.y);
// re-init the nav (so it changes for pausemap vs radar)
CGps::ForceUpdateOfGpsOnMiniMap();
//
// set the crosshair as invisible for the minimap:
//
GFxValue asCrosshairMc;
if (ms_asRootContainer[MINIMAP_ROOT_LAYER_UNMASKED].GetMember("asCrosshair", &asCrosshairMc))
{
GFxValue::DisplayInfo newDisplayInfo;
newDisplayInfo.SetVisible(false);
asCrosshairMc.SetDisplayInfo(newDisplayInfo);
}
UpdateSea(true);
if (!bBigMapProperties)
{
if (ms_MiniMapRenderState.m_CurrentGolfMap != GOLF_COURSE_OFF)
{
SetupGolfCourseLayout();
}
}
UpdateWithActionScriptOnRT(true, false);
}
//
// new for 1881980 - render a code "wanted overlay"
//
void CMiniMap_RenderThread::RenderWantedOverlay()
{
static u32 iRangeTimer = fwTimer::GetTimeInMilliseconds();
static bool bOn = false;
if (ms_MiniMapRenderState.m_bFlashWantedOverlay)
{
if (fwTimer::GetTimeInMilliseconds()-iRangeTimer > CMiniMap::sm_Tunables.Display.WantedOverlayTime)
{
bOn = !bOn;
iRangeTimer = fwTimer::GetTimeInMilliseconds();
}
CRGBA overlayCol;
if (bOn)
{
overlayCol = CHudColour::GetRGBA(HUD_COLOUR_RED);
}
else
{
overlayCol = CHudColour::GetRGBA(HUD_COLOUR_BLUE);
}
grcDrawSingleQuadf(-1.0f,1.0f,1.0f,-1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, overlayCol);
}
else
{
iRangeTimer = fwTimer::GetTimeInMilliseconds();
bOn = false;
}
}
#if SUPPORT_MULTI_MONITOR
void CMiniMap_RenderThread::DrawFeatheredRect(Vector2 vBottomLeft, Vector2 vTopRight, Color32 middleColor)
{
#define NORM_TO_SCREEN(val) RemapRange(val, 0.0f, 1.0f, vBottomLeft.x, vTopRight.x)
#define SCREEN_TO_NORM(val) RemapRange(val, vBottomLeft.x, vTopRight.x, 0.0f, 1.0f)
fwRect middleScreen = GRCDEVICE.GetMonitorConfig().getLandscapeMonitor().getArea();
const float fLeftEdge = NORM_TO_SCREEN(middleScreen.GetLeft());
const float fRightEdge= NORM_TO_SCREEN(middleScreen.GetRight());
const float fFeatherPct = CMiniMap_RenderThread::sm_fMultiheadEdgeFeatherPct;
const float fFeatherZ = 0.0f;
// defines the bottom left and top right coordinate for each "tridrant"
Vector4 vPos[3] = { Vector4(fLeftEdge, vBottomLeft.y, fLeftEdge+fFeatherPct, vTopRight.y),
Vector4(fLeftEdge+fFeatherPct, vBottomLeft.y, fRightEdge-fFeatherPct, vTopRight.y),
Vector4(fRightEdge-fFeatherPct, vBottomLeft.y, fRightEdge, vTopRight.y) };
Vector4 uv[3] = { Vector4(SCREEN_TO_NORM(vPos[0].x), 0.0f, SCREEN_TO_NORM(vPos[0].z), 1.0f),
Vector4(SCREEN_TO_NORM(vPos[1].x), 0.0f, SCREEN_TO_NORM(vPos[1].z), 1.0f),
Vector4(SCREEN_TO_NORM(vPos[2].x), 0.0f, SCREEN_TO_NORM(vPos[2].z), 1.0f) };
rage::Color32 edgeColor(middleColor);
edgeColor.SetAlpha(0);
grcBegin(drawTriStrip,8);
grcVertex(vPos[0].x, vPos[0].y, fFeatherZ, 0,0,0, edgeColor, uv[0].x,uv[0].y);
grcVertex(vPos[0].x, vPos[0].w, fFeatherZ, 0,0,0, edgeColor, uv[0].x,uv[0].w);
grcVertex(vPos[0].z, vPos[0].y, fFeatherZ, 0,0,0, middleColor, uv[0].z,uv[0].y);
grcVertex(vPos[0].z, vPos[0].w, fFeatherZ, 0,0,0, middleColor, uv[0].z,uv[0].w);
grcVertex(vPos[1].z, vPos[1].y, fFeatherZ, 0,0,0, middleColor, uv[1].z,uv[1].y);
grcVertex(vPos[1].z, vPos[1].w, fFeatherZ, 0,0,0, middleColor, uv[1].z,uv[1].w);
grcVertex(vPos[2].z, vPos[2].y, fFeatherZ, 0,0,0, edgeColor, uv[2].z,uv[2].y);
grcVertex(vPos[2].z, vPos[2].w, fFeatherZ, 0,0,0, edgeColor, uv[2].z,uv[2].w);
grcEnd();
}
#endif // SUPPORT_MULTI_MONITOR
void CMiniMap_RenderThread::RenderPauseMap(Vector2 vBackgroundPos, Vector2 vBackgroundSize, float fAlphaFader, float fBlipFader, float fSizeScalar)
{
#if RSG_PC
if (ms_iMultiGPUCount > 0)
{
UploadFoWTextureData(true);
ms_iMultiGPUCount--;
}
#endif
Vector2 origPos(vBackgroundPos);
Vector2 origSize(vBackgroundSize);
CScaleformMgr::ScalePosAndSize(vBackgroundPos, vBackgroundSize, fSizeScalar);
grcStateBlock::SetRasterizerState(grcStateBlock::RS_Default);
grcRenderTarget *fbRT = CRenderTargets::GetOffscreenBuffer2();
grcRenderTarget *depthRT = CRenderTargets::GetUIDepthBuffer();
CRenderTargets::UnlockUIRenderTargets();
MULTI_MONITOR_ONLY( bool bDrawBlended = ms_MiniMapRenderState.bDrawCrosshair && GRCDEVICE.GetMonitorConfig().isMultihead() );
#if ENABLE_FOG_OF_WAR
// Prepare FoW map
{
grcTextureFactory::GetInstance().LockRenderTarget(0, CMiniMap_Common::GetFogOfWarCopyRT(), NULL);
grcStateBlock::SetBlendState(grcStateBlock::BS_Default);
CSprite2d fowCopy;
grcStateBlock::SetBlendState(grcStateBlock::BS_Default);
fowCopy.SetGeneralParams(Vector4(1.0f, 1.0f, 1.0f, 1.0f), Vector4(0.0f, 0.0, 0.0, 0.0));
fowCopy.BeginCustomList(CSprite2d::CS_BLIT, CMiniMap_Common::GetFogOfWarRT());
grcDrawSingleQuadf(-1.0f,1.0f,1.0f,-1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, Color32(0xffffffff));
fowCopy.EndCustomList();
// Render Blips
grcStateBlock::SetBlendState(grcStateBlock::BS_Add);
#if __PS3
// We need to use signed blend func here, so we force it.
cellGcmSetBlendFunc(GCM_CONTEXT, CELL_GCM_ONE, CELL_GCM_ONE, CELL_GCM_ONE, CELL_GCM_ONE);
cellGcmSetBlendEquation(GCM_CONTEXT, CELL_GCM_FUNC_ADD_SIGNED, CELL_GCM_FUNC_ADD_SIGNED);
cellGcmSetBlendEnable(GCM_CONTEXT, CELL_GCM_TRUE);
#endif // __PS3
// May want to filter to only blips that are on the island, but that should hit the side alone, so we don't really care
CMiniMap_Common::RenderBlipToFow();
grcTextureFactory::GetInstance().UnlockRenderTarget(0);
#if __PS3
// Reset to what everybody else think it actually is.
cellGcmSetBlendFunc(GCM_CONTEXT, CELL_GCM_ONE, CELL_GCM_ZERO, CELL_GCM_ONE, CELL_GCM_ZERO);
cellGcmSetBlendEquation(GCM_CONTEXT, CELL_GCM_FUNC_ADD, CELL_GCM_FUNC_ADD);
cellGcmSetBlendEnable(GCM_CONTEXT, CELL_GCM_FALSE);
grcStateBlock::MakeDirty();
#endif // __PS3
grcStateBlock::SetBlendState(grcStateBlock::BS_Default);
grcBindTexture(NULL);
}
#endif // ENABLE_FOG_OF_WAR
grcTextureFactory::GetInstance().LockRenderTarget(0, fbRT, depthRT);
int mapDeviceWidth = GRCDEVICE.GetWidth();
int mapDeviceHeight = GRCDEVICE.GetHeight();
float mapWidth = (float)VideoResManager::GetUIWidth();
float mapHeight = (float)VideoResManager::GetUIHeight();
int mapX = Clamp((int)(ms_MiniMapRenderState.m_vCurrentMiniMapPosition.x*mapWidth) - 2,0,mapDeviceWidth);
int mapY = Clamp((int)(ms_MiniMapRenderState.m_vCurrentMiniMapPosition.y*mapHeight) - 2,0,mapDeviceHeight);
int mapW = Clamp((int)(ms_MiniMapRenderState.m_vCurrentMiniMapSize.x*mapWidth) + 4,0,Min((int)mapWidth - mapX,mapDeviceWidth));
int mapH = Clamp((int)(ms_MiniMapRenderState.m_vCurrentMiniMapSize.y*mapHeight) + 10,0,Min((int)mapHeight - mapY,mapDeviceHeight));
if (mapH == mapDeviceHeight && mapW == mapDeviceWidth)
{
GRCDEVICE.Clear(true, Color32(0,0,0,0), false, 1.0f, true, 0);
}else
{
GRCDEVICE.ClearRect(mapX, mapY, mapW, mapH, true, Color32(0,0,0,0), false, 1.0f, true, 0, true);
}
RenderMiniMap(MINIMAP_MOVIE_BACKGROUND, origPos, origSize, 1.0f, 1.0f);
grcTextureFactory::GetInstance().UnlockRenderTarget(0);
#if DEVICE_MSAA
CRenderTargets::ResolveOffscreenBuffer2();
fbRT = CRenderTargets::GetOffscreenBuffer2_Resolved();
#endif //DEVICE_MSAA
CRenderTargets::LockUIRenderTargets();
// Blend minimap in
int screenDeviceWidth = GRCDEVICE.GetWidth();
int screenDeviceHeight = GRCDEVICE.GetHeight();
float screenWidth = (float)VideoResManager::GetUIWidth();
float screenHeight = (float)VideoResManager::GetUIHeight();
int screenX = Clamp((int)(ms_MiniMapRenderState.m_vCurrentMiniMapPosition.x*screenWidth) - 1,0,screenDeviceWidth);
int screenY = Clamp((int)(ms_MiniMapRenderState.m_vCurrentMiniMapPosition.y*screenHeight) - 1,0,screenDeviceHeight);
int screenW = Clamp((int)(ms_MiniMapRenderState.m_vCurrentMiniMapSize.x*screenWidth) + 1,0,Min((int)screenWidth - screenX,screenDeviceWidth));
int screenH = Clamp((int)(ms_MiniMapRenderState.m_vCurrentMiniMapSize.y*screenHeight) + 1,0,Min((int)screenHeight - screenY,screenDeviceHeight));
GRCDEVICE.SetScissor(screenX, screenY, screenW, screenH);
grcStateBlock::SetBlendState(grcStateBlock::BS_Normal);
CSprite2d minimapBlend;
float fDimmerColor = 1.0f;
if (ms_MiniMapRenderState.m_bIsInPauseMap || ms_MiniMapRenderState.m_bIsInCustomMap) // 1354721
{
// alternative shade of tint if navigating content (fixes 1481452)
eHUD_COLOURS whichTinter = HUD_COLOUR_PAUSEMAP_TINT;
if (CPauseMenu::IsNavigatingContent())
whichTinter = HUD_COLOUR_PAUSEMAP_TINT_HALF;
fDimmerColor = CHudColour::GetRGBA(whichTinter).GetAlphaf();
}
minimapBlend.SetGeneralParams(Vector4(fDimmerColor, fDimmerColor, fDimmerColor, fAlphaFader), Vector4(0.0f, 0.0, 0.0, 0.0));
const Vector2 TexSize(1.0f/float(fbRT->GetWidth()), 1.0f/float(fbRT->GetHeight()));
minimapBlend.SetTexelSize(TexSize);
int scissorX = rage::round(vBackgroundPos.x*screenWidth);
int scissorY = rage::round(vBackgroundPos.y*screenHeight);
int scissorW = rage::round(vBackgroundSize.x*screenWidth);
int scissorH = rage::round(vBackgroundSize.y*screenHeight);
if (scissorW < screenWidth || scissorH < screenHeight)
{
GRCDEVICE.SetScissor( scissorX, scissorY, scissorW, scissorH );
}
if(ms_MiniMapRenderState.m_bIsInPauseMap || ms_MiniMapRenderState.m_bIsInCustomMap) // 1354721
{
#if SUPPORT_MULTI_MONITOR
if( bDrawBlended )
{
eHUD_COLOURS hudColour = HUD_COLOUR_PAUSEMAP_TINT;
Color32 adjColor(CHudColour::GetRGBA(hudColour));
// the color is stored 'inverted', so reverse it
adjColor.SetAlpha( Clamp( int(float(255 - adjColor.GetAlpha()) * fAlphaFader), 0, 255) );
// (ab)using lambda closures because we can now (yay C++11!)
CSprite2d::DrawCustomShape( [&]() { DrawFeatheredRect(vBackgroundPos, vBackgroundPos+vBackgroundSize, adjColor); } );
}
else
#endif
{
CMapMenu::RenderPauseMapTint(vBackgroundPos, vBackgroundSize, fAlphaFader, false);
}
}
minimapBlend.BeginCustomList(CSprite2d::CS_BLIT, fbRT);
#if SUPPORT_MULTI_MONITOR
if( bDrawBlended )
{
DrawFeatheredRect(Vector2(-fSizeScalar, fSizeScalar), Vector2(fSizeScalar, -fSizeScalar), Color32(0xFFFFFFFF));
}
else
#endif
{
Vector4 vPos(-fSizeScalar,fSizeScalar,fSizeScalar,-fSizeScalar);
grcDrawSingleQuadf(vPos.x,vPos.y,vPos.z,vPos.w, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, Color32(0xffffffff));
}
minimapBlend.EndCustomList();
RenderMiniMap(MINIMAP_MOVIE_FOREGROUND, vBackgroundPos, vBackgroundSize, fBlipFader, fSizeScalar);
if (scissorW < screenWidth || scissorH < screenHeight)
{
GRCDEVICE.DisableScissor();
}
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap_RenderThread::Render
// PURPOSE: renders the minimap
/////////////////////////////////////////////////////////////////////////////////////
#if ENABLE_FOG_OF_WAR
void CMiniMap_RenderThread::FOWRenderQuadLocation(Vec4f *quads, int numQuads)
{
CRenderTargets::UnlockUIRenderTargets();
grcTextureFactory::GetInstance().LockRenderTarget(0, CMiniMap_Common::GetFogOfWarRT(), NULL);
grcStateBlock::SetBlendState(grcStateBlock::BS_Default);
grcStateBlock::SetBlendState(grcStateBlock::BS_Add);
grcBindTexture(CShaderLib::LookupTexture("FoW"));
for (long index = 0; index < numQuads; index++)
{
grcDrawSingleQuadf(quads[index].GetX(),quads[index].GetY(),quads[index].GetZ(),quads[index].GetW(), 0.0f, 0.0f , 0.0f , 1.0f , 1.0f , fowColor);
}
grcTextureFactory::GetInstance().UnlockRenderTarget(0);
grcStateBlock::SetBlendState(grcStateBlock::BS_Default);
grcBindTexture(NULL);
CRenderTargets::LockUIRenderTargets();
}
#if RSG_PC
void CMiniMap_RenderThread::FOWRenderCatchupQuads()
{
CRenderTargets::UnlockUIRenderTargets();
grcTextureFactory::GetInstance().LockRenderTarget(0, CMiniMap_Common::GetFogOfWarRT(), NULL);
grcStateBlock::SetBlendState(grcStateBlock::BS_Default);
grcStateBlock::SetBlendState(grcStateBlock::BS_Add);
grcBindTexture(CShaderLib::LookupTexture("FoW"));
unsigned int currentRTFlag = (1 << CMiniMap_Common::GetCurrentExportRTIndex());
ms_gotQuads = false;
for (int i = 0; i < MAX_FOW_TARGETS*(MAX_FOG_SCRIPT_REVEALS + 1); i++)
{
if ( (ms_quads[i].flags & currentRTFlag) == 0)
{
grcDrawSingleQuadf(ms_quads[i].pos.GetX(),ms_quads[i].pos.GetY(),ms_quads[i].pos.GetZ(),ms_quads[i].pos.GetW(), 0.0f, 0.0f , 0.0f , 1.0f , 1.0f , fowColor);
ms_quads[i].flags |= currentRTFlag;
}
ms_gotQuads |= (ms_quads[i].flags != 0x7);
}
grcTextureFactory::GetInstance().UnlockRenderTarget(0);
grcStateBlock::SetBlendState(grcStateBlock::BS_Default);
grcBindTexture(NULL);
CRenderTargets::LockUIRenderTargets();
}
#endif
void CMiniMap_RenderThread::FOWClear()
{
FoWPrevX = 0.0f;
FoWPrevY = 0.0f;
CRenderTargets::UnlockUIRenderTargets();
// Update Fog of War
grcTextureFactory::GetInstance().LockRenderTarget(0, CMiniMap_Common::GetFogOfWarRT(), NULL);
GRCDEVICE.Clear(true, Color32(0,0,0,0),false,0.0f,false,0);
grcTextureFactory::GetInstance().UnlockRenderTarget(0);
#if RSG_DURANGO
// Clear the reveal ratio texture to prevent spurious Sightseer Achievement awards
grcTextureFactory::GetInstance().LockRenderTarget(0, CMiniMap_Common::GetFogOfWarRevealRatioRT(), NULL);
GRCDEVICE.Clear(true, Color32(0,0,0,0),false,0.0f,false,0);
grcTextureFactory::GetInstance().UnlockRenderTarget(0);
#endif
CRenderTargets::LockUIRenderTargets();
}
void CMiniMap_RenderThread::FOWReveal()
{
FoWPrevX = 0.0f;
FoWPrevY = 0.0f;
grcStateBlock::SetBlendState(grcStateBlock::BS_Default);
CRenderTargets::UnlockUIRenderTargets();
// Update Fog of War
#if RSG_PC
for(size_t i = 0; i < MAX_FOW_TARGETS; ++i)
{
#endif
grcTextureFactory::GetInstance().LockRenderTarget(0, CMiniMap_Common::GetFogOfWarRT(), NULL);
GRCDEVICE.Clear(true, Color32(0xffffffff),false,0.0f,false,0);
grcTextureFactory::GetInstance().UnlockRenderTarget(0);
#if RSG_PC
CMiniMap_Common::UpdateFogOfWarRBIndex();
}
#endif
CRenderTargets::LockUIRenderTargets();
grcStateBlock::SetBlendState(grcStateBlock::BS_Normal);
}
void CMiniMap_RenderThread::FOWDownSample()
{
CRenderTargets::UnlockUIRenderTargets();
grcStateBlock::SetBlendState(grcStateBlock::BS_Default);
grcStateBlock::SetRasterizerState(grcStateBlock::RS_NoBackfaceCull);
CSprite2d fowReveal;
Vector4 TexSize;
fowReveal.SetGeneralParams(Vector4(1.0f, 1.0f, 1.0f, 1.0f), Vector4(0.0f, 0.0, 0.0, 0.0));
grcTextureFactory::GetInstance().LockRenderTarget(0,PostFX::FogOfWarRT0, NULL);
TexSize = Vector4(1.0f/float(CMiniMap_Common::GetFogOfWarRT()->GetWidth()),1.0f/float(CMiniMap_Common::GetFogOfWarRT()->GetHeight()), 1.0f/float(PostFX::FogOfWarRT0->GetWidth()), 1.0f/float(PostFX::FogOfWarRT0->GetHeight()));
fowReveal.SetTexelSize(TexSize);
fowReveal.BeginCustomList(CSprite2d::CS_FOWCOUNT, CMiniMap_Common::GetFogOfWarRT());
grcDrawSingleQuadf(-1.0f,1.0f,1.0f,-1.0f,0.1f,0.0f,0.0f,1.0f,1.0f,Color32(0xffffffff));
fowReveal.EndCustomList();
// Add Height map
fowReveal.BeginCustomList(CSprite2d::CS_FOWFILL, NULL);
for(int x=0;x<fowTileSize;x++)
{
for( int y=0;y<fowTileSize;y++)
{
float fowX1 = ((float)x)/((float)fowTileSize);
float fowY1 = ((float)y)/((float)fowTileSize);
float fowX2 = fowX1 + 1.0f/((float)fowTileSize);
float fowY2 = fowY1 + 1.0f/((float)fowTileSize);
Vector2 world1 = FowToWorldCoord(fowX1,fowY1);
Vector2 world2 = FowToWorldCoord(fowX2,fowY2);
float xMin = Min(world1.x,world2.x);
float yMin = Min(world1.y,world2.y);
float xMax = Max(world1.x,world2.x);
float yMax = Max(world1.y,world2.y);
float height = CGameWorldHeightMap::GetMaxHeightFromWorldHeightMap(xMin, yMin, xMax, yMax);
if( height < CMiniMap::sm_Tunables.FogOfWar.fFowWaterHeight )
{
grcDrawSingleQuadf(fowX1,fowY1,fowX2,fowY2, 0.0f, 0.0f , 0.0f , 1.0f , 1.0f , Color32(0xffffffff));
}
}
}
fowReveal.EndCustomList();
grcTextureFactory::GetInstance().UnlockRenderTarget(0);
grcTextureFactory::GetInstance().LockRenderTarget(0,PostFX::FogOfWarRT1, NULL);
TexSize = Vector4(1.0f/float(PostFX::FogOfWarRT0->GetWidth()),1.0f/float(PostFX::FogOfWarRT0->GetHeight()),1.0f/float(PostFX::FogOfWarRT1->GetWidth()),1.0f/float(PostFX::FogOfWarRT1->GetHeight()));
fowReveal.SetTexelSize(TexSize);
fowReveal.BeginCustomList(CSprite2d::CS_FOWAVERAGE, PostFX::FogOfWarRT0);
grcDrawSingleQuadf(-1.0f,1.0f,1.0f,-1.0f,0.1f,0.0f,0.0f,1.0f,1.0f,Color32(0xffffffff));
fowReveal.EndCustomList();
grcTextureFactory::GetInstance().UnlockRenderTarget(0);
grcTextureFactory::GetInstance().LockRenderTarget(0,PostFX::FogOfWarRT2, NULL);
TexSize = Vector4(1.0f/float(PostFX::FogOfWarRT1->GetWidth()),1.0f/float(PostFX::FogOfWarRT1->GetHeight()),1.0f/float(PostFX::FogOfWarRT2->GetWidth()),1.0f/float(PostFX::FogOfWarRT2->GetHeight()));
fowReveal.SetTexelSize(TexSize);
fowReveal.BeginCustomList(CSprite2d::CS_FOWAVERAGE, PostFX::FogOfWarRT1);
grcDrawSingleQuadf(-1.0f,1.0f,1.0f,-1.0f,0.1f,0.0f,0.0f,1.0f,1.0f,Color32(0xffffffff));
fowReveal.EndCustomList();
grcTextureFactory::GetInstance().UnlockRenderTarget(0);
grcTextureFactory::GetInstance().LockRenderTarget(0,CMiniMap_Common::GetFogOfWarRevealRatioRT(), NULL);
TexSize = Vector4(1.0f/float(PostFX::FogOfWarRT2->GetWidth()),1.0f/float(PostFX::FogOfWarRT2->GetHeight()),1.0f/float(CMiniMap_Common::GetFogOfWarRevealRatioRT()->GetWidth()),1.0f/float(CMiniMap_Common::GetFogOfWarRevealRatioRT()->GetHeight()));
fowReveal.SetTexelSize(TexSize);
fowReveal.BeginCustomList(CSprite2d::CS_FOWAVERAGE, PostFX::FogOfWarRT2);
grcDrawSingleQuadf(-1.0f,1.0f,1.0f,-1.0f,0.1f,0.0f,0.0f,1.0f,1.0f,Color32(0xffffffff));
fowReveal.EndCustomList();
grcTextureFactory::GetInstance().UnlockRenderTarget(0);
grcStateBlock::SetBlendState(grcStateBlock::BS_Default);
grcStateBlock::SetRasterizerState(grcStateBlock::RS_Default);
CRenderTargets::LockUIRenderTargets();
}
#endif //ENABLE_FOG_OF_WAR
void CMiniMap_RenderThread::Render()
{
#if DISABLE_HUD_FOR_CONTENT_CONTROLLED_BUILD
return;
#else
GRC_ALLOC_SCOPE_AUTO_PUSH_POP()
grcStateBlock::SetRasterizerState(grcStateBlock::RS_Default);
#if RSG_PC
if (GRCDEVICE.IsStereoEnabled() && GRCDEVICE.CanUseStereo())
{
CShaderLib::SetStereoParams(Vector4(0.0f,0.0f,0.0f,0.0f));
}
#endif
#if ENABLE_FOG_OF_WAR
#if __D3D11
if( ms_MiniMapRenderState.m_bUploadFoWTextureData )
{
UploadFoWTextureData();
}
static bool fogOfWarRatioRTValid = false;
if (fogOfWarRatioRTValid)
ReadBackFoWFromStaging();
#endif
bool fogOfWarUpdated = false;
#if RSG_PC
if( ms_gotQuads )
{
FOWRenderCatchupQuads();
}
if (g_curFOWClearGPUCount > 0)
{
FOWClear();
g_curFOWClearGPUCount--;
}
if (g_curFOWRevealGPUCount > 0)
{
FOWReveal();
g_curFOWRevealGPUCount--;
}
#endif
if( ms_MiniMapRenderState.m_bUpdateFoW )
{
// Update Fog of War
Vector2 coords = WorldToFowCoord(ms_MiniMapRenderState.m_vPlayerPos.x, ms_MiniMapRenderState.m_vPlayerPos.y);
float fowWidth = (float)CMiniMap_Common::GetFogOfWarRT()->GetWidth();
float fowHeight = (float)CMiniMap_Common::GetFogOfWarRT()->GetHeight();
bool needPedRender = ms_MiniMapRenderState.m_bUpdatePlayerFoW && (abs(FoWPrevX - coords.x) > moveStep/fowWidth || abs(FoWPrevY - coords.y) > moveStep/fowHeight);
bool needScriptRender = ms_MiniMapRenderState.m_numScriptRevealRequested > 0;
if( needPedRender || needScriptRender )
{
const float aspectRatio = CMiniMap::AreFowCustomWorldExtentsEnabled()?
(CMiniMap::GetFowCustomWorldH() / CMiniMap::GetFowCustomWorldW()) :
(CMiniMap::sm_Tunables.FogOfWar.fWorldH / CMiniMap::sm_Tunables.FogOfWar.fWorldW);
float xDelta = (fowColorSizeX/fowWidth)*aspectRatio;
float yDelta = (fowColorSizeY/fowHeight)*aspectRatio;
Vec4f quads[MAX_FOG_SCRIPT_REVEALS + 1];
int numOfQuads = 0;
if( needPedRender )
{
FoWPrevX = coords.x;
FoWPrevY = coords.y;
quads[numOfQuads++] = Vec4f(coords.x-xDelta,coords.y-yDelta,coords.x+xDelta,coords.y+yDelta);
}
if( needScriptRender )
{
for(int i=0;i<ms_MiniMapRenderState.m_numScriptRevealRequested;i++)
{
Vector2 coords = WorldToFowCoord(ms_MiniMapRenderState.m_ScriptReveal[i].x, ms_MiniMapRenderState.m_ScriptReveal[i].y);
quads[numOfQuads++] = Vec4f(coords.x-xDelta,coords.y-yDelta,coords.x+xDelta,coords.y+yDelta);
}
}
if (numOfQuads )
{
FOWRenderQuadLocation(quads, numOfQuads);
#if RSG_PC
int quadIdx = 0;
unsigned int currentRTFlag = (1 << CMiniMap_Common::GetCurrentExportRTIndex());
for (int i = 0; i < MAX_FOW_TARGETS*(MAX_FOG_SCRIPT_REVEALS + 1); i++)
{
if( ms_quads[i].flags == 0x7 )
{
ms_quads[i].pos = quads[quadIdx];
ms_quads[i].flags = currentRTFlag;
ms_gotQuads = true;
quadIdx++;
if( quadIdx == numOfQuads )
break;
}
}
#endif
}
fogOfWarUpdated = true;
}
}
if( ms_MiniMapRenderState.m_bClearFoW )
{
FOWClear();
#if RSG_PC
g_curFOWClearGPUCount = GRCDEVICE.GetGPUCount(true)-1;
#endif
fogOfWarUpdated = true;
}
if( ms_MiniMapRenderState.m_bRevealFoW)
{
FOWReveal();
#if RSG_PC
g_curFOWRevealGPUCount = GRCDEVICE.GetGPUCount(true)-1;
#endif
fogOfWarUpdated = true;
}
// Downsample FoW.
FowLastFrameRead++;
if( FowLastFrameRead > fowFrameCount )
{
FowLastFrameRead = 0;
FOWDownSample();
#if __D3D11
// copy to current frame to staging buffer and increment frame number
CopyFoWForCPURead();
fogOfWarRatioRTValid = true;
#endif
}
#endif // ENABLE_FOG_OF_WAR
#if !__FINAL
XPARAM(nominimap);
if (PARAM_nominimap.Get())
{
if (!ms_MiniMapRenderState.m_bIsInPauseMap)
return;
}
#endif // !__FINAL
if ( (ms_MiniMapRenderState.m_bShouldProcessMiniMap) && (ms_MiniMapRenderState.m_bShouldRenderMiniMap) ) // if in pause map and not in map screen then dont render
{
#define __TEST_SCALEFORM_3D_ISSUE (0)
#if __TEST_SCALEFORM_3D_ISSUE
ms_MiniMapRenderState.m_vCurrentMiniMapPosition = Vector2(0.3f,0.8f);
ms_MiniMapRenderState.m_vCurrentMiniMapSize = Vector2(0.5f, 0.5f);
CScaleformMgr::ChangeMovieParams(ms_iMovieId[MINIMAP_MOVIE_BACKGROUND], ms_MiniMapRenderState.m_vCurrentMiniMapPosition, ms_MiniMapRenderState.m_vCurrentMiniMapSize, GFxMovieView::SM_ExactFit);
CScaleformMgr::ChangeMovieParams(ms_iMovieId[MINIMAP_MOVIE_FOREGROUND], ms_MiniMapRenderState.m_vCurrentMiniMapPosition, ms_MiniMapRenderState.m_vCurrentMiniMapSize, GFxMovieView::SM_ExactFit);
#endif // __TEST_SCALEFORM_3D_ISSUE
// I'd love to skip the whole rigmarole of doing the scissoring and clear and copy, but it would appear
// the frontend menu relies on this behaviour to not spew map all over the screen...
bool doMiniMapAlpha = ( (!ms_MiniMapRenderState.m_bIsInPauseMap) && (!ms_MiniMapRenderState.m_bIsInCustomMap) && (ms_MiniMapAlpha < 1.0f) && (ms_MiniMapRenderState.m_CurrentGolfMap == GOLF_COURSE_OFF) );
float miniMapAlpha = doMiniMapAlpha ? ms_MiniMapAlpha : 1.0f;
if( ms_bUseTexturedAlphaAllMovies || ms_bUseTextureAlphaBaseMovie )
miniMapAlpha = 1.0f;
PF_PUSH_TIMEBAR("Scaleform Movie Render (MiniMap)");
bool useOffscreenBuffer = false;
if(doMiniMapAlpha)
useOffscreenBuffer = true;
Vector2 zero(0.0f, 0.0f);
Vector2 maskPos,maskSize;
int mapMaskX = 0;
int mapMaskY = 0;
int mapMaskW = 0;
int mapMaskH = 0;
int mapX = 0;
int mapY = 0;
int mapW = 0;
int mapH = 0;
if(useOffscreenBuffer)
{
int mapDeviceWidth = GRCDEVICE.GetWidth();
int mapDeviceHeight = GRCDEVICE.GetHeight();
float mapWidth = (float)VideoResManager::GetUIWidth();
float mapHeight = (float)VideoResManager::GetUIHeight();
#if SUPPORT_MULTI_MONITOR
MultiMonitorHudHelper helper(&ms_MiniMapRenderState);
#endif // SUPPORT_MULTI_MONITOR
if( ms_bUseTexturedAlphaAllMovies || ms_bUseTextureAlphaBaseMovie )
{
maskPos = ms_MiniMapRenderState.m_vCurrentMiniMapBlurPosition;
maskSize = ms_MiniMapRenderState.m_vCurrentMiniMapBlurSize;
}
else
{
maskPos = ms_MiniMapRenderState.m_vCurrentMiniMapMaskPosition;
maskSize = ms_MiniMapRenderState.m_vCurrentMiniMapMaskSize;
}
int mapMaskDeviceWidth = GRCDEVICE.GetWidth();
int mapMaskDeviceHeight = GRCDEVICE.GetHeight();
mapMaskX = Clamp((int)((maskPos.x)*mapWidth) - 1,0,mapMaskDeviceWidth);
mapMaskY = Clamp((int)((maskPos.y)*mapHeight) - 1,0,mapMaskDeviceHeight);
mapMaskW = Clamp((int)((maskSize.x)*mapWidth) + 1,0,Min((int)mapWidth - mapMaskX,mapMaskDeviceWidth));
mapMaskH = Clamp((int)((maskSize.y)*mapHeight) + 1,0,Min((int)mapHeight - mapMaskY,mapMaskDeviceHeight));
if (!ms_MiniMapRenderState.m_bBackgroundMapShouldBeHidden)
{
// Render the minimap to a secondary buffer and composite it to the final render
// That way we can apply a constant alpha blend to the whole thing, but let artists alpha blends elements together.
// Clever Shit.
// Render to offscreen target
grcRenderTarget *fbRT = CRenderTargets::GetOffscreenBuffer2();
grcRenderTarget *depthRT = CRenderTargets::GetUIDepthBuffer();
CRenderTargets::UnlockUIRenderTargets();
grcTextureFactory::GetInstance().LockRenderTarget(0, fbRT, depthRT);
if (GRCDEVICE.GetMSAA() || RSG_PC)
{
GRCDEVICE.Clear(true,Color32(0),false,1.f,false,0);
}
Vector2 vMapPos, vMapSize;
if( ms_bUseTexturedAlphaAllMovies || ms_bUseTextureAlphaBaseMovie )
{
vMapPos = ms_MiniMapRenderState.m_vCurrentMiniMapBlurPosition;
vMapSize = ms_MiniMapRenderState.m_vCurrentMiniMapBlurSize;
}
else
{
vMapPos = ms_MiniMapRenderState.m_vCurrentMiniMapPosition;
vMapSize = ms_MiniMapRenderState.m_vCurrentMiniMapSize;
}
mapX = Clamp((int)(vMapPos.x*mapWidth) - 1,0,mapDeviceWidth);
mapY = Clamp((int)(vMapPos.y*mapHeight) - 1,0,mapDeviceHeight);
mapW = Clamp((int)(vMapSize.x*mapWidth) + 1,0,Min((int)mapWidth - mapX,mapDeviceWidth));
mapH = Clamp((int)(vMapSize.y*mapHeight) + 1,0,Min((int)mapHeight - mapY,mapDeviceHeight));
GRCDEVICE.ClearRect(mapX, mapY, mapW, mapH, true, Color32(0,0,0,0),true,1.0f,true,0 ORBIS_ONLY(,true) DURANGO_ONLY(,true) WIN32PC_ONLY(,true));
RenderMiniMap(MINIMAP_MOVIE_BACKGROUND, zero, zero, 1.0f, 1.0f);
if( ms_bUseTexturedAlphaAllMovies )
{
RenderMiniMap(MINIMAP_MOVIE_FOREGROUND, zero, zero, 1.0f, 1.0f);
}
u32 now = fwTimer::GetTimeInMilliseconds();
float flashAlpha = Clamp(1.0f - (now-ms_MiniMapRenderState.m_uFlashStartTime)/float(CMiniMap::sm_Tunables.Display.ScriptOverlayTime), 0.0f, 1.0f);
if( flashAlpha > 0.0f )
{
CSprite2d minimapFlashOverlay;
CRGBA overlayCol = CHudColour::GetRGBF(ms_MiniMapRenderState.m_eFlashColour, flashAlpha);
minimapFlashOverlay.SetGeneralParams(Vector4(1.0f, 1.0f, 1.0f, 1.0f), Vector4(0.0f, 0.0, 0.0, 0.0));
minimapFlashOverlay.BeginCustomList(CSprite2d::CS_BLIT, grcTexture::NoneWhite);
grcDrawSingleQuadf(-1.0f,1.0f,1.0f,-1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, overlayCol);
minimapFlashOverlay.EndCustomList();
}
if(doMiniMapAlpha)
{
if( ms_bUseTexturedAlphaAllMovies || ms_bUseTextureAlphaBaseMovie )
{
CSprite2d minimapAlphaClear;
grcTexture *texture;
if(false && NetworkInterface::IsInCopsAndCrooks())
{ // use different radar mask textures for C&C (BS#6508644 - C&C - Radar Mask - Code set up our new Radar Mask Texture)
texture = ms_MiniMapRenderState.m_bIsInBigMap ? ms_MaskTextureCnCLg : ms_MaskTextureCnCSm;
}
else
{
texture = ms_MiniMapRenderState.m_bIsInBigMap ? ms_MaskTextureLg : ms_MaskTextureSm;
}
grcStateBlock::SetBlendState(ms_ClearAlphaMiniMapRenderBlendStateHandle);
// clear the full alpha background, because Scaleform leaks outside the rect...
minimapAlphaClear.SetGeneralParams(Vector4(0.0f, 0.0f, 0.0f, 0.0f), Vector4(0.0f, 0.0, 0.0, 0.0));
minimapAlphaClear.BeginCustomList(CSprite2d::CS_BLIT, grcTexture::NoneWhite);
grcDrawSingleQuadf(-1.0f,1.0f,1.0f,-1.0f,0.1f,0.0f,0.0f,1.0f,1.0f,Color32(0xffffffff));
minimapAlphaClear.EndCustomList();
// Render the textured blob....
float alphaOut = Lerp(flashAlpha, CMiniMap::sm_Tunables.Display.MaskNormalAlpha, CMiniMap::sm_Tunables.Display.MaskFlashAlpha );
minimapAlphaClear.SetGeneralParams(Vector4(1.0f, 0.0f, 0.0f, 0.0f), Vector4(0.0f, alphaOut, 0.0f, 0.0f));
minimapAlphaClear.SetTexelSize(Vector2(1.0f/((float)texture->GetWidth()),1.0f/((float)texture->GetHeight())));
minimapAlphaClear.BeginCustomList(CSprite2d::CS_BLIT_TO_ALPHA_BLUR, texture);
float ooScreenWidth = 1.0f/(float)VideoResManager::GetUIWidth();
float ooScreenHeight = 1.0f/(float)VideoResManager::GetUIHeight();
grcDrawSingleQuadf( maskPos.x-ooScreenWidth,
maskPos.y-ooScreenHeight,
maskPos.x + maskSize.x+ooScreenWidth,
maskPos.y + maskSize.y+ooScreenHeight,
0.0f,
0.0f,0.0f,1.0f,1.0f,
Color32(0xffffffff));
minimapAlphaClear.EndCustomList();
}
else
{
GRCDEVICE.SetScissor(mapMaskX, mapMaskY, mapMaskW, mapMaskH);
grcStateBlock::SetBlendState(ms_ClearAlphaMiniMapRenderBlendStateHandle);
CSprite2d minimapAlphaClear;
minimapAlphaClear.SetGeneralParams(Vector4(1.0f, 1.0f, 1.0f, 1.0f), Vector4(0.0f, 0.0, 0.0, 0.0));
minimapAlphaClear.BeginCustomList(CSprite2d::CS_BLIT, grcTexture::NoneWhite);
grcDrawSingleQuadf(-1.0f,1.0f,1.0f,-1.0f,0.1f,0.0f,0.0f,1.0f,1.0f,Color32(0xffffffff));
minimapAlphaClear.EndCustomList();
}
}
grcTextureFactory::GetInstance().UnlockRenderTarget(0);
{
#if DEVICE_EQAA
eqaa::ResolveArea area(mapX, mapY, mapW, mapH);
#endif // DEVICE_EQAA
CRenderTargets::ResolveOffscreenBuffer2();
fbRT = CRenderTargets::GetOffscreenBuffer2_Resolved();
}
CRenderTargets::LockUIRenderTargets();
// Blend minimap in
GRCDEVICE.SetScissor(mapMaskX, mapMaskY, mapMaskW, mapMaskH);
grcStateBlock::SetBlendState(grcStateBlock::BS_Normal);
CSprite2d minimapBlend;
const Vector2 TexSize(1.0f/float(fbRT->GetWidth()),1.0f/float(fbRT->GetHeight()));
minimapBlend.SetTexelSize(TexSize);
minimapBlend.SetGeneralParams(Vector4(miniMapAlpha, miniMapAlpha, miniMapAlpha, miniMapAlpha), Vector4(0.0f, 0.0, 0.0, 0.0));
minimapBlend.BeginCustomList(CSprite2d::CS_BLIT, fbRT);
grcDrawSingleQuadf(-1.0f,1.0f,1.0f,-1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, Color32(0xffffffff));
// if we attempt to flash the radar while wanted, we just get a brighter red radar. And that's no good
if( flashAlpha <= 0.0f )
RenderWantedOverlay();
minimapBlend.EndCustomList();
GRCDEVICE.DisableScissor();
}
if( ms_bUseTexturedAlphaAllMovies == false ) // we always want to show foreground (so we can render "blips only" mode) - fix for 1883759
{
if (!(RSG_PC && GRCDEVICE.GetMSAA()))
{
RenderMiniMap(MINIMAP_MOVIE_FOREGROUND, zero, zero, 1.0f, 1.0f);
}
else
{
grcRenderTarget *uiRT = CRenderTargets::GetUIBackBuffer();
grcRenderTarget *fbRT = CRenderTargets::GetOffscreenBuffer2();
grcRenderTarget *depthRT = CRenderTargets::GetUIDepthBuffer();
CRenderTargets::UnlockUIRenderTargets();
// Copy minimap back to OffscreenBuffer2 and render foreground layer with AA
grcTextureFactory::GetInstance().LockRenderTarget(0, fbRT, depthRT);
{
grcStateBlock::SetBlendState(ms_CopyAAMiniMapRenderBlendStateHandle);
GRCDEVICE.SetScissor(mapMaskX, mapMaskY, mapMaskW, mapMaskH);
CSprite2d minimapBlend;
const Vector2 TexSize(1.0f/float(fbRT->GetWidth()),1.0f/float(fbRT->GetHeight()));
minimapBlend.SetTexelSize(TexSize);
minimapBlend.SetGeneralParams(Vector4(miniMapAlpha, miniMapAlpha, miniMapAlpha, miniMapAlpha), Vector4(0.0f, 0.0, 0.0, 0.0));
minimapBlend.BeginCustomList(CSprite2d::CS_BLIT, uiRT);
{
grcDrawSingleQuadf(-1.0f,1.0f,1.0f,-1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, Color32(0xffffffff));
}
minimapBlend.EndCustomList();
RenderMiniMap(MINIMAP_MOVIE_FOREGROUND, zero, zero, 1.0f, 1.0f);
GRCDEVICE.DisableScissor();
}
grcTextureFactory::GetInstance().UnlockRenderTarget(0);
#if DEVICE_EQAA
eqaa::ResolveArea area(mapX, mapY, mapW, mapH);
#endif
CRenderTargets::ResolveOffscreenBuffer2();
fbRT = CRenderTargets::GetOffscreenBuffer2_Resolved();
CRenderTargets::LockUIRenderTargets();
// Copy composited minimap to UI Back Buffer
grcStateBlock::SetBlendState(ms_CopyAAMiniMapRenderBlendStateHandle);
GRCDEVICE.SetScissor(mapMaskX, mapMaskY, mapMaskW, mapMaskH);
CSprite2d minimapBlend;
const Vector2 TexSize(1.0f/float(fbRT->GetWidth()),1.0f/float(fbRT->GetHeight()));
minimapBlend.SetTexelSize(TexSize);
minimapBlend.SetGeneralParams(Vector4(miniMapAlpha, miniMapAlpha, miniMapAlpha, miniMapAlpha), Vector4(0.0f, 0.0, 0.0, 0.0));
minimapBlend.BeginCustomList(CSprite2d::CS_BLIT, fbRT);
{
grcDrawSingleQuadf(-1.0f,1.0f,1.0f,-1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, Color32(0xffffffff));
}
minimapBlend.EndCustomList();
GRCDEVICE.DisableScissor();
}
}
}
else
{
if (!ms_MiniMapRenderState.m_bBackgroundMapShouldBeHidden)
{
RenderMiniMap(MINIMAP_MOVIE_BACKGROUND, zero, zero, 1.0f, 1.0f);
}
RenderMiniMap(MINIMAP_MOVIE_FOREGROUND, zero, zero, 1.0f, 1.0f);
}
PF_POP_TIMEBAR();
#if __BANK
if (bDebug3DBlips && vGameScreenPos.x != 0 && vGameScreenPos.y != 0)
{
CSprite2d::DrawRect( fwRect(vGameScreenPos.x, vGameScreenPos.y, vGameScreenPos.x+0.003f, vGameScreenPos.y+0.005f), CRGBA(0,255,0,255) );
vGameScreenPos = Vector2(0,0); // reset it for next frame
}
#endif // __BANK
}
#endif
#if __DEV
if (iTimeTaken != 0)
{
uiDebugf1("Time taken to switch between MiniMap and PauseMap: %d", fwTimer::GetSystemTimeInMilliseconds() - iTimeTaken);
iTimeTaken = 0;
}
#endif // __DEV
#if __BANK && ENABLE_FOG_OF_WAR
if( DebugDrawFOW )
{
CSprite2d::SetRenderState(CMiniMap_Common::GetFogOfWarRT());
CSprite2d::SetGeneralParams(Vector4(1.0f,1.0f,1.0f,1.0f), Vector4(0.0f, 0.0, 0.0, 0.0));
CSprite2d::DrawRect(Vector2(DebugFOWX1,DebugFOWY1),
Vector2(DebugFOWX2,DebugFOWY1),
Vector2(DebugFOWX1,DebugFOWY2),
Vector2(DebugFOWX2,DebugFOWY2),
0.0f,
Vector2(0.0f,0.0f),
Vector2(1.0f,0.0f),
Vector2(0.0f,1.0f),
Vector2(1.0f,1.0f),
Color32(0xffffffff));
CSprite2d::ClearRenderState();
}
#endif // __BANK && ENABLE_FOG_OF_WAR
#if RSG_PC
if (GRCDEVICE.IsStereoEnabled() && GRCDEVICE.CanUseStereo())
{
CShaderLib::SetStereoParams(Vector4(0.0f,0.0f,0.0f,0.0f));
}
#endif
}
#if __D3D11 && ENABLE_FOG_OF_WAR
#if RSG_PC
bool CMiniMap_RenderThread::IsRenderMultiGPU()
{
return (ms_gotQuads || (g_curFOWClearGPUCount > 0) || (g_curFOWRevealGPUCount > 0));
}
#endif
void CMiniMap_RenderThread::CopyFoWForCPURead()
{
Assert(CSystem::IsThisThreadId(SYS_THREAD_RENDER));
grcTextureD3D11* fogOfWarTex11 = (grcTextureD3D11*)CMiniMap_Common::GetFogOfWarTex();
fogOfWarTex11->CopyFromGPUToStagingBuffer();
grcTextureD3D11* fogOfWarRatioTex11 = (grcTextureD3D11*)CMiniMap_Common::GetFogOfWarRevealRatioTex();
fogOfWarRatioTex11->CopyFromGPUToStagingBuffer();
#if RSG_PC
CMiniMap_Common::UpdateFogOfWarRBIndex();
#endif
ms_bUpdateFogOfWarData = true;
}
void CMiniMap_RenderThread::ReadBackFoWFromStaging()
{
Assert(CSystem::IsThisThreadId(SYS_THREAD_RENDER));
if(ms_bUpdateFogOfWarData)
{
PF_PUSH_TIMEBAR_BUDGETED("CMiniMap_Common::ms_MiniMapFogOfWarTex Read Back", 0.4f);
bool fogOfWarDataUpdated = false;
#if RSG_PC
grcTextureD3D11* fogOfWarTex11 = (grcTextureD3D11*)CMiniMap_Common::GetPreviousFogOfWarTex();
#else
grcTextureD3D11* fogOfWarTex11 = (grcTextureD3D11*)CMiniMap_Common::GetFogOfWarTex();
#endif
u8* fogOfWarData = CMiniMap_Common::GetFogOfWarData();
if(fogOfWarTex11->MapStagingBufferToBackingStore(true))
{
grcTextureLock lock;
if (fogOfWarTex11->LockRect( 0, 0, lock, grcsRead ))
{
u8* pBits = (u8*)lock.Base;
for (int col=0; col<lock.Height; col++)
{
sysMemCpy( fogOfWarData, pBits, sizeof(u8)*FOG_OF_WAR_RT_SIZE);
fogOfWarData += FOG_OF_WAR_RT_SIZE;
pBits += lock.Pitch / sizeof(u8);
}
fogOfWarTex11->UnlockRect(lock);
fogOfWarDataUpdated = true;
}
}
PF_POP_TIMEBAR();
PF_PUSH_TIMEBAR_BUDGETED("CMiniMap_Common::ms_MiniMapFogofWarRevealRatioTex Read Back", 0.4f);
bool fogOfWarRatioDataUpdated = false;
#if RSG_PC
grcTextureD3D11* fogOfWarRatioTex11 = (grcTextureD3D11*)CMiniMap_Common::GetPreviousFogOfWarRevealRatioTex();
#else
grcTextureD3D11* fogOfWarRatioTex11 = (grcTextureD3D11*)CMiniMap_Common::GetFogOfWarRevealRatioTex();
#endif
if(fogOfWarRatioTex11->MapStagingBufferToBackingStore(true))
{
grcTextureLock lock;
if (fogOfWarRatioTex11->LockRect( 0, 0, lock, grcsRead ))
{
*CMiniMap_Common::GetFogOfWarRevealRatioLockPtr() = *(float*)lock.Base;
fogOfWarRatioDataUpdated = true;
fogOfWarRatioTex11->UnlockRect(lock);
}
}
PF_POP_TIMEBAR();
ms_bUpdateFogOfWarData = !(fogOfWarDataUpdated && fogOfWarRatioDataUpdated);
}
}
void CMiniMap_RenderThread::UploadFoWTextureData(WIN32PC_ONLY(bool bMultiGPUSync))
{
Assert(CSystem::IsThisThreadId(SYS_THREAD_RENDER));
#if RSG_PC
// copy everything across the different textures
for(size_t i = 0; i < MAX_FOW_TARGETS; ++i)
{
((grcTextureD3D11*)CMiniMap_Common::GetFogOfWarTex(i))->UpdateGPUCopy(0, 0, CMiniMap_Common::GetFogOfWarLockPtr());
#if RSG_PC
if (!bMultiGPUSync)
#endif
((grcTextureD3D11*)CMiniMap_Common::GetFogOfWarTex(i))->CopyFromGPUToStagingBuffer();
}
#else
// UpdateGPU Copy is a lie...
grcTextureLock texLock;
if(CMiniMap_Common::GetFogOfWarTex()->LockRect(0, 0, texLock))
{
u8 *fogOfWarData = CMiniMap_Common::GetFogOfWarLockPtr();
u8* pBits = (u8*)texLock.Base;
for (int col=0; col<texLock.Height; col++)
{
sysMemCpy(pBits , fogOfWarData, sizeof(u8)*FOG_OF_WAR_RT_SIZE);
fogOfWarData += FOG_OF_WAR_RT_SIZE;
pBits += texLock.Pitch / sizeof(u8);
}
CMiniMap_Common::GetFogOfWarTex()->UnlockRect(texLock);
}
#endif
}
#endif // __D3D11
#if __RENDER_PED_VISUAL_FIELD
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap_RenderThread::RenderPedVisualField
// PURPOSE: renders the ped visual field to the minimap (needs moving over to Scaleform)
/////////////////////////////////////////////////////////////////////////////////////
void CMiniMap_RenderThread::RenderPedVisualField()
{
if (!GetInStealthMode()) // if not in stealth mode, then dont create any stealth blips
return;
// Render AI perception cones and dead peds
CEntityIterator entityIterator(IteratePeds);
CPed* pPed = static_cast<CPed*>(entityIterator.GetNext());
while(pPed)
{
if( pPed->GetPedConfigFlag( CPED_CONFIG_FLAG_DrawRadarVisualField ) )
{
if( pPed->IsInjured() )
{
DrawDeadPed(pPed);
}
else
{
#if __DEV
if (CTaskInvestigate::ms_bToggleRenderInvestigationPosition)
{
CTask* pTask = pPed->GetPedIntelligence()->FindTaskActiveByType(CTaskTypes::TASK_INVESTIGATE);
if (pTask && pTask->GetTaskType() == CTaskTypes::TASK_INVESTIGATE)
{
DrawLine(VEC3V_TO_VECTOR3(pPed->GetTransform().GetPosition()),static_cast<CTaskInvestigate*>(pTask)->GetInvestigationPos(),Color_orange);
}
pTask = pPed->GetPedIntelligence()->FindTaskActiveByType(CTaskTypes::TASK_SEARCH);
if (pTask && pTask->GetTaskType() == CTaskTypes::TASK_SEARCH)
{
DrawLine(VEC3V_TO_VECTOR3(pPed->GetTransform().GetPosition()),static_cast<CTaskInvestigate*>(pTask)->GetInvestigationPos(),Color_orange);
}
}
#endif // __DEV
DrawPedVisualField(pPed);
}
}
pPed = static_cast<CPed*>(entityIterator.GetNext());
}
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap_RenderThread::DrawPedVisualField
// PURPOSE: (needs moving over to Scaleform)
/////////////////////////////////////////////////////////////////////////////////////
void CMiniMap_RenderThread::DrawPedVisualField( CPed* pPed )
{
if (pPed)
{
// Get global positions for the peds visual field
Vector3 avPerceptionCone[CPedPerception::VF_Max];
pPed->GetPedIntelligence()->GetPedPerception().GetVisualFieldLines(avPerceptionCone);//, pPed->GetPedIntelligence()->GetPedPerception().GetIdentificationRange());
Vector3 vHead = avPerceptionCone[CPedPerception::VF_HeadPos];
// Work out the line and fill colours
Color32 lineColour = pPed->GetPedIntelligence()->GetAlertnessState() == CPedIntelligence::AS_NotAlert ? Color_DarkGreen : Color_DarkOrange;
if( pPed->GetPedIntelligence()->GetQueriableInterface()->IsTaskCurrentlyRunning(CTaskTypes::TASK_COMBAT))
{
lineColour = Color_red;
}
Color32 fillColour = lineColour;
fillColour.SetAlpha(60);
// Convert the targets into screen coords
Vector3 vLeftEnd = avPerceptionCone[CPedPerception::VF_LeftFocus];
Vector3 vRightEnd = avPerceptionCone[CPedPerception::VF_RightFocus];
// Draw the field onto the hud
if( DrawPoly( vHead, vLeftEnd, vRightEnd, fillColour ) )
{
DrawLine(vHead, vLeftEnd, lineColour);
DrawLine(vHead, vRightEnd, lineColour);
}
}
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap_RenderThread::DrawDeadPed
// PURPOSE: (needs moving over to Scaleform)
/////////////////////////////////////////////////////////////////////////////////////
void CMiniMap_RenderThread::DrawDeadPed( CPed* pPed )
{
#define DEAD_PED_SIZE (1.0f)
Vector3 vCentre = VEC3V_TO_VECTOR3(pPed->GetTransform().GetPosition());
Vector3 vLineStart1 = Vector3(vCentre.x - DEAD_PED_SIZE, vCentre.y - DEAD_PED_SIZE, vCentre.z);
Vector3 vLineEnd1 = Vector3(vCentre.x + DEAD_PED_SIZE, vCentre.y + DEAD_PED_SIZE, vCentre.z);
Vector3 vLineStart2 = Vector3(vCentre.x + DEAD_PED_SIZE, vCentre.y - DEAD_PED_SIZE, vCentre.z);
Vector3 vLineEnd2 = Vector3(vCentre.x - DEAD_PED_SIZE, vCentre.y + DEAD_PED_SIZE, vCentre.z);
DrawLine(vLineStart1, vLineEnd1, Color_red);
DrawLine(vLineStart2, vLineEnd2, Color_red);
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap_RenderThread::ConvertToScreenCoords()
// PURPOSE:
/////////////////////////////////////////////////////////////////////////////////////
bool CMiniMap_RenderThread::ConvertToScreenCoords(Vector2& screenCoordsOut, const Vector3& vWorldCoords)
{
if(ms_iMovieId[MINIMAP_MOVIE_FOREGROUND] >= 0)
{
GPointF blipPoint, screenPoint;
blipPoint.x = vWorldCoords.x;
blipPoint.y = -vWorldCoords.y;
GFxMovieView* pView = CScaleformMgr::GetMovieView(ms_iMovieId[MINIMAP_MOVIE_FOREGROUND]);
if(pView && pView->TranslateLocalToScreen(BLIP_LAYER_PATH, blipPoint, &screenPoint))
{
screenCoordsOut.Set(screenPoint.x/SCREEN_WIDTH, screenPoint.y/SCREEN_HEIGHT);
return true;
}
}
return false;
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap_RenderThread::DrawLine
// PURPOSE: (needs moving over to Scaleform)
/////////////////////////////////////////////////////////////////////////////////////
void CMiniMap_RenderThread::DrawLine( const Vector3 &vFrom, const Vector3 &vTo, const Color32 DEBUG_DRAW_ONLY(colour) )
{
Vector2 p1, p2;
ConvertToScreenCoords(p1, vFrom);
ConvertToScreenCoords(p2, vTo);
if( ClampInsideLimits(p1, p2) )
{
#if DEBUG_DRAW
grcDebugDraw::Line(p1, p2, colour, colour);
#endif
}
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap_RenderThread::DrawPoly
// PURPOSE: (needs moving over to Scaleform)
/////////////////////////////////////////////////////////////////////////////////////
#if DEBUG_DRAW
bool CMiniMap_RenderThread::DrawPoly( const Vector3 &p1, const Vector3 &p2, const Vector3 &p3, const Color32 colour)
#else
bool CMiniMap_RenderThread::DrawPoly( const Vector3 &p1, const Vector3 &p2, const Vector3 &p3, const Color32 UNUSED_PARAM(colour))
#endif
{
s32 iNumValidLines = 0;
Vector2 vEdge1A, vEdge1B, vEdge2B;
ConvertToScreenCoords(vEdge1A, p1);
ConvertToScreenCoords(vEdge1B, p2);
Vector2 vEdge2A = vEdge1B;
ConvertToScreenCoords(vEdge2B, p3);
Vector2 vEdge3A = vEdge2B;
Vector2 vEdge3B = vEdge1A;
if( ClampInsideLimits(vEdge1A, vEdge1B) )
++iNumValidLines;
if( ClampInsideLimits(vEdge2A, vEdge2B) )
++iNumValidLines;
if( ClampInsideLimits(vEdge3A, vEdge3B) )
++iNumValidLines;
if( iNumValidLines == 3 )
{
#if DEBUG_DRAW
grcDebugDraw::Poly(vEdge3B, vEdge1A, vEdge3A, colour, colour, colour);
grcDebugDraw::Poly(vEdge1A, vEdge1B, vEdge3A, colour, colour, colour);
grcDebugDraw::Poly(vEdge1B, vEdge2A, vEdge3A, colour, colour, colour);
grcDebugDraw::Poly(vEdge2A, vEdge2B, vEdge3A, colour, colour, colour);
#endif
return true;
}
return false;
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: CMiniMap_RenderThread::ClampInsideLimits
// PURPOSE: (needs moving over to Scaleform)
/////////////////////////////////////////////////////////////////////////////////////
bool CMiniMap_RenderThread::ClampInsideLimits(Vector2 &vFrom, Vector2 &vTo)
{
// Transform to "minimap coordinates", ranged -0.5...0.5.
const float mapPosX = ms_MiniMapRenderState.m_vCurrentMiniMapPosition.x;
const float mapPosY = ms_MiniMapRenderState.m_vCurrentMiniMapPosition.y;
const float mapSizeX = ms_MiniMapRenderState.m_vCurrentMiniMapSize.x;
const float mapSizeY = ms_MiniMapRenderState.m_vCurrentMiniMapSize.y;
const float x1 = (vFrom.x - mapPosX)/mapSizeX - 0.5f;
const float y1 = (vFrom.y - mapPosY)/mapSizeY - 0.5f;
const float x2 = (vTo.x - mapPosX)/mapSizeX - 0.5f;
const float y2 = (vTo.y - mapPosY)/mapSizeY - 0.5f;
// Compute the direction of the line segment.
const float dirX = x2 - x1;
const float dirY = y2 - y1;
// Compute the square of the clip radius and the distance to the starting point.
static float s_ClipRadius = 0.43f; // MAGIC! This is MAX_2D_RADAR_DISTANCE in CMiniMap_RenderThread::UpdateIndividualBlip().
const float radiusSq = square(s_ClipRadius);
const float distSq = square(x1) + square(y1);
// Convert to a quadratic equation a*t^2 + b*t + c = 0.
const float a = square(dirX) + square(dirY);
const float b = 2.0f*(dirX*x1 + dirY*y1);
const float c = distSq - radiusSq;
// Make sure we don't divide by zero if it's a degenerate segment.
if(a != 0.0f)
{
// Transform to t^2 + p*t + q = 0 form.
const float p = b/a;
const float q = c/a;
// Check if there is a solution.
const float r2 = p*p - 4*q;
if(r2 > 0.0f)
{
// Yes, the infinite line intersects the circle.
// Compute the roots.
const float r = sqrtf(r2);
const float tt1 = 0.5f*(-p - r);
const float tt2 = 0.5f*(-p + r);
// Check if the relevant line segment part of the infinite line intersects.
if(tt2 >= 0.0f && tt1 <= 1.0f)
{
// Clamp the T values to not go outside the segment.
const float t1 = Clamp(tt1, 0.0f, 1.0f);
const float t2 = Clamp(tt2, 0.0f, 1.0f);
// Compute the clipped positions.
const float clippedx1 = x1 + dirX*t1;
const float clippedy1 = y1 + dirY*t1;
const float clippedx2 = x1 + dirX*t2;
const float clippedy2 = y1 + dirY*t2;
// Transform back to screen coordinates.
vFrom.x = (clippedx1 + 0.5f)*mapSizeX + mapPosX;
vFrom.y = (clippedy1 + 0.5f)*mapSizeY + mapPosY;
vTo.x = (clippedx2 + 0.5f)*mapSizeX + mapPosX;
vTo.y = (clippedy2 + 0.5f)*mapSizeY + mapPosY;
return true;
}
}
}
else if(c < 0.0f)
{
// Both points are in the same spot, but they are inside the circle.
return true;
}
// In this case, no part of the line segment intersects the disc.
return false;
}
#endif // __RENDER_PED_VISUAL_FIELD