#ifndef GAME_RENDER_LOCALMAP_H #define GAME_RENDER_LOCALMAP_H #include #include #include #include #include #include #include namespace MWWorld { class CellStore; } namespace ESM { struct FogTexture; } namespace osg { class Texture2D; class Image; class Camera; class Group; class Node; } namespace MWRender { class LocalMapRenderToTexture; /// /// \brief Local map rendering /// class LocalMap { public: LocalMap(osg::Group* root); ~LocalMap(); /** * Clear all savegame-specific data (i.e. fog of war textures) */ void clear(); /** * Request a map render for the given cell. Render textures will be immediately created and can be retrieved * with the getMapTexture function. */ void requestMap(const MWWorld::CellStore* cell); void addCell(MWWorld::CellStore* cell); void removeExteriorCell(int x, int y); void removeCell(MWWorld::CellStore* cell); osg::ref_ptr getMapTexture(int x, int y); osg::ref_ptr getFogOfWarTexture(int x, int y); /** * Removes cameras that have already been rendered. Should be called every frame to ensure that * we do not render the same map more than once. Note, this cleanup is difficult to implement in an * automated fashion, since we can't alter the scene graph structure from within an update callback. */ void cleanupCameras(); /** * Set the position & direction of the player, and returns the position in map space through the reference * parameters. * @remarks This is used to draw a "fog of war" effect * to hide areas on the map the player has not discovered yet. */ void updatePlayer(const osg::Vec3f& position, const osg::Quat& orientation, float& u, float& v, int& x, int& y, osg::Vec3f& direction); /** * Save the fog of war for this cell to its CellStore. * @remarks This should be called when unloading a cell, and for all active cells prior to saving the game. */ void saveFogOfWar(MWWorld::CellStore* cell); /** * Get the interior map texture index and normalized position on this texture, given a world position */ void worldToInteriorMapPosition(osg::Vec2f pos, float& nX, float& nY, int& x, int& y); osg::Vec2f interiorMapToWorldPosition(float nX, float nY, int x, int y); /** * Check if a given position is explored by the player (i.e. not obscured by fog of war) */ bool isPositionExplored(float nX, float nY, int x, int y); osg::Group* getRoot(); private: osg::ref_ptr mRoot; osg::ref_ptr mSceneRoot; typedef std::vector> RTTVector; RTTVector mLocalMapRTTs; typedef std::set> Grid; Grid mCurrentGrid; enum NeighbourCellFlag : std::uint8_t { NeighbourCellTopLeft = 1, NeighbourCellTopCenter = 1 << 1, NeighbourCellTopRight = 1 << 2, NeighbourCellMiddleLeft = 1 << 3, NeighbourCellMiddleRight = 1 << 4, NeighbourCellBottomLeft = 1 << 5, NeighbourCellBottomCenter = 1 << 6, NeighbourCellBottomRight = 1 << 7, }; struct MapSegment { void initFogOfWar(); void loadFogOfWar(const ESM::FogTexture& fog); void saveFogOfWar(ESM::FogTexture& fog) const; void createFogOfWarTexture(); std::uint8_t mLastRenderNeighbourFlags = 0; bool mHasFogState = false; osg::ref_ptr mMapTexture; osg::ref_ptr mFogOfWarTexture; osg::ref_ptr mFogOfWarImage; }; typedef std::map, MapSegment> SegmentMap; SegmentMap mExteriorSegments; SegmentMap mInteriorSegments; int mMapResolution; // the dynamic texture is a bottleneck, so don't set this too high static const int sFogOfWarResolution = 32; // size of a map segment (for exteriors, 1 cell) float mMapWorldSize; int mCellDistance; float mAngle; const osg::Vec2f rotatePoint(const osg::Vec2f& point, const osg::Vec2f& center, const float angle); void requestExteriorMap(const MWWorld::CellStore* cell, MapSegment& segment); void requestInteriorMap(const MWWorld::CellStore* cell); void setupRenderToTexture( int segment_x, int segment_y, float left, float top, const osg::Vec3d& upVector, float zmin, float zmax); bool mInterior; osg::BoundingBox mBounds; std::uint8_t getExteriorNeighbourFlags(int cellX, int cellY) const; }; } #endif