|
|
|
@ -72,173 +72,42 @@ namespace CSVRender
|
|
|
|
|
return &mAlteredHeight[inCellY*ESM::Land::LAND_SIZE + inCellX];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TerrainStorage::fillVertexBuffers (int lodLevel, float size, const osg::Vec2f& center,
|
|
|
|
|
osg::ref_ptr<osg::Vec3Array> positions,
|
|
|
|
|
osg::ref_ptr<osg::Vec3Array> normals,
|
|
|
|
|
osg::ref_ptr<osg::Vec4ubArray> colours)
|
|
|
|
|
void TerrainStorage::getBounds(float &minX, float &maxX, float &minY, float &maxY)
|
|
|
|
|
{
|
|
|
|
|
// LOD level n means every 2^n-th vertex is kept
|
|
|
|
|
size_t increment = static_cast<size_t>(1) << lodLevel;
|
|
|
|
|
|
|
|
|
|
osg::Vec2f origin = center - osg::Vec2f(size/2.f, size/2.f);
|
|
|
|
|
|
|
|
|
|
int startCellX = static_cast<int>(std::floor(origin.x()));
|
|
|
|
|
int startCellY = static_cast<int>(std::floor(origin.y()));
|
|
|
|
|
|
|
|
|
|
size_t numVerts = static_cast<size_t>(size*(ESM::Land::LAND_SIZE - 1) / increment + 1);
|
|
|
|
|
|
|
|
|
|
positions->resize(numVerts*numVerts);
|
|
|
|
|
normals->resize(numVerts*numVerts);
|
|
|
|
|
colours->resize(numVerts*numVerts);
|
|
|
|
|
|
|
|
|
|
osg::Vec3f normal;
|
|
|
|
|
osg::Vec4ub color;
|
|
|
|
|
|
|
|
|
|
float vertY = 0;
|
|
|
|
|
float vertX = 0;
|
|
|
|
|
|
|
|
|
|
ESMTerrain::LandCache cache;
|
|
|
|
|
// not needed at the moment - this returns the bounds of the whole world, but we only edit individual cells
|
|
|
|
|
throw std::runtime_error("getBounds not implemented");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float vertY_ = 0; // of current cell corner
|
|
|
|
|
for (int cellY = startCellY; cellY < startCellY + std::ceil(size); ++cellY)
|
|
|
|
|
void TerrainStorage::adjustColor(int col, int row, const ESM::Land::LandData *heightData, osg::Vec4ub& color) const
|
|
|
|
|
{
|
|
|
|
|
// Highlight broken height changes
|
|
|
|
|
if ( ((col > 0 && row > 0) &&
|
|
|
|
|
((abs(heightData->mHeights[col*ESM::Land::LAND_SIZE + row] +
|
|
|
|
|
mAlteredHeight[static_cast<unsigned int>(col*ESM::Land::LAND_SIZE + row)] -
|
|
|
|
|
(heightData->mHeights[(col)*ESM::Land::LAND_SIZE + row - 1] +
|
|
|
|
|
mAlteredHeight[static_cast<unsigned int>((col)*ESM::Land::LAND_SIZE + row - 1)])) >= 1024 ) ||
|
|
|
|
|
abs(heightData->mHeights[col*ESM::Land::LAND_SIZE + row] +
|
|
|
|
|
mAlteredHeight[static_cast<unsigned int>(col*ESM::Land::LAND_SIZE + row)] -
|
|
|
|
|
(heightData->mHeights[(col - 1)*ESM::Land::LAND_SIZE + row] +
|
|
|
|
|
mAlteredHeight[static_cast<unsigned int>((col - 1)*ESM::Land::LAND_SIZE + row)])) >= 1024 )) ||
|
|
|
|
|
((col < ESM::Land::LAND_SIZE - 1 && row < ESM::Land::LAND_SIZE - 1) &&
|
|
|
|
|
((abs(heightData->mHeights[col*ESM::Land::LAND_SIZE + row] +
|
|
|
|
|
mAlteredHeight[static_cast<unsigned int>(col*ESM::Land::LAND_SIZE + row)] -
|
|
|
|
|
(heightData->mHeights[(col)*ESM::Land::LAND_SIZE + row + 1] +
|
|
|
|
|
mAlteredHeight[static_cast<unsigned int>((col)*ESM::Land::LAND_SIZE + row + 1)])) >= 1024 ) ||
|
|
|
|
|
abs(heightData->mHeights[col*ESM::Land::LAND_SIZE + row] +
|
|
|
|
|
mAlteredHeight[static_cast<unsigned int>(col*ESM::Land::LAND_SIZE + row)] -
|
|
|
|
|
(heightData->mHeights[(col + 1)*ESM::Land::LAND_SIZE + row] +
|
|
|
|
|
mAlteredHeight[static_cast<unsigned int>((col + 1)*ESM::Land::LAND_SIZE + row)])) >= 1024 )))
|
|
|
|
|
{
|
|
|
|
|
float vertX_ = 0; // of current cell corner
|
|
|
|
|
for (int cellX = startCellX; cellX < startCellX + std::ceil(size); ++cellX)
|
|
|
|
|
{
|
|
|
|
|
const ESMTerrain::LandObject* land = ESMTerrain::Storage::getLand(cellX, cellY, cache);
|
|
|
|
|
const ESM::Land::LandData *heightData = 0;
|
|
|
|
|
const ESM::Land::LandData *normalData = 0;
|
|
|
|
|
const ESM::Land::LandData *colourData = 0;
|
|
|
|
|
if (land)
|
|
|
|
|
{
|
|
|
|
|
heightData = land->getData(ESM::Land::DATA_VHGT);
|
|
|
|
|
normalData = land->getData(ESM::Land::DATA_VNML);
|
|
|
|
|
colourData = land->getData(ESM::Land::DATA_VCLR);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int rowStart = 0;
|
|
|
|
|
int colStart = 0;
|
|
|
|
|
// Skip the first row / column unless we're at a chunk edge,
|
|
|
|
|
// since this row / column is already contained in a previous cell
|
|
|
|
|
// This is only relevant if we're creating a chunk spanning multiple cells
|
|
|
|
|
if (vertY_ != 0)
|
|
|
|
|
colStart += increment;
|
|
|
|
|
if (vertX_ != 0)
|
|
|
|
|
rowStart += increment;
|
|
|
|
|
|
|
|
|
|
// Only relevant for chunks smaller than (contained in) one cell
|
|
|
|
|
rowStart += (origin.x() - startCellX) * ESM::Land::LAND_SIZE;
|
|
|
|
|
colStart += (origin.y() - startCellY) * ESM::Land::LAND_SIZE;
|
|
|
|
|
int rowEnd = std::min(static_cast<int>(rowStart + std::min(1.f, size) * (ESM::Land::LAND_SIZE-1) + 1), static_cast<int>(ESM::Land::LAND_SIZE));
|
|
|
|
|
int colEnd = std::min(static_cast<int>(colStart + std::min(1.f, size) * (ESM::Land::LAND_SIZE-1) + 1), static_cast<int>(ESM::Land::LAND_SIZE));
|
|
|
|
|
|
|
|
|
|
vertY = vertY_;
|
|
|
|
|
for (int col=colStart; col<colEnd; col += increment)
|
|
|
|
|
{
|
|
|
|
|
vertX = vertX_;
|
|
|
|
|
for (int row=rowStart; row<rowEnd; row += increment)
|
|
|
|
|
{
|
|
|
|
|
int srcArrayIndex = col*ESM::Land::LAND_SIZE*3+row*3;
|
|
|
|
|
|
|
|
|
|
assert(row >= 0 && row < ESM::Land::LAND_SIZE);
|
|
|
|
|
assert(col >= 0 && col < ESM::Land::LAND_SIZE);
|
|
|
|
|
|
|
|
|
|
assert (vertX < numVerts);
|
|
|
|
|
assert (vertY < numVerts);
|
|
|
|
|
|
|
|
|
|
float height = defaultHeight;
|
|
|
|
|
if (heightData)
|
|
|
|
|
height = heightData->mHeights[col*ESM::Land::LAND_SIZE + row];
|
|
|
|
|
|
|
|
|
|
(*positions)[static_cast<unsigned int>(vertX*numVerts + vertY)]
|
|
|
|
|
= osg::Vec3f((vertX / float(numVerts - 1) - 0.5f) * size * Constants::CellSizeInUnits,
|
|
|
|
|
(vertY / float(numVerts - 1) - 0.5f) * size * Constants::CellSizeInUnits,
|
|
|
|
|
height + mAlteredHeight[static_cast<unsigned int>(col*ESM::Land::LAND_SIZE + row)]);
|
|
|
|
|
|
|
|
|
|
if (normalData)
|
|
|
|
|
{
|
|
|
|
|
for (int i=0; i<3; ++i)
|
|
|
|
|
normal[i] = normalData->mNormals[srcArrayIndex+i];
|
|
|
|
|
|
|
|
|
|
normal.normalize();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
normal = osg::Vec3f(0,0,1);
|
|
|
|
|
|
|
|
|
|
// Normals apparently don't connect seamlessly between cells
|
|
|
|
|
if (col == ESM::Land::LAND_SIZE-1 || row == ESM::Land::LAND_SIZE-1)
|
|
|
|
|
fixNormal(normal, cellX, cellY, col, row, cache);
|
|
|
|
|
|
|
|
|
|
// some corner normals appear to be complete garbage (z < 0)
|
|
|
|
|
if ((row == 0 || row == ESM::Land::LAND_SIZE-1) && (col == 0 || col == ESM::Land::LAND_SIZE-1))
|
|
|
|
|
averageNormal(normal, cellX, cellY, col, row, cache);
|
|
|
|
|
|
|
|
|
|
assert(normal.z() > 0);
|
|
|
|
|
|
|
|
|
|
(*normals)[static_cast<unsigned int>(vertX*numVerts + vertY)] = normal;
|
|
|
|
|
|
|
|
|
|
if (colourData)
|
|
|
|
|
{
|
|
|
|
|
for (int i=0; i<3; ++i)
|
|
|
|
|
color[i] = colourData->mColours[srcArrayIndex+i];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
color.r() = 255;
|
|
|
|
|
color.g() = 255;
|
|
|
|
|
color.b() = 255;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Highlight broken height changes
|
|
|
|
|
if ( ((col > 0 && row > 0) &&
|
|
|
|
|
((abs(heightData->mHeights[col*ESM::Land::LAND_SIZE + row] +
|
|
|
|
|
mAlteredHeight[static_cast<unsigned int>(col*ESM::Land::LAND_SIZE + row)] -
|
|
|
|
|
(heightData->mHeights[(col)*ESM::Land::LAND_SIZE + row - 1] +
|
|
|
|
|
mAlteredHeight[static_cast<unsigned int>((col)*ESM::Land::LAND_SIZE + row - 1)])) >= 1024 ) ||
|
|
|
|
|
abs(heightData->mHeights[col*ESM::Land::LAND_SIZE + row] +
|
|
|
|
|
mAlteredHeight[static_cast<unsigned int>(col*ESM::Land::LAND_SIZE + row)] -
|
|
|
|
|
(heightData->mHeights[(col - 1)*ESM::Land::LAND_SIZE + row] +
|
|
|
|
|
mAlteredHeight[static_cast<unsigned int>((col - 1)*ESM::Land::LAND_SIZE + row)])) >= 1024 )) ||
|
|
|
|
|
((col < ESM::Land::LAND_SIZE - 1 && row < ESM::Land::LAND_SIZE - 1) &&
|
|
|
|
|
((abs(heightData->mHeights[col*ESM::Land::LAND_SIZE + row] +
|
|
|
|
|
mAlteredHeight[static_cast<unsigned int>(col*ESM::Land::LAND_SIZE + row)] -
|
|
|
|
|
(heightData->mHeights[(col)*ESM::Land::LAND_SIZE + row + 1] +
|
|
|
|
|
mAlteredHeight[static_cast<unsigned int>((col)*ESM::Land::LAND_SIZE + row + 1)])) >= 1024 ) ||
|
|
|
|
|
abs(heightData->mHeights[col*ESM::Land::LAND_SIZE + row] +
|
|
|
|
|
mAlteredHeight[static_cast<unsigned int>(col*ESM::Land::LAND_SIZE + row)] -
|
|
|
|
|
(heightData->mHeights[(col + 1)*ESM::Land::LAND_SIZE + row] +
|
|
|
|
|
mAlteredHeight[static_cast<unsigned int>((col + 1)*ESM::Land::LAND_SIZE + row)])) >= 1024 )))
|
|
|
|
|
{
|
|
|
|
|
color.r() = 255;
|
|
|
|
|
color.g() = 0;
|
|
|
|
|
color.b() = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Unlike normals, colors mostly connect seamlessly between cells, but not always...
|
|
|
|
|
if (col == ESM::Land::LAND_SIZE-1 || row == ESM::Land::LAND_SIZE-1)
|
|
|
|
|
fixColour(color, cellX, cellY, col, row, cache);
|
|
|
|
|
|
|
|
|
|
color.a() = 255;
|
|
|
|
|
|
|
|
|
|
(*colours)[static_cast<unsigned int>(vertX*numVerts + vertY)] = color;
|
|
|
|
|
|
|
|
|
|
++vertX;
|
|
|
|
|
}
|
|
|
|
|
++vertY;
|
|
|
|
|
}
|
|
|
|
|
vertX_ = vertX;
|
|
|
|
|
}
|
|
|
|
|
vertY_ = vertY;
|
|
|
|
|
|
|
|
|
|
assert(vertX_ == numVerts); // Ensure we covered whole area
|
|
|
|
|
color.r() = 255;
|
|
|
|
|
color.g() = 0;
|
|
|
|
|
color.b() = 0;
|
|
|
|
|
}
|
|
|
|
|
assert(vertY_ == numVerts); // Ensure we covered whole area*/
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TerrainStorage::getBounds(float &minX, float &maxX, float &minY, float &maxY)
|
|
|
|
|
float TerrainStorage::getAlteredHeight(int col, int row) const
|
|
|
|
|
{
|
|
|
|
|
// not needed at the moment - this returns the bounds of the whole world, but we only edit individual cells
|
|
|
|
|
throw std::runtime_error("getBounds not implemented");
|
|
|
|
|
return mAlteredHeight[static_cast<unsigned int>(col*ESM::Land::LAND_SIZE + row)];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|