text: #include "Map.h"
  
  #include <stdlib.h> 
  
  using namespace std;
  
  Map::Map(ViewRenderer *pViewRenderer, const std::string &sName, Player *pPlayer, Things *pThings) : m_sName(sName), m_XMin(INT_MAX), m_XMax(INT_MIN), m_YMin(INT_MAX), m_YMax(INT_MIN), m_iLumpIndex(-1), m_pPlayer(pPlayer), m_pThings(pThings), m_pViewRenderer(pViewRenderer)
  {
      m_pSectors = new std::vector<WADSector>();
      m_pSidedefs = new std::vector<WADSidedef>();
      m_pLinedefs = new std::vector<WADLinedef>();
      m_pSegs = new std::vector<WADSeg>();
  }
  
  Map::~Map()
  {
  }
  
  void Map::Init()
  {
      BuildSectors();
      BuildSidedefs();
      BuildLinedef();
      BuildSeg();
  }
  
  void Map::BuildSectors()
  {
      WADSector wadsector;
      Sector sector;
      for (int i = 0; i < m_pSectors->size(); ++i)
      {
          wadsector = m_pSectors->at(i);
          sector.FloorHeight = wadsector.FloorHeight;
          sector.CeilingHeight = wadsector.CeilingHeight;
          strncpy_s(sector.FloorTexture, wadsector.FloorTexture, 8);
          sector.FloorTexture[8] = '\0';
          strncpy_s(sector.CeilingTexture, wadsector.CeilingTexture, 8);
          sector.CeilingTexture[8] = '\0';
          sector.Lightlevel = wadsector.Lightlevel;
          sector.Type = wadsector.Type;
          sector.Tag = wadsector.Tag;
          m_Sectors.push_back(sector);
      }
      delete m_pSectors;
      m_pSectors = nullptr;
  }
  
  void Map::BuildSidedefs()
  {
      WADSidedef wadsidedef;
      Sidedef sidedef;
      for (int i = 0; i < m_pSidedefs->size(); ++i)
      {
          wadsidedef = m_pSidedefs->at(i);
          sidedef.XOffset = wadsidedef.XOffset;
          sidedef.YOffset = wadsidedef.YOffset;
          strncpy_s(sidedef.UpperTexture, wadsidedef.UpperTexture, 8);
          sidedef.UpperTexture[8] = '\0';
          strncpy_s(sidedef.LowerTexture, wadsidedef.LowerTexture, 8);
          sidedef.LowerTexture[8] = '\0';
          strncpy_s(sidedef.MiddleTexture, wadsidedef.MiddleTexture, 8);
          sidedef.MiddleTexture[8] = '\0';
          sidedef.pSector = &m_Sectors[wadsidedef.SectorID];
          m_Sidedefs.push_back(sidedef);
      }
      delete m_pSidedefs;
      m_pSidedefs = nullptr;
  }
  
  void Map::BuildLinedef()
  {
      WADLinedef wadlinedef;
      Linedef linedef;
  
      for (int i = 0; i < m_pLinedefs->size(); ++i)
      {
          wadlinedef = m_pLinedefs->at(i);
  
          linedef.pStartVertex = &m_Vertexes[wadlinedef.StartVertexID];
          linedef.pEndVertex = &m_Vertexes[wadlinedef.EndVertexID];
          linedef.Flags = wadlinedef.Flags;
          linedef.LineType = wadlinedef.LineType;
          linedef.SectorTag = wadlinedef.SectorTag;
  
          if (wadlinedef.RightSidedef == 0xFFFF)
          {
              linedef.pRightSidedef = nullptr;
          }
          else
          {
              linedef.pRightSidedef = &m_Sidedefs[wadlinedef.RightSidedef];
          }
  
          if (wadlinedef.LeftSidedef == 0xFFFF)
          {
              linedef.pLeftSidedef = nullptr;
          }
          else
          {
              linedef.pLeftSidedef = &m_Sidedefs[wadlinedef.LeftSidedef];
          }
  
          m_Linedefs.push_back(linedef);
      }
  
      delete m_pLinedefs;
      m_pLinedefs = nullptr;
  }
  
  void Map::BuildSeg()
  {
      WADSeg wadseg;
      Seg seg;
  
      for (int i = 0; i < m_pSegs->size(); ++i)
      {
          wadseg = m_pSegs->at(i);
  
          seg.pStartVertex = &m_Vertexes[wadseg.StartVertexID];
          seg.pEndVertex = &m_Vertexes[wadseg.EndVertexID];
          // 8.38190317e-8 is to conver from Binary angles (BAMS) to float
          seg.SlopeAngle = ((float)(wadseg.SlopeAngle << 16) * 8.38190317e-8);
          seg.pLinedef = &m_Linedefs[wadseg.LinedefID];
          seg.Direction = wadseg.Direction;
          seg.Offset = (float)(wadseg.Offset << 16) / (float)(1 << 16);
  
          Sidedef *pRightSidedef;
          Sidedef *pLeftSidedef;
  
          if (seg.Direction)
          {
              pRightSidedef = seg.pLinedef->pLeftSidedef;
              pLeftSidedef = seg.pLinedef->pRightSidedef;
          }
          else
          {
              pRightSidedef = seg.pLinedef->pRightSidedef;
              pLeftSidedef = seg.pLinedef->pLeftSidedef;
          }
  
          if (pRightSidedef)
          {
              seg.pRightSector = pRightSidedef->pSector;
          }
          else
          {
              seg.pRightSector = nullptr;
          }
  
          if (pLeftSidedef)
          {
              seg.pLeftSector = pLeftSidedef->pSector;
          }
          else
          {
              seg.pLeftSector = nullptr;
          }
  
          m_Segs.push_back(seg);
      }
  
      delete m_pSegs;
      m_pSegs = nullptr;
  }
  
  void Map::AddVertex(Vertex &v)
  {
      m_Vertexes.push_back(v);
  
      if (m_XMin > v.XPosition)
      {
          m_XMin = v.XPosition;
      }
      else if (m_XMax < v.XPosition)
      {
          m_XMax = v.XPosition;
      }
  
      if (m_YMin > v.YPosition)
      {
          m_YMin = v.YPosition;
      }
      else if (m_YMax < v.YPosition)
      {
          m_YMax = v.YPosition;
      }
  }
  
  void Map::AddSidedef(WADSidedef &sidedef)
  {
      m_pSidedefs->push_back(sidedef);
  }
  
  void Map::AddSector(WADSector &sector)
  {
      m_pSectors->push_back(sector);
  }
  
  int Map::GetXMin()
  {
      return m_XMin;
  }
  
  int Map::GetXMax()
  {
      return m_XMax;
  }
  
  int Map::GetYMin()
  {
      return m_YMin;
  }
  
  int Map::GetYMax()
  {
      return m_YMax;
  }
  
  void Map::AddLinedef(WADLinedef &l)
  {
      m_pLinedefs->push_back(l);
  }
  
  void Map::AddNode(Node &node)
  {
      m_Nodes.push_back(node);
  }
  
  void Map::AddSubsector(Subsector &subsector)
  {
      m_Subsector.push_back(subsector);
  }
  
  void Map::AddSeg(WADSeg &seg)
  {
      m_pSegs->push_back(seg);
  }
  
  string Map::GetName()
  {
      return m_sName;
  }
  
  void Map::Render3DView()
  {
      RenderBSPNodes();
  }
  
  void Map::RenderBSPNodes()
  {
      RenderBSPNodes(m_Nodes.size() - 1);
  }
  
  void Map::RenderBSPNodes(int iNodeID)
  {
      // Masking all the bits exipt the last one
      // to check if this is a subsector
      if (iNodeID & SUBSECTORIDENTIFIER)
      {
          RenderSubsector(iNodeID & (~SUBSECTORIDENTIFIER));
          return;
      }
  
      bool isOnLeft = IsPointOnLeftSide(m_pPlayer->GetXPosition(), m_pPlayer->GetYPosition(), iNodeID);
  
      if (isOnLeft)
      {
          RenderBSPNodes(m_Nodes[iNodeID].LeftChildID);
          RenderBSPNodes(m_Nodes[iNodeID].RightChildID);
      }
      else
      {
          RenderBSPNodes(m_Nodes[iNodeID].RightChildID);
          RenderBSPNodes(m_Nodes[iNodeID].LeftChildID);
      }
  }
  
  void Map::RenderSubsector(int iSubsectorID)
  {
      Subsector &subsector = m_Subsector[iSubsectorID];
  
      for (int i = 0; i < subsector.SegCount; i++)
      {
          Seg &seg = m_Segs[subsector.FirstSegID + i];
          Angle V1Angle, V2Angle, V1AngleFromPlayer, V2AngleFromPlayer;
          if (m_pPlayer->ClipVertexesInFOV(*(seg.pStartVertex), *(seg.pEndVertex), V1Angle, V2Angle, V1AngleFromPlayer, V2AngleFromPlayer))
          {
              m_pViewRenderer->AddWallInFOV(seg, V1Angle, V2Angle, V1AngleFromPlayer, V2AngleFromPlayer);
          }
      }
  }
  
  bool Map::IsPointOnLeftSide(int XPosition, int YPosition, int iNodeID)
  {
      int dx = XPosition - m_Nodes[iNodeID].XPartition;
      int dy = YPosition - m_Nodes[iNodeID].YPartition;
  
      return (((dx * m_Nodes[iNodeID].ChangeYPartition) - (dy * m_Nodes[iNodeID].ChangeXPartition)) <= 0);
  }
  
  void Map::SetLumpIndex(int iIndex)
  {
      m_iLumpIndex = iIndex;
  }
  
  int Map::GetLumpIndex()
  {
      return m_iLumpIndex;
  }
  
  Things* Map::GetThings()
  {
      return m_pThings;
  }
  
  int Map::GetPlayerSubSectorHieght()
  {
      int iSubsectorID = m_Nodes.size() - 1;
      while (!(iSubsectorID & SUBSECTORIDENTIFIER))
      {
  
          bool isOnLeft = IsPointOnLeftSide(m_pPlayer->GetXPosition(), m_pPlayer->GetYPosition(), iSubsectorID);
  
          if (isOnLeft)
          {
              iSubsectorID = m_Nodes[iSubsectorID].LeftChildID;
          }
          else
          {
              iSubsectorID = m_Nodes[iSubsectorID].RightChildID;
          }
      }
      Subsector &subsector = m_Subsector[iSubsectorID & (~SUBSECTORIDENTIFIER)];
      Seg &seg = m_Segs[subsector.FirstSegID];
      return seg.pRightSector->FloorHeight;
      
  }
  