Ah wth, here, my full landscape code

:
#region LANDSCAPES
///////////////////////////////////////////////////////////////////////////
/////// LANDSCAPES //////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
public struct Land // Landscapes
{
static TVLandscape[,] terrain = new TVLandscape[3, 3];
static int[,][] tert = new int[3, 3][];
public static TV_2DVECTOR landpos, newpos;
// Dynamic world loader thread
static Thread Loader = new Thread(World.Land.TerrainLoader);
static bool loading = false;
public static TVLandscape Terrain(int ChunkX, int ChunkY)
{
return terrain[tert[ChunkX, ChunkY][0], tert[ChunkX, ChunkY][1]];
}
static void LoadChunk(int ChunkX, int ChunkY)
{
terrain[tert[ChunkX, ChunkY][0], tert[ChunkX, ChunkY][1]] = Core.Scene.CreateLandscape("ls" + Convert.ToString(newpos.x) + Convert.ToString(newpos.y));
terrain[tert[ChunkX, ChunkY][0], tert[ChunkX, ChunkY][1]].SetAffineLevel(CONST_TV_LANDSCAPE_AFFINE.TV_AFFINE_HIGH);
terrain[tert[ChunkX, ChunkY][0], tert[ChunkX, ChunkY][1]].GenerateTerrain(@"World\" + Convert.ToString(newpos.x + (ChunkX - 1)) + Convert.ToString(newpos.y + (ChunkY - 1)) + @"\height.png", CONST_TV_LANDSCAPE_PRECISION.TV_PRECISION_HIGH, 10, 10, 2560 * ChunkX, 0, 2560 * ChunkY, true);
terrain[tert[ChunkX, ChunkY][0], tert[ChunkX, ChunkY][1]].SetLightingMode(CONST_TV_LIGHTINGMODE.TV_LIGHTING_MANAGED);
terrain[tert[ChunkX, ChunkY][0], tert[ChunkX, ChunkY][1]].SetMaterial(Core.Globals.GetMat("MatteTer"));
terrain[tert[ChunkX, ChunkY][0], tert[ChunkX, ChunkY][1]].ExpandTexture(Core.TextureFactory.LoadTexture(@"World\" + Convert.ToString(newpos.x + (ChunkX - 1)) + Convert.ToString(newpos.y + (ChunkY - 1)) + @"\tex.dds", "lstex" + Convert.ToString(tert[ChunkX, ChunkY][0]) + Convert.ToString(tert[ChunkX, ChunkY][1])), 0, 0, 10, 10);
terrain[tert[ChunkX, ChunkY][0], tert[ChunkX, ChunkY][1]].SetDetailTexture(Core.Globals.GetTex("lsdet"));
terrain[tert[ChunkX, ChunkY][0], tert[ChunkX, ChunkY][1]].SetDetailTextureScale(20, 20);
terrain[tert[ChunkX, ChunkY][0], tert[ChunkX, ChunkY][1]].SetCustomLightmap(Core.TextureFactory.LoadTexture(@"World\" + Convert.ToString(newpos.x + (ChunkX - 1)) + Convert.ToString(newpos.y + (ChunkY - 1)) + @"\light.dds", "lslight" + Convert.ToString(tert[ChunkX, ChunkY][0]) + Convert.ToString(tert[ChunkX, ChunkY][1])));
terrain[tert[ChunkX, ChunkY][0], tert[ChunkX, ChunkY][1]].EnableLOD(true, 1000, CONST_TV_LANDSCAPE_PRECISION.TV_PRECISION_AVERAGE, 500);
}
public static void InitLandscapes(int LandX, int LandY)
{
// Initialize dynamic terrain loading thread
Loader.Start();
newpos.x = landpos.x = LandX;
newpos.y = landpos.y = LandY;
// Initialize terrain transformation matrix
tert[0, 0] = new int[2] { 0, 0 };
tert[0, 1] = new int[2] { 0, 1 };
tert[0, 2] = new int[2] { 0, 2 };
tert[1, 0] = new int[2] { 1, 0 };
tert[1, 1] = new int[2] { 1, 1 };
tert[1, 2] = new int[2] { 1, 2 };
tert[2, 0] = new int[2] { 2, 0 };
tert[2, 1] = new int[2] { 2, 1 };
tert[2, 2] = new int[2] { 2, 2 };
// Load materials
InitMaterials();
// Load textures
InitTextures();
// Setup landscapes
for (int ly = 0; ly < 3; ly++)
{
for (int lx = 0; lx < 3; lx++)
{
LoadChunk(lx, ly);
}
}
// Seam landscapes together
Seam(1, 1, RelativeLoc.Up);
Seam(1, 1, RelativeLoc.Down);
Seam(1, 1, RelativeLoc.Left);
Seam(1, 1, RelativeLoc.Right);
Seam(1, 0, RelativeLoc.Left);
Seam(1, 0, RelativeLoc.Right);
Seam(1, 2, RelativeLoc.Left);
Seam(1, 2, RelativeLoc.Right);
Seam(0, 1, RelativeLoc.Up);
Seam(0, 1, RelativeLoc.Down);
Seam(2, 1, RelativeLoc.Up);
Seam(2, 1, RelativeLoc.Down);
}
static void InitTextures()
{
// Load textures
Core.TextureFactory.LoadTexture(@"World\Textures\detail.dds", "lsdet");
}
static void InitMaterials()
{
int matId;
matId = Core.MaterialFactory.CreateMaterial("MatteTer");
Core.MaterialFactory.SetAmbient(matId, 1, 1, 1, 1);
Core.MaterialFactory.SetDiffuse(matId, 1, 1, 1, 1);
Core.MaterialFactory.SetSpecular(matId, 0, 0, 0, 1);
Core.MaterialFactory.SetEmissive(matId, 0, 0, 0, 1);
}
public static void Render()
{
terrain[tert[1, 1][0], tert[1, 1][1]].Render();
try
{
for (int rx = 0; rx < 3; rx++)
for (int ry = 0; ry < 3; ry++)
if (!(rx == 1 && ry == 1) && (terrain[tert[rx, ry][0], tert[rx, ry][1]] != null))
terrain[tert[rx, ry][0], tert[rx, ry][1]].Render();
}
catch
{
//Do nothing!!! Wheeeee..
}
}
public static void TerrainLoader()
{
int loadX = new int();
int loadY = new int();
bool useY = new bool();
while (Program.running)
{
if (loading)
{
if (newpos.x < landpos.x)
{
loadX = 0;
useY = true;
}
else if (newpos.x > landpos.x)
{
loadX = 2;
useY = true;
}
else if (newpos.y < landpos.y)
{
loadY = 0;
useY = false;
}
else if (newpos.y > landpos.y)
{
loadY = 2;
useY = false;
}
for (int tl = 0; tl < 3; tl++)
{
if (useY)
loadY = tl;
else
loadX = tl;
LoadChunk(loadX, loadY);
}
landpos.x = newpos.x;
landpos.y = newpos.y;
loading = false;
}
Application.DoEvents();
}
}
static void Destroy(int LandX, int LandY)
{
// Destroy its textures to avoid a memory leak
Core.TextureFactory.DeleteTexture(Core.Globals.GetTex("lstex" + Convert.ToString(tert[LandX, LandY][0]) + Convert.ToString(tert[LandX, LandY][1])));
Core.TextureFactory.DeleteTexture(Core.Globals.GetTex("lslight" + Convert.ToString(tert[LandX, LandY][0]) + Convert.ToString(tert[LandX, LandY][1])));
terrain[tert[LandX, LandY][0], tert[LandX, LandY][1]].Destroy();
terrain[tert[LandX, LandY][0], tert[LandX, LandY][1]] = null;
}
static void MoveTerrainX(int MoveX)
{
int[] transbuf = new int[2];
if (MoveX < 0)
{
for (int mt = 0; mt < 3; mt++)
{
Destroy(0, mt);
transbuf[0] = tert[0, mt][0];
transbuf[1] = tert[0, mt][1];
tert[0, mt][0] = tert[1, mt][0];
tert[0, mt][1] = tert[1, mt][1];
tert[1, mt][0] = tert[2, mt][0];
tert[1, mt][1] = tert[2, mt][1];
tert[2, mt][0] = transbuf[0];
tert[2, mt][1] = transbuf[1];
}
}
else if (MoveX > 0)
{
for (int mt = 0; mt < 3; mt++)
{
Destroy(2, mt);
transbuf[0] = tert[2, mt][0];
transbuf[1] = tert[2, mt][1];
tert[2, mt][0] = tert[1, mt][0];
tert[2, mt][1] = tert[1, mt][1];
tert[1, mt][0] = tert[0, mt][0];
tert[1, mt][1] = tert[0, mt][1];
tert[0, mt][0] = transbuf[0];
tert[0, mt][1] = transbuf[1];
}
}
Reposition();
}
static void MoveTerrainY(int MoveY)
{
int[] transbuf = new int[2];
if (MoveY < 0)
{
for (int mt = 0; mt < 3; mt++)
{
Destroy(mt, 0);
transbuf[0] = tert[mt, 0][0];
transbuf[1] = tert[mt, 0][1];
tert[mt, 0][0] = tert[mt, 1][0];
tert[mt, 0][1] = tert[mt, 1][1];
tert[mt, 1][0] = tert[mt, 2][0];
tert[mt, 1][1] = tert[mt, 2][1];
tert[mt, 2][0] = transbuf[0];
tert[mt, 2][1] = transbuf[1];
}
}
else if (MoveY > 0)
{
for (int mt = 0; mt < 3; mt++)
{
Destroy(mt, 2);
transbuf[0] = tert[mt, 2][0];
transbuf[1] = tert[mt, 2][1];
tert[mt, 2][0] = tert[mt, 1][0];
tert[mt, 2][1] = tert[mt, 1][1];
tert[mt, 1][0] = tert[mt, 0][0];
tert[mt, 1][1] = tert[mt, 0][1];
tert[mt, 0][0] = transbuf[0];
tert[mt, 0][1] = transbuf[1];
}
}
Reposition();
}
static void Reposition()
{
for (int repx = 0; repx < 3; repx++)
{
for (int repy = 0; repy < 3; repy++)
{
if (terrain[tert[repx, repy][0], tert[repx, repy][1]] != null)
terrain[tert[repx, repy][0], tert[repx, repy][1]].SetPosition((repx * 2560), 0f, (repy * 2560));
}
}
// Load new terrain
loading = true;
}
public static TV_3DVECTOR CheckBounds(TV_3DVECTOR PlayerPos)
{
if (PlayerPos.x < 2560)
{
// Wait if there is still terrain loading
while (loading)
Application.DoEvents();
newpos.x = landpos.x - 1;
newpos.y = landpos.y;
PlayerPos.x = PlayerPos.x + 2560;
MoveTerrainX(1);
Meshes.MoveMeshesX(1);
}
else if (PlayerPos.x > 5120)
{
// Wait if there is still terrain loading
while (loading)
Application.DoEvents();
newpos.x = landpos.x + 1;
newpos.y = landpos.y;
PlayerPos.x = PlayerPos.x - 2560;
MoveTerrainX(-1);
Meshes.MoveMeshesX(-1);
}
else if (PlayerPos.z < 2560)
{
// Wait if there is still terrain loading
while (loading)
Application.DoEvents();
newpos.x = landpos.x;
newpos.y = landpos.y - 1;
PlayerPos.z = PlayerPos.z + 2560;
MoveTerrainY(1);
Meshes.MoveMeshesY(1);
}
else if (PlayerPos.z > 5120)
{
// Wait if there is still terrain loading
while (loading)
Application.DoEvents();
newpos.x = landpos.x;
newpos.y = landpos.y + 1;
PlayerPos.z = PlayerPos.z - 2560;
MoveTerrainY(-1);
Meshes.MoveMeshesY(-1);
}
return PlayerPos;
}
public static void SetShader(TVShader NewShader)
{
for (int shadex = 0; shadex < 3; shadex++)
{
for (int shadey = 0; shadey < 3; shadey++)
{
if (terrain[shadex, shadey] != null)
terrain[shadex, shadey].SetShader(NewShader);
}
}
}
enum RelativeLoc
{
Up,
Down,
Left,
Right
}
static void Seam(int TerX, int TerY, RelativeLoc Location)
{
float firstHeight = 0;
float secondHeight = 0;
float averageHeight = 0;
int TerX2 = 0;
int TerY2 = 0;
bool UseX = false;
int ModX = 0;
int ModY = 0;
switch (Location)
{
case RelativeLoc.Left:
TerX2 = TerX - 1;
TerY2 = TerY;
UseX = false;
break;
case RelativeLoc.Right:
TerX2 = TerX + 1;
TerY2 = TerY;
UseX = false;
break;
case RelativeLoc.Up:
TerX2 = TerX;
TerY2 = TerY - 1;
UseX = true;
break;
case RelativeLoc.Down:
TerX2 = TerX;
TerY2 = TerY + 1;
UseX = true;
break;
}
for (int sI = 0; sI < 2560; sI++)
{
if (UseX)
{
ModX = sI + (2560 * TerX);
ModY = 2560 * TerY;
}
else
{
ModX = 2560 * TerX;
ModY = sI + (2560 * TerY);
}
firstHeight = Terrain(TerX, TerY).GetHeight(ModX, ModY);
secondHeight = Terrain(TerX2, TerY2).GetHeight(ModX, ModY);
averageHeight = (firstHeight + secondHeight) / 2;
Terrain(TerX, TerY).SetHeight(ModX, ModY, averageHeight, true, false, false);
Terrain(TerX2, TerY2).SetHeight(ModX, ModY, averageHeight, true, false, false);
}
}
}
#endregion
The seaming code here still leaves a small gap through.
Also there might be some bits where 2560 & 5120 are hardcoded in: My landscapes are 10x10 so they are 2560 in size. Which means, the main (center) landscape always has its position 2560 - 5120.
And CHUNKS in the code do not refer to landscape chunks here, they refer to individual landscapes.
Enjoy!