//---------------------------------------------------------------------------------------------------------------------------------------------------
//
// Copyright (C)2007 DarkWynter Studios. All rights reserved.
//
//---------------------------------------------------------------------------------------------------------------------------------------------------
// {Contact : darkwynter.com for licensing information
//---------------------------------------------------------------------------------------------------------------------------------------------------
namespace DarkWynter.Game.GameObjects
{
#region Using Statements
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System.Xml;
using DarkWynter.Engine.Globals;
using DarkWynter.Engine.ObjectLib;
using DarkWynter.Stream;
using DarkWynter.Engine.Init;
using DarkWynter.Engine.GameObjects;
#endregion
///
/// Basic Terrain Object
///
public class Terrain : GameObject
{
// Diffuse cofactor
private float[] materialDiffuse = { 0.5f, 0.5f, 0.5f, 1.0f };
// Specular cofactor
private float[] materialSpecular = { 0.1f, 0.1f, 0.1f, 1.0f };
///
/// Height Map of the terrain
///
public Texture2D heightMapTexture;
///
/// Normal map of the terrain
///
public Texture2D normalMapTexture;
///
/// Minimum height of the terrain (from XML)
///
public float terrainScaleMinY;
///
/// Maximum height of the terrain (from XML)
///
public float terrainScaleMaxY;
private VertexPositionNormal[] vertices;
// Terrain scaling factor
private float terrainHeightScale;
// Terrain modification distance limit
private bool terrainChanged = false;
///
/// Amount of rebound force applied by the terrain on a player falling on the terrain
///
public float playerSurfaceTension = 2000.0f;
///
/// Amount of rebound force applied by the terrain on a prop falling on the terrain
///
public float propSurfaceTension = 200.0f;
///
/// Amount of rebound force applied by the terrain on a particle falling on the terrain
///
public float particleSurfaceTension = 600.0f;
private float MaxHeight = 3;
private float MinHeight= -1.5f;
private string heightMapFile;
private string normalMapFile;
private Vector4[] normalData;
private Vector4[] heightData;
private int terrainClippingRate;
private int modelScale = 32;
private TerrainNormalStuff terrainNormalGen;
//public bool lightUpTerrainMod = true;
//public Vector3 terrainLookAtPoint = new Vector3();
//public float terrainModRange = 0;
///
/// Constructor
///
public Terrain(Load gameObjectLoader)
: base(gameObjectLoader)
{
mass.objectType = Enums_Engine.ObjectType.TERRAIN;
mass.gameObjectPointer = this;
mass.mass = 1.0f;
mass.staticFrictionCoefficient = 0.6f;
draw = new Draw();
if(Statics_Engine.TerrainSettings.terrainInstanced)
{
draw.drawMethod = Enums_Stream.DrawMethod.Terrain_Draw;
if (Statics_Engine.SystemSettings.enableTerrainBumpMapping)
{
draw.technique = "TerrainInstanced";
}
else
{
draw.technique = "TerrainNoBumpsInstanced";
}
draw.vertexDeclaration = new VertexDeclaration(Statics_Stream.RenderSettings.graphics.GraphicsDevice, draw.FBTDElements);
draw.instanceDataFBTD = new VertexFogBinormalTangentDepth[64];
draw.vertexBuffer = new VertexBuffer(Statics_Stream.RenderSettings.graphics.GraphicsDevice,
typeof(VertexFogBinormalTangentDepth),
draw.instanceDataFBTD.Length,
BufferUsage.WriteOnly);
}
else
{
draw.drawMethod = Enums_Stream.DrawMethod.BasicGameObject_Draw;
if (Statics_Engine.SystemSettings.enableTerrainBumpMapping)
{
draw.technique = "TerrainShaderMain";
}
else
{
draw.technique = "TerrainNoBumpsShaderMain";
}
}
drawAIVision = new Draw(Enums_Stream.DrawMethod.Terrain_Draw, "AI_Vision_TerrainShaderMain");
drawAIVision.vertexDeclaration = new VertexDeclaration(Statics_Stream.RenderSettings.graphics.GraphicsDevice, drawAIVision.FBTDElements);
drawAIVision.instanceDataFBTD = new VertexFogBinormalTangentDepth[64];
}
/* GameObject Interface Methods
*
*/
///
/// Load terrain info from XML
///
/// ObjectLibrary
/// True if load was successful
public override bool Load(ObjectLibrary objectLibrary)
{
this.name = load.node.Attributes["name"].Value;
// Height Map and Normal Maps
heightMapFile = load.node.Attributes["heightmap"].Value;
heightMapTexture = Statics_Engine.SystemSettings.content.Load(heightMapFile);
ShaderParameters.DrawFX.heightMapTexture.SetValue(heightMapTexture);
// Set terrain Y scaling
terrainScaleMinY = float.Parse(load.node.Attributes["terrainMinScaleY"].Value);
terrainScaleMaxY = float.Parse(load.node.Attributes["terrainMaxScaleY"].Value);
terrainScaleMinY *= heightMapTexture.Width * Statics_Engine.TerrainSettings.terrainScaleFactor;
terrainScaleMaxY *= heightMapTexture.Width * Statics_Engine.TerrainSettings.terrainScaleFactor;
ShaderParameters.DrawFX.worldMinY.SetValue(terrainScaleMinY);
ShaderParameters.DrawFX.worldMaxY.SetValue(terrainScaleMaxY);
terrainHeightScale = terrainScaleMaxY - terrainScaleMinY;
ShaderParameters.TerrainNormalFX.terrainHeightScale.SetValue(terrainHeightScale);
ShaderParameters.TerrainNormalFX.terrainScaleMinY.SetValue(terrainScaleMinY);
ShaderParameters.TerrainNormalFX.invMapWidth.SetValue(1.0f / (float)heightMapTexture.Width);
// TerrainLOD will Snap to new coordinates this many times across the map
terrainClippingRate = int.Parse(load.node.Attributes["TerrainClippingRate"].Value);
mass.dynamicFrictionCoefficient = Statics_Engine.LevelSettings.TERRAIN_FRICTION;
ShaderParameters.DrawFX.terrainScaleFactor.SetValue(Statics_Engine.TerrainSettings.terrainScaleFactor);
// Load Multi-texturing graphics
draw.textureList.Clear();
draw.textureList.Add(Statics_Engine.SystemSettings.content.Load(load.node.Attributes["textureLow"].Value));
draw.textureList.Add(Statics_Engine.SystemSettings.content.Load(load.node.Attributes["textureMid"].Value));
draw.textureList.Add(Statics_Engine.SystemSettings.content.Load(load.node.Attributes["textureHigh"].Value));
draw.textureList.Add(Statics_Engine.SystemSettings.content.Load(load.node.Attributes["textureSlope"].Value));
draw.textureList.Add(Statics_Engine.SystemSettings.content.Load(load.node.Attributes["textureBumpLow"].Value));
draw.textureList.Add(Statics_Engine.SystemSettings.content.Load(load.node.Attributes["textureBumpMid"].Value));
draw.textureList.Add(Statics_Engine.SystemSettings.content.Load(load.node.Attributes["textureBumpHigh"].Value));
draw.textureList.Add(Statics_Engine.SystemSettings.content.Load(load.node.Attributes["textureBumpSlope"].Value));
draw.textureList.Add(Statics_Engine.SystemSettings.content.Load(load.node.Attributes["textureTerrainMod"].Value));
ShaderParameters.DrawFX.terrainModTexture.SetValue(draw.textureList[8]);
// Create Terrain Mesh for TerrainLOD Algorithm
if (Statics_Engine.TerrainSettings.terrainInstanced)
{
draw.model = Statics_Engine.SystemSettings.content.Load("Content/_models/Terrain_Instanced");
}
else
{
draw.model = Statics_Engine.SystemSettings.content.Load("Content/_models/TerrainMesh2");
}
foreach (ModelMesh mesh in draw.model.Meshes)
{
for (int i = 0; i < mesh.MeshParts.Count; i++)
{
// Add effect to mesh
mesh.MeshParts[i].Effect = ShaderParameters.DrawFX.effect;
}
}
drawAIVision.model = Statics_Engine.SystemSettings.content.Load("Content/_models/Terrain_Instanced_AIVision");
foreach (ModelMesh mesh in drawAIVision.model.Meshes)
{
for (int i = 0; i < mesh.MeshParts.Count; i++)
{
// Add effect to mesh
mesh.MeshParts[i].Effect = ShaderParameters.DrawFX.effect;
}
}
// Generate Normal map and store height values
CreateTerrainNNormalMap();
return true;
}
private void CreateTerrainNNormalMap()
{
// Initialize normal map and terrain normal generator
terrainNormalGen = new TerrainNormalStuff(heightMapTexture.Width, heightMapTexture.Height);
normalMapTexture = new Texture2D(Statics_Stream.RenderSettings.graphics.GraphicsDevice,
heightMapTexture.Width,
heightMapTexture.Height,
1,
TextureUsage.None,
SurfaceFormat.Vector4);
// Set size variables
Statics_Engine.TerrainSettings.vertexMapSize = heightMapTexture.Height;
ShaderParameters.DrawFX.terrainMapSize.SetValue(Statics_Engine.TerrainSettings.vertexMapSize);
ShaderParameters.DrawFX.mapSizeXScaleFactor.SetValue(Statics_Engine.TerrainSettings.terrainScaleFactor * Statics_Engine.TerrainSettings.vertexMapSize);
Statics_Engine.TerrainSettings.collisionMapSize = Statics_Engine.TerrainSettings.vertexMapSize * Statics_Engine.TerrainSettings.terrainScaleFactor;
// Create Vertex and Collision Height Maps
float vertexHeightData;
// Set texture step
int index = 0;
float textureStep = 1.0f / (float)Statics_Engine.TerrainSettings.vertexMapSize;
// Set up color array
heightData = new Vector4[Statics_Engine.TerrainSettings.vertexMapSize * Statics_Engine.TerrainSettings.vertexMapSize];
heightMapTexture.GetData(heightData, 0, Statics_Engine.TerrainSettings.vertexMapSize * Statics_Engine.TerrainSettings.vertexMapSize);
// Call function to generate the terrain normals
terrainNormalGen.GenerateTerrainNormals(ref normalMapTexture, heightMapTexture);
normalData = new Vector4[Statics_Engine.TerrainSettings.vertexMapSize * Statics_Engine.TerrainSettings.vertexMapSize];
normalMapTexture.GetData(normalData);
// Create Vertices
vertices = new VertexPositionNormal[Statics_Engine.TerrainSettings.vertexMapSize * Statics_Engine.TerrainSettings.vertexMapSize];
for (int x = 0; x < Statics_Engine.TerrainSettings.vertexMapSize; x++)
{
for (int z = 0; z < Statics_Engine.TerrainSettings.vertexMapSize; z++)
{
vertexHeightData = ((float)heightData[index].X * terrainHeightScale) + terrainScaleMinY;
vertices[z + x * Statics_Engine.TerrainSettings.vertexMapSize].Position = new Vector3(x, vertexHeightData, z);
vertices[z + x * Statics_Engine.TerrainSettings.vertexMapSize].Normal = new Vector3(normalData[index].X,
normalData[index].Y,
normalData[index].Z);
index++;
}
}
}
///
/// Update to see if the terrain has been modified
///
/// ObjectLibrary
public override void Update(ref ObjectLibrary objectLibrary)
{
if (terrainChanged)
{
terrainChanged = false;
ShaderParameters.DrawFX.heightMapTexture.SetValue(heightMapTexture);
}
}
///
/// Draw the level selection screen in the Menu
///
public void DrawLevelSelectionScreen()
{
//------------------------------------------------------------------------------------------------
// NOTE: This will not work in it's current state... This code is old and hasn't been used in ages
//------------------------------------------------------------------------------------------------
// Set this object's global transformation matrix
Matrix matrix = Matrix.CreateScale(new Vector3(Statics_Engine.TerrainSettings.terrainScaleFactor, 1, Statics_Engine.TerrainSettings.terrainScaleFactor)) *
Matrix.CreateTranslation(new Vector3(-255.0f, 0.0f, 255.0f)) *
Matrix.CreateRotationY(-(float)Math.PI / 2.0f);
ShaderParameters.DrawFX.World.SetValue(matrix);
// Lighting
ShaderParameters.DrawFX.shininess.SetValue(7000.0f);
ShaderParameters.DrawFX.materialDiffuse.SetValue(materialDiffuse);
ShaderParameters.DrawFX.materialSpecular.SetValue(materialSpecular);
// Texture
ShaderParameters.DrawFX.modelTexture1.SetValue(draw.textureList[0]);
ShaderParameters.DrawFX.modelTexture2.SetValue(draw.textureList[1]);
ShaderParameters.DrawFX.bumpTexture1.SetValue(draw.textureList[4]);
ShaderParameters.DrawFX.bumpTexture2.SetValue(draw.textureList[5]);
ShaderParameters.DrawFX.terrainModEnabled.SetValue(false);
ShaderParameters.DrawFX.playerPosition.SetValue(Vector3.Zero);
//base.DrawTriStrips("TerrainNoBumpsShaderMain");
}
///
/// General draw function
///
public override Draw Draw()
{
if (Statics_Engine.TerrainSettings.terrainInstanced)
{
return DrawInstanced();
}
else
{
return DrawSimple();
}
}
private Draw DrawSimple()
{
// Snap grid to nearest 32 boundary
int snapX = (int)((Statics_Engine.PlayerSettings.playerPosition.X / Statics_Engine.TerrainSettings.terrainScaleFactor - 255.0f) / 4.0f);
int snapZ = (int)((Statics_Engine.PlayerSettings.playerPosition.Z / Statics_Engine.TerrainSettings.terrainScaleFactor - 255.0f) / 4.0f);
snapX *= 4;
snapZ *= 4;
// Set this object's global transformation matrix
draw.matrix = Matrix.CreateRotationY(-(float)Math.PI / 2.0f) *
Matrix.CreateTranslation(new Vector3(snapX, 0.0f, snapZ)) *
Matrix.CreateScale(new Vector3(Statics_Engine.TerrainSettings.terrainScaleFactor, 1.0f, Statics_Engine.TerrainSettings.terrainScaleFactor));
// Lighting
ShaderParameters.DrawFX.shininess.SetValue(7000.0f);
ShaderParameters.DrawFX.materialDiffuse.SetValue(materialDiffuse);
ShaderParameters.DrawFX.materialSpecular.SetValue(materialSpecular);
// Texture
ShaderParameters.DrawFX.modelTexture1.SetValue(draw.textureList[0]);
ShaderParameters.DrawFX.modelTexture2.SetValue(draw.textureList[1]);
ShaderParameters.DrawFX.modelTexture3.SetValue(draw.textureList[2]);
ShaderParameters.DrawFX.modelTexture4.SetValue(draw.textureList[3]);
ShaderParameters.DrawFX.bumpTexture1.SetValue(draw.textureList[4]);
ShaderParameters.DrawFX.bumpTexture2.SetValue(draw.textureList[5]);
ShaderParameters.DrawFX.bumpTexture3.SetValue(draw.textureList[6]);
ShaderParameters.DrawFX.bumpTexture4.SetValue(draw.textureList[7]);
ShaderParameters.DrawFX.terrainModEnabled.SetValue(Statics_Engine.TerrainSettings.terrainModEnabled);
ShaderParameters.DrawFX.PlaneRayIntersectionPoint.SetValue(Statics_Engine.TerrainSettings.terrainLookAtPoint);
ShaderParameters.DrawFX.TerrainModRange.SetValue((Statics_Engine.TerrainSettings.terrainModRange + 1) * Statics_Engine.TerrainSettings.terrainScaleFactor);
return draw;
}
private Draw DrawInstanced()
{
// Tile the terrain map around the player's current position
TileMap(Statics_Engine.PlayerSettings.playerPosition);
// Lighting
ShaderParameters.DrawFX.shininess.SetValue(7000.0f);
ShaderParameters.DrawFX.materialDiffuse.SetValue(materialDiffuse);
ShaderParameters.DrawFX.materialSpecular.SetValue(materialSpecular);
// Texture
ShaderParameters.DrawFX.modelTexture1.SetValue(draw.textureList[0]);
ShaderParameters.DrawFX.modelTexture2.SetValue(draw.textureList[1]);
ShaderParameters.DrawFX.modelTexture3.SetValue(draw.textureList[2]);
ShaderParameters.DrawFX.modelTexture4.SetValue(draw.textureList[3]);
ShaderParameters.DrawFX.bumpTexture1.SetValue(draw.textureList[4]);
ShaderParameters.DrawFX.bumpTexture2.SetValue(draw.textureList[5]);
ShaderParameters.DrawFX.bumpTexture3.SetValue(draw.textureList[6]);
ShaderParameters.DrawFX.bumpTexture4.SetValue(draw.textureList[7]);
ShaderParameters.DrawFX.terrainModEnabled.SetValue(Statics_Engine.TerrainSettings.terrainModEnabled);
ShaderParameters.DrawFX.PlaneRayIntersectionPoint.SetValue(Statics_Engine.TerrainSettings.terrainLookAtPoint);
ShaderParameters.DrawFX.TerrainModRange.SetValue((Statics_Engine.TerrainSettings.terrainModRange + 1) * Statics_Engine.TerrainSettings.terrainScaleFactor);
//draw.DoDraw();
return draw;
}
///
/// Draw function for AI-Vision
///
/// Current AI's position
public void DrawAIVision(Vector3 currentAIPosition)
{
GraphicsDevice gd = Statics_Stream.RenderSettings.graphics.GraphicsDevice;
// Tile the terrain map around the ai's current position
TileMap(currentAIPosition);
//drawAIVision.DoDraw();
}
private void TileMap(Vector3 playerPosition)
{
// Snap grid to nearest Clip boundary, relative to the player's location in vertexMapSpace
int snapX = (int)((playerPosition.X / Statics_Engine.TerrainSettings.terrainScaleFactor - Statics_Engine.TerrainSettings.vertexMapSize)
/ terrainClippingRate);
int snapZ = (int)((playerPosition.Z / Statics_Engine.TerrainSettings.terrainScaleFactor - Statics_Engine.TerrainSettings.vertexMapSize)
/ terrainClippingRate);
float ratio = (float)Statics_Engine.TerrainSettings.terrainScaleFactor / modelScale;
// Scale back to collisionMapSize, having rounded off the Clip amount
snapX *= terrainClippingRate;
snapZ *= terrainClippingRate;
// Set this object's World transformation matrix
Matrix matrix;
int coverEntireMap = Statics_Engine.TerrainSettings.vertexMapSize / modelScale;
int start = coverEntireMap - 4;
int end = coverEntireMap + 4;
int index = 0;
for (int x = start; x < end; x++)
{
int xPos = (x * modelScale) + snapX;
for (int z = start; z < end; z++)
{
int zPos = (z * modelScale) + snapZ;
matrix = Matrix.CreateTranslation(new Vector3(xPos, 0.0f, zPos)) *
Matrix.CreateScale(new Vector3(modelScale * ratio, 1.0f, modelScale * ratio));
draw.instanceDataFBTD[index].Fog = new Vector4(matrix.M11, matrix.M12, matrix.M13, matrix.M14);
draw.instanceDataFBTD[index].Binormal = new Vector4(matrix.M21, matrix.M22, matrix.M23, matrix.M24);
draw.instanceDataFBTD[index].Tangent = new Vector4(matrix.M31, matrix.M32, matrix.M33, matrix.M34);
draw.instanceDataFBTD[index].Depth = new Vector4(matrix.M41, matrix.M42, matrix.M43, matrix.M44);
index++;
}
}
}
///
/// Procedurally let the user modify the terrain height values
///
/// Amount by which to modify the terrain
/// Target point on the terrain
/// Radius of modification
public void ModifyTerrain(float modFactor, Vector3 lookAtPoint, int manhattanRadius, Enums_Engine.TerrainModType type)
{
int minX = (int)lookAtPoint.X - manhattanRadius;
int maxX = (int)lookAtPoint.X + manhattanRadius;
int minZ = (int)lookAtPoint.Z - manhattanRadius;
int maxZ = (int)lookAtPoint.Z + manhattanRadius;
if (maxX >= Statics_Engine.TerrainSettings.vertexMapSize)
{
maxX = Statics_Engine.TerrainSettings.vertexMapSize - 2;
}
if (minX < 0)
{
minX = 0;
}
if (maxZ >= Statics_Engine.TerrainSettings.vertexMapSize)
{
maxZ = Statics_Engine.TerrainSettings.vertexMapSize - 2;
}
if (minZ < 0)
{
minZ = 0;
}
Rectangle heightRect = new Rectangle(minZ, minX, maxZ - minZ + 1, maxX - minX + 1);
List newHeightList = new List();
// The Tip
for (int x = minX; x <= maxX; x++)
{
for (int z = minZ; z <= maxZ; z++)
{
if (x == minX || x == maxX - 1 || z == minZ || z == maxZ - 1)
{
vertices[z + x * Statics_Engine.TerrainSettings.vertexMapSize].Normal = new Vector3();
}
if (type == Enums_Engine.TerrainModType.ADDITIVE)
{
heightData[z + x * Statics_Engine.TerrainSettings.vertexMapSize] += new Vector4(modFactor / 25.5f);
}
if (type == Enums_Engine.TerrainModType.EQUALTO)
{
heightData[z + x * Statics_Engine.TerrainSettings.vertexMapSize] = new Vector4(modFactor / 25.5f);
}
// Clamp height values so they don't exceed range..
if (heightData[z + x * Statics_Engine.TerrainSettings.vertexMapSize].X > 3.0f)
{
heightData[z + x * Statics_Engine.TerrainSettings.vertexMapSize].X = 3.0f;
}
if (heightData[z + x * Statics_Engine.TerrainSettings.vertexMapSize].Y > 3.0f)
{
heightData[z + x * Statics_Engine.TerrainSettings.vertexMapSize].Y = 3.0f;
}
if (heightData[z + x * Statics_Engine.TerrainSettings.vertexMapSize].Z > 3.0f)
{
heightData[z + x * Statics_Engine.TerrainSettings.vertexMapSize].Z = 3.0f;
}
if (heightData[z + x * Statics_Engine.TerrainSettings.vertexMapSize].W > 3.0f)
{
heightData[z + x * Statics_Engine.TerrainSettings.vertexMapSize].W = 3.0f;
}
newHeightList.Add(heightData[z + x * Statics_Engine.TerrainSettings.vertexMapSize]);
vertices[(z + 1) + x * Statics_Engine.TerrainSettings.vertexMapSize].Position.Y =
(newHeightList[newHeightList.Count - 1].X * terrainHeightScale) + terrainScaleMinY;
}
}
if (newHeightList.Count > 0)
{
// Set new data
Vector4[] newHeightData = new Vector4[newHeightList.Count];
newHeightList.CopyTo(newHeightData);
newHeightList.Clear();
try
{
heightMapTexture.SetData(0, heightRect, newHeightData, 0, newHeightData.Length, SetDataOptions.Discard);
}
catch (Exception e)
{
//Console.Write(e.ToString());
}
}
// Get grid round point to adjust normals
minX -= 1;
maxX += 1;
minZ -= 1;
maxZ += 1;
// Check grid bounds
if (maxX >= Statics_Engine.TerrainSettings.vertexMapSize)
{
maxX = Statics_Engine.TerrainSettings.vertexMapSize - 2;
}
if (minX < 0)
{
minX = 0;
}
if (maxZ >= Statics_Engine.TerrainSettings.vertexMapSize)
{
maxZ = Statics_Engine.TerrainSettings.vertexMapSize - 2;
}
if (minZ < 0)
{
minZ = 0;
}
// Calculate normal
Vector3 edge1, edge2, normal;
for (int x = minX; x < maxX; x++)
{
for (int z = minZ; z < maxZ; z++)
{
if (x == minX || x == maxX - 1 || z == minZ || z == maxZ - 1)
{
edge1 = vertices[(z + 1) + x * Statics_Engine.TerrainSettings.vertexMapSize].Position -
vertices[z + x * Statics_Engine.TerrainSettings.vertexMapSize].Position;
edge2 = vertices[z + x * Statics_Engine.TerrainSettings.vertexMapSize].Position -
vertices[(z + 1) + (x + 1) * Statics_Engine.TerrainSettings.vertexMapSize].Position;
normal = Vector3.Cross(edge2, edge1); // normal = Vector3.Cross(edge1, edge2); --> To play the NAN-mine game:-)
normal.Normalize();
vertices[z + x * Statics_Engine.TerrainSettings.vertexMapSize].Normal += normal;
vertices[(z + 1) + x * Statics_Engine.TerrainSettings.vertexMapSize].Normal += normal;
vertices[(z + 1) + (x + 1) * Statics_Engine.TerrainSettings.vertexMapSize].Normal += normal;
edge1 = vertices[z + x * Statics_Engine.TerrainSettings.vertexMapSize].Position -
vertices[z + (x + 1) * Statics_Engine.TerrainSettings.vertexMapSize].Position;
edge2 = vertices[z + (x + 1) * Statics_Engine.TerrainSettings.vertexMapSize].Position -
vertices[(z + 1) + (x + 1) * Statics_Engine.TerrainSettings.vertexMapSize].Position;
normal = Vector3.Cross(edge2, edge1); // normal = Vector3.Cross(edge1, edge2); --> To play the NAN-mine game:-)
normal.Normalize();
vertices[z + (x + 1) * Statics_Engine.TerrainSettings.vertexMapSize].Normal += normal;
vertices[z + x * Statics_Engine.TerrainSettings.vertexMapSize].Normal += normal;
vertices[(z + 1) + (x + 1) * Statics_Engine.TerrainSettings.vertexMapSize].Normal += normal;
}
}
}
// Normalize
for (int x = minX; x <= maxX; x++)
{
for (int z = minZ; z <= maxZ; z++)
{
if (x == minX || x == maxX - 1 || z == minZ || z == maxZ - 1)
{
vertices[z + x * Statics_Engine.TerrainSettings.vertexMapSize].Normal.Normalize();
}
}
}
//Rectangle normalRect = new Rectangle(minX, minZ, maxX - minX + 1, maxZ - minZ + 1);
//normalMapTexture.SetData(0, normalRect, normalData, 0, normalData.Length, SetDataOptions.Discard);
terrainChanged = true;
}
///
/// Returns the normal of the terrain between point (x, z) and the next point that the object is going to land on
/// based on the velocity
///
/// X
/// Z
/// Object's velocity
/// Normal of the terrain
public Vector3 GetTerrainNormal(float x, float z, Vector3 velocity)
{
int floorX = (int)x;
int floorZ = (int)z;
int ceilX = 0;
int ceilZ = 0;
velocity.Normalize();
if (velocity.X < 0)
{
if (x > 0)
{
floorX = (int)(x - 1);
}
else
{
floorX = 0;
}
if (x < Statics_Engine.TerrainSettings.vertexMapSize - 1)
{
ceilX = (int)(x + 1);
}
else
{
ceilX = Statics_Engine.TerrainSettings.vertexMapSize - 1;
}
}
else //other way
{
if (x < Statics_Engine.TerrainSettings.vertexMapSize - 1)
{
floorX = (int)(x + 1);
}
else
{
floorX = Statics_Engine.TerrainSettings.vertexMapSize - 1;
}
if (x > 0)
{
ceilX = (int)(x - 1);
}
else
{
ceilX = 0;
}
}
if (velocity.Z < 0)
{
if (z > 0)
{
floorZ = (int)(z - 1);
}
else
{
floorZ = 0;
}
if (z < Statics_Engine.TerrainSettings.vertexMapSize - 1)
{
ceilZ = (int)(z + 1);
}
else
{
ceilZ = Statics_Engine.TerrainSettings.vertexMapSize - 1;
}
}
else //other way
{
if (z < Statics_Engine.TerrainSettings.vertexMapSize - 1)
{
floorZ = (int)(z + 1);
}
else
{
floorZ = Statics_Engine.TerrainSettings.vertexMapSize - 1;
}
if (z > 0)
{
ceilZ = (int)(z - 1);
}
else
{
ceilZ = 0;
}
}
Vector3 A = new Vector3(floorX, GetTerrainHeight(floorX, floorZ), floorZ);
Vector3 B = new Vector3(ceilX, GetTerrainHeight(ceilX, ceilZ), ceilZ);
Vector3 C;
if (GetTerrainHeight(floorX, ceilZ) > GetTerrainHeight(ceilX, floorZ))
{
C = new Vector3(floorX, GetTerrainHeight(floorX, ceilZ), ceilZ);
}
else
{
C = new Vector3(ceilX, GetTerrainHeight(ceilX, floorZ), floorZ);
}
Vector3 vec1 = B - A;
Vector3 vec2 = C - A;
Vector3 result = Vector3.Cross(vec1, vec2);
result.Normalize();
if (float.IsNaN(result.X) || float.IsNaN(result.Y) || float.IsNaN(result.Z))
{
result = Vector3.Zero;
}
if (result.Y < 0)
{
//can never be pointing down!!!!
result = -result;
}
return result;
}
///
/// Returns the height of the terrain at a particular x, z point
///
/// X
/// Z
/// Height of the terrain
public float GetTerrainHeight(float x, float z)
{
int floorX = (int)x;
int floorZ = (int)z;
int ceilX = Statics_Engine.TerrainSettings.vertexMapSize - 1;
int ceilZ = Statics_Engine.TerrainSettings.vertexMapSize - 1;
// Check if X is less than our map size
if (x < ceilX)
{
ceilX = (int)(x + 1);
}
// Check if Z is less than our map size
if (z < ceilZ)
{
ceilZ = (int)(z + 1);
}
// Get the fractional components
float fracX = x - (float)floorX;
float fracZ = z - (float)floorZ;
// Get height value using X to lerp
float lerpX = MathHelper.Lerp(heightData[floorZ + floorX * Statics_Engine.TerrainSettings.vertexMapSize].X,
heightData[ceilZ + ceilX * Statics_Engine.TerrainSettings.vertexMapSize].X,
fracX);
// Get height value using Z to lerp
float lerpZ = MathHelper.Lerp(heightData[floorZ + floorX * Statics_Engine.TerrainSettings.vertexMapSize].X,
heightData[ceilZ + ceilX * Statics_Engine.TerrainSettings.vertexMapSize].X,
fracZ);
float diff;
// Get the difference between the two fractions
float diffXZ = (x - (float)floorX) - (z - (float)floorZ);
if (diffXZ > 0)
{
// X fraction is greater
diff = 1 - diffXZ;
}
else if (diffXZ < 0)
{
// Z fraction is greater
diff = 1 + diffXZ;
}
else
{
// They are equal
diff = 0.5f;
}
return (MathHelper.Lerp(lerpX, lerpZ, diff) * terrainHeightScale) + terrainScaleMinY;
}
}
}
// ======================= OLD TERRAIN CODE =======================
/*
private void CreateTerrainNNormalMap()
{
normalMapTexture = new Texture2D(Statics_Stream.RenderSettings.graphics.GraphicsDevice,
heightMapTexture.Width,
heightMapTexture.Height,
0,
TextureUsage.AutoGenerateMipMap,
SurfaceFormat.Vector4);
// Set size variables
Statics_Engine.TerrainSettings.vertexMapSize = heightMapTexture.Height;
ShaderParameters.DrawFX.terrainMapSize.SetValue(Statics_Engine.TerrainSettings.vertexMapSize);
ShaderParameters.DrawFX.mapSizeXScaleFactor.SetValue(Statics_Engine.TerrainSettings.terrainScaleFactor * Statics_Engine.TerrainSettings.vertexMapSize);
Statics_Engine.TerrainSettings.collisionMapSize = Statics_Engine.TerrainSettings.vertexMapSize * Statics_Engine.TerrainSettings.terrainScaleFactor;
// Create Vertex and Collision Height Maps
vertexHeightData = null;
vertexHeightData = new float[Statics_Engine.TerrainSettings.vertexMapSize, Statics_Engine.TerrainSettings.vertexMapSize];
GC.Collect();
// Set texture step
int index = 0;
float textureStep = 1.0f / (float)Statics_Engine.TerrainSettings.vertexMapSize;
// Set up color array
heightData = new Vector4[Statics_Engine.TerrainSettings.vertexMapSize * Statics_Engine.TerrainSettings.vertexMapSize];
heightMapTexture.GetData(heightData, 0, Statics_Engine.TerrainSettings.vertexMapSize * Statics_Engine.TerrainSettings.vertexMapSize);
normalData = new Vector4[Statics_Engine.TerrainSettings.vertexMapSize * Statics_Engine.TerrainSettings.vertexMapSize];
// Create Vertices
vertices = new VertexPositionNormalTexture[Statics_Engine.TerrainSettings.vertexMapSize * Statics_Engine.TerrainSettings.vertexMapSize];
for (int x = 0; x < Statics_Engine.TerrainSettings.vertexMapSize; x++)
{
for (int z = 0; z < Statics_Engine.TerrainSettings.vertexMapSize; z++)
{
vertexHeightData[x, z] = ((float)heightData[index].X * terrainHeightScale) + terrainScaleMinY;
vertices[z + x * Statics_Engine.TerrainSettings.vertexMapSize].Position = new Vector3(x, vertexHeightData[x, z], z);
index++;
}
}
Vector3 normal = new Vector3();
Vector3 edge1 = new Vector3();
Vector3 edge2 = new Vector3();
// Stitch the verteces together into triangles. Two triangles per square
for (int x = 0; x < Statics_Engine.TerrainSettings.vertexMapSize - 1; x++)
{
for (int z = 0; z < Statics_Engine.TerrainSettings.vertexMapSize - 1; z++)
{
edge1 = vertices[(z + 1) + x * Statics_Engine.TerrainSettings.vertexMapSize].Position -
vertices[z + x * Statics_Engine.TerrainSettings.vertexMapSize].Position;
edge2 = vertices[z + x * Statics_Engine.TerrainSettings.vertexMapSize].Position -
vertices[(z + 1) + (x + 1) * Statics_Engine.TerrainSettings.vertexMapSize].Position;
normal = Vector3.Cross(edge2, edge1);
normal.Normalize();
vertices[z + x * Statics_Engine.TerrainSettings.vertexMapSize].Normal += normal;
vertices[(z + 1) + x * Statics_Engine.TerrainSettings.vertexMapSize].Normal += normal;
vertices[(z + 1) + (x + 1) * Statics_Engine.TerrainSettings.vertexMapSize].Normal += normal;
edge1 = vertices[z + x * Statics_Engine.TerrainSettings.vertexMapSize].Position -
vertices[z + (x + 1) * Statics_Engine.TerrainSettings.vertexMapSize].Position;
edge2 = vertices[z + (x + 1) * Statics_Engine.TerrainSettings.vertexMapSize].Position -
vertices[(z + 1) + (x + 1) * Statics_Engine.TerrainSettings.vertexMapSize].Position;
normal = Vector3.Cross(edge2, edge1);
normal.Normalize();
vertices[z + (x + 1) * Statics_Engine.TerrainSettings.vertexMapSize].Normal += normal;
vertices[z + x * Statics_Engine.TerrainSettings.vertexMapSize].Normal += normal;
vertices[(z + 1) + (x + 1) * Statics_Engine.TerrainSettings.vertexMapSize].Normal += normal;
}
}
// Normalize vertex normals
for (int i = 0; i < Statics_Engine.TerrainSettings.vertexMapSize * Statics_Engine.TerrainSettings.vertexMapSize; i++)
{
vertices[i].Normal.Normalize();
normalData[i] = new Vector4(vertices[i].Normal, 1.0f);
}
// Set the data
normalMapTexture.SetData(normalData);
normalMapTexture.Save("terrainNormalMap.dds", ImageFileFormat.Dds);
}
private void CreateTerrain()
{
// Set size variables
Statics_Engine.TerrainSettings.vertexMapSize = heightMapTexture.Height;
ShaderParameters.DrawFX.terrainMapSize.SetValue(Statics_Engine.TerrainSettings.vertexMapSize);
ShaderParameters.DrawFX.mapSizeXScaleFactor.SetValue(Statics_Engine.TerrainSettings.terrainScaleFactor * Statics_Engine.TerrainSettings.vertexMapSize);
Statics_Engine.TerrainSettings.collisionMapSize = Statics_Engine.TerrainSettings.vertexMapSize * Statics_Engine.TerrainSettings.terrainScaleFactor;
// Create Vertex and Collision Height Maps
float vertexHeightData;
// Set texture step
int index = 0;
float textureStep = 1.0f / (float)Statics_Engine.TerrainSettings.vertexMapSize;
// Set up color array
heightData = new Vector4[Statics_Engine.TerrainSettings.vertexMapSize * Statics_Engine.TerrainSettings.vertexMapSize];
heightMapTexture.GetData(heightData, 0, Statics_Engine.TerrainSettings.vertexMapSize * Statics_Engine.TerrainSettings.vertexMapSize);
normalData = new Vector4[Statics_Engine.TerrainSettings.vertexMapSize * Statics_Engine.TerrainSettings.vertexMapSize];
normalMapTexture.GetData(normalData, 0, Statics_Engine.TerrainSettings.vertexMapSize * Statics_Engine.TerrainSettings.vertexMapSize);
// Create Vertices
vertices = new VertexPositionNormalTexture[Statics_Engine.TerrainSettings.vertexMapSize * Statics_Engine.TerrainSettings.vertexMapSize];
for (int x = 0; x < Statics_Engine.TerrainSettings.vertexMapSize; x++)
{
for (int z = 0; z < Statics_Engine.TerrainSettings.vertexMapSize; z++)
{
vertexHeightData = ((float)heightData[index].X * terrainHeightScale) + terrainScaleMinY;
vertices[z + x * Statics_Engine.TerrainSettings.vertexMapSize].Position = new Vector3(x, vertexHeightData, z);
vertices[z + x * Statics_Engine.TerrainSettings.vertexMapSize].Normal = Vector3.Normalize(new Vector3(normalData[index].X,
normalData[index].Y,
normalData[index].Z));
index++;
}
}
}
public void DrawRotated(ModelManager modelManager, string technique)
{
// Snap grid to nearest Clip boundary, relative to the player's location in vertexMapSpace
int snapX = (int)((Statics.PlayerSettings.playerPosition.X / Statics.TerrainSettings.terrainScaleFactor - Statics.TerrainSettings.vertexMapSize) / TerrainClippingRate);
int snapZ = (int)((Statics.PlayerSettings.playerPosition.Y / Statics.TerrainSettings.terrainScaleFactor - Statics.TerrainSettings.vertexMapSize) / TerrainClippingRate);
// Scale back to collisionMapSize, having rounded off the Clip amount
snapX *= TerrainClippingRate;
snapZ *= TerrainClippingRate;
float xRot, zRot;
Vector3 xVector = new Vector3(Statics.PlayerSettings.playerLookVector.X, 0.0f, 0.0f);
Vector3 zVector = new Vector3(0.0f, 0.0f, Statics.PlayerSettings.playerLookVector.Y);
xRot = (float)Math.Acos(Vector3.Dot(xVector, Vector3.UnitX) / (xVector.Length() * Vector3.UnitX.Length()));
if (float.IsNaN(xRot))
{
xRot = 0.0f;
}
zRot = (float)Math.Acos(Vector3.Dot(zVector, Vector3.UnitZ) / (zVector.Length() * Vector3.UnitZ.Length()));
if (float.IsNaN(zRot))
{
zRot = 0.0f;
}
// Set this object's global transformation matrix
Matrix matrix = Matrix.CreateTranslation(new Vector3(snapX, 0.0f, snapZ)) *
Matrix.CreateScale(new Vector3(Statics.TerrainSettings.terrainScaleFactor, 1.0f, Statics.TerrainSettings.terrainScaleFactor));
//*
//Matrix.CreateRotationX(xRot) *
//Matrix.CreateRotationZ(zRot);
// Set light shading parameters
ShaderParameters.DrawFX.World.SetValue(matrix);
// Lighting
ShaderParameters.DrawFX.shininess.SetValue(7000.0f);
ShaderParameters.DrawFX.materialDiffuse.SetValue(materialDiffuse);
ShaderParameters.DrawFX.materialSpecular.SetValue(materialSpecular);
// Texture
ShaderParameters.DrawFX.modelTexture1.SetValue(textureList[0]);
ShaderParameters.DrawFX.modelTexture2.SetValue(textureList[1]);
ShaderParameters.DrawFX.bumpTexture1.SetValue(textureList[4]);
ShaderParameters.DrawFX.bumpTexture2.SetValue(textureList[5]);
ShaderParameters.DrawFX.modelTexture3.SetValue(textureList[2]);
ShaderParameters.DrawFX.modelTexture4.SetValue(textureList[3]);
ShaderParameters.DrawFX.bumpTexture3.SetValue(textureList[6]);
ShaderParameters.DrawFX.bumpTexture4.SetValue(textureList[7]);
ShaderParameters.DrawFX.terrainModEnabled.SetValue(Statics.TerrainSettings.terrainModEnabled);
ShaderParameters.PlaneRayIntersectionPoint.SetValue(Statics.TerrainSettings.terrainLookAtPoint);
ShaderParameters.TerrainModRange.SetValue((Statics.TerrainSettings.terrainModRange + 1) * Statics.TerrainSettings.terrainScaleFactor);
ShaderParameters.DrawFX.playerPosition.SetValue(Statics.PlayerSettings.playerPosition);
if (Statics.SystemSettings.enableTerrainBumpMapping)
{
base.DrawTriStrips(model, "TerrainShaderMain");
}
else
{
base.DrawTriStrips(model, "TerrainNoBumpsShaderMain");
}
}
public void OldDraw(ModelManager modelManager, string technique)
{
// Snap grid to nearest Clip boundary, relative to the player's location in vertexMapSpace
int snapX = (int)((Statics.PlayerSettings.playerPosition.X / Statics.TerrainSettings.terrainScaleFactor - Statics.TerrainSettings.vertexMapSize) / TerrainClippingRate);
int snapZ = (int)((Statics.PlayerSettings.playerPosition.Y / Statics.TerrainSettings.terrainScaleFactor - Statics.TerrainSettings.vertexMapSize) / TerrainClippingRate);
// Scale back to collisionMapSize, having rounded off the Clip amount
snapX *= TerrainClippingRate;
snapZ *= TerrainClippingRate;
// Set this object's global transformation matrix
Matrix matrix = Matrix.CreateRotationY(-(float)Math.PI / 2.0f) *
Matrix.CreateTranslation(new Vector3(snapX, 0.0f, snapZ)) *
Matrix.CreateScale(new Vector3(Statics.TerrainSettings.terrainScaleFactor, 1.0f, Statics.TerrainSettings.terrainScaleFactor));
// Set light shading parameters
ShaderParameters.DrawFX.World.SetValue(matrix);
// Lighting
ShaderParameters.DrawFX.shininess.SetValue(7000.0f);
ShaderParameters.DrawFX.materialDiffuse.SetValue(materialDiffuse);
ShaderParameters.DrawFX.materialSpecular.SetValue(materialSpecular);
// Texture
ShaderParameters.DrawFX.modelTexture1.SetValue(textureList[0]);
ShaderParameters.DrawFX.modelTexture2.SetValue(textureList[1]);
ShaderParameters.DrawFX.bumpTexture1.SetValue(textureList[4]);
ShaderParameters.DrawFX.bumpTexture2.SetValue(textureList[5]);
ShaderParameters.DrawFX.modelTexture3.SetValue(textureList[2]);
ShaderParameters.DrawFX.modelTexture4.SetValue(textureList[3]);
ShaderParameters.DrawFX.bumpTexture3.SetValue(textureList[6]);
ShaderParameters.DrawFX.bumpTexture4.SetValue(textureList[7]);
ShaderParameters.DrawFX.terrainModEnabled.SetValue(Statics.TerrainSettings.terrainModEnabled);
ShaderParameters.PlaneRayIntersectionPoint.SetValue(Statics.TerrainSettings.terrainLookAtPoint);
ShaderParameters.TerrainModRange.SetValue((Statics.TerrainSettings.terrainModRange + 1) * Statics.TerrainSettings.terrainScaleFactor);
ShaderParameters.DrawFX.playerPosition.SetValue(Statics.PlayerSettings.playerPosition );
base.DrawTriStrips(model, technique);
}
// Procedurally generate terrain from heightmap and scale
private void CreateTerrain_CPU(GraphicsDeviceManager graphics)
{
// Set size variables
vertexMapSize = heightMapTexture.Height;
collisionMapSize = vertexMapSize * terrainScaleFactor;
// Create Vertex and Collision Height Maps
vertexHeightData = new float[vertexMapSize, vertexMapSize];
collisionHeightData = new float[collisionMapSize, collisionMapSize];
// Set texture step
int index = 0;
float textureStep = 1.0f / (float)vertexMapSize;
// Set up color array
Color[] data = new Color[vertexMapSize * vertexMapSize];
heightMapTexture.GetData(data);
// Create Vertex Declaration and Buffer
vertexDeclaration = new VertexDeclaration(graphics.GraphicsDevice,
VertexPositionNormalTexture.VertexElements);
vertexBuffer = new VertexBuffer(graphics.GraphicsDevice,
VertexPositionNormalTexture.SizeInBytes * vertexMapSize * vertexMapSize,
ResourceUsage.Dynamic,
ResourceManagementMode.Manual);
// Create Vertecies
vertices = new VertexPositionNormalTexture[vertexMapSize * vertexMapSize];
for (int x = 0; x < vertexMapSize; x++)
{
for (int z = 0; z < vertexMapSize; z++)
{
vertexHeightData[x, z] = (float)data[index].R * terrainHeightScale;
vertices[z + x * vertexMapSize].Position = new Vector3(x, vertexHeightData[x, z], z);
vertices[z + x * vertexMapSize].Normal = new Vector3(0, 0, 0);
vertices[z + x * vertexMapSize].TextureCoordinate = new Vector2(x * textureStep, z * textureStep);
index++;
// Fill collision array with known height values from vertices
collisionHeightData[x * terrainScaleFactor, z * terrainScaleFactor] = vertexHeightData[x, z];
}
}
// Holds the order in which triangles are created from vertex buffer
meshIndexBuffer = new IndexBuffer(graphics.GraphicsDevice,
sizeof(int) * ((vertexMapSize - 1) * (vertexMapSize - 1) * 6),
ResourceUsage.Dynamic,
ResourceManagementMode.Manual,
IndexElementSize.ThirtyTwoBits);
meshIndices = new int[(vertexMapSize - 1) * (vertexMapSize - 1) * 6];
Vector3 normal = new Vector3();
Vector3 edge1 = new Vector3();
Vector3 edge2 = new Vector3();
// Stitch the verteces together into triangles. Two triangles per square
for (int x = 0; x < vertexMapSize - 1; x++)
{
for (int z = 0; z < vertexMapSize - 1; z++)
{
meshIndices[(z + x * (vertexMapSize - 1)) * 6] = (z + x * vertexMapSize);
meshIndices[(z + x * (vertexMapSize - 1)) * 6 + 1] = ((z + 1) + x * vertexMapSize);
meshIndices[(z + x * (vertexMapSize - 1)) * 6 + 2] = ((z + 1) + (x + 1) * vertexMapSize);
edge1 = vertices[(z + 1) + x * vertexMapSize].Position - vertices[z + x * vertexMapSize].Position;
edge2 = vertices[z + x * vertexMapSize].Position - vertices[(z + 1) + (x + 1) * vertexMapSize].Position;
normal = Vector3.Cross(edge2, edge1);
normal.Normalize();
vertices[z + x * vertexMapSize].Normal += normal;
vertices[(z + 1) + x * vertexMapSize].Normal += normal;
vertices[(z + 1) + (x + 1) * vertexMapSize].Normal += normal;
meshIndices[(z + x * (vertexMapSize - 1)) * 6 + 3] = (z + (x + 1) * vertexMapSize);
meshIndices[(z + x * (vertexMapSize - 1)) * 6 + 4] = (z + x * vertexMapSize);
meshIndices[(z + x * (vertexMapSize - 1)) * 6 + 5] = ((z + 1) + (x + 1) * vertexMapSize);
edge1 = vertices[z + x * vertexMapSize].Position - vertices[z + (x + 1) * vertexMapSize].Position;
edge2 = vertices[z + (x + 1) * vertexMapSize].Position - vertices[(z + 1) + (x + 1) * vertexMapSize].Position;
normal = Vector3.Cross(edge2, edge1);
normal.Normalize();
vertices[z + (x + 1) * vertexMapSize].Normal += normal;
vertices[z + x * vertexMapSize].Normal += normal;
vertices[(z + 1) + (x + 1) * vertexMapSize].Normal += normal;
}
}
// Normalize vertex normals
for (int i = 0; i < vertexMapSize * vertexMapSize; i++)
{
vertices[i].Normal.Normalize();
}
// Set the data
vertexBuffer.SetData(vertices);
meshIndexBuffer.SetData(meshIndices);
}
public void GenerateCollisionMap()
{
// Interpolate the missing values between scaled vertex values for smoother collision go through each block
for (int blockX = 0; blockX < vertexMapSize; blockX++)
{
for (int blockZ = 0; blockZ < vertexMapSize; blockZ++)
{
float diffx = 0;
float diffz = 0;
// This crap is b/c we need to avoid array out of bounds exception
if ((blockX != (vertexMapSize - 1)) && (blockZ != (vertexMapSize - 1)))
{
diffx = vertexHeightData[blockX + 1, blockZ] - vertexHeightData[blockX, blockZ];
diffz = vertexHeightData[blockX, blockZ + 1] - vertexHeightData[blockX, blockZ];
}
else if ((blockX == (vertexMapSize - 1)) && (blockZ == (vertexMapSize - 1)))
{
// Leave 0
}
else if (blockX == vertexMapSize - 1)
{
// Calculate difference between height values from base point to next point in array
diffz = vertexHeightData[blockX, blockZ + 1] - vertexHeightData[blockX, blockZ];
}
else if (blockZ == vertexMapSize - 1)
{
// Calculate difference between height values from base point to next point in array
diffx = vertexHeightData[blockX + 1, blockZ] - vertexHeightData[blockX, blockZ];
}
// Moving on, For each empty block in array
for (int x = 0; x < terrainScaleFactor; x++)
{
for (int z = 0; z < terrainScaleFactor; z++)
{
// Distance from base position to current collision point
float distx = 1.0f * x / terrainScaleFactor;
float distz = 1.0f * z / terrainScaleFactor;
// Calc height of new value
float interpValueX = vertexHeightData[blockX, blockZ] + distx * diffx;
float interpValueZ = vertexHeightData[blockX, blockZ] + distz * diffz;
collisionHeightData[blockX * terrainScaleFactor + x,
blockZ * terrainScaleFactor + z] = (interpValueX + interpValueZ) / 2;
}
}
}
}
}
private void UpdateCollisionMap(int minX, int maxX, int minZ, int maxZ)
{
for (int blockX = minX; blockX < maxX; blockX++)
{
for (int blockZ = minZ; blockZ < maxZ; blockZ++)
{
float diffx = 0;
float diffz = 0;
// Calculate difference between height values from base point to next point in array
diffx = vertices[blockZ + (blockX + 1) * vertexMapSize].Position.Y - vertices[blockZ + blockX * vertexMapSize].Position.Y;
diffz = vertices[(blockZ + 1) + blockX * vertexMapSize].Position.Y - vertices[blockZ + blockX * vertexMapSize].Position.Y;
// Moving on, For each empty block in array
for (int x = 0; x < terrainScaleFactor; x++)
{
for (int z = 0; z < terrainScaleFactor; z++)
{
// Distance from base position to current collision point
float distx = 1.0f * x / terrainScaleFactor;
float distz = 1.0f * z / terrainScaleFactor;
// Calc height of new value
float interpValueX = vertices[blockZ + blockX * vertexMapSize].Position.Y + distx * diffx;
float interpValueZ = vertices[blockZ + blockX * vertexMapSize].Position.Y + distz * diffz;
//collisionHeightData[blockX * terrainScaleFactor + x,
// blockZ * terrainScaleFactor + z] = (interpValueX + interpValueZ) / 2;
}
}
}
}
}
public void ModifyTerrain(float modFactor, Vector3 lookAtPoint)
{
// TERRAIN OBJECT
Vector3 normal = new Vector3();
Vector3 edge1 = new Vector3();
Vector3 edge2 = new Vector3();
int minX, maxX, minZ, maxZ;
// Change the height value and renormalize vertex normals in surrounding area
if (lookAtPoint.X >= 0 && lookAtPoint.Z >= 0)
{
vertices[((int)lookAtPoint.Z + (int)lookAtPoint.X * vertexMapSize)].Position.Y += 10 * modFactor;
vertices[((int)lookAtPoint.Z + (int)lookAtPoint.X * vertexMapSize)].Normal = new Vector3();
minX = (int)lookAtPoint.X - 1;
maxX = (int)lookAtPoint.X + 1;
minZ = (int)lookAtPoint.Z - 1;
maxZ = (int)lookAtPoint.Z + 1;
if (maxX >= vertexMapSize)
{
maxX = vertexMapSize - 2;
}
if (minX < 0)
{
minX = 0;
}
if (maxZ >= vertexMapSize)
{
maxZ = vertexMapSize - 2;
}
if (minZ < 0)
{
minZ = 0;
}
//UpdateCollisionMap(minX, maxX, minZ, maxZ);
// Renormalize normals
for (int x = minX; x < maxX; x++)
{
for (int z = minZ; z < maxZ; z++)
{
if ((x > lookAtPoint.X && z < lookAtPoint.Z) || (x < lookAtPoint.X && z > lookAtPoint.Z))
{
continue;
}
edge1 = vertices[(z + 1) + x * vertexMapSize].Position - vertices[z + x * vertexMapSize].Position;
edge2 = vertices[z + x * vertexMapSize].Position - vertices[(z + 1) + (x + 1) * vertexMapSize].Position;
normal = Vector3.Cross(edge2, edge1); // normal = Vector3.Cross(edge1, edge2); --> To play the NAN-mine game:-)
normal.Normalize();
vertices[z + x * vertexMapSize].Normal += normal;
vertices[(z + 1) + x * vertexMapSize].Normal += normal;
vertices[(z + 1) + (x + 1) * vertexMapSize].Normal += normal;
edge1 = vertices[z + x * vertexMapSize].Position - vertices[z + (x + 1) * vertexMapSize].Position;
edge2 = vertices[z + (x + 1) * vertexMapSize].Position - vertices[(z + 1) + (x + 1) * vertexMapSize].Position;
normal = Vector3.Cross(edge2, edge1); // normal = Vector3.Cross(edge1, edge2); --> To play the NAN-mine game:-)
normal.Normalize();
vertices[z + (x + 1) * vertexMapSize].Normal += normal;
vertices[z + x * vertexMapSize].Normal += normal;
vertices[(z + 1) + (x + 1) * vertexMapSize].Normal += normal;
}
}
for (int x = minX; x <= maxX; x++)
{
for (int z = minZ; z <= maxZ; z++)
{
vertices[z + x * vertexMapSize].Normal.Normalize();
}
}
terrainChanged = true;
}
}
*/