Ticket #599: update_visibility.patch

File update_visibility.patch, 12.4 KB (added by Itms, 10 years ago)
  • source/simulation2/components/CCmpRangeManager.cpp

     
    1 /* Copyright (C) 2013 Wildfire Games.
     1/* Copyright (C) 2014 Wildfire Games.
    22 * This file is part of 0 A.D.
    33 *
    44 * 0 A.D. is free software: you can redistribute it and/or modify
     
    3939#include "renderer/Scene.h"
    4040#include "lib/ps_stl.h"
    4141
    42 
     42#define LOS_TILES_RATIO 8
    4343#define DEBUG_RANGE_MANAGER_BOUNDS 0
    4444
    4545/**
     
    138138    EntityData() : retainInFog(0), owner(-1), inWorld(0), flags(1) { }
    139139    entity_pos_t x, z;
    140140    entity_pos_t visionRange;
     141    u32 visibilities; // 2-bit visibility, per player
    141142    u8 retainInFog; // boolean
    142143    i8 owner;
    143144    u8 inWorld; // boolean
     
    144145    u8 flags; // See GetEntityFlagMask
    145146};
    146147
    147 cassert(sizeof(EntityData) == 16);
     148cassert(sizeof(EntityData) == 20);
    148149
    149150/**
    150151 * Serialization helper template for Query
     
    197198        serialize.NumberFixed_Unbounded("z", value.z);
    198199        serialize.NumberFixed_Unbounded("vision", value.visionRange);
    199200        serialize.NumberU8("retain in fog", value.retainInFog, 0, 1);
     201        serialize.NumberU32_Unbounded("visibilities", value.visibilities);
    200202        serialize.NumberI8_Unbounded("owner", value.owner);
    201203        serialize.NumberU8("in world", value.inWorld, 0, 1);
    202204        serialize.NumberU8_Unbounded("flags", value.flags);
     
    283285    bool m_LosCircular;
    284286    i32 m_TerrainVerticesPerSide;
    285287    size_t m_TerritoriesDirtyID;
     288   
     289    // Cache for visibility tracking (not serialized)
     290    i32 m_LosTilesPerSide;
     291    bool* m_DirtyVisibility;
     292    std::vector<std::set<entity_id_t>> m_LosTiles;
     293    // List of entities that must be updated, regardless of the status of their tile
     294    std::vector<entity_id_t> m_ModifiedEntities;
    286295
    287296    // Counts of units seeing vertex, per vertex, per player (starting with player 0).
    288297    // Use u16 to avoid overflows when we have very large (but not infeasibly large) numbers
     
    332341        m_LosCircular = false;
    333342        m_TerrainVerticesPerSide = 0;
    334343
     344        m_DirtyVisibility = NULL;
     345
    335346        m_TerritoriesDirtyID = 0;
    336347    }
    337348
    338349    virtual void Deinit()
    339350    {
     351        delete[] m_DirtyVisibility;
    340352    }
    341353
    342354    template<typename S>
     
    355367        serialize.Bool("los circular", m_LosCircular);
    356368        serialize.NumberI32_Unbounded("terrain verts per side", m_TerrainVerticesPerSide);
    357369
    358         // We don't serialize m_Subdivision or m_LosPlayerCounts
     370        SerializeVector<SerializeU32_Unbounded>()(serialize, "modified entities", m_ModifiedEntities);
     371
     372        // We don't serialize m_Subdivision, m_LosPlayerCounts or m_LosTiles
    359373        // since they can be recomputed from the entity data when deserializing;
    360374        // m_LosState must be serialized since it depends on the history of exploration
    361375
     
    432446                    CFixedVector2D to(msgData.x, msgData.z);
    433447                    m_Subdivision.Move(ent, from, to);
    434448                    LosMove(it->second.owner, it->second.visionRange, from, to);
     449                    i32 oldLosTile = PosToLosTilesHelper(it->second.x, it->second.z);
     450                    i32 newLosTile = PosToLosTilesHelper(msgData.x, msgData.z);
     451                    if (oldLosTile != newLosTile)
     452                    {
     453                        RemoveFromTile(oldLosTile, ent);
     454                        AddToTile(newLosTile, ent);
     455                    }
    435456                }
    436457                else
    437458                {
     
    438459                    CFixedVector2D to(msgData.x, msgData.z);
    439460                    m_Subdivision.Add(ent, to);
    440461                    LosAdd(it->second.owner, it->second.visionRange, to);
     462                    AddToTile(PosToLosTilesHelper(msgData.x, msgData.z), ent);
    441463                }
    442464
    443465                it->second.inWorld = 1;
     
    451473                    CFixedVector2D from(it->second.x, it->second.z);
    452474                    m_Subdivision.Remove(ent, from);
    453475                    LosRemove(it->second.owner, it->second.visionRange, from);
     476                    RemoveFromTile(PosToLosTilesHelper(it->second.x, it->second.z), ent);
    454477                }
    455478
    456479                it->second.inWorld = 0;
     
    458481                it->second.z = entity_pos_t::Zero();
    459482            }
    460483
     484            m_ModifiedEntities.push_back(ent);
     485
    461486            break;
    462487        }
    463488        case MT_OwnershipChanged:
     
    495520                break;
    496521
    497522            if (it->second.inWorld)
     523            {
    498524                m_Subdivision.Remove(ent, CFixedVector2D(it->second.x, it->second.z));
     525                RemoveFromTile(PosToLosTilesHelper(it->second.x, it->second.z), ent);
     526            }
    499527
    500528            // This will be called after Ownership's OnDestroy, so ownership will be set
    501529            // to -1 already and we don't have to do a LosRemove here
     
    539567        case MT_Update:
    540568        {
    541569            m_DebugOverlayDirty = true;
     570            UpdateVisibilityData();
    542571            UpdateTerritoriesLos();
    543572            ExecuteActiveQueries();
    544573            break;
     
    559588        m_WorldX1 = x1;
    560589        m_WorldZ1 = z1;
    561590        m_TerrainVerticesPerSide = (i32)vertices;
     591       
     592        m_LosTilesPerSide = (m_TerrainVerticesPerSide - 1)/LOS_TILES_RATIO;
    562593
    563594        ResetDerivedData(false);
    564595    }
     
    639670        }
    640671        m_LosStateRevealed.clear();
    641672        m_LosStateRevealed.resize(m_TerrainVerticesPerSide*m_TerrainVerticesPerSide);
     673       
     674        delete[] m_DirtyVisibility;
     675        m_DirtyVisibility = new bool[m_LosTilesPerSide*m_LosTilesPerSide]();
     676        m_LosTiles.clear();
     677        m_LosTiles.resize(m_LosTilesPerSide*m_LosTilesPerSide);
    642678
    643679        for (EntityMap<EntityData>::const_iterator it = m_EntityData.begin(); it != m_EntityData.end(); ++it)
    644680        {
    645681            if (it->second.inWorld)
     682            {
    646683                LosAdd(it->second.owner, it->second.visionRange, CFixedVector2D(it->second.x, it->second.z));
     684                AddToTile(PosToLosTilesHelper(it->second.x, it->second.z), it->first);
     685            }
    647686        }
    648687
    649688        m_TotalInworldVertices = 0;
     
    13841423        return GetLosVisibility(handle, player, forceRetainInFog);
    13851424    }
    13861425
     1426    i32 PosToLosTilesHelper(entity_pos_t x, entity_pos_t z)
     1427    {
     1428        i32 i = Clamp(
     1429            (x/(entity_pos_t::FromInt(TERRAIN_TILE_SIZE * LOS_TILES_RATIO))).ToInt_RoundToZero(),
     1430            0,
     1431            m_LosTilesPerSide - 1);
     1432        i32 j = Clamp(
     1433            (z/(entity_pos_t::FromInt(TERRAIN_TILE_SIZE * LOS_TILES_RATIO))).ToInt_RoundToZero(),
     1434            0,
     1435            m_LosTilesPerSide - 1);
     1436        return j*m_LosTilesPerSide + i;
     1437    }
    13871438
     1439    void AddToTile(i32 tile, entity_id_t ent)
     1440    {
     1441        m_LosTiles[tile].insert(ent);
     1442    }
     1443
     1444    void RemoveFromTile(i32 tile, entity_id_t ent)
     1445    {
     1446        for (std::set<entity_id_t>::iterator tileIt = m_LosTiles[tile].begin();
     1447            tileIt != m_LosTiles[tile].end();
     1448            ++tileIt)
     1449        {
     1450            if (*tileIt == ent)
     1451            {
     1452                m_LosTiles[tile].erase(tileIt);
     1453                return;
     1454            }
     1455        }
     1456    }
     1457
     1458    void UpdateVisibilityData()
     1459    {
     1460        PROFILE("UpdateVisibilityData");
     1461       
     1462        for (i32 n = 0; n < m_LosTilesPerSide*m_LosTilesPerSide; ++n)
     1463        {
     1464            if (m_DirtyVisibility[n])
     1465            {
     1466                for (std::set<entity_id_t>::iterator it = m_LosTiles[n].begin();
     1467                    it != m_LosTiles[n].end();
     1468                    ++it)
     1469                {
     1470                    UpdateVisibility(*it);
     1471                }
     1472                m_DirtyVisibility[n] = false;
     1473            }
     1474        }
     1475
     1476        for (std::vector<entity_id_t>::iterator it = m_ModifiedEntities.begin(); it != m_ModifiedEntities.end(); ++it)
     1477        {
     1478            UpdateVisibility(*it);
     1479        }
     1480        m_ModifiedEntities.clear();
     1481    }
     1482
     1483    void UpdateVisibility(entity_id_t ent)
     1484    {
     1485        EntityMap<EntityData>::iterator itEnts = m_EntityData.find(ent);
     1486        if (itEnts == m_EntityData.end())
     1487            return;
     1488       
     1489        for (player_id_t player = 1; player <= MAX_LOS_PLAYER_ID; ++player)
     1490        {
     1491            u8 oldVis = (itEnts->second.visibilities >> (2*player)) & 0x3;
     1492            u8 newVis = GetLosVisibility(itEnts->first, player, false);
     1493
     1494            if (oldVis != newVis)
     1495            {
     1496                CMessageVisibilityChanged msg(player, ent, oldVis, newVis);
     1497                GetSimContext().GetComponentManager().PostMessage(ent, msg);
     1498                itEnts->second.visibilities = (itEnts->second.visibilities & ~(0x3 << 2*player)) | (newVis << 2*player);
     1499            }
     1500        }
     1501    }
     1502
    13881503    virtual void SetLosRevealAll(player_id_t player, bool enabled)
    13891504    {
    13901505        if (player == -1)
     
    15321647                    explored += !(m_LosState[idx] & (LOS_EXPLORED << (2*(owner-1))));
    15331648                    m_LosState[idx] |= ((LOS_VISIBLE | LOS_EXPLORED) << (2*(owner-1)));
    15341649                }
     1650                m_DirtyVisibility[(j/LOS_TILES_RATIO)*m_LosTilesPerSide + i/LOS_TILES_RATIO] = true;
    15351651            }
    15361652
    15371653            ASSERT(counts[idx] < 65535);
     
    15591675            {
    15601676                // (If LosIsOffWorld then this is a no-op, so don't bother doing the check)
    15611677                m_LosState[idx] &= ~(LOS_VISIBLE << (2*(owner-1)));
     1678
     1679                i32 i = i0 + idx - idx0;
     1680                m_DirtyVisibility[(j/LOS_TILES_RATIO)*m_LosTilesPerSide + i/LOS_TILES_RATIO] = true;
    15621681            }
    15631682        }
    15641683    }
  • source/simulation2/components/ICmpRangeManager.cpp

     
    1 /* Copyright (C) 2013 Wildfire Games.
     1/* Copyright (C) 2014 Wildfire Games.
    22 * This file is part of 0 A.D.
    33 *
    44 * 0 A.D. is free software: you can redistribute it and/or modify
  • source/simulation2/components/ICmpRangeManager.h

     
    1 /* Copyright (C) 2013 Wildfire Games.
     1/* Copyright (C) 2014 Wildfire Games.
    22 * This file is part of 0 A.D.
    33 *
    44 * 0 A.D. is free software: you can redistribute it and/or modify
     
    216216
    217217    enum ELosVisibility
    218218    {
    219         VIS_HIDDEN,
    220         VIS_FOGGED,
    221         VIS_VISIBLE
     219        VIS_HIDDEN = 0,
     220        VIS_FOGGED = 1,
     221        VIS_VISIBLE = 2
    222222    };
    223223
    224224    /**
     
    326326    virtual ELosVisibility GetLosVisibility(CEntityHandle ent, player_id_t player, bool forceRetainInFog = false) = 0;
    327327    virtual ELosVisibility GetLosVisibility(entity_id_t ent, player_id_t player, bool forceRetainInFog = false) = 0;
    328328
     329
    329330    /**
    330331     * GetLosVisibility wrapped for script calls.
    331332     * Returns "hidden", "fogged" or "visible".
  • source/simulation2/MessageTypes.h

     
    1 /* Copyright (C) 2013 Wildfire Games.
     1/* Copyright (C) 2014 Wildfire Games.
    22 * This file is part of 0 A.D.
    33 *
    44 * 0 A.D. is free software: you can redistribute it and/or modify
     
    362362};
    363363
    364364/**
     365 * Sent, at most once per turn, when the visibility of an entity changed
     366 */
     367class CMessageVisibilityChanged : public CMessage
     368{
     369public:
     370    DEFAULT_MESSAGE_IMPL(VisibilityChanged)
     371
     372    CMessageVisibilityChanged(player_id_t player, entity_id_t ent, int oldVisibility, int newVisibility) :
     373        player(player), ent(ent), oldVisibility(oldVisibility), newVisibility(newVisibility)
     374    {
     375    }
     376
     377    player_id_t player;
     378    entity_id_t ent;
     379    int oldVisibility;
     380    int newVisibility;
     381};
     382
     383/**
    365384 * Sent when ObstructionManager's view of the shape of the world has changed
    366385 * (changing the TILE_OUTOFBOUNDS tiles returned by Rasterise).
    367386 */
  • source/simulation2/scripting/MessageTypeConversions.cpp

     
    1 /* Copyright (C) 2013 Wildfire Games.
     1/* Copyright (C) 2014 Wildfire Games.
    22 * This file is part of 0 A.D.
    33 *
    44 * 0 A.D. is free software: you can redistribute it and/or modify
     
    310310
    311311////////////////////////////////
    312312
     313jsval CMessageVisibilityChanged::ToJSVal(ScriptInterface& scriptInterface) const
     314{
     315    TOJSVAL_SETUP();
     316    SET_MSG_PROPERTY(player);
     317    SET_MSG_PROPERTY(ent);
     318    SET_MSG_PROPERTY(oldVisibility);
     319    SET_MSG_PROPERTY(newVisibility);
     320    return OBJECT_TO_JSVAL(obj);
     321}
     322
     323CMessage* CMessageVisibilityChanged::FromJSVal(ScriptInterface& scriptInterface, jsval val)
     324{
     325    FROMJSVAL_SETUP();
     326    GET_MSG_PROPERTY(player_id_t, player);
     327    GET_MSG_PROPERTY(entity_id_t, ent);
     328    GET_MSG_PROPERTY(int, oldVisibility);
     329    GET_MSG_PROPERTY(int, newVisibility);
     330    return new CMessageVisibilityChanged(player, ent, oldVisibility, newVisibility);
     331}
     332
     333////////////////////////////////
     334
    313335jsval CMessageWaterChanged::ToJSVal(ScriptInterface& scriptInterface) const
    314336{
    315337    TOJSVAL_SETUP();
  • source/simulation2/TypeList.h

     
    1 /* Copyright (C) 2013 Wildfire Games.
     1/* Copyright (C) 2014 Wildfire Games.
    22 * This file is part of 0 A.D.
    33 *
    44 * 0 A.D. is free software: you can redistribute it and/or modify
     
    4848MESSAGE(MotionChanged)
    4949MESSAGE(RangeUpdate)
    5050MESSAGE(TerrainChanged)
     51MESSAGE(VisibilityChanged)
    5152MESSAGE(WaterChanged)
    5253MESSAGE(ObstructionMapShapeChanged)
    5354MESSAGE(TerritoriesChanged)