00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 using System;
00018 using System.Collections.Generic;
00019 using System.Text;
00020 using Microsoft.DirectX;
00021 using Microsoft.DirectX.Direct3D;
00022 using Microsoft.Samples.DirectX.UtilityToolkit;
00023 using System.Drawing;
00024
00025 namespace DXGfxLib
00026 {
00027 public struct TerrainVertex
00028 {
00029 public float X;
00030 public float Y;
00031 public float Z;
00032 public float Nx;
00033 public float Ny;
00034 public float Nz;
00035 public float Tu1;
00036 public float Tv1;
00037 public float Tu2;
00038 public float Tv2;
00039 public static readonly VertexFormats format = VertexFormats.Position | VertexFormats.Normal | VertexFormats.Texture2;
00040 public static readonly int strideSize = DXHelp.GetTypeSize(typeof(TerrainVertex));
00041 }
00042
00050 internal class TerrainTile : MeshObject
00051 {
00055 public static int settedPass = -1;
00056
00060 public static float near = 500.0f;
00061
00065 public static float mid = 700.0f;
00066
00067 public bool far = false;
00068
00073 public Mesh collMesh = null;
00074
00075 protected Mesh localMemMesh = null;
00076
00077 public Texture texture = null;
00078 public Material material;
00079 public float maxTerrainHeigth;
00080 public float minTerrainHeigth;
00081
00082 public float secondTexHeigth;
00083 public Texture secondTexture = null;
00084
00085
00086 public int width;
00087 public int heigth;
00088 public float spacing;
00089 public float stretchFactor;
00090
00091 protected int currentTriCount = 0;
00092 protected IndexBuffer currentIndexBuff = null;
00093 protected bool useLOD = false;
00094 protected int LOD2TriCount = 0;
00095 protected IndexBuffer indexBuffLOD2 = null;
00096 protected int LOD3TriCount = 0;
00097 protected IndexBuffer indexBuffLOD3 = null;
00098
00099
00100
00101
00102 public List<Batch> batches;
00103
00108 internal TerrainTile()
00109 {
00110
00111
00112
00113 width = 128;
00114 heigth = 128;
00115 spacing = 10;
00116 stretchFactor = 1.0f;
00117
00118 maxTerrainHeigth = 1000.0f;
00119 minTerrainHeigth = 1000.0f;
00120
00121
00122 material = new Material();
00123 material.Ambient = Color.Aqua;
00124 material.Diffuse = Color.Azure;
00125 material.Emissive = Color.Blue;
00126 material.Specular = Color.Brown;
00127
00128 secondTexHeigth = 0.0f;
00129
00130 batches = new List<Batch>();
00131 }
00132
00136 public override void Dispose()
00137 {
00138 if (collMesh != null)
00139 {
00140 collMesh.Dispose();
00141 }
00142 if (texture != null)
00143 {
00144 texture.Dispose();
00145 }
00146 if (batches != null)
00147 {
00148 foreach (Batch batch in batches)
00149 {
00150 batch.Dispose();
00151 }
00152 }
00153 }
00154
00155 public override void SetEffectsValues(Device d3ddevice, Effect eff, int pass)
00156 {
00157 if (pass != settedPass)
00158 {
00159 eff.SetValue("baseTexture", texture);
00160 eff.SetValue("areaTexture", secondTexture);
00161 d3ddevice.SetTransform(TransformType.World, worldMat);
00162 settedPass = pass;
00163 }
00164 }
00165
00170 public override void Draw(Device d3ddevice)
00171 {
00172 d3ddevice.SetStreamSource(0, localMemMesh.VertexBuffer, 0, TerrainVertex.strideSize);
00173 d3ddevice.Indices = currentIndexBuff;
00174 d3ddevice.VertexFormat = TerrainVertex.format;
00175 d3ddevice.RenderState.CullMode = Cull.None;
00176 d3ddevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, localMemMesh.NumberVertices,
00177 0, currentTriCount);
00178 }
00179
00191 internal void Populate(Device d3ddevice, int numColl, int numRow,
00192 int collOffsetInSource, int rowOffsetInSource,
00193 int numCollInSource, int numRowInSource,
00194 TerrainVertex[] sourceVertices)
00195 {
00196 TerrainVertex[] vertices = new TerrainVertex[(numColl + 1) * (numRow + 1)];
00197
00198 this.width = numColl;
00199 this.heigth = numRow;
00200
00201 for (int j = 0; j < numRow + 1; j++)
00202 {
00203 for (int i = 0; i < numColl + 1; i++)
00204 {
00205 vertices[i + j * (numColl + 1)] = sourceVertices[(i + collOffsetInSource) + (j + rowOffsetInSource) * (numCollInSource + 1)];
00206 }
00207 }
00208
00209 BuildMeshFromVertices(d3ddevice, vertices);
00210
00211 collMesh = originalMesh.Clone(MeshFlags.SystemMemory, CustomVertex.PositionOnly.Format, d3ddevice);
00212 }
00213
00220 private void BuildMeshFromVertices(Device d3ddevice, TerrainVertex[] vertices)
00221 {
00222 localBoundingBox.vMax = new Vector3(vertices[0].X, vertices[0].Y, vertices[0].Z);
00223 localBoundingBox.vMax = new Vector3(vertices[0].X, vertices[0].Y, vertices[0].Z);
00224
00225
00226 for (int k = 0; k < vertices.Length; k++)
00227 {
00228 if (vertices[k].X < localBoundingBox.vMin.X)
00229 {
00230 localBoundingBox.vMin.X = vertices[k].X;
00231 }
00232 if (vertices[k].X > localBoundingBox.vMax.X)
00233 {
00234 localBoundingBox.vMax.X = vertices[k].X;
00235 }
00236 if (vertices[k].Y < localBoundingBox.vMin.Y)
00237 {
00238 localBoundingBox.vMin.Y = vertices[k].Y;
00239 }
00240 if (vertices[k].Y > localBoundingBox.vMax.Y)
00241 {
00242 localBoundingBox.vMax.Y = vertices[k].Y;
00243 }
00244 if (vertices[k].Z < localBoundingBox.vMin.Z)
00245 {
00246 localBoundingBox.vMin.Z = vertices[k].Z;
00247 }
00248 if (vertices[k].Z > localBoundingBox.vMax.Z)
00249 {
00250 localBoundingBox.vMax.Z = vertices[k].Z;
00251 }
00252 }
00253
00254 Mesh terrainMesh = new Mesh((width * heigth) * 2, (width + 1) * (heigth + 1), MeshFlags.SystemMemory,
00255 TerrainVertex.format,
00256 d3ddevice);
00257
00258
00259 GraphicsStream buffStream = terrainMesh.LockVertexBuffer(LockFlags.NoSystemLock);
00260 buffStream.Write(vertices);
00261 terrainMesh.UnlockVertexBuffer();
00262
00263
00264 Int16[] indices = new Int16[width * heigth * 6];
00265
00266 for (Int16 b = 0; b < heigth; b++)
00267 {
00268 for (Int16 a = 0; a < width; a++)
00269 {
00270 indices[((a + b * width) * 6)] = (Int16)(a + b * (width + 1));
00271 indices[((a + b * width) * 6) + 1] = (Int16)((a + 1) + b * (width + 1));
00272 indices[((a + b * width) * 6) + 2] = (Int16)((a + 1) + (b + 1) * (width + 1));
00273
00274 indices[((a + b * width) * 6) + 3] = (Int16)(a + b * (width + 1));
00275 indices[((a + b * width) * 6) + 4] = (Int16)((a + 1) + (b + 1) * (width + 1));
00276 indices[((a + b * width) * 6) + 5] = (Int16)(a + (b + 1) * (width + 1));
00277 }
00278 }
00279
00280 GraphicsStream iBuffStream = terrainMesh.LockIndexBuffer(LockFlags.NoSystemLock);
00281 iBuffStream.Write(indices);
00282 terrainMesh.UnlockIndexBuffer();
00283
00284 localMemMesh = terrainMesh.Clone((terrainMesh.Options.Value & ~MeshFlags.SystemMemory),
00285 terrainMesh.VertexFormat, d3ddevice);
00286
00287 base.Attach(terrainMesh);
00288
00289
00290
00291 if ((width == 8) && (heigth == 8))
00292 {
00293 LODQuad8(d3ddevice);
00294 useLOD = true;
00295 }
00296 if ((width == 32) && (heigth == 32))
00297 {
00298 LODQuad32(d3ddevice);
00299 useLOD = true;
00300 }
00301 }
00302
00306 private void LODQuad32(Device d3ddevice)
00307 {
00308 Int16[] indicesLOD2 = {0000,0001,0272, 0001,0002,0272, 0002,0003,0272, 0003,0004,0272, 0004,0005,0272, 0005,0006,0272, 0006,0007,0272, 0007,0008,0272,
00309 0000,0272,0033, 0033,0272,0066, 0066,0272,0099, 0099,0272,0132, 0132,0272,0165, 0165,0272,0198, 0198,0272,0231, 0231,0272,0264,
00310
00311
00312 0008,0280,0272, 0008,0009,0280, 0280,0024,0288, 0023,0024,0280,
00313 0009,0010,0280, 0010,0011,0280, 0011,0012,0280, 0012,0013,0280, 0013,0014,0280, 0014,0015,0280, 0015,0016,0280,
00314 0016,0017,0280, 0017,0018,0280, 0018,0019,0280, 0019,0020,0280, 0020,0021,0280, 0021,0022,0280, 0022,0023,0280,
00315
00316 0024,0025,0288, 0025,0026,0288, 0026,0027,0288, 0027,0028,0288, 0028,0029,0288, 0029,0030,0288, 0030,0031,0288, 0031,0032,0288,
00317 0032,0065,0288, 0065,0098,0288, 0098,0131,0288, 0131,0164,0288, 0164,0197,0288, 0197,0230,0288, 0230,0263,0288, 0263,0296,0288,
00318
00319 1064,1063,0800, 1063,1062,0800, 1062,1061,0800, 1061,1060,0800, 1060,1059,0800, 1059,1058,0800, 1058,1057,0800, 1057,1056,0800,
00320 1056,1023,0800, 1023,0990,0800, 0990,0957,0800, 0957,0924,0800, 0924,0891,0800, 0891,0858,0800, 0858,0825,0800, 0825,0792,0800,
00321
00322 1064,0800,0808, 1065,1064,0808, 1080,0808,0816, 1080,1079,0808,
00323 1079,1078,0808, 1078,1077,0808, 1077,1076,0808, 1076,1075,0808, 1075,1074,0808, 1074,1073,0808, 1073,1072,0808,
00324 1072,1071,0808, 1071,1070,0808, 1070,1069,0808, 1069,1068,0808, 1068,1067,0808, 1067,1066,0808, 1066,1065,0808,
00325
00326 0824,0857,0816, 0857,0890,0816, 0890,0923,0816, 0923,0956,0816, 0956,0989,0816, 0989,1022,0816, 1022,1055,0816, 1055,1088,0816,
00327 1088,1087,0816, 1087,1086,0816, 1086,1085,0816, 1085,1084,0816, 1084,1083,0816, 1083,1082,0816, 1082,1081,0816, 1081,1080,0816,
00328
00329 0792,0536,0800, 0792,0759,0536, 0264,0272,0536, 0297,0264,0536,
00330 0759,0726,0536, 0726,0693,0536, 0693,0660,0536, 0660,0627,0536, 0627,0594,0536, 0594,0561,0536, 0561,0528,0536,
00331 0528,0495,0536, 0495,0462,0536, 0462,0429,0536, 0429,0396,0536, 0396,0363,0536, 0363,0330,0536, 0330,0297,0536,
00332
00333 0824,0816,0552, 0791,0824,0552, 0296,0552,0288, 0296,0329,0552,
00334 0329,0362,0552, 0362,0395,0552, 0395,0428,0552, 0428,0461,0552, 0461,0494,0552, 0494,0527,0552, 0527,0560,0552,
00335 0560,0593,0552, 0593,0626,0552, 0626,0659,0552, 0659,0692,0552, 0692,0725,0552, 0725,0758,0552, 0758,0791,0552,
00336
00337 0272,0280,0544, 0272,0544,0536, 0280,0288,0544, 0288,0552,0544, 0800,0536,0544, 0800,0544,0808, 0808,0544,0816, 0816,0544,0552};
00338
00339 indexBuffLOD2 = new IndexBuffer(d3ddevice, sizeof(Int16) * indicesLOD2.Length, Usage.None, Pool.SystemMemory, true);
00340 GraphicsStream iBuffStream2 = indexBuffLOD2.Lock(0, 0, LockFlags.NoSystemLock);
00341 for (int t = 0; t < indicesLOD2.Length; t++)
00342 {
00343 iBuffStream2.Write((Int16)indicesLOD2[t]);
00344 }
00345 indexBuffLOD2.Unlock();
00346
00347 int reminder = 0;
00348 LOD2TriCount = Math.DivRem(indicesLOD2.Length, 3, out reminder);
00349 if (reminder != 0)
00350 {
00351 throw new Exception("Really the number of indices should be a multiple of three, there is an issue here!");
00352 }
00353
00354 int[] indicesLOD3 = {0000,0001,0544, 0001,0002,0544, 0002,0003,0544, 0003,0004,0544, 0004,0005,0544, 0005,0006,0544, 0006,0007,0544, 0007,0008,0544,
00355 0008,0009,0544, 0009,0010,0544, 0010,0011,0544, 0011,0012,0544, 0012,0013,0544, 0013,0014,0544, 0014,0015,0544, 0015,0016,0544,
00356 0016,0017,0544, 0017,0018,0544, 0018,0019,0544, 0019,0020,0544, 0020,0021,0544, 0021,0022,0544, 0022,0023,0544, 0023,0024,0544,
00357 0024,0025,0544, 0025,0026,0544, 0026,0027,0544, 0027,0028,0544, 0028,0029,0544, 0029,0030,0544, 0030,0031,0544, 0031,0032,0544,
00358
00359 0032,0065,0544, 0065,0098,0544, 0098,0131,0544, 0131,0164,0544, 0164,0197,0544, 0197,0230,0544, 0230,0263,0544, 0263,0296,0544,
00360 0296,0329,0544, 0329,0362,0544, 0362,0395,0544, 0395,0428,0544, 0428,0461,0544, 0461,0494,0544, 0494,0527,0544, 0527,0560,0544,
00361 0560,0593,0544, 0593,0626,0544, 0626,0659,0544, 0659,0692,0544, 0692,0725,0544, 0725,0758,0544, 0758,0791,0544, 0791,0824,0544,
00362 0824,0857,0544, 0857,0890,0544, 0890,0923,0544, 0923,0956,0544, 0956,0989,0544, 0989,1022,0544, 1022,1055,0544, 1055,1088,0544,
00363
00364 1088,1087,0544, 1087,1086,0544, 1086,1085,0544, 1085,1084,0544, 1084,1083,0544, 1083,1082,0544, 1082,1081,0544, 1081,1080,0544,
00365 1080,1079,0544, 1079,1078,0544, 1078,1077,0544, 1077,1076,0544, 1076,1075,0544, 1075,1074,0544, 1074,1073,0544, 1073,1072,0544,
00366 1072,1071,0544, 1071,1070,0544, 1070,1069,0544, 1069,1068,0544, 1068,1067,0544, 1067,1066,0544, 1066,1065,0544, 1065,1064,0544,
00367 1064,1063,0544, 1063,1062,0544, 1062,1061,0544, 1061,1060,0544, 1060,1059,0544, 1059,1058,0544, 1058,1057,0544, 1057,1056,0544,
00368
00369 1056,1023,0544, 1023,0990,0544, 0990,0957,0544, 0957,0924,0544, 0924,0891,0544, 0891,0858,0544, 0858,0825,0544, 0825,0792,0544,
00370 0792,0759,0544, 0759,0726,0544, 0726,0693,0544, 0693,0660,0544, 0660,0627,0544, 0627,0594,0544, 0594,0561,0544, 0561,0528,0544,
00371 0528,0495,0544, 0495,0462,0544, 0462,0429,0544, 0429,0396,0544, 0396,0363,0544, 0363,0330,0544, 0330,0297,0544, 0297,0264,0544,
00372 0264,0231,0544, 0231,0198,0544, 0198,0165,0544, 0165,0132,0544, 0132,0099,0544, 0099,0066,0544, 0066,0033,0544, 0033,0000,0544};
00373
00374 indexBuffLOD3 = new IndexBuffer(d3ddevice, sizeof(Int16) * indicesLOD3.Length, Usage.None, Pool.SystemMemory, true);
00375 GraphicsStream iBuffStream3 = indexBuffLOD3.Lock(0, 0, LockFlags.NoSystemLock);
00376 for (int t = 0; t < indicesLOD3.Length; t++)
00377 {
00378 iBuffStream3.Write((Int16)indicesLOD3[t]);
00379 }
00380 indexBuffLOD3.Unlock();
00381
00382 LOD3TriCount = Math.DivRem(indicesLOD3.Length, 3, out reminder);
00383 if (reminder != 0)
00384 {
00385 throw new Exception("Really the number of indices should be a multiple of three, there is an issue here!");
00386 }
00387 }
00388
00392 private void LODQuad8(Device d3ddevice)
00393 {
00394 int[] indicesLOD2 = {00,01,20, 00,20,09, 01,02,20, 09,20,18,
00395 02,22,20, 22,06,24,
00396 02,03,22, 05,06,22, 03,04,22, 04,05,22,
00397 06,07,24, 07,08,24, 08,17,24, 17,26,24,
00398 72,63,56, 72,56,73, 63,54,56, 73,56,74,
00399 74,56,58, 78,58,60,
00400 74,58,75, 76,75,58, 76,58,77, 77,58,78,
00401 78,60,79, 79,60,80, 71,80,60, 71,60,62,
00402 54,38,56, 18,20,38,
00403 54,45,38, 45,36,38, 36,27,38, 27,18,38,
00404 62,60,42, 42,24,26,
00405 62,42,53, 53,42,44, 44,42,35, 35,42,26,
00406 20,22,40, 20,40,38, 22,24,40, 24,42,40,
00407 56,38,40, 56,40,58, 60,58,40, 60,40,42};
00408 indexBuffLOD2 = new IndexBuffer(d3ddevice, sizeof(Int16) * indicesLOD2.Length, Usage.None, Pool.SystemMemory, true);
00409 GraphicsStream iBuffStream2 = indexBuffLOD2.Lock(0, 0, LockFlags.NoSystemLock);
00410 for (int t = 0; t < indicesLOD2.Length; t++)
00411 {
00412 iBuffStream2.Write((Int16)indicesLOD2[t]);
00413 }
00414 indexBuffLOD2.Unlock();
00415
00416 int reminder = 0;
00417 LOD2TriCount = Math.DivRem(indicesLOD2.Length, 3, out reminder);
00418 if (reminder != 0)
00419 {
00420 throw new Exception("Really the number of indices should be a multiple of three, there is an issue here!");
00421 }
00422
00423 int[] indicesLOD3 = {00,01,40, 01,02,40, 02,03,40, 03,04,40, 04,05,40, 05,06,40, 06,07,40, 07,08,40,
00424 08,17,40, 17,26,40, 26,35,40, 35,44,40, 44,53,40, 53,62,40, 62,71,40, 71,80,40,
00425 80,79,40, 79,78,40, 78,77,40, 77,76,40, 76,75,40, 75,74,40, 74,73,40, 73,72,40,
00426 72,63,40, 63,54,40, 54,45,40, 45,36,40, 36,27,40, 27,18,40, 18,09,40, 09,00,40};
00427
00428 indexBuffLOD3 = new IndexBuffer(d3ddevice, sizeof(Int16) * indicesLOD3.Length, Usage.None, Pool.SystemMemory, true);
00429 GraphicsStream iBuffStream3 = indexBuffLOD3.Lock(0, 0, LockFlags.NoSystemLock);
00430 for (int t = 0; t < indicesLOD3.Length; t++)
00431 {
00432 iBuffStream3.Write((Int16)indicesLOD3[t]);
00433 }
00434 indexBuffLOD3.Unlock();
00435
00436 LOD3TriCount = Math.DivRem(indicesLOD3.Length, 3, out reminder);
00437 if (reminder != 0)
00438 {
00439 throw new Exception("Really the number of indices should be a multiple of three, there is an issue here!");
00440 }
00441 }
00442
00450 public override void AttachForRendering(Frustrum frustrum, List<IDrawable> objectsToBeRendered)
00451 {
00452
00453
00454 if (useFrustrumCulling)
00455 {
00456 if (!frustrum.IsInFrustrum(worldAABBox))
00457 return;
00458 }
00459
00460 objectsToBeRendered.Add(this);
00461
00462 if (far)
00463 return;
00464
00465 foreach (Batch batch in batches)
00466 {
00467 objectsToBeRendered.Add(batch);
00468 }
00469
00470 foreach (SceneNode child in children)
00471 {
00472 child.AttachForRendering(frustrum, objectsToBeRendered);
00473 }
00474 }
00475
00476 public override void Update(Frustrum frustrum, float elapsedTime, double appTime, List<IDrawable> objectsToBeRendered)
00477 {
00478 base.Update(frustrum, elapsedTime, appTime, objectsToBeRendered);
00479
00480 if (useLOD)
00481 {
00482 float distToNearPlane = MathUtil.SignedDistance(frustrum.NearPlane, barycenter);
00483
00484 if (distToNearPlane < near)
00485 {
00486 currentIndexBuff = this.originalMesh.IndexBuffer;
00487 currentTriCount = this.originalMesh.NumberFaces;
00488 far = false;
00489 }
00490 else if (distToNearPlane < mid)
00491 {
00492 currentIndexBuff = indexBuffLOD2;
00493 currentTriCount = LOD2TriCount;
00494 far = true;
00495 }
00496 else
00497 {
00498 currentIndexBuff = indexBuffLOD3;
00499 currentTriCount = LOD3TriCount;
00500 far = true;
00501 }
00502 }
00503 }
00504
00511 public float GetHeigth(float x, float z)
00512 {
00513 Vector3 rayPos = new Vector3(x, maxTerrainHeigth, z);
00514 Vector3 rayDir = new Vector3(0.0f, -1.0f, 0.0f);
00515
00516 Microsoft.DirectX.Direct3D.IntersectInformation closestHit = new IntersectInformation();
00517
00518 if (this.collMesh.Intersect(rayPos, rayDir, out closestHit))
00519 return (maxTerrainHeigth - closestHit.Dist);
00520 else
00521 return maxTerrainHeigth;
00522 }
00523
00524
00531 public float GetHeigth(float x, float y, float z)
00532 {
00533 Vector3 rayPos = new Vector3(x, y, z);
00534 Vector3 rayDir = new Vector3(0.0f, -1.0f, 0.0f);
00535
00536 Microsoft.DirectX.Direct3D.IntersectInformation closestHit = new IntersectInformation();
00537
00538 if (this.collMesh.Intersect(rayPos, rayDir, out closestHit))
00539 return (y - closestHit.Dist);
00540 else
00541 return 65536;
00542 }
00543
00550 public float GetHeigth(Vector3 underPoint)
00551 {
00552 Vector3 rayDir = new Vector3(0.0f, -1.0f, 0.0f);
00553
00554 Microsoft.DirectX.Direct3D.IntersectInformation closestHit = new IntersectInformation();
00555
00556 if (this.collMesh.Intersect(underPoint, rayDir, out closestHit))
00557 return (underPoint.Y - closestHit.Dist);
00558 else
00559 return 65536;
00560 }
00561
00566 public BBox CalculateBBox()
00567 {
00568 if (localBoundingBox == null)
00569 {
00570 localBoundingBox = new BBox();
00571
00572
00573 VertexBuffer vb = collMesh.VertexBuffer;
00574
00575
00576 GraphicsStream vertexData = vb.Lock(0, 0, LockFlags.NoSystemLock);
00577 Geometry.ComputeBoundingBox(vertexData,
00578 collMesh.NumberVertices,
00579 collMesh.VertexFormat,
00580 out this.localBoundingBox.vMin, out this.localBoundingBox.vMax);
00581 vb.Unlock();
00582 vb.Dispose();
00583 }
00584 worldAABBox = new AABBox(localBoundingBox.Transform(this.WorldMat));
00585 return worldAABBox;
00586 }
00587
00595 public override bool Intersect(Vector3 rayPos, Vector3 rayDir, out IntersectInformation closestHit)
00596 {
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607 return collMesh.Intersect(rayPos, rayDir, out closestHit);
00608 }
00609
00610 public void AddInstances(FrameworkMesh mesh, InstanceInfo[] instancesInfo)
00611 {
00612
00613 Batch batch = new Batch();
00614 batches.Add(batch);
00615 }
00616 }
00617 }