aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region
diff options
context:
space:
mode:
authorMelanie2010-03-18 20:09:04 +0000
committerMelanie2010-03-18 20:09:04 +0000
commit4c2a51b1b5e2169e0f336c56a023c35bcc334cbd (patch)
tree9fbaf708764f315034a283fd8fedc8afe0864d75 /OpenSim/Region
parentMerge branch 'careminster' into careminster-presence-refactor (diff)
parentFlesh out the new permission method (diff)
downloadopensim-SC_OLD-4c2a51b1b5e2169e0f336c56a023c35bcc334cbd.zip
opensim-SC_OLD-4c2a51b1b5e2169e0f336c56a023c35bcc334cbd.tar.gz
opensim-SC_OLD-4c2a51b1b5e2169e0f336c56a023c35bcc334cbd.tar.bz2
opensim-SC_OLD-4c2a51b1b5e2169e0f336c56a023c35bcc334cbd.tar.xz
Merge branch 'master' into careminster-presence-refactor
Diffstat (limited to 'OpenSim/Region')
-rwxr-xr-xOpenSim/Region/Application/OpenSim.cs2
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs2
-rw-r--r--OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs2
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Combat/CombatModule.cs77
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Dialog/DialogModule.cs30
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs4
-rw-r--r--OpenSim/Region/CoreModules/Framework/InventoryAccess/HGAssetMapper.cs4
-rw-r--r--OpenSim/Region/CoreModules/Scripting/DynamicTexture/DynamicTextureModule.cs20
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs5
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/RemoteSimulationConnector.cs5
-rw-r--r--OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequestPreparation.cs14
-rw-r--r--OpenSim/Region/CoreModules/World/Archiver/AssetsRequest.cs23
-rw-r--r--OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs6
-rw-r--r--OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs99
-rw-r--r--OpenSim/Region/CoreModules/World/WorldMap/MapImageModule.cs7
-rw-r--r--OpenSim/Region/DataSnapshot/ObjectSnapshot.cs62
-rw-r--r--OpenSim/Region/Framework/Scenes/Scene.cs69
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneGraph.cs193
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneManager.cs17
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs4
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectPart.cs82
-rw-r--r--OpenSim/Region/Framework/Scenes/ScenePresence.cs20
-rw-r--r--OpenSim/Region/Framework/Scenes/Tests/UuidGathererTests.cs4
-rw-r--r--OpenSim/Region/Framework/Scenes/UuidGatherer.cs48
-rw-r--r--OpenSim/Region/Physics/Meshing/PrimMesher.cs4402
-rw-r--r--OpenSim/Region/Physics/Meshing/SculptMesh.cs1290
-rw-r--r--OpenSim/Region/UserStatistics/ActiveConnectionsAJAX.cs2
27 files changed, 3313 insertions, 3180 deletions
diff --git a/OpenSim/Region/Application/OpenSim.cs b/OpenSim/Region/Application/OpenSim.cs
index 7e81650..38b2084 100755
--- a/OpenSim/Region/Application/OpenSim.cs
+++ b/OpenSim/Region/Application/OpenSim.cs
@@ -897,7 +897,7 @@ namespace OpenSim
897 { 897 {
898 connections.AppendFormat("{0}: {1} ({2}) from {3} on circuit {4}\n", 898 connections.AppendFormat("{0}: {1} ({2}) from {3} on circuit {4}\n",
899 scene.RegionInfo.RegionName, client.Name, client.AgentId, client.RemoteEndPoint, client.CircuitCode); 899 scene.RegionInfo.RegionName, client.Name, client.AgentId, client.RemoteEndPoint, client.CircuitCode);
900 }, false 900 }
901 ); 901 );
902 } 902 }
903 ); 903 );
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs
index 36d24e8..850474d 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs
@@ -1020,7 +1020,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1020 1020
1021 // Handle outgoing packets, resends, acknowledgements, and pings for each 1021 // Handle outgoing packets, resends, acknowledgements, and pings for each
1022 // client. m_packetSent will be set to true if a packet is sent 1022 // client. m_packetSent will be set to true if a packet is sent
1023 m_scene.ForEachClient(clientPacketHandler, false); 1023 m_scene.ForEachClient(clientPacketHandler);
1024 1024
1025 // If nothing was sent, sleep for the minimum amount of time before a 1025 // If nothing was sent, sleep for the minimum amount of time before a
1026 // token bucket could get more tokens 1026 // token bucket could get more tokens
diff --git a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs
index 967c0a1..37cdaae 100644
--- a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs
+++ b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs
@@ -642,7 +642,7 @@ namespace Flotsam.RegionModules.AssetCache
642 { 642 {
643 UuidGatherer gatherer = new UuidGatherer(m_AssetService); 643 UuidGatherer gatherer = new UuidGatherer(m_AssetService);
644 644
645 Dictionary<UUID, int> assets = new Dictionary<UUID, int>(); 645 Dictionary<UUID, AssetType> assets = new Dictionary<UUID, AssetType>();
646 foreach (Scene s in m_Scenes) 646 foreach (Scene s in m_Scenes)
647 { 647 {
648 StampRegionStatusFile(s.RegionInfo.RegionID); 648 StampRegionStatusFile(s.RegionInfo.RegionID);
diff --git a/OpenSim/Region/CoreModules/Avatar/Combat/CombatModule.cs b/OpenSim/Region/CoreModules/Avatar/Combat/CombatModule.cs
index 3614915..9df6074 100644
--- a/OpenSim/Region/CoreModules/Avatar/Combat/CombatModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Combat/CombatModule.cs
@@ -89,60 +89,57 @@ namespace OpenSim.Region.CoreModules.Avatar.Combat.CombatModule
89 get { return true; } 89 get { return true; }
90 } 90 }
91 91
92 private void KillAvatar(uint killerObjectLocalID, ScenePresence DeadAvatar) 92 private void KillAvatar(uint killerObjectLocalID, ScenePresence deadAvatar)
93 { 93 {
94 string deadAvatarMessage;
95 ScenePresence killingAvatar = null;
96 string killingAvatarMessage;
97
94 if (killerObjectLocalID == 0) 98 if (killerObjectLocalID == 0)
95 DeadAvatar.ControllingClient.SendAgentAlertMessage("You committed suicide!", true); 99 deadAvatarMessage = "You committed suicide!";
96 else 100 else
97 { 101 {
98 bool foundResult = false; 102 // Try to get the avatar responsible for the killing
99 string resultstring = String.Empty; 103 killingAvatar = deadAvatar.Scene.GetScenePresence(killerObjectLocalID);
100 ScenePresence[] allav = DeadAvatar.Scene.GetScenePresences(); 104 if (killingAvatar == null)
101 try
102 { 105 {
103 for (int i = 0; i < allav.Length; i++) 106 // Try to get the object which was responsible for the killing
107 SceneObjectPart part = deadAvatar.Scene.GetSceneObjectPart(killerObjectLocalID);
108 if (part == null)
104 { 109 {
105 ScenePresence av = allav[i]; 110 // Cause of death: Unknown
106 111 deadAvatarMessage = "You died!";
107 if (av.LocalId == killerObjectLocalID)
108 {
109 av.ControllingClient.SendAlertMessage("You fragged " + DeadAvatar.Firstname + " " + DeadAvatar.Lastname);
110 resultstring = av.Firstname + " " + av.Lastname;
111 foundResult = true;
112 }
113 } 112 }
114 } catch (InvalidOperationException) 113 else
115 {
116
117 }
118
119 if (!foundResult)
120 {
121 SceneObjectPart part = DeadAvatar.Scene.GetSceneObjectPart(killerObjectLocalID);
122 if (part != null)
123 { 114 {
124 ScenePresence av = DeadAvatar.Scene.GetScenePresence(part.OwnerID); 115 // Try to find the avatar wielding the killing object
125 if (av != null) 116 killingAvatar = deadAvatar.Scene.GetScenePresence(part.OwnerID);
126 { 117 if (killingAvatar == null)
127 av.ControllingClient.SendAlertMessage("You fragged " + DeadAvatar.Firstname + " " + DeadAvatar.Lastname); 118 deadAvatarMessage = String.Format("You impaled yourself on {0} owned by {1}!", part.Name, deadAvatar.Scene.GetUserName(part.OwnerID));
128 resultstring = av.Firstname + " " + av.Lastname;
129 DeadAvatar.ControllingClient.SendAgentAlertMessage("You got killed by " + resultstring + "!", true);
130 }
131 else 119 else
132 { 120 {
133 string killer = DeadAvatar.Scene.GetUserName(part.OwnerID); 121 killingAvatarMessage = String.Format("You fragged {0}!", deadAvatar.Name);
134 DeadAvatar.ControllingClient.SendAgentAlertMessage("You impaled yourself on " + part.Name + " owned by " + killer +"!", true); 122 deadAvatarMessage = String.Format("You got killed by {0}!", killingAvatar.Name);
135 } 123 }
136 //DeadAvatar.Scene. part.ObjectOwner
137 }
138 else
139 {
140 DeadAvatar.ControllingClient.SendAgentAlertMessage("You died!", true);
141 } 124 }
142 } 125 }
126 else
127 {
128 killingAvatarMessage = String.Format("You fragged {0}!", deadAvatar.Name);
129 deadAvatarMessage = String.Format("You got killed by {0}!", killingAvatar.Name);
130 }
143 } 131 }
144 DeadAvatar.Health = 100; 132 try
145 DeadAvatar.Scene.TeleportClientHome(DeadAvatar.UUID, DeadAvatar.ControllingClient); 133 {
134 deadAvatar.ControllingClient.SendAgentAlertMessage(deadAvatarMessage, true);
135 if(killingAvatar != null)
136 killingAvatar.ControllingClient.SendAlertMessage("You fragged " + deadAvatar.Firstname + " " + deadAvatar.Lastname);
137 }
138 catch (InvalidOperationException)
139 { }
140
141 deadAvatar.Health = 100;
142 deadAvatar.Scene.TeleportClientHome(deadAvatar.UUID, deadAvatar.ControllingClient);
146 } 143 }
147 144
148 private void AvatarEnteringParcel(ScenePresence avatar, int localLandID, UUID regionID) 145 private void AvatarEnteringParcel(ScenePresence avatar, int localLandID, UUID regionID)
diff --git a/OpenSim/Region/CoreModules/Avatar/Dialog/DialogModule.cs b/OpenSim/Region/CoreModules/Avatar/Dialog/DialogModule.cs
index b8e013c..c31266c 100644
--- a/OpenSim/Region/CoreModules/Avatar/Dialog/DialogModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Dialog/DialogModule.cs
@@ -87,31 +87,18 @@ namespace OpenSim.Region.CoreModules.Avatar.Dialog
87 87
88 public void SendAlertToUser(string firstName, string lastName, string message, bool modal) 88 public void SendAlertToUser(string firstName, string lastName, string message, bool modal)
89 { 89 {
90 ScenePresence[] presenceList = m_scene.GetScenePresences(); 90 ScenePresence presence = m_scene.GetScenePresence(firstName, lastName);
91 91 if(presence != null)
92 for (int i = 0; i < presenceList.Length; i++) 92 presence.ControllingClient.SendAgentAlertMessage(message, modal);
93 {
94 ScenePresence presence = presenceList[i];
95
96 if (presence.Firstname == firstName && presence.Lastname == lastName)
97 {
98 presence.ControllingClient.SendAgentAlertMessage(message, modal);
99 break;
100 }
101 }
102 } 93 }
103 94
104 public void SendGeneralAlert(string message) 95 public void SendGeneralAlert(string message)
105 { 96 {
106 ScenePresence[] presenceList = m_scene.GetScenePresences(); 97 m_scene.ForEachScenePresence(delegate(ScenePresence presence)
107
108 for (int i = 0; i < presenceList.Length; i++)
109 { 98 {
110 ScenePresence presence = presenceList[i];
111
112 if (!presence.IsChildAgent) 99 if (!presence.IsChildAgent)
113 presence.ControllingClient.SendAlertMessage(message); 100 presence.ControllingClient.SendAlertMessage(message);
114 } 101 });
115 } 102 }
116 103
117 public void SendDialogToUser( 104 public void SendDialogToUser(
@@ -179,14 +166,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Dialog
179 public void SendNotificationToUsersInRegion( 166 public void SendNotificationToUsersInRegion(
180 UUID fromAvatarID, string fromAvatarName, string message) 167 UUID fromAvatarID, string fromAvatarName, string message)
181 { 168 {
182 ScenePresence[] presences = m_scene.GetScenePresences(); 169 m_scene.ForEachScenePresence(delegate(ScenePresence presence)
183
184 for (int i = 0; i < presences.Length; i++)
185 { 170 {
186 ScenePresence presence = presences[i];
187 if (!presence.IsChildAgent) 171 if (!presence.IsChildAgent)
188 presence.ControllingClient.SendBlueBoxMessage(fromAvatarID, fromAvatarName, message); 172 presence.ControllingClient.SendBlueBoxMessage(fromAvatarID, fromAvatarName, message);
189 } 173 });
190 } 174 }
191 175
192 /// <summary> 176 /// <summary>
diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs
index ef10104..cfe3caa 100644
--- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs
@@ -73,7 +73,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
73 /// <value> 73 /// <value>
74 /// Used to collect the uuids of the assets that we need to save into the archive 74 /// Used to collect the uuids of the assets that we need to save into the archive
75 /// </value> 75 /// </value>
76 protected Dictionary<UUID, int> m_assetUuids = new Dictionary<UUID, int>(); 76 protected Dictionary<UUID, AssetType> m_assetUuids = new Dictionary<UUID, AssetType>();
77 77
78 /// <value> 78 /// <value>
79 /// Used to collect the uuids of the users that we need to save into the archive 79 /// Used to collect the uuids of the users that we need to save into the archive
@@ -305,7 +305,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
305 } 305 }
306 306
307 new AssetsRequest( 307 new AssetsRequest(
308 new AssetsArchiver(m_archiveWriter), m_assetUuids.Keys, 308 new AssetsArchiver(m_archiveWriter), m_assetUuids,
309 m_scene.AssetService, ReceivedAllAssets).Execute(); 309 m_scene.AssetService, ReceivedAllAssets).Execute();
310 } 310 }
311 311
diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGAssetMapper.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGAssetMapper.cs
index 664f38d..58ce550 100644
--- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGAssetMapper.cs
+++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGAssetMapper.cs
@@ -150,7 +150,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
150 if (asset != null) 150 if (asset != null)
151 { 151 {
152 // OK, now fetch the inside. 152 // OK, now fetch the inside.
153 Dictionary<UUID, int> ids = new Dictionary<UUID, int>(); 153 Dictionary<UUID, AssetType> ids = new Dictionary<UUID, AssetType>();
154 HGUuidGatherer uuidGatherer = new HGUuidGatherer(this, m_scene.AssetService, userAssetURL); 154 HGUuidGatherer uuidGatherer = new HGUuidGatherer(this, m_scene.AssetService, userAssetURL);
155 uuidGatherer.GatherAssetUuids(asset.FullID, (AssetType)asset.Type, ids); 155 uuidGatherer.GatherAssetUuids(asset.FullID, (AssetType)asset.Type, ids);
156 foreach (UUID uuid in ids.Keys) 156 foreach (UUID uuid in ids.Keys)
@@ -173,7 +173,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
173 AssetBase asset = m_scene.AssetService.Get(assetID.ToString()); 173 AssetBase asset = m_scene.AssetService.Get(assetID.ToString());
174 if (asset != null) 174 if (asset != null)
175 { 175 {
176 Dictionary<UUID, int> ids = new Dictionary<UUID, int>(); 176 Dictionary<UUID, AssetType> ids = new Dictionary<UUID, AssetType>();
177 HGUuidGatherer uuidGatherer = new HGUuidGatherer(this, m_scene.AssetService, string.Empty); 177 HGUuidGatherer uuidGatherer = new HGUuidGatherer(this, m_scene.AssetService, string.Empty);
178 uuidGatherer.GatherAssetUuids(asset.FullID, (AssetType)asset.Type, ids); 178 uuidGatherer.GatherAssetUuids(asset.FullID, (AssetType)asset.Type, ids);
179 foreach (UUID uuid in ids.Keys) 179 foreach (UUID uuid in ids.Keys)
diff --git a/OpenSim/Region/CoreModules/Scripting/DynamicTexture/DynamicTextureModule.cs b/OpenSim/Region/CoreModules/Scripting/DynamicTexture/DynamicTextureModule.cs
index 643764f..678e772 100644
--- a/OpenSim/Region/CoreModules/Scripting/DynamicTexture/DynamicTextureModule.cs
+++ b/OpenSim/Region/CoreModules/Scripting/DynamicTexture/DynamicTextureModule.cs
@@ -285,24 +285,22 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture
285 return; 285 return;
286 } 286 }
287 287
288 byte[] assetData; 288 byte[] assetData = null;
289 AssetBase oldAsset = null; 289 AssetBase oldAsset = null;
290 290
291 if (BlendWithOldTexture) 291 if (BlendWithOldTexture)
292 { 292 {
293 UUID lastTextureID = part.Shape.Textures.DefaultTexture.TextureID; 293 Primitive.TextureEntryFace defaultFace = part.Shape.Textures.DefaultTexture;
294 oldAsset = scene.AssetService.Get(lastTextureID.ToString()); 294 if (defaultFace != null)
295 if (oldAsset != null)
296 {
297 assetData = BlendTextures(data, oldAsset.Data, SetNewFrontAlpha, FrontAlpha);
298 }
299 else
300 { 295 {
301 assetData = new byte[data.Length]; 296 oldAsset = scene.AssetService.Get(defaultFace.TextureID.ToString());
302 Array.Copy(data, assetData, data.Length); 297
298 if (oldAsset != null)
299 assetData = BlendTextures(data, oldAsset.Data, SetNewFrontAlpha, FrontAlpha);
303 } 300 }
304 } 301 }
305 else 302
303 if (assetData == null)
306 { 304 {
307 assetData = new byte[data.Length]; 305 assetData = new byte[data.Length];
308 Array.Copy(data, assetData, data.Length); 306 Array.Copy(data, assetData, data.Length);
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs
index 783d606..e32dbb3 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs
@@ -166,6 +166,11 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation
166 return m_sceneList[0]; 166 return m_sceneList[0];
167 } 167 }
168 168
169 public ISimulationService GetInnerService()
170 {
171 return this;
172 }
173
169 /** 174 /**
170 * Agent-related communications 175 * Agent-related communications
171 */ 176 */
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/RemoteSimulationConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/RemoteSimulationConnector.cs
index 4d82a05..9e8454f 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/RemoteSimulationConnector.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/RemoteSimulationConnector.cs
@@ -156,6 +156,11 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation
156 return m_localBackend.GetScene(handle); 156 return m_localBackend.GetScene(handle);
157 } 157 }
158 158
159 public ISimulationService GetInnerService()
160 {
161 return m_localBackend;
162 }
163
159 /** 164 /**
160 * Agent-related communications 165 * Agent-related communications
161 */ 166 */
diff --git a/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequestPreparation.cs b/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequestPreparation.cs
index b61b341..b25636f 100644
--- a/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequestPreparation.cs
+++ b/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequestPreparation.cs
@@ -100,7 +100,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
100 /// <exception cref="System.IO.IOException">if there was an io problem with creating the file</exception> 100 /// <exception cref="System.IO.IOException">if there was an io problem with creating the file</exception>
101 public void ArchiveRegion() 101 public void ArchiveRegion()
102 { 102 {
103 Dictionary<UUID, int> assetUuids = new Dictionary<UUID, int>(); 103 Dictionary<UUID, AssetType> assetUuids = new Dictionary<UUID, AssetType>();
104 104
105 List<EntityBase> entities = m_scene.GetEntities(); 105 List<EntityBase> entities = m_scene.GetEntities();
106 List<SceneObjectGroup> sceneObjects = new List<SceneObjectGroup>(); 106 List<SceneObjectGroup> sceneObjects = new List<SceneObjectGroup>();
@@ -142,18 +142,18 @@ namespace OpenSim.Region.CoreModules.World.Archiver
142 142
143 // Make sure that we also request terrain texture assets 143 // Make sure that we also request terrain texture assets
144 RegionSettings regionSettings = m_scene.RegionInfo.RegionSettings; 144 RegionSettings regionSettings = m_scene.RegionInfo.RegionSettings;
145 145
146 if (regionSettings.TerrainTexture1 != RegionSettings.DEFAULT_TERRAIN_TEXTURE_1) 146 if (regionSettings.TerrainTexture1 != RegionSettings.DEFAULT_TERRAIN_TEXTURE_1)
147 assetUuids[regionSettings.TerrainTexture1] = 1; 147 assetUuids[regionSettings.TerrainTexture1] = AssetType.Texture;
148 148
149 if (regionSettings.TerrainTexture2 != RegionSettings.DEFAULT_TERRAIN_TEXTURE_2) 149 if (regionSettings.TerrainTexture2 != RegionSettings.DEFAULT_TERRAIN_TEXTURE_2)
150 assetUuids[regionSettings.TerrainTexture2] = 1; 150 assetUuids[regionSettings.TerrainTexture2] = AssetType.Texture;
151 151
152 if (regionSettings.TerrainTexture3 != RegionSettings.DEFAULT_TERRAIN_TEXTURE_3) 152 if (regionSettings.TerrainTexture3 != RegionSettings.DEFAULT_TERRAIN_TEXTURE_3)
153 assetUuids[regionSettings.TerrainTexture3] = 1; 153 assetUuids[regionSettings.TerrainTexture3] = AssetType.Texture;
154 154
155 if (regionSettings.TerrainTexture4 != RegionSettings.DEFAULT_TERRAIN_TEXTURE_4) 155 if (regionSettings.TerrainTexture4 != RegionSettings.DEFAULT_TERRAIN_TEXTURE_4)
156 assetUuids[regionSettings.TerrainTexture4] = 1; 156 assetUuids[regionSettings.TerrainTexture4] = AssetType.Texture;
157 157
158 TarArchiveWriter archiveWriter = new TarArchiveWriter(m_saveStream); 158 TarArchiveWriter archiveWriter = new TarArchiveWriter(m_saveStream);
159 159
@@ -168,7 +168,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
168 m_requestId); 168 m_requestId);
169 169
170 new AssetsRequest( 170 new AssetsRequest(
171 new AssetsArchiver(archiveWriter), assetUuids.Keys, 171 new AssetsArchiver(archiveWriter), assetUuids,
172 m_scene.AssetService, awre.ReceivedAllAssets).Execute(); 172 m_scene.AssetService, awre.ReceivedAllAssets).Execute();
173 } 173 }
174 } 174 }
diff --git a/OpenSim/Region/CoreModules/World/Archiver/AssetsRequest.cs b/OpenSim/Region/CoreModules/World/Archiver/AssetsRequest.cs
index c9fce91..4215f97 100644
--- a/OpenSim/Region/CoreModules/World/Archiver/AssetsRequest.cs
+++ b/OpenSim/Region/CoreModules/World/Archiver/AssetsRequest.cs
@@ -74,7 +74,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
74 /// <value> 74 /// <value>
75 /// uuids to request 75 /// uuids to request
76 /// </value> 76 /// </value>
77 protected ICollection<UUID> m_uuids; 77 protected IDictionary<UUID, AssetType> m_uuids;
78 78
79 /// <value> 79 /// <value>
80 /// Callback used when all the assets requested have been received. 80 /// Callback used when all the assets requested have been received.
@@ -104,7 +104,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
104 protected AssetsArchiver m_assetsArchiver; 104 protected AssetsArchiver m_assetsArchiver;
105 105
106 protected internal AssetsRequest( 106 protected internal AssetsRequest(
107 AssetsArchiver assetsArchiver, ICollection<UUID> uuids, 107 AssetsArchiver assetsArchiver, IDictionary<UUID, AssetType> uuids,
108 IAssetService assetService, AssetsRequestCallback assetsRequestCallback) 108 IAssetService assetService, AssetsRequestCallback assetsRequestCallback)
109 { 109 {
110 m_assetsArchiver = assetsArchiver; 110 m_assetsArchiver = assetsArchiver;
@@ -132,9 +132,9 @@ namespace OpenSim.Region.CoreModules.World.Archiver
132 return; 132 return;
133 } 133 }
134 134
135 foreach (UUID uuid in m_uuids) 135 foreach (KeyValuePair<UUID, AssetType> kvp in m_uuids)
136 { 136 {
137 m_assetService.Get(uuid.ToString(), this, AssetRequestCallback); 137 m_assetService.Get(kvp.Key.ToString(), kvp.Value, PreAssetRequestCallback);
138 } 138 }
139 139
140 m_requestCallbackTimer.Enabled = true; 140 m_requestCallbackTimer.Enabled = true;
@@ -157,7 +157,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
157 // Calculate which uuids were not found. This is an expensive way of doing it, but this is a failure 157 // Calculate which uuids were not found. This is an expensive way of doing it, but this is a failure
158 // case anyway. 158 // case anyway.
159 List<UUID> uuids = new List<UUID>(); 159 List<UUID> uuids = new List<UUID>();
160 foreach (UUID uuid in m_uuids) 160 foreach (UUID uuid in m_uuids.Keys)
161 { 161 {
162 uuids.Add(uuid); 162 uuids.Add(uuid);
163 } 163 }
@@ -200,6 +200,19 @@ namespace OpenSim.Region.CoreModules.World.Archiver
200 } 200 }
201 } 201 }
202 202
203 protected void PreAssetRequestCallback(string fetchedAssetID, object assetType, AssetBase fetchedAsset)
204 {
205 // Check for broken asset types and fix them with the AssetType gleaned by UuidGatherer
206 if (fetchedAsset != null && fetchedAsset.Type == (sbyte)AssetType.Unknown)
207 {
208 AssetType type = (AssetType)assetType;
209 m_log.InfoFormat("[ARCHIVER]: Rewriting broken asset type for {0} to {1}", fetchedAsset.ID, type);
210 fetchedAsset.Type = (sbyte)type;
211 }
212
213 AssetRequestCallback(fetchedAssetID, this, fetchedAsset);
214 }
215
203 /// <summary> 216 /// <summary>
204 /// Called back by the asset cache when it has the asset 217 /// Called back by the asset cache when it has the asset
205 /// </summary> 218 /// </summary>
diff --git a/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs
index e3bab2d..464d922 100644
--- a/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs
+++ b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs
@@ -469,12 +469,10 @@ namespace OpenSim.Region.CoreModules.World.Estate
469 private void handleEstateTeleportAllUsersHomeRequest(IClientAPI remover_client, UUID invoice, UUID senderID) 469 private void handleEstateTeleportAllUsersHomeRequest(IClientAPI remover_client, UUID invoice, UUID senderID)
470 { 470 {
471 // Get a fresh list that will not change as people get teleported away 471 // Get a fresh list that will not change as people get teleported away
472 ScenePresence[] presences = m_scene.GetScenePresences(); 472 List<ScenePresence> presences = m_scene.GetScenePresences();
473 473
474 for (int i = 0; i < presences.Length; i++) 474 foreach(ScenePresence p in presences)
475 { 475 {
476 ScenePresence p = presences[i];
477
478 if (p.UUID != senderID) 476 if (p.UUID != senderID)
479 { 477 {
480 // make sure they are still there, we could be working down a long list 478 // make sure they are still there, we could be working down a long list
diff --git a/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs b/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs
index 38fc250..4dbdb01 100644
--- a/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs
+++ b/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs
@@ -1276,13 +1276,104 @@ namespace OpenSim.Region.CoreModules.World.Permissions
1276 1276
1277 private bool CanReturnObjects(ILandObject land, UUID user, List<SceneObjectGroup> objects, Scene scene) 1277 private bool CanReturnObjects(ILandObject land, UUID user, List<SceneObjectGroup> objects, Scene scene)
1278 { 1278 {
1279 if (objects.Count == 0)
1280 return false;
1281
1282 DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name); 1279 DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name);
1283 if (m_bypassPermissions) return m_bypassPermissionsValue; 1280 if (m_bypassPermissions) return m_bypassPermissionsValue;
1284 1281
1285 return GenericObjectPermission(user, objects[0].UUID, false); 1282 GroupPowers powers;
1283 ILandObject l;
1284
1285 ScenePresence sp = scene.GetScenePresence(user);
1286 if (sp == null)
1287 return false;
1288
1289 IClientAPI client = sp.ControllingClient;
1290
1291 foreach (SceneObjectGroup g in new List<SceneObjectGroup>(objects))
1292 {
1293 // Any user can return their own objects at any time
1294 //
1295 if (GenericObjectPermission(user, g.UUID, false))
1296 continue;
1297
1298 // This is a short cut for efficiency. If land is non-null,
1299 // then all objects are on that parcel and we can save
1300 // ourselves the checking for each prim. Much faster.
1301 //
1302 if (land != null)
1303 {
1304 l = land;
1305 }
1306 else
1307 {
1308 Vector3 pos = g.AbsolutePosition;
1309
1310 l = scene.LandChannel.GetLandObject(pos.X, pos.Y);
1311 }
1312
1313 // If it's not over any land, then we can't do a thing
1314 if (l == null)
1315 {
1316 objects.Remove(g);
1317 continue;
1318 }
1319
1320 // If we own the land outright, then allow
1321 //
1322 if (l.LandData.OwnerID == user)
1323 continue;
1324
1325 // Group voodoo
1326 //
1327 if (land.LandData.IsGroupOwned)
1328 {
1329 powers = (GroupPowers)client.GetGroupPowers(land.LandData.GroupID);
1330 // Not a group member, or no rights at all
1331 //
1332 if (powers == (GroupPowers)0)
1333 {
1334 objects.Remove(g);
1335 continue;
1336 }
1337
1338 // Group deeded object?
1339 //
1340 if (g.OwnerID == l.LandData.GroupID &&
1341 (powers & GroupPowers.ReturnGroupOwned) == (GroupPowers)0)
1342 {
1343 objects.Remove(g);
1344 continue;
1345 }
1346
1347 // Group set object?
1348 //
1349 if (g.GroupID == l.LandData.GroupID &&
1350 (powers & GroupPowers.ReturnGroupSet) == (GroupPowers)0)
1351 {
1352 objects.Remove(g);
1353 continue;
1354 }
1355
1356 if ((powers & GroupPowers.ReturnNonGroup) == (GroupPowers)0)
1357 {
1358 objects.Remove(g);
1359 continue;
1360 }
1361
1362 // So we can remove all objects from this group land.
1363 // Fine.
1364 //
1365 continue;
1366 }
1367
1368 // By default, we can't remove
1369 //
1370 objects.Remove(g);
1371 }
1372
1373 if (objects.Count == 0)
1374 return false;
1375
1376 return true;
1286 } 1377 }
1287 1378
1288 private bool CanRezObject(int objectCount, UUID owner, Vector3 objectPosition, Scene scene) 1379 private bool CanRezObject(int objectCount, UUID owner, Vector3 objectPosition, Scene scene)
diff --git a/OpenSim/Region/CoreModules/World/WorldMap/MapImageModule.cs b/OpenSim/Region/CoreModules/World/WorldMap/MapImageModule.cs
index 285d36a..b71b5f6 100644
--- a/OpenSim/Region/CoreModules/World/WorldMap/MapImageModule.cs
+++ b/OpenSim/Region/CoreModules/World/WorldMap/MapImageModule.cs
@@ -251,13 +251,12 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
251 // if you want tree blocks on the map comment the above line and uncomment the below line 251 // if you want tree blocks on the map comment the above line and uncomment the below line
252 //mapdotspot = Color.PaleGreen; 252 //mapdotspot = Color.PaleGreen;
253 253
254 if (part.Shape.Textures == null) 254 Primitive.TextureEntry textureEntry = part.Shape.Textures;
255 continue;
256 255
257 if (part.Shape.Textures.DefaultTexture == null) 256 if (textureEntry == null || textureEntry.DefaultTexture == null)
258 continue; 257 continue;
259 258
260 Color4 texcolor = part.Shape.Textures.DefaultTexture.RGBA; 259 Color4 texcolor = textureEntry.DefaultTexture.RGBA;
261 260
262 // Not sure why some of these are null, oh well. 261 // Not sure why some of these are null, oh well.
263 262
diff --git a/OpenSim/Region/DataSnapshot/ObjectSnapshot.cs b/OpenSim/Region/DataSnapshot/ObjectSnapshot.cs
index 76dac61..f441aa9 100644
--- a/OpenSim/Region/DataSnapshot/ObjectSnapshot.cs
+++ b/OpenSim/Region/DataSnapshot/ObjectSnapshot.cs
@@ -203,44 +203,54 @@ namespace OpenSim.Region.DataSnapshot.Providers
203 { 203 {
204 string bestguess = string.Empty; 204 string bestguess = string.Empty;
205 Dictionary<UUID, int> counts = new Dictionary<UUID, int>(); 205 Dictionary<UUID, int> counts = new Dictionary<UUID, int>();
206 if (sog.RootPart.Shape != null && sog.RootPart.Shape.ProfileShape == ProfileShape.Square && 206
207 sog.RootPart.Shape.Textures != null && sog.RootPart.Shape.Textures.FaceTextures != null) 207 PrimitiveBaseShape shape = sog.RootPart.Shape;
208 if (shape != null && shape.ProfileShape == ProfileShape.Square)
208 { 209 {
209 if (sog.RootPart.Shape.Textures.DefaultTexture.TextureID != UUID.Zero && 210 Primitive.TextureEntry textures = shape.Textures;
210 sog.RootPart.Shape.Textures.DefaultTexture.TextureID != m_DefaultImage && 211 if (textures != null)
211 sog.RootPart.Shape.Textures.DefaultTexture.TextureID != m_BlankImage &&
212 sog.RootPart.Shape.Textures.DefaultTexture.RGBA.A < 50)
213 { 212 {
214 counts[sog.RootPart.Shape.Textures.DefaultTexture.TextureID] = 8; 213 if (textures.DefaultTexture != null &&
215 } 214 textures.DefaultTexture.TextureID != UUID.Zero &&
215 textures.DefaultTexture.TextureID != m_DefaultImage &&
216 textures.DefaultTexture.TextureID != m_BlankImage &&
217 textures.DefaultTexture.RGBA.A < 50f)
218 {
219 counts[textures.DefaultTexture.TextureID] = 8;
220 }
216 221
217 foreach (Primitive.TextureEntryFace tentry in sog.RootPart.Shape.Textures.FaceTextures) 222 if (textures.FaceTextures != null)
218 {
219 if (tentry != null)
220 { 223 {
221 if (tentry.TextureID != UUID.Zero && tentry.TextureID != m_DefaultImage && tentry.TextureID != m_BlankImage && tentry.RGBA.A < 50) 224 foreach (Primitive.TextureEntryFace tentry in textures.FaceTextures)
222 { 225 {
223 int c = 0; 226 if (tentry != null)
224 counts.TryGetValue(tentry.TextureID, out c); 227 {
225 counts[tentry.TextureID] = c + 1; 228 if (tentry.TextureID != UUID.Zero && tentry.TextureID != m_DefaultImage && tentry.TextureID != m_BlankImage && tentry.RGBA.A < 50)
226 // decrease the default texture count 229 {
227 if (counts.ContainsKey(sog.RootPart.Shape.Textures.DefaultTexture.TextureID)) 230 int c = 0;
228 counts[sog.RootPart.Shape.Textures.DefaultTexture.TextureID] = counts[sog.RootPart.Shape.Textures.DefaultTexture.TextureID] - 1; 231 counts.TryGetValue(tentry.TextureID, out c);
232 counts[tentry.TextureID] = c + 1;
233 // decrease the default texture count
234 if (counts.ContainsKey(textures.DefaultTexture.TextureID))
235 counts[textures.DefaultTexture.TextureID] = counts[textures.DefaultTexture.TextureID] - 1;
236 }
237 }
229 } 238 }
230 } 239 }
231 }
232 240
233 // Let's pick the most unique texture 241 // Let's pick the most unique texture
234 int min = 9999; 242 int min = 9999;
235 foreach (KeyValuePair<UUID, int> kv in counts) 243 foreach (KeyValuePair<UUID, int> kv in counts)
236 {
237 if (kv.Value < min && kv.Value >= 1)
238 { 244 {
239 bestguess = kv.Key.ToString(); 245 if (kv.Value < min && kv.Value >= 1)
240 min = kv.Value; 246 {
247 bestguess = kv.Key.ToString();
248 min = kv.Value;
249 }
241 } 250 }
242 } 251 }
243 } 252 }
253
244 return bestguess; 254 return bestguess;
245 } 255 }
246 } 256 }
diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs
index 03f1ee2..b2c8dfd 100644
--- a/OpenSim/Region/Framework/Scenes/Scene.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.cs
@@ -131,7 +131,6 @@ namespace OpenSim.Region.Framework.Scenes
131 private readonly Timer m_restartTimer = new Timer(15000); // Wait before firing 131 private readonly Timer m_restartTimer = new Timer(15000); // Wait before firing
132 private int m_incrementsof15seconds; 132 private int m_incrementsof15seconds;
133 private volatile bool m_backingup; 133 private volatile bool m_backingup;
134 private bool m_useAsyncWhenPossible;
135 134
136 private Dictionary<UUID, ReturnInfo> m_returns = new Dictionary<UUID, ReturnInfo>(); 135 private Dictionary<UUID, ReturnInfo> m_returns = new Dictionary<UUID, ReturnInfo>();
137 private Dictionary<UUID, SceneObjectGroup> m_groupsWithTargets = new Dictionary<UUID, SceneObjectGroup>(); 136 private Dictionary<UUID, SceneObjectGroup> m_groupsWithTargets = new Dictionary<UUID, SceneObjectGroup>();
@@ -656,9 +655,6 @@ namespace OpenSim.Region.Framework.Scenes
656 // 655 //
657 IConfig startupConfig = m_config.Configs["Startup"]; 656 IConfig startupConfig = m_config.Configs["Startup"];
658 657
659 // Should we try to run loops synchronously or asynchronously?
660 m_useAsyncWhenPossible = startupConfig.GetBoolean("use_async_when_possible", false);
661
662 //Animation states 658 //Animation states
663 m_useFlySlow = startupConfig.GetBoolean("enableflyslow", false); 659 m_useFlySlow = startupConfig.GetBoolean("enableflyslow", false);
664 // TODO: Change default to true once the feature is supported 660 // TODO: Change default to true once the feature is supported
@@ -3636,9 +3632,7 @@ namespace OpenSim.Region.Framework.Scenes
3636 public virtual void AgentCrossing(UUID agentID, Vector3 position, bool isFlying) 3632 public virtual void AgentCrossing(UUID agentID, Vector3 position, bool isFlying)
3637 { 3633 {
3638 ScenePresence presence; 3634 ScenePresence presence;
3639 m_sceneGraph.TryGetAvatar(agentID, out presence); 3635 if(m_sceneGraph.TryGetAvatar(agentID, out presence))
3640
3641 if (presence != null)
3642 { 3636 {
3643 try 3637 try
3644 { 3638 {
@@ -3813,9 +3807,7 @@ namespace OpenSim.Region.Framework.Scenes
3813 Vector3 lookAt, uint teleportFlags) 3807 Vector3 lookAt, uint teleportFlags)
3814 { 3808 {
3815 ScenePresence sp; 3809 ScenePresence sp;
3816 m_sceneGraph.TryGetAvatar(remoteClient.AgentId, out sp); 3810 if(m_sceneGraph.TryGetAvatar(remoteClient.AgentId, out sp))
3817
3818 if (sp != null)
3819 { 3811 {
3820 uint regionX = m_regInfo.RegionLocX; 3812 uint regionX = m_regInfo.RegionLocX;
3821 uint regionY = m_regInfo.RegionLocY; 3813 uint regionY = m_regInfo.RegionLocY;
@@ -4171,6 +4163,11 @@ namespace OpenSim.Region.Framework.Scenes
4171 4163
4172 //The idea is to have a group of method that return a list of avatars meeting some requirement 4164 //The idea is to have a group of method that return a list of avatars meeting some requirement
4173 // ie it could be all m_scenePresences within a certain range of the calling prim/avatar. 4165 // ie it could be all m_scenePresences within a certain range of the calling prim/avatar.
4166 //
4167 // GetAvatars returns a new list of all root agent presences in the scene
4168 // GetScenePresences returns a new list of all presences in the scene or a filter may be passed.
4169 // GetScenePresence returns the presence with matching UUID or first/last name.
4170 // ForEachScenePresence requests the Scene to run a delegate function against all presences.
4174 4171
4175 /// <summary> 4172 /// <summary>
4176 /// Return a list of all avatars in this region. 4173 /// Return a list of all avatars in this region.
@@ -4187,7 +4184,7 @@ namespace OpenSim.Region.Framework.Scenes
4187 /// This list is a new object, so it can be iterated over without locking. 4184 /// This list is a new object, so it can be iterated over without locking.
4188 /// </summary> 4185 /// </summary>
4189 /// <returns></returns> 4186 /// <returns></returns>
4190 public ScenePresence[] GetScenePresences() 4187 public List<ScenePresence> GetScenePresences()
4191 { 4188 {
4192 return m_sceneGraph.GetScenePresences(); 4189 return m_sceneGraph.GetScenePresences();
4193 } 4190 }
@@ -4213,6 +4210,28 @@ namespace OpenSim.Region.Framework.Scenes
4213 return m_sceneGraph.GetScenePresence(avatarID); 4210 return m_sceneGraph.GetScenePresence(avatarID);
4214 } 4211 }
4215 4212
4213 /// <summary>
4214 /// Request the ScenePresence in this region by first/last name.
4215 /// Should normally only be a single match, but first is always returned
4216 /// </summary>
4217 /// <param name="firstName"></param>
4218 /// <param name="lastName"></param>
4219 /// <returns></returns>
4220 public ScenePresence GetScenePresence(string firstName, string lastName)
4221 {
4222 return m_sceneGraph.GetScenePresence(firstName, lastName);
4223 }
4224
4225 /// <summary>
4226 /// Request the ScenePresence in this region by localID.
4227 /// </summary>
4228 /// <param name="localID"></param>
4229 /// <returns></returns>
4230 public ScenePresence GetScenePresence(uint localID)
4231 {
4232 return m_sceneGraph.GetScenePresence(localID);
4233 }
4234
4216 public override bool PresenceChildStatus(UUID avatarID) 4235 public override bool PresenceChildStatus(UUID avatarID)
4217 { 4236 {
4218 ScenePresence cp = GetScenePresence(avatarID); 4237 ScenePresence cp = GetScenePresence(avatarID);
@@ -4228,25 +4247,14 @@ namespace OpenSim.Region.Framework.Scenes
4228 } 4247 }
4229 4248
4230 /// <summary> 4249 /// <summary>
4231 /// 4250 /// Performs action on all scene presences.
4232 /// </summary> 4251 /// </summary>
4233 /// <param name="action"></param> 4252 /// <param name="action"></param>
4234 public void ForEachScenePresence(Action<ScenePresence> action) 4253 public void ForEachScenePresence(Action<ScenePresence> action)
4235 { 4254 {
4236 // We don't want to try to send messages if there are no avatars.
4237 if (m_sceneGraph != null) 4255 if (m_sceneGraph != null)
4238 { 4256 {
4239 try 4257 m_sceneGraph.ForEachScenePresence(action);
4240 {
4241 ScenePresence[] presences = GetScenePresences();
4242 for (int i = 0; i < presences.Length; i++)
4243 action(presences[i]);
4244 }
4245 catch (Exception e)
4246 {
4247 m_log.Info("[BUG] in " + RegionInfo.RegionName + ": " + e.ToString());
4248 m_log.Info("[BUG] Stack Trace: " + e.StackTrace);
4249 }
4250 } 4258 }
4251 } 4259 }
4252 4260
@@ -4322,20 +4330,7 @@ namespace OpenSim.Region.Framework.Scenes
4322 4330
4323 public void ForEachClient(Action<IClientAPI> action) 4331 public void ForEachClient(Action<IClientAPI> action)
4324 { 4332 {
4325 ForEachClient(action, m_useAsyncWhenPossible);
4326 }
4327
4328 public void ForEachClient(Action<IClientAPI> action, bool doAsynchronous)
4329 {
4330 // FIXME: Asynchronous iteration is disabled until we have a threading model that
4331 // can support calling this function from an async packet handler without
4332 // potentially deadlocking
4333 m_clientManager.ForEachSync(action); 4333 m_clientManager.ForEachSync(action);
4334
4335 //if (doAsynchronous)
4336 // m_clientManager.ForEach(action);
4337 //else
4338 // m_clientManager.ForEachSync(action);
4339 } 4334 }
4340 4335
4341 public bool TryGetClient(UUID avatarID, out IClientAPI client) 4336 public bool TryGetClient(UUID avatarID, out IClientAPI client)
diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs
index db70d6a..19298d2 100644
--- a/OpenSim/Region/Framework/Scenes/SceneGraph.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneGraph.cs
@@ -165,9 +165,10 @@ namespace OpenSim.Region.Framework.Scenes
165 165
166 protected internal void UpdatePresences() 166 protected internal void UpdatePresences()
167 { 167 {
168 ScenePresence[] updateScenePresences = GetScenePresences(); 168 ForEachScenePresence(delegate(ScenePresence presence)
169 for (int i = 0; i < updateScenePresences.Length; i++) 169 {
170 updateScenePresences[i].Update(); 170 presence.Update();
171 });
171 } 172 }
172 173
173 protected internal float UpdatePhysics(double elapsed) 174 protected internal float UpdatePhysics(double elapsed)
@@ -196,9 +197,10 @@ namespace OpenSim.Region.Framework.Scenes
196 197
197 protected internal void UpdateScenePresenceMovement() 198 protected internal void UpdateScenePresenceMovement()
198 { 199 {
199 ScenePresence[] moveEntities = GetScenePresences(); 200 ForEachScenePresence(delegate(ScenePresence presence)
200 for (int i = 0; i < moveEntities.Length; i++) 201 {
201 moveEntities[i].UpdateMovement(); 202 presence.UpdateMovement();
203 });
202 } 204 }
203 205
204 #endregion 206 #endregion
@@ -640,18 +642,16 @@ namespace OpenSim.Region.Framework.Scenes
640 642
641 public void RecalculateStats() 643 public void RecalculateStats()
642 { 644 {
643 ScenePresence[] presences = GetScenePresences();
644 int rootcount = 0; 645 int rootcount = 0;
645 int childcount = 0; 646 int childcount = 0;
646 647
647 for (int i = 0; i < presences.Length; i++) 648 ForEachScenePresence(delegate(ScenePresence presence)
648 { 649 {
649 ScenePresence user = presences[i]; 650 if (presence.IsChildAgent)
650 if (user.IsChildAgent)
651 ++childcount; 651 ++childcount;
652 else 652 else
653 ++rootcount; 653 ++rootcount;
654 } 654 });
655 655
656 m_numRootAgents = rootcount; 656 m_numRootAgents = rootcount;
657 m_numChildAgents = childcount; 657 m_numChildAgents = childcount;
@@ -698,25 +698,6 @@ namespace OpenSim.Region.Framework.Scenes
698 #endregion 698 #endregion
699 699
700 #region Get Methods 700 #region Get Methods
701
702 /// <summary>
703 /// Request a List of all scene presences in this scene. This is a new list, so no
704 /// locking is required to iterate over it.
705 /// </summary>
706 /// <returns></returns>
707 protected internal ScenePresence[] GetScenePresences()
708 {
709 return m_scenePresenceArray;
710 }
711
712 protected internal List<ScenePresence> GetAvatars()
713 {
714 List<ScenePresence> result =
715 GetScenePresences(delegate(ScenePresence scenePresence) { return !scenePresence.IsChildAgent; });
716
717 return result;
718 }
719
720 /// <summary> 701 /// <summary>
721 /// Get the controlling client for the given avatar, if there is one. 702 /// Get the controlling client for the given avatar, if there is one.
722 /// 703 ///
@@ -742,45 +723,119 @@ namespace OpenSim.Region.Framework.Scenes
742 return null; 723 return null;
743 } 724 }
744 725
726 // The idea is to have a group of method that return a list of avatars meeting some requirement
727 // ie it could be all m_scenePresences within a certain range of the calling prim/avatar.
728 //
729 // GetAvatars returns a new list of all root agent presences in the scene
730 // GetScenePresences returns a new list of all presences in the scene or a filter may be passed.
731 // GetScenePresence returns the presence with matching UUID or the first presence matching the passed filter.
732 // ForEachScenePresence requests the Scene to run a delegate function against all presences.
733
734 /// <summary>
735 /// Request a list of all avatars in this region (no child agents)
736 /// This list is a new object, so it can be iterated over without locking.
737 /// </summary>
738 /// <returns></returns>
739 public List<ScenePresence> GetAvatars()
740 {
741 return GetScenePresences(delegate(ScenePresence scenePresence)
742 {
743 return !scenePresence.IsChildAgent;
744 });
745 }
746
747 /// <summary>
748 /// Request a list of m_scenePresences in this World
749 /// Returns a copy so it can be iterated without a lock.
750 /// There is no guarantee that presences will remain in the scene after the list is returned.
751 /// </summary>
752 /// <returns></returns>
753 protected internal List<ScenePresence> GetScenePresences()
754 {
755 List<ScenePresence> result;
756 lock (m_scenePresences)
757 {
758 result = new List<ScenePresence>(m_scenePresenceArray.Length);
759 result.AddRange(m_scenePresenceArray);
760 }
761 return result;
762 }
763
745 /// <summary> 764 /// <summary>
746 /// Request a filtered list of m_scenePresences in this World 765 /// Request a filtered list of m_scenePresences in this World
766 /// Returns a copy so it can be iterated without a lock.
767 /// There is no guarantee that presences will remain in the scene after the list is returned.
747 /// </summary> 768 /// </summary>
748 /// <returns></returns> 769 /// <returns></returns>
749 protected internal List<ScenePresence> GetScenePresences(FilterAvatarList filter) 770 protected internal List<ScenePresence> GetScenePresences(FilterAvatarList filter)
750 { 771 {
751 // No locking of scene presences here since we're passing back a list...
752
753 List<ScenePresence> result = new List<ScenePresence>(); 772 List<ScenePresence> result = new List<ScenePresence>();
754 ScenePresence[] scenePresences = GetScenePresences(); 773 // Check each ScenePresence against the filter
774 ForEachScenePresence(delegate(ScenePresence presence)
775 {
776 if (filter(presence))
777 result.Add(presence);
778 });
779 return result;
780 }
755 781
756 for (int i = 0; i < scenePresences.Length; i++) 782 /// <summary>
783 /// Request the ScenePresence in this region matching filter.
784 /// Only the first match is returned.
785 ///
786 /// </summary>
787 /// <param name="filter"></param>
788 /// <returns></returns>
789 protected internal ScenePresence GetScenePresence(FilterAvatarList filter)
790 {
791 ScenePresence result = null;
792 // Get all of the ScenePresences
793 List<ScenePresence> presences = GetScenePresences();
794 foreach (ScenePresence presence in presences)
757 { 795 {
758 ScenePresence avatar = scenePresences[i]; 796 if (filter(presence))
759 if (filter(avatar)) 797 {
760 result.Add(avatar); 798 result = presence;
799 break;
800 }
761 } 801 }
762
763 return result; 802 return result;
764 } 803 }
765 804
805 protected internal ScenePresence GetScenePresence(string firstName, string lastName)
806 {
807 return GetScenePresence(delegate(ScenePresence presence)
808 {
809 return(presence.Firstname == firstName && presence.Lastname == lastName);
810 });
811 }
812
766 /// <summary> 813 /// <summary>
767 /// Request a scene presence by UUID 814 /// Request a scene presence by UUID
768 /// </summary> 815 /// </summary>
769 /// <param name="avatarID"></param> 816 /// <param name="agentID"></param>
770 /// <returns>null if the agent was not found</returns> 817 /// <returns>null if the agent was not found</returns>
771 protected internal ScenePresence GetScenePresence(UUID agentID) 818 protected internal ScenePresence GetScenePresence(UUID agentID)
772 { 819 {
773 ScenePresence sp; 820 ScenePresence sp;
774 821 TryGetAvatar(agentID, out sp);
775 lock (m_scenePresences)
776 {
777 m_scenePresences.TryGetValue(agentID, out sp);
778 }
779
780 return sp; 822 return sp;
781 } 823 }
782 824
783 /// <summary> 825 /// <summary>
826 /// Request the ScenePresence in this region by localID.
827 /// </summary>
828 /// <param name="localID"></param>
829 /// <returns></returns>
830 protected internal ScenePresence GetScenePresence(uint localID)
831 {
832 return GetScenePresence(delegate(ScenePresence presence)
833 {
834 return (presence.LocalId == localID);
835 });
836 }
837
838 /// <summary>
784 /// Get a scene object group that contains the prim with the given local id 839 /// Get a scene object group that contains the prim with the given local id
785 /// </summary> 840 /// </summary>
786 /// <param name="localID"></param> 841 /// <param name="localID"></param>
@@ -934,29 +989,19 @@ namespace OpenSim.Region.Framework.Scenes
934 protected internal bool TryGetAvatar(UUID avatarId, out ScenePresence avatar) 989 protected internal bool TryGetAvatar(UUID avatarId, out ScenePresence avatar)
935 { 990 {
936 lock (m_scenePresences) 991 lock (m_scenePresences)
937 return m_scenePresences.TryGetValue(avatarId, out avatar); 992 {
993 m_scenePresences.TryGetValue(avatarId, out avatar);
994 }
995 return (avatar != null);
938 } 996 }
939 997
940 protected internal bool TryGetAvatarByName(string avatarName, out ScenePresence avatar) 998 protected internal bool TryGetAvatarByName(string avatarName, out ScenePresence avatar)
941 { 999 {
942 ScenePresence[] presences = GetScenePresences(); 1000 avatar = GetScenePresence(delegate(ScenePresence presence)
943
944 for (int i = 0; i < presences.Length; i++)
945 { 1001 {
946 ScenePresence presence = presences[i]; 1002 return (String.Compare(avatarName, presence.ControllingClient.Name, true) == 0);
947 1003 });
948 if (!presence.IsChildAgent) 1004 return (avatar != null);
949 {
950 if (String.Compare(avatarName, presence.ControllingClient.Name, true) == 0)
951 {
952 avatar = presence;
953 return true;
954 }
955 }
956 }
957
958 avatar = null;
959 return false;
960 } 1005 }
961 1006
962 /// <summary> 1007 /// <summary>
@@ -1037,6 +1082,28 @@ namespace OpenSim.Region.Framework.Scenes
1037 } 1082 }
1038 } 1083 }
1039 } 1084 }
1085
1086
1087 /// <summary>
1088 /// Performs action on all scene presences.
1089 /// </summary>
1090 /// <param name="action"></param>
1091 public void ForEachScenePresence(Action<ScenePresence> action)
1092 {
1093 List<ScenePresence> presences = GetScenePresences();
1094 try
1095 {
1096 foreach(ScenePresence presence in presences)
1097 {
1098 action(presence);
1099 }
1100 }
1101 catch (Exception e)
1102 {
1103 m_log.Info("[BUG] in " + m_parentScene.RegionInfo.RegionName + ": " + e.ToString());
1104 m_log.Info("[BUG] Stack Trace: " + e.StackTrace);
1105 }
1106 }
1040 1107
1041 #endregion 1108 #endregion
1042 1109
diff --git a/OpenSim/Region/Framework/Scenes/SceneManager.cs b/OpenSim/Region/Framework/Scenes/SceneManager.cs
index 680c39a..a955532 100644
--- a/OpenSim/Region/Framework/Scenes/SceneManager.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneManager.cs
@@ -414,12 +414,8 @@ namespace OpenSim.Region.Framework.Scenes
414 ForEachCurrentScene( 414 ForEachCurrentScene(
415 delegate(Scene scene) 415 delegate(Scene scene)
416 { 416 {
417 ScenePresence[] scenePresences = scene.GetScenePresences(); 417 scene.ForEachScenePresence(delegate(ScenePresence scenePresence)
418
419 for (int i = 0; i < scenePresences.Length; i++)
420 { 418 {
421 ScenePresence scenePresence = scenePresences[i];
422
423 if (!scenePresence.IsChildAgent) 419 if (!scenePresence.IsChildAgent)
424 { 420 {
425 m_log.DebugFormat("Packet debug for {0} {1} set to {2}", 421 m_log.DebugFormat("Packet debug for {0} {1} set to {2}",
@@ -429,7 +425,7 @@ namespace OpenSim.Region.Framework.Scenes
429 425
430 scenePresence.ControllingClient.SetDebugPacketLevel(newDebug); 426 scenePresence.ControllingClient.SetDebugPacketLevel(newDebug);
431 } 427 }
432 } 428 });
433 } 429 }
434 ); 430 );
435 } 431 }
@@ -441,14 +437,11 @@ namespace OpenSim.Region.Framework.Scenes
441 ForEachCurrentScene( 437 ForEachCurrentScene(
442 delegate(Scene scene) 438 delegate(Scene scene)
443 { 439 {
444 ScenePresence[] scenePresences = scene.GetScenePresences(); 440 scene.ForEachScenePresence(delegate(ScenePresence scenePresence)
445
446 for (int i = 0; i < scenePresences.Length; i++)
447 { 441 {
448 ScenePresence scenePresence = scenePresences[i];
449 if (!scenePresence.IsChildAgent) 442 if (!scenePresence.IsChildAgent)
450 avatars.Add(scenePresence); 443 avatars.Add(scenePresence);
451 } 444 });
452 } 445 }
453 ); 446 );
454 447
@@ -461,7 +454,7 @@ namespace OpenSim.Region.Framework.Scenes
461 454
462 ForEachCurrentScene(delegate(Scene scene) 455 ForEachCurrentScene(delegate(Scene scene)
463 { 456 {
464 ScenePresence[] scenePresences = scene.GetScenePresences(); 457 List<ScenePresence> scenePresences = scene.GetScenePresences();
465 presences.AddRange(scenePresences); 458 presences.AddRange(scenePresences);
466 }); 459 });
467 460
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
index d083119..3895d93 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
@@ -1370,8 +1370,8 @@ namespace OpenSim.Region.Framework.Scenes
1370 { 1370 {
1371// part.Inventory.RemoveScriptInstances(); 1371// part.Inventory.RemoveScriptInstances();
1372 1372
1373 ScenePresence[] avatars = Scene.GetScenePresences(); 1373 List<ScenePresence> avatars = Scene.GetScenePresences();
1374 for (int i = 0; i < avatars.Length; i++) 1374 for (int i = 0; i < avatars.Count; i++)
1375 { 1375 {
1376 if (avatars[i].ParentID == LocalId) 1376 if (avatars[i].ParentID == LocalId)
1377 { 1377 {
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
index 48e34ee..539f2b1 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
@@ -1208,15 +1208,14 @@ namespace OpenSim.Region.Framework.Scenes
1208 1208
1209 private void SendObjectPropertiesToClient(UUID AgentID) 1209 private void SendObjectPropertiesToClient(UUID AgentID)
1210 { 1210 {
1211 ScenePresence[] avatars = m_parentGroup.Scene.GetScenePresences(); 1211 m_parentGroup.Scene.ForEachScenePresence(delegate(ScenePresence avatar)
1212 for (int i = 0; i < avatars.Length; i++)
1213 { 1212 {
1214 // Ugly reference :( 1213 // Ugly reference :(
1215 if (avatars[i].UUID == AgentID) 1214 if (avatar.UUID == AgentID)
1216 { 1215 {
1217 m_parentGroup.GetProperties(avatars[i].ControllingClient); 1216 m_parentGroup.GetProperties(avatar.ControllingClient);
1218 } 1217 }
1219 } 1218 });
1220 } 1219 }
1221 1220
1222 // TODO: unused: 1221 // TODO: unused:
@@ -1271,11 +1270,10 @@ namespace OpenSim.Region.Framework.Scenes
1271 /// </summary> 1270 /// </summary>
1272 public void AddFullUpdateToAllAvatars() 1271 public void AddFullUpdateToAllAvatars()
1273 { 1272 {
1274 ScenePresence[] avatars = m_parentGroup.Scene.GetScenePresences(); 1273 m_parentGroup.Scene.ForEachScenePresence(delegate(ScenePresence avatar)
1275 for (int i = 0; i < avatars.Length; i++)
1276 { 1274 {
1277 avatars[i].SceneViewer.QueuePartForUpdate(this); 1275 avatar.SceneViewer.QueuePartForUpdate(this);
1278 } 1276 });
1279 } 1277 }
1280 1278
1281 public void AddFullUpdateToAvatar(ScenePresence presence) 1279 public void AddFullUpdateToAvatar(ScenePresence presence)
@@ -1296,11 +1294,10 @@ namespace OpenSim.Region.Framework.Scenes
1296 /// Terse updates 1294 /// Terse updates
1297 public void AddTerseUpdateToAllAvatars() 1295 public void AddTerseUpdateToAllAvatars()
1298 { 1296 {
1299 ScenePresence[] avatars = m_parentGroup.Scene.GetScenePresences(); 1297 m_parentGroup.Scene.ForEachScenePresence(delegate(ScenePresence avatar)
1300 for (int i = 0; i < avatars.Length; i++)
1301 { 1298 {
1302 avatars[i].SceneViewer.QueuePartForUpdate(this); 1299 avatar.SceneViewer.QueuePartForUpdate(this);
1303 } 1300 });
1304 } 1301 }
1305 1302
1306 public void AddTerseUpdateToAvatar(ScenePresence presence) 1303 public void AddTerseUpdateToAvatar(ScenePresence presence)
@@ -2137,17 +2134,13 @@ namespace OpenSim.Region.Framework.Scenes
2137 } 2134 }
2138 else 2135 else
2139 { 2136 {
2140 ScenePresence[] avlist = m_parentGroup.Scene.GetScenePresences(); 2137 m_parentGroup.Scene.ForEachScenePresence(delegate(ScenePresence av)
2141
2142 for (int i = 0; i < avlist.Length; i++)
2143 { 2138 {
2144 ScenePresence av = avlist[i];
2145
2146 if (av.LocalId == localId) 2139 if (av.LocalId == localId)
2147 { 2140 {
2148 if (m_parentGroup.RootPart.CollisionFilter.ContainsValue(av.UUID.ToString()) || m_parentGroup.RootPart.CollisionFilter.ContainsValue(av.Name)) 2141 if (m_parentGroup.RootPart.CollisionFilter.ContainsValue(av.UUID.ToString()) || m_parentGroup.RootPart.CollisionFilter.ContainsValue(av.Name))
2149 { 2142 {
2150 bool found = m_parentGroup.RootPart.CollisionFilter.TryGetValue(1,out data); 2143 bool found = m_parentGroup.RootPart.CollisionFilter.TryGetValue(1, out data);
2151 //If it is 1, it is to accept ONLY collisions from this avatar 2144 //If it is 1, it is to accept ONLY collisions from this avatar
2152 if (found) 2145 if (found)
2153 { 2146 {
@@ -2169,7 +2162,7 @@ namespace OpenSim.Region.Framework.Scenes
2169 } 2162 }
2170 else 2163 else
2171 { 2164 {
2172 bool found = m_parentGroup.RootPart.CollisionFilter.TryGetValue(1,out data); 2165 bool found = m_parentGroup.RootPart.CollisionFilter.TryGetValue(1, out data);
2173 //If it is 1, it is to accept ONLY collisions from this avatar, so this other avatar will not work 2166 //If it is 1, it is to accept ONLY collisions from this avatar, so this other avatar will not work
2174 if (!found) 2167 if (!found)
2175 { 2168 {
@@ -2187,7 +2180,7 @@ namespace OpenSim.Region.Framework.Scenes
2187 } 2180 }
2188 2181
2189 } 2182 }
2190 } 2183 });
2191 } 2184 }
2192 } 2185 }
2193 if (colliding.Count > 0) 2186 if (colliding.Count > 0)
@@ -2273,17 +2266,13 @@ namespace OpenSim.Region.Framework.Scenes
2273 } 2266 }
2274 else 2267 else
2275 { 2268 {
2276 ScenePresence[] avlist = m_parentGroup.Scene.GetScenePresences(); 2269 m_parentGroup.Scene.ForEachScenePresence(delegate(ScenePresence av)
2277
2278 for (int i = 0; i < avlist.Length; i++)
2279 { 2270 {
2280 ScenePresence av = avlist[i];
2281
2282 if (av.LocalId == localId) 2271 if (av.LocalId == localId)
2283 { 2272 {
2284 if (m_parentGroup.RootPart.CollisionFilter.ContainsValue(av.UUID.ToString()) || m_parentGroup.RootPart.CollisionFilter.ContainsValue(av.Name)) 2273 if (m_parentGroup.RootPart.CollisionFilter.ContainsValue(av.UUID.ToString()) || m_parentGroup.RootPart.CollisionFilter.ContainsValue(av.Name))
2285 { 2274 {
2286 bool found = m_parentGroup.RootPart.CollisionFilter.TryGetValue(1,out data); 2275 bool found = m_parentGroup.RootPart.CollisionFilter.TryGetValue(1, out data);
2287 //If it is 1, it is to accept ONLY collisions from this avatar 2276 //If it is 1, it is to accept ONLY collisions from this avatar
2288 if (found) 2277 if (found)
2289 { 2278 {
@@ -2305,7 +2294,7 @@ namespace OpenSim.Region.Framework.Scenes
2305 } 2294 }
2306 else 2295 else
2307 { 2296 {
2308 bool found = m_parentGroup.RootPart.CollisionFilter.TryGetValue(1,out data); 2297 bool found = m_parentGroup.RootPart.CollisionFilter.TryGetValue(1, out data);
2309 //If it is 1, it is to accept ONLY collisions from this avatar, so this other avatar will not work 2298 //If it is 1, it is to accept ONLY collisions from this avatar, so this other avatar will not work
2310 if (!found) 2299 if (!found)
2311 { 2300 {
@@ -2323,7 +2312,7 @@ namespace OpenSim.Region.Framework.Scenes
2323 } 2312 }
2324 2313
2325 } 2314 }
2326 } 2315 });
2327 } 2316 }
2328 } 2317 }
2329 if (colliding.Count > 0) 2318 if (colliding.Count > 0)
@@ -2404,17 +2393,13 @@ namespace OpenSim.Region.Framework.Scenes
2404 } 2393 }
2405 else 2394 else
2406 { 2395 {
2407 ScenePresence[] avlist = m_parentGroup.Scene.GetScenePresences(); 2396 m_parentGroup.Scene.ForEachScenePresence(delegate(ScenePresence av)
2408
2409 for (int i = 0; i < avlist.Length; i++)
2410 { 2397 {
2411 ScenePresence av = avlist[i];
2412
2413 if (av.LocalId == localId) 2398 if (av.LocalId == localId)
2414 { 2399 {
2415 if (m_parentGroup.RootPart.CollisionFilter.ContainsValue(av.UUID.ToString()) || m_parentGroup.RootPart.CollisionFilter.ContainsValue(av.Name)) 2400 if (m_parentGroup.RootPart.CollisionFilter.ContainsValue(av.UUID.ToString()) || m_parentGroup.RootPart.CollisionFilter.ContainsValue(av.Name))
2416 { 2401 {
2417 bool found = m_parentGroup.RootPart.CollisionFilter.TryGetValue(1,out data); 2402 bool found = m_parentGroup.RootPart.CollisionFilter.TryGetValue(1, out data);
2418 //If it is 1, it is to accept ONLY collisions from this avatar 2403 //If it is 1, it is to accept ONLY collisions from this avatar
2419 if (found) 2404 if (found)
2420 { 2405 {
@@ -2436,7 +2421,7 @@ namespace OpenSim.Region.Framework.Scenes
2436 } 2421 }
2437 else 2422 else
2438 { 2423 {
2439 bool found = m_parentGroup.RootPart.CollisionFilter.TryGetValue(1,out data); 2424 bool found = m_parentGroup.RootPart.CollisionFilter.TryGetValue(1, out data);
2440 //If it is 1, it is to accept ONLY collisions from this avatar, so this other avatar will not work 2425 //If it is 1, it is to accept ONLY collisions from this avatar, so this other avatar will not work
2441 if (!found) 2426 if (!found)
2442 { 2427 {
@@ -2454,7 +2439,7 @@ namespace OpenSim.Region.Framework.Scenes
2454 } 2439 }
2455 2440
2456 } 2441 }
2457 } 2442 });
2458 } 2443 }
2459 } 2444 }
2460 2445
@@ -2863,11 +2848,10 @@ namespace OpenSim.Region.Framework.Scenes
2863 /// </summary> 2848 /// </summary>
2864 public void SendFullUpdateToAllClients() 2849 public void SendFullUpdateToAllClients()
2865 { 2850 {
2866 ScenePresence[] avatars = m_parentGroup.Scene.GetScenePresences(); 2851 m_parentGroup.Scene.ForEachScenePresence(delegate(ScenePresence avatar)
2867 for (int i = 0; i < avatars.Length; i++)
2868 { 2852 {
2869 SendFullUpdate(avatars[i].ControllingClient, avatars[i].GenerateClientFlags(UUID)); 2853 SendFullUpdate(avatar.ControllingClient, avatar.GenerateClientFlags(UUID));
2870 } 2854 });
2871 } 2855 }
2872 2856
2873 /// <summary> 2857 /// <summary>
@@ -2876,13 +2860,12 @@ namespace OpenSim.Region.Framework.Scenes
2876 /// <param name="agentID"></param> 2860 /// <param name="agentID"></param>
2877 public void SendFullUpdateToAllClientsExcept(UUID agentID) 2861 public void SendFullUpdateToAllClientsExcept(UUID agentID)
2878 { 2862 {
2879 ScenePresence[] avatars = m_parentGroup.Scene.GetScenePresences(); 2863 m_parentGroup.Scene.ForEachScenePresence(delegate(ScenePresence avatar)
2880 for (int i = 0; i < avatars.Length; i++)
2881 { 2864 {
2882 // Ugly reference :( 2865 // Ugly reference :(
2883 if (avatars[i].UUID != agentID) 2866 if (avatar.UUID != agentID)
2884 SendFullUpdate(avatars[i].ControllingClient, avatars[i].GenerateClientFlags(UUID)); 2867 SendFullUpdate(avatar.ControllingClient, avatar.GenerateClientFlags(UUID));
2885 } 2868 });
2886 } 2869 }
2887 2870
2888 /// <summary> 2871 /// <summary>
@@ -3083,11 +3066,10 @@ namespace OpenSim.Region.Framework.Scenes
3083 /// </summary> 3066 /// </summary>
3084 public void SendTerseUpdateToAllClients() 3067 public void SendTerseUpdateToAllClients()
3085 { 3068 {
3086 ScenePresence[] avatars = m_parentGroup.Scene.GetScenePresences(); 3069 m_parentGroup.Scene.ForEachScenePresence(delegate(ScenePresence avatar)
3087 for (int i = 0; i < avatars.Length; i++)
3088 { 3070 {
3089 SendTerseUpdateToClient(avatars[i].ControllingClient); 3071 SendTerseUpdateToClient(avatar.ControllingClient);
3090 } 3072 });
3091 } 3073 }
3092 3074
3093 public void SetAttachmentPoint(uint AttachmentPoint) 3075 public void SetAttachmentPoint(uint AttachmentPoint)
diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
index 2661dc3..b3e7d67 100644
--- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs
+++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
@@ -957,14 +957,11 @@ namespace OpenSim.Region.Framework.Scenes
957 957
958 m_isChildAgent = false; 958 m_isChildAgent = false;
959 959
960 ScenePresence[] animAgents = m_scene.GetScenePresences(); 960 m_scene.ForEachScenePresence(delegate(ScenePresence presence)
961 for (int i = 0; i < animAgents.Length; i++)
962 { 961 {
963 ScenePresence presence = animAgents[i];
964
965 if (presence != this) 962 if (presence != this)
966 presence.Animator.SendAnimPackToClient(ControllingClient); 963 presence.Animator.SendAnimPackToClient(ControllingClient);
967 } 964 });
968 965
969 m_scene.EventManager.TriggerOnMakeRootAgent(this); 966 m_scene.EventManager.TriggerOnMakeRootAgent(this);
970 } 967 }
@@ -2666,13 +2663,10 @@ namespace OpenSim.Region.Framework.Scenes
2666 public void SendInitialFullUpdateToAllClients() 2663 public void SendInitialFullUpdateToAllClients()
2667 { 2664 {
2668 m_perfMonMS = Util.EnvironmentTickCount(); 2665 m_perfMonMS = Util.EnvironmentTickCount();
2669 2666 int avUpdates = 0;
2670 ScenePresence[] avatars = m_scene.GetScenePresences(); 2667 m_scene.ForEachScenePresence(delegate(ScenePresence avatar)
2671
2672 for (int i = 0; i < avatars.Length; i++)
2673 { 2668 {
2674 ScenePresence avatar = avatars[i]; 2669 ++avUpdates;
2675
2676 // only send if this is the root (children are only "listening posts" in a foreign region) 2670 // only send if this is the root (children are only "listening posts" in a foreign region)
2677 if (!IsChildAgent) 2671 if (!IsChildAgent)
2678 { 2672 {
@@ -2688,9 +2682,9 @@ namespace OpenSim.Region.Framework.Scenes
2688 avatar.Animator.SendAnimPackToClient(ControllingClient); 2682 avatar.Animator.SendAnimPackToClient(ControllingClient);
2689 } 2683 }
2690 } 2684 }
2691 } 2685 });
2692 2686
2693 m_scene.StatsReporter.AddAgentUpdates(avatars.Length); 2687 m_scene.StatsReporter.AddAgentUpdates(avUpdates);
2694 m_scene.StatsReporter.AddAgentTime(Util.EnvironmentTickCountSubtract(m_perfMonMS)); 2688 m_scene.StatsReporter.AddAgentTime(Util.EnvironmentTickCountSubtract(m_perfMonMS));
2695 2689
2696 //Animator.SendAnimPack(); 2690 //Animator.SendAnimPack();
diff --git a/OpenSim/Region/Framework/Scenes/Tests/UuidGathererTests.cs b/OpenSim/Region/Framework/Scenes/Tests/UuidGathererTests.cs
index 6686264..8b80ebe 100644
--- a/OpenSim/Region/Framework/Scenes/Tests/UuidGathererTests.cs
+++ b/OpenSim/Region/Framework/Scenes/Tests/UuidGathererTests.cs
@@ -61,7 +61,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests
61 AssetBase corruptAsset = AssetHelpers.CreateAsset(corruptAssetUuid, "CORRUPT ASSET", UUID.Zero); 61 AssetBase corruptAsset = AssetHelpers.CreateAsset(corruptAssetUuid, "CORRUPT ASSET", UUID.Zero);
62 m_assetService.Store(corruptAsset); 62 m_assetService.Store(corruptAsset);
63 63
64 IDictionary<UUID, int> foundAssetUuids = new Dictionary<UUID, int>(); 64 IDictionary<UUID, AssetType> foundAssetUuids = new Dictionary<UUID, AssetType>();
65 m_uuidGatherer.GatherAssetUuids(corruptAssetUuid, AssetType.Object, foundAssetUuids); 65 m_uuidGatherer.GatherAssetUuids(corruptAssetUuid, AssetType.Object, foundAssetUuids);
66 66
67 // We count the uuid as gathered even if the asset itself is corrupt. 67 // We count the uuid as gathered even if the asset itself is corrupt.
@@ -77,7 +77,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests
77 TestHelper.InMethod(); 77 TestHelper.InMethod();
78 78
79 UUID missingAssetUuid = UUID.Parse("00000000-0000-0000-0000-000000000666"); 79 UUID missingAssetUuid = UUID.Parse("00000000-0000-0000-0000-000000000666");
80 IDictionary<UUID, int> foundAssetUuids = new Dictionary<UUID, int>(); 80 IDictionary<UUID, AssetType> foundAssetUuids = new Dictionary<UUID, AssetType>();
81 81
82 m_uuidGatherer.GatherAssetUuids(missingAssetUuid, AssetType.Object, foundAssetUuids); 82 m_uuidGatherer.GatherAssetUuids(missingAssetUuid, AssetType.Object, foundAssetUuids);
83 83
diff --git a/OpenSim/Region/Framework/Scenes/UuidGatherer.cs b/OpenSim/Region/Framework/Scenes/UuidGatherer.cs
index 3edb677..0ec3cc3 100644
--- a/OpenSim/Region/Framework/Scenes/UuidGatherer.cs
+++ b/OpenSim/Region/Framework/Scenes/UuidGatherer.cs
@@ -84,9 +84,9 @@ namespace OpenSim.Region.Framework.Scenes
84 /// <param name="assetUuid">The uuid of the asset for which to gather referenced assets</param> 84 /// <param name="assetUuid">The uuid of the asset for which to gather referenced assets</param>
85 /// <param name="assetType">The type of the asset for the uuid given</param> 85 /// <param name="assetType">The type of the asset for the uuid given</param>
86 /// <param name="assetUuids">The assets gathered</param> 86 /// <param name="assetUuids">The assets gathered</param>
87 public void GatherAssetUuids(UUID assetUuid, AssetType assetType, IDictionary<UUID, int> assetUuids) 87 public void GatherAssetUuids(UUID assetUuid, AssetType assetType, IDictionary<UUID, AssetType> assetUuids)
88 { 88 {
89 assetUuids[assetUuid] = 1; 89 assetUuids[assetUuid] = assetType;
90 90
91 if (AssetType.Bodypart == assetType || AssetType.Clothing == assetType) 91 if (AssetType.Bodypart == assetType || AssetType.Clothing == assetType)
92 { 92 {
@@ -116,7 +116,7 @@ namespace OpenSim.Region.Framework.Scenes
116 /// 116 ///
117 /// <param name="sceneObject">The scene object for which to gather assets</param> 117 /// <param name="sceneObject">The scene object for which to gather assets</param>
118 /// <param name="assetUuids">The assets gathered</param> 118 /// <param name="assetUuids">The assets gathered</param>
119 public void GatherAssetUuids(SceneObjectGroup sceneObject, IDictionary<UUID, int> assetUuids) 119 public void GatherAssetUuids(SceneObjectGroup sceneObject, IDictionary<UUID, AssetType> assetUuids)
120 { 120 {
121// m_log.DebugFormat( 121// m_log.DebugFormat(
122// "[ASSET GATHERER]: Getting assets for object {0}, {1}", sceneObject.Name, sceneObject.UUID); 122// "[ASSET GATHERER]: Getting assets for object {0}, {1}", sceneObject.Name, sceneObject.UUID);
@@ -129,25 +129,26 @@ namespace OpenSim.Region.Framework.Scenes
129 try 129 try
130 { 130 {
131 Primitive.TextureEntry textureEntry = part.Shape.Textures; 131 Primitive.TextureEntry textureEntry = part.Shape.Textures;
132 132 if (textureEntry != null)
133 // Get the prim's default texture. This will be used for faces which don't have their own texture
134 assetUuids[textureEntry.DefaultTexture.TextureID] = 1;
135
136 // XXX: Not a great way to iterate through face textures, but there's no
137 // other method available to tell how many faces there actually are
138 //int i = 0;
139 foreach (Primitive.TextureEntryFace texture in textureEntry.FaceTextures)
140 { 133 {
141 if (texture != null) 134 // Get the prim's default texture. This will be used for faces which don't have their own texture
135 if (textureEntry.DefaultTexture != null)
136 assetUuids[textureEntry.DefaultTexture.TextureID] = AssetType.Texture;
137
138 if (textureEntry.FaceTextures != null)
142 { 139 {
143 //m_log.DebugFormat("[ARCHIVER]: Got face {0}", i++); 140 // Loop through the rest of the texture faces (a non-null face means the face is different from DefaultTexture)
144 assetUuids[texture.TextureID] = 1; 141 foreach (Primitive.TextureEntryFace texture in textureEntry.FaceTextures)
142 {
143 if (texture != null)
144 assetUuids[texture.TextureID] = AssetType.Texture;
145 }
145 } 146 }
146 } 147 }
147 148
148 // If the prim is a sculpt then preserve this information too 149 // If the prim is a sculpt then preserve this information too
149 if (part.Shape.SculptTexture != UUID.Zero) 150 if (part.Shape.SculptTexture != UUID.Zero)
150 assetUuids[part.Shape.SculptTexture] = 1; 151 assetUuids[part.Shape.SculptTexture] = AssetType.Texture;
151 152
152 TaskInventoryDictionary taskDictionary = (TaskInventoryDictionary)part.TaskInventory.Clone(); 153 TaskInventoryDictionary taskDictionary = (TaskInventoryDictionary)part.TaskInventory.Clone();
153 154
@@ -217,7 +218,7 @@ namespace OpenSim.Region.Framework.Scenes
217 /// </summary> 218 /// </summary>
218 /// <param name="scriptUuid"></param> 219 /// <param name="scriptUuid"></param>
219 /// <param name="assetUuids">Dictionary in which to record the references</param> 220 /// <param name="assetUuids">Dictionary in which to record the references</param>
220 protected void GetScriptAssetUuids(UUID scriptUuid, IDictionary<UUID, int> assetUuids) 221 protected void GetScriptAssetUuids(UUID scriptUuid, IDictionary<UUID, AssetType> assetUuids)
221 { 222 {
222 AssetBase scriptAsset = GetAsset(scriptUuid); 223 AssetBase scriptAsset = GetAsset(scriptUuid);
223 224
@@ -232,7 +233,9 @@ namespace OpenSim.Region.Framework.Scenes
232 { 233 {
233 UUID uuid = new UUID(uuidMatch.Value); 234 UUID uuid = new UUID(uuidMatch.Value);
234 //m_log.DebugFormat("[ARCHIVER]: Recording {0} in script", uuid); 235 //m_log.DebugFormat("[ARCHIVER]: Recording {0} in script", uuid);
235 assetUuids[uuid] = 1; 236
237 // Assume AssetIDs embedded in scripts are textures
238 assetUuids[uuid] = AssetType.Texture;
236 } 239 }
237 } 240 }
238 } 241 }
@@ -242,7 +245,7 @@ namespace OpenSim.Region.Framework.Scenes
242 /// </summary> 245 /// </summary>
243 /// <param name="wearableAssetUuid"></param> 246 /// <param name="wearableAssetUuid"></param>
244 /// <param name="assetUuids">Dictionary in which to record the references</param> 247 /// <param name="assetUuids">Dictionary in which to record the references</param>
245 protected void GetWearableAssetUuids(UUID wearableAssetUuid, IDictionary<UUID, int> assetUuids) 248 protected void GetWearableAssetUuids(UUID wearableAssetUuid, IDictionary<UUID, AssetType> assetUuids)
246 { 249 {
247 AssetBase assetBase = GetAsset(wearableAssetUuid); 250 AssetBase assetBase = GetAsset(wearableAssetUuid);
248 251
@@ -257,8 +260,7 @@ namespace OpenSim.Region.Framework.Scenes
257 260
258 foreach (UUID uuid in wearableAsset.Textures.Values) 261 foreach (UUID uuid in wearableAsset.Textures.Values)
259 { 262 {
260 //m_log.DebugFormat("[ARCHIVER]: Got bodypart uuid {0}", uuid); 263 assetUuids[uuid] = AssetType.Texture;
261 assetUuids[uuid] = 1;
262 } 264 }
263 } 265 }
264 } 266 }
@@ -270,7 +272,7 @@ namespace OpenSim.Region.Framework.Scenes
270 /// </summary> 272 /// </summary>
271 /// <param name="sceneObject"></param> 273 /// <param name="sceneObject"></param>
272 /// <param name="assetUuids"></param> 274 /// <param name="assetUuids"></param>
273 protected void GetSceneObjectAssetUuids(UUID sceneObjectUuid, IDictionary<UUID, int> assetUuids) 275 protected void GetSceneObjectAssetUuids(UUID sceneObjectUuid, IDictionary<UUID, AssetType> assetUuids)
274 { 276 {
275 AssetBase objectAsset = GetAsset(sceneObjectUuid); 277 AssetBase objectAsset = GetAsset(sceneObjectUuid);
276 278
@@ -284,7 +286,7 @@ namespace OpenSim.Region.Framework.Scenes
284 } 286 }
285 } 287 }
286 288
287 protected void GetGestureAssetUuids(UUID gestureUuid, IDictionary<UUID, int> assetUuids) 289 protected void GetGestureAssetUuids(UUID gestureUuid, IDictionary<UUID, AssetType> assetUuids)
288 { 290 {
289 AssetBase assetBase = GetAsset(gestureUuid); 291 AssetBase assetBase = GetAsset(gestureUuid);
290 292
@@ -316,7 +318,7 @@ namespace OpenSim.Region.Framework.Scenes
316 // If it can be parsed as a UUID, it is an asset ID 318 // If it can be parsed as a UUID, it is an asset ID
317 UUID uuid; 319 UUID uuid;
318 if (UUID.TryParse(id, out uuid)) 320 if (UUID.TryParse(id, out uuid))
319 assetUuids[uuid] = 1; 321 assetUuids[uuid] = AssetType.Animation;
320 } 322 }
321 } 323 }
322 } 324 }
diff --git a/OpenSim/Region/Physics/Meshing/PrimMesher.cs b/OpenSim/Region/Physics/Meshing/PrimMesher.cs
index 6e9654b..932943c 100644
--- a/OpenSim/Region/Physics/Meshing/PrimMesher.cs
+++ b/OpenSim/Region/Physics/Meshing/PrimMesher.cs
@@ -1,2201 +1,2201 @@
1/* 1/*
2 * Copyright (c) Contributors 2 * Copyright (c) Contributors
3 * See CONTRIBUTORS.TXT for a full list of copyright holders. 3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 * 4 *
5 * Redistribution and use in source and binary forms, with or without 5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met: 6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright 7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer. 8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright 9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the 10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution. 11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the 12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products 13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission. 14 * derived from this software without specific prior written permission.
15 * 15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY 16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY 19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27 27
28using System; 28using System;
29using System.Collections.Generic; 29using System.Collections.Generic;
30using System.Text; 30using System.Text;
31using System.IO; 31using System.IO;
32 32
33namespace PrimMesher 33namespace PrimMesher
34{ 34{
35 public struct Quat 35 public struct Quat
36 { 36 {
37 /// <summary>X value</summary> 37 /// <summary>X value</summary>
38 public float X; 38 public float X;
39 /// <summary>Y value</summary> 39 /// <summary>Y value</summary>
40 public float Y; 40 public float Y;
41 /// <summary>Z value</summary> 41 /// <summary>Z value</summary>
42 public float Z; 42 public float Z;
43 /// <summary>W value</summary> 43 /// <summary>W value</summary>
44 public float W; 44 public float W;
45 45
46 public Quat(float x, float y, float z, float w) 46 public Quat(float x, float y, float z, float w)
47 { 47 {
48 X = x; 48 X = x;
49 Y = y; 49 Y = y;
50 Z = z; 50 Z = z;
51 W = w; 51 W = w;
52 } 52 }
53 53
54 public Quat(Coord axis, float angle) 54 public Quat(Coord axis, float angle)
55 { 55 {
56 axis = axis.Normalize(); 56 axis = axis.Normalize();
57 57
58 angle *= 0.5f; 58 angle *= 0.5f;
59 float c = (float)Math.Cos(angle); 59 float c = (float)Math.Cos(angle);
60 float s = (float)Math.Sin(angle); 60 float s = (float)Math.Sin(angle);
61 61
62 X = axis.X * s; 62 X = axis.X * s;
63 Y = axis.Y * s; 63 Y = axis.Y * s;
64 Z = axis.Z * s; 64 Z = axis.Z * s;
65 W = c; 65 W = c;
66 66
67 Normalize(); 67 Normalize();
68 } 68 }
69 69
70 public float Length() 70 public float Length()
71 { 71 {
72 return (float)Math.Sqrt(X * X + Y * Y + Z * Z + W * W); 72 return (float)Math.Sqrt(X * X + Y * Y + Z * Z + W * W);
73 } 73 }
74 74
75 public Quat Normalize() 75 public Quat Normalize()
76 { 76 {
77 const float MAG_THRESHOLD = 0.0000001f; 77 const float MAG_THRESHOLD = 0.0000001f;
78 float mag = Length(); 78 float mag = Length();
79 79
80 // Catch very small rounding errors when normalizing 80 // Catch very small rounding errors when normalizing
81 if (mag > MAG_THRESHOLD) 81 if (mag > MAG_THRESHOLD)
82 { 82 {
83 float oomag = 1f / mag; 83 float oomag = 1f / mag;
84 X *= oomag; 84 X *= oomag;
85 Y *= oomag; 85 Y *= oomag;
86 Z *= oomag; 86 Z *= oomag;
87 W *= oomag; 87 W *= oomag;
88 } 88 }
89 else 89 else
90 { 90 {
91 X = 0f; 91 X = 0f;
92 Y = 0f; 92 Y = 0f;
93 Z = 0f; 93 Z = 0f;
94 W = 1f; 94 W = 1f;
95 } 95 }
96 96
97 return this; 97 return this;
98 } 98 }
99 99
100 public static Quat operator *(Quat q1, Quat q2) 100 public static Quat operator *(Quat q1, Quat q2)
101 { 101 {
102 float x = q1.W * q2.X + q1.X * q2.W + q1.Y * q2.Z - q1.Z * q2.Y; 102 float x = q1.W * q2.X + q1.X * q2.W + q1.Y * q2.Z - q1.Z * q2.Y;
103 float y = q1.W * q2.Y - q1.X * q2.Z + q1.Y * q2.W + q1.Z * q2.X; 103 float y = q1.W * q2.Y - q1.X * q2.Z + q1.Y * q2.W + q1.Z * q2.X;
104 float z = q1.W * q2.Z + q1.X * q2.Y - q1.Y * q2.X + q1.Z * q2.W; 104 float z = q1.W * q2.Z + q1.X * q2.Y - q1.Y * q2.X + q1.Z * q2.W;
105 float w = q1.W * q2.W - q1.X * q2.X - q1.Y * q2.Y - q1.Z * q2.Z; 105 float w = q1.W * q2.W - q1.X * q2.X - q1.Y * q2.Y - q1.Z * q2.Z;
106 return new Quat(x, y, z, w); 106 return new Quat(x, y, z, w);
107 } 107 }
108 108
109 public override string ToString() 109 public override string ToString()
110 { 110 {
111 return "< X: " + this.X.ToString() + ", Y: " + this.Y.ToString() + ", Z: " + this.Z.ToString() + ", W: " + this.W.ToString() + ">"; 111 return "< X: " + this.X.ToString() + ", Y: " + this.Y.ToString() + ", Z: " + this.Z.ToString() + ", W: " + this.W.ToString() + ">";
112 } 112 }
113 } 113 }
114 114
115 public struct Coord 115 public struct Coord
116 { 116 {
117 public float X; 117 public float X;
118 public float Y; 118 public float Y;
119 public float Z; 119 public float Z;
120 120
121 public Coord(float x, float y, float z) 121 public Coord(float x, float y, float z)
122 { 122 {
123 this.X = x; 123 this.X = x;
124 this.Y = y; 124 this.Y = y;
125 this.Z = z; 125 this.Z = z;
126 } 126 }
127 127
128 public float Length() 128 public float Length()
129 { 129 {
130 return (float)Math.Sqrt(this.X * this.X + this.Y * this.Y + this.Z * this.Z); 130 return (float)Math.Sqrt(this.X * this.X + this.Y * this.Y + this.Z * this.Z);
131 } 131 }
132 132
133 public Coord Invert() 133 public Coord Invert()
134 { 134 {
135 this.X = -this.X; 135 this.X = -this.X;
136 this.Y = -this.Y; 136 this.Y = -this.Y;
137 this.Z = -this.Z; 137 this.Z = -this.Z;
138 138
139 return this; 139 return this;
140 } 140 }
141 141
142 public Coord Normalize() 142 public Coord Normalize()
143 { 143 {
144 const float MAG_THRESHOLD = 0.0000001f; 144 const float MAG_THRESHOLD = 0.0000001f;
145 float mag = Length(); 145 float mag = Length();
146 146
147 // Catch very small rounding errors when normalizing 147 // Catch very small rounding errors when normalizing
148 if (mag > MAG_THRESHOLD) 148 if (mag > MAG_THRESHOLD)
149 { 149 {
150 float oomag = 1.0f / mag; 150 float oomag = 1.0f / mag;
151 this.X *= oomag; 151 this.X *= oomag;
152 this.Y *= oomag; 152 this.Y *= oomag;
153 this.Z *= oomag; 153 this.Z *= oomag;
154 } 154 }
155 else 155 else
156 { 156 {
157 this.X = 0.0f; 157 this.X = 0.0f;
158 this.Y = 0.0f; 158 this.Y = 0.0f;
159 this.Z = 0.0f; 159 this.Z = 0.0f;
160 } 160 }
161 161
162 return this; 162 return this;
163 } 163 }
164 164
165 public override string ToString() 165 public override string ToString()
166 { 166 {
167 return this.X.ToString() + " " + this.Y.ToString() + " " + this.Z.ToString(); 167 return this.X.ToString() + " " + this.Y.ToString() + " " + this.Z.ToString();
168 } 168 }
169 169
170 public static Coord Cross(Coord c1, Coord c2) 170 public static Coord Cross(Coord c1, Coord c2)
171 { 171 {
172 return new Coord( 172 return new Coord(
173 c1.Y * c2.Z - c2.Y * c1.Z, 173 c1.Y * c2.Z - c2.Y * c1.Z,
174 c1.Z * c2.X - c2.Z * c1.X, 174 c1.Z * c2.X - c2.Z * c1.X,
175 c1.X * c2.Y - c2.X * c1.Y 175 c1.X * c2.Y - c2.X * c1.Y
176 ); 176 );
177 } 177 }
178 178
179 public static Coord operator +(Coord v, Coord a) 179 public static Coord operator +(Coord v, Coord a)
180 { 180 {
181 return new Coord(v.X + a.X, v.Y + a.Y, v.Z + a.Z); 181 return new Coord(v.X + a.X, v.Y + a.Y, v.Z + a.Z);
182 } 182 }
183 183
184 public static Coord operator *(Coord v, Coord m) 184 public static Coord operator *(Coord v, Coord m)
185 { 185 {
186 return new Coord(v.X * m.X, v.Y * m.Y, v.Z * m.Z); 186 return new Coord(v.X * m.X, v.Y * m.Y, v.Z * m.Z);
187 } 187 }
188 188
189 public static Coord operator *(Coord v, Quat q) 189 public static Coord operator *(Coord v, Quat q)
190 { 190 {
191 // From http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/transforms/ 191 // From http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/transforms/
192 192
193 Coord c2 = new Coord(0.0f, 0.0f, 0.0f); 193 Coord c2 = new Coord(0.0f, 0.0f, 0.0f);
194 194
195 c2.X = q.W * q.W * v.X + 195 c2.X = q.W * q.W * v.X +
196 2f * q.Y * q.W * v.Z - 196 2f * q.Y * q.W * v.Z -
197 2f * q.Z * q.W * v.Y + 197 2f * q.Z * q.W * v.Y +
198 q.X * q.X * v.X + 198 q.X * q.X * v.X +
199 2f * q.Y * q.X * v.Y + 199 2f * q.Y * q.X * v.Y +
200 2f * q.Z * q.X * v.Z - 200 2f * q.Z * q.X * v.Z -
201 q.Z * q.Z * v.X - 201 q.Z * q.Z * v.X -
202 q.Y * q.Y * v.X; 202 q.Y * q.Y * v.X;
203 203
204 c2.Y = 204 c2.Y =
205 2f * q.X * q.Y * v.X + 205 2f * q.X * q.Y * v.X +
206 q.Y * q.Y * v.Y + 206 q.Y * q.Y * v.Y +
207 2f * q.Z * q.Y * v.Z + 207 2f * q.Z * q.Y * v.Z +
208 2f * q.W * q.Z * v.X - 208 2f * q.W * q.Z * v.X -
209 q.Z * q.Z * v.Y + 209 q.Z * q.Z * v.Y +
210 q.W * q.W * v.Y - 210 q.W * q.W * v.Y -
211 2f * q.X * q.W * v.Z - 211 2f * q.X * q.W * v.Z -
212 q.X * q.X * v.Y; 212 q.X * q.X * v.Y;
213 213
214 c2.Z = 214 c2.Z =
215 2f * q.X * q.Z * v.X + 215 2f * q.X * q.Z * v.X +
216 2f * q.Y * q.Z * v.Y + 216 2f * q.Y * q.Z * v.Y +
217 q.Z * q.Z * v.Z - 217 q.Z * q.Z * v.Z -
218 2f * q.W * q.Y * v.X - 218 2f * q.W * q.Y * v.X -
219 q.Y * q.Y * v.Z + 219 q.Y * q.Y * v.Z +
220 2f * q.W * q.X * v.Y - 220 2f * q.W * q.X * v.Y -
221 q.X * q.X * v.Z + 221 q.X * q.X * v.Z +
222 q.W * q.W * v.Z; 222 q.W * q.W * v.Z;
223 223
224 return c2; 224 return c2;
225 } 225 }
226 } 226 }
227 227
228 public struct UVCoord 228 public struct UVCoord
229 { 229 {
230 public float U; 230 public float U;
231 public float V; 231 public float V;
232 232
233 233
234 public UVCoord(float u, float v) 234 public UVCoord(float u, float v)
235 { 235 {
236 this.U = u; 236 this.U = u;
237 this.V = v; 237 this.V = v;
238 } 238 }
239 } 239 }
240 240
241 public struct Face 241 public struct Face
242 { 242 {
243 public int primFace; 243 public int primFace;
244 244
245 // vertices 245 // vertices
246 public int v1; 246 public int v1;
247 public int v2; 247 public int v2;
248 public int v3; 248 public int v3;
249 249
250 //normals 250 //normals
251 public int n1; 251 public int n1;
252 public int n2; 252 public int n2;
253 public int n3; 253 public int n3;
254 254
255 // uvs 255 // uvs
256 public int uv1; 256 public int uv1;
257 public int uv2; 257 public int uv2;
258 public int uv3; 258 public int uv3;
259 259
260 260
261 public Face(int v1, int v2, int v3) 261 public Face(int v1, int v2, int v3)
262 { 262 {
263 primFace = 0; 263 primFace = 0;
264 264
265 this.v1 = v1; 265 this.v1 = v1;
266 this.v2 = v2; 266 this.v2 = v2;
267 this.v3 = v3; 267 this.v3 = v3;
268 268
269 this.n1 = 0; 269 this.n1 = 0;
270 this.n2 = 0; 270 this.n2 = 0;
271 this.n3 = 0; 271 this.n3 = 0;
272 272
273 this.uv1 = 0; 273 this.uv1 = 0;
274 this.uv2 = 0; 274 this.uv2 = 0;
275 this.uv3 = 0; 275 this.uv3 = 0;
276 276
277 } 277 }
278 278
279 public Face(int v1, int v2, int v3, int n1, int n2, int n3) 279 public Face(int v1, int v2, int v3, int n1, int n2, int n3)
280 { 280 {
281 primFace = 0; 281 primFace = 0;
282 282
283 this.v1 = v1; 283 this.v1 = v1;
284 this.v2 = v2; 284 this.v2 = v2;
285 this.v3 = v3; 285 this.v3 = v3;
286 286
287 this.n1 = n1; 287 this.n1 = n1;
288 this.n2 = n2; 288 this.n2 = n2;
289 this.n3 = n3; 289 this.n3 = n3;
290 290
291 this.uv1 = 0; 291 this.uv1 = 0;
292 this.uv2 = 0; 292 this.uv2 = 0;
293 this.uv3 = 0; 293 this.uv3 = 0;
294 } 294 }
295 295
296 public Coord SurfaceNormal(List<Coord> coordList) 296 public Coord SurfaceNormal(List<Coord> coordList)
297 { 297 {
298 Coord c1 = coordList[this.v1]; 298 Coord c1 = coordList[this.v1];
299 Coord c2 = coordList[this.v2]; 299 Coord c2 = coordList[this.v2];
300 Coord c3 = coordList[this.v3]; 300 Coord c3 = coordList[this.v3];
301 301
302 Coord edge1 = new Coord(c2.X - c1.X, c2.Y - c1.Y, c2.Z - c1.Z); 302 Coord edge1 = new Coord(c2.X - c1.X, c2.Y - c1.Y, c2.Z - c1.Z);
303 Coord edge2 = new Coord(c3.X - c1.X, c3.Y - c1.Y, c3.Z - c1.Z); 303 Coord edge2 = new Coord(c3.X - c1.X, c3.Y - c1.Y, c3.Z - c1.Z);
304 304
305 return Coord.Cross(edge1, edge2).Normalize(); 305 return Coord.Cross(edge1, edge2).Normalize();
306 } 306 }
307 } 307 }
308 308
309 public struct ViewerFace 309 public struct ViewerFace
310 { 310 {
311 public int primFaceNumber; 311 public int primFaceNumber;
312 312
313 public Coord v1; 313 public Coord v1;
314 public Coord v2; 314 public Coord v2;
315 public Coord v3; 315 public Coord v3;
316 316
317 public int coordIndex1; 317 public int coordIndex1;
318 public int coordIndex2; 318 public int coordIndex2;
319 public int coordIndex3; 319 public int coordIndex3;
320 320
321 public Coord n1; 321 public Coord n1;
322 public Coord n2; 322 public Coord n2;
323 public Coord n3; 323 public Coord n3;
324 324
325 public UVCoord uv1; 325 public UVCoord uv1;
326 public UVCoord uv2; 326 public UVCoord uv2;
327 public UVCoord uv3; 327 public UVCoord uv3;
328 328
329 public ViewerFace(int primFaceNumber) 329 public ViewerFace(int primFaceNumber)
330 { 330 {
331 this.primFaceNumber = primFaceNumber; 331 this.primFaceNumber = primFaceNumber;
332 332
333 this.v1 = new Coord(); 333 this.v1 = new Coord();
334 this.v2 = new Coord(); 334 this.v2 = new Coord();
335 this.v3 = new Coord(); 335 this.v3 = new Coord();
336 336
337 this.coordIndex1 = this.coordIndex2 = this.coordIndex3 = -1; // -1 means not assigned yet 337 this.coordIndex1 = this.coordIndex2 = this.coordIndex3 = -1; // -1 means not assigned yet
338 338
339 this.n1 = new Coord(); 339 this.n1 = new Coord();
340 this.n2 = new Coord(); 340 this.n2 = new Coord();
341 this.n3 = new Coord(); 341 this.n3 = new Coord();
342 342
343 this.uv1 = new UVCoord(); 343 this.uv1 = new UVCoord();
344 this.uv2 = new UVCoord(); 344 this.uv2 = new UVCoord();
345 this.uv3 = new UVCoord(); 345 this.uv3 = new UVCoord();
346 } 346 }
347 347
348 public void Scale(float x, float y, float z) 348 public void Scale(float x, float y, float z)
349 { 349 {
350 this.v1.X *= x; 350 this.v1.X *= x;
351 this.v1.Y *= y; 351 this.v1.Y *= y;
352 this.v1.Z *= z; 352 this.v1.Z *= z;
353 353
354 this.v2.X *= x; 354 this.v2.X *= x;
355 this.v2.Y *= y; 355 this.v2.Y *= y;
356 this.v2.Z *= z; 356 this.v2.Z *= z;
357 357
358 this.v3.X *= x; 358 this.v3.X *= x;
359 this.v3.Y *= y; 359 this.v3.Y *= y;
360 this.v3.Z *= z; 360 this.v3.Z *= z;
361 } 361 }
362 362
363 public void AddPos(float x, float y, float z) 363 public void AddPos(float x, float y, float z)
364 { 364 {
365 this.v1.X += x; 365 this.v1.X += x;
366 this.v2.X += x; 366 this.v2.X += x;
367 this.v3.X += x; 367 this.v3.X += x;
368 368
369 this.v1.Y += y; 369 this.v1.Y += y;
370 this.v2.Y += y; 370 this.v2.Y += y;
371 this.v3.Y += y; 371 this.v3.Y += y;
372 372
373 this.v1.Z += z; 373 this.v1.Z += z;
374 this.v2.Z += z; 374 this.v2.Z += z;
375 this.v3.Z += z; 375 this.v3.Z += z;
376 } 376 }
377 377
378 public void AddRot(Quat q) 378 public void AddRot(Quat q)
379 { 379 {
380 this.v1 *= q; 380 this.v1 *= q;
381 this.v2 *= q; 381 this.v2 *= q;
382 this.v3 *= q; 382 this.v3 *= q;
383 383
384 this.n1 *= q; 384 this.n1 *= q;
385 this.n2 *= q; 385 this.n2 *= q;
386 this.n3 *= q; 386 this.n3 *= q;
387 } 387 }
388 388
389 public void CalcSurfaceNormal() 389 public void CalcSurfaceNormal()
390 { 390 {
391 391
392 Coord edge1 = new Coord(this.v2.X - this.v1.X, this.v2.Y - this.v1.Y, this.v2.Z - this.v1.Z); 392 Coord edge1 = new Coord(this.v2.X - this.v1.X, this.v2.Y - this.v1.Y, this.v2.Z - this.v1.Z);
393 Coord edge2 = new Coord(this.v3.X - this.v1.X, this.v3.Y - this.v1.Y, this.v3.Z - this.v1.Z); 393 Coord edge2 = new Coord(this.v3.X - this.v1.X, this.v3.Y - this.v1.Y, this.v3.Z - this.v1.Z);
394 394
395 this.n1 = this.n2 = this.n3 = Coord.Cross(edge1, edge2).Normalize(); 395 this.n1 = this.n2 = this.n3 = Coord.Cross(edge1, edge2).Normalize();
396 } 396 }
397 } 397 }
398 398
399 internal struct Angle 399 internal struct Angle
400 { 400 {
401 internal float angle; 401 internal float angle;
402 internal float X; 402 internal float X;
403 internal float Y; 403 internal float Y;
404 404
405 internal Angle(float angle, float x, float y) 405 internal Angle(float angle, float x, float y)
406 { 406 {
407 this.angle = angle; 407 this.angle = angle;
408 this.X = x; 408 this.X = x;
409 this.Y = y; 409 this.Y = y;
410 } 410 }
411 } 411 }
412 412
413 internal class AngleList 413 internal class AngleList
414 { 414 {
415 private float iX, iY; // intersection point 415 private float iX, iY; // intersection point
416 416
417 private static Angle[] angles3 = 417 private static Angle[] angles3 =
418 { 418 {
419 new Angle(0.0f, 1.0f, 0.0f), 419 new Angle(0.0f, 1.0f, 0.0f),
420 new Angle(0.33333333333333333f, -0.5f, 0.86602540378443871f), 420 new Angle(0.33333333333333333f, -0.5f, 0.86602540378443871f),
421 new Angle(0.66666666666666667f, -0.5f, -0.86602540378443837f), 421 new Angle(0.66666666666666667f, -0.5f, -0.86602540378443837f),
422 new Angle(1.0f, 1.0f, 0.0f) 422 new Angle(1.0f, 1.0f, 0.0f)
423 }; 423 };
424 424
425 private static Coord[] normals3 = 425 private static Coord[] normals3 =
426 { 426 {
427 new Coord(0.25f, 0.4330127019f, 0.0f).Normalize(), 427 new Coord(0.25f, 0.4330127019f, 0.0f).Normalize(),
428 new Coord(-0.5f, 0.0f, 0.0f).Normalize(), 428 new Coord(-0.5f, 0.0f, 0.0f).Normalize(),
429 new Coord(0.25f, -0.4330127019f, 0.0f).Normalize(), 429 new Coord(0.25f, -0.4330127019f, 0.0f).Normalize(),
430 new Coord(0.25f, 0.4330127019f, 0.0f).Normalize() 430 new Coord(0.25f, 0.4330127019f, 0.0f).Normalize()
431 }; 431 };
432 432
433 private static Angle[] angles4 = 433 private static Angle[] angles4 =
434 { 434 {
435 new Angle(0.0f, 1.0f, 0.0f), 435 new Angle(0.0f, 1.0f, 0.0f),
436 new Angle(0.25f, 0.0f, 1.0f), 436 new Angle(0.25f, 0.0f, 1.0f),
437 new Angle(0.5f, -1.0f, 0.0f), 437 new Angle(0.5f, -1.0f, 0.0f),
438 new Angle(0.75f, 0.0f, -1.0f), 438 new Angle(0.75f, 0.0f, -1.0f),
439 new Angle(1.0f, 1.0f, 0.0f) 439 new Angle(1.0f, 1.0f, 0.0f)
440 }; 440 };
441 441
442 private static Coord[] normals4 = 442 private static Coord[] normals4 =
443 { 443 {
444 new Coord(0.5f, 0.5f, 0.0f).Normalize(), 444 new Coord(0.5f, 0.5f, 0.0f).Normalize(),
445 new Coord(-0.5f, 0.5f, 0.0f).Normalize(), 445 new Coord(-0.5f, 0.5f, 0.0f).Normalize(),
446 new Coord(-0.5f, -0.5f, 0.0f).Normalize(), 446 new Coord(-0.5f, -0.5f, 0.0f).Normalize(),
447 new Coord(0.5f, -0.5f, 0.0f).Normalize(), 447 new Coord(0.5f, -0.5f, 0.0f).Normalize(),
448 new Coord(0.5f, 0.5f, 0.0f).Normalize() 448 new Coord(0.5f, 0.5f, 0.0f).Normalize()
449 }; 449 };
450 450
451 private static Angle[] angles24 = 451 private static Angle[] angles24 =
452 { 452 {
453 new Angle(0.0f, 1.0f, 0.0f), 453 new Angle(0.0f, 1.0f, 0.0f),
454 new Angle(0.041666666666666664f, 0.96592582628906831f, 0.25881904510252074f), 454 new Angle(0.041666666666666664f, 0.96592582628906831f, 0.25881904510252074f),
455 new Angle(0.083333333333333329f, 0.86602540378443871f, 0.5f), 455 new Angle(0.083333333333333329f, 0.86602540378443871f, 0.5f),
456 new Angle(0.125f, 0.70710678118654757f, 0.70710678118654746f), 456 new Angle(0.125f, 0.70710678118654757f, 0.70710678118654746f),
457 new Angle(0.16666666666666667f, 0.5f, 0.8660254037844386f), 457 new Angle(0.16666666666666667f, 0.5f, 0.8660254037844386f),
458 new Angle(0.20833333333333331f, 0.25881904510252096f, 0.9659258262890682f), 458 new Angle(0.20833333333333331f, 0.25881904510252096f, 0.9659258262890682f),
459 new Angle(0.25f, 0.0f, 1.0f), 459 new Angle(0.25f, 0.0f, 1.0f),
460 new Angle(0.29166666666666663f, -0.25881904510252063f, 0.96592582628906831f), 460 new Angle(0.29166666666666663f, -0.25881904510252063f, 0.96592582628906831f),
461 new Angle(0.33333333333333333f, -0.5f, 0.86602540378443871f), 461 new Angle(0.33333333333333333f, -0.5f, 0.86602540378443871f),
462 new Angle(0.375f, -0.70710678118654746f, 0.70710678118654757f), 462 new Angle(0.375f, -0.70710678118654746f, 0.70710678118654757f),
463 new Angle(0.41666666666666663f, -0.86602540378443849f, 0.5f), 463 new Angle(0.41666666666666663f, -0.86602540378443849f, 0.5f),
464 new Angle(0.45833333333333331f, -0.9659258262890682f, 0.25881904510252102f), 464 new Angle(0.45833333333333331f, -0.9659258262890682f, 0.25881904510252102f),
465 new Angle(0.5f, -1.0f, 0.0f), 465 new Angle(0.5f, -1.0f, 0.0f),
466 new Angle(0.54166666666666663f, -0.96592582628906842f, -0.25881904510252035f), 466 new Angle(0.54166666666666663f, -0.96592582628906842f, -0.25881904510252035f),
467 new Angle(0.58333333333333326f, -0.86602540378443882f, -0.5f), 467 new Angle(0.58333333333333326f, -0.86602540378443882f, -0.5f),
468 new Angle(0.62499999999999989f, -0.70710678118654791f, -0.70710678118654713f), 468 new Angle(0.62499999999999989f, -0.70710678118654791f, -0.70710678118654713f),
469 new Angle(0.66666666666666667f, -0.5f, -0.86602540378443837f), 469 new Angle(0.66666666666666667f, -0.5f, -0.86602540378443837f),
470 new Angle(0.70833333333333326f, -0.25881904510252152f, -0.96592582628906809f), 470 new Angle(0.70833333333333326f, -0.25881904510252152f, -0.96592582628906809f),
471 new Angle(0.75f, 0.0f, -1.0f), 471 new Angle(0.75f, 0.0f, -1.0f),
472 new Angle(0.79166666666666663f, 0.2588190451025203f, -0.96592582628906842f), 472 new Angle(0.79166666666666663f, 0.2588190451025203f, -0.96592582628906842f),
473 new Angle(0.83333333333333326f, 0.5f, -0.86602540378443904f), 473 new Angle(0.83333333333333326f, 0.5f, -0.86602540378443904f),
474 new Angle(0.875f, 0.70710678118654735f, -0.70710678118654768f), 474 new Angle(0.875f, 0.70710678118654735f, -0.70710678118654768f),
475 new Angle(0.91666666666666663f, 0.86602540378443837f, -0.5f), 475 new Angle(0.91666666666666663f, 0.86602540378443837f, -0.5f),
476 new Angle(0.95833333333333326f, 0.96592582628906809f, -0.25881904510252157f), 476 new Angle(0.95833333333333326f, 0.96592582628906809f, -0.25881904510252157f),
477 new Angle(1.0f, 1.0f, 0.0f) 477 new Angle(1.0f, 1.0f, 0.0f)
478 }; 478 };
479 479
480 private Angle interpolatePoints(float newPoint, Angle p1, Angle p2) 480 private Angle interpolatePoints(float newPoint, Angle p1, Angle p2)
481 { 481 {
482 float m = (newPoint - p1.angle) / (p2.angle - p1.angle); 482 float m = (newPoint - p1.angle) / (p2.angle - p1.angle);
483 return new Angle(newPoint, p1.X + m * (p2.X - p1.X), p1.Y + m * (p2.Y - p1.Y)); 483 return new Angle(newPoint, p1.X + m * (p2.X - p1.X), p1.Y + m * (p2.Y - p1.Y));
484 } 484 }
485 485
486 private void intersection(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4) 486 private void intersection(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)
487 { // ref: http://local.wasp.uwa.edu.au/~pbourke/geometry/lineline2d/ 487 { // ref: http://local.wasp.uwa.edu.au/~pbourke/geometry/lineline2d/
488 double denom = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1); 488 double denom = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1);
489 double uaNumerator = (x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3); 489 double uaNumerator = (x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3);
490 490
491 if (denom != 0.0) 491 if (denom != 0.0)
492 { 492 {
493 double ua = uaNumerator / denom; 493 double ua = uaNumerator / denom;
494 iX = (float)(x1 + ua * (x2 - x1)); 494 iX = (float)(x1 + ua * (x2 - x1));
495 iY = (float)(y1 + ua * (y2 - y1)); 495 iY = (float)(y1 + ua * (y2 - y1));
496 } 496 }
497 } 497 }
498 498
499 internal List<Angle> angles; 499 internal List<Angle> angles;
500 internal List<Coord> normals; 500 internal List<Coord> normals;
501 501
502 internal void makeAngles(int sides, float startAngle, float stopAngle) 502 internal void makeAngles(int sides, float startAngle, float stopAngle)
503 { 503 {
504 angles = new List<Angle>(); 504 angles = new List<Angle>();
505 normals = new List<Coord>(); 505 normals = new List<Coord>();
506 506
507 double twoPi = System.Math.PI * 2.0; 507 double twoPi = System.Math.PI * 2.0;
508 float twoPiInv = 1.0f / (float)twoPi; 508 float twoPiInv = 1.0f / (float)twoPi;
509 509
510 if (sides < 1) 510 if (sides < 1)
511 throw new Exception("number of sides not greater than zero"); 511 throw new Exception("number of sides not greater than zero");
512 if (stopAngle <= startAngle) 512 if (stopAngle <= startAngle)
513 throw new Exception("stopAngle not greater than startAngle"); 513 throw new Exception("stopAngle not greater than startAngle");
514 514
515 if ((sides == 3 || sides == 4 || sides == 24)) 515 if ((sides == 3 || sides == 4 || sides == 24))
516 { 516 {
517 startAngle *= twoPiInv; 517 startAngle *= twoPiInv;
518 stopAngle *= twoPiInv; 518 stopAngle *= twoPiInv;
519 519
520 Angle[] sourceAngles; 520 Angle[] sourceAngles;
521 if (sides == 3) 521 if (sides == 3)
522 sourceAngles = angles3; 522 sourceAngles = angles3;
523 else if (sides == 4) 523 else if (sides == 4)
524 sourceAngles = angles4; 524 sourceAngles = angles4;
525 else sourceAngles = angles24; 525 else sourceAngles = angles24;
526 526
527 int startAngleIndex = (int)(startAngle * sides); 527 int startAngleIndex = (int)(startAngle * sides);
528 int endAngleIndex = sourceAngles.Length - 1; 528 int endAngleIndex = sourceAngles.Length - 1;
529 if (stopAngle < 1.0f) 529 if (stopAngle < 1.0f)
530 endAngleIndex = (int)(stopAngle * sides) + 1; 530 endAngleIndex = (int)(stopAngle * sides) + 1;
531 if (endAngleIndex == startAngleIndex) 531 if (endAngleIndex == startAngleIndex)
532 endAngleIndex++; 532 endAngleIndex++;
533 533
534 for (int angleIndex = startAngleIndex; angleIndex < endAngleIndex + 1; angleIndex++) 534 for (int angleIndex = startAngleIndex; angleIndex < endAngleIndex + 1; angleIndex++)
535 { 535 {
536 angles.Add(sourceAngles[angleIndex]); 536 angles.Add(sourceAngles[angleIndex]);
537 if (sides == 3) 537 if (sides == 3)
538 normals.Add(normals3[angleIndex]); 538 normals.Add(normals3[angleIndex]);
539 else if (sides == 4) 539 else if (sides == 4)
540 normals.Add(normals4[angleIndex]); 540 normals.Add(normals4[angleIndex]);
541 } 541 }
542 542
543 if (startAngle > 0.0f) 543 if (startAngle > 0.0f)
544 angles[0] = interpolatePoints(startAngle, angles[0], angles[1]); 544 angles[0] = interpolatePoints(startAngle, angles[0], angles[1]);
545 545
546 if (stopAngle < 1.0f) 546 if (stopAngle < 1.0f)
547 { 547 {
548 int lastAngleIndex = angles.Count - 1; 548 int lastAngleIndex = angles.Count - 1;
549 angles[lastAngleIndex] = interpolatePoints(stopAngle, angles[lastAngleIndex - 1], angles[lastAngleIndex]); 549 angles[lastAngleIndex] = interpolatePoints(stopAngle, angles[lastAngleIndex - 1], angles[lastAngleIndex]);
550 } 550 }
551 } 551 }
552 else 552 else
553 { 553 {
554 double stepSize = twoPi / sides; 554 double stepSize = twoPi / sides;
555 555
556 int startStep = (int)(startAngle / stepSize); 556 int startStep = (int)(startAngle / stepSize);
557 double angle = stepSize * startStep; 557 double angle = stepSize * startStep;
558 int step = startStep; 558 int step = startStep;
559 double stopAngleTest = stopAngle; 559 double stopAngleTest = stopAngle;
560 if (stopAngle < twoPi) 560 if (stopAngle < twoPi)
561 { 561 {
562 stopAngleTest = stepSize * ((int)(stopAngle / stepSize) + 1); 562 stopAngleTest = stepSize * ((int)(stopAngle / stepSize) + 1);
563 if (stopAngleTest < stopAngle) 563 if (stopAngleTest < stopAngle)
564 stopAngleTest += stepSize; 564 stopAngleTest += stepSize;
565 if (stopAngleTest > twoPi) 565 if (stopAngleTest > twoPi)
566 stopAngleTest = twoPi; 566 stopAngleTest = twoPi;
567 } 567 }
568 568
569 while (angle <= stopAngleTest) 569 while (angle <= stopAngleTest)
570 { 570 {
571 Angle newAngle; 571 Angle newAngle;
572 newAngle.angle = (float)angle; 572 newAngle.angle = (float)angle;
573 newAngle.X = (float)System.Math.Cos(angle); 573 newAngle.X = (float)System.Math.Cos(angle);
574 newAngle.Y = (float)System.Math.Sin(angle); 574 newAngle.Y = (float)System.Math.Sin(angle);
575 angles.Add(newAngle); 575 angles.Add(newAngle);
576 step += 1; 576 step += 1;
577 angle = stepSize * step; 577 angle = stepSize * step;
578 } 578 }
579 579
580 if (startAngle > angles[0].angle) 580 if (startAngle > angles[0].angle)
581 { 581 {
582 Angle newAngle; 582 Angle newAngle;
583 intersection(angles[0].X, angles[0].Y, angles[1].X, angles[1].Y, 0.0f, 0.0f, (float)Math.Cos(startAngle), (float)Math.Sin(startAngle)); 583 intersection(angles[0].X, angles[0].Y, angles[1].X, angles[1].Y, 0.0f, 0.0f, (float)Math.Cos(startAngle), (float)Math.Sin(startAngle));
584 newAngle.angle = startAngle; 584 newAngle.angle = startAngle;
585 newAngle.X = iX; 585 newAngle.X = iX;
586 newAngle.Y = iY; 586 newAngle.Y = iY;
587 angles[0] = newAngle; 587 angles[0] = newAngle;
588 } 588 }
589 589
590 int index = angles.Count - 1; 590 int index = angles.Count - 1;
591 if (stopAngle < angles[index].angle) 591 if (stopAngle < angles[index].angle)
592 { 592 {
593 Angle newAngle; 593 Angle newAngle;
594 intersection(angles[index - 1].X, angles[index - 1].Y, angles[index].X, angles[index].Y, 0.0f, 0.0f, (float)Math.Cos(stopAngle), (float)Math.Sin(stopAngle)); 594 intersection(angles[index - 1].X, angles[index - 1].Y, angles[index].X, angles[index].Y, 0.0f, 0.0f, (float)Math.Cos(stopAngle), (float)Math.Sin(stopAngle));
595 newAngle.angle = stopAngle; 595 newAngle.angle = stopAngle;
596 newAngle.X = iX; 596 newAngle.X = iX;
597 newAngle.Y = iY; 597 newAngle.Y = iY;
598 angles[index] = newAngle; 598 angles[index] = newAngle;
599 } 599 }
600 } 600 }
601 } 601 }
602 } 602 }
603 603
604 /// <summary> 604 /// <summary>
605 /// generates a profile for extrusion 605 /// generates a profile for extrusion
606 /// </summary> 606 /// </summary>
607 internal class Profile 607 internal class Profile
608 { 608 {
609 private const float twoPi = 2.0f * (float)Math.PI; 609 private const float twoPi = 2.0f * (float)Math.PI;
610 610
611 internal string errorMessage = null; 611 internal string errorMessage = null;
612 612
613 internal List<Coord> coords; 613 internal List<Coord> coords;
614 internal List<Face> faces; 614 internal List<Face> faces;
615 internal List<Coord> vertexNormals; 615 internal List<Coord> vertexNormals;
616 internal List<float> us; 616 internal List<float> us;
617 internal List<UVCoord> faceUVs; 617 internal List<UVCoord> faceUVs;
618 internal List<int> faceNumbers; 618 internal List<int> faceNumbers;
619 619
620 // use these for making individual meshes for each prim face 620 // use these for making individual meshes for each prim face
621 internal List<int> outerCoordIndices = null; 621 internal List<int> outerCoordIndices = null;
622 internal List<int> hollowCoordIndices = null; 622 internal List<int> hollowCoordIndices = null;
623 internal List<int> cut1CoordIndices = null; 623 internal List<int> cut1CoordIndices = null;
624 internal List<int> cut2CoordIndices = null; 624 internal List<int> cut2CoordIndices = null;
625 625
626 internal Coord faceNormal = new Coord(0.0f, 0.0f, 1.0f); 626 internal Coord faceNormal = new Coord(0.0f, 0.0f, 1.0f);
627 internal Coord cutNormal1 = new Coord(); 627 internal Coord cutNormal1 = new Coord();
628 internal Coord cutNormal2 = new Coord(); 628 internal Coord cutNormal2 = new Coord();
629 629
630 internal int numOuterVerts = 0; 630 internal int numOuterVerts = 0;
631 internal int numHollowVerts = 0; 631 internal int numHollowVerts = 0;
632 632
633 internal bool calcVertexNormals = false; 633 internal bool calcVertexNormals = false;
634 internal int bottomFaceNumber = 0; 634 internal int bottomFaceNumber = 0;
635 internal int numPrimFaces = 0; 635 internal int numPrimFaces = 0;
636 636
637 internal Profile() 637 internal Profile()
638 { 638 {
639 this.coords = new List<Coord>(); 639 this.coords = new List<Coord>();
640 this.faces = new List<Face>(); 640 this.faces = new List<Face>();
641 this.vertexNormals = new List<Coord>(); 641 this.vertexNormals = new List<Coord>();
642 this.us = new List<float>(); 642 this.us = new List<float>();
643 this.faceUVs = new List<UVCoord>(); 643 this.faceUVs = new List<UVCoord>();
644 this.faceNumbers = new List<int>(); 644 this.faceNumbers = new List<int>();
645 } 645 }
646 646
647 internal Profile(int sides, float profileStart, float profileEnd, float hollow, int hollowSides, bool createFaces, bool calcVertexNormals) 647 internal Profile(int sides, float profileStart, float profileEnd, float hollow, int hollowSides, bool createFaces, bool calcVertexNormals)
648 { 648 {
649 this.calcVertexNormals = calcVertexNormals; 649 this.calcVertexNormals = calcVertexNormals;
650 this.coords = new List<Coord>(); 650 this.coords = new List<Coord>();
651 this.faces = new List<Face>(); 651 this.faces = new List<Face>();
652 this.vertexNormals = new List<Coord>(); 652 this.vertexNormals = new List<Coord>();
653 this.us = new List<float>(); 653 this.us = new List<float>();
654 this.faceUVs = new List<UVCoord>(); 654 this.faceUVs = new List<UVCoord>();
655 this.faceNumbers = new List<int>(); 655 this.faceNumbers = new List<int>();
656 656
657 Coord center = new Coord(0.0f, 0.0f, 0.0f); 657 Coord center = new Coord(0.0f, 0.0f, 0.0f);
658 //bool hasCenter = false; 658 //bool hasCenter = false;
659 659
660 List<Coord> hollowCoords = new List<Coord>(); 660 List<Coord> hollowCoords = new List<Coord>();
661 List<Coord> hollowNormals = new List<Coord>(); 661 List<Coord> hollowNormals = new List<Coord>();
662 List<float> hollowUs = new List<float>(); 662 List<float> hollowUs = new List<float>();
663 663
664 if (calcVertexNormals) 664 if (calcVertexNormals)
665 { 665 {
666 this.outerCoordIndices = new List<int>(); 666 this.outerCoordIndices = new List<int>();
667 this.hollowCoordIndices = new List<int>(); 667 this.hollowCoordIndices = new List<int>();
668 this.cut1CoordIndices = new List<int>(); 668 this.cut1CoordIndices = new List<int>();
669 this.cut2CoordIndices = new List<int>(); 669 this.cut2CoordIndices = new List<int>();
670 } 670 }
671 671
672 bool hasHollow = (hollow > 0.0f); 672 bool hasHollow = (hollow > 0.0f);
673 673
674 bool hasProfileCut = (profileStart > 0.0f || profileEnd < 1.0f); 674 bool hasProfileCut = (profileStart > 0.0f || profileEnd < 1.0f);
675 675
676 AngleList angles = new AngleList(); 676 AngleList angles = new AngleList();
677 AngleList hollowAngles = new AngleList(); 677 AngleList hollowAngles = new AngleList();
678 678
679 float xScale = 0.5f; 679 float xScale = 0.5f;
680 float yScale = 0.5f; 680 float yScale = 0.5f;
681 if (sides == 4) // corners of a square are sqrt(2) from center 681 if (sides == 4) // corners of a square are sqrt(2) from center
682 { 682 {
683 xScale = 0.707f; 683 xScale = 0.707f;
684 yScale = 0.707f; 684 yScale = 0.707f;
685 } 685 }
686 686
687 float startAngle = profileStart * twoPi; 687 float startAngle = profileStart * twoPi;
688 float stopAngle = profileEnd * twoPi; 688 float stopAngle = profileEnd * twoPi;
689 689
690 try { angles.makeAngles(sides, startAngle, stopAngle); } 690 try { angles.makeAngles(sides, startAngle, stopAngle); }
691 catch (Exception ex) 691 catch (Exception ex)
692 { 692 {
693 693
694 errorMessage = "makeAngles failed: Exception: " + ex.ToString() 694 errorMessage = "makeAngles failed: Exception: " + ex.ToString()
695 + "\nsides: " + sides.ToString() + " startAngle: " + startAngle.ToString() + " stopAngle: " + stopAngle.ToString(); 695 + "\nsides: " + sides.ToString() + " startAngle: " + startAngle.ToString() + " stopAngle: " + stopAngle.ToString();
696 696
697 return; 697 return;
698 } 698 }
699 699
700 this.numOuterVerts = angles.angles.Count; 700 this.numOuterVerts = angles.angles.Count;
701 701
702 // flag to create as few triangles as possible for 3 or 4 side profile 702 // flag to create as few triangles as possible for 3 or 4 side profile
703 bool simpleFace = (sides < 5 && !hasHollow && !hasProfileCut); 703 bool simpleFace = (sides < 5 && !hasHollow && !hasProfileCut);
704 704
705 if (hasHollow) 705 if (hasHollow)
706 { 706 {
707 if (sides == hollowSides) 707 if (sides == hollowSides)
708 hollowAngles = angles; 708 hollowAngles = angles;
709 else 709 else
710 { 710 {
711 try { hollowAngles.makeAngles(hollowSides, startAngle, stopAngle); } 711 try { hollowAngles.makeAngles(hollowSides, startAngle, stopAngle); }
712 catch (Exception ex) 712 catch (Exception ex)
713 { 713 {
714 errorMessage = "makeAngles failed: Exception: " + ex.ToString() 714 errorMessage = "makeAngles failed: Exception: " + ex.ToString()
715 + "\nsides: " + sides.ToString() + " startAngle: " + startAngle.ToString() + " stopAngle: " + stopAngle.ToString(); 715 + "\nsides: " + sides.ToString() + " startAngle: " + startAngle.ToString() + " stopAngle: " + stopAngle.ToString();
716 716
717 return; 717 return;
718 } 718 }
719 } 719 }
720 this.numHollowVerts = hollowAngles.angles.Count; 720 this.numHollowVerts = hollowAngles.angles.Count;
721 } 721 }
722 else if (!simpleFace) 722 else if (!simpleFace)
723 { 723 {
724 this.coords.Add(center); 724 this.coords.Add(center);
725 //hasCenter = true; 725 //hasCenter = true;
726 if (this.calcVertexNormals) 726 if (this.calcVertexNormals)
727 this.vertexNormals.Add(new Coord(0.0f, 0.0f, 1.0f)); 727 this.vertexNormals.Add(new Coord(0.0f, 0.0f, 1.0f));
728 this.us.Add(0.0f); 728 this.us.Add(0.0f);
729 } 729 }
730 730
731 float z = 0.0f; 731 float z = 0.0f;
732 732
733 Angle angle; 733 Angle angle;
734 Coord newVert = new Coord(); 734 Coord newVert = new Coord();
735 if (hasHollow && hollowSides != sides) 735 if (hasHollow && hollowSides != sides)
736 { 736 {
737 int numHollowAngles = hollowAngles.angles.Count; 737 int numHollowAngles = hollowAngles.angles.Count;
738 for (int i = 0; i < numHollowAngles; i++) 738 for (int i = 0; i < numHollowAngles; i++)
739 { 739 {
740 angle = hollowAngles.angles[i]; 740 angle = hollowAngles.angles[i];
741 newVert.X = hollow * xScale * angle.X; 741 newVert.X = hollow * xScale * angle.X;
742 newVert.Y = hollow * yScale * angle.Y; 742 newVert.Y = hollow * yScale * angle.Y;
743 newVert.Z = z; 743 newVert.Z = z;
744 744
745 hollowCoords.Add(newVert); 745 hollowCoords.Add(newVert);
746 if (this.calcVertexNormals) 746 if (this.calcVertexNormals)
747 { 747 {
748 if (hollowSides < 5) 748 if (hollowSides < 5)
749 hollowNormals.Add(hollowAngles.normals[i].Invert()); 749 hollowNormals.Add(hollowAngles.normals[i].Invert());
750 else 750 else
751 hollowNormals.Add(new Coord(-angle.X, -angle.Y, 0.0f)); 751 hollowNormals.Add(new Coord(-angle.X, -angle.Y, 0.0f));
752 752
753 hollowUs.Add(angle.angle * hollow); 753 hollowUs.Add(angle.angle * hollow);
754 } 754 }
755 } 755 }
756 } 756 }
757 757
758 int index = 0; 758 int index = 0;
759 int numAngles = angles.angles.Count; 759 int numAngles = angles.angles.Count;
760 760
761 for (int i = 0; i < numAngles; i++) 761 for (int i = 0; i < numAngles; i++)
762 { 762 {
763 angle = angles.angles[i]; 763 angle = angles.angles[i];
764 newVert.X = angle.X * xScale; 764 newVert.X = angle.X * xScale;
765 newVert.Y = angle.Y * yScale; 765 newVert.Y = angle.Y * yScale;
766 newVert.Z = z; 766 newVert.Z = z;
767 this.coords.Add(newVert); 767 this.coords.Add(newVert);
768 if (this.calcVertexNormals) 768 if (this.calcVertexNormals)
769 { 769 {
770 this.outerCoordIndices.Add(this.coords.Count - 1); 770 this.outerCoordIndices.Add(this.coords.Count - 1);
771 771
772 if (sides < 5) 772 if (sides < 5)
773 { 773 {
774 this.vertexNormals.Add(angles.normals[i]); 774 this.vertexNormals.Add(angles.normals[i]);
775 float u = angle.angle; 775 float u = angle.angle;
776 this.us.Add(u); 776 this.us.Add(u);
777 } 777 }
778 else 778 else
779 { 779 {
780 this.vertexNormals.Add(new Coord(angle.X, angle.Y, 0.0f)); 780 this.vertexNormals.Add(new Coord(angle.X, angle.Y, 0.0f));
781 this.us.Add(angle.angle); 781 this.us.Add(angle.angle);
782 } 782 }
783 } 783 }
784 784
785 if (hasHollow) 785 if (hasHollow)
786 { 786 {
787 if (hollowSides == sides) 787 if (hollowSides == sides)
788 { 788 {
789 newVert.X *= hollow; 789 newVert.X *= hollow;
790 newVert.Y *= hollow; 790 newVert.Y *= hollow;
791 newVert.Z = z; 791 newVert.Z = z;
792 hollowCoords.Add(newVert); 792 hollowCoords.Add(newVert);
793 if (this.calcVertexNormals) 793 if (this.calcVertexNormals)
794 { 794 {
795 if (sides < 5) 795 if (sides < 5)
796 { 796 {
797 hollowNormals.Add(angles.normals[i].Invert()); 797 hollowNormals.Add(angles.normals[i].Invert());
798 } 798 }
799 799
800 else 800 else
801 hollowNormals.Add(new Coord(-angle.X, -angle.Y, 0.0f)); 801 hollowNormals.Add(new Coord(-angle.X, -angle.Y, 0.0f));
802 802
803 hollowUs.Add(angle.angle * hollow); 803 hollowUs.Add(angle.angle * hollow);
804 } 804 }
805 } 805 }
806 } 806 }
807 else if (!simpleFace && createFaces && angle.angle > 0.0001f) 807 else if (!simpleFace && createFaces && angle.angle > 0.0001f)
808 { 808 {
809 Face newFace = new Face(); 809 Face newFace = new Face();
810 newFace.v1 = 0; 810 newFace.v1 = 0;
811 newFace.v2 = index; 811 newFace.v2 = index;
812 newFace.v3 = index + 1; 812 newFace.v3 = index + 1;
813 813
814 this.faces.Add(newFace); 814 this.faces.Add(newFace);
815 } 815 }
816 index += 1; 816 index += 1;
817 } 817 }
818 818
819 if (hasHollow) 819 if (hasHollow)
820 { 820 {
821 hollowCoords.Reverse(); 821 hollowCoords.Reverse();
822 if (this.calcVertexNormals) 822 if (this.calcVertexNormals)
823 { 823 {
824 hollowNormals.Reverse(); 824 hollowNormals.Reverse();
825 hollowUs.Reverse(); 825 hollowUs.Reverse();
826 } 826 }
827 827
828 if (createFaces) 828 if (createFaces)
829 { 829 {
830 //int numOuterVerts = this.coords.Count; 830 //int numOuterVerts = this.coords.Count;
831 //numOuterVerts = this.coords.Count; 831 //numOuterVerts = this.coords.Count;
832 //int numHollowVerts = hollowCoords.Count; 832 //int numHollowVerts = hollowCoords.Count;
833 int numTotalVerts = this.numOuterVerts + this.numHollowVerts; 833 int numTotalVerts = this.numOuterVerts + this.numHollowVerts;
834 834
835 if (this.numOuterVerts == this.numHollowVerts) 835 if (this.numOuterVerts == this.numHollowVerts)
836 { 836 {
837 Face newFace = new Face(); 837 Face newFace = new Face();
838 838
839 for (int coordIndex = 0; coordIndex < this.numOuterVerts - 1; coordIndex++) 839 for (int coordIndex = 0; coordIndex < this.numOuterVerts - 1; coordIndex++)
840 { 840 {
841 newFace.v1 = coordIndex; 841 newFace.v1 = coordIndex;
842 newFace.v2 = coordIndex + 1; 842 newFace.v2 = coordIndex + 1;
843 newFace.v3 = numTotalVerts - coordIndex - 1; 843 newFace.v3 = numTotalVerts - coordIndex - 1;
844 this.faces.Add(newFace); 844 this.faces.Add(newFace);
845 845
846 newFace.v1 = coordIndex + 1; 846 newFace.v1 = coordIndex + 1;
847 newFace.v2 = numTotalVerts - coordIndex - 2; 847 newFace.v2 = numTotalVerts - coordIndex - 2;
848 newFace.v3 = numTotalVerts - coordIndex - 1; 848 newFace.v3 = numTotalVerts - coordIndex - 1;
849 this.faces.Add(newFace); 849 this.faces.Add(newFace);
850 } 850 }
851 } 851 }
852 else 852 else
853 { 853 {
854 if (this.numOuterVerts < this.numHollowVerts) 854 if (this.numOuterVerts < this.numHollowVerts)
855 { 855 {
856 Face newFace = new Face(); 856 Face newFace = new Face();
857 int j = 0; // j is the index for outer vertices 857 int j = 0; // j is the index for outer vertices
858 int maxJ = this.numOuterVerts - 1; 858 int maxJ = this.numOuterVerts - 1;
859 for (int i = 0; i < this.numHollowVerts; i++) // i is the index for inner vertices 859 for (int i = 0; i < this.numHollowVerts; i++) // i is the index for inner vertices
860 { 860 {
861 if (j < maxJ) 861 if (j < maxJ)
862 if (angles.angles[j + 1].angle - hollowAngles.angles[i].angle < hollowAngles.angles[i].angle - angles.angles[j].angle + 0.000001f) 862 if (angles.angles[j + 1].angle - hollowAngles.angles[i].angle < hollowAngles.angles[i].angle - angles.angles[j].angle + 0.000001f)
863 { 863 {
864 newFace.v1 = numTotalVerts - i - 1; 864 newFace.v1 = numTotalVerts - i - 1;
865 newFace.v2 = j; 865 newFace.v2 = j;
866 newFace.v3 = j + 1; 866 newFace.v3 = j + 1;
867 867
868 this.faces.Add(newFace); 868 this.faces.Add(newFace);
869 j += 1; 869 j += 1;
870 } 870 }
871 871
872 newFace.v1 = j; 872 newFace.v1 = j;
873 newFace.v2 = numTotalVerts - i - 2; 873 newFace.v2 = numTotalVerts - i - 2;
874 newFace.v3 = numTotalVerts - i - 1; 874 newFace.v3 = numTotalVerts - i - 1;
875 875
876 this.faces.Add(newFace); 876 this.faces.Add(newFace);
877 } 877 }
878 } 878 }
879 else // numHollowVerts < numOuterVerts 879 else // numHollowVerts < numOuterVerts
880 { 880 {
881 Face newFace = new Face(); 881 Face newFace = new Face();
882 int j = 0; // j is the index for inner vertices 882 int j = 0; // j is the index for inner vertices
883 int maxJ = this.numHollowVerts - 1; 883 int maxJ = this.numHollowVerts - 1;
884 for (int i = 0; i < this.numOuterVerts; i++) 884 for (int i = 0; i < this.numOuterVerts; i++)
885 { 885 {
886 if (j < maxJ) 886 if (j < maxJ)
887 if (hollowAngles.angles[j + 1].angle - angles.angles[i].angle < angles.angles[i].angle - hollowAngles.angles[j].angle + 0.000001f) 887 if (hollowAngles.angles[j + 1].angle - angles.angles[i].angle < angles.angles[i].angle - hollowAngles.angles[j].angle + 0.000001f)
888 { 888 {
889 newFace.v1 = i; 889 newFace.v1 = i;
890 newFace.v2 = numTotalVerts - j - 2; 890 newFace.v2 = numTotalVerts - j - 2;
891 newFace.v3 = numTotalVerts - j - 1; 891 newFace.v3 = numTotalVerts - j - 1;
892 892
893 this.faces.Add(newFace); 893 this.faces.Add(newFace);
894 j += 1; 894 j += 1;
895 } 895 }
896 896
897 newFace.v1 = numTotalVerts - j - 1; 897 newFace.v1 = numTotalVerts - j - 1;
898 newFace.v2 = i; 898 newFace.v2 = i;
899 newFace.v3 = i + 1; 899 newFace.v3 = i + 1;
900 900
901 this.faces.Add(newFace); 901 this.faces.Add(newFace);
902 } 902 }
903 } 903 }
904 } 904 }
905 } 905 }
906 906
907 if (calcVertexNormals) 907 if (calcVertexNormals)
908 { 908 {
909 foreach (Coord hc in hollowCoords) 909 foreach (Coord hc in hollowCoords)
910 { 910 {
911 this.coords.Add(hc); 911 this.coords.Add(hc);
912 hollowCoordIndices.Add(this.coords.Count - 1); 912 hollowCoordIndices.Add(this.coords.Count - 1);
913 } 913 }
914 } 914 }
915 else 915 else
916 this.coords.AddRange(hollowCoords); 916 this.coords.AddRange(hollowCoords);
917 917
918 if (this.calcVertexNormals) 918 if (this.calcVertexNormals)
919 { 919 {
920 this.vertexNormals.AddRange(hollowNormals); 920 this.vertexNormals.AddRange(hollowNormals);
921 this.us.AddRange(hollowUs); 921 this.us.AddRange(hollowUs);
922 922
923 } 923 }
924 } 924 }
925 925
926 if (simpleFace && createFaces) 926 if (simpleFace && createFaces)
927 { 927 {
928 if (sides == 3) 928 if (sides == 3)
929 this.faces.Add(new Face(0, 1, 2)); 929 this.faces.Add(new Face(0, 1, 2));
930 else if (sides == 4) 930 else if (sides == 4)
931 { 931 {
932 this.faces.Add(new Face(0, 1, 2)); 932 this.faces.Add(new Face(0, 1, 2));
933 this.faces.Add(new Face(0, 2, 3)); 933 this.faces.Add(new Face(0, 2, 3));
934 } 934 }
935 } 935 }
936 936
937 if (calcVertexNormals && hasProfileCut) 937 if (calcVertexNormals && hasProfileCut)
938 { 938 {
939 if (hasHollow) 939 if (hasHollow)
940 { 940 {
941 int lastOuterVertIndex = this.numOuterVerts - 1; 941 int lastOuterVertIndex = this.numOuterVerts - 1;
942 942
943 this.cut1CoordIndices.Add(0); 943 this.cut1CoordIndices.Add(0);
944 this.cut1CoordIndices.Add(this.coords.Count - 1); 944 this.cut1CoordIndices.Add(this.coords.Count - 1);
945 945
946 this.cut2CoordIndices.Add(lastOuterVertIndex + 1); 946 this.cut2CoordIndices.Add(lastOuterVertIndex + 1);
947 this.cut2CoordIndices.Add(lastOuterVertIndex); 947 this.cut2CoordIndices.Add(lastOuterVertIndex);
948 948
949 this.cutNormal1.X = this.coords[0].Y - this.coords[this.coords.Count - 1].Y; 949 this.cutNormal1.X = this.coords[0].Y - this.coords[this.coords.Count - 1].Y;
950 this.cutNormal1.Y = -(this.coords[0].X - this.coords[this.coords.Count - 1].X); 950 this.cutNormal1.Y = -(this.coords[0].X - this.coords[this.coords.Count - 1].X);
951 951
952 this.cutNormal2.X = this.coords[lastOuterVertIndex + 1].Y - this.coords[lastOuterVertIndex].Y; 952 this.cutNormal2.X = this.coords[lastOuterVertIndex + 1].Y - this.coords[lastOuterVertIndex].Y;
953 this.cutNormal2.Y = -(this.coords[lastOuterVertIndex + 1].X - this.coords[lastOuterVertIndex].X); 953 this.cutNormal2.Y = -(this.coords[lastOuterVertIndex + 1].X - this.coords[lastOuterVertIndex].X);
954 } 954 }
955 955
956 else 956 else
957 { 957 {
958 this.cutNormal1.X = this.vertexNormals[1].Y; 958 this.cutNormal1.X = this.vertexNormals[1].Y;
959 this.cutNormal1.Y = -this.vertexNormals[1].X; 959 this.cutNormal1.Y = -this.vertexNormals[1].X;
960 960
961 this.cutNormal2.X = -this.vertexNormals[this.vertexNormals.Count - 2].Y; 961 this.cutNormal2.X = -this.vertexNormals[this.vertexNormals.Count - 2].Y;
962 this.cutNormal2.Y = this.vertexNormals[this.vertexNormals.Count - 2].X; 962 this.cutNormal2.Y = this.vertexNormals[this.vertexNormals.Count - 2].X;
963 963
964 } 964 }
965 this.cutNormal1.Normalize(); 965 this.cutNormal1.Normalize();
966 this.cutNormal2.Normalize(); 966 this.cutNormal2.Normalize();
967 } 967 }
968 968
969 this.MakeFaceUVs(); 969 this.MakeFaceUVs();
970 970
971 hollowCoords = null; 971 hollowCoords = null;
972 hollowNormals = null; 972 hollowNormals = null;
973 hollowUs = null; 973 hollowUs = null;
974 974
975 if (calcVertexNormals) 975 if (calcVertexNormals)
976 { // calculate prim face numbers 976 { // calculate prim face numbers
977 977
978 // face number order is top, outer, hollow, bottom, start cut, end cut 978 // face number order is top, outer, hollow, bottom, start cut, end cut
979 // I know it's ugly but so is the whole concept of prim face numbers 979 // I know it's ugly but so is the whole concept of prim face numbers
980 980
981 int faceNum = 1; // start with outer faces 981 int faceNum = 1; // start with outer faces
982 int startVert = hasProfileCut && !hasHollow ? 1 : 0; 982 int startVert = hasProfileCut && !hasHollow ? 1 : 0;
983 if (startVert > 0) 983 if (startVert > 0)
984 this.faceNumbers.Add(-1); 984 this.faceNumbers.Add(-1);
985 for (int i = 0; i < this.numOuterVerts - 1; i++) 985 for (int i = 0; i < this.numOuterVerts - 1; i++)
986 this.faceNumbers.Add(sides < 5 ? faceNum++ : faceNum); 986 this.faceNumbers.Add(sides < 5 ? faceNum++ : faceNum);
987 987
988 //if (!hasHollow && !hasProfileCut) 988 //if (!hasHollow && !hasProfileCut)
989 // this.bottomFaceNumber = faceNum++; 989 // this.bottomFaceNumber = faceNum++;
990 990
991 this.faceNumbers.Add(hasProfileCut ? -1 : faceNum++); 991 this.faceNumbers.Add(hasProfileCut ? -1 : faceNum++);
992 992
993 if (sides > 4 && (hasHollow || hasProfileCut)) 993 if (sides > 4 && (hasHollow || hasProfileCut))
994 faceNum++; 994 faceNum++;
995 995
996 if (hasHollow) 996 if (hasHollow)
997 { 997 {
998 for (int i = 0; i < this.numHollowVerts; i++) 998 for (int i = 0; i < this.numHollowVerts; i++)
999 this.faceNumbers.Add(faceNum); 999 this.faceNumbers.Add(faceNum);
1000 1000
1001 faceNum++; 1001 faceNum++;
1002 } 1002 }
1003 //if (hasProfileCut || hasHollow) 1003 //if (hasProfileCut || hasHollow)
1004 // this.bottomFaceNumber = faceNum++; 1004 // this.bottomFaceNumber = faceNum++;
1005 this.bottomFaceNumber = faceNum++; 1005 this.bottomFaceNumber = faceNum++;
1006 1006
1007 if (hasHollow && hasProfileCut) 1007 if (hasHollow && hasProfileCut)
1008 this.faceNumbers.Add(faceNum++); 1008 this.faceNumbers.Add(faceNum++);
1009 for (int i = 0; i < this.faceNumbers.Count; i++) 1009 for (int i = 0; i < this.faceNumbers.Count; i++)
1010 if (this.faceNumbers[i] == -1) 1010 if (this.faceNumbers[i] == -1)
1011 this.faceNumbers[i] = faceNum++; 1011 this.faceNumbers[i] = faceNum++;
1012 1012
1013 1013
1014 this.numPrimFaces = faceNum; 1014 this.numPrimFaces = faceNum;
1015 } 1015 }
1016 1016
1017 } 1017 }
1018 1018
1019 internal void MakeFaceUVs() 1019 internal void MakeFaceUVs()
1020 { 1020 {
1021 this.faceUVs = new List<UVCoord>(); 1021 this.faceUVs = new List<UVCoord>();
1022 foreach (Coord c in this.coords) 1022 foreach (Coord c in this.coords)
1023 this.faceUVs.Add(new UVCoord(0.5f + c.X, 0.5f - c.Y)); 1023 this.faceUVs.Add(new UVCoord(0.5f + c.X, 0.5f - c.Y));
1024 } 1024 }
1025 1025
1026 internal Profile Copy() 1026 internal Profile Copy()
1027 { 1027 {
1028 return this.Copy(true); 1028 return this.Copy(true);
1029 } 1029 }
1030 1030
1031 internal Profile Copy(bool needFaces) 1031 internal Profile Copy(bool needFaces)
1032 { 1032 {
1033 Profile copy = new Profile(); 1033 Profile copy = new Profile();
1034 1034
1035 copy.coords.AddRange(this.coords); 1035 copy.coords.AddRange(this.coords);
1036 copy.faceUVs.AddRange(this.faceUVs); 1036 copy.faceUVs.AddRange(this.faceUVs);
1037 1037
1038 if (needFaces) 1038 if (needFaces)
1039 copy.faces.AddRange(this.faces); 1039 copy.faces.AddRange(this.faces);
1040 if ((copy.calcVertexNormals = this.calcVertexNormals) == true) 1040 if ((copy.calcVertexNormals = this.calcVertexNormals) == true)
1041 { 1041 {
1042 copy.vertexNormals.AddRange(this.vertexNormals); 1042 copy.vertexNormals.AddRange(this.vertexNormals);
1043 copy.faceNormal = this.faceNormal; 1043 copy.faceNormal = this.faceNormal;
1044 copy.cutNormal1 = this.cutNormal1; 1044 copy.cutNormal1 = this.cutNormal1;
1045 copy.cutNormal2 = this.cutNormal2; 1045 copy.cutNormal2 = this.cutNormal2;
1046 copy.us.AddRange(this.us); 1046 copy.us.AddRange(this.us);
1047 copy.faceNumbers.AddRange(this.faceNumbers); 1047 copy.faceNumbers.AddRange(this.faceNumbers);
1048 1048
1049 copy.cut1CoordIndices = new List<int>(this.cut1CoordIndices); 1049 copy.cut1CoordIndices = new List<int>(this.cut1CoordIndices);
1050 copy.cut2CoordIndices = new List<int>(this.cut2CoordIndices); 1050 copy.cut2CoordIndices = new List<int>(this.cut2CoordIndices);
1051 copy.hollowCoordIndices = new List<int>(this.hollowCoordIndices); 1051 copy.hollowCoordIndices = new List<int>(this.hollowCoordIndices);
1052 copy.outerCoordIndices = new List<int>(this.outerCoordIndices); 1052 copy.outerCoordIndices = new List<int>(this.outerCoordIndices);
1053 } 1053 }
1054 copy.numOuterVerts = this.numOuterVerts; 1054 copy.numOuterVerts = this.numOuterVerts;
1055 copy.numHollowVerts = this.numHollowVerts; 1055 copy.numHollowVerts = this.numHollowVerts;
1056 1056
1057 return copy; 1057 return copy;
1058 } 1058 }
1059 1059
1060 internal void AddPos(Coord v) 1060 internal void AddPos(Coord v)
1061 { 1061 {
1062 this.AddPos(v.X, v.Y, v.Z); 1062 this.AddPos(v.X, v.Y, v.Z);
1063 } 1063 }
1064 1064
1065 internal void AddPos(float x, float y, float z) 1065 internal void AddPos(float x, float y, float z)
1066 { 1066 {
1067 int i; 1067 int i;
1068 int numVerts = this.coords.Count; 1068 int numVerts = this.coords.Count;
1069 Coord vert; 1069 Coord vert;
1070 1070
1071 for (i = 0; i < numVerts; i++) 1071 for (i = 0; i < numVerts; i++)
1072 { 1072 {
1073 vert = this.coords[i]; 1073 vert = this.coords[i];
1074 vert.X += x; 1074 vert.X += x;
1075 vert.Y += y; 1075 vert.Y += y;
1076 vert.Z += z; 1076 vert.Z += z;
1077 this.coords[i] = vert; 1077 this.coords[i] = vert;
1078 } 1078 }
1079 } 1079 }
1080 1080
1081 internal void AddRot(Quat q) 1081 internal void AddRot(Quat q)
1082 { 1082 {
1083 int i; 1083 int i;
1084 int numVerts = this.coords.Count; 1084 int numVerts = this.coords.Count;
1085 1085
1086 for (i = 0; i < numVerts; i++) 1086 for (i = 0; i < numVerts; i++)
1087 this.coords[i] *= q; 1087 this.coords[i] *= q;
1088 1088
1089 if (this.calcVertexNormals) 1089 if (this.calcVertexNormals)
1090 { 1090 {
1091 int numNormals = this.vertexNormals.Count; 1091 int numNormals = this.vertexNormals.Count;
1092 for (i = 0; i < numNormals; i++) 1092 for (i = 0; i < numNormals; i++)
1093 this.vertexNormals[i] *= q; 1093 this.vertexNormals[i] *= q;
1094 1094
1095 this.faceNormal *= q; 1095 this.faceNormal *= q;
1096 this.cutNormal1 *= q; 1096 this.cutNormal1 *= q;
1097 this.cutNormal2 *= q; 1097 this.cutNormal2 *= q;
1098 1098
1099 } 1099 }
1100 } 1100 }
1101 1101
1102 internal void Scale(float x, float y) 1102 internal void Scale(float x, float y)
1103 { 1103 {
1104 int i; 1104 int i;
1105 int numVerts = this.coords.Count; 1105 int numVerts = this.coords.Count;
1106 Coord vert; 1106 Coord vert;
1107 1107
1108 for (i = 0; i < numVerts; i++) 1108 for (i = 0; i < numVerts; i++)
1109 { 1109 {
1110 vert = this.coords[i]; 1110 vert = this.coords[i];
1111 vert.X *= x; 1111 vert.X *= x;
1112 vert.Y *= y; 1112 vert.Y *= y;
1113 this.coords[i] = vert; 1113 this.coords[i] = vert;
1114 } 1114 }
1115 } 1115 }
1116 1116
1117 /// <summary> 1117 /// <summary>
1118 /// Changes order of the vertex indices and negates the center vertex normal. Does not alter vertex normals of radial vertices 1118 /// Changes order of the vertex indices and negates the center vertex normal. Does not alter vertex normals of radial vertices
1119 /// </summary> 1119 /// </summary>
1120 internal void FlipNormals() 1120 internal void FlipNormals()
1121 { 1121 {
1122 int i; 1122 int i;
1123 int numFaces = this.faces.Count; 1123 int numFaces = this.faces.Count;
1124 Face tmpFace; 1124 Face tmpFace;
1125 int tmp; 1125 int tmp;
1126 1126
1127 for (i = 0; i < numFaces; i++) 1127 for (i = 0; i < numFaces; i++)
1128 { 1128 {
1129 tmpFace = this.faces[i]; 1129 tmpFace = this.faces[i];
1130 tmp = tmpFace.v3; 1130 tmp = tmpFace.v3;
1131 tmpFace.v3 = tmpFace.v1; 1131 tmpFace.v3 = tmpFace.v1;
1132 tmpFace.v1 = tmp; 1132 tmpFace.v1 = tmp;
1133 this.faces[i] = tmpFace; 1133 this.faces[i] = tmpFace;
1134 } 1134 }
1135 1135
1136 if (this.calcVertexNormals) 1136 if (this.calcVertexNormals)
1137 { 1137 {
1138 int normalCount = this.vertexNormals.Count; 1138 int normalCount = this.vertexNormals.Count;
1139 if (normalCount > 0) 1139 if (normalCount > 0)
1140 { 1140 {
1141 Coord n = this.vertexNormals[normalCount - 1]; 1141 Coord n = this.vertexNormals[normalCount - 1];
1142 n.Z = -n.Z; 1142 n.Z = -n.Z;
1143 this.vertexNormals[normalCount - 1] = n; 1143 this.vertexNormals[normalCount - 1] = n;
1144 } 1144 }
1145 } 1145 }
1146 1146
1147 this.faceNormal.X = -this.faceNormal.X; 1147 this.faceNormal.X = -this.faceNormal.X;
1148 this.faceNormal.Y = -this.faceNormal.Y; 1148 this.faceNormal.Y = -this.faceNormal.Y;
1149 this.faceNormal.Z = -this.faceNormal.Z; 1149 this.faceNormal.Z = -this.faceNormal.Z;
1150 1150
1151 int numfaceUVs = this.faceUVs.Count; 1151 int numfaceUVs = this.faceUVs.Count;
1152 for (i = 0; i < numfaceUVs; i++) 1152 for (i = 0; i < numfaceUVs; i++)
1153 { 1153 {
1154 UVCoord uv = this.faceUVs[i]; 1154 UVCoord uv = this.faceUVs[i];
1155 uv.V = 1.0f - uv.V; 1155 uv.V = 1.0f - uv.V;
1156 this.faceUVs[i] = uv; 1156 this.faceUVs[i] = uv;
1157 } 1157 }
1158 } 1158 }
1159 1159
1160 internal void AddValue2FaceVertexIndices(int num) 1160 internal void AddValue2FaceVertexIndices(int num)
1161 { 1161 {
1162 int numFaces = this.faces.Count; 1162 int numFaces = this.faces.Count;
1163 Face tmpFace; 1163 Face tmpFace;
1164 for (int i = 0; i < numFaces; i++) 1164 for (int i = 0; i < numFaces; i++)
1165 { 1165 {
1166 tmpFace = this.faces[i]; 1166 tmpFace = this.faces[i];
1167 tmpFace.v1 += num; 1167 tmpFace.v1 += num;
1168 tmpFace.v2 += num; 1168 tmpFace.v2 += num;
1169 tmpFace.v3 += num; 1169 tmpFace.v3 += num;
1170 1170
1171 this.faces[i] = tmpFace; 1171 this.faces[i] = tmpFace;
1172 } 1172 }
1173 } 1173 }
1174 1174
1175 internal void AddValue2FaceNormalIndices(int num) 1175 internal void AddValue2FaceNormalIndices(int num)
1176 { 1176 {
1177 if (this.calcVertexNormals) 1177 if (this.calcVertexNormals)
1178 { 1178 {
1179 int numFaces = this.faces.Count; 1179 int numFaces = this.faces.Count;
1180 Face tmpFace; 1180 Face tmpFace;
1181 for (int i = 0; i < numFaces; i++) 1181 for (int i = 0; i < numFaces; i++)
1182 { 1182 {
1183 tmpFace = this.faces[i]; 1183 tmpFace = this.faces[i];
1184 tmpFace.n1 += num; 1184 tmpFace.n1 += num;
1185 tmpFace.n2 += num; 1185 tmpFace.n2 += num;
1186 tmpFace.n3 += num; 1186 tmpFace.n3 += num;
1187 1187
1188 this.faces[i] = tmpFace; 1188 this.faces[i] = tmpFace;
1189 } 1189 }
1190 } 1190 }
1191 } 1191 }
1192 1192
1193 internal void DumpRaw(String path, String name, String title) 1193 internal void DumpRaw(String path, String name, String title)
1194 { 1194 {
1195 if (path == null) 1195 if (path == null)
1196 return; 1196 return;
1197 String fileName = name + "_" + title + ".raw"; 1197 String fileName = name + "_" + title + ".raw";
1198 String completePath = System.IO.Path.Combine(path, fileName); 1198 String completePath = System.IO.Path.Combine(path, fileName);
1199 StreamWriter sw = new StreamWriter(completePath); 1199 StreamWriter sw = new StreamWriter(completePath);
1200 1200
1201 for (int i = 0; i < this.faces.Count; i++) 1201 for (int i = 0; i < this.faces.Count; i++)
1202 { 1202 {
1203 string s = this.coords[this.faces[i].v1].ToString(); 1203 string s = this.coords[this.faces[i].v1].ToString();
1204 s += " " + this.coords[this.faces[i].v2].ToString(); 1204 s += " " + this.coords[this.faces[i].v2].ToString();
1205 s += " " + this.coords[this.faces[i].v3].ToString(); 1205 s += " " + this.coords[this.faces[i].v3].ToString();
1206 1206
1207 sw.WriteLine(s); 1207 sw.WriteLine(s);
1208 } 1208 }
1209 1209
1210 sw.Close(); 1210 sw.Close();
1211 } 1211 }
1212 } 1212 }
1213 1213
1214 public struct PathNode 1214 public struct PathNode
1215 { 1215 {
1216 public Coord position; 1216 public Coord position;
1217 public Quat rotation; 1217 public Quat rotation;
1218 public float xScale; 1218 public float xScale;
1219 public float yScale; 1219 public float yScale;
1220 public float percentOfPath; 1220 public float percentOfPath;
1221 } 1221 }
1222 1222
1223 public enum PathType { Linear = 0, Circular = 1, Flexible = 2 } 1223 public enum PathType { Linear = 0, Circular = 1, Flexible = 2 }
1224 1224
1225 public class Path 1225 public class Path
1226 { 1226 {
1227 public List<PathNode> pathNodes = new List<PathNode>(); 1227 public List<PathNode> pathNodes = new List<PathNode>();
1228 1228
1229 public float twistBegin = 0.0f; 1229 public float twistBegin = 0.0f;
1230 public float twistEnd = 0.0f; 1230 public float twistEnd = 0.0f;
1231 public float topShearX = 0.0f; 1231 public float topShearX = 0.0f;
1232 public float topShearY = 0.0f; 1232 public float topShearY = 0.0f;
1233 public float pathCutBegin = 0.0f; 1233 public float pathCutBegin = 0.0f;
1234 public float pathCutEnd = 1.0f; 1234 public float pathCutEnd = 1.0f;
1235 public float dimpleBegin = 0.0f; 1235 public float dimpleBegin = 0.0f;
1236 public float dimpleEnd = 1.0f; 1236 public float dimpleEnd = 1.0f;
1237 public float skew = 0.0f; 1237 public float skew = 0.0f;
1238 public float holeSizeX = 1.0f; // called pathScaleX in pbs 1238 public float holeSizeX = 1.0f; // called pathScaleX in pbs
1239 public float holeSizeY = 0.25f; 1239 public float holeSizeY = 0.25f;
1240 public float taperX = 0.0f; 1240 public float taperX = 0.0f;
1241 public float taperY = 0.0f; 1241 public float taperY = 0.0f;
1242 public float radius = 0.0f; 1242 public float radius = 0.0f;
1243 public float revolutions = 1.0f; 1243 public float revolutions = 1.0f;
1244 public int stepsPerRevolution = 24; 1244 public int stepsPerRevolution = 24;
1245 1245
1246 private const float twoPi = 2.0f * (float)Math.PI; 1246 private const float twoPi = 2.0f * (float)Math.PI;
1247 1247
1248 public void Create(PathType pathType, int steps) 1248 public void Create(PathType pathType, int steps)
1249 { 1249 {
1250 if (pathType == PathType.Linear || pathType == PathType.Flexible) 1250 if (pathType == PathType.Linear || pathType == PathType.Flexible)
1251 { 1251 {
1252 int step = 0; 1252 int step = 0;
1253 1253
1254 float length = this.pathCutEnd - this.pathCutBegin; 1254 float length = this.pathCutEnd - this.pathCutBegin;
1255 float twistTotal = twistEnd - twistBegin; 1255 float twistTotal = twistEnd - twistBegin;
1256 float twistTotalAbs = Math.Abs(twistTotal); 1256 float twistTotalAbs = Math.Abs(twistTotal);
1257 if (twistTotalAbs > 0.01f) 1257 if (twistTotalAbs > 0.01f)
1258 steps += (int)(twistTotalAbs * 3.66); // dahlia's magic number 1258 steps += (int)(twistTotalAbs * 3.66); // dahlia's magic number
1259 1259
1260 float start = -0.5f; 1260 float start = -0.5f;
1261 float stepSize = length / (float)steps; 1261 float stepSize = length / (float)steps;
1262 float percentOfPathMultiplier = stepSize; 1262 float percentOfPathMultiplier = stepSize;
1263 float xOffset = 0.0f; 1263 float xOffset = 0.0f;
1264 float yOffset = 0.0f; 1264 float yOffset = 0.0f;
1265 float zOffset = start; 1265 float zOffset = start;
1266 float xOffsetStepIncrement = this.topShearX / steps; 1266 float xOffsetStepIncrement = this.topShearX / steps;
1267 float yOffsetStepIncrement = this.topShearY / steps; 1267 float yOffsetStepIncrement = this.topShearY / steps;
1268 1268
1269 float percentOfPath = this.pathCutBegin; 1269 float percentOfPath = this.pathCutBegin;
1270 zOffset += percentOfPath; 1270 zOffset += percentOfPath;
1271 1271
1272 // sanity checks 1272 // sanity checks
1273 1273
1274 bool done = false; 1274 bool done = false;
1275 1275
1276 while (!done) 1276 while (!done)
1277 { 1277 {
1278 PathNode newNode = new PathNode(); 1278 PathNode newNode = new PathNode();
1279 1279
1280 newNode.xScale = 1.0f; 1280 newNode.xScale = 1.0f;
1281 if (this.taperX == 0.0f) 1281 if (this.taperX == 0.0f)
1282 newNode.xScale = 1.0f; 1282 newNode.xScale = 1.0f;
1283 else if (this.taperX > 0.0f) 1283 else if (this.taperX > 0.0f)
1284 newNode.xScale = 1.0f - percentOfPath * this.taperX; 1284 newNode.xScale = 1.0f - percentOfPath * this.taperX;
1285 else newNode.xScale = 1.0f + (1.0f - percentOfPath) * this.taperX; 1285 else newNode.xScale = 1.0f + (1.0f - percentOfPath) * this.taperX;
1286 1286
1287 newNode.yScale = 1.0f; 1287 newNode.yScale = 1.0f;
1288 if (this.taperY == 0.0f) 1288 if (this.taperY == 0.0f)
1289 newNode.yScale = 1.0f; 1289 newNode.yScale = 1.0f;
1290 else if (this.taperY > 0.0f) 1290 else if (this.taperY > 0.0f)
1291 newNode.yScale = 1.0f - percentOfPath * this.taperY; 1291 newNode.yScale = 1.0f - percentOfPath * this.taperY;
1292 else newNode.yScale = 1.0f + (1.0f - percentOfPath) * this.taperY; 1292 else newNode.yScale = 1.0f + (1.0f - percentOfPath) * this.taperY;
1293 1293
1294 float twist = twistBegin + twistTotal * percentOfPath; 1294 float twist = twistBegin + twistTotal * percentOfPath;
1295 1295
1296 newNode.rotation = new Quat(new Coord(0.0f, 0.0f, 1.0f), twist); 1296 newNode.rotation = new Quat(new Coord(0.0f, 0.0f, 1.0f), twist);
1297 newNode.position = new Coord(xOffset, yOffset, zOffset); 1297 newNode.position = new Coord(xOffset, yOffset, zOffset);
1298 newNode.percentOfPath = percentOfPath; 1298 newNode.percentOfPath = percentOfPath;
1299 1299
1300 pathNodes.Add(newNode); 1300 pathNodes.Add(newNode);
1301 1301
1302 if (step < steps) 1302 if (step < steps)
1303 { 1303 {
1304 step += 1; 1304 step += 1;
1305 percentOfPath += percentOfPathMultiplier; 1305 percentOfPath += percentOfPathMultiplier;
1306 xOffset += xOffsetStepIncrement; 1306 xOffset += xOffsetStepIncrement;
1307 yOffset += yOffsetStepIncrement; 1307 yOffset += yOffsetStepIncrement;
1308 zOffset += stepSize; 1308 zOffset += stepSize;
1309 if (percentOfPath > this.pathCutEnd) 1309 if (percentOfPath > this.pathCutEnd)
1310 done = true; 1310 done = true;
1311 } 1311 }
1312 else done = true; 1312 else done = true;
1313 } 1313 }
1314 } // end of linear path code 1314 } // end of linear path code
1315 1315
1316 else // pathType == Circular 1316 else // pathType == Circular
1317 { 1317 {
1318 float twistTotal = twistEnd - twistBegin; 1318 float twistTotal = twistEnd - twistBegin;
1319 1319
1320 // if the profile has a lot of twist, add more layers otherwise the layers may overlap 1320 // if the profile has a lot of twist, add more layers otherwise the layers may overlap
1321 // and the resulting mesh may be quite inaccurate. This method is arbitrary and doesn't 1321 // and the resulting mesh may be quite inaccurate. This method is arbitrary and doesn't
1322 // accurately match the viewer 1322 // accurately match the viewer
1323 float twistTotalAbs = Math.Abs(twistTotal); 1323 float twistTotalAbs = Math.Abs(twistTotal);
1324 if (twistTotalAbs > 0.01f) 1324 if (twistTotalAbs > 0.01f)
1325 { 1325 {
1326 if (twistTotalAbs > Math.PI * 1.5f) 1326 if (twistTotalAbs > Math.PI * 1.5f)
1327 steps *= 2; 1327 steps *= 2;
1328 if (twistTotalAbs > Math.PI * 3.0f) 1328 if (twistTotalAbs > Math.PI * 3.0f)
1329 steps *= 2; 1329 steps *= 2;
1330 } 1330 }
1331 1331
1332 float yPathScale = this.holeSizeY * 0.5f; 1332 float yPathScale = this.holeSizeY * 0.5f;
1333 float pathLength = this.pathCutEnd - this.pathCutBegin; 1333 float pathLength = this.pathCutEnd - this.pathCutBegin;
1334 float totalSkew = this.skew * 2.0f * pathLength; 1334 float totalSkew = this.skew * 2.0f * pathLength;
1335 float skewStart = this.pathCutBegin * 2.0f * this.skew - this.skew; 1335 float skewStart = this.pathCutBegin * 2.0f * this.skew - this.skew;
1336 float xOffsetTopShearXFactor = this.topShearX * (0.25f + 0.5f * (0.5f - this.holeSizeY)); 1336 float xOffsetTopShearXFactor = this.topShearX * (0.25f + 0.5f * (0.5f - this.holeSizeY));
1337 float yShearCompensation = 1.0f + Math.Abs(this.topShearY) * 0.25f; 1337 float yShearCompensation = 1.0f + Math.Abs(this.topShearY) * 0.25f;
1338 1338
1339 // It's not quite clear what pushY (Y top shear) does, but subtracting it from the start and end 1339 // It's not quite clear what pushY (Y top shear) does, but subtracting it from the start and end
1340 // angles appears to approximate it's effects on path cut. Likewise, adding it to the angle used 1340 // angles appears to approximate it's effects on path cut. Likewise, adding it to the angle used
1341 // to calculate the sine for generating the path radius appears to approximate it's effects there 1341 // to calculate the sine for generating the path radius appears to approximate it's effects there
1342 // too, but there are some subtle differences in the radius which are noticeable as the prim size 1342 // too, but there are some subtle differences in the radius which are noticeable as the prim size
1343 // increases and it may affect megaprims quite a bit. The effect of the Y top shear parameter on 1343 // increases and it may affect megaprims quite a bit. The effect of the Y top shear parameter on
1344 // the meshes generated with this technique appear nearly identical in shape to the same prims when 1344 // the meshes generated with this technique appear nearly identical in shape to the same prims when
1345 // displayed by the viewer. 1345 // displayed by the viewer.
1346 1346
1347 float startAngle = (twoPi * this.pathCutBegin * this.revolutions) - this.topShearY * 0.9f; 1347 float startAngle = (twoPi * this.pathCutBegin * this.revolutions) - this.topShearY * 0.9f;
1348 float endAngle = (twoPi * this.pathCutEnd * this.revolutions) - this.topShearY * 0.9f; 1348 float endAngle = (twoPi * this.pathCutEnd * this.revolutions) - this.topShearY * 0.9f;
1349 float stepSize = twoPi / this.stepsPerRevolution; 1349 float stepSize = twoPi / this.stepsPerRevolution;
1350 1350
1351 int step = (int)(startAngle / stepSize); 1351 int step = (int)(startAngle / stepSize);
1352 float angle = startAngle; 1352 float angle = startAngle;
1353 1353
1354 bool done = false; 1354 bool done = false;
1355 while (!done) // loop through the length of the path and add the layers 1355 while (!done) // loop through the length of the path and add the layers
1356 { 1356 {
1357 PathNode newNode = new PathNode(); 1357 PathNode newNode = new PathNode();
1358 1358
1359 float xProfileScale = (1.0f - Math.Abs(this.skew)) * this.holeSizeX; 1359 float xProfileScale = (1.0f - Math.Abs(this.skew)) * this.holeSizeX;
1360 float yProfileScale = this.holeSizeY; 1360 float yProfileScale = this.holeSizeY;
1361 1361
1362 float percentOfPath = angle / (twoPi * this.revolutions); 1362 float percentOfPath = angle / (twoPi * this.revolutions);
1363 float percentOfAngles = (angle - startAngle) / (endAngle - startAngle); 1363 float percentOfAngles = (angle - startAngle) / (endAngle - startAngle);
1364 1364
1365 if (this.taperX > 0.01f) 1365 if (this.taperX > 0.01f)
1366 xProfileScale *= 1.0f - percentOfPath * this.taperX; 1366 xProfileScale *= 1.0f - percentOfPath * this.taperX;
1367 else if (this.taperX < -0.01f) 1367 else if (this.taperX < -0.01f)
1368 xProfileScale *= 1.0f + (1.0f - percentOfPath) * this.taperX; 1368 xProfileScale *= 1.0f + (1.0f - percentOfPath) * this.taperX;
1369 1369
1370 if (this.taperY > 0.01f) 1370 if (this.taperY > 0.01f)
1371 yProfileScale *= 1.0f - percentOfPath * this.taperY; 1371 yProfileScale *= 1.0f - percentOfPath * this.taperY;
1372 else if (this.taperY < -0.01f) 1372 else if (this.taperY < -0.01f)
1373 yProfileScale *= 1.0f + (1.0f - percentOfPath) * this.taperY; 1373 yProfileScale *= 1.0f + (1.0f - percentOfPath) * this.taperY;
1374 1374
1375 newNode.xScale = xProfileScale; 1375 newNode.xScale = xProfileScale;
1376 newNode.yScale = yProfileScale; 1376 newNode.yScale = yProfileScale;
1377 1377
1378 float radiusScale = 1.0f; 1378 float radiusScale = 1.0f;
1379 if (this.radius > 0.001f) 1379 if (this.radius > 0.001f)
1380 radiusScale = 1.0f - this.radius * percentOfPath; 1380 radiusScale = 1.0f - this.radius * percentOfPath;
1381 else if (this.radius < 0.001f) 1381 else if (this.radius < 0.001f)
1382 radiusScale = 1.0f + this.radius * (1.0f - percentOfPath); 1382 radiusScale = 1.0f + this.radius * (1.0f - percentOfPath);
1383 1383
1384 float twist = twistBegin + twistTotal * percentOfPath; 1384 float twist = twistBegin + twistTotal * percentOfPath;
1385 1385
1386 float xOffset = 0.5f * (skewStart + totalSkew * percentOfAngles); 1386 float xOffset = 0.5f * (skewStart + totalSkew * percentOfAngles);
1387 xOffset += (float)Math.Sin(angle) * xOffsetTopShearXFactor; 1387 xOffset += (float)Math.Sin(angle) * xOffsetTopShearXFactor;
1388 1388
1389 float yOffset = yShearCompensation * (float)Math.Cos(angle) * (0.5f - yPathScale) * radiusScale; 1389 float yOffset = yShearCompensation * (float)Math.Cos(angle) * (0.5f - yPathScale) * radiusScale;
1390 1390
1391 float zOffset = (float)Math.Sin(angle + this.topShearY) * (0.5f - yPathScale) * radiusScale; 1391 float zOffset = (float)Math.Sin(angle + this.topShearY) * (0.5f - yPathScale) * radiusScale;
1392 1392
1393 newNode.position = new Coord(xOffset, yOffset, zOffset); 1393 newNode.position = new Coord(xOffset, yOffset, zOffset);
1394 1394
1395 // now orient the rotation of the profile layer relative to it's position on the path 1395 // now orient the rotation of the profile layer relative to it's position on the path
1396 // adding taperY to the angle used to generate the quat appears to approximate the viewer 1396 // adding taperY to the angle used to generate the quat appears to approximate the viewer
1397 1397
1398 newNode.rotation = new Quat(new Coord(1.0f, 0.0f, 0.0f), angle + this.topShearY); 1398 newNode.rotation = new Quat(new Coord(1.0f, 0.0f, 0.0f), angle + this.topShearY);
1399 1399
1400 // next apply twist rotation to the profile layer 1400 // next apply twist rotation to the profile layer
1401 if (twistTotal != 0.0f || twistBegin != 0.0f) 1401 if (twistTotal != 0.0f || twistBegin != 0.0f)
1402 newNode.rotation *= new Quat(new Coord(0.0f, 0.0f, 1.0f), twist); 1402 newNode.rotation *= new Quat(new Coord(0.0f, 0.0f, 1.0f), twist);
1403 1403
1404 newNode.percentOfPath = percentOfPath; 1404 newNode.percentOfPath = percentOfPath;
1405 1405
1406 pathNodes.Add(newNode); 1406 pathNodes.Add(newNode);
1407 1407
1408 // calculate terms for next iteration 1408 // calculate terms for next iteration
1409 // calculate the angle for the next iteration of the loop 1409 // calculate the angle for the next iteration of the loop
1410 1410
1411 if (angle >= endAngle - 0.01) 1411 if (angle >= endAngle - 0.01)
1412 done = true; 1412 done = true;
1413 else 1413 else
1414 { 1414 {
1415 step += 1; 1415 step += 1;
1416 angle = stepSize * step; 1416 angle = stepSize * step;
1417 if (angle > endAngle) 1417 if (angle > endAngle)
1418 angle = endAngle; 1418 angle = endAngle;
1419 } 1419 }
1420 } 1420 }
1421 } 1421 }
1422 } 1422 }
1423 } 1423 }
1424 1424
1425 public class PrimMesh 1425 public class PrimMesh
1426 { 1426 {
1427 public string errorMessage = ""; 1427 public string errorMessage = "";
1428 private const float twoPi = 2.0f * (float)Math.PI; 1428 private const float twoPi = 2.0f * (float)Math.PI;
1429 1429
1430 public List<Coord> coords; 1430 public List<Coord> coords;
1431 public List<Coord> normals; 1431 public List<Coord> normals;
1432 public List<Face> faces; 1432 public List<Face> faces;
1433 1433
1434 public List<ViewerFace> viewerFaces; 1434 public List<ViewerFace> viewerFaces;
1435 1435
1436 private int sides = 4; 1436 private int sides = 4;
1437 private int hollowSides = 4; 1437 private int hollowSides = 4;
1438 private float profileStart = 0.0f; 1438 private float profileStart = 0.0f;
1439 private float profileEnd = 1.0f; 1439 private float profileEnd = 1.0f;
1440 private float hollow = 0.0f; 1440 private float hollow = 0.0f;
1441 public int twistBegin = 0; 1441 public int twistBegin = 0;
1442 public int twistEnd = 0; 1442 public int twistEnd = 0;
1443 public float topShearX = 0.0f; 1443 public float topShearX = 0.0f;
1444 public float topShearY = 0.0f; 1444 public float topShearY = 0.0f;
1445 public float pathCutBegin = 0.0f; 1445 public float pathCutBegin = 0.0f;
1446 public float pathCutEnd = 1.0f; 1446 public float pathCutEnd = 1.0f;
1447 public float dimpleBegin = 0.0f; 1447 public float dimpleBegin = 0.0f;
1448 public float dimpleEnd = 1.0f; 1448 public float dimpleEnd = 1.0f;
1449 public float skew = 0.0f; 1449 public float skew = 0.0f;
1450 public float holeSizeX = 1.0f; // called pathScaleX in pbs 1450 public float holeSizeX = 1.0f; // called pathScaleX in pbs
1451 public float holeSizeY = 0.25f; 1451 public float holeSizeY = 0.25f;
1452 public float taperX = 0.0f; 1452 public float taperX = 0.0f;
1453 public float taperY = 0.0f; 1453 public float taperY = 0.0f;
1454 public float radius = 0.0f; 1454 public float radius = 0.0f;
1455 public float revolutions = 1.0f; 1455 public float revolutions = 1.0f;
1456 public int stepsPerRevolution = 24; 1456 public int stepsPerRevolution = 24;
1457 1457
1458 private bool hasProfileCut = false; 1458 private bool hasProfileCut = false;
1459 private bool hasHollow = false; 1459 private bool hasHollow = false;
1460 public bool calcVertexNormals = false; 1460 public bool calcVertexNormals = false;
1461 private bool normalsProcessed = false; 1461 private bool normalsProcessed = false;
1462 public bool viewerMode = false; 1462 public bool viewerMode = false;
1463 1463
1464 public int numPrimFaces = 0; 1464 public int numPrimFaces = 0;
1465 1465
1466 /// <summary> 1466 /// <summary>
1467 /// Human readable string representation of the parameters used to create a mesh. 1467 /// Human readable string representation of the parameters used to create a mesh.
1468 /// </summary> 1468 /// </summary>
1469 /// <returns></returns> 1469 /// <returns></returns>
1470 public string ParamsToDisplayString() 1470 public string ParamsToDisplayString()
1471 { 1471 {
1472 string s = ""; 1472 string s = "";
1473 s += "sides..................: " + this.sides.ToString(); 1473 s += "sides..................: " + this.sides.ToString();
1474 s += "\nhollowSides..........: " + this.hollowSides.ToString(); 1474 s += "\nhollowSides..........: " + this.hollowSides.ToString();
1475 s += "\nprofileStart.........: " + this.profileStart.ToString(); 1475 s += "\nprofileStart.........: " + this.profileStart.ToString();
1476 s += "\nprofileEnd...........: " + this.profileEnd.ToString(); 1476 s += "\nprofileEnd...........: " + this.profileEnd.ToString();
1477 s += "\nhollow...............: " + this.hollow.ToString(); 1477 s += "\nhollow...............: " + this.hollow.ToString();
1478 s += "\ntwistBegin...........: " + this.twistBegin.ToString(); 1478 s += "\ntwistBegin...........: " + this.twistBegin.ToString();
1479 s += "\ntwistEnd.............: " + this.twistEnd.ToString(); 1479 s += "\ntwistEnd.............: " + this.twistEnd.ToString();
1480 s += "\ntopShearX............: " + this.topShearX.ToString(); 1480 s += "\ntopShearX............: " + this.topShearX.ToString();
1481 s += "\ntopShearY............: " + this.topShearY.ToString(); 1481 s += "\ntopShearY............: " + this.topShearY.ToString();
1482 s += "\npathCutBegin.........: " + this.pathCutBegin.ToString(); 1482 s += "\npathCutBegin.........: " + this.pathCutBegin.ToString();
1483 s += "\npathCutEnd...........: " + this.pathCutEnd.ToString(); 1483 s += "\npathCutEnd...........: " + this.pathCutEnd.ToString();
1484 s += "\ndimpleBegin..........: " + this.dimpleBegin.ToString(); 1484 s += "\ndimpleBegin..........: " + this.dimpleBegin.ToString();
1485 s += "\ndimpleEnd............: " + this.dimpleEnd.ToString(); 1485 s += "\ndimpleEnd............: " + this.dimpleEnd.ToString();
1486 s += "\nskew.................: " + this.skew.ToString(); 1486 s += "\nskew.................: " + this.skew.ToString();
1487 s += "\nholeSizeX............: " + this.holeSizeX.ToString(); 1487 s += "\nholeSizeX............: " + this.holeSizeX.ToString();
1488 s += "\nholeSizeY............: " + this.holeSizeY.ToString(); 1488 s += "\nholeSizeY............: " + this.holeSizeY.ToString();
1489 s += "\ntaperX...............: " + this.taperX.ToString(); 1489 s += "\ntaperX...............: " + this.taperX.ToString();
1490 s += "\ntaperY...............: " + this.taperY.ToString(); 1490 s += "\ntaperY...............: " + this.taperY.ToString();
1491 s += "\nradius...............: " + this.radius.ToString(); 1491 s += "\nradius...............: " + this.radius.ToString();
1492 s += "\nrevolutions..........: " + this.revolutions.ToString(); 1492 s += "\nrevolutions..........: " + this.revolutions.ToString();
1493 s += "\nstepsPerRevolution...: " + this.stepsPerRevolution.ToString(); 1493 s += "\nstepsPerRevolution...: " + this.stepsPerRevolution.ToString();
1494 1494
1495 return s; 1495 return s;
1496 } 1496 }
1497 1497
1498 /// <summary> 1498 /// <summary>
1499 /// Constructs a PrimMesh object and creates the profile for extrusion. 1499 /// Constructs a PrimMesh object and creates the profile for extrusion.
1500 /// </summary> 1500 /// </summary>
1501 /// <param name="sides"></param> 1501 /// <param name="sides"></param>
1502 /// <param name="profileStart"></param> 1502 /// <param name="profileStart"></param>
1503 /// <param name="profileEnd"></param> 1503 /// <param name="profileEnd"></param>
1504 /// <param name="hollow"></param> 1504 /// <param name="hollow"></param>
1505 /// <param name="hollowSides"></param> 1505 /// <param name="hollowSides"></param>
1506 public PrimMesh(int sides, float profileStart, float profileEnd, float hollow, int hollowSides) 1506 public PrimMesh(int sides, float profileStart, float profileEnd, float hollow, int hollowSides)
1507 { 1507 {
1508 this.coords = new List<Coord>(); 1508 this.coords = new List<Coord>();
1509 this.faces = new List<Face>(); 1509 this.faces = new List<Face>();
1510 1510
1511 this.sides = sides; 1511 this.sides = sides;
1512 this.profileStart = profileStart; 1512 this.profileStart = profileStart;
1513 this.profileEnd = profileEnd; 1513 this.profileEnd = profileEnd;
1514 this.hollow = hollow; 1514 this.hollow = hollow;
1515 this.hollowSides = hollowSides; 1515 this.hollowSides = hollowSides;
1516 1516
1517 if (sides < 3) 1517 if (sides < 3)
1518 this.sides = 3; 1518 this.sides = 3;
1519 if (hollowSides < 3) 1519 if (hollowSides < 3)
1520 this.hollowSides = 3; 1520 this.hollowSides = 3;
1521 if (profileStart < 0.0f) 1521 if (profileStart < 0.0f)
1522 this.profileStart = 0.0f; 1522 this.profileStart = 0.0f;
1523 if (profileEnd > 1.0f) 1523 if (profileEnd > 1.0f)
1524 this.profileEnd = 1.0f; 1524 this.profileEnd = 1.0f;
1525 if (profileEnd < 0.02f) 1525 if (profileEnd < 0.02f)
1526 this.profileEnd = 0.02f; 1526 this.profileEnd = 0.02f;
1527 if (profileStart >= profileEnd) 1527 if (profileStart >= profileEnd)
1528 this.profileStart = profileEnd - 0.02f; 1528 this.profileStart = profileEnd - 0.02f;
1529 if (hollow > 0.99f) 1529 if (hollow > 0.99f)
1530 this.hollow = 0.99f; 1530 this.hollow = 0.99f;
1531 if (hollow < 0.0f) 1531 if (hollow < 0.0f)
1532 this.hollow = 0.0f; 1532 this.hollow = 0.0f;
1533 1533
1534 this.hasProfileCut = (this.profileStart > 0.0f || this.profileEnd < 1.0f); 1534 this.hasProfileCut = (this.profileStart > 0.0f || this.profileEnd < 1.0f);
1535 this.hasHollow = (this.hollow > 0.001f); 1535 this.hasHollow = (this.hollow > 0.001f);
1536 } 1536 }
1537 1537
1538 /// <summary> 1538 /// <summary>
1539 /// Extrudes a profile along a path. 1539 /// Extrudes a profile along a path.
1540 /// </summary> 1540 /// </summary>
1541 public void Extrude(PathType pathType) 1541 public void Extrude(PathType pathType)
1542 { 1542 {
1543 this.coords = new List<Coord>(); 1543 this.coords = new List<Coord>();
1544 this.faces = new List<Face>(); 1544 this.faces = new List<Face>();
1545 1545
1546 if (this.viewerMode) 1546 if (this.viewerMode)
1547 { 1547 {
1548 this.viewerFaces = new List<ViewerFace>(); 1548 this.viewerFaces = new List<ViewerFace>();
1549 this.calcVertexNormals = true; 1549 this.calcVertexNormals = true;
1550 } 1550 }
1551 1551
1552 if (this.calcVertexNormals) 1552 if (this.calcVertexNormals)
1553 this.normals = new List<Coord>(); 1553 this.normals = new List<Coord>();
1554 1554
1555 int steps = 1; 1555 int steps = 1;
1556 1556
1557 float length = this.pathCutEnd - this.pathCutBegin; 1557 float length = this.pathCutEnd - this.pathCutBegin;
1558 normalsProcessed = false; 1558 normalsProcessed = false;
1559 1559
1560 if (this.viewerMode && this.sides == 3) 1560 if (this.viewerMode && this.sides == 3)
1561 { 1561 {
1562 // prisms don't taper well so add some vertical resolution 1562 // prisms don't taper well so add some vertical resolution
1563 // other prims may benefit from this but just do prisms for now 1563 // other prims may benefit from this but just do prisms for now
1564 if (Math.Abs(this.taperX) > 0.01 || Math.Abs(this.taperY) > 0.01) 1564 if (Math.Abs(this.taperX) > 0.01 || Math.Abs(this.taperY) > 0.01)
1565 steps = (int)(steps * 4.5 * length); 1565 steps = (int)(steps * 4.5 * length);
1566 } 1566 }
1567 1567
1568 1568
1569 float twistBegin = this.twistBegin / 360.0f * twoPi; 1569 float twistBegin = this.twistBegin / 360.0f * twoPi;
1570 float twistEnd = this.twistEnd / 360.0f * twoPi; 1570 float twistEnd = this.twistEnd / 360.0f * twoPi;
1571 float twistTotal = twistEnd - twistBegin; 1571 float twistTotal = twistEnd - twistBegin;
1572 float twistTotalAbs = Math.Abs(twistTotal); 1572 float twistTotalAbs = Math.Abs(twistTotal);
1573 if (twistTotalAbs > 0.01f) 1573 if (twistTotalAbs > 0.01f)
1574 steps += (int)(twistTotalAbs * 3.66); // dahlia's magic number 1574 steps += (int)(twistTotalAbs * 3.66); // dahlia's magic number
1575 1575
1576 float hollow = this.hollow; 1576 float hollow = this.hollow;
1577 1577
1578 // sanity checks 1578 // sanity checks
1579 float initialProfileRot = 0.0f; 1579 float initialProfileRot = 0.0f;
1580 if (pathType == PathType.Circular) 1580 if (pathType == PathType.Circular)
1581 { 1581 {
1582 if (this.sides == 3) 1582 if (this.sides == 3)
1583 { 1583 {
1584 initialProfileRot = (float)Math.PI; 1584 initialProfileRot = (float)Math.PI;
1585 if (this.hollowSides == 4) 1585 if (this.hollowSides == 4)
1586 { 1586 {
1587 if (hollow > 0.7f) 1587 if (hollow > 0.7f)
1588 hollow = 0.7f; 1588 hollow = 0.7f;
1589 hollow *= 0.707f; 1589 hollow *= 0.707f;
1590 } 1590 }
1591 else hollow *= 0.5f; 1591 else hollow *= 0.5f;
1592 } 1592 }
1593 else if (this.sides == 4) 1593 else if (this.sides == 4)
1594 { 1594 {
1595 initialProfileRot = 0.25f * (float)Math.PI; 1595 initialProfileRot = 0.25f * (float)Math.PI;
1596 if (this.hollowSides != 4) 1596 if (this.hollowSides != 4)
1597 hollow *= 0.707f; 1597 hollow *= 0.707f;
1598 } 1598 }
1599 else if (this.sides > 4) 1599 else if (this.sides > 4)
1600 { 1600 {
1601 initialProfileRot = (float)Math.PI; 1601 initialProfileRot = (float)Math.PI;
1602 if (this.hollowSides == 4) 1602 if (this.hollowSides == 4)
1603 { 1603 {
1604 if (hollow > 0.7f) 1604 if (hollow > 0.7f)
1605 hollow = 0.7f; 1605 hollow = 0.7f;
1606 hollow /= 0.7f; 1606 hollow /= 0.7f;
1607 } 1607 }
1608 } 1608 }
1609 } 1609 }
1610 else 1610 else
1611 { 1611 {
1612 if (this.sides == 3) 1612 if (this.sides == 3)
1613 { 1613 {
1614 if (this.hollowSides == 4) 1614 if (this.hollowSides == 4)
1615 { 1615 {
1616 if (hollow > 0.7f) 1616 if (hollow > 0.7f)
1617 hollow = 0.7f; 1617 hollow = 0.7f;
1618 hollow *= 0.707f; 1618 hollow *= 0.707f;
1619 } 1619 }
1620 else hollow *= 0.5f; 1620 else hollow *= 0.5f;
1621 } 1621 }
1622 else if (this.sides == 4) 1622 else if (this.sides == 4)
1623 { 1623 {
1624 initialProfileRot = 1.25f * (float)Math.PI; 1624 initialProfileRot = 1.25f * (float)Math.PI;
1625 if (this.hollowSides != 4) 1625 if (this.hollowSides != 4)
1626 hollow *= 0.707f; 1626 hollow *= 0.707f;
1627 } 1627 }
1628 else if (this.sides == 24 && this.hollowSides == 4) 1628 else if (this.sides == 24 && this.hollowSides == 4)
1629 hollow *= 1.414f; 1629 hollow *= 1.414f;
1630 } 1630 }
1631 1631
1632 Profile profile = new Profile(this.sides, this.profileStart, this.profileEnd, hollow, this.hollowSides, true, calcVertexNormals); 1632 Profile profile = new Profile(this.sides, this.profileStart, this.profileEnd, hollow, this.hollowSides, true, calcVertexNormals);
1633 this.errorMessage = profile.errorMessage; 1633 this.errorMessage = profile.errorMessage;
1634 1634
1635 this.numPrimFaces = profile.numPrimFaces; 1635 this.numPrimFaces = profile.numPrimFaces;
1636 1636
1637 int cut1Vert = -1; 1637 int cut1Vert = -1;
1638 int cut2Vert = -1; 1638 int cut2Vert = -1;
1639 if (hasProfileCut) 1639 if (hasProfileCut)
1640 { 1640 {
1641 cut1Vert = hasHollow ? profile.coords.Count - 1 : 0; 1641 cut1Vert = hasHollow ? profile.coords.Count - 1 : 0;
1642 cut2Vert = hasHollow ? profile.numOuterVerts - 1 : profile.numOuterVerts; 1642 cut2Vert = hasHollow ? profile.numOuterVerts - 1 : profile.numOuterVerts;
1643 } 1643 }
1644 1644
1645 if (initialProfileRot != 0.0f) 1645 if (initialProfileRot != 0.0f)
1646 { 1646 {
1647 profile.AddRot(new Quat(new Coord(0.0f, 0.0f, 1.0f), initialProfileRot)); 1647 profile.AddRot(new Quat(new Coord(0.0f, 0.0f, 1.0f), initialProfileRot));
1648 if (viewerMode) 1648 if (viewerMode)
1649 profile.MakeFaceUVs(); 1649 profile.MakeFaceUVs();
1650 } 1650 }
1651 1651
1652 Coord lastCutNormal1 = new Coord(); 1652 Coord lastCutNormal1 = new Coord();
1653 Coord lastCutNormal2 = new Coord(); 1653 Coord lastCutNormal2 = new Coord();
1654 float lastV = 1.0f; 1654 float lastV = 1.0f;
1655 1655
1656 Path path = new Path(); 1656 Path path = new Path();
1657 path.twistBegin = twistBegin; 1657 path.twistBegin = twistBegin;
1658 path.twistEnd = twistEnd; 1658 path.twistEnd = twistEnd;
1659 path.topShearX = topShearX; 1659 path.topShearX = topShearX;
1660 path.topShearY = topShearY; 1660 path.topShearY = topShearY;
1661 path.pathCutBegin = pathCutBegin; 1661 path.pathCutBegin = pathCutBegin;
1662 path.pathCutEnd = pathCutEnd; 1662 path.pathCutEnd = pathCutEnd;
1663 path.dimpleBegin = dimpleBegin; 1663 path.dimpleBegin = dimpleBegin;
1664 path.dimpleEnd = dimpleEnd; 1664 path.dimpleEnd = dimpleEnd;
1665 path.skew = skew; 1665 path.skew = skew;
1666 path.holeSizeX = holeSizeX; 1666 path.holeSizeX = holeSizeX;
1667 path.holeSizeY = holeSizeY; 1667 path.holeSizeY = holeSizeY;
1668 path.taperX = taperX; 1668 path.taperX = taperX;
1669 path.taperY = taperY; 1669 path.taperY = taperY;
1670 path.radius = radius; 1670 path.radius = radius;
1671 path.revolutions = revolutions; 1671 path.revolutions = revolutions;
1672 path.stepsPerRevolution = stepsPerRevolution; 1672 path.stepsPerRevolution = stepsPerRevolution;
1673 1673
1674 path.Create(pathType, steps); 1674 path.Create(pathType, steps);
1675 1675
1676 bool needEndFaces = false; 1676 bool needEndFaces = false;
1677 if (pathType == PathType.Circular) 1677 if (pathType == PathType.Circular)
1678 { 1678 {
1679 needEndFaces = false; 1679 needEndFaces = false;
1680 if (this.pathCutBegin != 0.0f || this.pathCutEnd != 1.0f) 1680 if (this.pathCutBegin != 0.0f || this.pathCutEnd != 1.0f)
1681 needEndFaces = true; 1681 needEndFaces = true;
1682 else if (this.taperX != 0.0f || this.taperY != 0.0f) 1682 else if (this.taperX != 0.0f || this.taperY != 0.0f)
1683 needEndFaces = true; 1683 needEndFaces = true;
1684 else if (this.skew != 0.0f) 1684 else if (this.skew != 0.0f)
1685 needEndFaces = true; 1685 needEndFaces = true;
1686 else if (twistTotal != 0.0f) 1686 else if (twistTotal != 0.0f)
1687 needEndFaces = true; 1687 needEndFaces = true;
1688 else if (this.radius != 0.0f) 1688 else if (this.radius != 0.0f)
1689 needEndFaces = true; 1689 needEndFaces = true;
1690 } 1690 }
1691 else needEndFaces = true; 1691 else needEndFaces = true;
1692 1692
1693 for (int nodeIndex = 0; nodeIndex < path.pathNodes.Count; nodeIndex++) 1693 for (int nodeIndex = 0; nodeIndex < path.pathNodes.Count; nodeIndex++)
1694 { 1694 {
1695 PathNode node = path.pathNodes[nodeIndex]; 1695 PathNode node = path.pathNodes[nodeIndex];
1696 Profile newLayer = profile.Copy(); 1696 Profile newLayer = profile.Copy();
1697 newLayer.Scale(node.xScale, node.yScale); 1697 newLayer.Scale(node.xScale, node.yScale);
1698 1698
1699 newLayer.AddRot(node.rotation); 1699 newLayer.AddRot(node.rotation);
1700 newLayer.AddPos(node.position); 1700 newLayer.AddPos(node.position);
1701 1701
1702 if (needEndFaces && nodeIndex == 0) 1702 if (needEndFaces && nodeIndex == 0)
1703 { 1703 {
1704 newLayer.FlipNormals(); 1704 newLayer.FlipNormals();
1705 1705
1706 // add the top faces to the viewerFaces list here 1706 // add the top faces to the viewerFaces list here
1707 if (this.viewerMode) 1707 if (this.viewerMode)
1708 { 1708 {
1709 Coord faceNormal = newLayer.faceNormal; 1709 Coord faceNormal = newLayer.faceNormal;
1710 ViewerFace newViewerFace = new ViewerFace(profile.bottomFaceNumber); 1710 ViewerFace newViewerFace = new ViewerFace(profile.bottomFaceNumber);
1711 int numFaces = newLayer.faces.Count; 1711 int numFaces = newLayer.faces.Count;
1712 List<Face> faces = newLayer.faces; 1712 List<Face> faces = newLayer.faces;
1713 1713
1714 for (int i = 0; i < numFaces; i++) 1714 for (int i = 0; i < numFaces; i++)
1715 { 1715 {
1716 Face face = faces[i]; 1716 Face face = faces[i];
1717 newViewerFace.v1 = newLayer.coords[face.v1]; 1717 newViewerFace.v1 = newLayer.coords[face.v1];
1718 newViewerFace.v2 = newLayer.coords[face.v2]; 1718 newViewerFace.v2 = newLayer.coords[face.v2];
1719 newViewerFace.v3 = newLayer.coords[face.v3]; 1719 newViewerFace.v3 = newLayer.coords[face.v3];
1720 1720
1721 newViewerFace.coordIndex1 = face.v1; 1721 newViewerFace.coordIndex1 = face.v1;
1722 newViewerFace.coordIndex2 = face.v2; 1722 newViewerFace.coordIndex2 = face.v2;
1723 newViewerFace.coordIndex3 = face.v3; 1723 newViewerFace.coordIndex3 = face.v3;
1724 1724
1725 newViewerFace.n1 = faceNormal; 1725 newViewerFace.n1 = faceNormal;
1726 newViewerFace.n2 = faceNormal; 1726 newViewerFace.n2 = faceNormal;
1727 newViewerFace.n3 = faceNormal; 1727 newViewerFace.n3 = faceNormal;
1728 1728
1729 newViewerFace.uv1 = newLayer.faceUVs[face.v1]; 1729 newViewerFace.uv1 = newLayer.faceUVs[face.v1];
1730 newViewerFace.uv2 = newLayer.faceUVs[face.v2]; 1730 newViewerFace.uv2 = newLayer.faceUVs[face.v2];
1731 newViewerFace.uv3 = newLayer.faceUVs[face.v3]; 1731 newViewerFace.uv3 = newLayer.faceUVs[face.v3];
1732 1732
1733 this.viewerFaces.Add(newViewerFace); 1733 this.viewerFaces.Add(newViewerFace);
1734 } 1734 }
1735 } 1735 }
1736 } // if (nodeIndex == 0) 1736 } // if (nodeIndex == 0)
1737 1737
1738 // append this layer 1738 // append this layer
1739 1739
1740 int coordsLen = this.coords.Count; 1740 int coordsLen = this.coords.Count;
1741 newLayer.AddValue2FaceVertexIndices(coordsLen); 1741 newLayer.AddValue2FaceVertexIndices(coordsLen);
1742 1742
1743 this.coords.AddRange(newLayer.coords); 1743 this.coords.AddRange(newLayer.coords);
1744 1744
1745 if (this.calcVertexNormals) 1745 if (this.calcVertexNormals)
1746 { 1746 {
1747 newLayer.AddValue2FaceNormalIndices(this.normals.Count); 1747 newLayer.AddValue2FaceNormalIndices(this.normals.Count);
1748 this.normals.AddRange(newLayer.vertexNormals); 1748 this.normals.AddRange(newLayer.vertexNormals);
1749 } 1749 }
1750 1750
1751 if (node.percentOfPath < this.pathCutBegin + 0.01f || node.percentOfPath > this.pathCutEnd - 0.01f) 1751 if (node.percentOfPath < this.pathCutBegin + 0.01f || node.percentOfPath > this.pathCutEnd - 0.01f)
1752 this.faces.AddRange(newLayer.faces); 1752 this.faces.AddRange(newLayer.faces);
1753 1753
1754 // fill faces between layers 1754 // fill faces between layers
1755 1755
1756 int numVerts = newLayer.coords.Count; 1756 int numVerts = newLayer.coords.Count;
1757 Face newFace = new Face(); 1757 Face newFace = new Face();
1758 1758
1759 if (nodeIndex > 0) 1759 if (nodeIndex > 0)
1760 { 1760 {
1761 int startVert = coordsLen + 1; 1761 int startVert = coordsLen + 1;
1762 int endVert = this.coords.Count; 1762 int endVert = this.coords.Count;
1763 1763
1764 if (sides < 5 || this.hasProfileCut || hollow > 0.0f) 1764 if (sides < 5 || this.hasProfileCut || hollow > 0.0f)
1765 startVert--; 1765 startVert--;
1766 1766
1767 for (int i = startVert; i < endVert; i++) 1767 for (int i = startVert; i < endVert; i++)
1768 { 1768 {
1769 int iNext = i + 1; 1769 int iNext = i + 1;
1770 if (i == endVert - 1) 1770 if (i == endVert - 1)
1771 iNext = startVert; 1771 iNext = startVert;
1772 1772
1773 int whichVert = i - startVert; 1773 int whichVert = i - startVert;
1774 1774
1775 newFace.v1 = i; 1775 newFace.v1 = i;
1776 newFace.v2 = i - numVerts; 1776 newFace.v2 = i - numVerts;
1777 newFace.v3 = iNext - numVerts; 1777 newFace.v3 = iNext - numVerts;
1778 this.faces.Add(newFace); 1778 this.faces.Add(newFace);
1779 1779
1780 newFace.v2 = iNext - numVerts; 1780 newFace.v2 = iNext - numVerts;
1781 newFace.v3 = iNext; 1781 newFace.v3 = iNext;
1782 this.faces.Add(newFace); 1782 this.faces.Add(newFace);
1783 1783
1784 if (this.viewerMode) 1784 if (this.viewerMode)
1785 { 1785 {
1786 // add the side faces to the list of viewerFaces here 1786 // add the side faces to the list of viewerFaces here
1787 1787
1788 int primFaceNum = profile.faceNumbers[whichVert]; 1788 int primFaceNum = profile.faceNumbers[whichVert];
1789 if (!needEndFaces) 1789 if (!needEndFaces)
1790 primFaceNum -= 1; 1790 primFaceNum -= 1;
1791 1791
1792 ViewerFace newViewerFace1 = new ViewerFace(primFaceNum); 1792 ViewerFace newViewerFace1 = new ViewerFace(primFaceNum);
1793 ViewerFace newViewerFace2 = new ViewerFace(primFaceNum); 1793 ViewerFace newViewerFace2 = new ViewerFace(primFaceNum);
1794 1794
1795 float u1 = newLayer.us[whichVert]; 1795 float u1 = newLayer.us[whichVert];
1796 float u2 = 1.0f; 1796 float u2 = 1.0f;
1797 if (whichVert < newLayer.us.Count - 1) 1797 if (whichVert < newLayer.us.Count - 1)
1798 u2 = newLayer.us[whichVert + 1]; 1798 u2 = newLayer.us[whichVert + 1];
1799 1799
1800 if (whichVert == cut1Vert || whichVert == cut2Vert) 1800 if (whichVert == cut1Vert || whichVert == cut2Vert)
1801 { 1801 {
1802 u1 = 0.0f; 1802 u1 = 0.0f;
1803 u2 = 1.0f; 1803 u2 = 1.0f;
1804 } 1804 }
1805 else if (sides < 5) 1805 else if (sides < 5)
1806 { 1806 {
1807 if (whichVert < profile.numOuterVerts) 1807 if (whichVert < profile.numOuterVerts)
1808 { // boxes and prisms have one texture face per side of the prim, so the U values have to be scaled 1808 { // boxes and prisms have one texture face per side of the prim, so the U values have to be scaled
1809 // to reflect the entire texture width 1809 // to reflect the entire texture width
1810 u1 *= sides; 1810 u1 *= sides;
1811 u2 *= sides; 1811 u2 *= sides;
1812 u2 -= (int)u1; 1812 u2 -= (int)u1;
1813 u1 -= (int)u1; 1813 u1 -= (int)u1;
1814 if (u2 < 0.1f) 1814 if (u2 < 0.1f)
1815 u2 = 1.0f; 1815 u2 = 1.0f;
1816 } 1816 }
1817 else if (whichVert > profile.coords.Count - profile.numHollowVerts - 1) 1817 else if (whichVert > profile.coords.Count - profile.numHollowVerts - 1)
1818 { 1818 {
1819 u1 *= 2.0f; 1819 u1 *= 2.0f;
1820 u2 *= 2.0f; 1820 u2 *= 2.0f;
1821 } 1821 }
1822 } 1822 }
1823 1823
1824 newViewerFace1.uv1.U = u1; 1824 newViewerFace1.uv1.U = u1;
1825 newViewerFace1.uv2.U = u1; 1825 newViewerFace1.uv2.U = u1;
1826 newViewerFace1.uv3.U = u2; 1826 newViewerFace1.uv3.U = u2;
1827 1827
1828 newViewerFace1.uv1.V = 1.0f - node.percentOfPath; 1828 newViewerFace1.uv1.V = 1.0f - node.percentOfPath;
1829 newViewerFace1.uv2.V = lastV; 1829 newViewerFace1.uv2.V = lastV;
1830 newViewerFace1.uv3.V = lastV; 1830 newViewerFace1.uv3.V = lastV;
1831 1831
1832 newViewerFace2.uv1.U = u1; 1832 newViewerFace2.uv1.U = u1;
1833 newViewerFace2.uv2.U = u2; 1833 newViewerFace2.uv2.U = u2;
1834 newViewerFace2.uv3.U = u2; 1834 newViewerFace2.uv3.U = u2;
1835 1835
1836 newViewerFace2.uv1.V = 1.0f - node.percentOfPath; 1836 newViewerFace2.uv1.V = 1.0f - node.percentOfPath;
1837 newViewerFace2.uv2.V = lastV; 1837 newViewerFace2.uv2.V = lastV;
1838 newViewerFace2.uv3.V = 1.0f - node.percentOfPath; 1838 newViewerFace2.uv3.V = 1.0f - node.percentOfPath;
1839 1839
1840 newViewerFace1.v1 = this.coords[i]; 1840 newViewerFace1.v1 = this.coords[i];
1841 newViewerFace1.v2 = this.coords[i - numVerts]; 1841 newViewerFace1.v2 = this.coords[i - numVerts];
1842 newViewerFace1.v3 = this.coords[iNext - numVerts]; 1842 newViewerFace1.v3 = this.coords[iNext - numVerts];
1843 1843
1844 newViewerFace2.v1 = this.coords[i]; 1844 newViewerFace2.v1 = this.coords[i];
1845 newViewerFace2.v2 = this.coords[iNext - numVerts]; 1845 newViewerFace2.v2 = this.coords[iNext - numVerts];
1846 newViewerFace2.v3 = this.coords[iNext]; 1846 newViewerFace2.v3 = this.coords[iNext];
1847 1847
1848 newViewerFace1.coordIndex1 = i; 1848 newViewerFace1.coordIndex1 = i;
1849 newViewerFace1.coordIndex2 = i - numVerts; 1849 newViewerFace1.coordIndex2 = i - numVerts;
1850 newViewerFace1.coordIndex3 = iNext - numVerts; 1850 newViewerFace1.coordIndex3 = iNext - numVerts;
1851 1851
1852 newViewerFace2.coordIndex1 = i; 1852 newViewerFace2.coordIndex1 = i;
1853 newViewerFace2.coordIndex2 = iNext - numVerts; 1853 newViewerFace2.coordIndex2 = iNext - numVerts;
1854 newViewerFace2.coordIndex3 = iNext; 1854 newViewerFace2.coordIndex3 = iNext;
1855 1855
1856 // profile cut faces 1856 // profile cut faces
1857 if (whichVert == cut1Vert) 1857 if (whichVert == cut1Vert)
1858 { 1858 {
1859 newViewerFace1.n1 = newLayer.cutNormal1; 1859 newViewerFace1.n1 = newLayer.cutNormal1;
1860 newViewerFace1.n2 = newViewerFace1.n3 = lastCutNormal1; 1860 newViewerFace1.n2 = newViewerFace1.n3 = lastCutNormal1;
1861 1861
1862 newViewerFace2.n1 = newViewerFace2.n3 = newLayer.cutNormal1; 1862 newViewerFace2.n1 = newViewerFace2.n3 = newLayer.cutNormal1;
1863 newViewerFace2.n2 = lastCutNormal1; 1863 newViewerFace2.n2 = lastCutNormal1;
1864 } 1864 }
1865 else if (whichVert == cut2Vert) 1865 else if (whichVert == cut2Vert)
1866 { 1866 {
1867 newViewerFace1.n1 = newLayer.cutNormal2; 1867 newViewerFace1.n1 = newLayer.cutNormal2;
1868 newViewerFace1.n2 = newViewerFace1.n3 = lastCutNormal2; 1868 newViewerFace1.n2 = newViewerFace1.n3 = lastCutNormal2;
1869 1869
1870 newViewerFace2.n1 = newViewerFace2.n3 = newLayer.cutNormal2; 1870 newViewerFace2.n1 = newViewerFace2.n3 = newLayer.cutNormal2;
1871 newViewerFace2.n2 = lastCutNormal2; 1871 newViewerFace2.n2 = lastCutNormal2;
1872 } 1872 }
1873 1873
1874 else // outer and hollow faces 1874 else // outer and hollow faces
1875 { 1875 {
1876 if ((sides < 5 && whichVert < newLayer.numOuterVerts) || (hollowSides < 5 && whichVert >= newLayer.numOuterVerts)) 1876 if ((sides < 5 && whichVert < newLayer.numOuterVerts) || (hollowSides < 5 && whichVert >= newLayer.numOuterVerts))
1877 { // looks terrible when path is twisted... need vertex normals here 1877 { // looks terrible when path is twisted... need vertex normals here
1878 newViewerFace1.CalcSurfaceNormal(); 1878 newViewerFace1.CalcSurfaceNormal();
1879 newViewerFace2.CalcSurfaceNormal(); 1879 newViewerFace2.CalcSurfaceNormal();
1880 } 1880 }
1881 else 1881 else
1882 { 1882 {
1883 newViewerFace1.n1 = this.normals[i]; 1883 newViewerFace1.n1 = this.normals[i];
1884 newViewerFace1.n2 = this.normals[i - numVerts]; 1884 newViewerFace1.n2 = this.normals[i - numVerts];
1885 newViewerFace1.n3 = this.normals[iNext - numVerts]; 1885 newViewerFace1.n3 = this.normals[iNext - numVerts];
1886 1886
1887 newViewerFace2.n1 = this.normals[i]; 1887 newViewerFace2.n1 = this.normals[i];
1888 newViewerFace2.n2 = this.normals[iNext - numVerts]; 1888 newViewerFace2.n2 = this.normals[iNext - numVerts];
1889 newViewerFace2.n3 = this.normals[iNext]; 1889 newViewerFace2.n3 = this.normals[iNext];
1890 } 1890 }
1891 } 1891 }
1892 1892
1893 this.viewerFaces.Add(newViewerFace1); 1893 this.viewerFaces.Add(newViewerFace1);
1894 this.viewerFaces.Add(newViewerFace2); 1894 this.viewerFaces.Add(newViewerFace2);
1895 1895
1896 } 1896 }
1897 } 1897 }
1898 } 1898 }
1899 1899
1900 lastCutNormal1 = newLayer.cutNormal1; 1900 lastCutNormal1 = newLayer.cutNormal1;
1901 lastCutNormal2 = newLayer.cutNormal2; 1901 lastCutNormal2 = newLayer.cutNormal2;
1902 lastV = 1.0f - node.percentOfPath; 1902 lastV = 1.0f - node.percentOfPath;
1903 1903
1904 if (needEndFaces && nodeIndex == path.pathNodes.Count - 1 && viewerMode) 1904 if (needEndFaces && nodeIndex == path.pathNodes.Count - 1 && viewerMode)
1905 { 1905 {
1906 // add the top faces to the viewerFaces list here 1906 // add the top faces to the viewerFaces list here
1907 Coord faceNormal = newLayer.faceNormal; 1907 Coord faceNormal = newLayer.faceNormal;
1908 ViewerFace newViewerFace = new ViewerFace(); 1908 ViewerFace newViewerFace = new ViewerFace();
1909 newViewerFace.primFaceNumber = 0; 1909 newViewerFace.primFaceNumber = 0;
1910 int numFaces = newLayer.faces.Count; 1910 int numFaces = newLayer.faces.Count;
1911 List<Face> faces = newLayer.faces; 1911 List<Face> faces = newLayer.faces;
1912 1912
1913 for (int i = 0; i < numFaces; i++) 1913 for (int i = 0; i < numFaces; i++)
1914 { 1914 {
1915 Face face = faces[i]; 1915 Face face = faces[i];
1916 newViewerFace.v1 = newLayer.coords[face.v1 - coordsLen]; 1916 newViewerFace.v1 = newLayer.coords[face.v1 - coordsLen];
1917 newViewerFace.v2 = newLayer.coords[face.v2 - coordsLen]; 1917 newViewerFace.v2 = newLayer.coords[face.v2 - coordsLen];
1918 newViewerFace.v3 = newLayer.coords[face.v3 - coordsLen]; 1918 newViewerFace.v3 = newLayer.coords[face.v3 - coordsLen];
1919 1919
1920 newViewerFace.coordIndex1 = face.v1 - coordsLen; 1920 newViewerFace.coordIndex1 = face.v1 - coordsLen;
1921 newViewerFace.coordIndex2 = face.v2 - coordsLen; 1921 newViewerFace.coordIndex2 = face.v2 - coordsLen;
1922 newViewerFace.coordIndex3 = face.v3 - coordsLen; 1922 newViewerFace.coordIndex3 = face.v3 - coordsLen;
1923 1923
1924 newViewerFace.n1 = faceNormal; 1924 newViewerFace.n1 = faceNormal;
1925 newViewerFace.n2 = faceNormal; 1925 newViewerFace.n2 = faceNormal;
1926 newViewerFace.n3 = faceNormal; 1926 newViewerFace.n3 = faceNormal;
1927 1927
1928 newViewerFace.uv1 = newLayer.faceUVs[face.v1 - coordsLen]; 1928 newViewerFace.uv1 = newLayer.faceUVs[face.v1 - coordsLen];
1929 newViewerFace.uv2 = newLayer.faceUVs[face.v2 - coordsLen]; 1929 newViewerFace.uv2 = newLayer.faceUVs[face.v2 - coordsLen];
1930 newViewerFace.uv3 = newLayer.faceUVs[face.v3 - coordsLen]; 1930 newViewerFace.uv3 = newLayer.faceUVs[face.v3 - coordsLen];
1931 1931
1932 this.viewerFaces.Add(newViewerFace); 1932 this.viewerFaces.Add(newViewerFace);
1933 } 1933 }
1934 } 1934 }
1935 1935
1936 1936
1937 } // for (int nodeIndex = 0; nodeIndex < path.pathNodes.Count; nodeIndex++) 1937 } // for (int nodeIndex = 0; nodeIndex < path.pathNodes.Count; nodeIndex++)
1938 1938
1939 } 1939 }
1940 1940
1941 1941
1942 /// <summary> 1942 /// <summary>
1943 /// DEPRICATED - use Extrude(PathType.Linear) instead 1943 /// DEPRICATED - use Extrude(PathType.Linear) instead
1944 /// Extrudes a profile along a straight line path. Used for prim types box, cylinder, and prism. 1944 /// Extrudes a profile along a straight line path. Used for prim types box, cylinder, and prism.
1945 /// </summary> 1945 /// </summary>
1946 /// 1946 ///
1947 public void ExtrudeLinear() 1947 public void ExtrudeLinear()
1948 { 1948 {
1949 this.Extrude(PathType.Linear); 1949 this.Extrude(PathType.Linear);
1950 } 1950 }
1951 1951
1952 1952
1953 /// <summary> 1953 /// <summary>
1954 /// DEPRICATED - use Extrude(PathType.Circular) instead 1954 /// DEPRICATED - use Extrude(PathType.Circular) instead
1955 /// Extrude a profile into a circular path prim mesh. Used for prim types torus, tube, and ring. 1955 /// Extrude a profile into a circular path prim mesh. Used for prim types torus, tube, and ring.
1956 /// </summary> 1956 /// </summary>
1957 /// 1957 ///
1958 public void ExtrudeCircular() 1958 public void ExtrudeCircular()
1959 { 1959 {
1960 this.Extrude(PathType.Circular); 1960 this.Extrude(PathType.Circular);
1961 } 1961 }
1962 1962
1963 1963
1964 private Coord SurfaceNormal(Coord c1, Coord c2, Coord c3) 1964 private Coord SurfaceNormal(Coord c1, Coord c2, Coord c3)
1965 { 1965 {
1966 Coord edge1 = new Coord(c2.X - c1.X, c2.Y - c1.Y, c2.Z - c1.Z); 1966 Coord edge1 = new Coord(c2.X - c1.X, c2.Y - c1.Y, c2.Z - c1.Z);
1967 Coord edge2 = new Coord(c3.X - c1.X, c3.Y - c1.Y, c3.Z - c1.Z); 1967 Coord edge2 = new Coord(c3.X - c1.X, c3.Y - c1.Y, c3.Z - c1.Z);
1968 1968
1969 Coord normal = Coord.Cross(edge1, edge2); 1969 Coord normal = Coord.Cross(edge1, edge2);
1970 1970
1971 normal.Normalize(); 1971 normal.Normalize();
1972 1972
1973 return normal; 1973 return normal;
1974 } 1974 }
1975 1975
1976 private Coord SurfaceNormal(Face face) 1976 private Coord SurfaceNormal(Face face)
1977 { 1977 {
1978 return SurfaceNormal(this.coords[face.v1], this.coords[face.v2], this.coords[face.v3]); 1978 return SurfaceNormal(this.coords[face.v1], this.coords[face.v2], this.coords[face.v3]);
1979 } 1979 }
1980 1980
1981 /// <summary> 1981 /// <summary>
1982 /// Calculate the surface normal for a face in the list of faces 1982 /// Calculate the surface normal for a face in the list of faces
1983 /// </summary> 1983 /// </summary>
1984 /// <param name="faceIndex"></param> 1984 /// <param name="faceIndex"></param>
1985 /// <returns></returns> 1985 /// <returns></returns>
1986 public Coord SurfaceNormal(int faceIndex) 1986 public Coord SurfaceNormal(int faceIndex)
1987 { 1987 {
1988 int numFaces = this.faces.Count; 1988 int numFaces = this.faces.Count;
1989 if (faceIndex < 0 || faceIndex >= numFaces) 1989 if (faceIndex < 0 || faceIndex >= numFaces)
1990 throw new Exception("faceIndex out of range"); 1990 throw new Exception("faceIndex out of range");
1991 1991
1992 return SurfaceNormal(this.faces[faceIndex]); 1992 return SurfaceNormal(this.faces[faceIndex]);
1993 } 1993 }
1994 1994
1995 /// <summary> 1995 /// <summary>
1996 /// Duplicates a PrimMesh object. All object properties are copied by value, including lists. 1996 /// Duplicates a PrimMesh object. All object properties are copied by value, including lists.
1997 /// </summary> 1997 /// </summary>
1998 /// <returns></returns> 1998 /// <returns></returns>
1999 public PrimMesh Copy() 1999 public PrimMesh Copy()
2000 { 2000 {
2001 PrimMesh copy = new PrimMesh(this.sides, this.profileStart, this.profileEnd, this.hollow, this.hollowSides); 2001 PrimMesh copy = new PrimMesh(this.sides, this.profileStart, this.profileEnd, this.hollow, this.hollowSides);
2002 copy.twistBegin = this.twistBegin; 2002 copy.twistBegin = this.twistBegin;
2003 copy.twistEnd = this.twistEnd; 2003 copy.twistEnd = this.twistEnd;
2004 copy.topShearX = this.topShearX; 2004 copy.topShearX = this.topShearX;
2005 copy.topShearY = this.topShearY; 2005 copy.topShearY = this.topShearY;
2006 copy.pathCutBegin = this.pathCutBegin; 2006 copy.pathCutBegin = this.pathCutBegin;
2007 copy.pathCutEnd = this.pathCutEnd; 2007 copy.pathCutEnd = this.pathCutEnd;
2008 copy.dimpleBegin = this.dimpleBegin; 2008 copy.dimpleBegin = this.dimpleBegin;
2009 copy.dimpleEnd = this.dimpleEnd; 2009 copy.dimpleEnd = this.dimpleEnd;
2010 copy.skew = this.skew; 2010 copy.skew = this.skew;
2011 copy.holeSizeX = this.holeSizeX; 2011 copy.holeSizeX = this.holeSizeX;
2012 copy.holeSizeY = this.holeSizeY; 2012 copy.holeSizeY = this.holeSizeY;
2013 copy.taperX = this.taperX; 2013 copy.taperX = this.taperX;
2014 copy.taperY = this.taperY; 2014 copy.taperY = this.taperY;
2015 copy.radius = this.radius; 2015 copy.radius = this.radius;
2016 copy.revolutions = this.revolutions; 2016 copy.revolutions = this.revolutions;
2017 copy.stepsPerRevolution = this.stepsPerRevolution; 2017 copy.stepsPerRevolution = this.stepsPerRevolution;
2018 copy.calcVertexNormals = this.calcVertexNormals; 2018 copy.calcVertexNormals = this.calcVertexNormals;
2019 copy.normalsProcessed = this.normalsProcessed; 2019 copy.normalsProcessed = this.normalsProcessed;
2020 copy.viewerMode = this.viewerMode; 2020 copy.viewerMode = this.viewerMode;
2021 copy.numPrimFaces = this.numPrimFaces; 2021 copy.numPrimFaces = this.numPrimFaces;
2022 copy.errorMessage = this.errorMessage; 2022 copy.errorMessage = this.errorMessage;
2023 2023
2024 copy.coords = new List<Coord>(this.coords); 2024 copy.coords = new List<Coord>(this.coords);
2025 copy.faces = new List<Face>(this.faces); 2025 copy.faces = new List<Face>(this.faces);
2026 copy.viewerFaces = new List<ViewerFace>(this.viewerFaces); 2026 copy.viewerFaces = new List<ViewerFace>(this.viewerFaces);
2027 copy.normals = new List<Coord>(this.normals); 2027 copy.normals = new List<Coord>(this.normals);
2028 2028
2029 return copy; 2029 return copy;
2030 } 2030 }
2031 2031
2032 /// <summary> 2032 /// <summary>
2033 /// Calculate surface normals for all of the faces in the list of faces in this mesh 2033 /// Calculate surface normals for all of the faces in the list of faces in this mesh
2034 /// </summary> 2034 /// </summary>
2035 public void CalcNormals() 2035 public void CalcNormals()
2036 { 2036 {
2037 if (normalsProcessed) 2037 if (normalsProcessed)
2038 return; 2038 return;
2039 2039
2040 normalsProcessed = true; 2040 normalsProcessed = true;
2041 2041
2042 int numFaces = faces.Count; 2042 int numFaces = faces.Count;
2043 2043
2044 if (!this.calcVertexNormals) 2044 if (!this.calcVertexNormals)
2045 this.normals = new List<Coord>(); 2045 this.normals = new List<Coord>();
2046 2046
2047 for (int i = 0; i < numFaces; i++) 2047 for (int i = 0; i < numFaces; i++)
2048 { 2048 {
2049 Face face = faces[i]; 2049 Face face = faces[i];
2050 2050
2051 this.normals.Add(SurfaceNormal(i).Normalize()); 2051 this.normals.Add(SurfaceNormal(i).Normalize());
2052 2052
2053 int normIndex = normals.Count - 1; 2053 int normIndex = normals.Count - 1;
2054 face.n1 = normIndex; 2054 face.n1 = normIndex;
2055 face.n2 = normIndex; 2055 face.n2 = normIndex;
2056 face.n3 = normIndex; 2056 face.n3 = normIndex;
2057 2057
2058 this.faces[i] = face; 2058 this.faces[i] = face;
2059 } 2059 }
2060 } 2060 }
2061 2061
2062 /// <summary> 2062 /// <summary>
2063 /// Adds a value to each XYZ vertex coordinate in the mesh 2063 /// Adds a value to each XYZ vertex coordinate in the mesh
2064 /// </summary> 2064 /// </summary>
2065 /// <param name="x"></param> 2065 /// <param name="x"></param>
2066 /// <param name="y"></param> 2066 /// <param name="y"></param>
2067 /// <param name="z"></param> 2067 /// <param name="z"></param>
2068 public void AddPos(float x, float y, float z) 2068 public void AddPos(float x, float y, float z)
2069 { 2069 {
2070 int i; 2070 int i;
2071 int numVerts = this.coords.Count; 2071 int numVerts = this.coords.Count;
2072 Coord vert; 2072 Coord vert;
2073 2073
2074 for (i = 0; i < numVerts; i++) 2074 for (i = 0; i < numVerts; i++)
2075 { 2075 {
2076 vert = this.coords[i]; 2076 vert = this.coords[i];
2077 vert.X += x; 2077 vert.X += x;
2078 vert.Y += y; 2078 vert.Y += y;
2079 vert.Z += z; 2079 vert.Z += z;
2080 this.coords[i] = vert; 2080 this.coords[i] = vert;
2081 } 2081 }
2082 2082
2083 if (this.viewerFaces != null) 2083 if (this.viewerFaces != null)
2084 { 2084 {
2085 int numViewerFaces = this.viewerFaces.Count; 2085 int numViewerFaces = this.viewerFaces.Count;
2086 2086
2087 for (i = 0; i < numViewerFaces; i++) 2087 for (i = 0; i < numViewerFaces; i++)
2088 { 2088 {
2089 ViewerFace v = this.viewerFaces[i]; 2089 ViewerFace v = this.viewerFaces[i];
2090 v.AddPos(x, y, z); 2090 v.AddPos(x, y, z);
2091 this.viewerFaces[i] = v; 2091 this.viewerFaces[i] = v;
2092 } 2092 }
2093 } 2093 }
2094 } 2094 }
2095 2095
2096 /// <summary> 2096 /// <summary>
2097 /// Rotates the mesh 2097 /// Rotates the mesh
2098 /// </summary> 2098 /// </summary>
2099 /// <param name="q"></param> 2099 /// <param name="q"></param>
2100 public void AddRot(Quat q) 2100 public void AddRot(Quat q)
2101 { 2101 {
2102 int i; 2102 int i;
2103 int numVerts = this.coords.Count; 2103 int numVerts = this.coords.Count;
2104 2104
2105 for (i = 0; i < numVerts; i++) 2105 for (i = 0; i < numVerts; i++)
2106 this.coords[i] *= q; 2106 this.coords[i] *= q;
2107 2107
2108 if (this.normals != null) 2108 if (this.normals != null)
2109 { 2109 {
2110 int numNormals = this.normals.Count; 2110 int numNormals = this.normals.Count;
2111 for (i = 0; i < numNormals; i++) 2111 for (i = 0; i < numNormals; i++)
2112 this.normals[i] *= q; 2112 this.normals[i] *= q;
2113 } 2113 }
2114 2114
2115 if (this.viewerFaces != null) 2115 if (this.viewerFaces != null)
2116 { 2116 {
2117 int numViewerFaces = this.viewerFaces.Count; 2117 int numViewerFaces = this.viewerFaces.Count;
2118 2118
2119 for (i = 0; i < numViewerFaces; i++) 2119 for (i = 0; i < numViewerFaces; i++)
2120 { 2120 {
2121 ViewerFace v = this.viewerFaces[i]; 2121 ViewerFace v = this.viewerFaces[i];
2122 v.v1 *= q; 2122 v.v1 *= q;
2123 v.v2 *= q; 2123 v.v2 *= q;
2124 v.v3 *= q; 2124 v.v3 *= q;
2125 2125
2126 v.n1 *= q; 2126 v.n1 *= q;
2127 v.n2 *= q; 2127 v.n2 *= q;
2128 v.n3 *= q; 2128 v.n3 *= q;
2129 this.viewerFaces[i] = v; 2129 this.viewerFaces[i] = v;
2130 } 2130 }
2131 } 2131 }
2132 } 2132 }
2133 2133
2134#if VERTEX_INDEXER 2134#if VERTEX_INDEXER
2135 public VertexIndexer GetVertexIndexer() 2135 public VertexIndexer GetVertexIndexer()
2136 { 2136 {
2137 if (this.viewerMode && this.viewerFaces.Count > 0) 2137 if (this.viewerMode && this.viewerFaces.Count > 0)
2138 return new VertexIndexer(this); 2138 return new VertexIndexer(this);
2139 return null; 2139 return null;
2140 } 2140 }
2141#endif 2141#endif
2142 2142
2143 /// <summary> 2143 /// <summary>
2144 /// Scales the mesh 2144 /// Scales the mesh
2145 /// </summary> 2145 /// </summary>
2146 /// <param name="x"></param> 2146 /// <param name="x"></param>
2147 /// <param name="y"></param> 2147 /// <param name="y"></param>
2148 /// <param name="z"></param> 2148 /// <param name="z"></param>
2149 public void Scale(float x, float y, float z) 2149 public void Scale(float x, float y, float z)
2150 { 2150 {
2151 int i; 2151 int i;
2152 int numVerts = this.coords.Count; 2152 int numVerts = this.coords.Count;
2153 //Coord vert; 2153 //Coord vert;
2154 2154
2155 Coord m = new Coord(x, y, z); 2155 Coord m = new Coord(x, y, z);
2156 for (i = 0; i < numVerts; i++) 2156 for (i = 0; i < numVerts; i++)
2157 this.coords[i] *= m; 2157 this.coords[i] *= m;
2158 2158
2159 if (this.viewerFaces != null) 2159 if (this.viewerFaces != null)
2160 { 2160 {
2161 int numViewerFaces = this.viewerFaces.Count; 2161 int numViewerFaces = this.viewerFaces.Count;
2162 for (i = 0; i < numViewerFaces; i++) 2162 for (i = 0; i < numViewerFaces; i++)
2163 { 2163 {
2164 ViewerFace v = this.viewerFaces[i]; 2164 ViewerFace v = this.viewerFaces[i];
2165 v.v1 *= m; 2165 v.v1 *= m;
2166 v.v2 *= m; 2166 v.v2 *= m;
2167 v.v3 *= m; 2167 v.v3 *= m;
2168 this.viewerFaces[i] = v; 2168 this.viewerFaces[i] = v;
2169 } 2169 }
2170 2170
2171 } 2171 }
2172 2172
2173 } 2173 }
2174 2174
2175 /// <summary> 2175 /// <summary>
2176 /// Dumps the mesh to a Blender compatible "Raw" format file 2176 /// Dumps the mesh to a Blender compatible "Raw" format file
2177 /// </summary> 2177 /// </summary>
2178 /// <param name="path"></param> 2178 /// <param name="path"></param>
2179 /// <param name="name"></param> 2179 /// <param name="name"></param>
2180 /// <param name="title"></param> 2180 /// <param name="title"></param>
2181 public void DumpRaw(String path, String name, String title) 2181 public void DumpRaw(String path, String name, String title)
2182 { 2182 {
2183 if (path == null) 2183 if (path == null)
2184 return; 2184 return;
2185 String fileName = name + "_" + title + ".raw"; 2185 String fileName = name + "_" + title + ".raw";
2186 String completePath = System.IO.Path.Combine(path, fileName); 2186 String completePath = System.IO.Path.Combine(path, fileName);
2187 StreamWriter sw = new StreamWriter(completePath); 2187 StreamWriter sw = new StreamWriter(completePath);
2188 2188
2189 for (int i = 0; i < this.faces.Count; i++) 2189 for (int i = 0; i < this.faces.Count; i++)
2190 { 2190 {
2191 string s = this.coords[this.faces[i].v1].ToString(); 2191 string s = this.coords[this.faces[i].v1].ToString();
2192 s += " " + this.coords[this.faces[i].v2].ToString(); 2192 s += " " + this.coords[this.faces[i].v2].ToString();
2193 s += " " + this.coords[this.faces[i].v3].ToString(); 2193 s += " " + this.coords[this.faces[i].v3].ToString();
2194 2194
2195 sw.WriteLine(s); 2195 sw.WriteLine(s);
2196 } 2196 }
2197 2197
2198 sw.Close(); 2198 sw.Close();
2199 } 2199 }
2200 } 2200 }
2201} 2201}
diff --git a/OpenSim/Region/Physics/Meshing/SculptMesh.cs b/OpenSim/Region/Physics/Meshing/SculptMesh.cs
index 11b6cd4..ebc5be6 100644
--- a/OpenSim/Region/Physics/Meshing/SculptMesh.cs
+++ b/OpenSim/Region/Physics/Meshing/SculptMesh.cs
@@ -1,645 +1,645 @@
1/* 1/*
2 * Copyright (c) Contributors 2 * Copyright (c) Contributors
3 * See CONTRIBUTORS.TXT for a full list of copyright holders. 3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 * 4 *
5 * Redistribution and use in source and binary forms, with or without 5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met: 6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright 7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer. 8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright 9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the 10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution. 11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the 12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products 13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission. 14 * derived from this software without specific prior written permission.
15 * 15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY 16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY 19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27 27
28// to build without references to System.Drawing, comment this out 28// to build without references to System.Drawing, comment this out
29#define SYSTEM_DRAWING 29#define SYSTEM_DRAWING
30 30
31using System; 31using System;
32using System.Collections.Generic; 32using System.Collections.Generic;
33using System.Text; 33using System.Text;
34using System.IO; 34using System.IO;
35 35
36#if SYSTEM_DRAWING 36#if SYSTEM_DRAWING
37using System.Drawing; 37using System.Drawing;
38using System.Drawing.Imaging; 38using System.Drawing.Imaging;
39#endif 39#endif
40 40
41namespace PrimMesher 41namespace PrimMesher
42{ 42{
43 43
44 public class SculptMesh 44 public class SculptMesh
45 { 45 {
46 public List<Coord> coords; 46 public List<Coord> coords;
47 public List<Face> faces; 47 public List<Face> faces;
48 48
49 public List<ViewerFace> viewerFaces; 49 public List<ViewerFace> viewerFaces;
50 public List<Coord> normals; 50 public List<Coord> normals;
51 public List<UVCoord> uvs; 51 public List<UVCoord> uvs;
52 52
53 public enum SculptType { sphere = 1, torus = 2, plane = 3, cylinder = 4 }; 53 public enum SculptType { sphere = 1, torus = 2, plane = 3, cylinder = 4 };
54 54
55#if SYSTEM_DRAWING 55#if SYSTEM_DRAWING
56 private Bitmap ScaleImage(Bitmap srcImage, float scale, bool removeAlpha) 56 private Bitmap ScaleImage(Bitmap srcImage, float scale, bool removeAlpha)
57 { 57 {
58 int sourceWidth = srcImage.Width; 58 int sourceWidth = srcImage.Width;
59 int sourceHeight = srcImage.Height; 59 int sourceHeight = srcImage.Height;
60 int sourceX = 0; 60 int sourceX = 0;
61 int sourceY = 0; 61 int sourceY = 0;
62 62
63 int destX = 0; 63 int destX = 0;
64 int destY = 0; 64 int destY = 0;
65 int destWidth = (int)(srcImage.Width * scale); 65 int destWidth = (int)(srcImage.Width * scale);
66 int destHeight = (int)(srcImage.Height * scale); 66 int destHeight = (int)(srcImage.Height * scale);
67 67
68 Bitmap scaledImage; 68 Bitmap scaledImage;
69 69
70 if (removeAlpha) 70 if (removeAlpha)
71 { 71 {
72 if (srcImage.PixelFormat == PixelFormat.Format32bppArgb) 72 if (srcImage.PixelFormat == PixelFormat.Format32bppArgb)
73 for (int y = 0; y < srcImage.Height; y++) 73 for (int y = 0; y < srcImage.Height; y++)
74 for (int x = 0; x < srcImage.Width; x++) 74 for (int x = 0; x < srcImage.Width; x++)
75 { 75 {
76 Color c = srcImage.GetPixel(x, y); 76 Color c = srcImage.GetPixel(x, y);
77 srcImage.SetPixel(x, y, Color.FromArgb(255, c.R, c.G, c.B)); 77 srcImage.SetPixel(x, y, Color.FromArgb(255, c.R, c.G, c.B));
78 } 78 }
79 79
80 scaledImage = new Bitmap(destWidth, destHeight, 80 scaledImage = new Bitmap(destWidth, destHeight,
81 PixelFormat.Format24bppRgb); 81 PixelFormat.Format24bppRgb);
82 } 82 }
83 else 83 else
84 scaledImage = new Bitmap(srcImage, destWidth, destHeight); 84 scaledImage = new Bitmap(srcImage, destWidth, destHeight);
85 85
86 scaledImage.SetResolution(96.0f, 96.0f); 86 scaledImage.SetResolution(96.0f, 96.0f);
87 87
88 Graphics grPhoto = Graphics.FromImage(scaledImage); 88 Graphics grPhoto = Graphics.FromImage(scaledImage);
89 grPhoto.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.Low; 89 grPhoto.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.Low;
90 90
91 grPhoto.DrawImage(srcImage, 91 grPhoto.DrawImage(srcImage,
92 new Rectangle(destX, destY, destWidth, destHeight), 92 new Rectangle(destX, destY, destWidth, destHeight),
93 new Rectangle(sourceX, sourceY, sourceWidth, sourceHeight), 93 new Rectangle(sourceX, sourceY, sourceWidth, sourceHeight),
94 GraphicsUnit.Pixel); 94 GraphicsUnit.Pixel);
95 95
96 grPhoto.Dispose(); 96 grPhoto.Dispose();
97 return scaledImage; 97 return scaledImage;
98 } 98 }
99 99
100 100
101 public SculptMesh SculptMeshFromFile(string fileName, SculptType sculptType, int lod, bool viewerMode) 101 public SculptMesh SculptMeshFromFile(string fileName, SculptType sculptType, int lod, bool viewerMode)
102 { 102 {
103 Bitmap bitmap = (Bitmap)Bitmap.FromFile(fileName); 103 Bitmap bitmap = (Bitmap)Bitmap.FromFile(fileName);
104 SculptMesh sculptMesh = new SculptMesh(bitmap, sculptType, lod, viewerMode); 104 SculptMesh sculptMesh = new SculptMesh(bitmap, sculptType, lod, viewerMode);
105 bitmap.Dispose(); 105 bitmap.Dispose();
106 return sculptMesh; 106 return sculptMesh;
107 } 107 }
108 108
109 public SculptMesh(string fileName, int sculptType, int lod, int viewerMode, int mirror, int invert) 109 public SculptMesh(string fileName, int sculptType, int lod, int viewerMode, int mirror, int invert)
110 { 110 {
111 Bitmap bitmap = (Bitmap)Bitmap.FromFile(fileName); 111 Bitmap bitmap = (Bitmap)Bitmap.FromFile(fileName);
112 _SculptMesh(bitmap, (SculptType)sculptType, lod, viewerMode != 0, mirror != 0, invert != 0); 112 _SculptMesh(bitmap, (SculptType)sculptType, lod, viewerMode != 0, mirror != 0, invert != 0);
113 bitmap.Dispose(); 113 bitmap.Dispose();
114 } 114 }
115#endif 115#endif
116 116
117 /// <summary> 117 /// <summary>
118 /// ** Experimental ** May disappear from future versions ** not recommeneded for use in applications 118 /// ** Experimental ** May disappear from future versions ** not recommeneded for use in applications
119 /// Construct a sculpt mesh from a 2D array of floats 119 /// Construct a sculpt mesh from a 2D array of floats
120 /// </summary> 120 /// </summary>
121 /// <param name="zMap"></param> 121 /// <param name="zMap"></param>
122 /// <param name="xBegin"></param> 122 /// <param name="xBegin"></param>
123 /// <param name="xEnd"></param> 123 /// <param name="xEnd"></param>
124 /// <param name="yBegin"></param> 124 /// <param name="yBegin"></param>
125 /// <param name="yEnd"></param> 125 /// <param name="yEnd"></param>
126 /// <param name="viewerMode"></param> 126 /// <param name="viewerMode"></param>
127 public SculptMesh(float[,] zMap, float xBegin, float xEnd, float yBegin, float yEnd, bool viewerMode) 127 public SculptMesh(float[,] zMap, float xBegin, float xEnd, float yBegin, float yEnd, bool viewerMode)
128 { 128 {
129 float xStep, yStep; 129 float xStep, yStep;
130 float uStep, vStep; 130 float uStep, vStep;
131 131
132 int numYElements = zMap.GetLength(0); 132 int numYElements = zMap.GetLength(0);
133 int numXElements = zMap.GetLength(1); 133 int numXElements = zMap.GetLength(1);
134 134
135 try 135 try
136 { 136 {
137 xStep = (xEnd - xBegin) / (float)(numXElements - 1); 137 xStep = (xEnd - xBegin) / (float)(numXElements - 1);
138 yStep = (yEnd - yBegin) / (float)(numYElements - 1); 138 yStep = (yEnd - yBegin) / (float)(numYElements - 1);
139 139
140 uStep = 1.0f / (numXElements - 1); 140 uStep = 1.0f / (numXElements - 1);
141 vStep = 1.0f / (numYElements - 1); 141 vStep = 1.0f / (numYElements - 1);
142 } 142 }
143 catch (DivideByZeroException) 143 catch (DivideByZeroException)
144 { 144 {
145 return; 145 return;
146 } 146 }
147 147
148 coords = new List<Coord>(); 148 coords = new List<Coord>();
149 faces = new List<Face>(); 149 faces = new List<Face>();
150 normals = new List<Coord>(); 150 normals = new List<Coord>();
151 uvs = new List<UVCoord>(); 151 uvs = new List<UVCoord>();
152 152
153 viewerFaces = new List<ViewerFace>(); 153 viewerFaces = new List<ViewerFace>();
154 154
155 int p1, p2, p3, p4; 155 int p1, p2, p3, p4;
156 156
157 int x, y; 157 int x, y;
158 int xStart = 0, yStart = 0; 158 int xStart = 0, yStart = 0;
159 159
160 for (y = yStart; y < numYElements; y++) 160 for (y = yStart; y < numYElements; y++)
161 { 161 {
162 int rowOffset = y * numXElements; 162 int rowOffset = y * numXElements;
163 163
164 for (x = xStart; x < numXElements; x++) 164 for (x = xStart; x < numXElements; x++)
165 { 165 {
166 /* 166 /*
167 * p1-----p2 167 * p1-----p2
168 * | \ f2 | 168 * | \ f2 |
169 * | \ | 169 * | \ |
170 * | f1 \| 170 * | f1 \|
171 * p3-----p4 171 * p3-----p4
172 */ 172 */
173 173
174 p4 = rowOffset + x; 174 p4 = rowOffset + x;
175 p3 = p4 - 1; 175 p3 = p4 - 1;
176 176
177 p2 = p4 - numXElements; 177 p2 = p4 - numXElements;
178 p1 = p3 - numXElements; 178 p1 = p3 - numXElements;
179 179
180 Coord c = new Coord(xBegin + x * xStep, yBegin + y * yStep, zMap[y, x]); 180 Coord c = new Coord(xBegin + x * xStep, yBegin + y * yStep, zMap[y, x]);
181 this.coords.Add(c); 181 this.coords.Add(c);
182 if (viewerMode) 182 if (viewerMode)
183 { 183 {
184 this.normals.Add(new Coord()); 184 this.normals.Add(new Coord());
185 this.uvs.Add(new UVCoord(uStep * x, 1.0f - vStep * y)); 185 this.uvs.Add(new UVCoord(uStep * x, 1.0f - vStep * y));
186 } 186 }
187 187
188 if (y > 0 && x > 0) 188 if (y > 0 && x > 0)
189 { 189 {
190 Face f1, f2; 190 Face f1, f2;
191 191
192 if (viewerMode) 192 if (viewerMode)
193 { 193 {
194 f1 = new Face(p1, p4, p3, p1, p4, p3); 194 f1 = new Face(p1, p4, p3, p1, p4, p3);
195 f1.uv1 = p1; 195 f1.uv1 = p1;
196 f1.uv2 = p4; 196 f1.uv2 = p4;
197 f1.uv3 = p3; 197 f1.uv3 = p3;
198 198
199 f2 = new Face(p1, p2, p4, p1, p2, p4); 199 f2 = new Face(p1, p2, p4, p1, p2, p4);
200 f2.uv1 = p1; 200 f2.uv1 = p1;
201 f2.uv2 = p2; 201 f2.uv2 = p2;
202 f2.uv3 = p4; 202 f2.uv3 = p4;
203 } 203 }
204 else 204 else
205 { 205 {
206 f1 = new Face(p1, p4, p3); 206 f1 = new Face(p1, p4, p3);
207 f2 = new Face(p1, p2, p4); 207 f2 = new Face(p1, p2, p4);
208 } 208 }
209 209
210 this.faces.Add(f1); 210 this.faces.Add(f1);
211 this.faces.Add(f2); 211 this.faces.Add(f2);
212 } 212 }
213 } 213 }
214 } 214 }
215 215
216 if (viewerMode) 216 if (viewerMode)
217 calcVertexNormals(SculptType.plane, numXElements, numYElements); 217 calcVertexNormals(SculptType.plane, numXElements, numYElements);
218 } 218 }
219 219
220#if SYSTEM_DRAWING 220#if SYSTEM_DRAWING
221 public SculptMesh(Bitmap sculptBitmap, SculptType sculptType, int lod, bool viewerMode) 221 public SculptMesh(Bitmap sculptBitmap, SculptType sculptType, int lod, bool viewerMode)
222 { 222 {
223 _SculptMesh(sculptBitmap, sculptType, lod, viewerMode, false, false); 223 _SculptMesh(sculptBitmap, sculptType, lod, viewerMode, false, false);
224 } 224 }
225 225
226 public SculptMesh(Bitmap sculptBitmap, SculptType sculptType, int lod, bool viewerMode, bool mirror, bool invert) 226 public SculptMesh(Bitmap sculptBitmap, SculptType sculptType, int lod, bool viewerMode, bool mirror, bool invert)
227 { 227 {
228 _SculptMesh(sculptBitmap, sculptType, lod, viewerMode, mirror, invert); 228 _SculptMesh(sculptBitmap, sculptType, lod, viewerMode, mirror, invert);
229 } 229 }
230#endif 230#endif
231 231
232 public SculptMesh(List<List<Coord>> rows, SculptType sculptType, bool viewerMode, bool mirror, bool invert) 232 public SculptMesh(List<List<Coord>> rows, SculptType sculptType, bool viewerMode, bool mirror, bool invert)
233 { 233 {
234 _SculptMesh(rows, sculptType, viewerMode, mirror, invert); 234 _SculptMesh(rows, sculptType, viewerMode, mirror, invert);
235 } 235 }
236 236
237#if SYSTEM_DRAWING 237#if SYSTEM_DRAWING
238 /// <summary> 238 /// <summary>
239 /// converts a bitmap to a list of lists of coords, while scaling the image. 239 /// converts a bitmap to a list of lists of coords, while scaling the image.
240 /// the scaling is done in floating point so as to allow for reduced vertex position 240 /// the scaling is done in floating point so as to allow for reduced vertex position
241 /// quantization as the position will be averaged between pixel values. this routine will 241 /// quantization as the position will be averaged between pixel values. this routine will
242 /// likely fail if the bitmap width and height are not powers of 2. 242 /// likely fail if the bitmap width and height are not powers of 2.
243 /// </summary> 243 /// </summary>
244 /// <param name="bitmap"></param> 244 /// <param name="bitmap"></param>
245 /// <param name="scale"></param> 245 /// <param name="scale"></param>
246 /// <param name="mirror"></param> 246 /// <param name="mirror"></param>
247 /// <returns></returns> 247 /// <returns></returns>
248 private List<List<Coord>> bitmap2Coords(Bitmap bitmap, int scale, bool mirror) 248 private List<List<Coord>> bitmap2Coords(Bitmap bitmap, int scale, bool mirror)
249 { 249 {
250 int numRows = bitmap.Height / scale; 250 int numRows = bitmap.Height / scale;
251 int numCols = bitmap.Width / scale; 251 int numCols = bitmap.Width / scale;
252 List<List<Coord>> rows = new List<List<Coord>>(numRows); 252 List<List<Coord>> rows = new List<List<Coord>>(numRows);
253 253
254 float pixScale = 1.0f / (scale * scale); 254 float pixScale = 1.0f / (scale * scale);
255 pixScale /= 255; 255 pixScale /= 255;
256 256
257 int imageX, imageY = 0; 257 int imageX, imageY = 0;
258 258
259 int rowNdx, colNdx; 259 int rowNdx, colNdx;
260 260
261 for (rowNdx = 0; rowNdx < numRows; rowNdx++) 261 for (rowNdx = 0; rowNdx < numRows; rowNdx++)
262 { 262 {
263 List<Coord> row = new List<Coord>(numCols); 263 List<Coord> row = new List<Coord>(numCols);
264 for (colNdx = 0; colNdx < numCols; colNdx++) 264 for (colNdx = 0; colNdx < numCols; colNdx++)
265 { 265 {
266 imageX = colNdx * scale; 266 imageX = colNdx * scale;
267 int imageYStart = rowNdx * scale; 267 int imageYStart = rowNdx * scale;
268 int imageYEnd = imageYStart + scale; 268 int imageYEnd = imageYStart + scale;
269 int imageXEnd = imageX + scale; 269 int imageXEnd = imageX + scale;
270 float rSum = 0.0f; 270 float rSum = 0.0f;
271 float gSum = 0.0f; 271 float gSum = 0.0f;
272 float bSum = 0.0f; 272 float bSum = 0.0f;
273 for (; imageX < imageXEnd; imageX++) 273 for (; imageX < imageXEnd; imageX++)
274 { 274 {
275 for (imageY = imageYStart; imageY < imageYEnd; imageY++) 275 for (imageY = imageYStart; imageY < imageYEnd; imageY++)
276 { 276 {
277 Color c = bitmap.GetPixel(imageX, imageY); 277 Color c = bitmap.GetPixel(imageX, imageY);
278 if (c.A != 255) 278 if (c.A != 255)
279 { 279 {
280 bitmap.SetPixel(imageX, imageY, Color.FromArgb(255, c.R, c.G, c.B)); 280 bitmap.SetPixel(imageX, imageY, Color.FromArgb(255, c.R, c.G, c.B));
281 c = bitmap.GetPixel(imageX, imageY); 281 c = bitmap.GetPixel(imageX, imageY);
282 } 282 }
283 rSum += c.R; 283 rSum += c.R;
284 gSum += c.G; 284 gSum += c.G;
285 bSum += c.B; 285 bSum += c.B;
286 } 286 }
287 } 287 }
288 if (mirror) 288 if (mirror)
289 row.Add(new Coord(-(rSum * pixScale - 0.5f), gSum * pixScale - 0.5f, bSum * pixScale - 0.5f)); 289 row.Add(new Coord(-(rSum * pixScale - 0.5f), gSum * pixScale - 0.5f, bSum * pixScale - 0.5f));
290 else 290 else
291 row.Add(new Coord(rSum * pixScale - 0.5f, gSum * pixScale - 0.5f, bSum * pixScale - 0.5f)); 291 row.Add(new Coord(rSum * pixScale - 0.5f, gSum * pixScale - 0.5f, bSum * pixScale - 0.5f));
292 292
293 } 293 }
294 rows.Add(row); 294 rows.Add(row);
295 } 295 }
296 return rows; 296 return rows;
297 } 297 }
298 298
299 299
300 void _SculptMesh(Bitmap sculptBitmap, SculptType sculptType, int lod, bool viewerMode, bool mirror, bool invert) 300 void _SculptMesh(Bitmap sculptBitmap, SculptType sculptType, int lod, bool viewerMode, bool mirror, bool invert)
301 { 301 {
302 coords = new List<Coord>(); 302 coords = new List<Coord>();
303 faces = new List<Face>(); 303 faces = new List<Face>();
304 normals = new List<Coord>(); 304 normals = new List<Coord>();
305 uvs = new List<UVCoord>(); 305 uvs = new List<UVCoord>();
306 306
307 sculptType = (SculptType)(((int)sculptType) & 0x07); 307 sculptType = (SculptType)(((int)sculptType) & 0x07);
308 308
309 if (mirror) 309 if (mirror)
310 if (sculptType == SculptType.plane) 310 if (sculptType == SculptType.plane)
311 invert = !invert; 311 invert = !invert;
312 312
313 float sculptBitmapLod = (float)Math.Sqrt(sculptBitmap.Width * sculptBitmap.Height); 313 float sculptBitmapLod = (float)Math.Sqrt(sculptBitmap.Width * sculptBitmap.Height);
314 314
315 float sourceScaleFactor = (float)(lod) / sculptBitmapLod; 315 float sourceScaleFactor = (float)(lod) / sculptBitmapLod;
316 316
317 float fScale = 1.0f / sourceScaleFactor; 317 float fScale = 1.0f / sourceScaleFactor;
318 318
319 int iScale = (int)fScale; 319 int iScale = (int)fScale;
320 if (iScale < 1) iScale = 1; 320 if (iScale < 1) iScale = 1;
321 if (iScale > 2 && iScale % 2 == 0) 321 if (iScale > 2 && iScale % 2 == 0)
322 _SculptMesh(bitmap2Coords(ScaleImage(sculptBitmap, 64.0f / sculptBitmapLod, true), 64 / lod, mirror), sculptType, viewerMode, mirror, invert); 322 _SculptMesh(bitmap2Coords(ScaleImage(sculptBitmap, 64.0f / sculptBitmapLod, true), 64 / lod, mirror), sculptType, viewerMode, mirror, invert);
323 else 323 else
324 _SculptMesh(bitmap2Coords(sculptBitmap, iScale, mirror), sculptType, viewerMode, mirror, invert); 324 _SculptMesh(bitmap2Coords(sculptBitmap, iScale, mirror), sculptType, viewerMode, mirror, invert);
325 } 325 }
326#endif 326#endif
327 327
328 328
329 void _SculptMesh(List<List<Coord>> rows, SculptType sculptType, bool viewerMode, bool mirror, bool invert) 329 void _SculptMesh(List<List<Coord>> rows, SculptType sculptType, bool viewerMode, bool mirror, bool invert)
330 { 330 {
331 coords = new List<Coord>(); 331 coords = new List<Coord>();
332 faces = new List<Face>(); 332 faces = new List<Face>();
333 normals = new List<Coord>(); 333 normals = new List<Coord>();
334 uvs = new List<UVCoord>(); 334 uvs = new List<UVCoord>();
335 335
336 sculptType = (SculptType)(((int)sculptType) & 0x07); 336 sculptType = (SculptType)(((int)sculptType) & 0x07);
337 337
338 if (mirror) 338 if (mirror)
339 if (sculptType == SculptType.plane) 339 if (sculptType == SculptType.plane)
340 invert = !invert; 340 invert = !invert;
341 341
342 viewerFaces = new List<ViewerFace>(); 342 viewerFaces = new List<ViewerFace>();
343 343
344 int width = rows[0].Count; 344 int width = rows[0].Count;
345 345
346 int p1, p2, p3, p4; 346 int p1, p2, p3, p4;
347 347
348 int imageX, imageY; 348 int imageX, imageY;
349 349
350 if (sculptType != SculptType.plane) 350 if (sculptType != SculptType.plane)
351 { 351 {
352 for (int rowNdx = 0; rowNdx < rows.Count; rowNdx++) 352 for (int rowNdx = 0; rowNdx < rows.Count; rowNdx++)
353 rows[rowNdx].Add(rows[rowNdx][0]); 353 rows[rowNdx].Add(rows[rowNdx][0]);
354 } 354 }
355 355
356 Coord topPole = rows[0][width / 2]; 356 Coord topPole = rows[0][width / 2];
357 Coord bottomPole = rows[rows.Count - 1][width / 2]; 357 Coord bottomPole = rows[rows.Count - 1][width / 2];
358 358
359 if (sculptType == SculptType.sphere) 359 if (sculptType == SculptType.sphere)
360 { 360 {
361 int count = rows[0].Count; 361 int count = rows[0].Count;
362 List<Coord> topPoleRow = new List<Coord>(count); 362 List<Coord> topPoleRow = new List<Coord>(count);
363 List<Coord> bottomPoleRow = new List<Coord>(count); 363 List<Coord> bottomPoleRow = new List<Coord>(count);
364 364
365 for (int i = 0; i < count; i++) 365 for (int i = 0; i < count; i++)
366 { 366 {
367 topPoleRow.Add(topPole); 367 topPoleRow.Add(topPole);
368 bottomPoleRow.Add(bottomPole); 368 bottomPoleRow.Add(bottomPole);
369 } 369 }
370 rows.Insert(0, topPoleRow); 370 rows.Insert(0, topPoleRow);
371 rows.Add(bottomPoleRow); 371 rows.Add(bottomPoleRow);
372 } 372 }
373 else if (sculptType == SculptType.torus) 373 else if (sculptType == SculptType.torus)
374 rows.Add(rows[0]); 374 rows.Add(rows[0]);
375 375
376 int coordsDown = rows.Count; 376 int coordsDown = rows.Count;
377 int coordsAcross = rows[0].Count; 377 int coordsAcross = rows[0].Count;
378 378
379 float widthUnit = 1.0f / (coordsAcross - 1); 379 float widthUnit = 1.0f / (coordsAcross - 1);
380 float heightUnit = 1.0f / (coordsDown - 1); 380 float heightUnit = 1.0f / (coordsDown - 1);
381 381
382 for (imageY = 0; imageY < coordsDown; imageY++) 382 for (imageY = 0; imageY < coordsDown; imageY++)
383 { 383 {
384 int rowOffset = imageY * coordsAcross; 384 int rowOffset = imageY * coordsAcross;
385 385
386 for (imageX = 0; imageX < coordsAcross; imageX++) 386 for (imageX = 0; imageX < coordsAcross; imageX++)
387 { 387 {
388 /* 388 /*
389 * p1-----p2 389 * p1-----p2
390 * | \ f2 | 390 * | \ f2 |
391 * | \ | 391 * | \ |
392 * | f1 \| 392 * | f1 \|
393 * p3-----p4 393 * p3-----p4
394 */ 394 */
395 395
396 p4 = rowOffset + imageX; 396 p4 = rowOffset + imageX;
397 p3 = p4 - 1; 397 p3 = p4 - 1;
398 398
399 p2 = p4 - coordsAcross; 399 p2 = p4 - coordsAcross;
400 p1 = p3 - coordsAcross; 400 p1 = p3 - coordsAcross;
401 401
402 this.coords.Add(rows[imageY][imageX]); 402 this.coords.Add(rows[imageY][imageX]);
403 if (viewerMode) 403 if (viewerMode)
404 { 404 {
405 this.normals.Add(new Coord()); 405 this.normals.Add(new Coord());
406 this.uvs.Add(new UVCoord(widthUnit * imageX, heightUnit * imageY)); 406 this.uvs.Add(new UVCoord(widthUnit * imageX, heightUnit * imageY));
407 } 407 }
408 408
409 if (imageY > 0 && imageX > 0) 409 if (imageY > 0 && imageX > 0)
410 { 410 {
411 Face f1, f2; 411 Face f1, f2;
412 412
413 if (viewerMode) 413 if (viewerMode)
414 { 414 {
415 if (invert) 415 if (invert)
416 { 416 {
417 f1 = new Face(p1, p4, p3, p1, p4, p3); 417 f1 = new Face(p1, p4, p3, p1, p4, p3);
418 f1.uv1 = p1; 418 f1.uv1 = p1;
419 f1.uv2 = p4; 419 f1.uv2 = p4;
420 f1.uv3 = p3; 420 f1.uv3 = p3;
421 421
422 f2 = new Face(p1, p2, p4, p1, p2, p4); 422 f2 = new Face(p1, p2, p4, p1, p2, p4);
423 f2.uv1 = p1; 423 f2.uv1 = p1;
424 f2.uv2 = p2; 424 f2.uv2 = p2;
425 f2.uv3 = p4; 425 f2.uv3 = p4;
426 } 426 }
427 else 427 else
428 { 428 {
429 f1 = new Face(p1, p3, p4, p1, p3, p4); 429 f1 = new Face(p1, p3, p4, p1, p3, p4);
430 f1.uv1 = p1; 430 f1.uv1 = p1;
431 f1.uv2 = p3; 431 f1.uv2 = p3;
432 f1.uv3 = p4; 432 f1.uv3 = p4;
433 433
434 f2 = new Face(p1, p4, p2, p1, p4, p2); 434 f2 = new Face(p1, p4, p2, p1, p4, p2);
435 f2.uv1 = p1; 435 f2.uv1 = p1;
436 f2.uv2 = p4; 436 f2.uv2 = p4;
437 f2.uv3 = p2; 437 f2.uv3 = p2;
438 } 438 }
439 } 439 }
440 else 440 else
441 { 441 {
442 if (invert) 442 if (invert)
443 { 443 {
444 f1 = new Face(p1, p4, p3); 444 f1 = new Face(p1, p4, p3);
445 f2 = new Face(p1, p2, p4); 445 f2 = new Face(p1, p2, p4);
446 } 446 }
447 else 447 else
448 { 448 {
449 f1 = new Face(p1, p3, p4); 449 f1 = new Face(p1, p3, p4);
450 f2 = new Face(p1, p4, p2); 450 f2 = new Face(p1, p4, p2);
451 } 451 }
452 } 452 }
453 453
454 this.faces.Add(f1); 454 this.faces.Add(f1);
455 this.faces.Add(f2); 455 this.faces.Add(f2);
456 } 456 }
457 } 457 }
458 } 458 }
459 459
460 if (viewerMode) 460 if (viewerMode)
461 calcVertexNormals(sculptType, coordsAcross, coordsDown); 461 calcVertexNormals(sculptType, coordsAcross, coordsDown);
462 } 462 }
463 463
464 /// <summary> 464 /// <summary>
465 /// Duplicates a SculptMesh object. All object properties are copied by value, including lists. 465 /// Duplicates a SculptMesh object. All object properties are copied by value, including lists.
466 /// </summary> 466 /// </summary>
467 /// <returns></returns> 467 /// <returns></returns>
468 public SculptMesh Copy() 468 public SculptMesh Copy()
469 { 469 {
470 return new SculptMesh(this); 470 return new SculptMesh(this);
471 } 471 }
472 472
473 public SculptMesh(SculptMesh sm) 473 public SculptMesh(SculptMesh sm)
474 { 474 {
475 coords = new List<Coord>(sm.coords); 475 coords = new List<Coord>(sm.coords);
476 faces = new List<Face>(sm.faces); 476 faces = new List<Face>(sm.faces);
477 viewerFaces = new List<ViewerFace>(sm.viewerFaces); 477 viewerFaces = new List<ViewerFace>(sm.viewerFaces);
478 normals = new List<Coord>(sm.normals); 478 normals = new List<Coord>(sm.normals);
479 uvs = new List<UVCoord>(sm.uvs); 479 uvs = new List<UVCoord>(sm.uvs);
480 } 480 }
481 481
482 private void calcVertexNormals(SculptType sculptType, int xSize, int ySize) 482 private void calcVertexNormals(SculptType sculptType, int xSize, int ySize)
483 { // compute vertex normals by summing all the surface normals of all the triangles sharing 483 { // compute vertex normals by summing all the surface normals of all the triangles sharing
484 // each vertex and then normalizing 484 // each vertex and then normalizing
485 int numFaces = this.faces.Count; 485 int numFaces = this.faces.Count;
486 for (int i = 0; i < numFaces; i++) 486 for (int i = 0; i < numFaces; i++)
487 { 487 {
488 Face face = this.faces[i]; 488 Face face = this.faces[i];
489 Coord surfaceNormal = face.SurfaceNormal(this.coords); 489 Coord surfaceNormal = face.SurfaceNormal(this.coords);
490 this.normals[face.n1] += surfaceNormal; 490 this.normals[face.n1] += surfaceNormal;
491 this.normals[face.n2] += surfaceNormal; 491 this.normals[face.n2] += surfaceNormal;
492 this.normals[face.n3] += surfaceNormal; 492 this.normals[face.n3] += surfaceNormal;
493 } 493 }
494 494
495 int numNormals = this.normals.Count; 495 int numNormals = this.normals.Count;
496 for (int i = 0; i < numNormals; i++) 496 for (int i = 0; i < numNormals; i++)
497 this.normals[i] = this.normals[i].Normalize(); 497 this.normals[i] = this.normals[i].Normalize();
498 498
499 if (sculptType != SculptType.plane) 499 if (sculptType != SculptType.plane)
500 { // blend the vertex normals at the cylinder seam 500 { // blend the vertex normals at the cylinder seam
501 for (int y = 0; y < ySize; y++) 501 for (int y = 0; y < ySize; y++)
502 { 502 {
503 int rowOffset = y * xSize; 503 int rowOffset = y * xSize;
504 504
505 this.normals[rowOffset] = this.normals[rowOffset + xSize - 1] = (this.normals[rowOffset] + this.normals[rowOffset + xSize - 1]).Normalize(); 505 this.normals[rowOffset] = this.normals[rowOffset + xSize - 1] = (this.normals[rowOffset] + this.normals[rowOffset + xSize - 1]).Normalize();
506 } 506 }
507 } 507 }
508 508
509 foreach (Face face in this.faces) 509 foreach (Face face in this.faces)
510 { 510 {
511 ViewerFace vf = new ViewerFace(0); 511 ViewerFace vf = new ViewerFace(0);
512 vf.v1 = this.coords[face.v1]; 512 vf.v1 = this.coords[face.v1];
513 vf.v2 = this.coords[face.v2]; 513 vf.v2 = this.coords[face.v2];
514 vf.v3 = this.coords[face.v3]; 514 vf.v3 = this.coords[face.v3];
515 515
516 vf.coordIndex1 = face.v1; 516 vf.coordIndex1 = face.v1;
517 vf.coordIndex2 = face.v2; 517 vf.coordIndex2 = face.v2;
518 vf.coordIndex3 = face.v3; 518 vf.coordIndex3 = face.v3;
519 519
520 vf.n1 = this.normals[face.n1]; 520 vf.n1 = this.normals[face.n1];
521 vf.n2 = this.normals[face.n2]; 521 vf.n2 = this.normals[face.n2];
522 vf.n3 = this.normals[face.n3]; 522 vf.n3 = this.normals[face.n3];
523 523
524 vf.uv1 = this.uvs[face.uv1]; 524 vf.uv1 = this.uvs[face.uv1];
525 vf.uv2 = this.uvs[face.uv2]; 525 vf.uv2 = this.uvs[face.uv2];
526 vf.uv3 = this.uvs[face.uv3]; 526 vf.uv3 = this.uvs[face.uv3];
527 527
528 this.viewerFaces.Add(vf); 528 this.viewerFaces.Add(vf);
529 } 529 }
530 } 530 }
531 531
532 /// <summary> 532 /// <summary>
533 /// Adds a value to each XYZ vertex coordinate in the mesh 533 /// Adds a value to each XYZ vertex coordinate in the mesh
534 /// </summary> 534 /// </summary>
535 /// <param name="x"></param> 535 /// <param name="x"></param>
536 /// <param name="y"></param> 536 /// <param name="y"></param>
537 /// <param name="z"></param> 537 /// <param name="z"></param>
538 public void AddPos(float x, float y, float z) 538 public void AddPos(float x, float y, float z)
539 { 539 {
540 int i; 540 int i;
541 int numVerts = this.coords.Count; 541 int numVerts = this.coords.Count;
542 Coord vert; 542 Coord vert;
543 543
544 for (i = 0; i < numVerts; i++) 544 for (i = 0; i < numVerts; i++)
545 { 545 {
546 vert = this.coords[i]; 546 vert = this.coords[i];
547 vert.X += x; 547 vert.X += x;
548 vert.Y += y; 548 vert.Y += y;
549 vert.Z += z; 549 vert.Z += z;
550 this.coords[i] = vert; 550 this.coords[i] = vert;
551 } 551 }
552 552
553 if (this.viewerFaces != null) 553 if (this.viewerFaces != null)
554 { 554 {
555 int numViewerFaces = this.viewerFaces.Count; 555 int numViewerFaces = this.viewerFaces.Count;
556 556
557 for (i = 0; i < numViewerFaces; i++) 557 for (i = 0; i < numViewerFaces; i++)
558 { 558 {
559 ViewerFace v = this.viewerFaces[i]; 559 ViewerFace v = this.viewerFaces[i];
560 v.AddPos(x, y, z); 560 v.AddPos(x, y, z);
561 this.viewerFaces[i] = v; 561 this.viewerFaces[i] = v;
562 } 562 }
563 } 563 }
564 } 564 }
565 565
566 /// <summary> 566 /// <summary>
567 /// Rotates the mesh 567 /// Rotates the mesh
568 /// </summary> 568 /// </summary>
569 /// <param name="q"></param> 569 /// <param name="q"></param>
570 public void AddRot(Quat q) 570 public void AddRot(Quat q)
571 { 571 {
572 int i; 572 int i;
573 int numVerts = this.coords.Count; 573 int numVerts = this.coords.Count;
574 574
575 for (i = 0; i < numVerts; i++) 575 for (i = 0; i < numVerts; i++)
576 this.coords[i] *= q; 576 this.coords[i] *= q;
577 577
578 int numNormals = this.normals.Count; 578 int numNormals = this.normals.Count;
579 for (i = 0; i < numNormals; i++) 579 for (i = 0; i < numNormals; i++)
580 this.normals[i] *= q; 580 this.normals[i] *= q;
581 581
582 if (this.viewerFaces != null) 582 if (this.viewerFaces != null)
583 { 583 {
584 int numViewerFaces = this.viewerFaces.Count; 584 int numViewerFaces = this.viewerFaces.Count;
585 585
586 for (i = 0; i < numViewerFaces; i++) 586 for (i = 0; i < numViewerFaces; i++)
587 { 587 {
588 ViewerFace v = this.viewerFaces[i]; 588 ViewerFace v = this.viewerFaces[i];
589 v.v1 *= q; 589 v.v1 *= q;
590 v.v2 *= q; 590 v.v2 *= q;
591 v.v3 *= q; 591 v.v3 *= q;
592 592
593 v.n1 *= q; 593 v.n1 *= q;
594 v.n2 *= q; 594 v.n2 *= q;
595 v.n3 *= q; 595 v.n3 *= q;
596 596
597 this.viewerFaces[i] = v; 597 this.viewerFaces[i] = v;
598 } 598 }
599 } 599 }
600 } 600 }
601 601
602 public void Scale(float x, float y, float z) 602 public void Scale(float x, float y, float z)
603 { 603 {
604 int i; 604 int i;
605 int numVerts = this.coords.Count; 605 int numVerts = this.coords.Count;
606 606
607 Coord m = new Coord(x, y, z); 607 Coord m = new Coord(x, y, z);
608 for (i = 0; i < numVerts; i++) 608 for (i = 0; i < numVerts; i++)
609 this.coords[i] *= m; 609 this.coords[i] *= m;
610 610
611 if (this.viewerFaces != null) 611 if (this.viewerFaces != null)
612 { 612 {
613 int numViewerFaces = this.viewerFaces.Count; 613 int numViewerFaces = this.viewerFaces.Count;
614 for (i = 0; i < numViewerFaces; i++) 614 for (i = 0; i < numViewerFaces; i++)
615 { 615 {
616 ViewerFace v = this.viewerFaces[i]; 616 ViewerFace v = this.viewerFaces[i];
617 v.v1 *= m; 617 v.v1 *= m;
618 v.v2 *= m; 618 v.v2 *= m;
619 v.v3 *= m; 619 v.v3 *= m;
620 this.viewerFaces[i] = v; 620 this.viewerFaces[i] = v;
621 } 621 }
622 } 622 }
623 } 623 }
624 624
625 public void DumpRaw(String path, String name, String title) 625 public void DumpRaw(String path, String name, String title)
626 { 626 {
627 if (path == null) 627 if (path == null)
628 return; 628 return;
629 String fileName = name + "_" + title + ".raw"; 629 String fileName = name + "_" + title + ".raw";
630 String completePath = System.IO.Path.Combine(path, fileName); 630 String completePath = System.IO.Path.Combine(path, fileName);
631 StreamWriter sw = new StreamWriter(completePath); 631 StreamWriter sw = new StreamWriter(completePath);
632 632
633 for (int i = 0; i < this.faces.Count; i++) 633 for (int i = 0; i < this.faces.Count; i++)
634 { 634 {
635 string s = this.coords[this.faces[i].v1].ToString(); 635 string s = this.coords[this.faces[i].v1].ToString();
636 s += " " + this.coords[this.faces[i].v2].ToString(); 636 s += " " + this.coords[this.faces[i].v2].ToString();
637 s += " " + this.coords[this.faces[i].v3].ToString(); 637 s += " " + this.coords[this.faces[i].v3].ToString();
638 638
639 sw.WriteLine(s); 639 sw.WriteLine(s);
640 } 640 }
641 641
642 sw.Close(); 642 sw.Close();
643 } 643 }
644 } 644 }
645} 645}
diff --git a/OpenSim/Region/UserStatistics/ActiveConnectionsAJAX.cs b/OpenSim/Region/UserStatistics/ActiveConnectionsAJAX.cs
index 704b74f..a567413 100644
--- a/OpenSim/Region/UserStatistics/ActiveConnectionsAJAX.cs
+++ b/OpenSim/Region/UserStatistics/ActiveConnectionsAJAX.cs
@@ -68,7 +68,7 @@ namespace OpenSim.Region.UserStatistics
68 HTMLUtil.OL_O(ref output, ""); 68 HTMLUtil.OL_O(ref output, "");
69 foreach (Scene scene in all_scenes) 69 foreach (Scene scene in all_scenes)
70 { 70 {
71 ScenePresence[] avatarInScene = scene.GetScenePresences(); 71 List<ScenePresence> avatarInScene = scene.GetScenePresences();
72 72
73 HTMLUtil.LI_O(ref output, String.Empty); 73 HTMLUtil.LI_O(ref output, String.Empty);
74 output.Append(scene.RegionInfo.RegionName); 74 output.Append(scene.RegionInfo.RegionName);