- Main Page
- Packages
- Classes
- Files

- File List
- File Members

# D:/guillaume/guillara/3D/DXGfx/DXGfxLib/Terrain.cs

Go to the documentation of this file.

    00001 //BSD License
    00002 //DXGfx® - http://www.eteractions.com
    00003 //Copyright (c) 2005
    00004 //by Guillaume Randon
    00005 //Permission is hereby granted, free of charge, to any person obtaining a copy of this software
    00006 //and associated documentation files (the "Software"), to deal in the Software without restriction,
    00007 //including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
    00008 //and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
    00009 //subject to the following conditions:
    00010 //The above copyright notice and this permission notice shall be included in all copies or substantial
    00011 //portions of the Software.
    00012 //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
    00013 //INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
    00014 //AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
    00015 //DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    00016 //OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    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             // This means that we have 129*129 vertices. Our bitmap should also be
    00168             // 129*129
    00169             //bitmapWidth = 128;
    00170             //bitmapHeigth = 128;
    00171             //spacing = 10;
    00172             this.desiredWidth = desiredWidth;
    00173             this.desiredHeigth = desiredHeigth;
    00174
    00175             stretchFactor = 70.0f;
    00176
    00177             maxTerrainHeigth = -10000.0f;
    00178             minTerrainHeigth = 10000.0f;
    00179
    00180             // Default material
    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                 // Position 0,0 doesn't match with tile 0,0
    00372                 // we need to add half our extents value to x and z
    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             // Create an effect group that we are going to use for our terrain tiles.
    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                         // set the texture coordinates
    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                         // calc the normal from the last pixel and row
    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 }