1 #include "loadpgrd.hpp" 2 3 #include "esmreader.hpp" 4 #include "esmwriter.hpp" 5 #include "defs.hpp" 6 7 namespace ESM 8 { 9 unsigned int Pathgrid::sRecordId = REC_PGRD; 10 operator =(const float rhs[3])11 Pathgrid::Point& Pathgrid::Point::operator=(const float rhs[3]) 12 { 13 mX = static_cast<int>(rhs[0]); 14 mY = static_cast<int>(rhs[1]); 15 mZ = static_cast<int>(rhs[2]); 16 mAutogenerated = 0; 17 mConnectionNum = 0; 18 mUnknown = 0; 19 return *this; 20 } Point(const float rhs[3])21 Pathgrid::Point::Point(const float rhs[3]) 22 : mX(static_cast<int>(rhs[0])), 23 mY(static_cast<int>(rhs[1])), 24 mZ(static_cast<int>(rhs[2])), 25 mAutogenerated(0), 26 mConnectionNum(0), 27 mUnknown(0) 28 { 29 } Point()30 Pathgrid::Point::Point():mX(0),mY(0),mZ(0),mAutogenerated(0), 31 mConnectionNum(0),mUnknown(0) 32 { 33 } 34 load(ESMReader & esm,bool & isDeleted)35 void Pathgrid::load(ESMReader &esm, bool &isDeleted) 36 { 37 isDeleted = false; 38 39 mPoints.clear(); 40 mEdges.clear(); 41 42 // keep track of total connections so we can reserve edge vector size 43 int edgeCount = 0; 44 45 bool hasData = false; 46 while (esm.hasMoreSubs()) 47 { 48 esm.getSubName(); 49 switch (esm.retSubName().intval) 50 { 51 case ESM::SREC_NAME: 52 mCell = esm.getHString(); 53 break; 54 case ESM::FourCC<'D','A','T','A'>::value: 55 esm.getHT(mData, 12); 56 hasData = true; 57 break; 58 case ESM::FourCC<'P','G','R','P'>::value: 59 { 60 esm.getSubHeader(); 61 int size = esm.getSubSize(); 62 // Check that the sizes match up. Size = 16 * s2 (path points) 63 if (size != static_cast<int> (sizeof(Point) * mData.mS2)) 64 esm.fail("Path point subrecord size mismatch"); 65 else 66 { 67 int pointCount = mData.mS2; 68 mPoints.reserve(pointCount); 69 for (int i = 0; i < pointCount; ++i) 70 { 71 Point p; 72 esm.getExact(&p, sizeof(Point)); 73 mPoints.push_back(p); 74 edgeCount += p.mConnectionNum; 75 } 76 } 77 break; 78 } 79 case ESM::FourCC<'P','G','R','C'>::value: 80 { 81 esm.getSubHeader(); 82 int size = esm.getSubSize(); 83 if (size % sizeof(int) != 0) 84 esm.fail("PGRC size not a multiple of 4"); 85 else 86 { 87 int rawConnNum = size / sizeof(int); 88 std::vector<int> rawConnections; 89 rawConnections.reserve(rawConnNum); 90 for (int i = 0; i < rawConnNum; ++i) 91 { 92 int currentValue; 93 esm.getT(currentValue); 94 rawConnections.push_back(currentValue); 95 } 96 97 std::vector<int>::const_iterator rawIt = rawConnections.begin(); 98 int pointIndex = 0; 99 mEdges.reserve(edgeCount); 100 for(PointList::const_iterator it = mPoints.begin(); it != mPoints.end(); ++it, ++pointIndex) 101 { 102 unsigned char connectionNum = (*it).mConnectionNum; 103 if (rawConnections.end() - rawIt < connectionNum) 104 esm.fail("Not enough connections"); 105 for (int i = 0; i < connectionNum; ++i) { 106 Edge edge; 107 edge.mV0 = pointIndex; 108 edge.mV1 = *rawIt; 109 ++rawIt; 110 mEdges.push_back(edge); 111 } 112 } 113 } 114 break; 115 } 116 case ESM::SREC_DELE: 117 esm.skipHSub(); 118 isDeleted = true; 119 break; 120 default: 121 esm.fail("Unknown subrecord"); 122 break; 123 } 124 } 125 126 if (!hasData) 127 esm.fail("Missing DATA subrecord"); 128 } 129 save(ESMWriter & esm,bool isDeleted) const130 void Pathgrid::save(ESMWriter &esm, bool isDeleted) const 131 { 132 // Correct connection count and sort edges by point 133 // Can probably be optimized 134 PointList correctedPoints = mPoints; 135 std::vector<int> sortedEdges; 136 137 sortedEdges.reserve(mEdges.size()); 138 139 for (size_t point = 0; point < correctedPoints.size(); ++point) 140 { 141 correctedPoints[point].mConnectionNum = 0; 142 143 for (EdgeList::const_iterator it = mEdges.begin(); it != mEdges.end(); ++it) 144 { 145 if (static_cast<size_t>(it->mV0) == point) 146 { 147 sortedEdges.push_back(it->mV1); 148 ++correctedPoints[point].mConnectionNum; 149 } 150 } 151 } 152 153 // Save 154 esm.writeHNCString("NAME", mCell); 155 esm.writeHNT("DATA", mData, 12); 156 157 if (isDeleted) 158 { 159 esm.writeHNCString("DELE", ""); 160 return; 161 } 162 163 if (!correctedPoints.empty()) 164 { 165 esm.startSubRecord("PGRP"); 166 for (PointList::const_iterator it = correctedPoints.begin(); it != correctedPoints.end(); ++it) 167 { 168 esm.writeT(*it); 169 } 170 esm.endRecord("PGRP"); 171 } 172 173 if (!sortedEdges.empty()) 174 { 175 esm.startSubRecord("PGRC"); 176 for (std::vector<int>::const_iterator it = sortedEdges.begin(); it != sortedEdges.end(); ++it) 177 { 178 esm.writeT(*it); 179 } 180 esm.endRecord("PGRC"); 181 } 182 } 183 blank()184 void Pathgrid::blank() 185 { 186 mCell.clear(); 187 mData.mX = 0; 188 mData.mY = 0; 189 mData.mS1 = 0; 190 mData.mS2 = 0; 191 mPoints.clear(); 192 mEdges.clear(); 193 } 194 } 195