00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 using System;
00018 using System.Collections;
00019 using System.Collections.Generic;
00020 using System.Text;
00021 using System.Drawing;
00022 using Microsoft.DirectX;
00023 using Microsoft.DirectX.Direct3D;
00024 using System.Diagnostics;
00025 using System.IO;
00026 using Microsoft.Samples.DirectX.UtilityToolkit;
00027
00028 namespace DXGfxLib
00029 {
00039 public class Terrain
00040 {
00045 public static string terrainEffectFile = "terrainTile.fx";
00046
00050 private Bitmap terrainData;
00051
00055 public Texture texture = null;
00056
00060 public Material material;
00061
00065 public string heightmapFile;
00066
00070 public string baseTextureFile;
00071
00075 public string secondTextureFile;
00076
00080 public float maxTerrainHeigth;
00081
00085 public float minTerrainHeigth;
00086
00090 public float secondTexHeigth;
00091
00095 public Texture secondTexture = null;
00096
00100 public Texture alphaMap = null;
00101
00106 public float desiredWidth;
00107
00112 public float desiredHeigth;
00113
00117 public int width;
00118
00122 public int heigth;
00123
00127 public float xSpacing;
00128
00132 public float zSpacing;
00133
00137 public float stretchFactor;
00138
00142 private List<TerrainTile> tiles = null;
00143
00144 public Terrain()
00145 {
00146 Initialize();
00147 }
00148
00155 public Terrain(float desiredWidth, float desiredHeigth)
00156 {
00157 Initialize(desiredWidth, desiredHeigth);
00158 }
00159
00160 public void Initialize()
00161 {
00162 Initialize(1024, 1024);
00163 }
00164
00165 public void Initialize(float desiredWidth, float desiredHeigth)
00166 {
00167
00168
00169
00170
00171
00172 this.desiredWidth = desiredWidth;
00173 this.desiredHeigth = desiredHeigth;
00174
00175 stretchFactor = 70.0f;
00176
00177 maxTerrainHeigth = -10000.0f;
00178 minTerrainHeigth = 10000.0f;
00179
00180
00181 material = new Material();
00182 material.Ambient = Color.Aqua;
00183 material.Diffuse = Color.Azure;
00184 material.Emissive = Color.Blue;
00185 material.Specular = Color.Brown;
00186
00187 secondTexHeigth = 0.0f;
00188
00189 tiles = new List<TerrainTile>();
00190 }
00191
00197 public void DeviceChanged(Device d3ddevice, OutDoorScene scene)
00198 {
00199 Load(d3ddevice, scene, heightmapFile, baseTextureFile, secondTextureFile);
00200 }
00201
00211 public void Load(Device d3ddevice, OutDoorScene scene, string ressourceName)
00212 {
00213 LoadFromFile(d3ddevice, scene, ressourceName);
00214 }
00215
00225 public void LoadFromFile(Device d3ddevice, OutDoorScene scene, string fileName)
00226 {
00227 string path = StringUtil.GetPath(fileName);
00228 if (path == null)
00229 {
00230 Load(d3ddevice, scene, fileName, "newbase.jpg", "grass.bmp");
00231 }
00232 else
00233 {
00234 if (path.Length != 0)
00235 {
00236 Load(d3ddevice, scene, fileName, path + "\\newbase.jpg", path + "\\grass.bmp");
00237 }
00238 else
00239 {
00240 Load(d3ddevice, scene, fileName, "newbase.jpg", "grass.bmp");
00241 }
00242 }
00243 }
00254 public void Load(Device d3ddevice, OutDoorScene scene, string fileName, string baseTextureFile, string secondTextureFile)
00255 {
00256 this.heightmapFile = fileName;
00257 this.baseTextureFile = baseTextureFile;
00258 this.secondTextureFile = secondTextureFile;
00259
00260 if (File.Exists(baseTextureFile))
00261 {
00262 texture = ResourceCache.GetGlobalInstance().CreateTextureFromFile(d3ddevice, baseTextureFile);
00263 }
00264 else
00265 {
00266 Trace.TraceError("File for base texture does not exist!");
00267 throw new ArgumentException("File :" + baseTextureFile + " for base texture does not exist!");
00268 }
00269
00270 if (File.Exists(secondTextureFile))
00271 {
00272 secondTexture = ResourceCache.GetGlobalInstance().CreateTextureFromFile(d3ddevice, secondTextureFile);
00273 }
00274 else
00275 {
00276 Trace.TraceError("File for second texture file does not exist!");
00277 throw new ArgumentException("File :" + secondTextureFile + " for second texture does not exist!");
00278 }
00279
00280 if (File.Exists(heightmapFile))
00281 {
00282 this.terrainData = new Bitmap(heightmapFile);
00283 }
00284 else
00285 {
00286 Trace.TraceError("File for heigthmap does not exist!");
00287 throw new ArgumentException("File :" + heightmapFile + " for heigthmap does not exist!");
00288 }
00289
00290 width = terrainData.Width - 1;
00291 heigth = terrainData.Height - 1;
00292
00293 xSpacing = this.desiredWidth / width;
00294 zSpacing = this.desiredHeigth / heigth;
00295
00296 TerrainVertex[] vertices = BuildVerticesFromBitMap(width, heigth, xSpacing,
00297 zSpacing, stretchFactor, terrainData);
00298
00299 BuildTilesFromVertices(d3ddevice, scene, vertices);
00300
00301 terrainData.Dispose();
00302 }
00303
00311 public float GetHeigth(OutDoorScene scene, float x, float z)
00312 {
00313 TerrainTile tile = FindTile(scene, x, z);
00314 return tile.GetHeigth(x, z);
00315 }
00316
00328 public float GetHeigth(OutDoorScene scene, float x, float y, float z)
00329 {
00330 TerrainTile tile = FindTile(scene, x, z);
00331 return tile.GetHeigth(x, y, z);
00332 }
00333
00334
00341 public float GetHeigth(OutDoorScene scene, Vector3 underPoint)
00342 {
00343 TerrainTile tile = FindTile(scene, underPoint.X, underPoint.Z);
00344 return tile.GetHeigth(underPoint);
00345 }
00346
00355 internal TerrainTile FindTile(OutDoorScene scene, float x, float z)
00356 {
00357 int maxLevel;
00358 Vector3 extents;
00359
00360 if (CheckForQuadTree(scene, out maxLevel, out extents))
00361 {
00362 if (x > extents.X * 0.5f)
00363 {
00364 throw new ArgumentOutOfRangeException("x value is greater than terrain x limit");
00365 }
00366 if (z > extents.Z * 0.5f)
00367 {
00368 throw new ArgumentOutOfRangeException("z value is greater than terrain z limit");
00369 }
00370
00371
00372
00373 x += extents.X * 0.5f;
00374 z += extents.Z * 0.5f;
00375
00376 int numTilesSQRT = (int)System.Math.Pow(2, maxLevel);
00377
00378
00379 float tileExtentX = extents.X / numTilesSQRT;
00380 float tileExtentZ = extents.Z / numTilesSQRT;
00381
00382 int coll = (int)System.Math.Floor(x / tileExtentX);
00383 int row = (int)System.Math.Floor(z / tileExtentZ);
00384
00385 return (TerrainTile)tiles[coll + row * numTilesSQRT];
00386 }
00387 return null;
00388 }
00389
00396 private void BuildTilesFromVertices(Device d3ddevice, OutDoorScene scene, TerrainVertex[] vertices)
00397 {
00398
00399 EffectGroup terrainEG = new EffectGroup();
00400 terrainEG.Set(d3ddevice, terrainEffectFile);
00401
00402 int maxLevel;
00403 Vector3 extents;
00404
00405 if (CheckForQuadTree(scene, out maxLevel, out extents))
00406 {
00407 int numTilesSQRT = (int)System.Math.Pow(2, maxLevel);
00408
00409
00410 for (int j = 0; j < numTilesSQRT; j++)
00411 {
00412 for (int i = 0; i < numTilesSQRT; i++)
00413 {
00414
00415 TerrainTile tile = new TerrainTile();
00416 tile.AssociatedEffectGroup = terrainEG;
00417 tile.Populate(d3ddevice, (width / numTilesSQRT), (heigth / numTilesSQRT),
00418 i * (width / numTilesSQRT), j * (heigth / numTilesSQRT),
00419 width, heigth,
00420 vertices);
00421
00422 tile.texture = this.texture;
00423 tile.material = this.material;
00424 tile.secondTexture = this.secondTexture;
00425
00426 tiles.Add(tile);
00427 scene.nodes[maxLevel][i + j * numTilesSQRT].AddChild(tile);
00428 }
00429 }
00430 }
00431 else
00432 {
00433 TerrainTile tile = new TerrainTile();
00434 tile.AssociatedEffectGroup = terrainEG;
00435 tile.Populate(d3ddevice, width, heigth, 0, 0, width, heigth, vertices);
00436 tiles.Add(tile);
00437 scene.Add(tile);
00438 }
00439 }
00440
00441
00442 private bool CheckForQuadTree(OutDoorScene scene, out int maxLevel, out Vector3 extents)
00443 {
00444
00445 maxLevel = scene.depth;
00446 extents = scene.Extents;
00447
00448 return true;
00449 }
00450
00462 private TerrainVertex[] BuildVerticesFromBitMap(int width, int heigth,
00463 float xSpacing, float zSpacing, float stretchFactor,
00464 Bitmap bitmapToUse)
00465 {
00466
00467 TerrainVertex[] tmpVertices = new TerrainVertex[(width + 1) * (heigth + 1)];
00468 if (bitmapToUse != null)
00469 {
00470 float x = -(width * xSpacing) / 2;
00471 float z = -(heigth * zSpacing) / 2;
00472
00473 float texv = 0.0f;
00474
00475 for (int j = 0; j <= heigth; j++)
00476 {
00477 float texu = 0.0f;
00478
00479 for (int i = 0; i <= width; i++)
00480 {
00481 tmpVertices[i + j * (width + 1)].X = x;
00482 tmpVertices[i + j * (width + 1)].Z = z;
00483
00484 if ((i == 0) || (j == 0) || (i == width) || (j == heigth))
00485 tmpVertices[i + j * (width + 1)].Y = -1000.0f;
00486 else
00487 tmpVertices[i + j * (width + 1)].Y = ((bitmapToUse.GetPixel(i, j)).ToArgb() / (100000)) + 100.0f;
00488
00489 if (tmpVertices[i + j * (width + 1)].Y < minTerrainHeigth)
00490 minTerrainHeigth = tmpVertices[i + j * (width + 1)].Y;
00491 if (tmpVertices[i + j * (width + 1)].Y > maxTerrainHeigth)
00492 maxTerrainHeigth = tmpVertices[i + j * (width + 1)].Y;
00493
00494
00495
00496 tmpVertices[i + j * (width + 1)].Tu1 = (float)i / (float)width;
00497 tmpVertices[i + j * (width + 1)].Tv1 = ((float)j / (float)heigth);
00498 tmpVertices[i + j * (width + 1)].Tu2 = (((float)(texu) / (float)(width)));
00499 tmpVertices[i + j * (width + 1)].Tv2 = (((float)texv / (float)heigth));
00500
00501
00502 if (texu < width)
00503 texu += stretchFactor;
00504 else
00505 texu = 0.0f;
00506
00507
00508 Vector3 rowVector = new Vector3(1.0f, 0.0f, 0.0f);
00509 Vector3 collumnVector = new Vector3(0.0f, 1.0f, 0.0f);
00510 Vector3 tempNorm = new Vector3(0.0f, 1.0f, 0.0f);
00511 if (i > 0)
00512 {
00513 rowVector.X = tmpVertices[(i - 1) + j * (width + 1)].X - tmpVertices[i + j * (width + 1)].X;
00514 rowVector.Y = tmpVertices[(i - 1) + j * (width + 1)].Y - tmpVertices[i + j * (width + 1)].Y;
00515 rowVector.Z = tmpVertices[(i - 1) + j * (width + 1)].Z - tmpVertices[i + j * (width + 1)].Z;
00516 }
00517 if (j > 0)
00518 {
00519 collumnVector.X = tmpVertices[(i) + (j - 1) * (width + 1)].X - tmpVertices[i + j * (width + 1)].X;
00520 collumnVector.Y = tmpVertices[(i) + (j - 1) * (width + 1)].Y - tmpVertices[i + j * (width + 1)].Y;
00521 collumnVector.Z = tmpVertices[(i) + (j - 1) * (width + 1)].Z - tmpVertices[i + j * (width + 1)].Z;
00522 }
00523 tempNorm = Vector3.Cross(rowVector, collumnVector);
00524 tempNorm = Vector3.Normalize(tempNorm);
00525
00526 tmpVertices[i + j * (width + 1)].Nx = tempNorm.X;
00527 tmpVertices[i + j * (width + 1)].Ny = tempNorm.Y;
00528 tmpVertices[i + j * (width + 1)].Nz = tempNorm.Z;
00529
00530 x += xSpacing;
00531 }
00532
00533 if (texv < heigth)
00534 texv += stretchFactor;
00535 else
00536 texv = 0.0f;
00537
00538 z += zSpacing;
00539 x = -(width * xSpacing) / 2;
00540 }
00541 }
00542
00543 return tmpVertices;
00544 }
00545
00546 public void AddInstances(OutDoorScene scene, FrameworkMesh mesh, InstanceInfo[] instancesInfo)
00547 {
00548 Hashtable tileInstanceAssociations = new Hashtable();
00549
00550 foreach (InstanceInfo info in instancesInfo)
00551 {
00552 TerrainTile tile = FindTile(scene, info.positionRot.X, info.positionRot.Z);
00553
00554 if (tileInstanceAssociations.ContainsKey(tile))
00555 {
00556 List<InstanceInfo> infos = (List<InstanceInfo>)tileInstanceAssociations[tile];
00557 infos.Add(info);
00558 }
00559 else
00560 {
00561 List<InstanceInfo> infos = new List<InstanceInfo>();
00562 infos.Add(info);
00563 tileInstanceAssociations.Add(tile, infos);
00564 }
00565 }
00566
00567 IDictionaryEnumerator enumerator = tileInstanceAssociations.GetEnumerator();
00568
00569 while (enumerator.MoveNext())
00570 {
00571 List<InstanceInfo> infos = (List<InstanceInfo>)enumerator.Value;
00572 InstanceInfo[] instInfos = new InstanceInfo[infos.Count];
00573 infos.CopyTo(instInfos);
00574
00575 TerrainTile tile = (TerrainTile)enumerator.Key;
00576 tile.AddInstances(mesh, instInfos);
00577 }
00578 }
00579 }
00580 }