mirror of
https://github.com/OpenMW/openmw.git
synced 2025-01-16 15:29:55 +00:00
Merge branch 'i-have-no-land-and-i-must-scream' into 'master'
Fix(CS): Add landscape flag if it doesn't exist at all and improve landscape QOL Closes #7707 See merge request OpenMW/openmw!3617
This commit is contained in:
commit
c1d74763ed
11 changed files with 115 additions and 72 deletions
|
@ -141,6 +141,7 @@
|
|||
Bug #7676: Incorrect magic effect order in alchemy
|
||||
Bug #7679: Scene luminance value flashes when toggling shaders
|
||||
Bug #7685: Corky sometimes doesn't follow Llovyn Andus
|
||||
Bug #7707: (OpenCS): New landscape records do not contain appropriate flags
|
||||
Bug #7712: Casting doesn't support spells and enchantments with no effects
|
||||
Bug #7721: CS: Special Chars Not Allowed in IDs
|
||||
Bug #7723: Assaulting vampires and werewolves shouldn't be a crime
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <components/esm3/loadcont.hpp>
|
||||
#include <components/esm3/loadcrea.hpp>
|
||||
#include <components/esm3/loadench.hpp>
|
||||
#include <components/esm3/loadland.hpp>
|
||||
#include <components/esm3/loadlevlist.hpp>
|
||||
#include <components/esm3/loadligh.hpp>
|
||||
#include <components/esm3/loadmgef.hpp>
|
||||
|
@ -766,18 +767,16 @@ std::string enchantmentFlags(int flags)
|
|||
std::string landFlags(std::uint32_t flags)
|
||||
{
|
||||
std::string properties;
|
||||
// The ESM component says that this first four bits are used, but
|
||||
// only the first three bits are used as far as I can tell.
|
||||
// There's also no enumeration of the bit in the ESM component.
|
||||
if (flags == 0)
|
||||
properties += "[None] ";
|
||||
if (flags & 0x00000001)
|
||||
properties += "Unknown1 ";
|
||||
if (flags & 0x00000004)
|
||||
properties += "Unknown3 ";
|
||||
if (flags & 0x00000002)
|
||||
properties += "Unknown2 ";
|
||||
if (flags & 0xFFFFFFF8)
|
||||
if (flags & ESM::Land::Flag_HeightsNormals)
|
||||
properties += "HeightsNormals ";
|
||||
if (flags & ESM::Land::Flag_Colors)
|
||||
properties += "Colors ";
|
||||
if (flags & ESM::Land::Flag_Textures)
|
||||
properties += "Textures ";
|
||||
int unused = 0xFFFFFFFF ^ (ESM::Land::Flag_HeightsNormals | ESM::Land::Flag_Colors | ESM::Land::Flag_Textures);
|
||||
if (flags & unused)
|
||||
properties += "Invalid ";
|
||||
properties += Misc::StringUtils::format("(0x%08X)", flags);
|
||||
return properties;
|
||||
|
|
|
@ -202,6 +202,8 @@ namespace CSMWorld
|
|||
copy.getLandData()->mHeights[i] = values[i];
|
||||
}
|
||||
|
||||
copy.mFlags |= Land::Flag_HeightsNormals;
|
||||
|
||||
record.setModified(copy);
|
||||
}
|
||||
|
||||
|
@ -249,6 +251,8 @@ namespace CSMWorld
|
|||
copy.getLandData()->mColours[i] = values[i];
|
||||
}
|
||||
|
||||
copy.mFlags |= Land::Flag_Colors;
|
||||
|
||||
record.setModified(copy);
|
||||
}
|
||||
|
||||
|
@ -296,6 +300,8 @@ namespace CSMWorld
|
|||
copy.getLandData()->mTextures[i] = values[i];
|
||||
}
|
||||
|
||||
copy.mFlags |= Land::Flag_Textures;
|
||||
|
||||
record.setModified(copy);
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include <components/misc/strings/lower.hpp>
|
||||
#include <components/terrain/terraingrid.hpp>
|
||||
|
||||
#include "../../model/doc/document.hpp"
|
||||
#include "../../model/world/idtable.hpp"
|
||||
|
||||
#include "cellarrow.hpp"
|
||||
|
@ -31,6 +32,7 @@
|
|||
#include <apps/opencs/model/world/cell.hpp>
|
||||
#include <apps/opencs/model/world/cellcoordinates.hpp>
|
||||
#include <apps/opencs/model/world/columns.hpp>
|
||||
#include <apps/opencs/model/world/commands.hpp>
|
||||
#include <apps/opencs/model/world/data.hpp>
|
||||
#include <apps/opencs/model/world/idcollection.hpp>
|
||||
#include <apps/opencs/model/world/land.hpp>
|
||||
|
@ -130,15 +132,13 @@ void CSVRender::Cell::updateLand()
|
|||
return;
|
||||
}
|
||||
|
||||
// Setup land if available
|
||||
const CSMWorld::IdCollection<CSMWorld::Land>& land = mData.getLand();
|
||||
int landIndex = land.searchId(mId);
|
||||
if (landIndex != -1 && !land.getRecord(mId).isDeleted())
|
||||
{
|
||||
|
||||
if (land.getRecord(mId).isDeleted())
|
||||
return;
|
||||
|
||||
const ESM::Land& esmLand = land.getRecord(mId).get();
|
||||
|
||||
if (esmLand.getLandData(ESM::Land::DATA_VHGT))
|
||||
{
|
||||
if (mTerrain)
|
||||
{
|
||||
mTerrain->unloadCell(mCoordinates.getX(), mCoordinates.getY());
|
||||
|
@ -157,13 +157,6 @@ void CSVRender::Cell::updateLand()
|
|||
mCellBorder = std::make_unique<CellBorder>(mCellNode, mCoordinates);
|
||||
|
||||
mCellBorder->buildShape(esmLand);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// No land data
|
||||
unloadLand();
|
||||
}
|
||||
|
||||
void CSVRender::Cell::unloadLand()
|
||||
|
@ -175,13 +168,14 @@ void CSVRender::Cell::unloadLand()
|
|||
mCellBorder.reset();
|
||||
}
|
||||
|
||||
CSVRender::Cell::Cell(CSMWorld::Data& data, osg::Group* rootNode, const std::string& id, bool deleted)
|
||||
: mData(data)
|
||||
CSVRender::Cell::Cell(
|
||||
CSMDoc::Document& document, osg::Group* rootNode, const std::string& id, bool deleted, bool isExterior)
|
||||
: mData(document.getData())
|
||||
, mId(ESM::RefId::stringRefId(id))
|
||||
, mDeleted(deleted)
|
||||
, mSubMode(0)
|
||||
, mSubModeElementMask(0)
|
||||
, mUpdateLand(true)
|
||||
, mUpdateLand(isExterior)
|
||||
, mLandDeleted(false)
|
||||
{
|
||||
std::pair<CSMWorld::CellCoordinates, bool> result = CSMWorld::CellCoordinates::fromId(id);
|
||||
|
@ -207,7 +201,17 @@ CSVRender::Cell::Cell(CSMWorld::Data& data, osg::Group* rootNode, const std::str
|
|||
|
||||
addObjects(0, rows - 1);
|
||||
|
||||
if (mUpdateLand)
|
||||
{
|
||||
int landIndex = document.getData().getLand().searchId(mId);
|
||||
if (landIndex == -1)
|
||||
{
|
||||
CSMWorld::IdTable& landTable
|
||||
= dynamic_cast<CSMWorld::IdTable&>(*mData.getTableModel(CSMWorld::UniversalId::Type_Land));
|
||||
document.getUndoStack().push(new CSMWorld::CreateCommand(landTable, mId.getRefIdString()));
|
||||
}
|
||||
updateLand();
|
||||
}
|
||||
|
||||
mPathgrid = std::make_unique<Pathgrid>(mData, mCellNode, mId.getRefIdString(), mCoordinates);
|
||||
mCellWater = std::make_unique<CellWater>(mData, mCellNode, mId.getRefIdString(), mCoordinates);
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include <osg/Vec3d>
|
||||
#include <osg/ref_ptr>
|
||||
|
||||
#include "../../model/doc/document.hpp"
|
||||
#include "../../model/world/cellcoordinates.hpp"
|
||||
#include "instancedragmodes.hpp"
|
||||
#include <components/esm/refid.hpp>
|
||||
|
@ -89,7 +90,8 @@ namespace CSVRender
|
|||
public:
|
||||
/// \note Deleted covers both cells that are deleted and cells that don't exist in
|
||||
/// the first place.
|
||||
Cell(CSMWorld::Data& data, osg::Group* rootNode, const std::string& id, bool deleted = false);
|
||||
Cell(CSMDoc::Document& document, osg::Group* rootNode, const std::string& id, bool deleted = false,
|
||||
bool isExterior = false);
|
||||
|
||||
~Cell();
|
||||
|
||||
|
|
|
@ -47,9 +47,6 @@ void CSVRender::CellBorder::buildShape(const ESM::Land& esmLand)
|
|||
{
|
||||
const ESM::Land::LandData* landData = esmLand.getLandData(ESM::Land::DATA_VHGT);
|
||||
|
||||
if (!landData)
|
||||
return;
|
||||
|
||||
mBaseNode->removeChild(mBorderGeometry);
|
||||
mBorderGeometry = new osg::Geometry();
|
||||
|
||||
|
@ -62,6 +59,8 @@ void CSVRender::CellBorder::buildShape(const ESM::Land& esmLand)
|
|||
Traverse the cell border counter-clockwise starting at the SW corner vertex (0, 0).
|
||||
Each loop starts at a corner vertex and ends right before the next corner vertex.
|
||||
*/
|
||||
if (landData)
|
||||
{
|
||||
for (; x < ESM::Land::LAND_SIZE - 1; ++x)
|
||||
vertices->push_back(osg::Vec3f(scaleToWorld(x), scaleToWorld(y), landData->mHeights[landIndex(x, y)]));
|
||||
|
||||
|
@ -76,6 +75,24 @@ void CSVRender::CellBorder::buildShape(const ESM::Land& esmLand)
|
|||
x = 0;
|
||||
for (; y > 0; --y)
|
||||
vertices->push_back(osg::Vec3f(scaleToWorld(x), scaleToWorld(y), landData->mHeights[landIndex(x, y)]));
|
||||
}
|
||||
else
|
||||
{
|
||||
for (; x < ESM::Land::LAND_SIZE - 1; ++x)
|
||||
vertices->push_back(osg::Vec3f(scaleToWorld(x), scaleToWorld(y), ESM::Land::DEFAULT_HEIGHT));
|
||||
|
||||
x = ESM::Land::LAND_SIZE - 1;
|
||||
for (; y < ESM::Land::LAND_SIZE - 1; ++y)
|
||||
vertices->push_back(osg::Vec3f(scaleToWorld(x), scaleToWorld(y), ESM::Land::DEFAULT_HEIGHT));
|
||||
|
||||
y = ESM::Land::LAND_SIZE - 1;
|
||||
for (; x > 0; --x)
|
||||
vertices->push_back(osg::Vec3f(scaleToWorld(x), scaleToWorld(y), ESM::Land::DEFAULT_HEIGHT));
|
||||
|
||||
x = 0;
|
||||
for (; y > 0; --y)
|
||||
vertices->push_back(osg::Vec3f(scaleToWorld(x), scaleToWorld(y), ESM::Land::DEFAULT_HEIGHT));
|
||||
}
|
||||
|
||||
mBorderGeometry->setVertexArray(vertices);
|
||||
|
||||
|
|
|
@ -86,8 +86,8 @@ bool CSVRender::PagedWorldspaceWidget::adjustCells()
|
|||
{
|
||||
modified = true;
|
||||
|
||||
auto cell = std::make_unique<Cell>(
|
||||
mDocument.getData(), mRootNode, iter->first.getId(mWorldspace), deleted);
|
||||
auto cell
|
||||
= std::make_unique<Cell>(mDocument, mRootNode, iter->first.getId(mWorldspace), deleted, true);
|
||||
|
||||
delete iter->second;
|
||||
iter->second = cell.release();
|
||||
|
@ -465,7 +465,7 @@ void CSVRender::PagedWorldspaceWidget::addCellToScene(const CSMWorld::CellCoordi
|
|||
|
||||
bool deleted = index == -1 || cells.getRecord(index).mState == CSMWorld::RecordBase::State_Deleted;
|
||||
|
||||
auto cell = std::make_unique<Cell>(mDocument.getData(), mRootNode, coordinates.getId(mWorldspace), deleted);
|
||||
auto cell = std::make_unique<Cell>(mDocument, mRootNode, coordinates.getId(mWorldspace), deleted, true);
|
||||
EditMode* editMode = getEditMode();
|
||||
cell->setSubMode(editMode->getSubMode(), editMode->getInteractionMask());
|
||||
|
||||
|
|
|
@ -154,6 +154,8 @@ namespace CSVRender
|
|||
|
||||
void TerrainStorage::adjustColor(int col, int row, const ESM::LandData* heightData, osg::Vec4ub& color) const
|
||||
{
|
||||
if (!heightData)
|
||||
return;
|
||||
// Highlight broken height changes
|
||||
int heightWarningLimit = 1024;
|
||||
if (((col > 0 && row > 0) && leftOrUpIsOverTheLimit(col, row, heightWarningLimit, heightData->getHeights()))
|
||||
|
|
|
@ -79,7 +79,7 @@ CSVRender::UnpagedWorldspaceWidget::UnpagedWorldspaceWidget(
|
|||
|
||||
update();
|
||||
|
||||
mCell = std::make_unique<Cell>(document.getData(), mRootNode, mCellId);
|
||||
mCell = std::make_unique<Cell>(document, mRootNode, mCellId);
|
||||
}
|
||||
|
||||
void CSVRender::UnpagedWorldspaceWidget::cellDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight)
|
||||
|
@ -127,7 +127,7 @@ bool CSVRender::UnpagedWorldspaceWidget::handleDrop(
|
|||
|
||||
mCellId = universalIdData.begin()->getId();
|
||||
|
||||
mCell = std::make_unique<Cell>(getDocument().getData(), mRootNode, mCellId);
|
||||
mCell = std::make_unique<Cell>(getDocument(), mRootNode, mCellId);
|
||||
mCamPositionSet = false;
|
||||
mOrbitCamControl->reset();
|
||||
|
||||
|
|
|
@ -101,22 +101,27 @@ namespace ESM
|
|||
{
|
||||
case fourCC("VNML"):
|
||||
esm.skipHSub();
|
||||
if (mFlags & Flag_HeightsNormals)
|
||||
mDataTypes |= DATA_VNML;
|
||||
break;
|
||||
case fourCC("VHGT"):
|
||||
esm.skipHSub();
|
||||
if (mFlags & Flag_HeightsNormals)
|
||||
mDataTypes |= DATA_VHGT;
|
||||
break;
|
||||
case fourCC("WNAM"):
|
||||
esm.getHT(mWnam);
|
||||
if (mFlags & Flag_HeightsNormals)
|
||||
mDataTypes |= DATA_WNAM;
|
||||
break;
|
||||
case fourCC("VCLR"):
|
||||
esm.skipHSub();
|
||||
if (mFlags & Flag_Colors)
|
||||
mDataTypes |= DATA_VCLR;
|
||||
break;
|
||||
case fourCC("VTEX"):
|
||||
esm.skipHSub();
|
||||
if (mFlags & Flag_Textures)
|
||||
mDataTypes |= DATA_VTEX;
|
||||
break;
|
||||
default:
|
||||
|
@ -204,9 +209,9 @@ namespace ESM
|
|||
if (mLandData == nullptr)
|
||||
mLandData = std::make_unique<LandData>();
|
||||
|
||||
mLandData->mHeights.fill(0);
|
||||
mLandData->mMinHeight = 0;
|
||||
mLandData->mMaxHeight = 0;
|
||||
mLandData->mHeights.fill(DEFAULT_HEIGHT);
|
||||
mLandData->mMinHeight = DEFAULT_HEIGHT;
|
||||
mLandData->mMaxHeight = DEFAULT_HEIGHT;
|
||||
for (size_t i = 0; i < LandRecordData::sLandNumVerts; ++i)
|
||||
{
|
||||
mLandData->mNormals[i * 3 + 0] = 0;
|
||||
|
|
|
@ -66,6 +66,13 @@ namespace ESM
|
|||
DATA_VTEX = 16
|
||||
};
|
||||
|
||||
enum Flags
|
||||
{
|
||||
Flag_HeightsNormals = 0x1,
|
||||
Flag_Colors = 0x2,
|
||||
Flag_Textures = 0x4
|
||||
};
|
||||
|
||||
// default height to use in case there is no Land record
|
||||
static constexpr int DEFAULT_HEIGHT = -2048;
|
||||
|
||||
|
|
Loading…
Reference in a new issue