diff options
Diffstat (limited to '')
-rw-r--r-- | OpenSim/Region/Framework/Scenes/Scene.cs | 159 |
1 files changed, 99 insertions, 60 deletions
diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index a43de29..18376c3 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs | |||
@@ -329,6 +329,17 @@ namespace OpenSim.Region.Framework.Scenes | |||
329 | private Dictionary<string, string> m_extraSettings; | 329 | private Dictionary<string, string> m_extraSettings; |
330 | 330 | ||
331 | /// <summary> | 331 | /// <summary> |
332 | /// If true then the next time the scene loop is activated, updates will be performed by firing of a timer | ||
333 | /// rather than on a single thread that sleeps. | ||
334 | /// </summary> | ||
335 | public bool UpdateOnTimer { get; set; } | ||
336 | |||
337 | /// <summary> | ||
338 | /// Only used if we are updating scene on a timer rather than sleeping a thread. | ||
339 | /// </summary> | ||
340 | private Timer m_sceneUpdateTimer; | ||
341 | |||
342 | /// <summary> | ||
332 | /// Current scene frame number | 343 | /// Current scene frame number |
333 | /// </summary> | 344 | /// </summary> |
334 | public uint Frame | 345 | public uint Frame |
@@ -430,7 +441,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
430 | /// Is the scene active? | 441 | /// Is the scene active? |
431 | /// </summary> | 442 | /// </summary> |
432 | /// <remarks> | 443 | /// <remarks> |
433 | /// If false, maintenance and update loops are not being run. Updates can still be triggered manually if | 444 | /// If false, maintenance and update loops are not being run, though after setting to false update may still |
445 | /// be active for a period (and IsRunning will still be true). Updates can still be triggered manually if | ||
434 | /// the scene is not active. | 446 | /// the scene is not active. |
435 | /// </remarks> | 447 | /// </remarks> |
436 | public bool Active | 448 | public bool Active |
@@ -453,8 +465,11 @@ namespace OpenSim.Region.Framework.Scenes | |||
453 | } | 465 | } |
454 | private volatile bool m_active; | 466 | private volatile bool m_active; |
455 | 467 | ||
456 | // private int m_lastUpdate; | 468 | /// <summary> |
457 | // private bool m_firstHeartbeat = true; | 469 | /// If true then updates are running. This may be true for a short period after a scene is de-activated. |
470 | /// </summary> | ||
471 | public bool IsRunning { get { return m_isRunning; } } | ||
472 | private volatile bool m_isRunning; | ||
458 | 473 | ||
459 | private Timer m_mapGenerationTimer = new Timer(); | 474 | private Timer m_mapGenerationTimer = new Timer(); |
460 | private bool m_generateMaptiles; | 475 | private bool m_generateMaptiles; |
@@ -1352,19 +1367,18 @@ namespace OpenSim.Region.Framework.Scenes | |||
1352 | /// </param> | 1367 | /// </param> |
1353 | public void Start(bool startScripts) | 1368 | public void Start(bool startScripts) |
1354 | { | 1369 | { |
1370 | if (IsRunning) | ||
1371 | return; | ||
1372 | |||
1373 | m_isRunning = true; | ||
1355 | m_active = true; | 1374 | m_active = true; |
1356 | 1375 | ||
1357 | // m_log.DebugFormat("[SCENE]: Starting Heartbeat timer for {0}", RegionInfo.RegionName); | 1376 | // m_log.DebugFormat("[SCENE]: Starting Heartbeat timer for {0}", RegionInfo.RegionName); |
1358 | |||
1359 | //m_heartbeatTimer.Enabled = true; | ||
1360 | //m_heartbeatTimer.Interval = (int)(m_timespan * 1000); | ||
1361 | //m_heartbeatTimer.Elapsed += new ElapsedEventHandler(Heartbeat); | ||
1362 | if (m_heartbeatThread != null) | 1377 | if (m_heartbeatThread != null) |
1363 | { | 1378 | { |
1364 | m_heartbeatThread.Abort(); | 1379 | m_heartbeatThread.Abort(); |
1365 | m_heartbeatThread = null; | 1380 | m_heartbeatThread = null; |
1366 | } | 1381 | } |
1367 | // m_lastUpdate = Util.EnvironmentTickCount(); | ||
1368 | 1382 | ||
1369 | m_heartbeatThread | 1383 | m_heartbeatThread |
1370 | = Watchdog.StartThread( | 1384 | = Watchdog.StartThread( |
@@ -1401,15 +1415,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
1401 | /// </summary> | 1415 | /// </summary> |
1402 | private void Heartbeat() | 1416 | private void Heartbeat() |
1403 | { | 1417 | { |
1404 | // if (!Monitor.TryEnter(m_heartbeatLock)) | ||
1405 | // { | ||
1406 | // Watchdog.RemoveThread(); | ||
1407 | // return; | ||
1408 | // } | ||
1409 | |||
1410 | // try | ||
1411 | // { | ||
1412 | |||
1413 | m_eventManager.TriggerOnRegionStarted(this); | 1418 | m_eventManager.TriggerOnRegionStarted(this); |
1414 | 1419 | ||
1415 | // The first frame can take a very long time due to physics actors being added on startup. Therefore, | 1420 | // The first frame can take a very long time due to physics actors being added on startup. Therefore, |
@@ -1418,21 +1423,47 @@ namespace OpenSim.Region.Framework.Scenes | |||
1418 | Update(1); | 1423 | Update(1); |
1419 | 1424 | ||
1420 | Watchdog.StartThread( | 1425 | Watchdog.StartThread( |
1421 | Maintenance, string.Format("Maintenance ({0})", RegionInfo.RegionName), ThreadPriority.Normal, false, true); | 1426 | Maintenance, string.Format("Maintenance ({0})", RegionInfo.RegionName), ThreadPriority.Normal, false, true); |
1422 | 1427 | ||
1423 | Watchdog.GetCurrentThreadInfo().AlarmIfTimeout = true; | 1428 | Watchdog.GetCurrentThreadInfo().AlarmIfTimeout = true; |
1424 | Update(-1); | 1429 | m_lastFrameTick = Util.EnvironmentTickCount(); |
1425 | 1430 | ||
1426 | // m_lastUpdate = Util.EnvironmentTickCount(); | 1431 | if (UpdateOnTimer) |
1427 | // m_firstHeartbeat = false; | 1432 | { |
1428 | // } | 1433 | m_sceneUpdateTimer = new Timer(MinFrameTime * 1000); |
1429 | // finally | 1434 | m_sceneUpdateTimer.AutoReset = true; |
1430 | // { | 1435 | m_sceneUpdateTimer.Elapsed += Update; |
1431 | // Monitor.Pulse(m_heartbeatLock); | 1436 | m_sceneUpdateTimer.Start(); |
1432 | // Monitor.Exit(m_heartbeatLock); | 1437 | } |
1433 | // } | 1438 | else |
1439 | { | ||
1440 | Update(-1); | ||
1441 | Watchdog.RemoveThread(); | ||
1442 | m_isRunning = false; | ||
1443 | } | ||
1444 | } | ||
1434 | 1445 | ||
1435 | Watchdog.RemoveThread(); | 1446 | private volatile bool m_isTimerUpdateRunning; |
1447 | |||
1448 | private void Update(object sender, ElapsedEventArgs e) | ||
1449 | { | ||
1450 | if (m_isTimerUpdateRunning) | ||
1451 | return; | ||
1452 | |||
1453 | m_isTimerUpdateRunning = true; | ||
1454 | |||
1455 | // If the last frame did not complete on time, then immediately start the next update on the same thread | ||
1456 | // and ignore further timed updates until we have a frame that had spare time. | ||
1457 | while (!Update(1) && Active) {} | ||
1458 | |||
1459 | if (!Active || m_shuttingDown) | ||
1460 | { | ||
1461 | m_sceneUpdateTimer.Stop(); | ||
1462 | m_sceneUpdateTimer = null; | ||
1463 | m_isRunning = false; | ||
1464 | } | ||
1465 | |||
1466 | m_isTimerUpdateRunning = false; | ||
1436 | } | 1467 | } |
1437 | 1468 | ||
1438 | private void Maintenance() | 1469 | private void Maintenance() |
@@ -1502,7 +1533,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
1502 | } | 1533 | } |
1503 | } | 1534 | } |
1504 | 1535 | ||
1505 | public override void Update(int frames) | 1536 | public override bool Update(int frames) |
1506 | { | 1537 | { |
1507 | long? endFrame = null; | 1538 | long? endFrame = null; |
1508 | 1539 | ||
@@ -1511,7 +1542,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
1511 | 1542 | ||
1512 | float physicsFPS = 0f; | 1543 | float physicsFPS = 0f; |
1513 | int previousFrameTick, tmpMS; | 1544 | int previousFrameTick, tmpMS; |
1514 | int maintc = Util.EnvironmentTickCount(); | ||
1515 | 1545 | ||
1516 | while (!m_shuttingDown && ((endFrame == null && Active) || Frame < endFrame)) | 1546 | while (!m_shuttingDown && ((endFrame == null && Active) || Frame < endFrame)) |
1517 | { | 1547 | { |
@@ -1651,24 +1681,29 @@ namespace OpenSim.Region.Framework.Scenes | |||
1651 | } | 1681 | } |
1652 | 1682 | ||
1653 | EventManager.TriggerRegionHeartbeatEnd(this); | 1683 | EventManager.TriggerRegionHeartbeatEnd(this); |
1684 | otherMS = tempOnRezMS + eventMS + backupMS + terrainMS + landMS; | ||
1654 | 1685 | ||
1655 | Watchdog.UpdateThread(); | 1686 | if (!UpdateOnTimer) |
1687 | { | ||
1688 | Watchdog.UpdateThread(); | ||
1656 | 1689 | ||
1657 | previousFrameTick = m_lastFrameTick; | 1690 | tmpMS = Util.EnvironmentTickCountSubtract(Util.EnvironmentTickCount(), m_lastFrameTick); |
1658 | m_lastFrameTick = Util.EnvironmentTickCount(); | 1691 | tmpMS = (int)(MinFrameTime * 1000) - tmpMS; |
1659 | tmpMS = Util.EnvironmentTickCountSubtract(m_lastFrameTick, maintc); | ||
1660 | tmpMS = (int)(MinFrameTime * 1000) - tmpMS; | ||
1661 | 1692 | ||
1662 | if (tmpMS > 0) | 1693 | if (tmpMS > 0) |
1694 | { | ||
1695 | spareMS = tmpMS; | ||
1696 | Thread.Sleep(tmpMS); | ||
1697 | } | ||
1698 | } | ||
1699 | else | ||
1663 | { | 1700 | { |
1664 | Thread.Sleep(tmpMS); | 1701 | spareMS = Math.Max(0, (int)(MinFrameTime * 1000) - physicsMS2 - agentMS - physicsMS -otherMS); |
1665 | spareMS += tmpMS; | ||
1666 | } | 1702 | } |
1667 | 1703 | ||
1668 | frameMS = Util.EnvironmentTickCountSubtract(maintc); | 1704 | previousFrameTick = m_lastFrameTick; |
1669 | maintc = Util.EnvironmentTickCount(); | 1705 | frameMS = Util.EnvironmentTickCountSubtract(m_lastFrameTick); |
1670 | 1706 | m_lastFrameTick = Util.EnvironmentTickCount(); | |
1671 | otherMS = tempOnRezMS + eventMS + backupMS + terrainMS + landMS; | ||
1672 | 1707 | ||
1673 | // if (Frame%m_update_avatars == 0) | 1708 | // if (Frame%m_update_avatars == 0) |
1674 | // UpdateInWorldTime(); | 1709 | // UpdateInWorldTime(); |
@@ -1683,7 +1718,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
1683 | StatsReporter.AddSpareMS(spareMS); | 1718 | StatsReporter.AddSpareMS(spareMS); |
1684 | StatsReporter.addScriptLines(m_sceneGraph.GetScriptLPS()); | 1719 | StatsReporter.addScriptLines(m_sceneGraph.GetScriptLPS()); |
1685 | 1720 | ||
1686 | // Optionally warn if a frame takes double the amount of time that it should. | 1721 | // Optionally warn if a frame takes double the amount of time that it should. |
1687 | if (DebugUpdates | 1722 | if (DebugUpdates |
1688 | && Util.EnvironmentTickCountSubtract( | 1723 | && Util.EnvironmentTickCountSubtract( |
1689 | m_lastFrameTick, previousFrameTick) > (int)(MinFrameTime * 1000 * 2)) | 1724 | m_lastFrameTick, previousFrameTick) > (int)(MinFrameTime * 1000 * 2)) |
@@ -1693,6 +1728,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
1693 | MinFrameTime * 1000, | 1728 | MinFrameTime * 1000, |
1694 | RegionInfo.RegionName); | 1729 | RegionInfo.RegionName); |
1695 | } | 1730 | } |
1731 | |||
1732 | return spareMS >= 0; | ||
1696 | } | 1733 | } |
1697 | 1734 | ||
1698 | public void AddGroupTarget(SceneObjectGroup grp) | 1735 | public void AddGroupTarget(SceneObjectGroup grp) |
@@ -2073,8 +2110,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
2073 | SceneObjectPart target = GetSceneObjectPart(RayTargetID); | 2110 | SceneObjectPart target = GetSceneObjectPart(RayTargetID); |
2074 | 2111 | ||
2075 | Vector3 direction = Vector3.Normalize(RayEnd - RayStart); | 2112 | Vector3 direction = Vector3.Normalize(RayEnd - RayStart); |
2076 | Vector3 AXOrigin = new Vector3(RayStart.X, RayStart.Y, RayStart.Z); | 2113 | Vector3 AXOrigin = RayStart; |
2077 | Vector3 AXdirection = new Vector3(direction.X, direction.Y, direction.Z); | 2114 | Vector3 AXdirection = direction; |
2078 | 2115 | ||
2079 | if (target != null) | 2116 | if (target != null) |
2080 | { | 2117 | { |
@@ -2090,19 +2127,19 @@ namespace OpenSim.Region.Framework.Scenes | |||
2090 | EntityIntersection ei = target.TestIntersectionOBB(NewRay, Quaternion.Identity, frontFacesOnly, FaceCenter); | 2127 | EntityIntersection ei = target.TestIntersectionOBB(NewRay, Quaternion.Identity, frontFacesOnly, FaceCenter); |
2091 | 2128 | ||
2092 | // Un-comment out the following line to Get Raytrace results printed to the console. | 2129 | // Un-comment out the following line to Get Raytrace results printed to the console. |
2093 | // m_log.Info("[RAYTRACERESULTS]: Hit:" + ei.HitTF.ToString() + " Point: " + ei.ipoint.ToString() + " Normal: " + ei.normal.ToString()); | 2130 | // m_log.Info("[RAYTRACERESULTS]: Hit:" + ei.HitTF.ToString() + " Point: " + ei.ipoint.ToString() + " Normal: " + ei.normal.ToString()); |
2094 | float ScaleOffset = 0.5f; | 2131 | float ScaleOffset = 0.5f; |
2095 | 2132 | ||
2096 | // If we hit something | 2133 | // If we hit something |
2097 | if (ei.HitTF) | 2134 | if (ei.HitTF) |
2098 | { | 2135 | { |
2099 | Vector3 scaleComponent = new Vector3(ei.AAfaceNormal.X, ei.AAfaceNormal.Y, ei.AAfaceNormal.Z); | 2136 | Vector3 scaleComponent = ei.AAfaceNormal; |
2100 | if (scaleComponent.X != 0) ScaleOffset = scale.X; | 2137 | if (scaleComponent.X != 0) ScaleOffset = scale.X; |
2101 | if (scaleComponent.Y != 0) ScaleOffset = scale.Y; | 2138 | if (scaleComponent.Y != 0) ScaleOffset = scale.Y; |
2102 | if (scaleComponent.Z != 0) ScaleOffset = scale.Z; | 2139 | if (scaleComponent.Z != 0) ScaleOffset = scale.Z; |
2103 | ScaleOffset = Math.Abs(ScaleOffset); | 2140 | ScaleOffset = Math.Abs(ScaleOffset); |
2104 | Vector3 intersectionpoint = new Vector3(ei.ipoint.X, ei.ipoint.Y, ei.ipoint.Z); | 2141 | Vector3 intersectionpoint = ei.ipoint; |
2105 | Vector3 normal = new Vector3(ei.normal.X, ei.normal.Y, ei.normal.Z); | 2142 | Vector3 normal = ei.normal; |
2106 | // Set the position to the intersection point | 2143 | // Set the position to the intersection point |
2107 | Vector3 offset = (normal * (ScaleOffset / 2f)); | 2144 | Vector3 offset = (normal * (ScaleOffset / 2f)); |
2108 | pos = (intersectionpoint + offset); | 2145 | pos = (intersectionpoint + offset); |
@@ -2127,8 +2164,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
2127 | 2164 | ||
2128 | if (ei.HitTF) | 2165 | if (ei.HitTF) |
2129 | { | 2166 | { |
2130 | pos = new Vector3(ei.ipoint.X, ei.ipoint.Y, ei.ipoint.Z); | 2167 | pos = ei.ipoint; |
2131 | } else | 2168 | } |
2169 | else | ||
2132 | { | 2170 | { |
2133 | // fall back to our stupid functionality | 2171 | // fall back to our stupid functionality |
2134 | pos = RayEnd; | 2172 | pos = RayEnd; |
@@ -3181,8 +3219,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
3181 | if (target != null && target2 != null) | 3219 | if (target != null && target2 != null) |
3182 | { | 3220 | { |
3183 | Vector3 direction = Vector3.Normalize(RayEnd - RayStart); | 3221 | Vector3 direction = Vector3.Normalize(RayEnd - RayStart); |
3184 | Vector3 AXOrigin = new Vector3(RayStart.X, RayStart.Y, RayStart.Z); | 3222 | Vector3 AXOrigin = RayStart; |
3185 | Vector3 AXdirection = new Vector3(direction.X, direction.Y, direction.Z); | 3223 | Vector3 AXdirection = direction; |
3186 | 3224 | ||
3187 | pos = target2.AbsolutePosition; | 3225 | pos = target2.AbsolutePosition; |
3188 | //m_log.Info("[OBJECT_REZ]: TargetPos: " + pos.ToString() + ", RayStart: " + RayStart.ToString() + ", RayEnd: " + RayEnd.ToString() + ", Volume: " + Util.GetDistanceTo(RayStart,RayEnd).ToString() + ", mag1: " + Util.GetMagnitude(RayStart).ToString() + ", mag2: " + Util.GetMagnitude(RayEnd).ToString()); | 3226 | //m_log.Info("[OBJECT_REZ]: TargetPos: " + pos.ToString() + ", RayStart: " + RayStart.ToString() + ", RayEnd: " + RayEnd.ToString() + ", Volume: " + Util.GetDistanceTo(RayStart,RayEnd).ToString() + ", mag1: " + Util.GetMagnitude(RayStart).ToString() + ", mag2: " + Util.GetMagnitude(RayEnd).ToString()); |
@@ -3203,13 +3241,13 @@ namespace OpenSim.Region.Framework.Scenes | |||
3203 | if (ei.HitTF) | 3241 | if (ei.HitTF) |
3204 | { | 3242 | { |
3205 | Vector3 scale = target.Scale; | 3243 | Vector3 scale = target.Scale; |
3206 | Vector3 scaleComponent = new Vector3(ei.AAfaceNormal.X, ei.AAfaceNormal.Y, ei.AAfaceNormal.Z); | 3244 | Vector3 scaleComponent = ei.AAfaceNormal; |
3207 | if (scaleComponent.X != 0) ScaleOffset = scale.X; | 3245 | if (scaleComponent.X != 0) ScaleOffset = scale.X; |
3208 | if (scaleComponent.Y != 0) ScaleOffset = scale.Y; | 3246 | if (scaleComponent.Y != 0) ScaleOffset = scale.Y; |
3209 | if (scaleComponent.Z != 0) ScaleOffset = scale.Z; | 3247 | if (scaleComponent.Z != 0) ScaleOffset = scale.Z; |
3210 | ScaleOffset = Math.Abs(ScaleOffset); | 3248 | ScaleOffset = Math.Abs(ScaleOffset); |
3211 | Vector3 intersectionpoint = new Vector3(ei.ipoint.X, ei.ipoint.Y, ei.ipoint.Z); | 3249 | Vector3 intersectionpoint = ei.ipoint; |
3212 | Vector3 normal = new Vector3(ei.normal.X, ei.normal.Y, ei.normal.Z); | 3250 | Vector3 normal = ei.normal; |
3213 | Vector3 offset = normal * (ScaleOffset / 2f); | 3251 | Vector3 offset = normal * (ScaleOffset / 2f); |
3214 | pos = intersectionpoint + offset; | 3252 | pos = intersectionpoint + offset; |
3215 | 3253 | ||
@@ -3229,6 +3267,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
3229 | { | 3267 | { |
3230 | copy = m_sceneGraph.DuplicateObject(localID, pos, target.GetEffectiveObjectFlags(), AgentID, GroupID, Quaternion.Identity); | 3268 | copy = m_sceneGraph.DuplicateObject(localID, pos, target.GetEffectiveObjectFlags(), AgentID, GroupID, Quaternion.Identity); |
3231 | } | 3269 | } |
3270 | |||
3232 | if (copy != null) | 3271 | if (copy != null) |
3233 | EventManager.TriggerObjectAddedToScene(copy); | 3272 | EventManager.TriggerObjectAddedToScene(copy); |
3234 | } | 3273 | } |
@@ -5061,7 +5100,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
5061 | case PhysicsJointType.Ball: | 5100 | case PhysicsJointType.Ball: |
5062 | { | 5101 | { |
5063 | Vector3 jointAnchor = PhysicsScene.GetJointAnchor(joint); | 5102 | Vector3 jointAnchor = PhysicsScene.GetJointAnchor(joint); |
5064 | Vector3 proxyPos = new Vector3(jointAnchor.X, jointAnchor.Y, jointAnchor.Z); | 5103 | Vector3 proxyPos = jointAnchor; |
5065 | jointProxyObject.ParentGroup.UpdateGroupPosition(proxyPos); // schedules the entire group for a terse update | 5104 | jointProxyObject.ParentGroup.UpdateGroupPosition(proxyPos); // schedules the entire group for a terse update |
5066 | } | 5105 | } |
5067 | break; | 5106 | break; |
@@ -5086,7 +5125,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
5086 | jointErrorMessage(joint, "joint.TrackedBodyName is null, joint " + joint.ObjectNameInScene); | 5125 | jointErrorMessage(joint, "joint.TrackedBodyName is null, joint " + joint.ObjectNameInScene); |
5087 | } | 5126 | } |
5088 | 5127 | ||
5089 | Vector3 proxyPos = new Vector3(jointAnchor.X, jointAnchor.Y, jointAnchor.Z); | 5128 | Vector3 proxyPos = jointAnchor; |
5090 | Quaternion q = trackedBody.RotationOffset * joint.LocalRotation; | 5129 | Quaternion q = trackedBody.RotationOffset * joint.LocalRotation; |
5091 | 5130 | ||
5092 | jointProxyObject.ParentGroup.UpdateGroupPosition(proxyPos); // schedules the entire group for a terse update | 5131 | jointProxyObject.ParentGroup.UpdateGroupPosition(proxyPos); // schedules the entire group for a terse update |
@@ -5187,8 +5226,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
5187 | y = Heightmap.Height - 1; | 5226 | y = Heightmap.Height - 1; |
5188 | 5227 | ||
5189 | Vector3 p0 = new Vector3(x, y, (float)Heightmap[(int)x, (int)y]); | 5228 | Vector3 p0 = new Vector3(x, y, (float)Heightmap[(int)x, (int)y]); |
5190 | Vector3 p1 = new Vector3(p0); | 5229 | Vector3 p1 = p0; |
5191 | Vector3 p2 = new Vector3(p0); | 5230 | Vector3 p2 = p0; |
5192 | 5231 | ||
5193 | p1.X += 1.0f; | 5232 | p1.X += 1.0f; |
5194 | if (p1.X < Heightmap.Width) | 5233 | if (p1.X < Heightmap.Width) |