|
@@ -44,6 +44,8 @@
|
|
|
namespace Urho3D
|
|
namespace Urho3D
|
|
|
{
|
|
{
|
|
|
|
|
|
|
|
|
|
+const char* TERRAIN_CATEGORY = "Terrain";
|
|
|
|
|
+
|
|
|
OBJECTTYPESTATIC(Terrain);
|
|
OBJECTTYPESTATIC(Terrain);
|
|
|
|
|
|
|
|
static const Vector3 DEFAULT_SPACING(1.0f, 0.25f, 1.0f);
|
|
static const Vector3 DEFAULT_SPACING(1.0f, 0.25f, 1.0f);
|
|
@@ -89,8 +91,8 @@ Terrain::~Terrain()
|
|
|
|
|
|
|
|
void Terrain::RegisterObject(Context* context)
|
|
void Terrain::RegisterObject(Context* context)
|
|
|
{
|
|
{
|
|
|
- context->RegisterFactory<Terrain>();
|
|
|
|
|
-
|
|
|
|
|
|
|
+ context->RegisterComponentFactory<Terrain>(TERRAIN_CATEGORY);
|
|
|
|
|
+
|
|
|
ACCESSOR_ATTRIBUTE(Terrain, VAR_BOOL, "Is Enabled", IsEnabled, SetEnabled, bool, true, AM_DEFAULT);
|
|
ACCESSOR_ATTRIBUTE(Terrain, VAR_BOOL, "Is Enabled", IsEnabled, SetEnabled, bool, true, AM_DEFAULT);
|
|
|
ACCESSOR_ATTRIBUTE(Terrain, VAR_RESOURCEREF, "Height Map", GetHeightMapAttr, SetHeightMapAttr, ResourceRef, ResourceRef(Image::GetTypeStatic()), AM_DEFAULT);
|
|
ACCESSOR_ATTRIBUTE(Terrain, VAR_RESOURCEREF, "Height Map", GetHeightMapAttr, SetHeightMapAttr, ResourceRef, ResourceRef(Image::GetTypeStatic()), AM_DEFAULT);
|
|
|
ACCESSOR_ATTRIBUTE(Terrain, VAR_RESOURCEREF, "Material", GetMaterialAttr, SetMaterialAttr, ResourceRef, ResourceRef(Material::GetTypeStatic()), AM_DEFAULT);
|
|
ACCESSOR_ATTRIBUTE(Terrain, VAR_RESOURCEREF, "Material", GetMaterialAttr, SetMaterialAttr, ResourceRef, ResourceRef(Material::GetTypeStatic()), AM_DEFAULT);
|
|
@@ -106,13 +108,13 @@ void Terrain::RegisterObject(Context* context)
|
|
|
ACCESSOR_ATTRIBUTE(Terrain, VAR_INT, "View Mask", GetViewMask, SetViewMask, unsigned, DEFAULT_VIEWMASK, AM_DEFAULT);
|
|
ACCESSOR_ATTRIBUTE(Terrain, VAR_INT, "View Mask", GetViewMask, SetViewMask, unsigned, DEFAULT_VIEWMASK, AM_DEFAULT);
|
|
|
ACCESSOR_ATTRIBUTE(Terrain, VAR_INT, "Light Mask", GetLightMask, SetLightMask, unsigned, DEFAULT_LIGHTMASK, AM_DEFAULT);
|
|
ACCESSOR_ATTRIBUTE(Terrain, VAR_INT, "Light Mask", GetLightMask, SetLightMask, unsigned, DEFAULT_LIGHTMASK, AM_DEFAULT);
|
|
|
ACCESSOR_ATTRIBUTE(Terrain, VAR_INT, "Shadow Mask", GetShadowMask, SetShadowMask, unsigned, DEFAULT_SHADOWMASK, AM_DEFAULT);
|
|
ACCESSOR_ATTRIBUTE(Terrain, VAR_INT, "Shadow Mask", GetShadowMask, SetShadowMask, unsigned, DEFAULT_SHADOWMASK, AM_DEFAULT);
|
|
|
- ACCESSOR_ATTRIBUTE(Terrain, VAR_INT, "Zone Mask", GetZoneMask, SetZoneMask, unsigned, DEFAULT_SHADOWMASK, AM_DEFAULT);
|
|
|
|
|
|
|
+ ACCESSOR_ATTRIBUTE(Terrain, VAR_INT, "Zone Mask", GetZoneMask, SetZoneMask, unsigned, DEFAULT_ZONEMASK, AM_DEFAULT);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void Terrain::OnSetAttribute(const AttributeInfo& attr, const Variant& src)
|
|
void Terrain::OnSetAttribute(const AttributeInfo& attr, const Variant& src)
|
|
|
{
|
|
{
|
|
|
Component::OnSetAttribute(attr, src);
|
|
Component::OnSetAttribute(attr, src);
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// Change of any non-accessor attribute requires recreation of the terrain
|
|
// Change of any non-accessor attribute requires recreation of the terrain
|
|
|
if (!attr.accessor_)
|
|
if (!attr.accessor_)
|
|
|
recreateTerrain_ = true;
|
|
recreateTerrain_ = true;
|
|
@@ -127,7 +129,7 @@ void Terrain::ApplyAttributes()
|
|
|
void Terrain::OnSetEnabled()
|
|
void Terrain::OnSetEnabled()
|
|
|
{
|
|
{
|
|
|
bool enabled = IsEnabledEffective();
|
|
bool enabled = IsEnabledEffective();
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
for (unsigned i = 0; i < patches_.Size(); ++i)
|
|
for (unsigned i = 0; i < patches_.Size(); ++i)
|
|
|
{
|
|
{
|
|
|
if (patches_[i])
|
|
if (patches_[i])
|
|
@@ -140,7 +142,7 @@ void Terrain::SetSpacing(const Vector3& spacing)
|
|
|
if (spacing != spacing_)
|
|
if (spacing != spacing_)
|
|
|
{
|
|
{
|
|
|
spacing_ = spacing;
|
|
spacing_ = spacing;
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
CreateGeometry();
|
|
CreateGeometry();
|
|
|
MarkNetworkUpdate();
|
|
MarkNetworkUpdate();
|
|
|
}
|
|
}
|
|
@@ -150,11 +152,11 @@ void Terrain::SetPatchSize(int size)
|
|
|
{
|
|
{
|
|
|
if (size < MIN_PATCH_SIZE || size > MAX_PATCH_SIZE || !IsPowerOfTwo(size))
|
|
if (size < MIN_PATCH_SIZE || size > MAX_PATCH_SIZE || !IsPowerOfTwo(size))
|
|
|
return;
|
|
return;
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
if (size != patchSize_)
|
|
if (size != patchSize_)
|
|
|
{
|
|
{
|
|
|
patchSize_ = size;
|
|
patchSize_ = size;
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
CreateGeometry();
|
|
CreateGeometry();
|
|
|
MarkNetworkUpdate();
|
|
MarkNetworkUpdate();
|
|
|
}
|
|
}
|
|
@@ -163,7 +165,7 @@ void Terrain::SetPatchSize(int size)
|
|
|
bool Terrain::SetHeightMap(Image* image)
|
|
bool Terrain::SetHeightMap(Image* image)
|
|
|
{
|
|
{
|
|
|
bool success = SetHeightMapInternal(image, true);
|
|
bool success = SetHeightMapInternal(image, true);
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
MarkNetworkUpdate();
|
|
MarkNetworkUpdate();
|
|
|
return success;
|
|
return success;
|
|
|
}
|
|
}
|
|
@@ -176,7 +178,7 @@ void Terrain::SetMaterial(Material* material)
|
|
|
if (patches_[i])
|
|
if (patches_[i])
|
|
|
patches_[i]->SetMaterial(material);
|
|
patches_[i]->SetMaterial(material);
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
MarkNetworkUpdate();
|
|
MarkNetworkUpdate();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -188,7 +190,7 @@ void Terrain::SetDrawDistance(float distance)
|
|
|
if (patches_[i])
|
|
if (patches_[i])
|
|
|
patches_[i]->SetDrawDistance(distance);
|
|
patches_[i]->SetDrawDistance(distance);
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
MarkNetworkUpdate();
|
|
MarkNetworkUpdate();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -200,7 +202,7 @@ void Terrain::SetShadowDistance(float distance)
|
|
|
if (patches_[i])
|
|
if (patches_[i])
|
|
|
patches_[i]->SetShadowDistance(distance);
|
|
patches_[i]->SetShadowDistance(distance);
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
MarkNetworkUpdate();
|
|
MarkNetworkUpdate();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -212,7 +214,7 @@ void Terrain::SetLodBias(float bias)
|
|
|
if (patches_[i])
|
|
if (patches_[i])
|
|
|
patches_[i]->SetLodBias(bias);
|
|
patches_[i]->SetLodBias(bias);
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
MarkNetworkUpdate();
|
|
MarkNetworkUpdate();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -224,7 +226,7 @@ void Terrain::SetViewMask(unsigned mask)
|
|
|
if (patches_[i])
|
|
if (patches_[i])
|
|
|
patches_[i]->SetViewMask(mask);
|
|
patches_[i]->SetViewMask(mask);
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
MarkNetworkUpdate();
|
|
MarkNetworkUpdate();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -236,7 +238,7 @@ void Terrain::SetLightMask(unsigned mask)
|
|
|
if (patches_[i])
|
|
if (patches_[i])
|
|
|
patches_[i]->SetLightMask(mask);
|
|
patches_[i]->SetLightMask(mask);
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
MarkNetworkUpdate();
|
|
MarkNetworkUpdate();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -248,7 +250,7 @@ void Terrain::SetShadowMask(unsigned mask)
|
|
|
if (patches_[i])
|
|
if (patches_[i])
|
|
|
patches_[i]->SetShadowMask(mask);
|
|
patches_[i]->SetShadowMask(mask);
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
MarkNetworkUpdate();
|
|
MarkNetworkUpdate();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -260,7 +262,7 @@ void Terrain::SetZoneMask(unsigned mask)
|
|
|
if (patches_[i])
|
|
if (patches_[i])
|
|
|
patches_[i]->SetZoneMask(mask);
|
|
patches_[i]->SetZoneMask(mask);
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
MarkNetworkUpdate();
|
|
MarkNetworkUpdate();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -272,7 +274,7 @@ void Terrain::SetMaxLights(unsigned num)
|
|
|
if (patches_[i])
|
|
if (patches_[i])
|
|
|
patches_[i]->SetMaxLights(num);
|
|
patches_[i]->SetMaxLights(num);
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
MarkNetworkUpdate();
|
|
MarkNetworkUpdate();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -284,7 +286,7 @@ void Terrain::SetCastShadows(bool enable)
|
|
|
if (patches_[i])
|
|
if (patches_[i])
|
|
|
patches_[i]->SetCastShadows(enable);
|
|
patches_[i]->SetCastShadows(enable);
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
MarkNetworkUpdate();
|
|
MarkNetworkUpdate();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -296,7 +298,7 @@ void Terrain::SetOccluder(bool enable)
|
|
|
if (patches_[i])
|
|
if (patches_[i])
|
|
|
patches_[i]->SetOccluder(enable);
|
|
patches_[i]->SetOccluder(enable);
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
MarkNetworkUpdate();
|
|
MarkNetworkUpdate();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -308,7 +310,7 @@ void Terrain::SetOccludee(bool enable)
|
|
|
if (patches_[i])
|
|
if (patches_[i])
|
|
|
patches_[i]->SetOccludee(enable);
|
|
patches_[i]->SetOccludee(enable);
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
MarkNetworkUpdate();
|
|
MarkNetworkUpdate();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -345,7 +347,7 @@ float Terrain::GetHeight(const Vector3& worldPosition) const
|
|
|
float xFrac = xPos - floorf(xPos);
|
|
float xFrac = xPos - floorf(xPos);
|
|
|
float zFrac = zPos - floorf(zPos);
|
|
float zFrac = zPos - floorf(zPos);
|
|
|
float h1, h2, h3;
|
|
float h1, h2, h3;
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
if (xFrac + zFrac >= 1.0f)
|
|
if (xFrac + zFrac >= 1.0f)
|
|
|
{
|
|
{
|
|
|
h1 = GetRawHeight((unsigned)xPos + 1, (unsigned)zPos + 1);
|
|
h1 = GetRawHeight((unsigned)xPos + 1, (unsigned)zPos + 1);
|
|
@@ -360,7 +362,7 @@ float Terrain::GetHeight(const Vector3& worldPosition) const
|
|
|
h2 = GetRawHeight((unsigned)xPos + 1, (unsigned)zPos);
|
|
h2 = GetRawHeight((unsigned)xPos + 1, (unsigned)zPos);
|
|
|
h3 = GetRawHeight((unsigned)xPos, (unsigned)zPos + 1);
|
|
h3 = GetRawHeight((unsigned)xPos, (unsigned)zPos + 1);
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
float h = h1 * (1.0f - xFrac - zFrac) + h2 * xFrac + h3 * zFrac;
|
|
float h = h1 * (1.0f - xFrac - zFrac) + h2 * xFrac + h3 * zFrac;
|
|
|
/// \todo This assumes that the terrain scene node is upright
|
|
/// \todo This assumes that the terrain scene node is upright
|
|
|
return node_->GetWorldScale().y_ * h + node_->GetWorldPosition().y_;
|
|
return node_->GetWorldScale().y_ * h + node_->GetWorldPosition().y_;
|
|
@@ -379,7 +381,7 @@ Vector3 Terrain::GetNormal(const Vector3& worldPosition) const
|
|
|
float xFrac = xPos - floorf(xPos);
|
|
float xFrac = xPos - floorf(xPos);
|
|
|
float zFrac = zPos - floorf(zPos);
|
|
float zFrac = zPos - floorf(zPos);
|
|
|
Vector3 n1, n2, n3;
|
|
Vector3 n1, n2, n3;
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
if (xFrac + zFrac >= 1.0f)
|
|
if (xFrac + zFrac >= 1.0f)
|
|
|
{
|
|
{
|
|
|
n1 = GetRawNormal((unsigned)xPos + 1, (unsigned)zPos + 1);
|
|
n1 = GetRawNormal((unsigned)xPos + 1, (unsigned)zPos + 1);
|
|
@@ -394,7 +396,7 @@ Vector3 Terrain::GetNormal(const Vector3& worldPosition) const
|
|
|
n2 = GetRawNormal((unsigned)xPos + 1, (unsigned)zPos);
|
|
n2 = GetRawNormal((unsigned)xPos + 1, (unsigned)zPos);
|
|
|
n3 = GetRawNormal((unsigned)xPos, (unsigned)zPos + 1);
|
|
n3 = GetRawNormal((unsigned)xPos, (unsigned)zPos + 1);
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
Vector3 n = (n1 * (1.0f - xFrac - zFrac) + n2 * xFrac + n3 * zFrac).Normalized();
|
|
Vector3 n = (n1 * (1.0f - xFrac - zFrac) + n2 * xFrac + n3 * zFrac).Normalized();
|
|
|
return node_->GetWorldRotation() * n;
|
|
return node_->GetWorldRotation() * n;
|
|
|
}
|
|
}
|
|
@@ -405,33 +407,33 @@ Vector3 Terrain::GetNormal(const Vector3& worldPosition) const
|
|
|
void Terrain::CreatePatchGeometry(TerrainPatch* patch)
|
|
void Terrain::CreatePatchGeometry(TerrainPatch* patch)
|
|
|
{
|
|
{
|
|
|
PROFILE(CreatePatchGeometry);
|
|
PROFILE(CreatePatchGeometry);
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
unsigned row = patchSize_ + 1;
|
|
unsigned row = patchSize_ + 1;
|
|
|
VertexBuffer* vertexBuffer = patch->GetVertexBuffer();
|
|
VertexBuffer* vertexBuffer = patch->GetVertexBuffer();
|
|
|
Geometry* geometry = patch->GetGeometry();
|
|
Geometry* geometry = patch->GetGeometry();
|
|
|
Geometry* maxLodGeometry = patch->GetMaxLodGeometry();
|
|
Geometry* maxLodGeometry = patch->GetMaxLodGeometry();
|
|
|
Geometry* minLodGeometry = patch->GetMinLodGeometry();
|
|
Geometry* minLodGeometry = patch->GetMinLodGeometry();
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
if (vertexBuffer->GetVertexCount() != row * row)
|
|
if (vertexBuffer->GetVertexCount() != row * row)
|
|
|
vertexBuffer->SetSize(row * row, MASK_POSITION | MASK_NORMAL | MASK_TEXCOORD1 | MASK_TANGENT);
|
|
vertexBuffer->SetSize(row * row, MASK_POSITION | MASK_NORMAL | MASK_TEXCOORD1 | MASK_TANGENT);
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
SharedArrayPtr<unsigned char> cpuVertexData(new unsigned char[row * row * sizeof(Vector3)]);
|
|
SharedArrayPtr<unsigned char> cpuVertexData(new unsigned char[row * row * sizeof(Vector3)]);
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
float* vertexData = (float*)vertexBuffer->Lock(0, vertexBuffer->GetVertexCount());
|
|
float* vertexData = (float*)vertexBuffer->Lock(0, vertexBuffer->GetVertexCount());
|
|
|
float* positionData = (float*)cpuVertexData.Get();
|
|
float* positionData = (float*)cpuVertexData.Get();
|
|
|
BoundingBox box;
|
|
BoundingBox box;
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
if (vertexData)
|
|
if (vertexData)
|
|
|
{
|
|
{
|
|
|
const IntVector2& coords = patch->GetCoordinates();
|
|
const IntVector2& coords = patch->GetCoordinates();
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
for (int z1 = 0; z1 <= patchSize_; ++z1)
|
|
for (int z1 = 0; z1 <= patchSize_; ++z1)
|
|
|
{
|
|
{
|
|
|
for (int x1 = 0; x1 <= patchSize_; ++x1)
|
|
for (int x1 = 0; x1 <= patchSize_; ++x1)
|
|
|
{
|
|
{
|
|
|
int xPos = coords.x_ * patchSize_ + x1;
|
|
int xPos = coords.x_ * patchSize_ + x1;
|
|
|
int zPos = coords.y_ * patchSize_ + z1;
|
|
int zPos = coords.y_ * patchSize_ + z1;
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// Position
|
|
// Position
|
|
|
Vector3 position((float)x1 * spacing_.x_, GetRawHeight(xPos, zPos), (float)z1 * spacing_.z_);
|
|
Vector3 position((float)x1 * spacing_.x_, GetRawHeight(xPos, zPos), (float)z1 * spacing_.z_);
|
|
|
*vertexData++ = position.x_;
|
|
*vertexData++ = position.x_;
|
|
@@ -440,20 +442,20 @@ void Terrain::CreatePatchGeometry(TerrainPatch* patch)
|
|
|
*positionData++ = position.x_;
|
|
*positionData++ = position.x_;
|
|
|
*positionData++ = position.y_;
|
|
*positionData++ = position.y_;
|
|
|
*positionData++ = position.z_;
|
|
*positionData++ = position.z_;
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
box.Merge(position);
|
|
box.Merge(position);
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// Normal
|
|
// Normal
|
|
|
Vector3 normal = GetRawNormal(xPos, zPos);
|
|
Vector3 normal = GetRawNormal(xPos, zPos);
|
|
|
*vertexData++ = normal.x_;
|
|
*vertexData++ = normal.x_;
|
|
|
*vertexData++ = normal.y_;
|
|
*vertexData++ = normal.y_;
|
|
|
*vertexData++ = normal.z_;
|
|
*vertexData++ = normal.z_;
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// Texture coordinate
|
|
// Texture coordinate
|
|
|
Vector2 texCoord((float)xPos / (float)numVertices_.x_, 1.0f - (float)zPos / (float)numVertices_.y_);
|
|
Vector2 texCoord((float)xPos / (float)numVertices_.x_, 1.0f - (float)zPos / (float)numVertices_.y_);
|
|
|
*vertexData++ = texCoord.x_;
|
|
*vertexData++ = texCoord.x_;
|
|
|
*vertexData++ = texCoord.y_;
|
|
*vertexData++ = texCoord.y_;
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// Tangent
|
|
// Tangent
|
|
|
Vector3 xyz = (Vector3::RIGHT - normal * normal.DotProduct(Vector3::RIGHT)).Normalized();
|
|
Vector3 xyz = (Vector3::RIGHT - normal * normal.DotProduct(Vector3::RIGHT)).Normalized();
|
|
|
*vertexData++ = xyz.x_;
|
|
*vertexData++ = xyz.x_;
|
|
@@ -462,17 +464,17 @@ void Terrain::CreatePatchGeometry(TerrainPatch* patch)
|
|
|
*vertexData++ = 1.0f;
|
|
*vertexData++ = 1.0f;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
vertexBuffer->Unlock();
|
|
vertexBuffer->Unlock();
|
|
|
vertexBuffer->ClearDataLost();
|
|
vertexBuffer->ClearDataLost();
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
patch->SetBoundingBox(box);
|
|
patch->SetBoundingBox(box);
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
if (drawRanges_.Size())
|
|
if (drawRanges_.Size())
|
|
|
{
|
|
{
|
|
|
unsigned lastDrawRange = drawRanges_.Size() - 1;
|
|
unsigned lastDrawRange = drawRanges_.Size() - 1;
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
geometry->SetIndexBuffer(indexBuffer_);
|
|
geometry->SetIndexBuffer(indexBuffer_);
|
|
|
geometry->SetDrawRange(TRIANGLE_LIST, drawRanges_[0].first_, drawRanges_[0].second_, false);
|
|
geometry->SetDrawRange(TRIANGLE_LIST, drawRanges_[0].first_, drawRanges_[0].second_, false);
|
|
|
geometry->SetRawVertexData(cpuVertexData, sizeof(Vector3), MASK_POSITION);
|
|
geometry->SetRawVertexData(cpuVertexData, sizeof(Vector3), MASK_POSITION);
|
|
@@ -483,7 +485,7 @@ void Terrain::CreatePatchGeometry(TerrainPatch* patch)
|
|
|
minLodGeometry->SetDrawRange(TRIANGLE_LIST, drawRanges_[lastDrawRange].first_, drawRanges_[lastDrawRange].second_, false);
|
|
minLodGeometry->SetDrawRange(TRIANGLE_LIST, drawRanges_[lastDrawRange].first_, drawRanges_[lastDrawRange].second_, false);
|
|
|
minLodGeometry->SetRawVertexData(cpuVertexData, sizeof(Vector3), MASK_POSITION);
|
|
minLodGeometry->SetRawVertexData(cpuVertexData, sizeof(Vector3), MASK_POSITION);
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// Offset the occlusion geometry by vertex spacing to reduce possibility of over-aggressive occlusion
|
|
// Offset the occlusion geometry by vertex spacing to reduce possibility of over-aggressive occlusion
|
|
|
patch->SetOcclusionOffset(-0.5f * (spacing_.x_ + spacing_.z_));
|
|
patch->SetOcclusionOffset(-0.5f * (spacing_.x_ + spacing_.z_));
|
|
|
patch->ResetLod();
|
|
patch->ResetLod();
|
|
@@ -492,7 +494,7 @@ void Terrain::CreatePatchGeometry(TerrainPatch* patch)
|
|
|
void Terrain::UpdatePatchLod(TerrainPatch* patch)
|
|
void Terrain::UpdatePatchLod(TerrainPatch* patch)
|
|
|
{
|
|
{
|
|
|
Geometry* geometry = patch->GetGeometry();
|
|
Geometry* geometry = patch->GetGeometry();
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// All LOD levels except the coarsest have 16 versions for stitching
|
|
// All LOD levels except the coarsest have 16 versions for stitching
|
|
|
unsigned lodLevel = patch->GetLodLevel();
|
|
unsigned lodLevel = patch->GetLodLevel();
|
|
|
unsigned drawRangeIndex = lodLevel << 4;
|
|
unsigned drawRangeIndex = lodLevel << 4;
|
|
@@ -502,7 +504,7 @@ void Terrain::UpdatePatchLod(TerrainPatch* patch)
|
|
|
TerrainPatch* south = patch->GetSouthPatch();
|
|
TerrainPatch* south = patch->GetSouthPatch();
|
|
|
TerrainPatch* west = patch->GetWestPatch();
|
|
TerrainPatch* west = patch->GetWestPatch();
|
|
|
TerrainPatch* east = patch->GetEastPatch();
|
|
TerrainPatch* east = patch->GetEastPatch();
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
if (north && north->GetLodLevel() > lodLevel)
|
|
if (north && north->GetLodLevel() > lodLevel)
|
|
|
drawRangeIndex |= STITCH_NORTH;
|
|
drawRangeIndex |= STITCH_NORTH;
|
|
|
if (south && south->GetLodLevel() > lodLevel)
|
|
if (south && south->GetLodLevel() > lodLevel)
|
|
@@ -512,7 +514,7 @@ void Terrain::UpdatePatchLod(TerrainPatch* patch)
|
|
|
if (east && east->GetLodLevel() > lodLevel)
|
|
if (east && east->GetLodLevel() > lodLevel)
|
|
|
drawRangeIndex |= STITCH_EAST;
|
|
drawRangeIndex |= STITCH_EAST;
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
if (drawRangeIndex < drawRanges_.Size())
|
|
if (drawRangeIndex < drawRanges_.Size())
|
|
|
geometry->SetDrawRange(TRIANGLE_LIST, drawRanges_[drawRangeIndex].first_, drawRanges_[drawRangeIndex].second_, false);
|
|
geometry->SetDrawRange(TRIANGLE_LIST, drawRanges_[drawRangeIndex].first_, drawRanges_[drawRangeIndex].second_, false);
|
|
|
}
|
|
}
|
|
@@ -534,7 +536,7 @@ void Terrain::SetPatchSizeAttr(int value)
|
|
|
{
|
|
{
|
|
|
if (value < MIN_PATCH_SIZE || value > MAX_PATCH_SIZE || !IsPowerOfTwo(value))
|
|
if (value < MIN_PATCH_SIZE || value > MAX_PATCH_SIZE || !IsPowerOfTwo(value))
|
|
|
return;
|
|
return;
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
if (value != patchSize_)
|
|
if (value != patchSize_)
|
|
|
{
|
|
{
|
|
|
patchSize_ = value;
|
|
patchSize_ = value;
|
|
@@ -555,14 +557,14 @@ ResourceRef Terrain::GetHeightMapAttr() const
|
|
|
void Terrain::CreateGeometry()
|
|
void Terrain::CreateGeometry()
|
|
|
{
|
|
{
|
|
|
recreateTerrain_ = false;
|
|
recreateTerrain_ = false;
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
if (!node_)
|
|
if (!node_)
|
|
|
return;
|
|
return;
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
PROFILE(CreateTerrainGeometry);
|
|
PROFILE(CreateTerrainGeometry);
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
unsigned prevNumPatches = patches_.Size();
|
|
unsigned prevNumPatches = patches_.Size();
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// Determine number of LOD levels
|
|
// Determine number of LOD levels
|
|
|
unsigned lodSize = patchSize_;
|
|
unsigned lodSize = patchSize_;
|
|
|
numLodLevels_ = 1;
|
|
numLodLevels_ = 1;
|
|
@@ -571,7 +573,7 @@ void Terrain::CreateGeometry()
|
|
|
lodSize >>= 1;
|
|
lodSize >>= 1;
|
|
|
++numLodLevels_;
|
|
++numLodLevels_;
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// Determine total terrain size
|
|
// Determine total terrain size
|
|
|
patchWorldSize_ = Vector2(spacing_.x_ * (float)patchSize_, spacing_.z_ * (float)patchSize_);
|
|
patchWorldSize_ = Vector2(spacing_.x_ * (float)patchSize_, spacing_.z_ * (float)patchSize_);
|
|
|
if (heightMap_)
|
|
if (heightMap_)
|
|
@@ -589,7 +591,7 @@ void Terrain::CreateGeometry()
|
|
|
patchWorldOrigin_ = Vector2::ZERO;
|
|
patchWorldOrigin_ = Vector2::ZERO;
|
|
|
heightData_.Reset();
|
|
heightData_.Reset();
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// Remove old patch nodes which are not needed
|
|
// Remove old patch nodes which are not needed
|
|
|
PODVector<Node*> oldPatchNodes;
|
|
PODVector<Node*> oldPatchNodes;
|
|
|
node_->GetChildrenWithComponent<TerrainPatch>(oldPatchNodes);
|
|
node_->GetChildrenWithComponent<TerrainPatch>(oldPatchNodes);
|
|
@@ -604,13 +606,13 @@ void Terrain::CreateGeometry()
|
|
|
if (x < numPatches_.x_ && z < numPatches_.y_)
|
|
if (x < numPatches_.x_ && z < numPatches_.y_)
|
|
|
nodeOk = true;
|
|
nodeOk = true;
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
if (!nodeOk)
|
|
if (!nodeOk)
|
|
|
node_->RemoveChild(*i);
|
|
node_->RemoveChild(*i);
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
patches_.Clear();
|
|
patches_.Clear();
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
if (heightMap_)
|
|
if (heightMap_)
|
|
|
{
|
|
{
|
|
|
// Copy heightmap data
|
|
// Copy heightmap data
|
|
@@ -618,7 +620,7 @@ void Terrain::CreateGeometry()
|
|
|
float* dest = heightData_;
|
|
float* dest = heightData_;
|
|
|
unsigned imgComps = heightMap_->GetComponents();
|
|
unsigned imgComps = heightMap_->GetComponents();
|
|
|
unsigned imgRow = heightMap_->GetWidth() * imgComps;
|
|
unsigned imgRow = heightMap_->GetWidth() * imgComps;
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
if (imgComps == 1)
|
|
if (imgComps == 1)
|
|
|
{
|
|
{
|
|
|
for (int z = 0; z < numVertices_.y_; ++z)
|
|
for (int z = 0; z < numVertices_.y_; ++z)
|
|
@@ -651,14 +653,14 @@ void Terrain::CreateGeometry()
|
|
|
Node* patchNode = node_->GetChild(nodeName);
|
|
Node* patchNode = node_->GetChild(nodeName);
|
|
|
if (!patchNode)
|
|
if (!patchNode)
|
|
|
patchNode = node_->CreateChild(nodeName, LOCAL);
|
|
patchNode = node_->CreateChild(nodeName, LOCAL);
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
patchNode->SetPosition(Vector3(patchWorldOrigin_.x_ + (float)x * patchWorldSize_.x_, 0.0f, patchWorldOrigin_.y_ +
|
|
patchNode->SetPosition(Vector3(patchWorldOrigin_.x_ + (float)x * patchWorldSize_.x_, 0.0f, patchWorldOrigin_.y_ +
|
|
|
(float)z * patchWorldSize_.y_));
|
|
(float)z * patchWorldSize_.y_));
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
TerrainPatch* patch = patchNode->GetOrCreateComponent<TerrainPatch>();
|
|
TerrainPatch* patch = patchNode->GetOrCreateComponent<TerrainPatch>();
|
|
|
patch->SetOwner(this);
|
|
patch->SetOwner(this);
|
|
|
patch->SetCoordinates(IntVector2(x, z));
|
|
patch->SetCoordinates(IntVector2(x, z));
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// Copy initial drawable parameters
|
|
// Copy initial drawable parameters
|
|
|
patch->SetEnabled(enabled);
|
|
patch->SetEnabled(enabled);
|
|
|
patch->SetMaterial(material_);
|
|
patch->SetMaterial(material_);
|
|
@@ -673,14 +675,14 @@ void Terrain::CreateGeometry()
|
|
|
patch->SetCastShadows(castShadows_);
|
|
patch->SetCastShadows(castShadows_);
|
|
|
patch->SetOccluder(occluder_);
|
|
patch->SetOccluder(occluder_);
|
|
|
patch->SetOccludee(occludee_);
|
|
patch->SetOccludee(occludee_);
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
patches_.Push(WeakPtr<TerrainPatch>(patch));
|
|
patches_.Push(WeakPtr<TerrainPatch>(patch));
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// Create the shared index data
|
|
// Create the shared index data
|
|
|
CreateIndexData();
|
|
CreateIndexData();
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// Create vertex data for patches
|
|
// Create vertex data for patches
|
|
|
for (Vector<WeakPtr<TerrainPatch> >::Iterator i = patches_.Begin(); i != patches_.End(); ++i)
|
|
for (Vector<WeakPtr<TerrainPatch> >::Iterator i = patches_.Begin(); i != patches_.End(); ++i)
|
|
|
{
|
|
{
|
|
@@ -689,12 +691,12 @@ void Terrain::CreateGeometry()
|
|
|
SetNeighbors(*i);
|
|
SetNeighbors(*i);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// Send event only if new geometry was generated, or the old was cleared
|
|
// Send event only if new geometry was generated, or the old was cleared
|
|
|
if (patches_.Size() || prevNumPatches)
|
|
if (patches_.Size() || prevNumPatches)
|
|
|
{
|
|
{
|
|
|
using namespace TerrainCreated;
|
|
using namespace TerrainCreated;
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
VariantMap eventData;
|
|
VariantMap eventData;
|
|
|
eventData[P_NODE] = (void*)node_;
|
|
eventData[P_NODE] = (void*)node_;
|
|
|
node_->SendEvent(E_TERRAINCREATED, eventData);
|
|
node_->SendEvent(E_TERRAINCREATED, eventData);
|
|
@@ -704,25 +706,25 @@ void Terrain::CreateGeometry()
|
|
|
void Terrain::CreateIndexData()
|
|
void Terrain::CreateIndexData()
|
|
|
{
|
|
{
|
|
|
PROFILE(CreateIndexData);
|
|
PROFILE(CreateIndexData);
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
PODVector<unsigned short> indices;
|
|
PODVector<unsigned short> indices;
|
|
|
drawRanges_.Clear();
|
|
drawRanges_.Clear();
|
|
|
unsigned row = patchSize_ + 1;
|
|
unsigned row = patchSize_ + 1;
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
for (unsigned i = 0; i < numLodLevels_; ++i)
|
|
for (unsigned i = 0; i < numLodLevels_; ++i)
|
|
|
{
|
|
{
|
|
|
unsigned combinations = (i < numLodLevels_ - 1) ? 16 : 1;
|
|
unsigned combinations = (i < numLodLevels_ - 1) ? 16 : 1;
|
|
|
int skip = 1 << i;
|
|
int skip = 1 << i;
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
for (unsigned j = 0; j < combinations; ++j)
|
|
for (unsigned j = 0; j < combinations; ++j)
|
|
|
{
|
|
{
|
|
|
unsigned indexStart = indices.Size();
|
|
unsigned indexStart = indices.Size();
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
int zStart = 0;
|
|
int zStart = 0;
|
|
|
int xStart = 0;
|
|
int xStart = 0;
|
|
|
int zEnd = patchSize_;
|
|
int zEnd = patchSize_;
|
|
|
int xEnd = patchSize_;
|
|
int xEnd = patchSize_;
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
if (j & STITCH_NORTH)
|
|
if (j & STITCH_NORTH)
|
|
|
zEnd -= skip;
|
|
zEnd -= skip;
|
|
|
if (j & STITCH_SOUTH)
|
|
if (j & STITCH_SOUTH)
|
|
@@ -731,7 +733,7 @@ void Terrain::CreateIndexData()
|
|
|
xStart += skip;
|
|
xStart += skip;
|
|
|
if (j & STITCH_EAST)
|
|
if (j & STITCH_EAST)
|
|
|
xEnd -= skip;
|
|
xEnd -= skip;
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// Build the main grid
|
|
// Build the main grid
|
|
|
for (int z = zStart; z < zEnd; z += skip)
|
|
for (int z = zStart; z < zEnd; z += skip)
|
|
|
{
|
|
{
|
|
@@ -745,7 +747,7 @@ void Terrain::CreateIndexData()
|
|
|
indices.Push(z * row + x + skip);
|
|
indices.Push(z * row + x + skip);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// Build the north edge
|
|
// Build the north edge
|
|
|
if (j & STITCH_NORTH)
|
|
if (j & STITCH_NORTH)
|
|
|
{
|
|
{
|
|
@@ -769,7 +771,7 @@ void Terrain::CreateIndexData()
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// Build the south edge
|
|
// Build the south edge
|
|
|
if (j & STITCH_SOUTH)
|
|
if (j & STITCH_SOUTH)
|
|
|
{
|
|
{
|
|
@@ -793,7 +795,7 @@ void Terrain::CreateIndexData()
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// Build the west edge
|
|
// Build the west edge
|
|
|
if (j & STITCH_WEST)
|
|
if (j & STITCH_WEST)
|
|
|
{
|
|
{
|
|
@@ -817,7 +819,7 @@ void Terrain::CreateIndexData()
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// Build the east edge
|
|
// Build the east edge
|
|
|
if (j & STITCH_EAST)
|
|
if (j & STITCH_EAST)
|
|
|
{
|
|
{
|
|
@@ -841,11 +843,11 @@ void Terrain::CreateIndexData()
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
drawRanges_.Push(MakePair(indexStart, indices.Size() - indexStart));
|
|
drawRanges_.Push(MakePair(indexStart, indices.Size() - indexStart));
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
indexBuffer_->SetSize(indices.Size(), false);
|
|
indexBuffer_->SetSize(indices.Size(), false);
|
|
|
unsigned short* indexData = (unsigned short*)indexBuffer_->Lock(0, indices.Size());
|
|
unsigned short* indexData = (unsigned short*)indexBuffer_->Lock(0, indices.Size());
|
|
|
if (indexData)
|
|
if (indexData)
|
|
@@ -859,7 +861,7 @@ float Terrain::GetRawHeight(int x, int z) const
|
|
|
{
|
|
{
|
|
|
if (!heightData_)
|
|
if (!heightData_)
|
|
|
return 0.0f;
|
|
return 0.0f;
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
x = Clamp(x, 0, numVertices_.x_ - 1);
|
|
x = Clamp(x, 0, numVertices_.x_ - 1);
|
|
|
z = Clamp(z, 0, numVertices_.y_ - 1);
|
|
z = Clamp(z, 0, numVertices_.y_ - 1);
|
|
|
return heightData_[z * numVertices_.x_ + x];
|
|
return heightData_[z * numVertices_.x_ + x];
|
|
@@ -872,7 +874,7 @@ float Terrain::GetLodHeight(int x, int z, unsigned lodLevel) const
|
|
|
float xFrac = (float)(x % offset) / divisor;
|
|
float xFrac = (float)(x % offset) / divisor;
|
|
|
float zFrac = (float)(z % offset) / divisor;
|
|
float zFrac = (float)(z % offset) / divisor;
|
|
|
float h1, h2, h3;
|
|
float h1, h2, h3;
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
if (xFrac + zFrac >= 1.0f)
|
|
if (xFrac + zFrac >= 1.0f)
|
|
|
{
|
|
{
|
|
|
h1 = GetRawHeight(x + offset, z + offset);
|
|
h1 = GetRawHeight(x + offset, z + offset);
|
|
@@ -887,7 +889,7 @@ float Terrain::GetLodHeight(int x, int z, unsigned lodLevel) const
|
|
|
h2 = GetRawHeight(x + offset, z);
|
|
h2 = GetRawHeight(x + offset, z);
|
|
|
h3 = GetRawHeight(x, z + offset);
|
|
h3 = GetRawHeight(x, z + offset);
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
return h1 * (1.0f - xFrac - zFrac) + h2 * xFrac + h3 * zFrac;
|
|
return h1 * (1.0f - xFrac - zFrac) + h2 * xFrac + h3 * zFrac;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -903,13 +905,13 @@ Vector3 Terrain::GetRawNormal(int x, int z) const
|
|
|
float wSlope = GetRawHeight(x - 1, z) - baseHeight;
|
|
float wSlope = GetRawHeight(x - 1, z) - baseHeight;
|
|
|
float nwSlope = GetRawHeight(x - 1, z - 1) - baseHeight;
|
|
float nwSlope = GetRawHeight(x - 1, z - 1) - baseHeight;
|
|
|
float up = 0.5f * (spacing_.x_ + spacing_.z_);
|
|
float up = 0.5f * (spacing_.x_ + spacing_.z_);
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
return (Vector3(0.0f, up, nSlope) +
|
|
return (Vector3(0.0f, up, nSlope) +
|
|
|
Vector3(-neSlope, up, neSlope) +
|
|
Vector3(-neSlope, up, neSlope) +
|
|
|
Vector3(-eSlope, up, 0.0f) +
|
|
Vector3(-eSlope, up, 0.0f) +
|
|
|
Vector3(-seSlope, up, -seSlope) +
|
|
Vector3(-seSlope, up, -seSlope) +
|
|
|
Vector3(0.0f, up, -sSlope) +
|
|
Vector3(0.0f, up, -sSlope) +
|
|
|
- Vector3(swSlope, up, -swSlope) +
|
|
|
|
|
|
|
+ Vector3(swSlope, up, -swSlope) +
|
|
|
Vector3(wSlope, up, 0.0f) +
|
|
Vector3(wSlope, up, 0.0f) +
|
|
|
Vector3(nwSlope, up, nwSlope)).Normalized();
|
|
Vector3(nwSlope, up, nwSlope)).Normalized();
|
|
|
}
|
|
}
|
|
@@ -917,22 +919,22 @@ Vector3 Terrain::GetRawNormal(int x, int z) const
|
|
|
void Terrain::CalculateLodErrors(TerrainPatch* patch)
|
|
void Terrain::CalculateLodErrors(TerrainPatch* patch)
|
|
|
{
|
|
{
|
|
|
PROFILE(CalculateLodErrors);
|
|
PROFILE(CalculateLodErrors);
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
const IntVector2& coords = patch->GetCoordinates();
|
|
const IntVector2& coords = patch->GetCoordinates();
|
|
|
PODVector<float>& lodErrors = patch->GetLodErrors();
|
|
PODVector<float>& lodErrors = patch->GetLodErrors();
|
|
|
lodErrors.Clear();
|
|
lodErrors.Clear();
|
|
|
lodErrors.Reserve(numLodLevels_);
|
|
lodErrors.Reserve(numLodLevels_);
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
int xStart = coords.x_ * patchSize_;
|
|
int xStart = coords.x_ * patchSize_;
|
|
|
int zStart = coords.y_ * patchSize_;
|
|
int zStart = coords.y_ * patchSize_;
|
|
|
int xEnd = xStart + patchSize_;
|
|
int xEnd = xStart + patchSize_;
|
|
|
int zEnd = zStart + patchSize_;
|
|
int zEnd = zStart + patchSize_;
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
for (unsigned i = 0; i < numLodLevels_; ++i)
|
|
for (unsigned i = 0; i < numLodLevels_; ++i)
|
|
|
{
|
|
{
|
|
|
float maxError = 0.0f;
|
|
float maxError = 0.0f;
|
|
|
int divisor = 1 << i;
|
|
int divisor = 1 << i;
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
if (i > 0)
|
|
if (i > 0)
|
|
|
{
|
|
{
|
|
|
for (int z = zStart; z <= zEnd; ++z)
|
|
for (int z = zStart; z <= zEnd; ++z)
|
|
@@ -946,11 +948,11 @@ void Terrain::CalculateLodErrors(TerrainPatch* patch)
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// Set error to be at least same as (half vertex spacing x LOD) to prevent horizontal stretches getting too inaccurate
|
|
// Set error to be at least same as (half vertex spacing x LOD) to prevent horizontal stretches getting too inaccurate
|
|
|
maxError = Max(maxError, 0.25f * (spacing_.x_ + spacing_.z_) * (float)(1 << i));
|
|
maxError = Max(maxError, 0.25f * (spacing_.x_ + spacing_.z_) * (float)(1 << i));
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
lodErrors.Push(maxError);
|
|
lodErrors.Push(maxError);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -969,20 +971,20 @@ bool Terrain::SetHeightMapInternal(Image* image, bool recreateNow)
|
|
|
LOGERROR("Can not use a compressed image as a terrain heightmap");
|
|
LOGERROR("Can not use a compressed image as a terrain heightmap");
|
|
|
return false;
|
|
return false;
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// Unsubscribe from the reload event of previous image (if any), then subscribe to the new
|
|
// Unsubscribe from the reload event of previous image (if any), then subscribe to the new
|
|
|
if (heightMap_)
|
|
if (heightMap_)
|
|
|
UnsubscribeFromEvent(heightMap_, E_RELOADFINISHED);
|
|
UnsubscribeFromEvent(heightMap_, E_RELOADFINISHED);
|
|
|
if (image)
|
|
if (image)
|
|
|
SubscribeToEvent(image, E_RELOADFINISHED, HANDLER(Terrain, HandleHeightMapReloadFinished));
|
|
SubscribeToEvent(image, E_RELOADFINISHED, HANDLER(Terrain, HandleHeightMapReloadFinished));
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
heightMap_ = image;
|
|
heightMap_ = image;
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
if (recreateNow)
|
|
if (recreateNow)
|
|
|
CreateGeometry();
|
|
CreateGeometry();
|
|
|
else
|
|
else
|
|
|
recreateTerrain_ = true;
|
|
recreateTerrain_ = true;
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
return true;
|
|
return true;
|
|
|
}
|
|
}
|
|
|
|
|
|