forked from teamnwah/openmw-tes3coop
More ESM records have DELE handling.
Changed records: Race, Land, Pathgrid, StartScript, DebugProfile, Filter
This commit is contained in:
parent
ad353e6dd0
commit
e65ff723ce
12 changed files with 504 additions and 307 deletions
|
@ -7,17 +7,53 @@
|
||||||
|
|
||||||
unsigned int ESM::DebugProfile::sRecordId = REC_DBGP;
|
unsigned int ESM::DebugProfile::sRecordId = REC_DBGP;
|
||||||
|
|
||||||
|
ESM::DebugProfile::DebugProfile()
|
||||||
|
: mIsDeleted(false)
|
||||||
|
{}
|
||||||
|
|
||||||
void ESM::DebugProfile::load (ESMReader& esm)
|
void ESM::DebugProfile::load (ESMReader& esm)
|
||||||
{
|
{
|
||||||
mId = esm.getHNString ("NAME");
|
mIsDeleted = false;
|
||||||
mDescription = esm.getHNString ("DESC");
|
|
||||||
mScriptText = esm.getHNString ("SCRP");
|
while (esm.hasMoreSubs())
|
||||||
esm.getHNT (mFlags, "FLAG");
|
{
|
||||||
|
esm.getSubName();
|
||||||
|
uint32_t name = esm.retSubName().val;
|
||||||
|
switch (name)
|
||||||
|
{
|
||||||
|
case ESM::FourCC<'N','A','M','E'>::value:
|
||||||
|
mId = esm.getHString();
|
||||||
|
break;
|
||||||
|
case ESM::FourCC<'D','E','L','E'>::value:
|
||||||
|
esm.skipHSub();
|
||||||
|
mIsDeleted = true;
|
||||||
|
break;
|
||||||
|
case ESM::FourCC<'D','E','S','C'>::value:
|
||||||
|
mDescription = esm.getHString();
|
||||||
|
break;
|
||||||
|
case ESM::FourCC<'S','C','R','P'>::value:
|
||||||
|
mScriptText = esm.getHString();
|
||||||
|
break;
|
||||||
|
case ESM::FourCC<'F','L','A','G'>::value:
|
||||||
|
esm.getHT(mFlags);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
esm.fail("Unknown subrecord");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ESM::DebugProfile::save (ESMWriter& esm) const
|
void ESM::DebugProfile::save (ESMWriter& esm) const
|
||||||
{
|
{
|
||||||
esm.writeHNCString ("NAME", mId);
|
esm.writeHNCString ("NAME", mId);
|
||||||
|
|
||||||
|
if (mIsDeleted)
|
||||||
|
{
|
||||||
|
esm.writeHNCString("DELE", "");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
esm.writeHNCString ("DESC", mDescription);
|
esm.writeHNCString ("DESC", mDescription);
|
||||||
esm.writeHNCString ("SCRP", mScriptText);
|
esm.writeHNCString ("SCRP", mScriptText);
|
||||||
esm.writeHNT ("FLAG", mFlags);
|
esm.writeHNT ("FLAG", mFlags);
|
||||||
|
@ -28,4 +64,5 @@ void ESM::DebugProfile::blank()
|
||||||
mDescription.clear();
|
mDescription.clear();
|
||||||
mScriptText.clear();
|
mScriptText.clear();
|
||||||
mFlags = 0;
|
mFlags = 0;
|
||||||
|
mIsDeleted = false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,10 @@ namespace ESM
|
||||||
|
|
||||||
unsigned int mFlags;
|
unsigned int mFlags;
|
||||||
|
|
||||||
|
bool mIsDeleted;
|
||||||
|
|
||||||
|
DebugProfile();
|
||||||
|
|
||||||
void load (ESMReader& esm);
|
void load (ESMReader& esm);
|
||||||
void save (ESMWriter& esm) const;
|
void save (ESMWriter& esm) const;
|
||||||
|
|
||||||
|
|
|
@ -7,16 +7,50 @@
|
||||||
|
|
||||||
unsigned int ESM::Filter::sRecordId = REC_FILT;
|
unsigned int ESM::Filter::sRecordId = REC_FILT;
|
||||||
|
|
||||||
|
ESM::Filter::Filter()
|
||||||
|
: mIsDeleted(false)
|
||||||
|
{}
|
||||||
|
|
||||||
void ESM::Filter::load (ESMReader& esm)
|
void ESM::Filter::load (ESMReader& esm)
|
||||||
{
|
{
|
||||||
mId = esm.getHNString ("NAME");
|
mIsDeleted = false;
|
||||||
mFilter = esm.getHNString ("FILT");
|
|
||||||
mDescription = esm.getHNString ("DESC");
|
while (esm.hasMoreSubs())
|
||||||
|
{
|
||||||
|
esm.getSubName();
|
||||||
|
uint32_t name = esm.retSubName().val;
|
||||||
|
switch (name)
|
||||||
|
{
|
||||||
|
case ESM::FourCC<'N','A','M','E'>::value:
|
||||||
|
mId = esm.getHString();
|
||||||
|
break;
|
||||||
|
case ESM::FourCC<'D','E','L','E'>::value:
|
||||||
|
esm.skipHSub();
|
||||||
|
mIsDeleted = true;
|
||||||
|
break;
|
||||||
|
case ESM::FourCC<'F','I','L','T'>::value:
|
||||||
|
mFilter = esm.getHString();
|
||||||
|
break;
|
||||||
|
case ESM::FourCC<'D','E','S','C'>::value:
|
||||||
|
mDescription = esm.getHString();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
esm.fail("Unknown subrecord");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ESM::Filter::save (ESMWriter& esm) const
|
void ESM::Filter::save (ESMWriter& esm) const
|
||||||
{
|
{
|
||||||
esm.writeHNCString ("NAME", mId);
|
esm.writeHNCString ("NAME", mId);
|
||||||
|
|
||||||
|
if (mIsDeleted)
|
||||||
|
{
|
||||||
|
esm.writeHNCString("DELE", "");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
esm.writeHNCString ("FILT", mFilter);
|
esm.writeHNCString ("FILT", mFilter);
|
||||||
esm.writeHNCString ("DESC", mDescription);
|
esm.writeHNCString ("DESC", mDescription);
|
||||||
}
|
}
|
||||||
|
@ -25,4 +59,5 @@ void ESM::Filter::blank()
|
||||||
{
|
{
|
||||||
mFilter.clear();
|
mFilter.clear();
|
||||||
mDescription.clear();
|
mDescription.clear();
|
||||||
|
mIsDeleted = false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,10 @@ namespace ESM
|
||||||
|
|
||||||
std::string mFilter;
|
std::string mFilter;
|
||||||
|
|
||||||
|
bool mIsDeleted;
|
||||||
|
|
||||||
|
Filter();
|
||||||
|
|
||||||
void load (ESMReader& esm);
|
void load (ESMReader& esm);
|
||||||
void save (ESMWriter& esm) const;
|
void save (ESMWriter& esm) const;
|
||||||
|
|
||||||
|
|
|
@ -8,211 +8,234 @@ namespace ESM
|
||||||
{
|
{
|
||||||
unsigned int Land::sRecordId = REC_LAND;
|
unsigned int Land::sRecordId = REC_LAND;
|
||||||
|
|
||||||
void Land::LandData::save(ESMWriter &esm)
|
void Land::LandData::save(ESMWriter &esm)
|
||||||
{
|
{
|
||||||
if (mDataTypes & Land::DATA_VNML) {
|
if (mDataTypes & Land::DATA_VNML) {
|
||||||
esm.writeHNT("VNML", mNormals, sizeof(mNormals));
|
esm.writeHNT("VNML", mNormals, sizeof(mNormals));
|
||||||
}
|
}
|
||||||
if (mDataTypes & Land::DATA_VHGT) {
|
if (mDataTypes & Land::DATA_VHGT) {
|
||||||
VHGT offsets;
|
VHGT offsets;
|
||||||
offsets.mHeightOffset = mHeights[0] / HEIGHT_SCALE;
|
offsets.mHeightOffset = mHeights[0] / HEIGHT_SCALE;
|
||||||
offsets.mUnk1 = mUnk1;
|
offsets.mUnk1 = mUnk1;
|
||||||
offsets.mUnk2 = mUnk2;
|
offsets.mUnk2 = mUnk2;
|
||||||
|
|
||||||
float prevY = mHeights[0];
|
float prevY = mHeights[0];
|
||||||
int number = 0; // avoid multiplication
|
int number = 0; // avoid multiplication
|
||||||
for (int i = 0; i < LAND_SIZE; ++i) {
|
for (int i = 0; i < LAND_SIZE; ++i) {
|
||||||
float diff = (mHeights[number] - prevY) / HEIGHT_SCALE;
|
float diff = (mHeights[number] - prevY) / HEIGHT_SCALE;
|
||||||
offsets.mHeightData[number] =
|
|
||||||
(diff >= 0) ? (int8_t) (diff + 0.5) : (int8_t) (diff - 0.5);
|
|
||||||
|
|
||||||
float prevX = prevY = mHeights[number];
|
|
||||||
++number;
|
|
||||||
|
|
||||||
for (int j = 1; j < LAND_SIZE; ++j) {
|
|
||||||
diff = (mHeights[number] - prevX) / HEIGHT_SCALE;
|
|
||||||
offsets.mHeightData[number] =
|
offsets.mHeightData[number] =
|
||||||
(diff >= 0) ? (int8_t) (diff + 0.5) : (int8_t) (diff - 0.5);
|
(diff >= 0) ? (int8_t) (diff + 0.5) : (int8_t) (diff - 0.5);
|
||||||
|
|
||||||
prevX = mHeights[number];
|
float prevX = prevY = mHeights[number];
|
||||||
++number;
|
++number;
|
||||||
}
|
|
||||||
}
|
|
||||||
esm.writeHNT("VHGT", offsets, sizeof(VHGT));
|
|
||||||
}
|
|
||||||
if (mDataTypes & Land::DATA_WNAM) {
|
|
||||||
esm.writeHNT("WNAM", mWnam, 81);
|
|
||||||
}
|
|
||||||
if (mDataTypes & Land::DATA_VCLR) {
|
|
||||||
esm.writeHNT("VCLR", mColours, 3*LAND_NUM_VERTS);
|
|
||||||
}
|
|
||||||
if (mDataTypes & Land::DATA_VTEX) {
|
|
||||||
static uint16_t vtex[LAND_NUM_TEXTURES];
|
|
||||||
transposeTextureData(mTextures, vtex);
|
|
||||||
esm.writeHNT("VTEX", vtex, sizeof(vtex));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Land::LandData::transposeTextureData(uint16_t *in, uint16_t *out)
|
for (int j = 1; j < LAND_SIZE; ++j) {
|
||||||
{
|
diff = (mHeights[number] - prevX) / HEIGHT_SCALE;
|
||||||
int readPos = 0; //bit ugly, but it works
|
offsets.mHeightData[number] =
|
||||||
for ( int y1 = 0; y1 < 4; y1++ )
|
(diff >= 0) ? (int8_t) (diff + 0.5) : (int8_t) (diff - 0.5);
|
||||||
for ( int x1 = 0; x1 < 4; x1++ )
|
|
||||||
for ( int y2 = 0; y2 < 4; y2++)
|
|
||||||
for ( int x2 = 0; x2 < 4; x2++ )
|
|
||||||
out[(y1*4+y2)*16+(x1*4+x2)] = in[readPos++];
|
|
||||||
}
|
|
||||||
|
|
||||||
Land::Land()
|
prevX = mHeights[number];
|
||||||
: mFlags(0)
|
++number;
|
||||||
, mX(0)
|
|
||||||
, mY(0)
|
|
||||||
, mPlugin(0)
|
|
||||||
, mEsm(NULL)
|
|
||||||
, mDataTypes(0)
|
|
||||||
, mDataLoaded(false)
|
|
||||||
, mLandData(NULL)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
Land::~Land()
|
|
||||||
{
|
|
||||||
delete mLandData;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Land::load(ESMReader &esm)
|
|
||||||
{
|
|
||||||
mEsm = &esm;
|
|
||||||
mPlugin = mEsm->getIndex();
|
|
||||||
|
|
||||||
// Get the grid location
|
|
||||||
esm.getSubNameIs("INTV");
|
|
||||||
esm.getSubHeaderIs(8);
|
|
||||||
esm.getT<int>(mX);
|
|
||||||
esm.getT<int>(mY);
|
|
||||||
|
|
||||||
esm.getHNT(mFlags, "DATA");
|
|
||||||
|
|
||||||
// Store the file position
|
|
||||||
mContext = esm.getContext();
|
|
||||||
|
|
||||||
// Skip these here. Load the actual data when the cell is loaded.
|
|
||||||
if (esm.isNextSub("VNML"))
|
|
||||||
{
|
|
||||||
esm.skipHSubSize(12675);
|
|
||||||
mDataTypes |= DATA_VNML;
|
|
||||||
}
|
|
||||||
if (esm.isNextSub("VHGT"))
|
|
||||||
{
|
|
||||||
esm.skipHSubSize(4232);
|
|
||||||
mDataTypes |= DATA_VHGT;
|
|
||||||
}
|
|
||||||
if (esm.isNextSub("WNAM"))
|
|
||||||
{
|
|
||||||
esm.skipHSubSize(81);
|
|
||||||
mDataTypes |= DATA_WNAM;
|
|
||||||
}
|
|
||||||
if (esm.isNextSub("VCLR"))
|
|
||||||
{
|
|
||||||
esm.skipHSubSize(12675);
|
|
||||||
mDataTypes |= DATA_VCLR;
|
|
||||||
}
|
|
||||||
if (esm.isNextSub("VTEX"))
|
|
||||||
{
|
|
||||||
esm.skipHSubSize(512);
|
|
||||||
mDataTypes |= DATA_VTEX;
|
|
||||||
}
|
|
||||||
|
|
||||||
mDataLoaded = 0;
|
|
||||||
mLandData = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Land::save(ESMWriter &esm) const
|
|
||||||
{
|
|
||||||
esm.startSubRecord("INTV");
|
|
||||||
esm.writeT(mX);
|
|
||||||
esm.writeT(mY);
|
|
||||||
esm.endRecord("INTV");
|
|
||||||
|
|
||||||
esm.writeHNT("DATA", mFlags);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Land::loadData(int flags)
|
|
||||||
{
|
|
||||||
// Try to load only available data
|
|
||||||
flags = flags & mDataTypes;
|
|
||||||
// Return if all required data is loaded
|
|
||||||
if ((mDataLoaded & flags) == flags) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Create storage if nothing is loaded
|
|
||||||
if (mLandData == NULL) {
|
|
||||||
mLandData = new LandData;
|
|
||||||
mLandData->mDataTypes = mDataTypes;
|
|
||||||
}
|
|
||||||
mEsm->restoreContext(mContext);
|
|
||||||
|
|
||||||
if (mEsm->isNextSub("VNML")) {
|
|
||||||
condLoad(flags, DATA_VNML, mLandData->mNormals, sizeof(mLandData->mNormals));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mEsm->isNextSub("VHGT")) {
|
|
||||||
static VHGT vhgt;
|
|
||||||
if (condLoad(flags, DATA_VHGT, &vhgt, sizeof(vhgt))) {
|
|
||||||
float rowOffset = vhgt.mHeightOffset;
|
|
||||||
for (int y = 0; y < LAND_SIZE; y++) {
|
|
||||||
rowOffset += vhgt.mHeightData[y * LAND_SIZE];
|
|
||||||
|
|
||||||
mLandData->mHeights[y * LAND_SIZE] = rowOffset * HEIGHT_SCALE;
|
|
||||||
|
|
||||||
float colOffset = rowOffset;
|
|
||||||
for (int x = 1; x < LAND_SIZE; x++) {
|
|
||||||
colOffset += vhgt.mHeightData[y * LAND_SIZE + x];
|
|
||||||
mLandData->mHeights[x + y * LAND_SIZE] = colOffset * HEIGHT_SCALE;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mLandData->mUnk1 = vhgt.mUnk1;
|
esm.writeHNT("VHGT", offsets, sizeof(VHGT));
|
||||||
mLandData->mUnk2 = vhgt.mUnk2;
|
}
|
||||||
|
if (mDataTypes & Land::DATA_WNAM) {
|
||||||
|
esm.writeHNT("WNAM", mWnam, 81);
|
||||||
|
}
|
||||||
|
if (mDataTypes & Land::DATA_VCLR) {
|
||||||
|
esm.writeHNT("VCLR", mColours, 3*LAND_NUM_VERTS);
|
||||||
|
}
|
||||||
|
if (mDataTypes & Land::DATA_VTEX) {
|
||||||
|
static uint16_t vtex[LAND_NUM_TEXTURES];
|
||||||
|
transposeTextureData(mTextures, vtex);
|
||||||
|
esm.writeHNT("VTEX", vtex, sizeof(vtex));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mEsm->isNextSub("WNAM")) {
|
void Land::LandData::transposeTextureData(uint16_t *in, uint16_t *out)
|
||||||
condLoad(flags, DATA_WNAM, mLandData->mWnam, 81);
|
{
|
||||||
|
int readPos = 0; //bit ugly, but it works
|
||||||
|
for ( int y1 = 0; y1 < 4; y1++ )
|
||||||
|
for ( int x1 = 0; x1 < 4; x1++ )
|
||||||
|
for ( int y2 = 0; y2 < 4; y2++)
|
||||||
|
for ( int x2 = 0; x2 < 4; x2++ )
|
||||||
|
out[(y1*4+y2)*16+(x1*4+x2)] = in[readPos++];
|
||||||
}
|
}
|
||||||
if (mEsm->isNextSub("VCLR"))
|
|
||||||
condLoad(flags, DATA_VCLR, mLandData->mColours, 3 * LAND_NUM_VERTS);
|
|
||||||
if (mEsm->isNextSub("VTEX")) {
|
|
||||||
static uint16_t vtex[LAND_NUM_TEXTURES];
|
|
||||||
if (condLoad(flags, DATA_VTEX, vtex, sizeof(vtex))) {
|
|
||||||
LandData::transposeTextureData(vtex, mLandData->mTextures);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Land::unloadData()
|
Land::Land()
|
||||||
{
|
: mFlags(0)
|
||||||
if (mDataLoaded)
|
, mX(0)
|
||||||
|
, mY(0)
|
||||||
|
, mPlugin(0)
|
||||||
|
, mEsm(NULL)
|
||||||
|
, mDataTypes(0)
|
||||||
|
, mDataLoaded(false)
|
||||||
|
, mLandData(NULL)
|
||||||
|
, mIsDeleted(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Land::~Land()
|
||||||
{
|
{
|
||||||
delete mLandData;
|
delete mLandData;
|
||||||
mLandData = NULL;
|
}
|
||||||
|
|
||||||
|
void Land::load(ESMReader &esm)
|
||||||
|
{
|
||||||
|
mEsm = &esm;
|
||||||
|
mPlugin = mEsm->getIndex();
|
||||||
|
mIsDeleted = false;
|
||||||
|
|
||||||
|
// Get the grid location
|
||||||
|
esm.getSubNameIs("INTV");
|
||||||
|
esm.getSubHeaderIs(8);
|
||||||
|
esm.getT<int>(mX);
|
||||||
|
esm.getT<int>(mY);
|
||||||
|
|
||||||
|
esm.getHNT(mFlags, "DATA");
|
||||||
|
|
||||||
|
if (esm.isNextSub("DELE"))
|
||||||
|
{
|
||||||
|
esm.skipHSub();
|
||||||
|
mIsDeleted = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store the file position
|
||||||
|
mContext = esm.getContext();
|
||||||
|
|
||||||
|
// Skip these here. Load the actual data when the cell is loaded.
|
||||||
|
if (esm.isNextSub("VNML"))
|
||||||
|
{
|
||||||
|
esm.skipHSubSize(12675);
|
||||||
|
mDataTypes |= DATA_VNML;
|
||||||
|
}
|
||||||
|
if (esm.isNextSub("VHGT"))
|
||||||
|
{
|
||||||
|
esm.skipHSubSize(4232);
|
||||||
|
mDataTypes |= DATA_VHGT;
|
||||||
|
}
|
||||||
|
if (esm.isNextSub("WNAM"))
|
||||||
|
{
|
||||||
|
esm.skipHSubSize(81);
|
||||||
|
mDataTypes |= DATA_WNAM;
|
||||||
|
}
|
||||||
|
if (esm.isNextSub("VCLR"))
|
||||||
|
{
|
||||||
|
esm.skipHSubSize(12675);
|
||||||
|
mDataTypes |= DATA_VCLR;
|
||||||
|
}
|
||||||
|
if (esm.isNextSub("VTEX"))
|
||||||
|
{
|
||||||
|
esm.skipHSubSize(512);
|
||||||
|
mDataTypes |= DATA_VTEX;
|
||||||
|
}
|
||||||
|
|
||||||
mDataLoaded = 0;
|
mDataLoaded = 0;
|
||||||
|
mLandData = NULL;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
bool Land::condLoad(int flags, int dataFlag, void *ptr, unsigned int size)
|
void Land::save(ESMWriter &esm) const
|
||||||
{
|
{
|
||||||
if ((mDataLoaded & dataFlag) == 0 && (flags & dataFlag) != 0) {
|
esm.startSubRecord("INTV");
|
||||||
mEsm->getHExact(ptr, size);
|
esm.writeT(mX);
|
||||||
mDataLoaded |= dataFlag;
|
esm.writeT(mY);
|
||||||
return true;
|
esm.endRecord("INTV");
|
||||||
|
|
||||||
|
esm.writeHNT("DATA", mFlags);
|
||||||
|
|
||||||
|
if (mIsDeleted)
|
||||||
|
{
|
||||||
|
esm.writeHNCString("DELE", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mLandData != NULL)
|
||||||
|
{
|
||||||
|
mLandData->save(esm);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
mEsm->skipHSubSize(size);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Land::isDataLoaded(int flags) const
|
void Land::blank()
|
||||||
{
|
{
|
||||||
return (mDataLoaded & flags) == (flags & mDataTypes);
|
mIsDeleted = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Land::loadData(int flags)
|
||||||
|
{
|
||||||
|
// Try to load only available data
|
||||||
|
flags = flags & mDataTypes;
|
||||||
|
// Return if all required data is loaded
|
||||||
|
if ((mDataLoaded & flags) == flags) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Create storage if nothing is loaded
|
||||||
|
if (mLandData == NULL) {
|
||||||
|
mLandData = new LandData;
|
||||||
|
mLandData->mDataTypes = mDataTypes;
|
||||||
|
}
|
||||||
|
mEsm->restoreContext(mContext);
|
||||||
|
|
||||||
|
if (mEsm->isNextSub("VNML")) {
|
||||||
|
condLoad(flags, DATA_VNML, mLandData->mNormals, sizeof(mLandData->mNormals));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mEsm->isNextSub("VHGT")) {
|
||||||
|
static VHGT vhgt;
|
||||||
|
if (condLoad(flags, DATA_VHGT, &vhgt, sizeof(vhgt))) {
|
||||||
|
float rowOffset = vhgt.mHeightOffset;
|
||||||
|
for (int y = 0; y < LAND_SIZE; y++) {
|
||||||
|
rowOffset += vhgt.mHeightData[y * LAND_SIZE];
|
||||||
|
|
||||||
|
mLandData->mHeights[y * LAND_SIZE] = rowOffset * HEIGHT_SCALE;
|
||||||
|
|
||||||
|
float colOffset = rowOffset;
|
||||||
|
for (int x = 1; x < LAND_SIZE; x++) {
|
||||||
|
colOffset += vhgt.mHeightData[y * LAND_SIZE + x];
|
||||||
|
mLandData->mHeights[x + y * LAND_SIZE] = colOffset * HEIGHT_SCALE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mLandData->mUnk1 = vhgt.mUnk1;
|
||||||
|
mLandData->mUnk2 = vhgt.mUnk2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mEsm->isNextSub("WNAM")) {
|
||||||
|
condLoad(flags, DATA_WNAM, mLandData->mWnam, 81);
|
||||||
|
}
|
||||||
|
if (mEsm->isNextSub("VCLR"))
|
||||||
|
condLoad(flags, DATA_VCLR, mLandData->mColours, 3 * LAND_NUM_VERTS);
|
||||||
|
if (mEsm->isNextSub("VTEX")) {
|
||||||
|
static uint16_t vtex[LAND_NUM_TEXTURES];
|
||||||
|
if (condLoad(flags, DATA_VTEX, vtex, sizeof(vtex))) {
|
||||||
|
LandData::transposeTextureData(vtex, mLandData->mTextures);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Land::unloadData()
|
||||||
|
{
|
||||||
|
if (mDataLoaded)
|
||||||
|
{
|
||||||
|
delete mLandData;
|
||||||
|
mLandData = NULL;
|
||||||
|
mDataLoaded = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Land::condLoad(int flags, int dataFlag, void *ptr, unsigned int size)
|
||||||
|
{
|
||||||
|
if ((mDataLoaded & dataFlag) == 0 && (flags & dataFlag) != 0) {
|
||||||
|
mEsm->getHExact(ptr, size);
|
||||||
|
mDataLoaded |= dataFlag;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
mEsm->skipHSubSize(size);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Land::isDataLoaded(int flags) const
|
||||||
|
{
|
||||||
|
return (mDataLoaded & flags) == (flags & mDataTypes);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -97,10 +97,12 @@ struct Land
|
||||||
|
|
||||||
LandData *mLandData;
|
LandData *mLandData;
|
||||||
|
|
||||||
|
bool mIsDeleted;
|
||||||
|
|
||||||
void load(ESMReader &esm);
|
void load(ESMReader &esm);
|
||||||
void save(ESMWriter &esm) const;
|
void save(ESMWriter &esm) const;
|
||||||
|
|
||||||
void blank() {}
|
void blank();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Actually loads data
|
* Actually loads data
|
||||||
|
|
|
@ -32,98 +32,137 @@ namespace ESM
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void Pathgrid::load(ESMReader &esm)
|
Pathgrid::Pathgrid()
|
||||||
{
|
: mIsDeleted(false)
|
||||||
esm.getHNT(mData, "DATA", 12);
|
{}
|
||||||
mCell = esm.getHNString("NAME");
|
|
||||||
|
|
||||||
mPoints.clear();
|
void Pathgrid::load(ESMReader &esm)
|
||||||
mEdges.clear();
|
|
||||||
|
|
||||||
// keep track of total connections so we can reserve edge vector size
|
|
||||||
int edgeCount = 0;
|
|
||||||
|
|
||||||
if (esm.isNextSub("PGRP"))
|
|
||||||
{
|
{
|
||||||
esm.getSubHeader();
|
mPoints.clear();
|
||||||
int size = esm.getSubSize();
|
mEdges.clear();
|
||||||
// Check that the sizes match up. Size = 16 * s2 (path points)
|
|
||||||
if (size != static_cast<int> (sizeof(Point) * mData.mS2))
|
|
||||||
esm.fail("Path point subrecord size mismatch");
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int pointCount = mData.mS2;
|
|
||||||
mPoints.reserve(pointCount);
|
|
||||||
for (int i = 0; i < pointCount; ++i)
|
|
||||||
{
|
|
||||||
Point p;
|
|
||||||
esm.getExact(&p, sizeof(Point));
|
|
||||||
mPoints.push_back(p);
|
|
||||||
edgeCount += p.mConnectionNum;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (esm.isNextSub("PGRC"))
|
// keep track of total connections so we can reserve edge vector size
|
||||||
{
|
int edgeCount = 0;
|
||||||
esm.getSubHeader();
|
|
||||||
int size = esm.getSubSize();
|
|
||||||
if (size % sizeof(int) != 0)
|
|
||||||
esm.fail("PGRC size not a multiple of 4");
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int rawConnNum = size / sizeof(int);
|
|
||||||
std::vector<int> rawConnections;
|
|
||||||
rawConnections.reserve(rawConnNum);
|
|
||||||
for (int i = 0; i < rawConnNum; ++i)
|
|
||||||
{
|
|
||||||
int currentValue;
|
|
||||||
esm.getT(currentValue);
|
|
||||||
rawConnections.push_back(currentValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<int>::const_iterator rawIt = rawConnections.begin();
|
bool hasData = false;
|
||||||
int pointIndex = 0;
|
bool hasName = false;
|
||||||
mEdges.reserve(edgeCount);
|
while (esm.hasMoreSubs())
|
||||||
for(PointList::const_iterator it = mPoints.begin(); it != mPoints.end(); ++it, ++pointIndex)
|
{
|
||||||
|
esm.getSubName();
|
||||||
|
uint32_t name = esm.retSubName().val;
|
||||||
|
switch (name)
|
||||||
{
|
{
|
||||||
unsigned char connectionNum = (*it).mConnectionNum;
|
case ESM::FourCC<'D','A','T','A'>::value:
|
||||||
for (int i = 0; i < connectionNum; ++i) {
|
esm.getHT(mData, 12);
|
||||||
Edge edge;
|
hasData = true;
|
||||||
edge.mV0 = pointIndex;
|
break;
|
||||||
edge.mV1 = *rawIt;
|
case ESM::FourCC<'N','A','M','E'>::value:
|
||||||
++rawIt;
|
mCell = esm.getHString();
|
||||||
mEdges.push_back(edge);
|
hasName = true;
|
||||||
|
break;
|
||||||
|
case ESM::FourCC<'P','G','R','P'>::value:
|
||||||
|
{
|
||||||
|
esm.getSubHeader();
|
||||||
|
int size = esm.getSubSize();
|
||||||
|
// Check that the sizes match up. Size = 16 * s2 (path points)
|
||||||
|
if (size != static_cast<int> (sizeof(Point) * mData.mS2))
|
||||||
|
esm.fail("Path point subrecord size mismatch");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int pointCount = mData.mS2;
|
||||||
|
mPoints.reserve(pointCount);
|
||||||
|
for (int i = 0; i < pointCount; ++i)
|
||||||
|
{
|
||||||
|
Point p;
|
||||||
|
esm.getExact(&p, sizeof(Point));
|
||||||
|
mPoints.push_back(p);
|
||||||
|
edgeCount += p.mConnectionNum;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
case ESM::FourCC<'P','G','R','C'>::value:
|
||||||
|
{
|
||||||
|
esm.getSubHeader();
|
||||||
|
int size = esm.getSubSize();
|
||||||
|
if (size % sizeof(int) != 0)
|
||||||
|
esm.fail("PGRC size not a multiple of 4");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int rawConnNum = size / sizeof(int);
|
||||||
|
std::vector<int> rawConnections;
|
||||||
|
rawConnections.reserve(rawConnNum);
|
||||||
|
for (int i = 0; i < rawConnNum; ++i)
|
||||||
|
{
|
||||||
|
int currentValue;
|
||||||
|
esm.getT(currentValue);
|
||||||
|
rawConnections.push_back(currentValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<int>::const_iterator rawIt = rawConnections.begin();
|
||||||
|
int pointIndex = 0;
|
||||||
|
mEdges.reserve(edgeCount);
|
||||||
|
for(PointList::const_iterator it = mPoints.begin(); it != mPoints.end(); ++it, ++pointIndex)
|
||||||
|
{
|
||||||
|
unsigned char connectionNum = (*it).mConnectionNum;
|
||||||
|
for (int i = 0; i < connectionNum; ++i) {
|
||||||
|
Edge edge;
|
||||||
|
edge.mV0 = pointIndex;
|
||||||
|
edge.mV1 = *rawIt;
|
||||||
|
++rawIt;
|
||||||
|
mEdges.push_back(edge);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ESM::FourCC<'D','E','L','E'>::value:
|
||||||
|
esm.skipHSub();
|
||||||
|
mIsDeleted = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
esm.fail("Unknown subrecord");
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
void Pathgrid::save(ESMWriter &esm) const
|
|
||||||
{
|
|
||||||
esm.writeHNT("DATA", mData, 12);
|
|
||||||
esm.writeHNCString("NAME", mCell);
|
|
||||||
|
|
||||||
if (!mPoints.empty())
|
if (!hasData)
|
||||||
{
|
esm.fail("Missing DATA subrecord");
|
||||||
esm.startSubRecord("PGRP");
|
if (!hasName)
|
||||||
for (PointList::const_iterator it = mPoints.begin(); it != mPoints.end(); ++it)
|
esm.fail("Missing NAME subrecord");
|
||||||
{
|
|
||||||
esm.writeT(*it);
|
|
||||||
}
|
|
||||||
esm.endRecord("PGRP");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mEdges.empty())
|
void Pathgrid::save(ESMWriter &esm) const
|
||||||
{
|
{
|
||||||
esm.startSubRecord("PGRC");
|
esm.writeHNT("DATA", mData, 12);
|
||||||
for (std::vector<Edge>::const_iterator it = mEdges.begin(); it != mEdges.end(); ++it)
|
esm.writeHNCString("NAME", mCell);
|
||||||
|
|
||||||
|
if (mIsDeleted)
|
||||||
{
|
{
|
||||||
esm.writeT(it->mV1);
|
esm.writeHNCString("DELE", "");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mPoints.empty())
|
||||||
|
{
|
||||||
|
esm.startSubRecord("PGRP");
|
||||||
|
for (PointList::const_iterator it = mPoints.begin(); it != mPoints.end(); ++it)
|
||||||
|
{
|
||||||
|
esm.writeT(*it);
|
||||||
|
}
|
||||||
|
esm.endRecord("PGRP");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mEdges.empty())
|
||||||
|
{
|
||||||
|
esm.startSubRecord("PGRC");
|
||||||
|
for (std::vector<Edge>::const_iterator it = mEdges.begin(); it != mEdges.end(); ++it)
|
||||||
|
{
|
||||||
|
esm.writeT(it->mV1);
|
||||||
|
}
|
||||||
|
esm.endRecord("PGRC");
|
||||||
}
|
}
|
||||||
esm.endRecord("PGRC");
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void Pathgrid::blank()
|
void Pathgrid::blank()
|
||||||
{
|
{
|
||||||
|
@ -134,5 +173,6 @@ void Pathgrid::save(ESMWriter &esm) const
|
||||||
mData.mS2 = 0;
|
mData.mS2 = 0;
|
||||||
mPoints.clear();
|
mPoints.clear();
|
||||||
mEdges.clear();
|
mEdges.clear();
|
||||||
|
mIsDeleted = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,6 +53,10 @@ struct Pathgrid
|
||||||
typedef std::vector<Edge> EdgeList;
|
typedef std::vector<Edge> EdgeList;
|
||||||
EdgeList mEdges;
|
EdgeList mEdges;
|
||||||
|
|
||||||
|
bool mIsDeleted;
|
||||||
|
|
||||||
|
Pathgrid();
|
||||||
|
|
||||||
void load(ESMReader &esm);
|
void load(ESMReader &esm);
|
||||||
void save(ESMWriter &esm) const;
|
void save(ESMWriter &esm) const;
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,10 @@ namespace ESM
|
||||||
{
|
{
|
||||||
unsigned int Race::sRecordId = REC_RACE;
|
unsigned int Race::sRecordId = REC_RACE;
|
||||||
|
|
||||||
|
Race::Race()
|
||||||
|
: mIsDeleted(false)
|
||||||
|
{}
|
||||||
|
|
||||||
int Race::MaleFemale::getValue (bool male) const
|
int Race::MaleFemale::getValue (bool male) const
|
||||||
{
|
{
|
||||||
return male ? mMale : mFemale;
|
return male ? mMale : mFemale;
|
||||||
|
@ -18,47 +22,65 @@ namespace ESM
|
||||||
return static_cast<int>(male ? mMale : mFemale);
|
return static_cast<int>(male ? mMale : mFemale);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Race::load(ESMReader &esm)
|
void Race::load(ESMReader &esm)
|
||||||
{
|
|
||||||
mPowers.mList.clear();
|
|
||||||
|
|
||||||
mId = esm.getHNString("NAME");
|
|
||||||
|
|
||||||
bool hasData = false;
|
|
||||||
while (esm.hasMoreSubs())
|
|
||||||
{
|
{
|
||||||
esm.getSubName();
|
mPowers.mList.clear();
|
||||||
uint32_t name = esm.retSubName().val;
|
mIsDeleted = false;
|
||||||
switch (name)
|
|
||||||
|
bool hasName = false;
|
||||||
|
bool hasData = false;
|
||||||
|
while (esm.hasMoreSubs())
|
||||||
{
|
{
|
||||||
case ESM::FourCC<'F','N','A','M'>::value:
|
esm.getSubName();
|
||||||
mName = esm.getHString();
|
uint32_t name = esm.retSubName().val;
|
||||||
break;
|
switch (name)
|
||||||
case ESM::FourCC<'R','A','D','T'>::value:
|
{
|
||||||
esm.getHT(mData, 140);
|
case ESM::FourCC<'N','A','M','E'>::value:
|
||||||
hasData = true;
|
mId = esm.getHString();
|
||||||
break;
|
hasName = true;
|
||||||
case ESM::FourCC<'D','E','S','C'>::value:
|
break;
|
||||||
mDescription = esm.getHString();
|
case ESM::FourCC<'D','E','L','E'>::value:
|
||||||
break;
|
esm.skipHSub();
|
||||||
case ESM::FourCC<'N','P','C','S'>::value:
|
mIsDeleted = true;
|
||||||
mPowers.add(esm);
|
break;
|
||||||
break;
|
case ESM::FourCC<'F','N','A','M'>::value:
|
||||||
default:
|
mName = esm.getHString();
|
||||||
esm.fail("Unknown subrecord");
|
break;
|
||||||
|
case ESM::FourCC<'R','A','D','T'>::value:
|
||||||
|
esm.getHT(mData, 140);
|
||||||
|
hasData = true;
|
||||||
|
break;
|
||||||
|
case ESM::FourCC<'D','E','S','C'>::value:
|
||||||
|
mDescription = esm.getHString();
|
||||||
|
break;
|
||||||
|
case ESM::FourCC<'N','P','C','S'>::value:
|
||||||
|
mPowers.add(esm);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
esm.fail("Unknown subrecord");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!hasName)
|
||||||
|
esm.fail("Missing NAME subrecord");
|
||||||
|
if (!hasData && !mIsDeleted)
|
||||||
|
esm.fail("Missing RADT subrecord");
|
||||||
|
}
|
||||||
|
void Race::save(ESMWriter &esm) const
|
||||||
|
{
|
||||||
|
esm.writeHNCString("NAME", mId);
|
||||||
|
|
||||||
|
if (mIsDeleted)
|
||||||
|
{
|
||||||
|
esm.writeHNCString("DELE", "");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
esm.writeHNOCString("FNAM", mName);
|
||||||
|
esm.writeHNT("RADT", mData, 140);
|
||||||
|
mPowers.save(esm);
|
||||||
|
esm.writeHNOString("DESC", mDescription);
|
||||||
}
|
}
|
||||||
if (!hasData)
|
|
||||||
esm.fail("Missing RADT subrecord");
|
|
||||||
}
|
|
||||||
void Race::save(ESMWriter &esm) const
|
|
||||||
{
|
|
||||||
esm.writeHNCString("NAME", mId);
|
|
||||||
esm.writeHNOCString("FNAM", mName);
|
|
||||||
esm.writeHNT("RADT", mData, 140);
|
|
||||||
mPowers.save(esm);
|
|
||||||
esm.writeHNOString("DESC", mDescription);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Race::blank()
|
void Race::blank()
|
||||||
{
|
{
|
||||||
|
|
|
@ -68,6 +68,10 @@ struct Race
|
||||||
std::string mId, mName, mDescription;
|
std::string mId, mName, mDescription;
|
||||||
SpellList mPowers;
|
SpellList mPowers;
|
||||||
|
|
||||||
|
bool mIsDeleted;
|
||||||
|
|
||||||
|
Race();
|
||||||
|
|
||||||
void load(ESMReader &esm);
|
void load(ESMReader &esm);
|
||||||
void save(ESMWriter &esm) const;
|
void save(ESMWriter &esm) const;
|
||||||
|
|
||||||
|
|
|
@ -8,8 +8,14 @@ namespace ESM
|
||||||
{
|
{
|
||||||
unsigned int StartScript::sRecordId = REC_SSCR;
|
unsigned int StartScript::sRecordId = REC_SSCR;
|
||||||
|
|
||||||
|
StartScript::StartScript()
|
||||||
|
: mIsDeleted(false)
|
||||||
|
{}
|
||||||
|
|
||||||
void StartScript::load(ESMReader &esm)
|
void StartScript::load(ESMReader &esm)
|
||||||
{
|
{
|
||||||
|
mIsDeleted = false;
|
||||||
|
|
||||||
bool hasData = false;
|
bool hasData = false;
|
||||||
bool hasName = false;
|
bool hasName = false;
|
||||||
while (esm.hasMoreSubs())
|
while (esm.hasMoreSubs())
|
||||||
|
@ -26,10 +32,16 @@ namespace ESM
|
||||||
mId = esm.getHString();
|
mId = esm.getHString();
|
||||||
hasName = true;
|
hasName = true;
|
||||||
break;
|
break;
|
||||||
|
case ESM::FourCC<'D','E','L','E'>::value:
|
||||||
|
esm.skipHSub();
|
||||||
|
mIsDeleted = true;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
esm.fail("Unknown subrecord");
|
esm.fail("Unknown subrecord");
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hasData)
|
if (!hasData)
|
||||||
esm.fail("Missing DATA");
|
esm.fail("Missing DATA");
|
||||||
if (!hasName)
|
if (!hasName)
|
||||||
|
@ -39,10 +51,16 @@ namespace ESM
|
||||||
{
|
{
|
||||||
esm.writeHNString("DATA", mData);
|
esm.writeHNString("DATA", mData);
|
||||||
esm.writeHNString("NAME", mId);
|
esm.writeHNString("NAME", mId);
|
||||||
|
|
||||||
|
if (mIsDeleted)
|
||||||
|
{
|
||||||
|
esm.writeHNCString("DELE", "");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void StartScript::blank()
|
void StartScript::blank()
|
||||||
{
|
{
|
||||||
mData.clear();
|
mData.clear();
|
||||||
|
mIsDeleted = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,10 @@ struct StartScript
|
||||||
std::string mData;
|
std::string mData;
|
||||||
std::string mId;
|
std::string mId;
|
||||||
|
|
||||||
|
bool mIsDeleted;
|
||||||
|
|
||||||
|
StartScript();
|
||||||
|
|
||||||
// Load a record and add it to the list
|
// Load a record and add it to the list
|
||||||
void load(ESMReader &esm);
|
void load(ESMReader &esm);
|
||||||
void save(ESMWriter &esm) const;
|
void save(ESMWriter &esm) const;
|
||||||
|
|
Loading…
Reference in a new issue