aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim')
-rw-r--r--OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs2
-rw-r--r--OpenSim/Data/IGridUserData.cs9
-rw-r--r--OpenSim/Data/IPresenceData.cs4
-rw-r--r--OpenSim/Data/MSSQL/MSSQLGridUserData.cs8
-rw-r--r--OpenSim/Data/MSSQL/MSSQLPresenceData.cs72
-rw-r--r--OpenSim/Data/MySQL/MySQLGridUserData.cs9
-rw-r--r--OpenSim/Data/MySQL/MySQLPresenceData.cs66
-rw-r--r--OpenSim/Data/MySQL/Resources/001_Presence.sql10
-rw-r--r--OpenSim/Data/MySQL/Resources/002_Presence.sql7
-rw-r--r--OpenSim/Data/MySQL/Resources/003_Presence.sql6
-rw-r--r--OpenSim/Data/Null/NullPresenceData.cs62
-rw-r--r--OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs9
-rw-r--r--OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs9
-rw-r--r--OpenSim/Region/CoreModules/Resources/CoreModulePlugin.addin.xml4
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/GridUser/LocalGridUserServiceConnector.cs69
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/LocalPresenceServiceConnector.cs13
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/PresenceDetector.cs12
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/RemotePresenceServiceConnector.cs13
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/Tests/PresenceConnectorsTests.cs8
-rw-r--r--OpenSim/Region/Framework/Scenes/Scene.cs21
-rw-r--r--OpenSim/Region/Physics/Meshing/PrimMesher.cs4568
-rw-r--r--OpenSim/Region/Physics/Meshing/SculptMap.cs352
-rw-r--r--OpenSim/Region/Physics/Meshing/SculptMesh.cs1282
-rw-r--r--OpenSim/Server/Handlers/Presence/PresenceServerPostHandler.cs45
-rw-r--r--OpenSim/Services/Connectors/GridUser/GridUserServiceConnector.cs196
-rw-r--r--OpenSim/Services/Connectors/Presence/PresenceServiceConnector.cs54
-rw-r--r--OpenSim/Services/Connectors/SimianGrid/SimianPresenceServiceConnector.cs88
-rw-r--r--OpenSim/Services/HypergridService/UserAgentService.cs21
-rw-r--r--OpenSim/Services/Interfaces/IGridUserService.cs42
-rw-r--r--OpenSim/Services/Interfaces/IPresenceService.cs24
-rw-r--r--OpenSim/Services/LLLoginService/LLLoginResponse.cs4
-rw-r--r--OpenSim/Services/LLLoginService/LLLoginService.cs63
-rw-r--r--OpenSim/Services/PresenceService/PresenceService.cs79
-rw-r--r--OpenSim/Services/UserAccountService/GridUserService.cs95
-rw-r--r--OpenSim/Services/UserAccountService/UserAccountService.cs10
-rw-r--r--OpenSim/Tests/Clients/Presence/PresenceClient.cs19
36 files changed, 3700 insertions, 3655 deletions
diff --git a/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs b/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs
index 5a23c90..13f9c9f 100644
--- a/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs
+++ b/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs
@@ -1611,7 +1611,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController
1611 GridRegion home = m_app.SceneManager.CurrentOrFirstScene.GridService.GetRegionByPosition(scopeID, 1611 GridRegion home = m_app.SceneManager.CurrentOrFirstScene.GridService.GetRegionByPosition(scopeID,
1612 (int)(regX * Constants.RegionSize), (int)(regY * Constants.RegionSize)); 1612 (int)(regX * Constants.RegionSize), (int)(regY * Constants.RegionSize));
1613 if (home != null) 1613 if (home != null)
1614 m_app.SceneManager.CurrentOrFirstScene.PresenceService.SetHomeLocation(account.PrincipalID.ToString(), home.RegionID, new Vector3(128, 128, 0), new Vector3(0, 1, 0)); 1614 m_app.SceneManager.CurrentOrFirstScene.GridUserService.SetHome(account.PrincipalID.ToString(), home.RegionID, new Vector3(128, 128, 0), new Vector3(0, 1, 0));
1615 } 1615 }
1616 else 1616 else
1617 { 1617 {
diff --git a/OpenSim/Data/IGridUserData.cs b/OpenSim/Data/IGridUserData.cs
index bd7a435..e15a1f8 100644
--- a/OpenSim/Data/IGridUserData.cs
+++ b/OpenSim/Data/IGridUserData.cs
@@ -37,6 +37,11 @@ namespace OpenSim.Data
37 { 37 {
38 public string UserID; 38 public string UserID;
39 public Dictionary<string, string> Data; 39 public Dictionary<string, string> Data;
40
41 public GridUserData()
42 {
43 Data = new Dictionary<string, string>();
44 }
40 } 45 }
41 46
42 /// <summary> 47 /// <summary>
@@ -44,7 +49,7 @@ namespace OpenSim.Data
44 /// </summary> 49 /// </summary>
45 public interface IGridUserData 50 public interface IGridUserData
46 { 51 {
47 GridUserData GetGridUserData(string userID); 52 GridUserData Get(string userID);
48 bool StoreGridUserData(GridUserData data); 53 bool Store(GridUserData data);
49 } 54 }
50} \ No newline at end of file 55} \ No newline at end of file
diff --git a/OpenSim/Data/IPresenceData.cs b/OpenSim/Data/IPresenceData.cs
index 71d0e31..b871f56 100644
--- a/OpenSim/Data/IPresenceData.cs
+++ b/OpenSim/Data/IPresenceData.cs
@@ -50,10 +50,8 @@ namespace OpenSim.Data
50 50
51 PresenceData Get(UUID sessionID); 51 PresenceData Get(UUID sessionID);
52 void LogoutRegionAgents(UUID regionID); 52 void LogoutRegionAgents(UUID regionID);
53 bool ReportAgent(UUID sessionID, UUID regionID, string position, string lookAt); 53 bool ReportAgent(UUID sessionID, UUID regionID);
54 bool SetHomeLocation(string userID, UUID regionID, Vector3 position, Vector3 lookAt);
55 PresenceData[] Get(string field, string data); 54 PresenceData[] Get(string field, string data);
56 void Prune(string userID);
57 bool Delete(string field, string val); 55 bool Delete(string field, string val);
58 } 56 }
59} 57}
diff --git a/OpenSim/Data/MSSQL/MSSQLGridUserData.cs b/OpenSim/Data/MSSQL/MSSQLGridUserData.cs
index 9993720..1870273 100644
--- a/OpenSim/Data/MSSQL/MSSQLGridUserData.cs
+++ b/OpenSim/Data/MSSQL/MSSQLGridUserData.cs
@@ -46,11 +46,11 @@ namespace OpenSim.Data.MSSQL
46 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 46 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
47 47
48 public MSSQLGridUserData(string connectionString, string realm) : 48 public MSSQLGridUserData(string connectionString, string realm) :
49 base(connectionString, realm, "UserGrid") 49 base(connectionString, realm, "GridUserStore")
50 { 50 {
51 } 51 }
52 52
53 public GridUserData GetGridUserData(string userID) 53 public GridUserData Get(string userID)
54 { 54 {
55 GridUserData[] ret = Get("UserID", userID); 55 GridUserData[] ret = Get("UserID", userID);
56 56
@@ -60,9 +60,5 @@ namespace OpenSim.Data.MSSQL
60 return ret[0]; 60 return ret[0];
61 } 61 }
62 62
63 public bool StoreGridUserData(GridUserData data)
64 {
65 return Store(data);
66 }
67 } 63 }
68} 64}
diff --git a/OpenSim/Data/MSSQL/MSSQLPresenceData.cs b/OpenSim/Data/MSSQL/MSSQLPresenceData.cs
index 5a4ad3a..e7b3d9c 100644
--- a/OpenSim/Data/MSSQL/MSSQLPresenceData.cs
+++ b/OpenSim/Data/MSSQL/MSSQLPresenceData.cs
@@ -67,7 +67,7 @@ namespace OpenSim.Data.MSSQL
67 using (SqlCommand cmd = new SqlCommand()) 67 using (SqlCommand cmd = new SqlCommand())
68 { 68 {
69 69
70 cmd.CommandText = String.Format("UPDATE {0} SET Online='false' WHERE [RegionID]=@RegionID", m_Realm); 70 cmd.CommandText = String.Format("DELETE FROM {0} WHERE [RegionID]=@RegionID", m_Realm);
71 71
72 cmd.Parameters.Add(m_database.CreateParameter("@RegionID", regionID.ToString())); 72 cmd.Parameters.Add(m_database.CreateParameter("@RegionID", regionID.ToString()));
73 cmd.Connection = conn; 73 cmd.Connection = conn;
@@ -76,8 +76,7 @@ namespace OpenSim.Data.MSSQL
76 } 76 }
77 } 77 }
78 78
79 public bool ReportAgent(UUID sessionID, UUID regionID, string position, 79 public bool ReportAgent(UUID sessionID, UUID regionID)
80 string lookAt)
81 { 80 {
82 PresenceData[] pd = Get("SessionID", sessionID.ToString()); 81 PresenceData[] pd = Get("SessionID", sessionID.ToString());
83 if (pd.Length == 0) 82 if (pd.Length == 0)
@@ -88,16 +87,11 @@ namespace OpenSim.Data.MSSQL
88 { 87 {
89 88
90 cmd.CommandText = String.Format(@"UPDATE {0} SET 89 cmd.CommandText = String.Format(@"UPDATE {0} SET
91 [RegionID] = @RegionID, 90 [RegionID] = @RegionID
92 [Position] = @Position,
93 [LookAt] = @LookAt,
94 [Online] = 'true'
95 WHERE [SessionID] = @SessionID", m_Realm); 91 WHERE [SessionID] = @SessionID", m_Realm);
96 92
97 cmd.Parameters.Add(m_database.CreateParameter("@SessionID", sessionID.ToString())); 93 cmd.Parameters.Add(m_database.CreateParameter("@SessionID", sessionID.ToString()));
98 cmd.Parameters.Add(m_database.CreateParameter("@RegionID", regionID.ToString())); 94 cmd.Parameters.Add(m_database.CreateParameter("@RegionID", regionID.ToString()));
99 cmd.Parameters.Add(m_database.CreateParameter("@Position", position.ToString()));
100 cmd.Parameters.Add(m_database.CreateParameter("@LookAt", lookAt.ToString()));
101 cmd.Connection = conn; 95 cmd.Connection = conn;
102 conn.Open(); 96 conn.Open();
103 if (cmd.ExecuteNonQuery() == 0) 97 if (cmd.ExecuteNonQuery() == 0)
@@ -106,65 +100,5 @@ namespace OpenSim.Data.MSSQL
106 return true; 100 return true;
107 } 101 }
108 102
109 public bool SetHomeLocation(string userID, UUID regionID, Vector3 position, Vector3 lookAt)
110 {
111 PresenceData[] pd = Get("UserID", userID);
112 if (pd.Length == 0)
113 return false;
114
115 using (SqlConnection conn = new SqlConnection(m_ConnectionString))
116 using (SqlCommand cmd = new SqlCommand())
117 {
118
119 cmd.CommandText = String.Format(@"UPDATE {0} SET
120 [HomeRegionID] = @HomeRegionID,
121 [HomePosition] = @HomePosition,
122 [HomeLookAt] = @HomeLookAt
123 WHERE [UserID] = @UserID", m_Realm);
124
125 cmd.Parameters.Add(m_database.CreateParameter("@UserID", userID));
126 cmd.Parameters.Add(m_database.CreateParameter("@HomeRegionID", regionID.ToString()));
127 cmd.Parameters.Add(m_database.CreateParameter("@HomePosition", position));
128 cmd.Parameters.Add(m_database.CreateParameter("@HomeLookAt", lookAt));
129 cmd.Connection = conn;
130 conn.Open();
131 if (cmd.ExecuteNonQuery() == 0)
132 return false;
133 }
134 return true;
135 }
136
137 public void Prune(string userID)
138 {
139 using (SqlConnection conn = new SqlConnection(m_ConnectionString))
140 using (SqlCommand cmd = new SqlCommand())
141 {
142 cmd.CommandText = String.Format("SELECT * from {0} WHERE [UserID] = @UserID", m_Realm);
143
144 cmd.Parameters.Add(m_database.CreateParameter("@UserID", userID));
145 cmd.Connection = conn;
146 conn.Open();
147
148 using (SqlDataReader reader = cmd.ExecuteReader())
149 {
150 List<UUID> deleteSessions = new List<UUID>();
151 int online = 0;
152
153 while (reader.Read())
154 {
155 if (bool.Parse(reader["Online"].ToString()))
156 online++;
157 else
158 deleteSessions.Add(new UUID(reader["SessionID"].ToString()));
159 }
160
161 if (online == 0 && deleteSessions.Count > 0)
162 deleteSessions.RemoveAt(0);
163
164 foreach (UUID s in deleteSessions)
165 Delete("SessionID", s.ToString());
166 }
167 }
168 }
169 } 103 }
170} 104}
diff --git a/OpenSim/Data/MySQL/MySQLGridUserData.cs b/OpenSim/Data/MySQL/MySQLGridUserData.cs
index df29ecd..a9ce94d 100644
--- a/OpenSim/Data/MySQL/MySQLGridUserData.cs
+++ b/OpenSim/Data/MySQL/MySQLGridUserData.cs
@@ -44,9 +44,9 @@ namespace OpenSim.Data.MySQL
44 { 44 {
45// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 45// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
46 46
47 public MySQLGridUserData(string connectionString, string realm) : base(connectionString, realm, "UserGrid") {} 47 public MySQLGridUserData(string connectionString, string realm) : base(connectionString, realm, "GridUserStore") {}
48 48
49 public GridUserData GetGridUserData(string userID) 49 public GridUserData Get(string userID)
50 { 50 {
51 GridUserData[] ret = Get("UserID", userID); 51 GridUserData[] ret = Get("UserID", userID);
52 52
@@ -56,9 +56,6 @@ namespace OpenSim.Data.MySQL
56 return ret[0]; 56 return ret[0];
57 } 57 }
58 58
59 public bool StoreGridUserData(GridUserData data) 59
60 {
61 return Store(data);
62 }
63 } 60 }
64} \ No newline at end of file 61} \ No newline at end of file
diff --git a/OpenSim/Data/MySQL/MySQLPresenceData.cs b/OpenSim/Data/MySQL/MySQLPresenceData.cs
index 143dbe3..71caa1a 100644
--- a/OpenSim/Data/MySQL/MySQLPresenceData.cs
+++ b/OpenSim/Data/MySQL/MySQLPresenceData.cs
@@ -65,15 +65,14 @@ namespace OpenSim.Data.MySQL
65 { 65 {
66 MySqlCommand cmd = new MySqlCommand(); 66 MySqlCommand cmd = new MySqlCommand();
67 67
68 cmd.CommandText = String.Format("update {0} set Online='false' where `RegionID`=?RegionID", m_Realm); 68 cmd.CommandText = String.Format("delete from {0} where `RegionID`=?RegionID", m_Realm);
69 69
70 cmd.Parameters.AddWithValue("?RegionID", regionID.ToString()); 70 cmd.Parameters.AddWithValue("?RegionID", regionID.ToString());
71 71
72 ExecuteNonQuery(cmd); 72 ExecuteNonQuery(cmd);
73 } 73 }
74 74
75 public bool ReportAgent(UUID sessionID, UUID regionID, string position, 75 public bool ReportAgent(UUID sessionID, UUID regionID)
76 string lookAt)
77 { 76 {
78 PresenceData[] pd = Get("SessionID", sessionID.ToString()); 77 PresenceData[] pd = Get("SessionID", sessionID.ToString());
79 if (pd.Length == 0) 78 if (pd.Length == 0)
@@ -81,12 +80,10 @@ namespace OpenSim.Data.MySQL
81 80
82 MySqlCommand cmd = new MySqlCommand(); 81 MySqlCommand cmd = new MySqlCommand();
83 82
84 cmd.CommandText = String.Format("update {0} set RegionID=?RegionID, Position=?Position, LookAt=?LookAt, Online='true' where `SessionID`=?SessionID", m_Realm); 83 cmd.CommandText = String.Format("update {0} set RegionID=?RegionID where `SessionID`=?SessionID", m_Realm);
85 84
86 cmd.Parameters.AddWithValue("?SessionID", sessionID.ToString()); 85 cmd.Parameters.AddWithValue("?SessionID", sessionID.ToString());
87 cmd.Parameters.AddWithValue("?RegionID", regionID.ToString()); 86 cmd.Parameters.AddWithValue("?RegionID", regionID.ToString());
88 cmd.Parameters.AddWithValue("?Position", position.ToString());
89 cmd.Parameters.AddWithValue("?LookAt", lookAt.ToString());
90 87
91 if (ExecuteNonQuery(cmd) == 0) 88 if (ExecuteNonQuery(cmd) == 0)
92 return false; 89 return false;
@@ -94,62 +91,5 @@ namespace OpenSim.Data.MySQL
94 return true; 91 return true;
95 } 92 }
96 93
97 public bool SetHomeLocation(string userID, UUID regionID, Vector3 position, Vector3 lookAt)
98 {
99 PresenceData[] pd = Get("UserID", userID);
100 if (pd.Length == 0)
101 return false;
102
103 MySqlCommand cmd = new MySqlCommand();
104
105 cmd.CommandText = String.Format("update {0} set HomeRegionID=?HomeRegionID, HomePosition=?HomePosition, HomeLookAt=?HomeLookAt where UserID=?UserID", m_Realm);
106
107 cmd.Parameters.AddWithValue("?UserID", userID);
108 cmd.Parameters.AddWithValue("?HomeRegionID", regionID.ToString());
109 cmd.Parameters.AddWithValue("?HomePosition", position);
110 cmd.Parameters.AddWithValue("?HomeLookAt", lookAt);
111
112 if (ExecuteNonQuery(cmd) == 0)
113 return false;
114
115 return true;
116 }
117
118 public void Prune(string userID)
119 {
120 MySqlCommand cmd = new MySqlCommand();
121
122 cmd.CommandText = String.Format("select * from {0} where UserID=?UserID", m_Realm);
123
124 cmd.Parameters.AddWithValue("?UserID", userID);
125
126 using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
127 {
128 dbcon.Open();
129
130 cmd.Connection = dbcon;
131
132 using (IDataReader reader = cmd.ExecuteReader())
133 {
134 List<UUID> deleteSessions = new List<UUID>();
135 int online = 0;
136
137 while (reader.Read())
138 {
139 if (bool.Parse(reader["Online"].ToString()))
140 online++;
141 else
142 deleteSessions.Add(new UUID(reader["SessionID"].ToString()));
143 }
144
145 // Leave one session behind so that we can pick up details such as home location
146 if (online == 0 && deleteSessions.Count > 0)
147 deleteSessions.RemoveAt(0);
148
149 foreach (UUID s in deleteSessions)
150 Delete("SessionID", s.ToString());
151 }
152 }
153 }
154 } 94 }
155} 95}
diff --git a/OpenSim/Data/MySQL/Resources/001_Presence.sql b/OpenSim/Data/MySQL/Resources/001_Presence.sql
index b8abaf7..84fa057 100644
--- a/OpenSim/Data/MySQL/Resources/001_Presence.sql
+++ b/OpenSim/Data/MySQL/Resources/001_Presence.sql
@@ -4,12 +4,10 @@ CREATE TABLE `Presence` (
4 `UserID` VARCHAR(255) NOT NULL, 4 `UserID` VARCHAR(255) NOT NULL,
5 `RegionID` CHAR(36) NOT NULL, 5 `RegionID` CHAR(36) NOT NULL,
6 `SessionID` CHAR(36) NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000', 6 `SessionID` CHAR(36) NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000',
7 `SecureSessionID` CHAR(36) NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000', 7 `SecureSessionID` CHAR(36) NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000'
8 `Online` CHAR(5) NOT NULL DEFAULT 'false',
9 `Login` CHAR(16) NOT NULL DEFAULT '0',
10 `Logout` CHAR(16) NOT NULL DEFAULT '0',
11 `Position` CHAR(64) NOT NULL DEFAULT '<0,0,0>',
12 `LookAt` CHAR(64) NOT NULL DEFAULT '<0,0,0>'
13) ENGINE=InnoDB; 8) ENGINE=InnoDB;
14 9
10CREATE UNIQUE INDEX SessionID ON Presence(SessionID);
11CREATE INDEX UserID ON Presence(UserID);
12
15COMMIT; 13COMMIT;
diff --git a/OpenSim/Data/MySQL/Resources/002_Presence.sql b/OpenSim/Data/MySQL/Resources/002_Presence.sql
deleted file mode 100644
index e65f105..0000000
--- a/OpenSim/Data/MySQL/Resources/002_Presence.sql
+++ /dev/null
@@ -1,7 +0,0 @@
1BEGIN;
2
3ALTER TABLE Presence ADD COLUMN `HomeRegionID` CHAR(36) NOT NULL;
4ALTER TABLE Presence ADD COLUMN `HomePosition` CHAR(64) NOT NULL DEFAULT '<0,0,0>';
5ALTER TABLE Presence ADD COLUMN `HomeLookAt` CHAR(64) NOT NULL DEFAULT '<0,0,0>';
6
7COMMIT;
diff --git a/OpenSim/Data/MySQL/Resources/003_Presence.sql b/OpenSim/Data/MySQL/Resources/003_Presence.sql
deleted file mode 100644
index 0efefa8..0000000
--- a/OpenSim/Data/MySQL/Resources/003_Presence.sql
+++ /dev/null
@@ -1,6 +0,0 @@
1BEGIN;
2
3CREATE UNIQUE INDEX SessionID ON Presence(SessionID);
4CREATE INDEX UserID ON Presence(UserID);
5
6COMMIT;
diff --git a/OpenSim/Data/Null/NullPresenceData.cs b/OpenSim/Data/Null/NullPresenceData.cs
index b98b5c9..91f1cc5 100644
--- a/OpenSim/Data/Null/NullPresenceData.cs
+++ b/OpenSim/Data/Null/NullPresenceData.cs
@@ -96,45 +96,20 @@ namespace OpenSim.Data.Null
96 m_presenceData.Remove(u); 96 m_presenceData.Remove(u);
97 } 97 }
98 98
99 public bool ReportAgent(UUID sessionID, UUID regionID, string position, string lookAt) 99 public bool ReportAgent(UUID sessionID, UUID regionID)
100 { 100 {
101 if (Instance != this) 101 if (Instance != this)
102 return Instance.ReportAgent(sessionID, regionID, position, lookAt); 102 return Instance.ReportAgent(sessionID, regionID);
103 103
104 if (m_presenceData.ContainsKey(sessionID)) 104 if (m_presenceData.ContainsKey(sessionID))
105 { 105 {
106 m_presenceData[sessionID].RegionID = regionID; 106 m_presenceData[sessionID].RegionID = regionID;
107 m_presenceData[sessionID].Data["Position"] = position;
108 m_presenceData[sessionID].Data["LookAt"] = lookAt;
109 return true; 107 return true;
110 } 108 }
111 109
112 return false; 110 return false;
113 } 111 }
114 112
115 public bool SetHomeLocation(string userID, UUID regionID, Vector3 position, Vector3 lookAt)
116 {
117 if (Instance != this)
118 return Instance.SetHomeLocation(userID, regionID, position, lookAt);
119
120 bool foundone = false;
121 foreach (PresenceData p in m_presenceData.Values)
122 {
123 if (p.UserID == userID)
124 {
125// m_log.DebugFormat(
126// "[NULL PRESENCE DATA]: Setting home location {0} {1} {2} for {3}",
127// regionID, position, lookAt, p.UserID);
128
129 p.Data["HomeRegionID"] = regionID.ToString();
130 p.Data["HomePosition"] = position.ToString();
131 p.Data["HomeLookAt"] = lookAt.ToString();
132 foundone = true;
133 }
134 }
135
136 return foundone;
137 }
138 113
139 public PresenceData[] Get(string field, string data) 114 public PresenceData[] Get(string field, string data)
140 { 115 {
@@ -193,39 +168,6 @@ namespace OpenSim.Data.Null
193 return presences.ToArray(); 168 return presences.ToArray();
194 } 169 }
195 170
196 public void Prune(string userID)
197 {
198 if (Instance != this)
199 {
200 Instance.Prune(userID);
201 return;
202 }
203
204// m_log.DebugFormat("[NULL PRESENCE DATA]: Prune called for {0}", userID);
205
206 List<UUID> deleteSessions = new List<UUID>();
207 int online = 0;
208
209 foreach (KeyValuePair<UUID, PresenceData> kvp in m_presenceData)
210 {
211// m_log.DebugFormat("Online: {0}", kvp.Value.Data["Online"]);
212
213 bool on = false;
214 if (bool.TryParse(kvp.Value.Data["Online"], out on) && on)
215 online++;
216 else
217 deleteSessions.Add(kvp.Key);
218 }
219
220// m_log.DebugFormat("[NULL PRESENCE DATA]: online [{0}], deleteSession.Count [{1}]", online, deleteSessions.Count);
221
222 // Leave one session behind so that we can pick up details such as home location
223 if (online == 0 && deleteSessions.Count > 0)
224 deleteSessions.RemoveAt(0);
225
226 foreach (UUID s in deleteSessions)
227 m_presenceData.Remove(s);
228 }
229 171
230 public bool Delete(string field, string data) 172 public bool Delete(string field, string data)
231 { 173 {
diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs
index f2b03e4..ef37f63 100644
--- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs
@@ -526,11 +526,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
526 { 526 {
527 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Request to teleport {0} {1} home", client.FirstName, client.LastName); 527 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Request to teleport {0} {1} home", client.FirstName, client.LastName);
528 528
529 OpenSim.Services.Interfaces.PresenceInfo pinfo = m_aScene.PresenceService.GetAgent(client.SessionId); 529 //OpenSim.Services.Interfaces.PresenceInfo pinfo = m_aScene.PresenceService.GetAgent(client.SessionId);
530 GridUserInfo uinfo = m_aScene.GridUserService.GetGridUserInfo(client.AgentId.ToString());
530 531
531 if (pinfo != null) 532 if (uinfo != null)
532 { 533 {
533 GridRegion regionInfo = m_aScene.GridService.GetRegionByUUID(UUID.Zero, pinfo.HomeRegionID); 534 GridRegion regionInfo = m_aScene.GridService.GetRegionByUUID(UUID.Zero, uinfo.HomeRegionID);
534 if (regionInfo == null) 535 if (regionInfo == null)
535 { 536 {
536 // can't find the Home region: Tell viewer and abort 537 // can't find the Home region: Tell viewer and abort
@@ -539,7 +540,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
539 } 540 }
540 // a little eekie that this goes back to Scene and with a forced cast, will fix that at some point... 541 // a little eekie that this goes back to Scene and with a forced cast, will fix that at some point...
541 ((Scene)(client.Scene)).RequestTeleportLocation( 542 ((Scene)(client.Scene)).RequestTeleportLocation(
542 client, regionInfo.RegionHandle, pinfo.HomePosition, pinfo.HomeLookAt, 543 client, regionInfo.RegionHandle, uinfo.HomePosition, uinfo.HomeLookAt,
543 (uint)(Constants.TeleportFlags.SetLastToTarget | Constants.TeleportFlags.ViaHome)); 544 (uint)(Constants.TeleportFlags.SetLastToTarget | Constants.TeleportFlags.ViaHome));
544 } 545 }
545 } 546 }
diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs
index 28593fc..137dfec 100644
--- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs
@@ -154,7 +154,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
154 bool success = connector.LoginAgentToGrid(agentCircuit, reg, finalDestination, out reason); 154 bool success = connector.LoginAgentToGrid(agentCircuit, reg, finalDestination, out reason);
155 if (success) 155 if (success)
156 // Log them out of this grid 156 // Log them out of this grid
157 m_aScene.PresenceService.LogoutAgent(agentCircuit.SessionID, sp.AbsolutePosition, sp.Lookat); 157 m_aScene.PresenceService.LogoutAgent(agentCircuit.SessionID);
158 158
159 return success; 159 return success;
160 } 160 }
@@ -238,6 +238,13 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
238 { 238 {
239 if (obj.IsLoggingOut) 239 if (obj.IsLoggingOut)
240 { 240 {
241 object sp = null;
242 if (obj.Scene.TryGetScenePresence(obj.AgentId, out sp))
243 {
244 if (((ScenePresence)sp).IsChildAgent)
245 return;
246 }
247
241 AgentCircuitData aCircuit = ((Scene)(obj.Scene)).AuthenticateHandler.GetAgentCircuitData(obj.CircuitCode); 248 AgentCircuitData aCircuit = ((Scene)(obj.Scene)).AuthenticateHandler.GetAgentCircuitData(obj.CircuitCode);
242 249
243 if (aCircuit.ServiceURLs.ContainsKey("HomeURI")) 250 if (aCircuit.ServiceURLs.ContainsKey("HomeURI"))
diff --git a/OpenSim/Region/CoreModules/Resources/CoreModulePlugin.addin.xml b/OpenSim/Region/CoreModules/Resources/CoreModulePlugin.addin.xml
index 0a5ff3f..ee07075 100644
--- a/OpenSim/Region/CoreModules/Resources/CoreModulePlugin.addin.xml
+++ b/OpenSim/Region/CoreModules/Resources/CoreModulePlugin.addin.xml
@@ -59,9 +59,11 @@
59 <RegionModule id="RemoteUserAccountServicesConnector" type="OpenSim.Region.CoreModules.ServiceConnectorsOut.UserAccounts.RemoteUserAccountServicesConnector" /> 59 <RegionModule id="RemoteUserAccountServicesConnector" type="OpenSim.Region.CoreModules.ServiceConnectorsOut.UserAccounts.RemoteUserAccountServicesConnector" />
60 60
61 <RegionModule id="LocalGridUserServicesConnector" type="OpenSim.Region.CoreModules.ServiceConnectorsOut.GridUser.LocalGridUserServicesConnector" /> 61 <RegionModule id="LocalGridUserServicesConnector" type="OpenSim.Region.CoreModules.ServiceConnectorsOut.GridUser.LocalGridUserServicesConnector" />
62 62 <RegionModule id="RemoteGridUserServicesConnector" type="OpenSim.Region.CoreModules.ServiceConnectorsOut.GridUser.RemoteGridUserServicesConnector" />
63
63 <RegionModule id="LocalSimulationConnectorModule" type="OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation.LocalSimulationConnectorModule" /> 64 <RegionModule id="LocalSimulationConnectorModule" type="OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation.LocalSimulationConnectorModule" />
64 <RegionModule id="RemoteSimulationConnectorModule" type="OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation.RemoteSimulationConnectorModule" /> 65 <RegionModule id="RemoteSimulationConnectorModule" type="OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation.RemoteSimulationConnectorModule" />
66
65 <!-- Service connectors IN modules --> 67 <!-- Service connectors IN modules -->
66 <RegionModule id="AssetServiceInConnectorModule" type="OpenSim.Region.CoreModules.ServiceConnectorsIn.Asset.AssetServiceInConnectorModule" /> 68 <RegionModule id="AssetServiceInConnectorModule" type="OpenSim.Region.CoreModules.ServiceConnectorsIn.Asset.AssetServiceInConnectorModule" />
67 <RegionModule id="InventoryServiceInConnectorModule" type="OpenSim.Region.CoreModules.ServiceConnectorsIn.Inventory.InventoryServiceInConnectorModule" /> 69 <RegionModule id="InventoryServiceInConnectorModule" type="OpenSim.Region.CoreModules.ServiceConnectorsIn.Inventory.InventoryServiceInConnectorModule" />
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/GridUser/LocalGridUserServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/GridUser/LocalGridUserServiceConnector.cs
index d5fae23..d914a57 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/GridUser/LocalGridUserServiceConnector.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/GridUser/LocalGridUserServiceConnector.cs
@@ -41,13 +41,19 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.GridUser
41{ 41{
42 public class LocalGridUserServicesConnector : ISharedRegionModule, IGridUserService 42 public class LocalGridUserServicesConnector : ISharedRegionModule, IGridUserService
43 { 43 {
44 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 44 private static readonly ILog m_log =
45 LogManager.GetLogger(
46 MethodBase.GetCurrentMethod().DeclaringType);
45 47
46 private IGridUserService m_service; 48 private IGridUserService m_GridUserService;
49
50 private ActivityDetector m_ActivityDetector;
47 51
48 private bool m_Enabled = false; 52 private bool m_Enabled = false;
49 53
50 public Type ReplaceableInterface 54 #region ISharedRegionModule
55
56 public Type ReplaceableInterface
51 { 57 {
52 get { return null; } 58 get { return null; }
53 } 59 }
@@ -68,7 +74,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.GridUser
68 IConfig userConfig = source.Configs["GridUserService"]; 74 IConfig userConfig = source.Configs["GridUserService"];
69 if (userConfig == null) 75 if (userConfig == null)
70 { 76 {
71 m_log.Error("[LOCAL GRID USER SERVICE CONNECTOR]: GridUserService missing from ini files"); 77 m_log.Error("[LOCAL GRID USER SERVICE CONNECTOR]: GridUserService missing from OpenSim.ini");
72 return; 78 return;
73 } 79 }
74 80
@@ -81,15 +87,20 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.GridUser
81 } 87 }
82 88
83 Object[] args = new Object[] { source }; 89 Object[] args = new Object[] { source };
84 m_service = ServerUtils.LoadPlugin<IGridUserService>(serviceDll, args); 90 m_GridUserService = ServerUtils.LoadPlugin<IGridUserService>(serviceDll, args);
85 91
86 if (m_service == null) 92 if (m_GridUserService == null)
87 { 93 {
88 m_log.Error("[LOCAL GRID USER SERVICE CONNECTOR]: Can't load GridUser service"); 94 m_log.ErrorFormat(
95 "[LOCAL GRID USER SERVICE CONNECTOR]: Cannot load user account service specified as {0}", serviceDll);
89 return; 96 return;
90 } 97 }
98
99 m_ActivityDetector = new ActivityDetector(this);
100
91 m_Enabled = true; 101 m_Enabled = true;
92 m_log.Info("[LOCAL GRID USER SERVICE CONNECTOR]: Local GridUser connector enabled"); 102
103 m_log.Info("[LOCAL GRID USER SERVICE CONNECTOR]: Local grid user connector enabled");
93 } 104 }
94 } 105 }
95 } 106 }
@@ -111,29 +122,57 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.GridUser
111 if (!m_Enabled) 122 if (!m_Enabled)
112 return; 123 return;
113 124
114 scene.RegisterModuleInterface<IGridUserService>(m_service); 125 scene.RegisterModuleInterface<IGridUserService>(m_GridUserService);
126 m_ActivityDetector.AddRegion(scene);
115 } 127 }
116 128
117 public void RemoveRegion(Scene scene) 129 public void RemoveRegion(Scene scene)
118 { 130 {
119 if (!m_Enabled) 131 if (!m_Enabled)
120 return; 132 return;
133
134 scene.UnregisterModuleInterface<IGridUserService>(this);
135 m_ActivityDetector.RemoveRegion(scene);
121 } 136 }
122 137
123 public void RegionLoaded(Scene scene) 138 public void RegionLoaded(Scene scene)
124 { 139 {
125 if (!m_Enabled) 140 if (!m_Enabled)
126 return; 141 return;
142
143 m_log.InfoFormat("[LOCAL GRID USER SERVICE CONNECTOR]: Enabled local grid user for region {0}", scene.RegionInfo.RegionName);
127 } 144 }
128 145
129 public GridUserInfo GetGridUserInfo(string userID) 146 #endregion
147
148 #region IGridUserService
149
150 public GridUserInfo LoggedIn(string userID)
130 { 151 {
131 return m_service.GetGridUserInfo(userID); 152 return m_GridUserService.LoggedIn(userID);
132 } 153 }
133 154
134 public bool StoreGridUserInfo(GridUserInfo info) 155 public bool LoggedOut(string userID, UUID regionID, Vector3 lastPosition, Vector3 lastLookAt)
135 { 156 {
136 return m_service.StoreGridUserInfo(info); 157 return m_GridUserService.LoggedOut(userID, regionID, lastPosition, lastLookAt);
137 } 158 }
159
160 public bool SetHome(string userID, UUID homeID, Vector3 homePosition, Vector3 homeLookAt)
161 {
162 return m_GridUserService.SetHome(userID, homeID, homePosition, homeLookAt);
163 }
164
165 public bool SetLastPosition(string userID, UUID regionID, Vector3 lastPosition, Vector3 lastLookAt)
166 {
167 return m_GridUserService.SetLastPosition(userID, regionID, lastPosition, lastLookAt);
168 }
169
170 public GridUserInfo GetGridUserInfo(string userID)
171 {
172 return m_GridUserService.GetGridUserInfo(userID);
173 }
174
175 #endregion
176
138 } 177 }
139} \ No newline at end of file 178}
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/LocalPresenceServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/LocalPresenceServiceConnector.cs
index c402a3f..49dd633 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/LocalPresenceServiceConnector.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/LocalPresenceServiceConnector.cs
@@ -167,9 +167,9 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Presence
167 return false; 167 return false;
168 } 168 }
169 169
170 public bool LogoutAgent(UUID sessionID, Vector3 position, Vector3 lookat) 170 public bool LogoutAgent(UUID sessionID)
171 { 171 {
172 return m_PresenceService.LogoutAgent(sessionID, position, lookat); 172 return m_PresenceService.LogoutAgent(sessionID);
173 } 173 }
174 174
175 175
@@ -178,9 +178,9 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Presence
178 return m_PresenceService.LogoutRegionAgents(regionID); 178 return m_PresenceService.LogoutRegionAgents(regionID);
179 } 179 }
180 180
181 public bool ReportAgent(UUID sessionID, UUID regionID, Vector3 position, Vector3 lookAt) 181 public bool ReportAgent(UUID sessionID, UUID regionID)
182 { 182 {
183 return m_PresenceService.ReportAgent(sessionID, regionID, position, lookAt); 183 return m_PresenceService.ReportAgent(sessionID, regionID);
184 } 184 }
185 185
186 public PresenceInfo GetAgent(UUID sessionID) 186 public PresenceInfo GetAgent(UUID sessionID)
@@ -193,11 +193,6 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Presence
193 return m_PresenceService.GetAgents(userIDs); 193 return m_PresenceService.GetAgents(userIDs);
194 } 194 }
195 195
196 public bool SetHomeLocation(string userID, UUID regionID, Vector3 position, Vector3 lookAt)
197 {
198 return m_PresenceService.SetHomeLocation(userID, regionID, position, lookAt);
199 }
200
201 #endregion 196 #endregion
202 197
203 } 198 }
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/PresenceDetector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/PresenceDetector.cs
index 7a75a89..62b8278 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/PresenceDetector.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/PresenceDetector.cs
@@ -72,7 +72,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Presence
72 public void OnMakeRootAgent(ScenePresence sp) 72 public void OnMakeRootAgent(ScenePresence sp)
73 { 73 {
74 m_log.DebugFormat("[PRESENCE DETECTOR]: Detected root presence {0} in {1}", sp.UUID, sp.Scene.RegionInfo.RegionName); 74 m_log.DebugFormat("[PRESENCE DETECTOR]: Detected root presence {0} in {1}", sp.UUID, sp.Scene.RegionInfo.RegionName);
75 m_PresenceService.ReportAgent(sp.ControllingClient.SessionId, sp.Scene.RegionInfo.RegionID, sp.AbsolutePosition, sp.Lookat); 75 m_PresenceService.ReportAgent(sp.ControllingClient.SessionId, sp.Scene.RegionInfo.RegionID);
76 } 76 }
77 77
78 public void OnNewClient(IClientAPI client) 78 public void OnNewClient(IClientAPI client)
@@ -85,19 +85,17 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Presence
85 if (client.IsLoggingOut) 85 if (client.IsLoggingOut)
86 { 86 {
87 object sp = null; 87 object sp = null;
88 Vector3 position = new Vector3(128, 128, 0);
89 Vector3 lookat = new Vector3(0, 1, 0);
90
91 if (client.Scene.TryGetScenePresence(client.AgentId, out sp)) 88 if (client.Scene.TryGetScenePresence(client.AgentId, out sp))
92 { 89 {
93 if (sp is ScenePresence) 90 if (sp is ScenePresence)
94 { 91 {
95 position = ((ScenePresence)sp).AbsolutePosition; 92 if (((ScenePresence)sp).IsChildAgent)
96 lookat = ((ScenePresence)sp).Lookat; 93 return;
97 } 94 }
98 } 95 }
99 96
100 m_PresenceService.LogoutAgent(client.SessionId, position, lookat); 97 m_log.DebugFormat("[PRESENCE DETECTOR]: Detected client logout {0} in {1}", client.AgentId, client.Scene.RegionInfo.RegionName);
98 m_PresenceService.LogoutAgent(client.SessionId);
101 } 99 }
102 100
103 } 101 }
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/RemotePresenceServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/RemotePresenceServiceConnector.cs
index 5f3666e..bf4e9ab 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/RemotePresenceServiceConnector.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/RemotePresenceServiceConnector.cs
@@ -127,9 +127,9 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Presence
127 return false; 127 return false;
128 } 128 }
129 129
130 public bool LogoutAgent(UUID sessionID, Vector3 position, Vector3 lookat) 130 public bool LogoutAgent(UUID sessionID)
131 { 131 {
132 return m_RemoteConnector.LogoutAgent(sessionID, position, lookat); 132 return m_RemoteConnector.LogoutAgent(sessionID);
133 } 133 }
134 134
135 135
@@ -138,9 +138,9 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Presence
138 return m_RemoteConnector.LogoutRegionAgents(regionID); 138 return m_RemoteConnector.LogoutRegionAgents(regionID);
139 } 139 }
140 140
141 public bool ReportAgent(UUID sessionID, UUID regionID, Vector3 position, Vector3 lookAt) 141 public bool ReportAgent(UUID sessionID, UUID regionID)
142 { 142 {
143 return m_RemoteConnector.ReportAgent(sessionID, regionID, position, lookAt); 143 return m_RemoteConnector.ReportAgent(sessionID, regionID);
144 } 144 }
145 145
146 public PresenceInfo GetAgent(UUID sessionID) 146 public PresenceInfo GetAgent(UUID sessionID)
@@ -153,11 +153,6 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Presence
153 return m_RemoteConnector.GetAgents(userIDs); 153 return m_RemoteConnector.GetAgents(userIDs);
154 } 154 }
155 155
156 public bool SetHomeLocation(string userID, UUID regionID, Vector3 position, Vector3 lookAt)
157 {
158 return m_RemoteConnector.SetHomeLocation(userID, regionID, position, lookAt);
159 }
160
161 #endregion 156 #endregion
162 157
163 } 158 }
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/Tests/PresenceConnectorsTests.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/Tests/PresenceConnectorsTests.cs
index 63a28fc..e5ded5b 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/Tests/PresenceConnectorsTests.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/Tests/PresenceConnectorsTests.cs
@@ -93,24 +93,24 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Presence.Tests
93 Assert.IsTrue(result.Online, "Agent just logged in but is offline"); 93 Assert.IsTrue(result.Online, "Agent just logged in but is offline");
94 94
95 UUID region1 = UUID.Random(); 95 UUID region1 = UUID.Random();
96 bool r = m_LocalConnector.ReportAgent(session1, region1, Vector3.Zero, Vector3.Zero); 96 bool r = m_LocalConnector.ReportAgent(session1, region1);
97 Assert.IsTrue(r, "First ReportAgent returned false"); 97 Assert.IsTrue(r, "First ReportAgent returned false");
98 result = m_LocalConnector.GetAgent(session1); 98 result = m_LocalConnector.GetAgent(session1);
99 Assert.That(result.RegionID, Is.EqualTo(region1), "Agent is not in the right region (region1)"); 99 Assert.That(result.RegionID, Is.EqualTo(region1), "Agent is not in the right region (region1)");
100 100
101 UUID region2 = UUID.Random(); 101 UUID region2 = UUID.Random();
102 r = m_LocalConnector.ReportAgent(session1, region2, Vector3.Zero, Vector3.Zero); 102 r = m_LocalConnector.ReportAgent(session1, region2);
103 Assert.IsTrue(r, "Second ReportAgent returned false"); 103 Assert.IsTrue(r, "Second ReportAgent returned false");
104 result = m_LocalConnector.GetAgent(session1); 104 result = m_LocalConnector.GetAgent(session1);
105 Assert.That(result.RegionID, Is.EqualTo(region2), "Agent is not in the right region (region2)"); 105 Assert.That(result.RegionID, Is.EqualTo(region2), "Agent is not in the right region (region2)");
106 106
107 r = m_LocalConnector.LogoutAgent(session1, Vector3.Zero, Vector3.UnitY); 107 r = m_LocalConnector.LogoutAgent(session1);
108 Assert.IsTrue(r, "LogoutAgent returned false"); 108 Assert.IsTrue(r, "LogoutAgent returned false");
109 result = m_LocalConnector.GetAgent(session1); 109 result = m_LocalConnector.GetAgent(session1);
110 Assert.IsNotNull(result, "Agent session disappeared from storage after logout"); 110 Assert.IsNotNull(result, "Agent session disappeared from storage after logout");
111 Assert.IsFalse(result.Online, "Agent is reported to be Online after logout"); 111 Assert.IsFalse(result.Online, "Agent is reported to be Online after logout");
112 112
113 r = m_LocalConnector.ReportAgent(session1, region1, Vector3.Zero, Vector3.Zero); 113 r = m_LocalConnector.ReportAgent(session1, region1);
114 Assert.IsFalse(r, "ReportAgent of non-logged in user returned true"); 114 Assert.IsFalse(r, "ReportAgent of non-logged in user returned true");
115 } 115 }
116 } 116 }
diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs
index 1a46837..c0fa7b4 100644
--- a/OpenSim/Region/Framework/Scenes/Scene.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.cs
@@ -304,7 +304,18 @@ namespace OpenSim.Region.Framework.Scenes
304 return m_AvatarService; 304 return m_AvatarService;
305 } 305 }
306 } 306 }
307 307
308 protected IGridUserService m_GridUserService;
309 public IGridUserService GridUserService
310 {
311 get
312 {
313 if (m_GridUserService == null)
314 m_GridUserService = RequestModuleInterface<IGridUserService>();
315 return m_GridUserService;
316 }
317 }
318
308 protected IXMLRPC m_xmlrpcModule; 319 protected IXMLRPC m_xmlrpcModule;
309 protected IWorldComm m_worldCommModule; 320 protected IWorldComm m_worldCommModule;
310 public IAttachmentsModule AttachmentsModule { get; set; } 321 public IAttachmentsModule AttachmentsModule { get; set; }
@@ -1306,8 +1317,8 @@ namespace OpenSim.Region.Framework.Scenes
1306 if (defaultRegions != null && defaultRegions.Count >= 1) 1317 if (defaultRegions != null && defaultRegions.Count >= 1)
1307 home = defaultRegions[0]; 1318 home = defaultRegions[0];
1308 1319
1309 if (PresenceService != null && home != null) 1320 if (GridUserService != null && home != null)
1310 PresenceService.SetHomeLocation(account.PrincipalID.ToString(), home.RegionID, new Vector3(128, 128, 0), new Vector3(0, 1, 0)); 1321 GridUserService.SetHome(account.PrincipalID.ToString(), home.RegionID, new Vector3(128, 128, 0), new Vector3(0, 1, 0));
1311 else 1322 else
1312 m_log.WarnFormat("[USER ACCOUNT SERVICE]: Unable to set home for account {0} {1}.", 1323 m_log.WarnFormat("[USER ACCOUNT SERVICE]: Unable to set home for account {0} {1}.",
1313 first, last); 1324 first, last);
@@ -3095,7 +3106,7 @@ namespace OpenSim.Region.Framework.Scenes
3095 /// <param name="flags"></param> 3106 /// <param name="flags"></param>
3096 public virtual void SetHomeRezPoint(IClientAPI remoteClient, ulong regionHandle, Vector3 position, Vector3 lookAt, uint flags) 3107 public virtual void SetHomeRezPoint(IClientAPI remoteClient, ulong regionHandle, Vector3 position, Vector3 lookAt, uint flags)
3097 { 3108 {
3098 if (PresenceService.SetHomeLocation(remoteClient.AgentId.ToString(), RegionInfo.RegionID, position, lookAt)) 3109 if (GridUserService != null && GridUserService.SetHome(remoteClient.AgentId.ToString(), RegionInfo.RegionID, position, lookAt))
3099 // FUBAR ALERT: this needs to be "Home position set." so the viewer saves a home-screenshot. 3110 // FUBAR ALERT: this needs to be "Home position set." so the viewer saves a home-screenshot.
3100 m_dialogModule.SendAlertToUser(remoteClient, "Home position set."); 3111 m_dialogModule.SendAlertToUser(remoteClient, "Home position set.");
3101 else 3112 else
@@ -3543,7 +3554,7 @@ namespace OpenSim.Region.Framework.Scenes
3543 3554
3544 OpenSim.Services.Interfaces.PresenceInfo pinfo = presence.GetAgent(agent.SessionID); 3555 OpenSim.Services.Interfaces.PresenceInfo pinfo = presence.GetAgent(agent.SessionID);
3545 3556
3546 if (pinfo == null || (pinfo != null && pinfo.Online == false)) 3557 if (pinfo == null)
3547 { 3558 {
3548 reason = String.Format("Failed to verify user {0} {1}, access denied to region {2}.", agent.firstname, agent.lastname, RegionInfo.RegionName); 3559 reason = String.Format("Failed to verify user {0} {1}, access denied to region {2}.", agent.firstname, agent.lastname, RegionInfo.RegionName);
3549 return false; 3560 return false;
diff --git a/OpenSim/Region/Physics/Meshing/PrimMesher.cs b/OpenSim/Region/Physics/Meshing/PrimMesher.cs
index b4e101a..53022ad 100644
--- a/OpenSim/Region/Physics/Meshing/PrimMesher.cs
+++ b/OpenSim/Region/Physics/Meshing/PrimMesher.cs
@@ -1,2284 +1,2284 @@
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 public Face(int v1, int v2, int v3) 260 public Face(int v1, int v2, int v3)
261 { 261 {
262 primFace = 0; 262 primFace = 0;
263 263
264 this.v1 = v1; 264 this.v1 = v1;
265 this.v2 = v2; 265 this.v2 = v2;
266 this.v3 = v3; 266 this.v3 = v3;
267 267
268 this.n1 = 0; 268 this.n1 = 0;
269 this.n2 = 0; 269 this.n2 = 0;
270 this.n3 = 0; 270 this.n3 = 0;
271 271
272 this.uv1 = 0; 272 this.uv1 = 0;
273 this.uv2 = 0; 273 this.uv2 = 0;
274 this.uv3 = 0; 274 this.uv3 = 0;
275 275
276 } 276 }
277 277
278 public Face(int v1, int v2, int v3, int n1, int n2, int n3) 278 public Face(int v1, int v2, int v3, int n1, int n2, int n3)
279 { 279 {
280 primFace = 0; 280 primFace = 0;
281 281
282 this.v1 = v1; 282 this.v1 = v1;
283 this.v2 = v2; 283 this.v2 = v2;
284 this.v3 = v3; 284 this.v3 = v3;
285 285
286 this.n1 = n1; 286 this.n1 = n1;
287 this.n2 = n2; 287 this.n2 = n2;
288 this.n3 = n3; 288 this.n3 = n3;
289 289
290 this.uv1 = 0; 290 this.uv1 = 0;
291 this.uv2 = 0; 291 this.uv2 = 0;
292 this.uv3 = 0; 292 this.uv3 = 0;
293 } 293 }
294 294
295 public Coord SurfaceNormal(List<Coord> coordList) 295 public Coord SurfaceNormal(List<Coord> coordList)
296 { 296 {
297 Coord c1 = coordList[this.v1]; 297 Coord c1 = coordList[this.v1];
298 Coord c2 = coordList[this.v2]; 298 Coord c2 = coordList[this.v2];
299 Coord c3 = coordList[this.v3]; 299 Coord c3 = coordList[this.v3];
300 300
301 Coord edge1 = new Coord(c2.X - c1.X, c2.Y - c1.Y, c2.Z - c1.Z); 301 Coord edge1 = new Coord(c2.X - c1.X, c2.Y - c1.Y, c2.Z - c1.Z);
302 Coord edge2 = new Coord(c3.X - c1.X, c3.Y - c1.Y, c3.Z - c1.Z); 302 Coord edge2 = new Coord(c3.X - c1.X, c3.Y - c1.Y, c3.Z - c1.Z);
303 303
304 return Coord.Cross(edge1, edge2).Normalize(); 304 return Coord.Cross(edge1, edge2).Normalize();
305 } 305 }
306 } 306 }
307 307
308 public struct ViewerFace 308 public struct ViewerFace
309 { 309 {
310 public int primFaceNumber; 310 public int primFaceNumber;
311 311
312 public Coord v1; 312 public Coord v1;
313 public Coord v2; 313 public Coord v2;
314 public Coord v3; 314 public Coord v3;
315 315
316 public int coordIndex1; 316 public int coordIndex1;
317 public int coordIndex2; 317 public int coordIndex2;
318 public int coordIndex3; 318 public int coordIndex3;
319 319
320 public Coord n1; 320 public Coord n1;
321 public Coord n2; 321 public Coord n2;
322 public Coord n3; 322 public Coord n3;
323 323
324 public UVCoord uv1; 324 public UVCoord uv1;
325 public UVCoord uv2; 325 public UVCoord uv2;
326 public UVCoord uv3; 326 public UVCoord uv3;
327 327
328 public ViewerFace(int primFaceNumber) 328 public ViewerFace(int primFaceNumber)
329 { 329 {
330 this.primFaceNumber = primFaceNumber; 330 this.primFaceNumber = primFaceNumber;
331 331
332 this.v1 = new Coord(); 332 this.v1 = new Coord();
333 this.v2 = new Coord(); 333 this.v2 = new Coord();
334 this.v3 = new Coord(); 334 this.v3 = new Coord();
335 335
336 this.coordIndex1 = this.coordIndex2 = this.coordIndex3 = -1; // -1 means not assigned yet 336 this.coordIndex1 = this.coordIndex2 = this.coordIndex3 = -1; // -1 means not assigned yet
337 337
338 this.n1 = new Coord(); 338 this.n1 = new Coord();
339 this.n2 = new Coord(); 339 this.n2 = new Coord();
340 this.n3 = new Coord(); 340 this.n3 = new Coord();
341 341
342 this.uv1 = new UVCoord(); 342 this.uv1 = new UVCoord();
343 this.uv2 = new UVCoord(); 343 this.uv2 = new UVCoord();
344 this.uv3 = new UVCoord(); 344 this.uv3 = new UVCoord();
345 } 345 }
346 346
347 public void Scale(float x, float y, float z) 347 public void Scale(float x, float y, float z)
348 { 348 {
349 this.v1.X *= x; 349 this.v1.X *= x;
350 this.v1.Y *= y; 350 this.v1.Y *= y;
351 this.v1.Z *= z; 351 this.v1.Z *= z;
352 352
353 this.v2.X *= x; 353 this.v2.X *= x;
354 this.v2.Y *= y; 354 this.v2.Y *= y;
355 this.v2.Z *= z; 355 this.v2.Z *= z;
356 356
357 this.v3.X *= x; 357 this.v3.X *= x;
358 this.v3.Y *= y; 358 this.v3.Y *= y;
359 this.v3.Z *= z; 359 this.v3.Z *= z;
360 } 360 }
361 361
362 public void AddPos(float x, float y, float z) 362 public void AddPos(float x, float y, float z)
363 { 363 {
364 this.v1.X += x; 364 this.v1.X += x;
365 this.v2.X += x; 365 this.v2.X += x;
366 this.v3.X += x; 366 this.v3.X += x;
367 367
368 this.v1.Y += y; 368 this.v1.Y += y;
369 this.v2.Y += y; 369 this.v2.Y += y;
370 this.v3.Y += y; 370 this.v3.Y += y;
371 371
372 this.v1.Z += z; 372 this.v1.Z += z;
373 this.v2.Z += z; 373 this.v2.Z += z;
374 this.v3.Z += z; 374 this.v3.Z += z;
375 } 375 }
376 376
377 public void AddRot(Quat q) 377 public void AddRot(Quat q)
378 { 378 {
379 this.v1 *= q; 379 this.v1 *= q;
380 this.v2 *= q; 380 this.v2 *= q;
381 this.v3 *= q; 381 this.v3 *= q;
382 382
383 this.n1 *= q; 383 this.n1 *= q;
384 this.n2 *= q; 384 this.n2 *= q;
385 this.n3 *= q; 385 this.n3 *= q;
386 } 386 }
387 387
388 public void CalcSurfaceNormal() 388 public void CalcSurfaceNormal()
389 { 389 {
390 390
391 Coord edge1 = new Coord(this.v2.X - this.v1.X, this.v2.Y - this.v1.Y, this.v2.Z - this.v1.Z); 391 Coord edge1 = new Coord(this.v2.X - this.v1.X, this.v2.Y - this.v1.Y, this.v2.Z - this.v1.Z);
392 Coord edge2 = new Coord(this.v3.X - this.v1.X, this.v3.Y - this.v1.Y, this.v3.Z - this.v1.Z); 392 Coord edge2 = new Coord(this.v3.X - this.v1.X, this.v3.Y - this.v1.Y, this.v3.Z - this.v1.Z);
393 393
394 this.n1 = this.n2 = this.n3 = Coord.Cross(edge1, edge2).Normalize(); 394 this.n1 = this.n2 = this.n3 = Coord.Cross(edge1, edge2).Normalize();
395 } 395 }
396 } 396 }
397 397
398 internal struct Angle 398 internal struct Angle
399 { 399 {
400 internal float angle; 400 internal float angle;
401 internal float X; 401 internal float X;
402 internal float Y; 402 internal float Y;
403 403
404 internal Angle(float angle, float x, float y) 404 internal Angle(float angle, float x, float y)
405 { 405 {
406 this.angle = angle; 406 this.angle = angle;
407 this.X = x; 407 this.X = x;
408 this.Y = y; 408 this.Y = y;
409 } 409 }
410 } 410 }
411 411
412 internal class AngleList 412 internal class AngleList
413 { 413 {
414 private float iX, iY; // intersection point 414 private float iX, iY; // intersection point
415 415
416 private static Angle[] angles3 = 416 private static Angle[] angles3 =
417 { 417 {
418 new Angle(0.0f, 1.0f, 0.0f), 418 new Angle(0.0f, 1.0f, 0.0f),
419 new Angle(0.33333333333333333f, -0.5f, 0.86602540378443871f), 419 new Angle(0.33333333333333333f, -0.5f, 0.86602540378443871f),
420 new Angle(0.66666666666666667f, -0.5f, -0.86602540378443837f), 420 new Angle(0.66666666666666667f, -0.5f, -0.86602540378443837f),
421 new Angle(1.0f, 1.0f, 0.0f) 421 new Angle(1.0f, 1.0f, 0.0f)
422 }; 422 };
423 423
424 private static Coord[] normals3 = 424 private static Coord[] normals3 =
425 { 425 {
426 new Coord(0.25f, 0.4330127019f, 0.0f).Normalize(), 426 new Coord(0.25f, 0.4330127019f, 0.0f).Normalize(),
427 new Coord(-0.5f, 0.0f, 0.0f).Normalize(), 427 new Coord(-0.5f, 0.0f, 0.0f).Normalize(),
428 new Coord(0.25f, -0.4330127019f, 0.0f).Normalize(), 428 new Coord(0.25f, -0.4330127019f, 0.0f).Normalize(),
429 new Coord(0.25f, 0.4330127019f, 0.0f).Normalize() 429 new Coord(0.25f, 0.4330127019f, 0.0f).Normalize()
430 }; 430 };
431 431
432 private static Angle[] angles4 = 432 private static Angle[] angles4 =
433 { 433 {
434 new Angle(0.0f, 1.0f, 0.0f), 434 new Angle(0.0f, 1.0f, 0.0f),
435 new Angle(0.25f, 0.0f, 1.0f), 435 new Angle(0.25f, 0.0f, 1.0f),
436 new Angle(0.5f, -1.0f, 0.0f), 436 new Angle(0.5f, -1.0f, 0.0f),
437 new Angle(0.75f, 0.0f, -1.0f), 437 new Angle(0.75f, 0.0f, -1.0f),
438 new Angle(1.0f, 1.0f, 0.0f) 438 new Angle(1.0f, 1.0f, 0.0f)
439 }; 439 };
440 440
441 private static Coord[] normals4 = 441 private static Coord[] normals4 =
442 { 442 {
443 new Coord(0.5f, 0.5f, 0.0f).Normalize(), 443 new Coord(0.5f, 0.5f, 0.0f).Normalize(),
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 }; 448 };
449 449
450 private static Angle[] angles24 = 450 private static Angle[] angles24 =
451 { 451 {
452 new Angle(0.0f, 1.0f, 0.0f), 452 new Angle(0.0f, 1.0f, 0.0f),
453 new Angle(0.041666666666666664f, 0.96592582628906831f, 0.25881904510252074f), 453 new Angle(0.041666666666666664f, 0.96592582628906831f, 0.25881904510252074f),
454 new Angle(0.083333333333333329f, 0.86602540378443871f, 0.5f), 454 new Angle(0.083333333333333329f, 0.86602540378443871f, 0.5f),
455 new Angle(0.125f, 0.70710678118654757f, 0.70710678118654746f), 455 new Angle(0.125f, 0.70710678118654757f, 0.70710678118654746f),
456 new Angle(0.16666666666666667f, 0.5f, 0.8660254037844386f), 456 new Angle(0.16666666666666667f, 0.5f, 0.8660254037844386f),
457 new Angle(0.20833333333333331f, 0.25881904510252096f, 0.9659258262890682f), 457 new Angle(0.20833333333333331f, 0.25881904510252096f, 0.9659258262890682f),
458 new Angle(0.25f, 0.0f, 1.0f), 458 new Angle(0.25f, 0.0f, 1.0f),
459 new Angle(0.29166666666666663f, -0.25881904510252063f, 0.96592582628906831f), 459 new Angle(0.29166666666666663f, -0.25881904510252063f, 0.96592582628906831f),
460 new Angle(0.33333333333333333f, -0.5f, 0.86602540378443871f), 460 new Angle(0.33333333333333333f, -0.5f, 0.86602540378443871f),
461 new Angle(0.375f, -0.70710678118654746f, 0.70710678118654757f), 461 new Angle(0.375f, -0.70710678118654746f, 0.70710678118654757f),
462 new Angle(0.41666666666666663f, -0.86602540378443849f, 0.5f), 462 new Angle(0.41666666666666663f, -0.86602540378443849f, 0.5f),
463 new Angle(0.45833333333333331f, -0.9659258262890682f, 0.25881904510252102f), 463 new Angle(0.45833333333333331f, -0.9659258262890682f, 0.25881904510252102f),
464 new Angle(0.5f, -1.0f, 0.0f), 464 new Angle(0.5f, -1.0f, 0.0f),
465 new Angle(0.54166666666666663f, -0.96592582628906842f, -0.25881904510252035f), 465 new Angle(0.54166666666666663f, -0.96592582628906842f, -0.25881904510252035f),
466 new Angle(0.58333333333333326f, -0.86602540378443882f, -0.5f), 466 new Angle(0.58333333333333326f, -0.86602540378443882f, -0.5f),
467 new Angle(0.62499999999999989f, -0.70710678118654791f, -0.70710678118654713f), 467 new Angle(0.62499999999999989f, -0.70710678118654791f, -0.70710678118654713f),
468 new Angle(0.66666666666666667f, -0.5f, -0.86602540378443837f), 468 new Angle(0.66666666666666667f, -0.5f, -0.86602540378443837f),
469 new Angle(0.70833333333333326f, -0.25881904510252152f, -0.96592582628906809f), 469 new Angle(0.70833333333333326f, -0.25881904510252152f, -0.96592582628906809f),
470 new Angle(0.75f, 0.0f, -1.0f), 470 new Angle(0.75f, 0.0f, -1.0f),
471 new Angle(0.79166666666666663f, 0.2588190451025203f, -0.96592582628906842f), 471 new Angle(0.79166666666666663f, 0.2588190451025203f, -0.96592582628906842f),
472 new Angle(0.83333333333333326f, 0.5f, -0.86602540378443904f), 472 new Angle(0.83333333333333326f, 0.5f, -0.86602540378443904f),
473 new Angle(0.875f, 0.70710678118654735f, -0.70710678118654768f), 473 new Angle(0.875f, 0.70710678118654735f, -0.70710678118654768f),
474 new Angle(0.91666666666666663f, 0.86602540378443837f, -0.5f), 474 new Angle(0.91666666666666663f, 0.86602540378443837f, -0.5f),
475 new Angle(0.95833333333333326f, 0.96592582628906809f, -0.25881904510252157f), 475 new Angle(0.95833333333333326f, 0.96592582628906809f, -0.25881904510252157f),
476 new Angle(1.0f, 1.0f, 0.0f) 476 new Angle(1.0f, 1.0f, 0.0f)
477 }; 477 };
478 478
479 private Angle interpolatePoints(float newPoint, Angle p1, Angle p2) 479 private Angle interpolatePoints(float newPoint, Angle p1, Angle p2)
480 { 480 {
481 float m = (newPoint - p1.angle) / (p2.angle - p1.angle); 481 float m = (newPoint - p1.angle) / (p2.angle - p1.angle);
482 return new Angle(newPoint, p1.X + m * (p2.X - p1.X), p1.Y + m * (p2.Y - p1.Y)); 482 return new Angle(newPoint, p1.X + m * (p2.X - p1.X), p1.Y + m * (p2.Y - p1.Y));
483 } 483 }
484 484
485 private void intersection(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4) 485 private void intersection(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)
486 { // ref: http://local.wasp.uwa.edu.au/~pbourke/geometry/lineline2d/ 486 { // ref: http://local.wasp.uwa.edu.au/~pbourke/geometry/lineline2d/
487 double denom = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1); 487 double denom = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1);
488 double uaNumerator = (x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3); 488 double uaNumerator = (x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3);
489 489
490 if (denom != 0.0) 490 if (denom != 0.0)
491 { 491 {
492 double ua = uaNumerator / denom; 492 double ua = uaNumerator / denom;
493 iX = (float)(x1 + ua * (x2 - x1)); 493 iX = (float)(x1 + ua * (x2 - x1));
494 iY = (float)(y1 + ua * (y2 - y1)); 494 iY = (float)(y1 + ua * (y2 - y1));
495 } 495 }
496 } 496 }
497 497
498 internal List<Angle> angles; 498 internal List<Angle> angles;
499 internal List<Coord> normals; 499 internal List<Coord> normals;
500 500
501 internal void makeAngles(int sides, float startAngle, float stopAngle) 501 internal void makeAngles(int sides, float startAngle, float stopAngle)
502 { 502 {
503 angles = new List<Angle>(); 503 angles = new List<Angle>();
504 normals = new List<Coord>(); 504 normals = new List<Coord>();
505 505
506 double twoPi = System.Math.PI * 2.0; 506 double twoPi = System.Math.PI * 2.0;
507 float twoPiInv = 1.0f / (float)twoPi; 507 float twoPiInv = 1.0f / (float)twoPi;
508 508
509 if (sides < 1) 509 if (sides < 1)
510 throw new Exception("number of sides not greater than zero"); 510 throw new Exception("number of sides not greater than zero");
511 if (stopAngle <= startAngle) 511 if (stopAngle <= startAngle)
512 throw new Exception("stopAngle not greater than startAngle"); 512 throw new Exception("stopAngle not greater than startAngle");
513 513
514 if ((sides == 3 || sides == 4 || sides == 24)) 514 if ((sides == 3 || sides == 4 || sides == 24))
515 { 515 {
516 startAngle *= twoPiInv; 516 startAngle *= twoPiInv;
517 stopAngle *= twoPiInv; 517 stopAngle *= twoPiInv;
518 518
519 Angle[] sourceAngles; 519 Angle[] sourceAngles;
520 if (sides == 3) 520 if (sides == 3)
521 sourceAngles = angles3; 521 sourceAngles = angles3;
522 else if (sides == 4) 522 else if (sides == 4)
523 sourceAngles = angles4; 523 sourceAngles = angles4;
524 else sourceAngles = angles24; 524 else sourceAngles = angles24;
525 525
526 int startAngleIndex = (int)(startAngle * sides); 526 int startAngleIndex = (int)(startAngle * sides);
527 int endAngleIndex = sourceAngles.Length - 1; 527 int endAngleIndex = sourceAngles.Length - 1;
528 if (stopAngle < 1.0f) 528 if (stopAngle < 1.0f)
529 endAngleIndex = (int)(stopAngle * sides) + 1; 529 endAngleIndex = (int)(stopAngle * sides) + 1;
530 if (endAngleIndex == startAngleIndex) 530 if (endAngleIndex == startAngleIndex)
531 endAngleIndex++; 531 endAngleIndex++;
532 532
533 for (int angleIndex = startAngleIndex; angleIndex < endAngleIndex + 1; angleIndex++) 533 for (int angleIndex = startAngleIndex; angleIndex < endAngleIndex + 1; angleIndex++)
534 { 534 {
535 angles.Add(sourceAngles[angleIndex]); 535 angles.Add(sourceAngles[angleIndex]);
536 if (sides == 3) 536 if (sides == 3)
537 normals.Add(normals3[angleIndex]); 537 normals.Add(normals3[angleIndex]);
538 else if (sides == 4) 538 else if (sides == 4)
539 normals.Add(normals4[angleIndex]); 539 normals.Add(normals4[angleIndex]);
540 } 540 }
541 541
542 if (startAngle > 0.0f) 542 if (startAngle > 0.0f)
543 angles[0] = interpolatePoints(startAngle, angles[0], angles[1]); 543 angles[0] = interpolatePoints(startAngle, angles[0], angles[1]);
544 544
545 if (stopAngle < 1.0f) 545 if (stopAngle < 1.0f)
546 { 546 {
547 int lastAngleIndex = angles.Count - 1; 547 int lastAngleIndex = angles.Count - 1;
548 angles[lastAngleIndex] = interpolatePoints(stopAngle, angles[lastAngleIndex - 1], angles[lastAngleIndex]); 548 angles[lastAngleIndex] = interpolatePoints(stopAngle, angles[lastAngleIndex - 1], angles[lastAngleIndex]);
549 } 549 }
550 } 550 }
551 else 551 else
552 { 552 {
553 double stepSize = twoPi / sides; 553 double stepSize = twoPi / sides;
554 554
555 int startStep = (int)(startAngle / stepSize); 555 int startStep = (int)(startAngle / stepSize);
556 double angle = stepSize * startStep; 556 double angle = stepSize * startStep;
557 int step = startStep; 557 int step = startStep;
558 double stopAngleTest = stopAngle; 558 double stopAngleTest = stopAngle;
559 if (stopAngle < twoPi) 559 if (stopAngle < twoPi)
560 { 560 {
561 stopAngleTest = stepSize * ((int)(stopAngle / stepSize) + 1); 561 stopAngleTest = stepSize * ((int)(stopAngle / stepSize) + 1);
562 if (stopAngleTest < stopAngle) 562 if (stopAngleTest < stopAngle)
563 stopAngleTest += stepSize; 563 stopAngleTest += stepSize;
564 if (stopAngleTest > twoPi) 564 if (stopAngleTest > twoPi)
565 stopAngleTest = twoPi; 565 stopAngleTest = twoPi;
566 } 566 }
567 567
568 while (angle <= stopAngleTest) 568 while (angle <= stopAngleTest)
569 { 569 {
570 Angle newAngle; 570 Angle newAngle;
571 newAngle.angle = (float)angle; 571 newAngle.angle = (float)angle;
572 newAngle.X = (float)System.Math.Cos(angle); 572 newAngle.X = (float)System.Math.Cos(angle);
573 newAngle.Y = (float)System.Math.Sin(angle); 573 newAngle.Y = (float)System.Math.Sin(angle);
574 angles.Add(newAngle); 574 angles.Add(newAngle);
575 step += 1; 575 step += 1;
576 angle = stepSize * step; 576 angle = stepSize * step;
577 } 577 }
578 578
579 if (startAngle > angles[0].angle) 579 if (startAngle > angles[0].angle)
580 { 580 {
581 Angle newAngle; 581 Angle newAngle;
582 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)); 582 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 newAngle.angle = startAngle; 583 newAngle.angle = startAngle;
584 newAngle.X = iX; 584 newAngle.X = iX;
585 newAngle.Y = iY; 585 newAngle.Y = iY;
586 angles[0] = newAngle; 586 angles[0] = newAngle;
587 } 587 }
588 588
589 int index = angles.Count - 1; 589 int index = angles.Count - 1;
590 if (stopAngle < angles[index].angle) 590 if (stopAngle < angles[index].angle)
591 { 591 {
592 Angle newAngle; 592 Angle newAngle;
593 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)); 593 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 newAngle.angle = stopAngle; 594 newAngle.angle = stopAngle;
595 newAngle.X = iX; 595 newAngle.X = iX;
596 newAngle.Y = iY; 596 newAngle.Y = iY;
597 angles[index] = newAngle; 597 angles[index] = newAngle;
598 } 598 }
599 } 599 }
600 } 600 }
601 } 601 }
602 602
603 /// <summary> 603 /// <summary>
604 /// generates a profile for extrusion 604 /// generates a profile for extrusion
605 /// </summary> 605 /// </summary>
606 internal class Profile 606 internal class Profile
607 { 607 {
608 private const float twoPi = 2.0f * (float)Math.PI; 608 private const float twoPi = 2.0f * (float)Math.PI;
609 609
610 internal string errorMessage = null; 610 internal string errorMessage = null;
611 611
612 internal List<Coord> coords; 612 internal List<Coord> coords;
613 internal List<Face> faces; 613 internal List<Face> faces;
614 internal List<Coord> vertexNormals; 614 internal List<Coord> vertexNormals;
615 internal List<float> us; 615 internal List<float> us;
616 internal List<UVCoord> faceUVs; 616 internal List<UVCoord> faceUVs;
617 internal List<int> faceNumbers; 617 internal List<int> faceNumbers;
618 618
619 // use these for making individual meshes for each prim face 619 // use these for making individual meshes for each prim face
620 internal List<int> outerCoordIndices = null; 620 internal List<int> outerCoordIndices = null;
621 internal List<int> hollowCoordIndices = null; 621 internal List<int> hollowCoordIndices = null;
622 internal List<int> cut1CoordIndices = null; 622 internal List<int> cut1CoordIndices = null;
623 internal List<int> cut2CoordIndices = null; 623 internal List<int> cut2CoordIndices = null;
624 624
625 internal Coord faceNormal = new Coord(0.0f, 0.0f, 1.0f); 625 internal Coord faceNormal = new Coord(0.0f, 0.0f, 1.0f);
626 internal Coord cutNormal1 = new Coord(); 626 internal Coord cutNormal1 = new Coord();
627 internal Coord cutNormal2 = new Coord(); 627 internal Coord cutNormal2 = new Coord();
628 628
629 internal int numOuterVerts = 0; 629 internal int numOuterVerts = 0;
630 internal int numHollowVerts = 0; 630 internal int numHollowVerts = 0;
631 631
632 internal int outerFaceNumber = -1; 632 internal int outerFaceNumber = -1;
633 internal int hollowFaceNumber = -1; 633 internal int hollowFaceNumber = -1;
634 634
635 internal bool calcVertexNormals = false; 635 internal bool calcVertexNormals = false;
636 internal int bottomFaceNumber = 0; 636 internal int bottomFaceNumber = 0;
637 internal int numPrimFaces = 0; 637 internal int numPrimFaces = 0;
638 638
639 internal Profile() 639 internal Profile()
640 { 640 {
641 this.coords = new List<Coord>(); 641 this.coords = new List<Coord>();
642 this.faces = new List<Face>(); 642 this.faces = new List<Face>();
643 this.vertexNormals = new List<Coord>(); 643 this.vertexNormals = new List<Coord>();
644 this.us = new List<float>(); 644 this.us = new List<float>();
645 this.faceUVs = new List<UVCoord>(); 645 this.faceUVs = new List<UVCoord>();
646 this.faceNumbers = new List<int>(); 646 this.faceNumbers = new List<int>();
647 } 647 }
648 648
649 internal Profile(int sides, float profileStart, float profileEnd, float hollow, int hollowSides, bool createFaces, bool calcVertexNormals) 649 internal Profile(int sides, float profileStart, float profileEnd, float hollow, int hollowSides, bool createFaces, bool calcVertexNormals)
650 { 650 {
651 this.calcVertexNormals = calcVertexNormals; 651 this.calcVertexNormals = calcVertexNormals;
652 this.coords = new List<Coord>(); 652 this.coords = new List<Coord>();
653 this.faces = new List<Face>(); 653 this.faces = new List<Face>();
654 this.vertexNormals = new List<Coord>(); 654 this.vertexNormals = new List<Coord>();
655 this.us = new List<float>(); 655 this.us = new List<float>();
656 this.faceUVs = new List<UVCoord>(); 656 this.faceUVs = new List<UVCoord>();
657 this.faceNumbers = new List<int>(); 657 this.faceNumbers = new List<int>();
658 658
659 Coord center = new Coord(0.0f, 0.0f, 0.0f); 659 Coord center = new Coord(0.0f, 0.0f, 0.0f);
660 //bool hasCenter = false; 660 //bool hasCenter = false;
661 661
662 List<Coord> hollowCoords = new List<Coord>(); 662 List<Coord> hollowCoords = new List<Coord>();
663 List<Coord> hollowNormals = new List<Coord>(); 663 List<Coord> hollowNormals = new List<Coord>();
664 List<float> hollowUs = new List<float>(); 664 List<float> hollowUs = new List<float>();
665 665
666 if (calcVertexNormals) 666 if (calcVertexNormals)
667 { 667 {
668 this.outerCoordIndices = new List<int>(); 668 this.outerCoordIndices = new List<int>();
669 this.hollowCoordIndices = new List<int>(); 669 this.hollowCoordIndices = new List<int>();
670 this.cut1CoordIndices = new List<int>(); 670 this.cut1CoordIndices = new List<int>();
671 this.cut2CoordIndices = new List<int>(); 671 this.cut2CoordIndices = new List<int>();
672 } 672 }
673 673
674 bool hasHollow = (hollow > 0.0f); 674 bool hasHollow = (hollow > 0.0f);
675 675
676 bool hasProfileCut = (profileStart > 0.0f || profileEnd < 1.0f); 676 bool hasProfileCut = (profileStart > 0.0f || profileEnd < 1.0f);
677 677
678 AngleList angles = new AngleList(); 678 AngleList angles = new AngleList();
679 AngleList hollowAngles = new AngleList(); 679 AngleList hollowAngles = new AngleList();
680 680
681 float xScale = 0.5f; 681 float xScale = 0.5f;
682 float yScale = 0.5f; 682 float yScale = 0.5f;
683 if (sides == 4) // corners of a square are sqrt(2) from center 683 if (sides == 4) // corners of a square are sqrt(2) from center
684 { 684 {
685 xScale = 0.707f; 685 xScale = 0.707f;
686 yScale = 0.707f; 686 yScale = 0.707f;
687 } 687 }
688 688
689 float startAngle = profileStart * twoPi; 689 float startAngle = profileStart * twoPi;
690 float stopAngle = profileEnd * twoPi; 690 float stopAngle = profileEnd * twoPi;
691 691
692 try { angles.makeAngles(sides, startAngle, stopAngle); } 692 try { angles.makeAngles(sides, startAngle, stopAngle); }
693 catch (Exception ex) 693 catch (Exception ex)
694 { 694 {
695 695
696 errorMessage = "makeAngles failed: Exception: " + ex.ToString() 696 errorMessage = "makeAngles failed: Exception: " + ex.ToString()
697 + "\nsides: " + sides.ToString() + " startAngle: " + startAngle.ToString() + " stopAngle: " + stopAngle.ToString(); 697 + "\nsides: " + sides.ToString() + " startAngle: " + startAngle.ToString() + " stopAngle: " + stopAngle.ToString();
698 698
699 return; 699 return;
700 } 700 }
701 701
702 this.numOuterVerts = angles.angles.Count; 702 this.numOuterVerts = angles.angles.Count;
703 703
704 // flag to create as few triangles as possible for 3 or 4 side profile 704 // flag to create as few triangles as possible for 3 or 4 side profile
705 bool simpleFace = (sides < 5 && !hasHollow && !hasProfileCut); 705 bool simpleFace = (sides < 5 && !hasHollow && !hasProfileCut);
706 706
707 if (hasHollow) 707 if (hasHollow)
708 { 708 {
709 if (sides == hollowSides) 709 if (sides == hollowSides)
710 hollowAngles = angles; 710 hollowAngles = angles;
711 else 711 else
712 { 712 {
713 try { hollowAngles.makeAngles(hollowSides, startAngle, stopAngle); } 713 try { hollowAngles.makeAngles(hollowSides, startAngle, stopAngle); }
714 catch (Exception ex) 714 catch (Exception ex)
715 { 715 {
716 errorMessage = "makeAngles failed: Exception: " + ex.ToString() 716 errorMessage = "makeAngles failed: Exception: " + ex.ToString()
717 + "\nsides: " + sides.ToString() + " startAngle: " + startAngle.ToString() + " stopAngle: " + stopAngle.ToString(); 717 + "\nsides: " + sides.ToString() + " startAngle: " + startAngle.ToString() + " stopAngle: " + stopAngle.ToString();
718 718
719 return; 719 return;
720 } 720 }
721 } 721 }
722 this.numHollowVerts = hollowAngles.angles.Count; 722 this.numHollowVerts = hollowAngles.angles.Count;
723 } 723 }
724 else if (!simpleFace) 724 else if (!simpleFace)
725 { 725 {
726 this.coords.Add(center); 726 this.coords.Add(center);
727 //hasCenter = true; 727 //hasCenter = true;
728 if (this.calcVertexNormals) 728 if (this.calcVertexNormals)
729 this.vertexNormals.Add(new Coord(0.0f, 0.0f, 1.0f)); 729 this.vertexNormals.Add(new Coord(0.0f, 0.0f, 1.0f));
730 this.us.Add(0.0f); 730 this.us.Add(0.0f);
731 } 731 }
732 732
733 float z = 0.0f; 733 float z = 0.0f;
734 734
735 Angle angle; 735 Angle angle;
736 Coord newVert = new Coord(); 736 Coord newVert = new Coord();
737 if (hasHollow && hollowSides != sides) 737 if (hasHollow && hollowSides != sides)
738 { 738 {
739 int numHollowAngles = hollowAngles.angles.Count; 739 int numHollowAngles = hollowAngles.angles.Count;
740 for (int i = 0; i < numHollowAngles; i++) 740 for (int i = 0; i < numHollowAngles; i++)
741 { 741 {
742 angle = hollowAngles.angles[i]; 742 angle = hollowAngles.angles[i];
743 newVert.X = hollow * xScale * angle.X; 743 newVert.X = hollow * xScale * angle.X;
744 newVert.Y = hollow * yScale * angle.Y; 744 newVert.Y = hollow * yScale * angle.Y;
745 newVert.Z = z; 745 newVert.Z = z;
746 746
747 hollowCoords.Add(newVert); 747 hollowCoords.Add(newVert);
748 if (this.calcVertexNormals) 748 if (this.calcVertexNormals)
749 { 749 {
750 if (hollowSides < 5) 750 if (hollowSides < 5)
751 hollowNormals.Add(hollowAngles.normals[i].Invert()); 751 hollowNormals.Add(hollowAngles.normals[i].Invert());
752 else 752 else
753 hollowNormals.Add(new Coord(-angle.X, -angle.Y, 0.0f)); 753 hollowNormals.Add(new Coord(-angle.X, -angle.Y, 0.0f));
754 754
755 hollowUs.Add(angle.angle * hollow); 755 hollowUs.Add(angle.angle * hollow);
756 } 756 }
757 } 757 }
758 } 758 }
759 759
760 int index = 0; 760 int index = 0;
761 int numAngles = angles.angles.Count; 761 int numAngles = angles.angles.Count;
762 762
763 for (int i = 0; i < numAngles; i++) 763 for (int i = 0; i < numAngles; i++)
764 { 764 {
765 angle = angles.angles[i]; 765 angle = angles.angles[i];
766 newVert.X = angle.X * xScale; 766 newVert.X = angle.X * xScale;
767 newVert.Y = angle.Y * yScale; 767 newVert.Y = angle.Y * yScale;
768 newVert.Z = z; 768 newVert.Z = z;
769 this.coords.Add(newVert); 769 this.coords.Add(newVert);
770 if (this.calcVertexNormals) 770 if (this.calcVertexNormals)
771 { 771 {
772 this.outerCoordIndices.Add(this.coords.Count - 1); 772 this.outerCoordIndices.Add(this.coords.Count - 1);
773 773
774 if (sides < 5) 774 if (sides < 5)
775 { 775 {
776 this.vertexNormals.Add(angles.normals[i]); 776 this.vertexNormals.Add(angles.normals[i]);
777 float u = angle.angle; 777 float u = angle.angle;
778 this.us.Add(u); 778 this.us.Add(u);
779 } 779 }
780 else 780 else
781 { 781 {
782 this.vertexNormals.Add(new Coord(angle.X, angle.Y, 0.0f)); 782 this.vertexNormals.Add(new Coord(angle.X, angle.Y, 0.0f));
783 this.us.Add(angle.angle); 783 this.us.Add(angle.angle);
784 } 784 }
785 } 785 }
786 786
787 if (hasHollow) 787 if (hasHollow)
788 { 788 {
789 if (hollowSides == sides) 789 if (hollowSides == sides)
790 { 790 {
791 newVert.X *= hollow; 791 newVert.X *= hollow;
792 newVert.Y *= hollow; 792 newVert.Y *= hollow;
793 newVert.Z = z; 793 newVert.Z = z;
794 hollowCoords.Add(newVert); 794 hollowCoords.Add(newVert);
795 if (this.calcVertexNormals) 795 if (this.calcVertexNormals)
796 { 796 {
797 if (sides < 5) 797 if (sides < 5)
798 { 798 {
799 hollowNormals.Add(angles.normals[i].Invert()); 799 hollowNormals.Add(angles.normals[i].Invert());
800 } 800 }
801 801
802 else 802 else
803 hollowNormals.Add(new Coord(-angle.X, -angle.Y, 0.0f)); 803 hollowNormals.Add(new Coord(-angle.X, -angle.Y, 0.0f));
804 804
805 hollowUs.Add(angle.angle * hollow); 805 hollowUs.Add(angle.angle * hollow);
806 } 806 }
807 } 807 }
808 } 808 }
809 else if (!simpleFace && createFaces && angle.angle > 0.0001f) 809 else if (!simpleFace && createFaces && angle.angle > 0.0001f)
810 { 810 {
811 Face newFace = new Face(); 811 Face newFace = new Face();
812 newFace.v1 = 0; 812 newFace.v1 = 0;
813 newFace.v2 = index; 813 newFace.v2 = index;
814 newFace.v3 = index + 1; 814 newFace.v3 = index + 1;
815 815
816 this.faces.Add(newFace); 816 this.faces.Add(newFace);
817 } 817 }
818 index += 1; 818 index += 1;
819 } 819 }
820 820
821 if (hasHollow) 821 if (hasHollow)
822 { 822 {
823 hollowCoords.Reverse(); 823 hollowCoords.Reverse();
824 if (this.calcVertexNormals) 824 if (this.calcVertexNormals)
825 { 825 {
826 hollowNormals.Reverse(); 826 hollowNormals.Reverse();
827 hollowUs.Reverse(); 827 hollowUs.Reverse();
828 } 828 }
829 829
830 if (createFaces) 830 if (createFaces)
831 { 831 {
832 //int numOuterVerts = this.coords.Count; 832 //int numOuterVerts = this.coords.Count;
833 //numOuterVerts = this.coords.Count; 833 //numOuterVerts = this.coords.Count;
834 //int numHollowVerts = hollowCoords.Count; 834 //int numHollowVerts = hollowCoords.Count;
835 int numTotalVerts = this.numOuterVerts + this.numHollowVerts; 835 int numTotalVerts = this.numOuterVerts + this.numHollowVerts;
836 836
837 if (this.numOuterVerts == this.numHollowVerts) 837 if (this.numOuterVerts == this.numHollowVerts)
838 { 838 {
839 Face newFace = new Face(); 839 Face newFace = new Face();
840 840
841 for (int coordIndex = 0; coordIndex < this.numOuterVerts - 1; coordIndex++) 841 for (int coordIndex = 0; coordIndex < this.numOuterVerts - 1; coordIndex++)
842 { 842 {
843 newFace.v1 = coordIndex; 843 newFace.v1 = coordIndex;
844 newFace.v2 = coordIndex + 1; 844 newFace.v2 = coordIndex + 1;
845 newFace.v3 = numTotalVerts - coordIndex - 1; 845 newFace.v3 = numTotalVerts - coordIndex - 1;
846 this.faces.Add(newFace); 846 this.faces.Add(newFace);
847 847
848 newFace.v1 = coordIndex + 1; 848 newFace.v1 = coordIndex + 1;
849 newFace.v2 = numTotalVerts - coordIndex - 2; 849 newFace.v2 = numTotalVerts - coordIndex - 2;
850 newFace.v3 = numTotalVerts - coordIndex - 1; 850 newFace.v3 = numTotalVerts - coordIndex - 1;
851 this.faces.Add(newFace); 851 this.faces.Add(newFace);
852 } 852 }
853 } 853 }
854 else 854 else
855 { 855 {
856 if (this.numOuterVerts < this.numHollowVerts) 856 if (this.numOuterVerts < this.numHollowVerts)
857 { 857 {
858 Face newFace = new Face(); 858 Face newFace = new Face();
859 int j = 0; // j is the index for outer vertices 859 int j = 0; // j is the index for outer vertices
860 int maxJ = this.numOuterVerts - 1; 860 int maxJ = this.numOuterVerts - 1;
861 for (int i = 0; i < this.numHollowVerts; i++) // i is the index for inner vertices 861 for (int i = 0; i < this.numHollowVerts; i++) // i is the index for inner vertices
862 { 862 {
863 if (j < maxJ) 863 if (j < maxJ)
864 if (angles.angles[j + 1].angle - hollowAngles.angles[i].angle < hollowAngles.angles[i].angle - angles.angles[j].angle + 0.000001f) 864 if (angles.angles[j + 1].angle - hollowAngles.angles[i].angle < hollowAngles.angles[i].angle - angles.angles[j].angle + 0.000001f)
865 { 865 {
866 newFace.v1 = numTotalVerts - i - 1; 866 newFace.v1 = numTotalVerts - i - 1;
867 newFace.v2 = j; 867 newFace.v2 = j;
868 newFace.v3 = j + 1; 868 newFace.v3 = j + 1;
869 869
870 this.faces.Add(newFace); 870 this.faces.Add(newFace);
871 j += 1; 871 j += 1;
872 } 872 }
873 873
874 newFace.v1 = j; 874 newFace.v1 = j;
875 newFace.v2 = numTotalVerts - i - 2; 875 newFace.v2 = numTotalVerts - i - 2;
876 newFace.v3 = numTotalVerts - i - 1; 876 newFace.v3 = numTotalVerts - i - 1;
877 877
878 this.faces.Add(newFace); 878 this.faces.Add(newFace);
879 } 879 }
880 } 880 }
881 else // numHollowVerts < numOuterVerts 881 else // numHollowVerts < numOuterVerts
882 { 882 {
883 Face newFace = new Face(); 883 Face newFace = new Face();
884 int j = 0; // j is the index for inner vertices 884 int j = 0; // j is the index for inner vertices
885 int maxJ = this.numHollowVerts - 1; 885 int maxJ = this.numHollowVerts - 1;
886 for (int i = 0; i < this.numOuterVerts; i++) 886 for (int i = 0; i < this.numOuterVerts; i++)
887 { 887 {
888 if (j < maxJ) 888 if (j < maxJ)
889 if (hollowAngles.angles[j + 1].angle - angles.angles[i].angle < angles.angles[i].angle - hollowAngles.angles[j].angle + 0.000001f) 889 if (hollowAngles.angles[j + 1].angle - angles.angles[i].angle < angles.angles[i].angle - hollowAngles.angles[j].angle + 0.000001f)
890 { 890 {
891 newFace.v1 = i; 891 newFace.v1 = i;
892 newFace.v2 = numTotalVerts - j - 2; 892 newFace.v2 = numTotalVerts - j - 2;
893 newFace.v3 = numTotalVerts - j - 1; 893 newFace.v3 = numTotalVerts - j - 1;
894 894
895 this.faces.Add(newFace); 895 this.faces.Add(newFace);
896 j += 1; 896 j += 1;
897 } 897 }
898 898
899 newFace.v1 = numTotalVerts - j - 1; 899 newFace.v1 = numTotalVerts - j - 1;
900 newFace.v2 = i; 900 newFace.v2 = i;
901 newFace.v3 = i + 1; 901 newFace.v3 = i + 1;
902 902
903 this.faces.Add(newFace); 903 this.faces.Add(newFace);
904 } 904 }
905 } 905 }
906 } 906 }
907 } 907 }
908 908
909 if (calcVertexNormals) 909 if (calcVertexNormals)
910 { 910 {
911 foreach (Coord hc in hollowCoords) 911 foreach (Coord hc in hollowCoords)
912 { 912 {
913 this.coords.Add(hc); 913 this.coords.Add(hc);
914 hollowCoordIndices.Add(this.coords.Count - 1); 914 hollowCoordIndices.Add(this.coords.Count - 1);
915 } 915 }
916 } 916 }
917 else 917 else
918 this.coords.AddRange(hollowCoords); 918 this.coords.AddRange(hollowCoords);
919 919
920 if (this.calcVertexNormals) 920 if (this.calcVertexNormals)
921 { 921 {
922 this.vertexNormals.AddRange(hollowNormals); 922 this.vertexNormals.AddRange(hollowNormals);
923 this.us.AddRange(hollowUs); 923 this.us.AddRange(hollowUs);
924 924
925 } 925 }
926 } 926 }
927 927
928 if (simpleFace && createFaces) 928 if (simpleFace && createFaces)
929 { 929 {
930 if (sides == 3) 930 if (sides == 3)
931 this.faces.Add(new Face(0, 1, 2)); 931 this.faces.Add(new Face(0, 1, 2));
932 else if (sides == 4) 932 else if (sides == 4)
933 { 933 {
934 this.faces.Add(new Face(0, 1, 2)); 934 this.faces.Add(new Face(0, 1, 2));
935 this.faces.Add(new Face(0, 2, 3)); 935 this.faces.Add(new Face(0, 2, 3));
936 } 936 }
937 } 937 }
938 938
939 if (calcVertexNormals && hasProfileCut) 939 if (calcVertexNormals && hasProfileCut)
940 { 940 {
941 int lastOuterVertIndex = this.numOuterVerts - 1; 941 int lastOuterVertIndex = this.numOuterVerts - 1;
942 942
943 if (hasHollow) 943 if (hasHollow)
944 { 944 {
945 this.cut1CoordIndices.Add(0); 945 this.cut1CoordIndices.Add(0);
946 this.cut1CoordIndices.Add(this.coords.Count - 1); 946 this.cut1CoordIndices.Add(this.coords.Count - 1);
947 947
948 this.cut2CoordIndices.Add(lastOuterVertIndex + 1); 948 this.cut2CoordIndices.Add(lastOuterVertIndex + 1);
949 this.cut2CoordIndices.Add(lastOuterVertIndex); 949 this.cut2CoordIndices.Add(lastOuterVertIndex);
950 950
951 this.cutNormal1.X = this.coords[0].Y - this.coords[this.coords.Count - 1].Y; 951 this.cutNormal1.X = this.coords[0].Y - this.coords[this.coords.Count - 1].Y;
952 this.cutNormal1.Y = -(this.coords[0].X - this.coords[this.coords.Count - 1].X); 952 this.cutNormal1.Y = -(this.coords[0].X - this.coords[this.coords.Count - 1].X);
953 953
954 this.cutNormal2.X = this.coords[lastOuterVertIndex + 1].Y - this.coords[lastOuterVertIndex].Y; 954 this.cutNormal2.X = this.coords[lastOuterVertIndex + 1].Y - this.coords[lastOuterVertIndex].Y;
955 this.cutNormal2.Y = -(this.coords[lastOuterVertIndex + 1].X - this.coords[lastOuterVertIndex].X); 955 this.cutNormal2.Y = -(this.coords[lastOuterVertIndex + 1].X - this.coords[lastOuterVertIndex].X);
956 } 956 }
957 957
958 else 958 else
959 { 959 {
960 this.cut1CoordIndices.Add(0); 960 this.cut1CoordIndices.Add(0);
961 this.cut1CoordIndices.Add(1); 961 this.cut1CoordIndices.Add(1);
962 962
963 this.cut2CoordIndices.Add(lastOuterVertIndex); 963 this.cut2CoordIndices.Add(lastOuterVertIndex);
964 this.cut2CoordIndices.Add(0); 964 this.cut2CoordIndices.Add(0);
965 965
966 this.cutNormal1.X = this.vertexNormals[1].Y; 966 this.cutNormal1.X = this.vertexNormals[1].Y;
967 this.cutNormal1.Y = -this.vertexNormals[1].X; 967 this.cutNormal1.Y = -this.vertexNormals[1].X;
968 968
969 this.cutNormal2.X = -this.vertexNormals[this.vertexNormals.Count - 2].Y; 969 this.cutNormal2.X = -this.vertexNormals[this.vertexNormals.Count - 2].Y;
970 this.cutNormal2.Y = this.vertexNormals[this.vertexNormals.Count - 2].X; 970 this.cutNormal2.Y = this.vertexNormals[this.vertexNormals.Count - 2].X;
971 971
972 } 972 }
973 this.cutNormal1.Normalize(); 973 this.cutNormal1.Normalize();
974 this.cutNormal2.Normalize(); 974 this.cutNormal2.Normalize();
975 } 975 }
976 976
977 this.MakeFaceUVs(); 977 this.MakeFaceUVs();
978 978
979 hollowCoords = null; 979 hollowCoords = null;
980 hollowNormals = null; 980 hollowNormals = null;
981 hollowUs = null; 981 hollowUs = null;
982 982
983 if (calcVertexNormals) 983 if (calcVertexNormals)
984 { // calculate prim face numbers 984 { // calculate prim face numbers
985 985
986 // face number order is top, outer, hollow, bottom, start cut, end cut 986 // face number order is top, outer, hollow, bottom, start cut, end cut
987 // I know it's ugly but so is the whole concept of prim face numbers 987 // I know it's ugly but so is the whole concept of prim face numbers
988 988
989 int faceNum = 1; // start with outer faces 989 int faceNum = 1; // start with outer faces
990 this.outerFaceNumber = faceNum; 990 this.outerFaceNumber = faceNum;
991 991
992 int startVert = hasProfileCut && !hasHollow ? 1 : 0; 992 int startVert = hasProfileCut && !hasHollow ? 1 : 0;
993 if (startVert > 0) 993 if (startVert > 0)
994 this.faceNumbers.Add(-1); 994 this.faceNumbers.Add(-1);
995 for (int i = 0; i < this.numOuterVerts - 1; i++) 995 for (int i = 0; i < this.numOuterVerts - 1; i++)
996 //this.faceNumbers.Add(sides < 5 ? faceNum++ : faceNum); 996 //this.faceNumbers.Add(sides < 5 ? faceNum++ : faceNum);
997 this.faceNumbers.Add(sides < 5 && i < sides ? faceNum++ : faceNum); 997 this.faceNumbers.Add(sides < 5 && i < sides ? faceNum++ : faceNum);
998 998
999 //if (!hasHollow && !hasProfileCut) 999 //if (!hasHollow && !hasProfileCut)
1000 // this.bottomFaceNumber = faceNum++; 1000 // this.bottomFaceNumber = faceNum++;
1001 1001
1002 this.faceNumbers.Add(hasProfileCut ? -1 : faceNum++); 1002 this.faceNumbers.Add(hasProfileCut ? -1 : faceNum++);
1003 1003
1004 if (sides > 4 && (hasHollow || hasProfileCut)) 1004 if (sides > 4 && (hasHollow || hasProfileCut))
1005 faceNum++; 1005 faceNum++;
1006 1006
1007 if (sides < 5 && (hasHollow || hasProfileCut) && this.numOuterVerts < sides) 1007 if (sides < 5 && (hasHollow || hasProfileCut) && this.numOuterVerts < sides)
1008 faceNum++; 1008 faceNum++;
1009 1009
1010 if (hasHollow) 1010 if (hasHollow)
1011 { 1011 {
1012 for (int i = 0; i < this.numHollowVerts; i++) 1012 for (int i = 0; i < this.numHollowVerts; i++)
1013 this.faceNumbers.Add(faceNum); 1013 this.faceNumbers.Add(faceNum);
1014 1014
1015 this.hollowFaceNumber = faceNum++; 1015 this.hollowFaceNumber = faceNum++;
1016 } 1016 }
1017 //if (hasProfileCut || hasHollow) 1017 //if (hasProfileCut || hasHollow)
1018 // this.bottomFaceNumber = faceNum++; 1018 // this.bottomFaceNumber = faceNum++;
1019 this.bottomFaceNumber = faceNum++; 1019 this.bottomFaceNumber = faceNum++;
1020 1020
1021 if (hasHollow && hasProfileCut) 1021 if (hasHollow && hasProfileCut)
1022 this.faceNumbers.Add(faceNum++); 1022 this.faceNumbers.Add(faceNum++);
1023 1023
1024 for (int i = 0; i < this.faceNumbers.Count; i++) 1024 for (int i = 0; i < this.faceNumbers.Count; i++)
1025 if (this.faceNumbers[i] == -1) 1025 if (this.faceNumbers[i] == -1)
1026 this.faceNumbers[i] = faceNum++; 1026 this.faceNumbers[i] = faceNum++;
1027 1027
1028 this.numPrimFaces = faceNum; 1028 this.numPrimFaces = faceNum;
1029 } 1029 }
1030 1030
1031 } 1031 }
1032 1032
1033 internal void MakeFaceUVs() 1033 internal void MakeFaceUVs()
1034 { 1034 {
1035 this.faceUVs = new List<UVCoord>(); 1035 this.faceUVs = new List<UVCoord>();
1036 foreach (Coord c in this.coords) 1036 foreach (Coord c in this.coords)
1037 this.faceUVs.Add(new UVCoord(0.5f + c.X, 0.5f - c.Y)); 1037 this.faceUVs.Add(new UVCoord(0.5f + c.X, 0.5f - c.Y));
1038 } 1038 }
1039 1039
1040 internal Profile Copy() 1040 internal Profile Copy()
1041 { 1041 {
1042 return this.Copy(true); 1042 return this.Copy(true);
1043 } 1043 }
1044 1044
1045 internal Profile Copy(bool needFaces) 1045 internal Profile Copy(bool needFaces)
1046 { 1046 {
1047 Profile copy = new Profile(); 1047 Profile copy = new Profile();
1048 1048
1049 copy.coords.AddRange(this.coords); 1049 copy.coords.AddRange(this.coords);
1050 copy.faceUVs.AddRange(this.faceUVs); 1050 copy.faceUVs.AddRange(this.faceUVs);
1051 1051
1052 if (needFaces) 1052 if (needFaces)
1053 copy.faces.AddRange(this.faces); 1053 copy.faces.AddRange(this.faces);
1054 if ((copy.calcVertexNormals = this.calcVertexNormals) == true) 1054 if ((copy.calcVertexNormals = this.calcVertexNormals) == true)
1055 { 1055 {
1056 copy.vertexNormals.AddRange(this.vertexNormals); 1056 copy.vertexNormals.AddRange(this.vertexNormals);
1057 copy.faceNormal = this.faceNormal; 1057 copy.faceNormal = this.faceNormal;
1058 copy.cutNormal1 = this.cutNormal1; 1058 copy.cutNormal1 = this.cutNormal1;
1059 copy.cutNormal2 = this.cutNormal2; 1059 copy.cutNormal2 = this.cutNormal2;
1060 copy.us.AddRange(this.us); 1060 copy.us.AddRange(this.us);
1061 copy.faceNumbers.AddRange(this.faceNumbers); 1061 copy.faceNumbers.AddRange(this.faceNumbers);
1062 1062
1063 copy.cut1CoordIndices = new List<int>(this.cut1CoordIndices); 1063 copy.cut1CoordIndices = new List<int>(this.cut1CoordIndices);
1064 copy.cut2CoordIndices = new List<int>(this.cut2CoordIndices); 1064 copy.cut2CoordIndices = new List<int>(this.cut2CoordIndices);
1065 copy.hollowCoordIndices = new List<int>(this.hollowCoordIndices); 1065 copy.hollowCoordIndices = new List<int>(this.hollowCoordIndices);
1066 copy.outerCoordIndices = new List<int>(this.outerCoordIndices); 1066 copy.outerCoordIndices = new List<int>(this.outerCoordIndices);
1067 } 1067 }
1068 copy.numOuterVerts = this.numOuterVerts; 1068 copy.numOuterVerts = this.numOuterVerts;
1069 copy.numHollowVerts = this.numHollowVerts; 1069 copy.numHollowVerts = this.numHollowVerts;
1070 1070
1071 return copy; 1071 return copy;
1072 } 1072 }
1073 1073
1074 internal void AddPos(Coord v) 1074 internal void AddPos(Coord v)
1075 { 1075 {
1076 this.AddPos(v.X, v.Y, v.Z); 1076 this.AddPos(v.X, v.Y, v.Z);
1077 } 1077 }
1078 1078
1079 internal void AddPos(float x, float y, float z) 1079 internal void AddPos(float x, float y, float z)
1080 { 1080 {
1081 int i; 1081 int i;
1082 int numVerts = this.coords.Count; 1082 int numVerts = this.coords.Count;
1083 Coord vert; 1083 Coord vert;
1084 1084
1085 for (i = 0; i < numVerts; i++) 1085 for (i = 0; i < numVerts; i++)
1086 { 1086 {
1087 vert = this.coords[i]; 1087 vert = this.coords[i];
1088 vert.X += x; 1088 vert.X += x;
1089 vert.Y += y; 1089 vert.Y += y;
1090 vert.Z += z; 1090 vert.Z += z;
1091 this.coords[i] = vert; 1091 this.coords[i] = vert;
1092 } 1092 }
1093 } 1093 }
1094 1094
1095 internal void AddRot(Quat q) 1095 internal void AddRot(Quat q)
1096 { 1096 {
1097 int i; 1097 int i;
1098 int numVerts = this.coords.Count; 1098 int numVerts = this.coords.Count;
1099 1099
1100 for (i = 0; i < numVerts; i++) 1100 for (i = 0; i < numVerts; i++)
1101 this.coords[i] *= q; 1101 this.coords[i] *= q;
1102 1102
1103 if (this.calcVertexNormals) 1103 if (this.calcVertexNormals)
1104 { 1104 {
1105 int numNormals = this.vertexNormals.Count; 1105 int numNormals = this.vertexNormals.Count;
1106 for (i = 0; i < numNormals; i++) 1106 for (i = 0; i < numNormals; i++)
1107 this.vertexNormals[i] *= q; 1107 this.vertexNormals[i] *= q;
1108 1108
1109 this.faceNormal *= q; 1109 this.faceNormal *= q;
1110 this.cutNormal1 *= q; 1110 this.cutNormal1 *= q;
1111 this.cutNormal2 *= q; 1111 this.cutNormal2 *= q;
1112 1112
1113 } 1113 }
1114 } 1114 }
1115 1115
1116 internal void Scale(float x, float y) 1116 internal void Scale(float x, float y)
1117 { 1117 {
1118 int i; 1118 int i;
1119 int numVerts = this.coords.Count; 1119 int numVerts = this.coords.Count;
1120 Coord vert; 1120 Coord vert;
1121 1121
1122 for (i = 0; i < numVerts; i++) 1122 for (i = 0; i < numVerts; i++)
1123 { 1123 {
1124 vert = this.coords[i]; 1124 vert = this.coords[i];
1125 vert.X *= x; 1125 vert.X *= x;
1126 vert.Y *= y; 1126 vert.Y *= y;
1127 this.coords[i] = vert; 1127 this.coords[i] = vert;
1128 } 1128 }
1129 } 1129 }
1130 1130
1131 /// <summary> 1131 /// <summary>
1132 /// Changes order of the vertex indices and negates the center vertex normal. Does not alter vertex normals of radial vertices 1132 /// Changes order of the vertex indices and negates the center vertex normal. Does not alter vertex normals of radial vertices
1133 /// </summary> 1133 /// </summary>
1134 internal void FlipNormals() 1134 internal void FlipNormals()
1135 { 1135 {
1136 int i; 1136 int i;
1137 int numFaces = this.faces.Count; 1137 int numFaces = this.faces.Count;
1138 Face tmpFace; 1138 Face tmpFace;
1139 int tmp; 1139 int tmp;
1140 1140
1141 for (i = 0; i < numFaces; i++) 1141 for (i = 0; i < numFaces; i++)
1142 { 1142 {
1143 tmpFace = this.faces[i]; 1143 tmpFace = this.faces[i];
1144 tmp = tmpFace.v3; 1144 tmp = tmpFace.v3;
1145 tmpFace.v3 = tmpFace.v1; 1145 tmpFace.v3 = tmpFace.v1;
1146 tmpFace.v1 = tmp; 1146 tmpFace.v1 = tmp;
1147 this.faces[i] = tmpFace; 1147 this.faces[i] = tmpFace;
1148 } 1148 }
1149 1149
1150 if (this.calcVertexNormals) 1150 if (this.calcVertexNormals)
1151 { 1151 {
1152 int normalCount = this.vertexNormals.Count; 1152 int normalCount = this.vertexNormals.Count;
1153 if (normalCount > 0) 1153 if (normalCount > 0)
1154 { 1154 {
1155 Coord n = this.vertexNormals[normalCount - 1]; 1155 Coord n = this.vertexNormals[normalCount - 1];
1156 n.Z = -n.Z; 1156 n.Z = -n.Z;
1157 this.vertexNormals[normalCount - 1] = n; 1157 this.vertexNormals[normalCount - 1] = n;
1158 } 1158 }
1159 } 1159 }
1160 1160
1161 this.faceNormal.X = -this.faceNormal.X; 1161 this.faceNormal.X = -this.faceNormal.X;
1162 this.faceNormal.Y = -this.faceNormal.Y; 1162 this.faceNormal.Y = -this.faceNormal.Y;
1163 this.faceNormal.Z = -this.faceNormal.Z; 1163 this.faceNormal.Z = -this.faceNormal.Z;
1164 1164
1165 int numfaceUVs = this.faceUVs.Count; 1165 int numfaceUVs = this.faceUVs.Count;
1166 for (i = 0; i < numfaceUVs; i++) 1166 for (i = 0; i < numfaceUVs; i++)
1167 { 1167 {
1168 UVCoord uv = this.faceUVs[i]; 1168 UVCoord uv = this.faceUVs[i];
1169 uv.V = 1.0f - uv.V; 1169 uv.V = 1.0f - uv.V;
1170 this.faceUVs[i] = uv; 1170 this.faceUVs[i] = uv;
1171 } 1171 }
1172 } 1172 }
1173 1173
1174 internal void AddValue2FaceVertexIndices(int num) 1174 internal void AddValue2FaceVertexIndices(int num)
1175 { 1175 {
1176 int numFaces = this.faces.Count; 1176 int numFaces = this.faces.Count;
1177 Face tmpFace; 1177 Face tmpFace;
1178 for (int i = 0; i < numFaces; i++) 1178 for (int i = 0; i < numFaces; i++)
1179 { 1179 {
1180 tmpFace = this.faces[i]; 1180 tmpFace = this.faces[i];
1181 tmpFace.v1 += num; 1181 tmpFace.v1 += num;
1182 tmpFace.v2 += num; 1182 tmpFace.v2 += num;
1183 tmpFace.v3 += num; 1183 tmpFace.v3 += num;
1184 1184
1185 this.faces[i] = tmpFace; 1185 this.faces[i] = tmpFace;
1186 } 1186 }
1187 } 1187 }
1188 1188
1189 internal void AddValue2FaceNormalIndices(int num) 1189 internal void AddValue2FaceNormalIndices(int num)
1190 { 1190 {
1191 if (this.calcVertexNormals) 1191 if (this.calcVertexNormals)
1192 { 1192 {
1193 int numFaces = this.faces.Count; 1193 int numFaces = this.faces.Count;
1194 Face tmpFace; 1194 Face tmpFace;
1195 for (int i = 0; i < numFaces; i++) 1195 for (int i = 0; i < numFaces; i++)
1196 { 1196 {
1197 tmpFace = this.faces[i]; 1197 tmpFace = this.faces[i];
1198 tmpFace.n1 += num; 1198 tmpFace.n1 += num;
1199 tmpFace.n2 += num; 1199 tmpFace.n2 += num;
1200 tmpFace.n3 += num; 1200 tmpFace.n3 += num;
1201 1201
1202 this.faces[i] = tmpFace; 1202 this.faces[i] = tmpFace;
1203 } 1203 }
1204 } 1204 }
1205 } 1205 }
1206 1206
1207 internal void DumpRaw(String path, String name, String title) 1207 internal void DumpRaw(String path, String name, String title)
1208 { 1208 {
1209 if (path == null) 1209 if (path == null)
1210 return; 1210 return;
1211 String fileName = name + "_" + title + ".raw"; 1211 String fileName = name + "_" + title + ".raw";
1212 String completePath = System.IO.Path.Combine(path, fileName); 1212 String completePath = System.IO.Path.Combine(path, fileName);
1213 StreamWriter sw = new StreamWriter(completePath); 1213 StreamWriter sw = new StreamWriter(completePath);
1214 1214
1215 for (int i = 0; i < this.faces.Count; i++) 1215 for (int i = 0; i < this.faces.Count; i++)
1216 { 1216 {
1217 string s = this.coords[this.faces[i].v1].ToString(); 1217 string s = this.coords[this.faces[i].v1].ToString();
1218 s += " " + this.coords[this.faces[i].v2].ToString(); 1218 s += " " + this.coords[this.faces[i].v2].ToString();
1219 s += " " + this.coords[this.faces[i].v3].ToString(); 1219 s += " " + this.coords[this.faces[i].v3].ToString();
1220 1220
1221 sw.WriteLine(s); 1221 sw.WriteLine(s);
1222 } 1222 }
1223 1223
1224 sw.Close(); 1224 sw.Close();
1225 } 1225 }
1226 } 1226 }
1227 1227
1228 public struct PathNode 1228 public struct PathNode
1229 { 1229 {
1230 public Coord position; 1230 public Coord position;
1231 public Quat rotation; 1231 public Quat rotation;
1232 public float xScale; 1232 public float xScale;
1233 public float yScale; 1233 public float yScale;
1234 public float percentOfPath; 1234 public float percentOfPath;
1235 } 1235 }
1236 1236
1237 public enum PathType { Linear = 0, Circular = 1, Flexible = 2 } 1237 public enum PathType { Linear = 0, Circular = 1, Flexible = 2 }
1238 1238
1239 public class Path 1239 public class Path
1240 { 1240 {
1241 public List<PathNode> pathNodes = new List<PathNode>(); 1241 public List<PathNode> pathNodes = new List<PathNode>();
1242 1242
1243 public float twistBegin = 0.0f; 1243 public float twistBegin = 0.0f;
1244 public float twistEnd = 0.0f; 1244 public float twistEnd = 0.0f;
1245 public float topShearX = 0.0f; 1245 public float topShearX = 0.0f;
1246 public float topShearY = 0.0f; 1246 public float topShearY = 0.0f;
1247 public float pathCutBegin = 0.0f; 1247 public float pathCutBegin = 0.0f;
1248 public float pathCutEnd = 1.0f; 1248 public float pathCutEnd = 1.0f;
1249 public float dimpleBegin = 0.0f; 1249 public float dimpleBegin = 0.0f;
1250 public float dimpleEnd = 1.0f; 1250 public float dimpleEnd = 1.0f;
1251 public float skew = 0.0f; 1251 public float skew = 0.0f;
1252 public float holeSizeX = 1.0f; // called pathScaleX in pbs 1252 public float holeSizeX = 1.0f; // called pathScaleX in pbs
1253 public float holeSizeY = 0.25f; 1253 public float holeSizeY = 0.25f;
1254 public float taperX = 0.0f; 1254 public float taperX = 0.0f;
1255 public float taperY = 0.0f; 1255 public float taperY = 0.0f;
1256 public float radius = 0.0f; 1256 public float radius = 0.0f;
1257 public float revolutions = 1.0f; 1257 public float revolutions = 1.0f;
1258 public int stepsPerRevolution = 24; 1258 public int stepsPerRevolution = 24;
1259 1259
1260 private const float twoPi = 2.0f * (float)Math.PI; 1260 private const float twoPi = 2.0f * (float)Math.PI;
1261 1261
1262 public void Create(PathType pathType, int steps) 1262 public void Create(PathType pathType, int steps)
1263 { 1263 {
1264 if (pathType == PathType.Linear || pathType == PathType.Flexible) 1264 if (pathType == PathType.Linear || pathType == PathType.Flexible)
1265 { 1265 {
1266 int step = 0; 1266 int step = 0;
1267 1267
1268 float length = this.pathCutEnd - this.pathCutBegin; 1268 float length = this.pathCutEnd - this.pathCutBegin;
1269 float twistTotal = twistEnd - twistBegin; 1269 float twistTotal = twistEnd - twistBegin;
1270 float twistTotalAbs = Math.Abs(twistTotal); 1270 float twistTotalAbs = Math.Abs(twistTotal);
1271 if (twistTotalAbs > 0.01f) 1271 if (twistTotalAbs > 0.01f)
1272 steps += (int)(twistTotalAbs * 3.66); // dahlia's magic number 1272 steps += (int)(twistTotalAbs * 3.66); // dahlia's magic number
1273 1273
1274 float start = -0.5f; 1274 float start = -0.5f;
1275 float stepSize = length / (float)steps; 1275 float stepSize = length / (float)steps;
1276 float percentOfPathMultiplier = stepSize; 1276 float percentOfPathMultiplier = stepSize;
1277 float xOffset = 0.0f; 1277 float xOffset = 0.0f;
1278 float yOffset = 0.0f; 1278 float yOffset = 0.0f;
1279 float zOffset = start; 1279 float zOffset = start;
1280 float xOffsetStepIncrement = this.topShearX / steps; 1280 float xOffsetStepIncrement = this.topShearX / steps;
1281 float yOffsetStepIncrement = this.topShearY / steps; 1281 float yOffsetStepIncrement = this.topShearY / steps;
1282 1282
1283 float percentOfPath = this.pathCutBegin; 1283 float percentOfPath = this.pathCutBegin;
1284 zOffset += percentOfPath; 1284 zOffset += percentOfPath;
1285 1285
1286 // sanity checks 1286 // sanity checks
1287 1287
1288 bool done = false; 1288 bool done = false;
1289 1289
1290 while (!done) 1290 while (!done)
1291 { 1291 {
1292 PathNode newNode = new PathNode(); 1292 PathNode newNode = new PathNode();
1293 1293
1294 newNode.xScale = 1.0f; 1294 newNode.xScale = 1.0f;
1295 if (this.taperX == 0.0f) 1295 if (this.taperX == 0.0f)
1296 newNode.xScale = 1.0f; 1296 newNode.xScale = 1.0f;
1297 else if (this.taperX > 0.0f) 1297 else if (this.taperX > 0.0f)
1298 newNode.xScale = 1.0f - percentOfPath * this.taperX; 1298 newNode.xScale = 1.0f - percentOfPath * this.taperX;
1299 else newNode.xScale = 1.0f + (1.0f - percentOfPath) * this.taperX; 1299 else newNode.xScale = 1.0f + (1.0f - percentOfPath) * this.taperX;
1300 1300
1301 newNode.yScale = 1.0f; 1301 newNode.yScale = 1.0f;
1302 if (this.taperY == 0.0f) 1302 if (this.taperY == 0.0f)
1303 newNode.yScale = 1.0f; 1303 newNode.yScale = 1.0f;
1304 else if (this.taperY > 0.0f) 1304 else if (this.taperY > 0.0f)
1305 newNode.yScale = 1.0f - percentOfPath * this.taperY; 1305 newNode.yScale = 1.0f - percentOfPath * this.taperY;
1306 else newNode.yScale = 1.0f + (1.0f - percentOfPath) * this.taperY; 1306 else newNode.yScale = 1.0f + (1.0f - percentOfPath) * this.taperY;
1307 1307
1308 float twist = twistBegin + twistTotal * percentOfPath; 1308 float twist = twistBegin + twistTotal * percentOfPath;
1309 1309
1310 newNode.rotation = new Quat(new Coord(0.0f, 0.0f, 1.0f), twist); 1310 newNode.rotation = new Quat(new Coord(0.0f, 0.0f, 1.0f), twist);
1311 newNode.position = new Coord(xOffset, yOffset, zOffset); 1311 newNode.position = new Coord(xOffset, yOffset, zOffset);
1312 newNode.percentOfPath = percentOfPath; 1312 newNode.percentOfPath = percentOfPath;
1313 1313
1314 pathNodes.Add(newNode); 1314 pathNodes.Add(newNode);
1315 1315
1316 if (step < steps) 1316 if (step < steps)
1317 { 1317 {
1318 step += 1; 1318 step += 1;
1319 percentOfPath += percentOfPathMultiplier; 1319 percentOfPath += percentOfPathMultiplier;
1320 xOffset += xOffsetStepIncrement; 1320 xOffset += xOffsetStepIncrement;
1321 yOffset += yOffsetStepIncrement; 1321 yOffset += yOffsetStepIncrement;
1322 zOffset += stepSize; 1322 zOffset += stepSize;
1323 if (percentOfPath > this.pathCutEnd) 1323 if (percentOfPath > this.pathCutEnd)
1324 done = true; 1324 done = true;
1325 } 1325 }
1326 else done = true; 1326 else done = true;
1327 } 1327 }
1328 } // end of linear path code 1328 } // end of linear path code
1329 1329
1330 else // pathType == Circular 1330 else // pathType == Circular
1331 { 1331 {
1332 float twistTotal = twistEnd - twistBegin; 1332 float twistTotal = twistEnd - twistBegin;
1333 1333
1334 // if the profile has a lot of twist, add more layers otherwise the layers may overlap 1334 // if the profile has a lot of twist, add more layers otherwise the layers may overlap
1335 // and the resulting mesh may be quite inaccurate. This method is arbitrary and doesn't 1335 // and the resulting mesh may be quite inaccurate. This method is arbitrary and doesn't
1336 // accurately match the viewer 1336 // accurately match the viewer
1337 float twistTotalAbs = Math.Abs(twistTotal); 1337 float twistTotalAbs = Math.Abs(twistTotal);
1338 if (twistTotalAbs > 0.01f) 1338 if (twistTotalAbs > 0.01f)
1339 { 1339 {
1340 if (twistTotalAbs > Math.PI * 1.5f) 1340 if (twistTotalAbs > Math.PI * 1.5f)
1341 steps *= 2; 1341 steps *= 2;
1342 if (twistTotalAbs > Math.PI * 3.0f) 1342 if (twistTotalAbs > Math.PI * 3.0f)
1343 steps *= 2; 1343 steps *= 2;
1344 } 1344 }
1345 1345
1346 float yPathScale = this.holeSizeY * 0.5f; 1346 float yPathScale = this.holeSizeY * 0.5f;
1347 float pathLength = this.pathCutEnd - this.pathCutBegin; 1347 float pathLength = this.pathCutEnd - this.pathCutBegin;
1348 float totalSkew = this.skew * 2.0f * pathLength; 1348 float totalSkew = this.skew * 2.0f * pathLength;
1349 float skewStart = this.pathCutBegin * 2.0f * this.skew - this.skew; 1349 float skewStart = this.pathCutBegin * 2.0f * this.skew - this.skew;
1350 float xOffsetTopShearXFactor = this.topShearX * (0.25f + 0.5f * (0.5f - this.holeSizeY)); 1350 float xOffsetTopShearXFactor = this.topShearX * (0.25f + 0.5f * (0.5f - this.holeSizeY));
1351 float yShearCompensation = 1.0f + Math.Abs(this.topShearY) * 0.25f; 1351 float yShearCompensation = 1.0f + Math.Abs(this.topShearY) * 0.25f;
1352 1352
1353 // It's not quite clear what pushY (Y top shear) does, but subtracting it from the start and end 1353 // It's not quite clear what pushY (Y top shear) does, but subtracting it from the start and end
1354 // angles appears to approximate it's effects on path cut. Likewise, adding it to the angle used 1354 // angles appears to approximate it's effects on path cut. Likewise, adding it to the angle used
1355 // to calculate the sine for generating the path radius appears to approximate it's effects there 1355 // to calculate the sine for generating the path radius appears to approximate it's effects there
1356 // too, but there are some subtle differences in the radius which are noticeable as the prim size 1356 // too, but there are some subtle differences in the radius which are noticeable as the prim size
1357 // increases and it may affect megaprims quite a bit. The effect of the Y top shear parameter on 1357 // increases and it may affect megaprims quite a bit. The effect of the Y top shear parameter on
1358 // the meshes generated with this technique appear nearly identical in shape to the same prims when 1358 // the meshes generated with this technique appear nearly identical in shape to the same prims when
1359 // displayed by the viewer. 1359 // displayed by the viewer.
1360 1360
1361 float startAngle = (twoPi * this.pathCutBegin * this.revolutions) - this.topShearY * 0.9f; 1361 float startAngle = (twoPi * this.pathCutBegin * this.revolutions) - this.topShearY * 0.9f;
1362 float endAngle = (twoPi * this.pathCutEnd * this.revolutions) - this.topShearY * 0.9f; 1362 float endAngle = (twoPi * this.pathCutEnd * this.revolutions) - this.topShearY * 0.9f;
1363 float stepSize = twoPi / this.stepsPerRevolution; 1363 float stepSize = twoPi / this.stepsPerRevolution;
1364 1364
1365 int step = (int)(startAngle / stepSize); 1365 int step = (int)(startAngle / stepSize);
1366 float angle = startAngle; 1366 float angle = startAngle;
1367 1367
1368 bool done = false; 1368 bool done = false;
1369 while (!done) // loop through the length of the path and add the layers 1369 while (!done) // loop through the length of the path and add the layers
1370 { 1370 {
1371 PathNode newNode = new PathNode(); 1371 PathNode newNode = new PathNode();
1372 1372
1373 float xProfileScale = (1.0f - Math.Abs(this.skew)) * this.holeSizeX; 1373 float xProfileScale = (1.0f - Math.Abs(this.skew)) * this.holeSizeX;
1374 float yProfileScale = this.holeSizeY; 1374 float yProfileScale = this.holeSizeY;
1375 1375
1376 float percentOfPath = angle / (twoPi * this.revolutions); 1376 float percentOfPath = angle / (twoPi * this.revolutions);
1377 float percentOfAngles = (angle - startAngle) / (endAngle - startAngle); 1377 float percentOfAngles = (angle - startAngle) / (endAngle - startAngle);
1378 1378
1379 if (this.taperX > 0.01f) 1379 if (this.taperX > 0.01f)
1380 xProfileScale *= 1.0f - percentOfPath * this.taperX; 1380 xProfileScale *= 1.0f - percentOfPath * this.taperX;
1381 else if (this.taperX < -0.01f) 1381 else if (this.taperX < -0.01f)
1382 xProfileScale *= 1.0f + (1.0f - percentOfPath) * this.taperX; 1382 xProfileScale *= 1.0f + (1.0f - percentOfPath) * this.taperX;
1383 1383
1384 if (this.taperY > 0.01f) 1384 if (this.taperY > 0.01f)
1385 yProfileScale *= 1.0f - percentOfPath * this.taperY; 1385 yProfileScale *= 1.0f - percentOfPath * this.taperY;
1386 else if (this.taperY < -0.01f) 1386 else if (this.taperY < -0.01f)
1387 yProfileScale *= 1.0f + (1.0f - percentOfPath) * this.taperY; 1387 yProfileScale *= 1.0f + (1.0f - percentOfPath) * this.taperY;
1388 1388
1389 newNode.xScale = xProfileScale; 1389 newNode.xScale = xProfileScale;
1390 newNode.yScale = yProfileScale; 1390 newNode.yScale = yProfileScale;
1391 1391
1392 float radiusScale = 1.0f; 1392 float radiusScale = 1.0f;
1393 if (this.radius > 0.001f) 1393 if (this.radius > 0.001f)
1394 radiusScale = 1.0f - this.radius * percentOfPath; 1394 radiusScale = 1.0f - this.radius * percentOfPath;
1395 else if (this.radius < 0.001f) 1395 else if (this.radius < 0.001f)
1396 radiusScale = 1.0f + this.radius * (1.0f - percentOfPath); 1396 radiusScale = 1.0f + this.radius * (1.0f - percentOfPath);
1397 1397
1398 float twist = twistBegin + twistTotal * percentOfPath; 1398 float twist = twistBegin + twistTotal * percentOfPath;
1399 1399
1400 float xOffset = 0.5f * (skewStart + totalSkew * percentOfAngles); 1400 float xOffset = 0.5f * (skewStart + totalSkew * percentOfAngles);
1401 xOffset += (float)Math.Sin(angle) * xOffsetTopShearXFactor; 1401 xOffset += (float)Math.Sin(angle) * xOffsetTopShearXFactor;
1402 1402
1403 float yOffset = yShearCompensation * (float)Math.Cos(angle) * (0.5f - yPathScale) * radiusScale; 1403 float yOffset = yShearCompensation * (float)Math.Cos(angle) * (0.5f - yPathScale) * radiusScale;
1404 1404
1405 float zOffset = (float)Math.Sin(angle + this.topShearY) * (0.5f - yPathScale) * radiusScale; 1405 float zOffset = (float)Math.Sin(angle + this.topShearY) * (0.5f - yPathScale) * radiusScale;
1406 1406
1407 newNode.position = new Coord(xOffset, yOffset, zOffset); 1407 newNode.position = new Coord(xOffset, yOffset, zOffset);
1408 1408
1409 // now orient the rotation of the profile layer relative to it's position on the path 1409 // now orient the rotation of the profile layer relative to it's position on the path
1410 // adding taperY to the angle used to generate the quat appears to approximate the viewer 1410 // adding taperY to the angle used to generate the quat appears to approximate the viewer
1411 1411
1412 newNode.rotation = new Quat(new Coord(1.0f, 0.0f, 0.0f), angle + this.topShearY); 1412 newNode.rotation = new Quat(new Coord(1.0f, 0.0f, 0.0f), angle + this.topShearY);
1413 1413
1414 // next apply twist rotation to the profile layer 1414 // next apply twist rotation to the profile layer
1415 if (twistTotal != 0.0f || twistBegin != 0.0f) 1415 if (twistTotal != 0.0f || twistBegin != 0.0f)
1416 newNode.rotation *= new Quat(new Coord(0.0f, 0.0f, 1.0f), twist); 1416 newNode.rotation *= new Quat(new Coord(0.0f, 0.0f, 1.0f), twist);
1417 1417
1418 newNode.percentOfPath = percentOfPath; 1418 newNode.percentOfPath = percentOfPath;
1419 1419
1420 pathNodes.Add(newNode); 1420 pathNodes.Add(newNode);
1421 1421
1422 // calculate terms for next iteration 1422 // calculate terms for next iteration
1423 // calculate the angle for the next iteration of the loop 1423 // calculate the angle for the next iteration of the loop
1424 1424
1425 if (angle >= endAngle - 0.01) 1425 if (angle >= endAngle - 0.01)
1426 done = true; 1426 done = true;
1427 else 1427 else
1428 { 1428 {
1429 step += 1; 1429 step += 1;
1430 angle = stepSize * step; 1430 angle = stepSize * step;
1431 if (angle > endAngle) 1431 if (angle > endAngle)
1432 angle = endAngle; 1432 angle = endAngle;
1433 } 1433 }
1434 } 1434 }
1435 } 1435 }
1436 } 1436 }
1437 } 1437 }
1438 1438
1439 public class PrimMesh 1439 public class PrimMesh
1440 { 1440 {
1441 public string errorMessage = ""; 1441 public string errorMessage = "";
1442 private const float twoPi = 2.0f * (float)Math.PI; 1442 private const float twoPi = 2.0f * (float)Math.PI;
1443 1443
1444 public List<Coord> coords; 1444 public List<Coord> coords;
1445 public List<Coord> normals; 1445 public List<Coord> normals;
1446 public List<Face> faces; 1446 public List<Face> faces;
1447 1447
1448 public List<ViewerFace> viewerFaces; 1448 public List<ViewerFace> viewerFaces;
1449 1449
1450 private int sides = 4; 1450 private int sides = 4;
1451 private int hollowSides = 4; 1451 private int hollowSides = 4;
1452 private float profileStart = 0.0f; 1452 private float profileStart = 0.0f;
1453 private float profileEnd = 1.0f; 1453 private float profileEnd = 1.0f;
1454 private float hollow = 0.0f; 1454 private float hollow = 0.0f;
1455 public int twistBegin = 0; 1455 public int twistBegin = 0;
1456 public int twistEnd = 0; 1456 public int twistEnd = 0;
1457 public float topShearX = 0.0f; 1457 public float topShearX = 0.0f;
1458 public float topShearY = 0.0f; 1458 public float topShearY = 0.0f;
1459 public float pathCutBegin = 0.0f; 1459 public float pathCutBegin = 0.0f;
1460 public float pathCutEnd = 1.0f; 1460 public float pathCutEnd = 1.0f;
1461 public float dimpleBegin = 0.0f; 1461 public float dimpleBegin = 0.0f;
1462 public float dimpleEnd = 1.0f; 1462 public float dimpleEnd = 1.0f;
1463 public float skew = 0.0f; 1463 public float skew = 0.0f;
1464 public float holeSizeX = 1.0f; // called pathScaleX in pbs 1464 public float holeSizeX = 1.0f; // called pathScaleX in pbs
1465 public float holeSizeY = 0.25f; 1465 public float holeSizeY = 0.25f;
1466 public float taperX = 0.0f; 1466 public float taperX = 0.0f;
1467 public float taperY = 0.0f; 1467 public float taperY = 0.0f;
1468 public float radius = 0.0f; 1468 public float radius = 0.0f;
1469 public float revolutions = 1.0f; 1469 public float revolutions = 1.0f;
1470 public int stepsPerRevolution = 24; 1470 public int stepsPerRevolution = 24;
1471 1471
1472 private int profileOuterFaceNumber = -1; 1472 private int profileOuterFaceNumber = -1;
1473 private int profileHollowFaceNumber = -1; 1473 private int profileHollowFaceNumber = -1;
1474 1474
1475 private bool hasProfileCut = false; 1475 private bool hasProfileCut = false;
1476 private bool hasHollow = false; 1476 private bool hasHollow = false;
1477 public bool calcVertexNormals = false; 1477 public bool calcVertexNormals = false;
1478 private bool normalsProcessed = false; 1478 private bool normalsProcessed = false;
1479 public bool viewerMode = false; 1479 public bool viewerMode = false;
1480 public bool sphereMode = false; 1480 public bool sphereMode = false;
1481 1481
1482 public int numPrimFaces = 0; 1482 public int numPrimFaces = 0;
1483 1483
1484 /// <summary> 1484 /// <summary>
1485 /// Human readable string representation of the parameters used to create a mesh. 1485 /// Human readable string representation of the parameters used to create a mesh.
1486 /// </summary> 1486 /// </summary>
1487 /// <returns></returns> 1487 /// <returns></returns>
1488 public string ParamsToDisplayString() 1488 public string ParamsToDisplayString()
1489 { 1489 {
1490 string s = ""; 1490 string s = "";
1491 s += "sides..................: " + this.sides.ToString(); 1491 s += "sides..................: " + this.sides.ToString();
1492 s += "\nhollowSides..........: " + this.hollowSides.ToString(); 1492 s += "\nhollowSides..........: " + this.hollowSides.ToString();
1493 s += "\nprofileStart.........: " + this.profileStart.ToString(); 1493 s += "\nprofileStart.........: " + this.profileStart.ToString();
1494 s += "\nprofileEnd...........: " + this.profileEnd.ToString(); 1494 s += "\nprofileEnd...........: " + this.profileEnd.ToString();
1495 s += "\nhollow...............: " + this.hollow.ToString(); 1495 s += "\nhollow...............: " + this.hollow.ToString();
1496 s += "\ntwistBegin...........: " + this.twistBegin.ToString(); 1496 s += "\ntwistBegin...........: " + this.twistBegin.ToString();
1497 s += "\ntwistEnd.............: " + this.twistEnd.ToString(); 1497 s += "\ntwistEnd.............: " + this.twistEnd.ToString();
1498 s += "\ntopShearX............: " + this.topShearX.ToString(); 1498 s += "\ntopShearX............: " + this.topShearX.ToString();
1499 s += "\ntopShearY............: " + this.topShearY.ToString(); 1499 s += "\ntopShearY............: " + this.topShearY.ToString();
1500 s += "\npathCutBegin.........: " + this.pathCutBegin.ToString(); 1500 s += "\npathCutBegin.........: " + this.pathCutBegin.ToString();
1501 s += "\npathCutEnd...........: " + this.pathCutEnd.ToString(); 1501 s += "\npathCutEnd...........: " + this.pathCutEnd.ToString();
1502 s += "\ndimpleBegin..........: " + this.dimpleBegin.ToString(); 1502 s += "\ndimpleBegin..........: " + this.dimpleBegin.ToString();
1503 s += "\ndimpleEnd............: " + this.dimpleEnd.ToString(); 1503 s += "\ndimpleEnd............: " + this.dimpleEnd.ToString();
1504 s += "\nskew.................: " + this.skew.ToString(); 1504 s += "\nskew.................: " + this.skew.ToString();
1505 s += "\nholeSizeX............: " + this.holeSizeX.ToString(); 1505 s += "\nholeSizeX............: " + this.holeSizeX.ToString();
1506 s += "\nholeSizeY............: " + this.holeSizeY.ToString(); 1506 s += "\nholeSizeY............: " + this.holeSizeY.ToString();
1507 s += "\ntaperX...............: " + this.taperX.ToString(); 1507 s += "\ntaperX...............: " + this.taperX.ToString();
1508 s += "\ntaperY...............: " + this.taperY.ToString(); 1508 s += "\ntaperY...............: " + this.taperY.ToString();
1509 s += "\nradius...............: " + this.radius.ToString(); 1509 s += "\nradius...............: " + this.radius.ToString();
1510 s += "\nrevolutions..........: " + this.revolutions.ToString(); 1510 s += "\nrevolutions..........: " + this.revolutions.ToString();
1511 s += "\nstepsPerRevolution...: " + this.stepsPerRevolution.ToString(); 1511 s += "\nstepsPerRevolution...: " + this.stepsPerRevolution.ToString();
1512 s += "\nsphereMode...........: " + this.sphereMode.ToString(); 1512 s += "\nsphereMode...........: " + this.sphereMode.ToString();
1513 s += "\nhasProfileCut........: " + this.hasProfileCut.ToString(); 1513 s += "\nhasProfileCut........: " + this.hasProfileCut.ToString();
1514 s += "\nhasHollow............: " + this.hasHollow.ToString(); 1514 s += "\nhasHollow............: " + this.hasHollow.ToString();
1515 s += "\nviewerMode...........: " + this.viewerMode.ToString(); 1515 s += "\nviewerMode...........: " + this.viewerMode.ToString();
1516 1516
1517 return s; 1517 return s;
1518 } 1518 }
1519 1519
1520 public int ProfileOuterFaceNumber 1520 public int ProfileOuterFaceNumber
1521 { 1521 {
1522 get { return profileOuterFaceNumber; } 1522 get { return profileOuterFaceNumber; }
1523 } 1523 }
1524 1524
1525 public int ProfileHollowFaceNumber 1525 public int ProfileHollowFaceNumber
1526 { 1526 {
1527 get { return profileHollowFaceNumber; } 1527 get { return profileHollowFaceNumber; }
1528 } 1528 }
1529 1529
1530 public bool HasProfileCut 1530 public bool HasProfileCut
1531 { 1531 {
1532 get { return hasProfileCut; } 1532 get { return hasProfileCut; }
1533 } 1533 }
1534 1534
1535 public bool HasHollow 1535 public bool HasHollow
1536 { 1536 {
1537 get { return hasHollow; } 1537 get { return hasHollow; }
1538 } 1538 }
1539 1539
1540 1540
1541 /// <summary> 1541 /// <summary>
1542 /// Constructs a PrimMesh object and creates the profile for extrusion. 1542 /// Constructs a PrimMesh object and creates the profile for extrusion.
1543 /// </summary> 1543 /// </summary>
1544 /// <param name="sides"></param> 1544 /// <param name="sides"></param>
1545 /// <param name="profileStart"></param> 1545 /// <param name="profileStart"></param>
1546 /// <param name="profileEnd"></param> 1546 /// <param name="profileEnd"></param>
1547 /// <param name="hollow"></param> 1547 /// <param name="hollow"></param>
1548 /// <param name="hollowSides"></param> 1548 /// <param name="hollowSides"></param>
1549 public PrimMesh(int sides, float profileStart, float profileEnd, float hollow, int hollowSides) 1549 public PrimMesh(int sides, float profileStart, float profileEnd, float hollow, int hollowSides)
1550 { 1550 {
1551 this.coords = new List<Coord>(); 1551 this.coords = new List<Coord>();
1552 this.faces = new List<Face>(); 1552 this.faces = new List<Face>();
1553 1553
1554 this.sides = sides; 1554 this.sides = sides;
1555 this.profileStart = profileStart; 1555 this.profileStart = profileStart;
1556 this.profileEnd = profileEnd; 1556 this.profileEnd = profileEnd;
1557 this.hollow = hollow; 1557 this.hollow = hollow;
1558 this.hollowSides = hollowSides; 1558 this.hollowSides = hollowSides;
1559 1559
1560 if (sides < 3) 1560 if (sides < 3)
1561 this.sides = 3; 1561 this.sides = 3;
1562 if (hollowSides < 3) 1562 if (hollowSides < 3)
1563 this.hollowSides = 3; 1563 this.hollowSides = 3;
1564 if (profileStart < 0.0f) 1564 if (profileStart < 0.0f)
1565 this.profileStart = 0.0f; 1565 this.profileStart = 0.0f;
1566 if (profileEnd > 1.0f) 1566 if (profileEnd > 1.0f)
1567 this.profileEnd = 1.0f; 1567 this.profileEnd = 1.0f;
1568 if (profileEnd < 0.02f) 1568 if (profileEnd < 0.02f)
1569 this.profileEnd = 0.02f; 1569 this.profileEnd = 0.02f;
1570 if (profileStart >= profileEnd) 1570 if (profileStart >= profileEnd)
1571 this.profileStart = profileEnd - 0.02f; 1571 this.profileStart = profileEnd - 0.02f;
1572 if (hollow > 0.99f) 1572 if (hollow > 0.99f)
1573 this.hollow = 0.99f; 1573 this.hollow = 0.99f;
1574 if (hollow < 0.0f) 1574 if (hollow < 0.0f)
1575 this.hollow = 0.0f; 1575 this.hollow = 0.0f;
1576 1576
1577 //if (sphereMode) 1577 //if (sphereMode)
1578 // this.hasProfileCut = this.profileEnd - this.profileStart < 0.4999f; 1578 // this.hasProfileCut = this.profileEnd - this.profileStart < 0.4999f;
1579 //else 1579 //else
1580 // //this.hasProfileCut = (this.profileStart > 0.0f || this.profileEnd < 1.0f); 1580 // //this.hasProfileCut = (this.profileStart > 0.0f || this.profileEnd < 1.0f);
1581 // this.hasProfileCut = this.profileEnd - this.profileStart < 0.9999f; 1581 // this.hasProfileCut = this.profileEnd - this.profileStart < 0.9999f;
1582 //this.hasHollow = (this.hollow > 0.001f); 1582 //this.hasHollow = (this.hollow > 0.001f);
1583 } 1583 }
1584 1584
1585 /// <summary> 1585 /// <summary>
1586 /// Extrudes a profile along a path. 1586 /// Extrudes a profile along a path.
1587 /// </summary> 1587 /// </summary>
1588 public void Extrude(PathType pathType) 1588 public void Extrude(PathType pathType)
1589 { 1589 {
1590 bool needEndFaces = false; 1590 bool needEndFaces = false;
1591 1591
1592 this.coords = new List<Coord>(); 1592 this.coords = new List<Coord>();
1593 this.faces = new List<Face>(); 1593 this.faces = new List<Face>();
1594 1594
1595 if (this.viewerMode) 1595 if (this.viewerMode)
1596 { 1596 {
1597 this.viewerFaces = new List<ViewerFace>(); 1597 this.viewerFaces = new List<ViewerFace>();
1598 this.calcVertexNormals = true; 1598 this.calcVertexNormals = true;
1599 } 1599 }
1600 1600
1601 if (this.calcVertexNormals) 1601 if (this.calcVertexNormals)
1602 this.normals = new List<Coord>(); 1602 this.normals = new List<Coord>();
1603 1603
1604 int steps = 1; 1604 int steps = 1;
1605 1605
1606 float length = this.pathCutEnd - this.pathCutBegin; 1606 float length = this.pathCutEnd - this.pathCutBegin;
1607 normalsProcessed = false; 1607 normalsProcessed = false;
1608 1608
1609 if (this.viewerMode && this.sides == 3) 1609 if (this.viewerMode && this.sides == 3)
1610 { 1610 {
1611 // prisms don't taper well so add some vertical resolution 1611 // prisms don't taper well so add some vertical resolution
1612 // other prims may benefit from this but just do prisms for now 1612 // other prims may benefit from this but just do prisms for now
1613 if (Math.Abs(this.taperX) > 0.01 || Math.Abs(this.taperY) > 0.01) 1613 if (Math.Abs(this.taperX) > 0.01 || Math.Abs(this.taperY) > 0.01)
1614 steps = (int)(steps * 4.5 * length); 1614 steps = (int)(steps * 4.5 * length);
1615 } 1615 }
1616 1616
1617 if (sphereMode) 1617 if (sphereMode)
1618 this.hasProfileCut = this.profileEnd - this.profileStart < 0.4999f; 1618 this.hasProfileCut = this.profileEnd - this.profileStart < 0.4999f;
1619 else 1619 else
1620 //this.hasProfileCut = (this.profileStart > 0.0f || this.profileEnd < 1.0f); 1620 //this.hasProfileCut = (this.profileStart > 0.0f || this.profileEnd < 1.0f);
1621 this.hasProfileCut = this.profileEnd - this.profileStart < 0.9999f; 1621 this.hasProfileCut = this.profileEnd - this.profileStart < 0.9999f;
1622 this.hasHollow = (this.hollow > 0.001f); 1622 this.hasHollow = (this.hollow > 0.001f);
1623 1623
1624 float twistBegin = this.twistBegin / 360.0f * twoPi; 1624 float twistBegin = this.twistBegin / 360.0f * twoPi;
1625 float twistEnd = this.twistEnd / 360.0f * twoPi; 1625 float twistEnd = this.twistEnd / 360.0f * twoPi;
1626 float twistTotal = twistEnd - twistBegin; 1626 float twistTotal = twistEnd - twistBegin;
1627 float twistTotalAbs = Math.Abs(twistTotal); 1627 float twistTotalAbs = Math.Abs(twistTotal);
1628 if (twistTotalAbs > 0.01f) 1628 if (twistTotalAbs > 0.01f)
1629 steps += (int)(twistTotalAbs * 3.66); // dahlia's magic number 1629 steps += (int)(twistTotalAbs * 3.66); // dahlia's magic number
1630 1630
1631 float hollow = this.hollow; 1631 float hollow = this.hollow;
1632 1632
1633 // sanity checks 1633 // sanity checks
1634 float initialProfileRot = 0.0f; 1634 float initialProfileRot = 0.0f;
1635 if (pathType == PathType.Circular) 1635 if (pathType == PathType.Circular)
1636 { 1636 {
1637 if (this.sides == 3) 1637 if (this.sides == 3)
1638 { 1638 {
1639 initialProfileRot = (float)Math.PI; 1639 initialProfileRot = (float)Math.PI;
1640 if (this.hollowSides == 4) 1640 if (this.hollowSides == 4)
1641 { 1641 {
1642 if (hollow > 0.7f) 1642 if (hollow > 0.7f)
1643 hollow = 0.7f; 1643 hollow = 0.7f;
1644 hollow *= 0.707f; 1644 hollow *= 0.707f;
1645 } 1645 }
1646 else hollow *= 0.5f; 1646 else hollow *= 0.5f;
1647 } 1647 }
1648 else if (this.sides == 4) 1648 else if (this.sides == 4)
1649 { 1649 {
1650 initialProfileRot = 0.25f * (float)Math.PI; 1650 initialProfileRot = 0.25f * (float)Math.PI;
1651 if (this.hollowSides != 4) 1651 if (this.hollowSides != 4)
1652 hollow *= 0.707f; 1652 hollow *= 0.707f;
1653 } 1653 }
1654 else if (this.sides > 4) 1654 else if (this.sides > 4)
1655 { 1655 {
1656 initialProfileRot = (float)Math.PI; 1656 initialProfileRot = (float)Math.PI;
1657 if (this.hollowSides == 4) 1657 if (this.hollowSides == 4)
1658 { 1658 {
1659 if (hollow > 0.7f) 1659 if (hollow > 0.7f)
1660 hollow = 0.7f; 1660 hollow = 0.7f;
1661 hollow /= 0.7f; 1661 hollow /= 0.7f;
1662 } 1662 }
1663 } 1663 }
1664 } 1664 }
1665 else 1665 else
1666 { 1666 {
1667 if (this.sides == 3) 1667 if (this.sides == 3)
1668 { 1668 {
1669 if (this.hollowSides == 4) 1669 if (this.hollowSides == 4)
1670 { 1670 {
1671 if (hollow > 0.7f) 1671 if (hollow > 0.7f)
1672 hollow = 0.7f; 1672 hollow = 0.7f;
1673 hollow *= 0.707f; 1673 hollow *= 0.707f;
1674 } 1674 }
1675 else hollow *= 0.5f; 1675 else hollow *= 0.5f;
1676 } 1676 }
1677 else if (this.sides == 4) 1677 else if (this.sides == 4)
1678 { 1678 {
1679 initialProfileRot = 1.25f * (float)Math.PI; 1679 initialProfileRot = 1.25f * (float)Math.PI;
1680 if (this.hollowSides != 4) 1680 if (this.hollowSides != 4)
1681 hollow *= 0.707f; 1681 hollow *= 0.707f;
1682 } 1682 }
1683 else if (this.sides == 24 && this.hollowSides == 4) 1683 else if (this.sides == 24 && this.hollowSides == 4)
1684 hollow *= 1.414f; 1684 hollow *= 1.414f;
1685 } 1685 }
1686 1686
1687 Profile profile = new Profile(this.sides, this.profileStart, this.profileEnd, hollow, this.hollowSides, true, calcVertexNormals); 1687 Profile profile = new Profile(this.sides, this.profileStart, this.profileEnd, hollow, this.hollowSides, true, calcVertexNormals);
1688 this.errorMessage = profile.errorMessage; 1688 this.errorMessage = profile.errorMessage;
1689 1689
1690 this.numPrimFaces = profile.numPrimFaces; 1690 this.numPrimFaces = profile.numPrimFaces;
1691 1691
1692 //profileOuterFaceNumber = profile.faceNumbers[0]; 1692 //profileOuterFaceNumber = profile.faceNumbers[0];
1693 //if (!needEndFaces) 1693 //if (!needEndFaces)
1694 // profileOuterFaceNumber--; 1694 // profileOuterFaceNumber--;
1695 //profileOuterFaceNumber = needEndFaces ? 1 : 0; 1695 //profileOuterFaceNumber = needEndFaces ? 1 : 0;
1696 1696
1697 1697
1698 //if (hasHollow) 1698 //if (hasHollow)
1699 //{ 1699 //{
1700 // if (needEndFaces) 1700 // if (needEndFaces)
1701 // profileHollowFaceNumber = profile.faceNumbers[profile.numOuterVerts + 1]; 1701 // profileHollowFaceNumber = profile.faceNumbers[profile.numOuterVerts + 1];
1702 // else 1702 // else
1703 // profileHollowFaceNumber = profile.faceNumbers[profile.numOuterVerts] - 1; 1703 // profileHollowFaceNumber = profile.faceNumbers[profile.numOuterVerts] - 1;
1704 //} 1704 //}
1705 1705
1706 1706
1707 profileOuterFaceNumber = profile.outerFaceNumber; 1707 profileOuterFaceNumber = profile.outerFaceNumber;
1708 if (!needEndFaces) 1708 if (!needEndFaces)
1709 profileOuterFaceNumber--; 1709 profileOuterFaceNumber--;
1710 1710
1711 if (hasHollow) 1711 if (hasHollow)
1712 { 1712 {
1713 profileHollowFaceNumber = profile.hollowFaceNumber; 1713 profileHollowFaceNumber = profile.hollowFaceNumber;
1714 if (!needEndFaces) 1714 if (!needEndFaces)
1715 profileHollowFaceNumber--; 1715 profileHollowFaceNumber--;
1716 } 1716 }
1717 1717
1718 int cut1Vert = -1; 1718 int cut1Vert = -1;
1719 int cut2Vert = -1; 1719 int cut2Vert = -1;
1720 if (hasProfileCut) 1720 if (hasProfileCut)
1721 { 1721 {
1722 cut1Vert = hasHollow ? profile.coords.Count - 1 : 0; 1722 cut1Vert = hasHollow ? profile.coords.Count - 1 : 0;
1723 cut2Vert = hasHollow ? profile.numOuterVerts - 1 : profile.numOuterVerts; 1723 cut2Vert = hasHollow ? profile.numOuterVerts - 1 : profile.numOuterVerts;
1724 } 1724 }
1725 1725
1726 if (initialProfileRot != 0.0f) 1726 if (initialProfileRot != 0.0f)
1727 { 1727 {
1728 profile.AddRot(new Quat(new Coord(0.0f, 0.0f, 1.0f), initialProfileRot)); 1728 profile.AddRot(new Quat(new Coord(0.0f, 0.0f, 1.0f), initialProfileRot));
1729 if (viewerMode) 1729 if (viewerMode)
1730 profile.MakeFaceUVs(); 1730 profile.MakeFaceUVs();
1731 } 1731 }
1732 1732
1733 Coord lastCutNormal1 = new Coord(); 1733 Coord lastCutNormal1 = new Coord();
1734 Coord lastCutNormal2 = new Coord(); 1734 Coord lastCutNormal2 = new Coord();
1735 float lastV = 1.0f; 1735 float lastV = 1.0f;
1736 1736
1737 Path path = new Path(); 1737 Path path = new Path();
1738 path.twistBegin = twistBegin; 1738 path.twistBegin = twistBegin;
1739 path.twistEnd = twistEnd; 1739 path.twistEnd = twistEnd;
1740 path.topShearX = topShearX; 1740 path.topShearX = topShearX;
1741 path.topShearY = topShearY; 1741 path.topShearY = topShearY;
1742 path.pathCutBegin = pathCutBegin; 1742 path.pathCutBegin = pathCutBegin;
1743 path.pathCutEnd = pathCutEnd; 1743 path.pathCutEnd = pathCutEnd;
1744 path.dimpleBegin = dimpleBegin; 1744 path.dimpleBegin = dimpleBegin;
1745 path.dimpleEnd = dimpleEnd; 1745 path.dimpleEnd = dimpleEnd;
1746 path.skew = skew; 1746 path.skew = skew;
1747 path.holeSizeX = holeSizeX; 1747 path.holeSizeX = holeSizeX;
1748 path.holeSizeY = holeSizeY; 1748 path.holeSizeY = holeSizeY;
1749 path.taperX = taperX; 1749 path.taperX = taperX;
1750 path.taperY = taperY; 1750 path.taperY = taperY;
1751 path.radius = radius; 1751 path.radius = radius;
1752 path.revolutions = revolutions; 1752 path.revolutions = revolutions;
1753 path.stepsPerRevolution = stepsPerRevolution; 1753 path.stepsPerRevolution = stepsPerRevolution;
1754 1754
1755 path.Create(pathType, steps); 1755 path.Create(pathType, steps);
1756 1756
1757 1757
1758 if (pathType == PathType.Circular) 1758 if (pathType == PathType.Circular)
1759 { 1759 {
1760 needEndFaces = false; 1760 needEndFaces = false;
1761 if (this.pathCutBegin != 0.0f || this.pathCutEnd != 1.0f) 1761 if (this.pathCutBegin != 0.0f || this.pathCutEnd != 1.0f)
1762 needEndFaces = true; 1762 needEndFaces = true;
1763 else if (this.taperX != 0.0f || this.taperY != 0.0f) 1763 else if (this.taperX != 0.0f || this.taperY != 0.0f)
1764 needEndFaces = true; 1764 needEndFaces = true;
1765 else if (this.skew != 0.0f) 1765 else if (this.skew != 0.0f)
1766 needEndFaces = true; 1766 needEndFaces = true;
1767 else if (twistTotal != 0.0f) 1767 else if (twistTotal != 0.0f)
1768 needEndFaces = true; 1768 needEndFaces = true;
1769 else if (this.radius != 0.0f) 1769 else if (this.radius != 0.0f)
1770 needEndFaces = true; 1770 needEndFaces = true;
1771 } 1771 }
1772 else needEndFaces = true; 1772 else needEndFaces = true;
1773 1773
1774 for (int nodeIndex = 0; nodeIndex < path.pathNodes.Count; nodeIndex++) 1774 for (int nodeIndex = 0; nodeIndex < path.pathNodes.Count; nodeIndex++)
1775 { 1775 {
1776 PathNode node = path.pathNodes[nodeIndex]; 1776 PathNode node = path.pathNodes[nodeIndex];
1777 Profile newLayer = profile.Copy(); 1777 Profile newLayer = profile.Copy();
1778 newLayer.Scale(node.xScale, node.yScale); 1778 newLayer.Scale(node.xScale, node.yScale);
1779 1779
1780 newLayer.AddRot(node.rotation); 1780 newLayer.AddRot(node.rotation);
1781 newLayer.AddPos(node.position); 1781 newLayer.AddPos(node.position);
1782 1782
1783 if (needEndFaces && nodeIndex == 0) 1783 if (needEndFaces && nodeIndex == 0)
1784 { 1784 {
1785 newLayer.FlipNormals(); 1785 newLayer.FlipNormals();
1786 1786
1787 // add the top faces to the viewerFaces list here 1787 // add the top faces to the viewerFaces list here
1788 if (this.viewerMode) 1788 if (this.viewerMode)
1789 { 1789 {
1790 Coord faceNormal = newLayer.faceNormal; 1790 Coord faceNormal = newLayer.faceNormal;
1791 ViewerFace newViewerFace = new ViewerFace(profile.bottomFaceNumber); 1791 ViewerFace newViewerFace = new ViewerFace(profile.bottomFaceNumber);
1792 int numFaces = newLayer.faces.Count; 1792 int numFaces = newLayer.faces.Count;
1793 List<Face> faces = newLayer.faces; 1793 List<Face> faces = newLayer.faces;
1794 1794
1795 for (int i = 0; i < numFaces; i++) 1795 for (int i = 0; i < numFaces; i++)
1796 { 1796 {
1797 Face face = faces[i]; 1797 Face face = faces[i];
1798 newViewerFace.v1 = newLayer.coords[face.v1]; 1798 newViewerFace.v1 = newLayer.coords[face.v1];
1799 newViewerFace.v2 = newLayer.coords[face.v2]; 1799 newViewerFace.v2 = newLayer.coords[face.v2];
1800 newViewerFace.v3 = newLayer.coords[face.v3]; 1800 newViewerFace.v3 = newLayer.coords[face.v3];
1801 1801
1802 newViewerFace.coordIndex1 = face.v1; 1802 newViewerFace.coordIndex1 = face.v1;
1803 newViewerFace.coordIndex2 = face.v2; 1803 newViewerFace.coordIndex2 = face.v2;
1804 newViewerFace.coordIndex3 = face.v3; 1804 newViewerFace.coordIndex3 = face.v3;
1805 1805
1806 newViewerFace.n1 = faceNormal; 1806 newViewerFace.n1 = faceNormal;
1807 newViewerFace.n2 = faceNormal; 1807 newViewerFace.n2 = faceNormal;
1808 newViewerFace.n3 = faceNormal; 1808 newViewerFace.n3 = faceNormal;
1809 1809
1810 newViewerFace.uv1 = newLayer.faceUVs[face.v1]; 1810 newViewerFace.uv1 = newLayer.faceUVs[face.v1];
1811 newViewerFace.uv2 = newLayer.faceUVs[face.v2]; 1811 newViewerFace.uv2 = newLayer.faceUVs[face.v2];
1812 newViewerFace.uv3 = newLayer.faceUVs[face.v3]; 1812 newViewerFace.uv3 = newLayer.faceUVs[face.v3];
1813 1813
1814 this.viewerFaces.Add(newViewerFace); 1814 this.viewerFaces.Add(newViewerFace);
1815 } 1815 }
1816 } 1816 }
1817 } // if (nodeIndex == 0) 1817 } // if (nodeIndex == 0)
1818 1818
1819 // append this layer 1819 // append this layer
1820 1820
1821 int coordsLen = this.coords.Count; 1821 int coordsLen = this.coords.Count;
1822 newLayer.AddValue2FaceVertexIndices(coordsLen); 1822 newLayer.AddValue2FaceVertexIndices(coordsLen);
1823 1823
1824 this.coords.AddRange(newLayer.coords); 1824 this.coords.AddRange(newLayer.coords);
1825 1825
1826 if (this.calcVertexNormals) 1826 if (this.calcVertexNormals)
1827 { 1827 {
1828 newLayer.AddValue2FaceNormalIndices(this.normals.Count); 1828 newLayer.AddValue2FaceNormalIndices(this.normals.Count);
1829 this.normals.AddRange(newLayer.vertexNormals); 1829 this.normals.AddRange(newLayer.vertexNormals);
1830 } 1830 }
1831 1831
1832 if (node.percentOfPath < this.pathCutBegin + 0.01f || node.percentOfPath > this.pathCutEnd - 0.01f) 1832 if (node.percentOfPath < this.pathCutBegin + 0.01f || node.percentOfPath > this.pathCutEnd - 0.01f)
1833 this.faces.AddRange(newLayer.faces); 1833 this.faces.AddRange(newLayer.faces);
1834 1834
1835 // fill faces between layers 1835 // fill faces between layers
1836 1836
1837 int numVerts = newLayer.coords.Count; 1837 int numVerts = newLayer.coords.Count;
1838 Face newFace = new Face(); 1838 Face newFace = new Face();
1839 1839
1840 if (nodeIndex > 0) 1840 if (nodeIndex > 0)
1841 { 1841 {
1842 int startVert = coordsLen + 1; 1842 int startVert = coordsLen + 1;
1843 int endVert = this.coords.Count; 1843 int endVert = this.coords.Count;
1844 1844
1845 if (sides < 5 || this.hasProfileCut || this.hasHollow) 1845 if (sides < 5 || this.hasProfileCut || this.hasHollow)
1846 startVert--; 1846 startVert--;
1847 1847
1848 for (int i = startVert; i < endVert; i++) 1848 for (int i = startVert; i < endVert; i++)
1849 { 1849 {
1850 int iNext = i + 1; 1850 int iNext = i + 1;
1851 if (i == endVert - 1) 1851 if (i == endVert - 1)
1852 iNext = startVert; 1852 iNext = startVert;
1853 1853
1854 int whichVert = i - startVert; 1854 int whichVert = i - startVert;
1855 1855
1856 newFace.v1 = i; 1856 newFace.v1 = i;
1857 newFace.v2 = i - numVerts; 1857 newFace.v2 = i - numVerts;
1858 newFace.v3 = iNext - numVerts; 1858 newFace.v3 = iNext - numVerts;
1859 this.faces.Add(newFace); 1859 this.faces.Add(newFace);
1860 1860
1861 newFace.v2 = iNext - numVerts; 1861 newFace.v2 = iNext - numVerts;
1862 newFace.v3 = iNext; 1862 newFace.v3 = iNext;
1863 this.faces.Add(newFace); 1863 this.faces.Add(newFace);
1864 1864
1865 if (this.viewerMode) 1865 if (this.viewerMode)
1866 { 1866 {
1867 // add the side faces to the list of viewerFaces here 1867 // add the side faces to the list of viewerFaces here
1868 1868
1869 int primFaceNum = profile.faceNumbers[whichVert]; 1869 int primFaceNum = profile.faceNumbers[whichVert];
1870 if (!needEndFaces) 1870 if (!needEndFaces)
1871 primFaceNum -= 1; 1871 primFaceNum -= 1;
1872 1872
1873 ViewerFace newViewerFace1 = new ViewerFace(primFaceNum); 1873 ViewerFace newViewerFace1 = new ViewerFace(primFaceNum);
1874 ViewerFace newViewerFace2 = new ViewerFace(primFaceNum); 1874 ViewerFace newViewerFace2 = new ViewerFace(primFaceNum);
1875 1875
1876 float u1 = newLayer.us[whichVert]; 1876 float u1 = newLayer.us[whichVert];
1877 float u2 = 1.0f; 1877 float u2 = 1.0f;
1878 if (whichVert < newLayer.us.Count - 1) 1878 if (whichVert < newLayer.us.Count - 1)
1879 u2 = newLayer.us[whichVert + 1]; 1879 u2 = newLayer.us[whichVert + 1];
1880 1880
1881 if (whichVert == cut1Vert || whichVert == cut2Vert) 1881 if (whichVert == cut1Vert || whichVert == cut2Vert)
1882 { 1882 {
1883 u1 = 0.0f; 1883 u1 = 0.0f;
1884 u2 = 1.0f; 1884 u2 = 1.0f;
1885 } 1885 }
1886 else if (sides < 5) 1886 else if (sides < 5)
1887 { 1887 {
1888 if (whichVert < profile.numOuterVerts) 1888 if (whichVert < profile.numOuterVerts)
1889 { // boxes and prisms have one texture face per side of the prim, so the U values have to be scaled 1889 { // boxes and prisms have one texture face per side of the prim, so the U values have to be scaled
1890 // to reflect the entire texture width 1890 // to reflect the entire texture width
1891 u1 *= sides; 1891 u1 *= sides;
1892 u2 *= sides; 1892 u2 *= sides;
1893 u2 -= (int)u1; 1893 u2 -= (int)u1;
1894 u1 -= (int)u1; 1894 u1 -= (int)u1;
1895 if (u2 < 0.1f) 1895 if (u2 < 0.1f)
1896 u2 = 1.0f; 1896 u2 = 1.0f;
1897 //this.profileOuterFaceNumber = primFaceNum; 1897 //this.profileOuterFaceNumber = primFaceNum;
1898 } 1898 }
1899 else if (whichVert > profile.coords.Count - profile.numHollowVerts - 1) 1899 else if (whichVert > profile.coords.Count - profile.numHollowVerts - 1)
1900 { 1900 {
1901 u1 *= 2.0f; 1901 u1 *= 2.0f;
1902 u2 *= 2.0f; 1902 u2 *= 2.0f;
1903 //this.profileHollowFaceNumber = primFaceNum; 1903 //this.profileHollowFaceNumber = primFaceNum;
1904 } 1904 }
1905 } 1905 }
1906 1906
1907 newViewerFace1.uv1.U = u1; 1907 newViewerFace1.uv1.U = u1;
1908 newViewerFace1.uv2.U = u1; 1908 newViewerFace1.uv2.U = u1;
1909 newViewerFace1.uv3.U = u2; 1909 newViewerFace1.uv3.U = u2;
1910 1910
1911 newViewerFace1.uv1.V = 1.0f - node.percentOfPath; 1911 newViewerFace1.uv1.V = 1.0f - node.percentOfPath;
1912 newViewerFace1.uv2.V = lastV; 1912 newViewerFace1.uv2.V = lastV;
1913 newViewerFace1.uv3.V = lastV; 1913 newViewerFace1.uv3.V = lastV;
1914 1914
1915 newViewerFace2.uv1.U = u1; 1915 newViewerFace2.uv1.U = u1;
1916 newViewerFace2.uv2.U = u2; 1916 newViewerFace2.uv2.U = u2;
1917 newViewerFace2.uv3.U = u2; 1917 newViewerFace2.uv3.U = u2;
1918 1918
1919 newViewerFace2.uv1.V = 1.0f - node.percentOfPath; 1919 newViewerFace2.uv1.V = 1.0f - node.percentOfPath;
1920 newViewerFace2.uv2.V = lastV; 1920 newViewerFace2.uv2.V = lastV;
1921 newViewerFace2.uv3.V = 1.0f - node.percentOfPath; 1921 newViewerFace2.uv3.V = 1.0f - node.percentOfPath;
1922 1922
1923 newViewerFace1.v1 = this.coords[i]; 1923 newViewerFace1.v1 = this.coords[i];
1924 newViewerFace1.v2 = this.coords[i - numVerts]; 1924 newViewerFace1.v2 = this.coords[i - numVerts];
1925 newViewerFace1.v3 = this.coords[iNext - numVerts]; 1925 newViewerFace1.v3 = this.coords[iNext - numVerts];
1926 1926
1927 newViewerFace2.v1 = this.coords[i]; 1927 newViewerFace2.v1 = this.coords[i];
1928 newViewerFace2.v2 = this.coords[iNext - numVerts]; 1928 newViewerFace2.v2 = this.coords[iNext - numVerts];
1929 newViewerFace2.v3 = this.coords[iNext]; 1929 newViewerFace2.v3 = this.coords[iNext];
1930 1930
1931 newViewerFace1.coordIndex1 = i; 1931 newViewerFace1.coordIndex1 = i;
1932 newViewerFace1.coordIndex2 = i - numVerts; 1932 newViewerFace1.coordIndex2 = i - numVerts;
1933 newViewerFace1.coordIndex3 = iNext - numVerts; 1933 newViewerFace1.coordIndex3 = iNext - numVerts;
1934 1934
1935 newViewerFace2.coordIndex1 = i; 1935 newViewerFace2.coordIndex1 = i;
1936 newViewerFace2.coordIndex2 = iNext - numVerts; 1936 newViewerFace2.coordIndex2 = iNext - numVerts;
1937 newViewerFace2.coordIndex3 = iNext; 1937 newViewerFace2.coordIndex3 = iNext;
1938 1938
1939 // profile cut faces 1939 // profile cut faces
1940 if (whichVert == cut1Vert) 1940 if (whichVert == cut1Vert)
1941 { 1941 {
1942 newViewerFace1.n1 = newLayer.cutNormal1; 1942 newViewerFace1.n1 = newLayer.cutNormal1;
1943 newViewerFace1.n2 = newViewerFace1.n3 = lastCutNormal1; 1943 newViewerFace1.n2 = newViewerFace1.n3 = lastCutNormal1;
1944 1944
1945 newViewerFace2.n1 = newViewerFace2.n3 = newLayer.cutNormal1; 1945 newViewerFace2.n1 = newViewerFace2.n3 = newLayer.cutNormal1;
1946 newViewerFace2.n2 = lastCutNormal1; 1946 newViewerFace2.n2 = lastCutNormal1;
1947 } 1947 }
1948 else if (whichVert == cut2Vert) 1948 else if (whichVert == cut2Vert)
1949 { 1949 {
1950 newViewerFace1.n1 = newLayer.cutNormal2; 1950 newViewerFace1.n1 = newLayer.cutNormal2;
1951 newViewerFace1.n2 = newViewerFace1.n3 = lastCutNormal2; 1951 newViewerFace1.n2 = newViewerFace1.n3 = lastCutNormal2;
1952 1952
1953 newViewerFace2.n1 = newViewerFace2.n3 = newLayer.cutNormal2; 1953 newViewerFace2.n1 = newViewerFace2.n3 = newLayer.cutNormal2;
1954 newViewerFace2.n2 = lastCutNormal2; 1954 newViewerFace2.n2 = lastCutNormal2;
1955 } 1955 }
1956 1956
1957 else // outer and hollow faces 1957 else // outer and hollow faces
1958 { 1958 {
1959 if ((sides < 5 && whichVert < newLayer.numOuterVerts) || (hollowSides < 5 && whichVert >= newLayer.numOuterVerts)) 1959 if ((sides < 5 && whichVert < newLayer.numOuterVerts) || (hollowSides < 5 && whichVert >= newLayer.numOuterVerts))
1960 { // looks terrible when path is twisted... need vertex normals here 1960 { // looks terrible when path is twisted... need vertex normals here
1961 newViewerFace1.CalcSurfaceNormal(); 1961 newViewerFace1.CalcSurfaceNormal();
1962 newViewerFace2.CalcSurfaceNormal(); 1962 newViewerFace2.CalcSurfaceNormal();
1963 } 1963 }
1964 else 1964 else
1965 { 1965 {
1966 newViewerFace1.n1 = this.normals[i]; 1966 newViewerFace1.n1 = this.normals[i];
1967 newViewerFace1.n2 = this.normals[i - numVerts]; 1967 newViewerFace1.n2 = this.normals[i - numVerts];
1968 newViewerFace1.n3 = this.normals[iNext - numVerts]; 1968 newViewerFace1.n3 = this.normals[iNext - numVerts];
1969 1969
1970 newViewerFace2.n1 = this.normals[i]; 1970 newViewerFace2.n1 = this.normals[i];
1971 newViewerFace2.n2 = this.normals[iNext - numVerts]; 1971 newViewerFace2.n2 = this.normals[iNext - numVerts];
1972 newViewerFace2.n3 = this.normals[iNext]; 1972 newViewerFace2.n3 = this.normals[iNext];
1973 } 1973 }
1974 } 1974 }
1975 1975
1976 this.viewerFaces.Add(newViewerFace1); 1976 this.viewerFaces.Add(newViewerFace1);
1977 this.viewerFaces.Add(newViewerFace2); 1977 this.viewerFaces.Add(newViewerFace2);
1978 1978
1979 } 1979 }
1980 } 1980 }
1981 } 1981 }
1982 1982
1983 lastCutNormal1 = newLayer.cutNormal1; 1983 lastCutNormal1 = newLayer.cutNormal1;
1984 lastCutNormal2 = newLayer.cutNormal2; 1984 lastCutNormal2 = newLayer.cutNormal2;
1985 lastV = 1.0f - node.percentOfPath; 1985 lastV = 1.0f - node.percentOfPath;
1986 1986
1987 if (needEndFaces && nodeIndex == path.pathNodes.Count - 1 && viewerMode) 1987 if (needEndFaces && nodeIndex == path.pathNodes.Count - 1 && viewerMode)
1988 { 1988 {
1989 // add the top faces to the viewerFaces list here 1989 // add the top faces to the viewerFaces list here
1990 Coord faceNormal = newLayer.faceNormal; 1990 Coord faceNormal = newLayer.faceNormal;
1991 ViewerFace newViewerFace = new ViewerFace(); 1991 ViewerFace newViewerFace = new ViewerFace();
1992 newViewerFace.primFaceNumber = 0; 1992 newViewerFace.primFaceNumber = 0;
1993 int numFaces = newLayer.faces.Count; 1993 int numFaces = newLayer.faces.Count;
1994 List<Face> faces = newLayer.faces; 1994 List<Face> faces = newLayer.faces;
1995 1995
1996 for (int i = 0; i < numFaces; i++) 1996 for (int i = 0; i < numFaces; i++)
1997 { 1997 {
1998 Face face = faces[i]; 1998 Face face = faces[i];
1999 newViewerFace.v1 = newLayer.coords[face.v1 - coordsLen]; 1999 newViewerFace.v1 = newLayer.coords[face.v1 - coordsLen];
2000 newViewerFace.v2 = newLayer.coords[face.v2 - coordsLen]; 2000 newViewerFace.v2 = newLayer.coords[face.v2 - coordsLen];
2001 newViewerFace.v3 = newLayer.coords[face.v3 - coordsLen]; 2001 newViewerFace.v3 = newLayer.coords[face.v3 - coordsLen];
2002 2002
2003 newViewerFace.coordIndex1 = face.v1 - coordsLen; 2003 newViewerFace.coordIndex1 = face.v1 - coordsLen;
2004 newViewerFace.coordIndex2 = face.v2 - coordsLen; 2004 newViewerFace.coordIndex2 = face.v2 - coordsLen;
2005 newViewerFace.coordIndex3 = face.v3 - coordsLen; 2005 newViewerFace.coordIndex3 = face.v3 - coordsLen;
2006 2006
2007 newViewerFace.n1 = faceNormal; 2007 newViewerFace.n1 = faceNormal;
2008 newViewerFace.n2 = faceNormal; 2008 newViewerFace.n2 = faceNormal;
2009 newViewerFace.n3 = faceNormal; 2009 newViewerFace.n3 = faceNormal;
2010 2010
2011 newViewerFace.uv1 = newLayer.faceUVs[face.v1 - coordsLen]; 2011 newViewerFace.uv1 = newLayer.faceUVs[face.v1 - coordsLen];
2012 newViewerFace.uv2 = newLayer.faceUVs[face.v2 - coordsLen]; 2012 newViewerFace.uv2 = newLayer.faceUVs[face.v2 - coordsLen];
2013 newViewerFace.uv3 = newLayer.faceUVs[face.v3 - coordsLen]; 2013 newViewerFace.uv3 = newLayer.faceUVs[face.v3 - coordsLen];
2014 2014
2015 this.viewerFaces.Add(newViewerFace); 2015 this.viewerFaces.Add(newViewerFace);
2016 } 2016 }
2017 } 2017 }
2018 2018
2019 2019
2020 } // for (int nodeIndex = 0; nodeIndex < path.pathNodes.Count; nodeIndex++) 2020 } // for (int nodeIndex = 0; nodeIndex < path.pathNodes.Count; nodeIndex++)
2021 2021
2022 } 2022 }
2023 2023
2024 2024
2025 /// <summary> 2025 /// <summary>
2026 /// DEPRICATED - use Extrude(PathType.Linear) instead 2026 /// DEPRICATED - use Extrude(PathType.Linear) instead
2027 /// Extrudes a profile along a straight line path. Used for prim types box, cylinder, and prism. 2027 /// Extrudes a profile along a straight line path. Used for prim types box, cylinder, and prism.
2028 /// </summary> 2028 /// </summary>
2029 /// 2029 ///
2030 public void ExtrudeLinear() 2030 public void ExtrudeLinear()
2031 { 2031 {
2032 this.Extrude(PathType.Linear); 2032 this.Extrude(PathType.Linear);
2033 } 2033 }
2034 2034
2035 2035
2036 /// <summary> 2036 /// <summary>
2037 /// DEPRICATED - use Extrude(PathType.Circular) instead 2037 /// DEPRICATED - use Extrude(PathType.Circular) instead
2038 /// Extrude a profile into a circular path prim mesh. Used for prim types torus, tube, and ring. 2038 /// Extrude a profile into a circular path prim mesh. Used for prim types torus, tube, and ring.
2039 /// </summary> 2039 /// </summary>
2040 /// 2040 ///
2041 public void ExtrudeCircular() 2041 public void ExtrudeCircular()
2042 { 2042 {
2043 this.Extrude(PathType.Circular); 2043 this.Extrude(PathType.Circular);
2044 } 2044 }
2045 2045
2046 2046
2047 private Coord SurfaceNormal(Coord c1, Coord c2, Coord c3) 2047 private Coord SurfaceNormal(Coord c1, Coord c2, Coord c3)
2048 { 2048 {
2049 Coord edge1 = new Coord(c2.X - c1.X, c2.Y - c1.Y, c2.Z - c1.Z); 2049 Coord edge1 = new Coord(c2.X - c1.X, c2.Y - c1.Y, c2.Z - c1.Z);
2050 Coord edge2 = new Coord(c3.X - c1.X, c3.Y - c1.Y, c3.Z - c1.Z); 2050 Coord edge2 = new Coord(c3.X - c1.X, c3.Y - c1.Y, c3.Z - c1.Z);
2051 2051
2052 Coord normal = Coord.Cross(edge1, edge2); 2052 Coord normal = Coord.Cross(edge1, edge2);
2053 2053
2054 normal.Normalize(); 2054 normal.Normalize();
2055 2055
2056 return normal; 2056 return normal;
2057 } 2057 }
2058 2058
2059 private Coord SurfaceNormal(Face face) 2059 private Coord SurfaceNormal(Face face)
2060 { 2060 {
2061 return SurfaceNormal(this.coords[face.v1], this.coords[face.v2], this.coords[face.v3]); 2061 return SurfaceNormal(this.coords[face.v1], this.coords[face.v2], this.coords[face.v3]);
2062 } 2062 }
2063 2063
2064 /// <summary> 2064 /// <summary>
2065 /// Calculate the surface normal for a face in the list of faces 2065 /// Calculate the surface normal for a face in the list of faces
2066 /// </summary> 2066 /// </summary>
2067 /// <param name="faceIndex"></param> 2067 /// <param name="faceIndex"></param>
2068 /// <returns></returns> 2068 /// <returns></returns>
2069 public Coord SurfaceNormal(int faceIndex) 2069 public Coord SurfaceNormal(int faceIndex)
2070 { 2070 {
2071 int numFaces = this.faces.Count; 2071 int numFaces = this.faces.Count;
2072 if (faceIndex < 0 || faceIndex >= numFaces) 2072 if (faceIndex < 0 || faceIndex >= numFaces)
2073 throw new Exception("faceIndex out of range"); 2073 throw new Exception("faceIndex out of range");
2074 2074
2075 return SurfaceNormal(this.faces[faceIndex]); 2075 return SurfaceNormal(this.faces[faceIndex]);
2076 } 2076 }
2077 2077
2078 /// <summary> 2078 /// <summary>
2079 /// Duplicates a PrimMesh object. All object properties are copied by value, including lists. 2079 /// Duplicates a PrimMesh object. All object properties are copied by value, including lists.
2080 /// </summary> 2080 /// </summary>
2081 /// <returns></returns> 2081 /// <returns></returns>
2082 public PrimMesh Copy() 2082 public PrimMesh Copy()
2083 { 2083 {
2084 PrimMesh copy = new PrimMesh(this.sides, this.profileStart, this.profileEnd, this.hollow, this.hollowSides); 2084 PrimMesh copy = new PrimMesh(this.sides, this.profileStart, this.profileEnd, this.hollow, this.hollowSides);
2085 copy.twistBegin = this.twistBegin; 2085 copy.twistBegin = this.twistBegin;
2086 copy.twistEnd = this.twistEnd; 2086 copy.twistEnd = this.twistEnd;
2087 copy.topShearX = this.topShearX; 2087 copy.topShearX = this.topShearX;
2088 copy.topShearY = this.topShearY; 2088 copy.topShearY = this.topShearY;
2089 copy.pathCutBegin = this.pathCutBegin; 2089 copy.pathCutBegin = this.pathCutBegin;
2090 copy.pathCutEnd = this.pathCutEnd; 2090 copy.pathCutEnd = this.pathCutEnd;
2091 copy.dimpleBegin = this.dimpleBegin; 2091 copy.dimpleBegin = this.dimpleBegin;
2092 copy.dimpleEnd = this.dimpleEnd; 2092 copy.dimpleEnd = this.dimpleEnd;
2093 copy.skew = this.skew; 2093 copy.skew = this.skew;
2094 copy.holeSizeX = this.holeSizeX; 2094 copy.holeSizeX = this.holeSizeX;
2095 copy.holeSizeY = this.holeSizeY; 2095 copy.holeSizeY = this.holeSizeY;
2096 copy.taperX = this.taperX; 2096 copy.taperX = this.taperX;
2097 copy.taperY = this.taperY; 2097 copy.taperY = this.taperY;
2098 copy.radius = this.radius; 2098 copy.radius = this.radius;
2099 copy.revolutions = this.revolutions; 2099 copy.revolutions = this.revolutions;
2100 copy.stepsPerRevolution = this.stepsPerRevolution; 2100 copy.stepsPerRevolution = this.stepsPerRevolution;
2101 copy.calcVertexNormals = this.calcVertexNormals; 2101 copy.calcVertexNormals = this.calcVertexNormals;
2102 copy.normalsProcessed = this.normalsProcessed; 2102 copy.normalsProcessed = this.normalsProcessed;
2103 copy.viewerMode = this.viewerMode; 2103 copy.viewerMode = this.viewerMode;
2104 copy.numPrimFaces = this.numPrimFaces; 2104 copy.numPrimFaces = this.numPrimFaces;
2105 copy.errorMessage = this.errorMessage; 2105 copy.errorMessage = this.errorMessage;
2106 2106
2107 copy.coords = new List<Coord>(this.coords); 2107 copy.coords = new List<Coord>(this.coords);
2108 copy.faces = new List<Face>(this.faces); 2108 copy.faces = new List<Face>(this.faces);
2109 copy.viewerFaces = new List<ViewerFace>(this.viewerFaces); 2109 copy.viewerFaces = new List<ViewerFace>(this.viewerFaces);
2110 copy.normals = new List<Coord>(this.normals); 2110 copy.normals = new List<Coord>(this.normals);
2111 2111
2112 return copy; 2112 return copy;
2113 } 2113 }
2114 2114
2115 /// <summary> 2115 /// <summary>
2116 /// Calculate surface normals for all of the faces in the list of faces in this mesh 2116 /// Calculate surface normals for all of the faces in the list of faces in this mesh
2117 /// </summary> 2117 /// </summary>
2118 public void CalcNormals() 2118 public void CalcNormals()
2119 { 2119 {
2120 if (normalsProcessed) 2120 if (normalsProcessed)
2121 return; 2121 return;
2122 2122
2123 normalsProcessed = true; 2123 normalsProcessed = true;
2124 2124
2125 int numFaces = faces.Count; 2125 int numFaces = faces.Count;
2126 2126
2127 if (!this.calcVertexNormals) 2127 if (!this.calcVertexNormals)
2128 this.normals = new List<Coord>(); 2128 this.normals = new List<Coord>();
2129 2129
2130 for (int i = 0; i < numFaces; i++) 2130 for (int i = 0; i < numFaces; i++)
2131 { 2131 {
2132 Face face = faces[i]; 2132 Face face = faces[i];
2133 2133
2134 this.normals.Add(SurfaceNormal(i).Normalize()); 2134 this.normals.Add(SurfaceNormal(i).Normalize());
2135 2135
2136 int normIndex = normals.Count - 1; 2136 int normIndex = normals.Count - 1;
2137 face.n1 = normIndex; 2137 face.n1 = normIndex;
2138 face.n2 = normIndex; 2138 face.n2 = normIndex;
2139 face.n3 = normIndex; 2139 face.n3 = normIndex;
2140 2140
2141 this.faces[i] = face; 2141 this.faces[i] = face;
2142 } 2142 }
2143 } 2143 }
2144 2144
2145 /// <summary> 2145 /// <summary>
2146 /// Adds a value to each XYZ vertex coordinate in the mesh 2146 /// Adds a value to each XYZ vertex coordinate in the mesh
2147 /// </summary> 2147 /// </summary>
2148 /// <param name="x"></param> 2148 /// <param name="x"></param>
2149 /// <param name="y"></param> 2149 /// <param name="y"></param>
2150 /// <param name="z"></param> 2150 /// <param name="z"></param>
2151 public void AddPos(float x, float y, float z) 2151 public void AddPos(float x, float y, float z)
2152 { 2152 {
2153 int i; 2153 int i;
2154 int numVerts = this.coords.Count; 2154 int numVerts = this.coords.Count;
2155 Coord vert; 2155 Coord vert;
2156 2156
2157 for (i = 0; i < numVerts; i++) 2157 for (i = 0; i < numVerts; i++)
2158 { 2158 {
2159 vert = this.coords[i]; 2159 vert = this.coords[i];
2160 vert.X += x; 2160 vert.X += x;
2161 vert.Y += y; 2161 vert.Y += y;
2162 vert.Z += z; 2162 vert.Z += z;
2163 this.coords[i] = vert; 2163 this.coords[i] = vert;
2164 } 2164 }
2165 2165
2166 if (this.viewerFaces != null) 2166 if (this.viewerFaces != null)
2167 { 2167 {
2168 int numViewerFaces = this.viewerFaces.Count; 2168 int numViewerFaces = this.viewerFaces.Count;
2169 2169
2170 for (i = 0; i < numViewerFaces; i++) 2170 for (i = 0; i < numViewerFaces; i++)
2171 { 2171 {
2172 ViewerFace v = this.viewerFaces[i]; 2172 ViewerFace v = this.viewerFaces[i];
2173 v.AddPos(x, y, z); 2173 v.AddPos(x, y, z);
2174 this.viewerFaces[i] = v; 2174 this.viewerFaces[i] = v;
2175 } 2175 }
2176 } 2176 }
2177 } 2177 }
2178 2178
2179 /// <summary> 2179 /// <summary>
2180 /// Rotates the mesh 2180 /// Rotates the mesh
2181 /// </summary> 2181 /// </summary>
2182 /// <param name="q"></param> 2182 /// <param name="q"></param>
2183 public void AddRot(Quat q) 2183 public void AddRot(Quat q)
2184 { 2184 {
2185 int i; 2185 int i;
2186 int numVerts = this.coords.Count; 2186 int numVerts = this.coords.Count;
2187 2187
2188 for (i = 0; i < numVerts; i++) 2188 for (i = 0; i < numVerts; i++)
2189 this.coords[i] *= q; 2189 this.coords[i] *= q;
2190 2190
2191 if (this.normals != null) 2191 if (this.normals != null)
2192 { 2192 {
2193 int numNormals = this.normals.Count; 2193 int numNormals = this.normals.Count;
2194 for (i = 0; i < numNormals; i++) 2194 for (i = 0; i < numNormals; i++)
2195 this.normals[i] *= q; 2195 this.normals[i] *= q;
2196 } 2196 }
2197 2197
2198 if (this.viewerFaces != null) 2198 if (this.viewerFaces != null)
2199 { 2199 {
2200 int numViewerFaces = this.viewerFaces.Count; 2200 int numViewerFaces = this.viewerFaces.Count;
2201 2201
2202 for (i = 0; i < numViewerFaces; i++) 2202 for (i = 0; i < numViewerFaces; i++)
2203 { 2203 {
2204 ViewerFace v = this.viewerFaces[i]; 2204 ViewerFace v = this.viewerFaces[i];
2205 v.v1 *= q; 2205 v.v1 *= q;
2206 v.v2 *= q; 2206 v.v2 *= q;
2207 v.v3 *= q; 2207 v.v3 *= q;
2208 2208
2209 v.n1 *= q; 2209 v.n1 *= q;
2210 v.n2 *= q; 2210 v.n2 *= q;
2211 v.n3 *= q; 2211 v.n3 *= q;
2212 this.viewerFaces[i] = v; 2212 this.viewerFaces[i] = v;
2213 } 2213 }
2214 } 2214 }
2215 } 2215 }
2216 2216
2217#if VERTEX_INDEXER 2217#if VERTEX_INDEXER
2218 public VertexIndexer GetVertexIndexer() 2218 public VertexIndexer GetVertexIndexer()
2219 { 2219 {
2220 if (this.viewerMode && this.viewerFaces.Count > 0) 2220 if (this.viewerMode && this.viewerFaces.Count > 0)
2221 return new VertexIndexer(this); 2221 return new VertexIndexer(this);
2222 return null; 2222 return null;
2223 } 2223 }
2224#endif 2224#endif
2225 2225
2226 /// <summary> 2226 /// <summary>
2227 /// Scales the mesh 2227 /// Scales the mesh
2228 /// </summary> 2228 /// </summary>
2229 /// <param name="x"></param> 2229 /// <param name="x"></param>
2230 /// <param name="y"></param> 2230 /// <param name="y"></param>
2231 /// <param name="z"></param> 2231 /// <param name="z"></param>
2232 public void Scale(float x, float y, float z) 2232 public void Scale(float x, float y, float z)
2233 { 2233 {
2234 int i; 2234 int i;
2235 int numVerts = this.coords.Count; 2235 int numVerts = this.coords.Count;
2236 //Coord vert; 2236 //Coord vert;
2237 2237
2238 Coord m = new Coord(x, y, z); 2238 Coord m = new Coord(x, y, z);
2239 for (i = 0; i < numVerts; i++) 2239 for (i = 0; i < numVerts; i++)
2240 this.coords[i] *= m; 2240 this.coords[i] *= m;
2241 2241
2242 if (this.viewerFaces != null) 2242 if (this.viewerFaces != null)
2243 { 2243 {
2244 int numViewerFaces = this.viewerFaces.Count; 2244 int numViewerFaces = this.viewerFaces.Count;
2245 for (i = 0; i < numViewerFaces; i++) 2245 for (i = 0; i < numViewerFaces; i++)
2246 { 2246 {
2247 ViewerFace v = this.viewerFaces[i]; 2247 ViewerFace v = this.viewerFaces[i];
2248 v.v1 *= m; 2248 v.v1 *= m;
2249 v.v2 *= m; 2249 v.v2 *= m;
2250 v.v3 *= m; 2250 v.v3 *= m;
2251 this.viewerFaces[i] = v; 2251 this.viewerFaces[i] = v;
2252 } 2252 }
2253 2253
2254 } 2254 }
2255 2255
2256 } 2256 }
2257 2257
2258 /// <summary> 2258 /// <summary>
2259 /// Dumps the mesh to a Blender compatible "Raw" format file 2259 /// Dumps the mesh to a Blender compatible "Raw" format file
2260 /// </summary> 2260 /// </summary>
2261 /// <param name="path"></param> 2261 /// <param name="path"></param>
2262 /// <param name="name"></param> 2262 /// <param name="name"></param>
2263 /// <param name="title"></param> 2263 /// <param name="title"></param>
2264 public void DumpRaw(String path, String name, String title) 2264 public void DumpRaw(String path, String name, String title)
2265 { 2265 {
2266 if (path == null) 2266 if (path == null)
2267 return; 2267 return;
2268 String fileName = name + "_" + title + ".raw"; 2268 String fileName = name + "_" + title + ".raw";
2269 String completePath = System.IO.Path.Combine(path, fileName); 2269 String completePath = System.IO.Path.Combine(path, fileName);
2270 StreamWriter sw = new StreamWriter(completePath); 2270 StreamWriter sw = new StreamWriter(completePath);
2271 2271
2272 for (int i = 0; i < this.faces.Count; i++) 2272 for (int i = 0; i < this.faces.Count; i++)
2273 { 2273 {
2274 string s = this.coords[this.faces[i].v1].ToString(); 2274 string s = this.coords[this.faces[i].v1].ToString();
2275 s += " " + this.coords[this.faces[i].v2].ToString(); 2275 s += " " + this.coords[this.faces[i].v2].ToString();
2276 s += " " + this.coords[this.faces[i].v3].ToString(); 2276 s += " " + this.coords[this.faces[i].v3].ToString();
2277 2277
2278 sw.WriteLine(s); 2278 sw.WriteLine(s);
2279 } 2279 }
2280 2280
2281 sw.Close(); 2281 sw.Close();
2282 } 2282 }
2283 } 2283 }
2284} 2284}
diff --git a/OpenSim/Region/Physics/Meshing/SculptMap.cs b/OpenSim/Region/Physics/Meshing/SculptMap.cs
index 4906cf6..d2d71de 100644
--- a/OpenSim/Region/Physics/Meshing/SculptMap.cs
+++ b/OpenSim/Region/Physics/Meshing/SculptMap.cs
@@ -1,176 +1,176 @@
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;
34 34
35#if SYSTEM_DRAWING 35#if SYSTEM_DRAWING
36using System.Drawing; 36using System.Drawing;
37using System.Drawing.Imaging; 37using System.Drawing.Imaging;
38 38
39namespace PrimMesher 39namespace PrimMesher
40{ 40{
41 public class SculptMap 41 public class SculptMap
42 { 42 {
43 public int width; 43 public int width;
44 public int height; 44 public int height;
45 public byte[] redBytes; 45 public byte[] redBytes;
46 public byte[] greenBytes; 46 public byte[] greenBytes;
47 public byte[] blueBytes; 47 public byte[] blueBytes;
48 48
49 public SculptMap() 49 public SculptMap()
50 { 50 {
51 } 51 }
52 52
53 public SculptMap(Bitmap bm, int lod) 53 public SculptMap(Bitmap bm, int lod)
54 { 54 {
55 int bmW = bm.Width; 55 int bmW = bm.Width;
56 int bmH = bm.Height; 56 int bmH = bm.Height;
57 57
58 if (bmW == 0 || bmH == 0) 58 if (bmW == 0 || bmH == 0)
59 throw new Exception("SculptMap: bitmap has no data"); 59 throw new Exception("SculptMap: bitmap has no data");
60 60
61 int numLodPixels = lod * 2 * lod * 2; // (32 * 2)^2 = 64^2 pixels for default sculpt map image 61 int numLodPixels = lod * 2 * lod * 2; // (32 * 2)^2 = 64^2 pixels for default sculpt map image
62 62
63 bool needsScaling = false; 63 bool needsScaling = false;
64 64
65 width = bmW; 65 width = bmW;
66 height = bmH; 66 height = bmH;
67 while (width * height > numLodPixels) 67 while (width * height > numLodPixels)
68 { 68 {
69 width >>= 1; 69 width >>= 1;
70 height >>= 1; 70 height >>= 1;
71 needsScaling = true; 71 needsScaling = true;
72 } 72 }
73 73
74 74
75 75
76 try 76 try
77 { 77 {
78 if (needsScaling) 78 if (needsScaling)
79 bm = ScaleImage(bm, width, height, 79 bm = ScaleImage(bm, width, height,
80 System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor); 80 System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor);
81 } 81 }
82 82
83 catch (Exception e) 83 catch (Exception e)
84 { 84 {
85 throw new Exception("Exception in ScaleImage(): e: " + e.ToString()); 85 throw new Exception("Exception in ScaleImage(): e: " + e.ToString());
86 } 86 }
87 87
88 if (width * height > lod * lod) 88 if (width * height > lod * lod)
89 { 89 {
90 width >>= 1; 90 width >>= 1;
91 height >>= 1; 91 height >>= 1;
92 } 92 }
93 93
94 int numBytes = (width + 1) * (height + 1); 94 int numBytes = (width + 1) * (height + 1);
95 redBytes = new byte[numBytes]; 95 redBytes = new byte[numBytes];
96 greenBytes = new byte[numBytes]; 96 greenBytes = new byte[numBytes];
97 blueBytes = new byte[numBytes]; 97 blueBytes = new byte[numBytes];
98 98
99 int byteNdx = 0; 99 int byteNdx = 0;
100 100
101 try 101 try
102 { 102 {
103 for (int y = 0; y <= height; y++) 103 for (int y = 0; y <= height; y++)
104 { 104 {
105 for (int x = 0; x <= width; x++) 105 for (int x = 0; x <= width; x++)
106 { 106 {
107 int bmY = y < height ? y * 2 : y * 2 - 1; 107 int bmY = y < height ? y * 2 : y * 2 - 1;
108 int bmX = x < width ? x * 2 : x * 2 - 1; 108 int bmX = x < width ? x * 2 : x * 2 - 1;
109 Color c = bm.GetPixel(bmX, bmY); 109 Color c = bm.GetPixel(bmX, bmY);
110 110
111 redBytes[byteNdx] = c.R; 111 redBytes[byteNdx] = c.R;
112 greenBytes[byteNdx] = c.G; 112 greenBytes[byteNdx] = c.G;
113 blueBytes[byteNdx] = c.B; 113 blueBytes[byteNdx] = c.B;
114 114
115 ++byteNdx; 115 ++byteNdx;
116 } 116 }
117 } 117 }
118 } 118 }
119 catch (Exception e) 119 catch (Exception e)
120 { 120 {
121 throw new Exception("Caught exception processing byte arrays in SculptMap(): e: " + e.ToString()); 121 throw new Exception("Caught exception processing byte arrays in SculptMap(): e: " + e.ToString());
122 } 122 }
123 123
124 width++; 124 width++;
125 height++; 125 height++;
126 } 126 }
127 127
128 public List<List<Coord>> ToRows(bool mirror) 128 public List<List<Coord>> ToRows(bool mirror)
129 { 129 {
130 int numRows = height; 130 int numRows = height;
131 int numCols = width; 131 int numCols = width;
132 132
133 List<List<Coord>> rows = new List<List<Coord>>(numRows); 133 List<List<Coord>> rows = new List<List<Coord>>(numRows);
134 134
135 float pixScale = 1.0f / 255; 135 float pixScale = 1.0f / 255;
136 136
137 int rowNdx, colNdx; 137 int rowNdx, colNdx;
138 int smNdx = 0; 138 int smNdx = 0;
139 139
140 for (rowNdx = 0; rowNdx < numRows; rowNdx++) 140 for (rowNdx = 0; rowNdx < numRows; rowNdx++)
141 { 141 {
142 List<Coord> row = new List<Coord>(numCols); 142 List<Coord> row = new List<Coord>(numCols);
143 for (colNdx = 0; colNdx < numCols; colNdx++) 143 for (colNdx = 0; colNdx < numCols; colNdx++)
144 { 144 {
145 if (mirror) 145 if (mirror)
146 row.Add(new Coord(-(redBytes[smNdx] * pixScale - 0.5f), (greenBytes[smNdx] * pixScale - 0.5f), blueBytes[smNdx] * pixScale - 0.5f)); 146 row.Add(new Coord(-(redBytes[smNdx] * pixScale - 0.5f), (greenBytes[smNdx] * pixScale - 0.5f), blueBytes[smNdx] * pixScale - 0.5f));
147 else 147 else
148 row.Add(new Coord(redBytes[smNdx] * pixScale - 0.5f, greenBytes[smNdx] * pixScale - 0.5f, blueBytes[smNdx] * pixScale - 0.5f)); 148 row.Add(new Coord(redBytes[smNdx] * pixScale - 0.5f, greenBytes[smNdx] * pixScale - 0.5f, blueBytes[smNdx] * pixScale - 0.5f));
149 149
150 ++smNdx; 150 ++smNdx;
151 } 151 }
152 rows.Add(row); 152 rows.Add(row);
153 } 153 }
154 return rows; 154 return rows;
155 } 155 }
156 156
157 private Bitmap ScaleImage(Bitmap srcImage, int destWidth, int destHeight, 157 private Bitmap ScaleImage(Bitmap srcImage, int destWidth, int destHeight,
158 System.Drawing.Drawing2D.InterpolationMode interpMode) 158 System.Drawing.Drawing2D.InterpolationMode interpMode)
159 { 159 {
160 Bitmap scaledImage = new Bitmap(srcImage, destWidth, destHeight); 160 Bitmap scaledImage = new Bitmap(srcImage, destWidth, destHeight);
161 scaledImage.SetResolution(96.0f, 96.0f); 161 scaledImage.SetResolution(96.0f, 96.0f);
162 162
163 Graphics grPhoto = Graphics.FromImage(scaledImage); 163 Graphics grPhoto = Graphics.FromImage(scaledImage);
164 grPhoto.InterpolationMode = interpMode; 164 grPhoto.InterpolationMode = interpMode;
165 165
166 grPhoto.DrawImage(srcImage, 166 grPhoto.DrawImage(srcImage,
167 new Rectangle(0, 0, destWidth, destHeight), 167 new Rectangle(0, 0, destWidth, destHeight),
168 new Rectangle(0, 0, srcImage.Width, srcImage.Height), 168 new Rectangle(0, 0, srcImage.Width, srcImage.Height),
169 GraphicsUnit.Pixel); 169 GraphicsUnit.Pixel);
170 170
171 grPhoto.Dispose(); 171 grPhoto.Dispose();
172 return scaledImage; 172 return scaledImage;
173 } 173 }
174 } 174 }
175} 175}
176#endif 176#endif
diff --git a/OpenSim/Region/Physics/Meshing/SculptMesh.cs b/OpenSim/Region/Physics/Meshing/SculptMesh.cs
index 06606c3..6aa8fe4 100644
--- a/OpenSim/Region/Physics/Meshing/SculptMesh.cs
+++ b/OpenSim/Region/Physics/Meshing/SculptMesh.cs
@@ -1,647 +1,647 @@
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 56
57 public SculptMesh SculptMeshFromFile(string fileName, SculptType sculptType, int lod, bool viewerMode) 57 public SculptMesh SculptMeshFromFile(string fileName, SculptType sculptType, int lod, bool viewerMode)
58 { 58 {
59 Bitmap bitmap = (Bitmap)Bitmap.FromFile(fileName); 59 Bitmap bitmap = (Bitmap)Bitmap.FromFile(fileName);
60 SculptMesh sculptMesh = new SculptMesh(bitmap, sculptType, lod, viewerMode); 60 SculptMesh sculptMesh = new SculptMesh(bitmap, sculptType, lod, viewerMode);
61 bitmap.Dispose(); 61 bitmap.Dispose();
62 return sculptMesh; 62 return sculptMesh;
63 } 63 }
64 64
65 65
66 public SculptMesh(string fileName, int sculptType, int lod, int viewerMode, int mirror, int invert) 66 public SculptMesh(string fileName, int sculptType, int lod, int viewerMode, int mirror, int invert)
67 { 67 {
68 Bitmap bitmap = (Bitmap)Bitmap.FromFile(fileName); 68 Bitmap bitmap = (Bitmap)Bitmap.FromFile(fileName);
69 _SculptMesh(bitmap, (SculptType)sculptType, lod, viewerMode != 0, mirror != 0, invert != 0); 69 _SculptMesh(bitmap, (SculptType)sculptType, lod, viewerMode != 0, mirror != 0, invert != 0);
70 bitmap.Dispose(); 70 bitmap.Dispose();
71 } 71 }
72#endif 72#endif
73 73
74 /// <summary> 74 /// <summary>
75 /// ** Experimental ** May disappear from future versions ** not recommeneded for use in applications 75 /// ** Experimental ** May disappear from future versions ** not recommeneded for use in applications
76 /// Construct a sculpt mesh from a 2D array of floats 76 /// Construct a sculpt mesh from a 2D array of floats
77 /// </summary> 77 /// </summary>
78 /// <param name="zMap"></param> 78 /// <param name="zMap"></param>
79 /// <param name="xBegin"></param> 79 /// <param name="xBegin"></param>
80 /// <param name="xEnd"></param> 80 /// <param name="xEnd"></param>
81 /// <param name="yBegin"></param> 81 /// <param name="yBegin"></param>
82 /// <param name="yEnd"></param> 82 /// <param name="yEnd"></param>
83 /// <param name="viewerMode"></param> 83 /// <param name="viewerMode"></param>
84 public SculptMesh(float[,] zMap, float xBegin, float xEnd, float yBegin, float yEnd, bool viewerMode) 84 public SculptMesh(float[,] zMap, float xBegin, float xEnd, float yBegin, float yEnd, bool viewerMode)
85 { 85 {
86 float xStep, yStep; 86 float xStep, yStep;
87 float uStep, vStep; 87 float uStep, vStep;
88 88
89 int numYElements = zMap.GetLength(0); 89 int numYElements = zMap.GetLength(0);
90 int numXElements = zMap.GetLength(1); 90 int numXElements = zMap.GetLength(1);
91 91
92 try 92 try
93 { 93 {
94 xStep = (xEnd - xBegin) / (float)(numXElements - 1); 94 xStep = (xEnd - xBegin) / (float)(numXElements - 1);
95 yStep = (yEnd - yBegin) / (float)(numYElements - 1); 95 yStep = (yEnd - yBegin) / (float)(numYElements - 1);
96 96
97 uStep = 1.0f / (numXElements - 1); 97 uStep = 1.0f / (numXElements - 1);
98 vStep = 1.0f / (numYElements - 1); 98 vStep = 1.0f / (numYElements - 1);
99 } 99 }
100 catch (DivideByZeroException) 100 catch (DivideByZeroException)
101 { 101 {
102 return; 102 return;
103 } 103 }
104 104
105 coords = new List<Coord>(); 105 coords = new List<Coord>();
106 faces = new List<Face>(); 106 faces = new List<Face>();
107 normals = new List<Coord>(); 107 normals = new List<Coord>();
108 uvs = new List<UVCoord>(); 108 uvs = new List<UVCoord>();
109 109
110 viewerFaces = new List<ViewerFace>(); 110 viewerFaces = new List<ViewerFace>();
111 111
112 int p1, p2, p3, p4; 112 int p1, p2, p3, p4;
113 113
114 int x, y; 114 int x, y;
115 int xStart = 0, yStart = 0; 115 int xStart = 0, yStart = 0;
116 116
117 for (y = yStart; y < numYElements; y++) 117 for (y = yStart; y < numYElements; y++)
118 { 118 {
119 int rowOffset = y * numXElements; 119 int rowOffset = y * numXElements;
120 120
121 for (x = xStart; x < numXElements; x++) 121 for (x = xStart; x < numXElements; x++)
122 { 122 {
123 /*
124 * p1-----p2
125 * | \ f2 |
126 * | \ |
127 * | f1 \|
128 * p3-----p4
129 */
130
131 p4 = rowOffset + x;
132 p3 = p4 - 1;
133
134 p2 = p4 - numXElements;
135 p1 = p3 - numXElements;
136
137 Coord c = new Coord(xBegin + x * xStep, yBegin + y * yStep, zMap[y, x]);
138 this.coords.Add(c);
139 if (viewerMode)
140 {
141 this.normals.Add(new Coord());
142 this.uvs.Add(new UVCoord(uStep * x, 1.0f - vStep * y));
143 }
144
145 if (y > 0 && x > 0)
146 {
147 Face f1, f2;
148
149 if (viewerMode)
150 {
151 f1 = new Face(p1, p4, p3, p1, p4, p3);
152 f1.uv1 = p1;
153 f1.uv2 = p4;
154 f1.uv3 = p3;
155
156 f2 = new Face(p1, p2, p4, p1, p2, p4);
157 f2.uv1 = p1;
158 f2.uv2 = p2;
159 f2.uv3 = p4;
160 }
161 else
162 {
163 f1 = new Face(p1, p4, p3);
164 f2 = new Face(p1, p2, p4);
165 }
166
167 this.faces.Add(f1);
168 this.faces.Add(f2);
169 }
170 }
171 }
172
173 if (viewerMode)
174 calcVertexNormals(SculptType.plane, numXElements, numYElements);
175 }
176
177#if SYSTEM_DRAWING
178 public SculptMesh(Bitmap sculptBitmap, SculptType sculptType, int lod, bool viewerMode)
179 {
180 _SculptMesh(sculptBitmap, sculptType, lod, viewerMode, false, false);
181 }
182
183 public SculptMesh(Bitmap sculptBitmap, SculptType sculptType, int lod, bool viewerMode, bool mirror, bool invert)
184 {
185 _SculptMesh(sculptBitmap, sculptType, lod, viewerMode, mirror, invert);
186 }
187#endif
188
189 public SculptMesh(List<List<Coord>> rows, SculptType sculptType, bool viewerMode, bool mirror, bool invert)
190 {
191 _SculptMesh(rows, sculptType, viewerMode, mirror, invert);
192 }
193
194#if SYSTEM_DRAWING
195 /// <summary>
196 /// converts a bitmap to a list of lists of coords, while scaling the image.
197 /// the scaling is done in floating point so as to allow for reduced vertex position
198 /// quantization as the position will be averaged between pixel values. this routine will
199 /// likely fail if the bitmap width and height are not powers of 2.
200 /// </summary>
201 /// <param name="bitmap"></param>
202 /// <param name="scale"></param>
203 /// <param name="mirror"></param>
204 /// <returns></returns>
205 private List<List<Coord>> bitmap2Coords(Bitmap bitmap, int scale, bool mirror)
206 {
207 int numRows = bitmap.Height / scale;
208 int numCols = bitmap.Width / scale;
209 List<List<Coord>> rows = new List<List<Coord>>(numRows);
210
211 float pixScale = 1.0f / (scale * scale);
212 pixScale /= 255;
213
214 int imageX, imageY = 0;
215
216 int rowNdx, colNdx;
217
218 for (rowNdx = 0; rowNdx < numRows; rowNdx++)
219 {
220 List<Coord> row = new List<Coord>(numCols);
221 for (colNdx = 0; colNdx < numCols; colNdx++)
222 {
223 imageX = colNdx * scale;
224 int imageYStart = rowNdx * scale;
225 int imageYEnd = imageYStart + scale;
226 int imageXEnd = imageX + scale;
227 float rSum = 0.0f;
228 float gSum = 0.0f;
229 float bSum = 0.0f;
230 for (; imageX < imageXEnd; imageX++)
231 {
232 for (imageY = imageYStart; imageY < imageYEnd; imageY++)
233 {
234 Color c = bitmap.GetPixel(imageX, imageY);
235 if (c.A != 255)
236 {
237 bitmap.SetPixel(imageX, imageY, Color.FromArgb(255, c.R, c.G, c.B));
238 c = bitmap.GetPixel(imageX, imageY);
239 }
240 rSum += c.R;
241 gSum += c.G;
242 bSum += c.B;
243 }
244 }
245 if (mirror)
246 row.Add(new Coord(-(rSum * pixScale - 0.5f), gSum * pixScale - 0.5f, bSum * pixScale - 0.5f));
247 else
248 row.Add(new Coord(rSum * pixScale - 0.5f, gSum * pixScale - 0.5f, bSum * pixScale - 0.5f));
249
250 }
251 rows.Add(row);
252 }
253 return rows;
254 }
255
256 private List<List<Coord>> bitmap2CoordsSampled(Bitmap bitmap, int scale, bool mirror)
257 {
258 int numRows = bitmap.Height / scale;
259 int numCols = bitmap.Width / scale;
260 List<List<Coord>> rows = new List<List<Coord>>(numRows);
261
262 float pixScale = 1.0f / 256.0f;
263
264 int imageX, imageY = 0;
265
266 int rowNdx, colNdx;
267
268 for (rowNdx = 0; rowNdx <= numRows; rowNdx++)
269 {
270 List<Coord> row = new List<Coord>(numCols);
271 imageY = rowNdx * scale;
272 if (rowNdx == numRows) imageY--;
273 for (colNdx = 0; colNdx <= numCols; colNdx++)
274 {
275 imageX = colNdx * scale;
276 if (colNdx == numCols) imageX--;
277
278 Color c = bitmap.GetPixel(imageX, imageY);
279 if (c.A != 255)
280 {
281 bitmap.SetPixel(imageX, imageY, Color.FromArgb(255, c.R, c.G, c.B));
282 c = bitmap.GetPixel(imageX, imageY);
283 }
284
285 if (mirror)
286 row.Add(new Coord(-(c.R * pixScale - 0.5f), c.G * pixScale - 0.5f, c.B * pixScale - 0.5f));
287 else
288 row.Add(new Coord(c.R * pixScale - 0.5f, c.G * pixScale - 0.5f, c.B * pixScale - 0.5f));
289
290 }
291 rows.Add(row);
292 }
293 return rows;
294 }
295
296
297 void _SculptMesh(Bitmap sculptBitmap, SculptType sculptType, int lod, bool viewerMode, bool mirror, bool invert)
298 {
299 _SculptMesh(new SculptMap(sculptBitmap, lod).ToRows(mirror), sculptType, viewerMode, mirror, invert);
300 }
301#endif
302
303 void _SculptMesh(List<List<Coord>> rows, SculptType sculptType, bool viewerMode, bool mirror, bool invert)
304 {
305 coords = new List<Coord>();
306 faces = new List<Face>();
307 normals = new List<Coord>();
308 uvs = new List<UVCoord>();
309
310 sculptType = (SculptType)(((int)sculptType) & 0x07);
311
312 if (mirror)
313 if (sculptType == SculptType.plane)
314 invert = !invert;
315
316 viewerFaces = new List<ViewerFace>();
317
318 int width = rows[0].Count;
319
320 int p1, p2, p3, p4;
321
322 int imageX, imageY;
323
324 if (sculptType != SculptType.plane)
325 {
326 if (rows.Count % 2 == 0)
327 {
328 for (int rowNdx = 0; rowNdx < rows.Count; rowNdx++)
329 rows[rowNdx].Add(rows[rowNdx][0]);
330 }
331 else
332 {
333 int lastIndex = rows[0].Count - 1;
334
335 for (int i = 0; i < rows.Count; i++)
336 rows[i][0] = rows[i][lastIndex];
337 }
338 }
339
340 Coord topPole = rows[0][width / 2];
341 Coord bottomPole = rows[rows.Count - 1][width / 2];
342
343 if (sculptType == SculptType.sphere)
344 {
345 if (rows.Count % 2 == 0)
346 {
347 int count = rows[0].Count;
348 List<Coord> topPoleRow = new List<Coord>(count);
349 List<Coord> bottomPoleRow = new List<Coord>(count);
350
351 for (int i = 0; i < count; i++)
352 {
353 topPoleRow.Add(topPole);
354 bottomPoleRow.Add(bottomPole);
355 }
356 rows.Insert(0, topPoleRow);
357 rows.Add(bottomPoleRow);
358 }
359 else
360 {
361 int count = rows[0].Count;
362
363 List<Coord> topPoleRow = rows[0];
364 List<Coord> bottomPoleRow = rows[rows.Count - 1];
365
366 for (int i = 0; i < count; i++)
367 {
368 topPoleRow[i] = topPole;
369 bottomPoleRow[i] = bottomPole;
370 }
371 }
372 }
373
374 if (sculptType == SculptType.torus)
375 rows.Add(rows[0]);
376
377 int coordsDown = rows.Count;
378 int coordsAcross = rows[0].Count;
379 int lastColumn = coordsAcross - 1;
380
381 float widthUnit = 1.0f / (coordsAcross - 1);
382 float heightUnit = 1.0f / (coordsDown - 1);
383
384 for (imageY = 0; imageY < coordsDown; imageY++)
385 {
386 int rowOffset = imageY * coordsAcross;
387
388 for (imageX = 0; imageX < coordsAcross; imageX++)
389 {
390 /* 123 /*
391 * p1-----p2 124 * p1-----p2
392 * | \ f2 | 125 * | \ f2 |
393 * | \ | 126 * | \ |
394 * | f1 \| 127 * | f1 \|
395 * p3-----p4 128 * p3-----p4
396 */ 129 */
397 130
398 p4 = rowOffset + imageX; 131 p4 = rowOffset + x;
399 p3 = p4 - 1; 132 p3 = p4 - 1;
400 133
401 p2 = p4 - coordsAcross; 134 p2 = p4 - numXElements;
402 p1 = p3 - coordsAcross; 135 p1 = p3 - numXElements;
403 136
404 this.coords.Add(rows[imageY][imageX]); 137 Coord c = new Coord(xBegin + x * xStep, yBegin + y * yStep, zMap[y, x]);
405 if (viewerMode) 138 this.coords.Add(c);
406 { 139 if (viewerMode)
407 this.normals.Add(new Coord()); 140 {
408 this.uvs.Add(new UVCoord(widthUnit * imageX, heightUnit * imageY)); 141 this.normals.Add(new Coord());
409 } 142 this.uvs.Add(new UVCoord(uStep * x, 1.0f - vStep * y));
410 143 }
411 if (imageY > 0 && imageX > 0) 144
412 { 145 if (y > 0 && x > 0)
413 Face f1, f2; 146 {
414 147 Face f1, f2;
415 if (viewerMode) 148
416 { 149 if (viewerMode)
417 if (invert) 150 {
418 { 151 f1 = new Face(p1, p4, p3, p1, p4, p3);
419 f1 = new Face(p1, p4, p3, p1, p4, p3); 152 f1.uv1 = p1;
420 f1.uv1 = p1; 153 f1.uv2 = p4;
421 f1.uv2 = p4; 154 f1.uv3 = p3;
422 f1.uv3 = p3; 155
423 156 f2 = new Face(p1, p2, p4, p1, p2, p4);
424 f2 = new Face(p1, p2, p4, p1, p2, p4); 157 f2.uv1 = p1;
425 f2.uv1 = p1; 158 f2.uv2 = p2;
426 f2.uv2 = p2; 159 f2.uv3 = p4;
427 f2.uv3 = p4; 160 }
428 } 161 else
429 else 162 {
430 { 163 f1 = new Face(p1, p4, p3);
431 f1 = new Face(p1, p3, p4, p1, p3, p4); 164 f2 = new Face(p1, p2, p4);
432 f1.uv1 = p1; 165 }
433 f1.uv2 = p3; 166
434 f1.uv3 = p4; 167 this.faces.Add(f1);
435 168 this.faces.Add(f2);
436 f2 = new Face(p1, p4, p2, p1, p4, p2); 169 }
437 f2.uv1 = p1; 170 }
438 f2.uv2 = p4; 171 }
439 f2.uv3 = p2; 172
440 } 173 if (viewerMode)
441 } 174 calcVertexNormals(SculptType.plane, numXElements, numYElements);
442 else 175 }
443 { 176
444 if (invert) 177#if SYSTEM_DRAWING
445 { 178 public SculptMesh(Bitmap sculptBitmap, SculptType sculptType, int lod, bool viewerMode)
446 f1 = new Face(p1, p4, p3); 179 {
447 f2 = new Face(p1, p2, p4); 180 _SculptMesh(sculptBitmap, sculptType, lod, viewerMode, false, false);
448 } 181 }
449 else 182
450 { 183 public SculptMesh(Bitmap sculptBitmap, SculptType sculptType, int lod, bool viewerMode, bool mirror, bool invert)
451 f1 = new Face(p1, p3, p4); 184 {
452 f2 = new Face(p1, p4, p2); 185 _SculptMesh(sculptBitmap, sculptType, lod, viewerMode, mirror, invert);
453 } 186 }
454 } 187#endif
455 188
456 this.faces.Add(f1); 189 public SculptMesh(List<List<Coord>> rows, SculptType sculptType, bool viewerMode, bool mirror, bool invert)
457 this.faces.Add(f2); 190 {
458 } 191 _SculptMesh(rows, sculptType, viewerMode, mirror, invert);
459 } 192 }
460 } 193
461 194#if SYSTEM_DRAWING
462 if (viewerMode) 195 /// <summary>
463 calcVertexNormals(sculptType, coordsAcross, coordsDown); 196 /// converts a bitmap to a list of lists of coords, while scaling the image.
464 } 197 /// the scaling is done in floating point so as to allow for reduced vertex position
465 198 /// quantization as the position will be averaged between pixel values. this routine will
466 /// <summary> 199 /// likely fail if the bitmap width and height are not powers of 2.
467 /// Duplicates a SculptMesh object. All object properties are copied by value, including lists. 200 /// </summary>
468 /// </summary> 201 /// <param name="bitmap"></param>
469 /// <returns></returns> 202 /// <param name="scale"></param>
470 public SculptMesh Copy() 203 /// <param name="mirror"></param>
471 { 204 /// <returns></returns>
472 return new SculptMesh(this); 205 private List<List<Coord>> bitmap2Coords(Bitmap bitmap, int scale, bool mirror)
473 } 206 {
474 207 int numRows = bitmap.Height / scale;
475 public SculptMesh(SculptMesh sm) 208 int numCols = bitmap.Width / scale;
476 { 209 List<List<Coord>> rows = new List<List<Coord>>(numRows);
477 coords = new List<Coord>(sm.coords); 210
478 faces = new List<Face>(sm.faces); 211 float pixScale = 1.0f / (scale * scale);
479 viewerFaces = new List<ViewerFace>(sm.viewerFaces); 212 pixScale /= 255;
480 normals = new List<Coord>(sm.normals); 213
481 uvs = new List<UVCoord>(sm.uvs); 214 int imageX, imageY = 0;
482 } 215
483 216 int rowNdx, colNdx;
484 private void calcVertexNormals(SculptType sculptType, int xSize, int ySize) 217
485 { // compute vertex normals by summing all the surface normals of all the triangles sharing 218 for (rowNdx = 0; rowNdx < numRows; rowNdx++)
486 // each vertex and then normalizing 219 {
487 int numFaces = this.faces.Count; 220 List<Coord> row = new List<Coord>(numCols);
488 for (int i = 0; i < numFaces; i++) 221 for (colNdx = 0; colNdx < numCols; colNdx++)
489 { 222 {
490 Face face = this.faces[i]; 223 imageX = colNdx * scale;
491 Coord surfaceNormal = face.SurfaceNormal(this.coords); 224 int imageYStart = rowNdx * scale;
492 this.normals[face.n1] += surfaceNormal; 225 int imageYEnd = imageYStart + scale;
493 this.normals[face.n2] += surfaceNormal; 226 int imageXEnd = imageX + scale;
494 this.normals[face.n3] += surfaceNormal; 227 float rSum = 0.0f;
495 } 228 float gSum = 0.0f;
496 229 float bSum = 0.0f;
497 int numNormals = this.normals.Count; 230 for (; imageX < imageXEnd; imageX++)
498 for (int i = 0; i < numNormals; i++) 231 {
499 this.normals[i] = this.normals[i].Normalize(); 232 for (imageY = imageYStart; imageY < imageYEnd; imageY++)
500 233 {
501 if (sculptType != SculptType.plane) 234 Color c = bitmap.GetPixel(imageX, imageY);
502 { // blend the vertex normals at the cylinder seam 235 if (c.A != 255)
503 for (int y = 0; y < ySize; y++) 236 {
504 { 237 bitmap.SetPixel(imageX, imageY, Color.FromArgb(255, c.R, c.G, c.B));
505 int rowOffset = y * xSize; 238 c = bitmap.GetPixel(imageX, imageY);
506 239 }
507 this.normals[rowOffset] = this.normals[rowOffset + xSize - 1] = (this.normals[rowOffset] + this.normals[rowOffset + xSize - 1]).Normalize(); 240 rSum += c.R;
508 } 241 gSum += c.G;
509 } 242 bSum += c.B;
510 243 }
511 foreach (Face face in this.faces) 244 }
512 { 245 if (mirror)
513 ViewerFace vf = new ViewerFace(0); 246 row.Add(new Coord(-(rSum * pixScale - 0.5f), gSum * pixScale - 0.5f, bSum * pixScale - 0.5f));
514 vf.v1 = this.coords[face.v1]; 247 else
515 vf.v2 = this.coords[face.v2]; 248 row.Add(new Coord(rSum * pixScale - 0.5f, gSum * pixScale - 0.5f, bSum * pixScale - 0.5f));
516 vf.v3 = this.coords[face.v3]; 249
517 250 }
518 vf.coordIndex1 = face.v1; 251 rows.Add(row);
519 vf.coordIndex2 = face.v2; 252 }
520 vf.coordIndex3 = face.v3; 253 return rows;
521 254 }
522 vf.n1 = this.normals[face.n1]; 255
523 vf.n2 = this.normals[face.n2]; 256 private List<List<Coord>> bitmap2CoordsSampled(Bitmap bitmap, int scale, bool mirror)
524 vf.n3 = this.normals[face.n3]; 257 {
525 258 int numRows = bitmap.Height / scale;
526 vf.uv1 = this.uvs[face.uv1]; 259 int numCols = bitmap.Width / scale;
527 vf.uv2 = this.uvs[face.uv2]; 260 List<List<Coord>> rows = new List<List<Coord>>(numRows);
528 vf.uv3 = this.uvs[face.uv3]; 261
529 262 float pixScale = 1.0f / 256.0f;
530 this.viewerFaces.Add(vf); 263
531 } 264 int imageX, imageY = 0;
532 } 265
533 266 int rowNdx, colNdx;
534 /// <summary> 267
535 /// Adds a value to each XYZ vertex coordinate in the mesh 268 for (rowNdx = 0; rowNdx <= numRows; rowNdx++)
536 /// </summary> 269 {
537 /// <param name="x"></param> 270 List<Coord> row = new List<Coord>(numCols);
538 /// <param name="y"></param> 271 imageY = rowNdx * scale;
539 /// <param name="z"></param> 272 if (rowNdx == numRows) imageY--;
540 public void AddPos(float x, float y, float z) 273 for (colNdx = 0; colNdx <= numCols; colNdx++)
541 { 274 {
542 int i; 275 imageX = colNdx * scale;
543 int numVerts = this.coords.Count; 276 if (colNdx == numCols) imageX--;
544 Coord vert; 277
545 278 Color c = bitmap.GetPixel(imageX, imageY);
546 for (i = 0; i < numVerts; i++) 279 if (c.A != 255)
547 { 280 {
548 vert = this.coords[i]; 281 bitmap.SetPixel(imageX, imageY, Color.FromArgb(255, c.R, c.G, c.B));
549 vert.X += x; 282 c = bitmap.GetPixel(imageX, imageY);
550 vert.Y += y; 283 }
551 vert.Z += z; 284
552 this.coords[i] = vert; 285 if (mirror)
553 } 286 row.Add(new Coord(-(c.R * pixScale - 0.5f), c.G * pixScale - 0.5f, c.B * pixScale - 0.5f));
554 287 else
555 if (this.viewerFaces != null) 288 row.Add(new Coord(c.R * pixScale - 0.5f, c.G * pixScale - 0.5f, c.B * pixScale - 0.5f));
556 { 289
557 int numViewerFaces = this.viewerFaces.Count; 290 }
558 291 rows.Add(row);
559 for (i = 0; i < numViewerFaces; i++) 292 }
560 { 293 return rows;
561 ViewerFace v = this.viewerFaces[i]; 294 }
562 v.AddPos(x, y, z); 295
563 this.viewerFaces[i] = v; 296
564 } 297 void _SculptMesh(Bitmap sculptBitmap, SculptType sculptType, int lod, bool viewerMode, bool mirror, bool invert)
565 } 298 {
566 } 299 _SculptMesh(new SculptMap(sculptBitmap, lod).ToRows(mirror), sculptType, viewerMode, mirror, invert);
567 300 }
568 /// <summary> 301#endif
569 /// Rotates the mesh 302
570 /// </summary> 303 void _SculptMesh(List<List<Coord>> rows, SculptType sculptType, bool viewerMode, bool mirror, bool invert)
571 /// <param name="q"></param> 304 {
572 public void AddRot(Quat q) 305 coords = new List<Coord>();
573 { 306 faces = new List<Face>();
574 int i; 307 normals = new List<Coord>();
575 int numVerts = this.coords.Count; 308 uvs = new List<UVCoord>();
576 309
577 for (i = 0; i < numVerts; i++) 310 sculptType = (SculptType)(((int)sculptType) & 0x07);
578 this.coords[i] *= q; 311
579 312 if (mirror)
580 int numNormals = this.normals.Count; 313 if (sculptType == SculptType.plane)
581 for (i = 0; i < numNormals; i++) 314 invert = !invert;
582 this.normals[i] *= q; 315
583 316 viewerFaces = new List<ViewerFace>();
584 if (this.viewerFaces != null) 317
585 { 318 int width = rows[0].Count;
586 int numViewerFaces = this.viewerFaces.Count; 319
587 320 int p1, p2, p3, p4;
588 for (i = 0; i < numViewerFaces; i++) 321
589 { 322 int imageX, imageY;
590 ViewerFace v = this.viewerFaces[i]; 323
591 v.v1 *= q; 324 if (sculptType != SculptType.plane)
592 v.v2 *= q; 325 {
593 v.v3 *= q; 326 if (rows.Count % 2 == 0)
594 327 {
595 v.n1 *= q; 328 for (int rowNdx = 0; rowNdx < rows.Count; rowNdx++)
596 v.n2 *= q; 329 rows[rowNdx].Add(rows[rowNdx][0]);
597 v.n3 *= q; 330 }
598 331 else
599 this.viewerFaces[i] = v; 332 {
600 } 333 int lastIndex = rows[0].Count - 1;
601 } 334
602 } 335 for (int i = 0; i < rows.Count; i++)
603 336 rows[i][0] = rows[i][lastIndex];
604 public void Scale(float x, float y, float z) 337 }
605 { 338 }
606 int i; 339
607 int numVerts = this.coords.Count; 340 Coord topPole = rows[0][width / 2];
608 341 Coord bottomPole = rows[rows.Count - 1][width / 2];
609 Coord m = new Coord(x, y, z); 342
610 for (i = 0; i < numVerts; i++) 343 if (sculptType == SculptType.sphere)
611 this.coords[i] *= m; 344 {
612 345 if (rows.Count % 2 == 0)
613 if (this.viewerFaces != null) 346 {
614 { 347 int count = rows[0].Count;
615 int numViewerFaces = this.viewerFaces.Count; 348 List<Coord> topPoleRow = new List<Coord>(count);
616 for (i = 0; i < numViewerFaces; i++) 349 List<Coord> bottomPoleRow = new List<Coord>(count);
617 { 350
618 ViewerFace v = this.viewerFaces[i]; 351 for (int i = 0; i < count; i++)
619 v.v1 *= m; 352 {
620 v.v2 *= m; 353 topPoleRow.Add(topPole);
621 v.v3 *= m; 354 bottomPoleRow.Add(bottomPole);
622 this.viewerFaces[i] = v; 355 }
623 } 356 rows.Insert(0, topPoleRow);
624 } 357 rows.Add(bottomPoleRow);
625 } 358 }
626 359 else
627 public void DumpRaw(String path, String name, String title) 360 {
628 { 361 int count = rows[0].Count;
629 if (path == null) 362
630 return; 363 List<Coord> topPoleRow = rows[0];
631 String fileName = name + "_" + title + ".raw"; 364 List<Coord> bottomPoleRow = rows[rows.Count - 1];
632 String completePath = System.IO.Path.Combine(path, fileName); 365
633 StreamWriter sw = new StreamWriter(completePath); 366 for (int i = 0; i < count; i++)
634 367 {
635 for (int i = 0; i < this.faces.Count; i++) 368 topPoleRow[i] = topPole;
636 { 369 bottomPoleRow[i] = bottomPole;
637 string s = this.coords[this.faces[i].v1].ToString(); 370 }
638 s += " " + this.coords[this.faces[i].v2].ToString(); 371 }
639 s += " " + this.coords[this.faces[i].v3].ToString(); 372 }
640 373
641 sw.WriteLine(s); 374 if (sculptType == SculptType.torus)
642 } 375 rows.Add(rows[0]);
643 376
644 sw.Close(); 377 int coordsDown = rows.Count;
645 } 378 int coordsAcross = rows[0].Count;
646 } 379 int lastColumn = coordsAcross - 1;
647} 380
381 float widthUnit = 1.0f / (coordsAcross - 1);
382 float heightUnit = 1.0f / (coordsDown - 1);
383
384 for (imageY = 0; imageY < coordsDown; imageY++)
385 {
386 int rowOffset = imageY * coordsAcross;
387
388 for (imageX = 0; imageX < coordsAcross; imageX++)
389 {
390 /*
391 * p1-----p2
392 * | \ f2 |
393 * | \ |
394 * | f1 \|
395 * p3-----p4
396 */
397
398 p4 = rowOffset + imageX;
399 p3 = p4 - 1;
400
401 p2 = p4 - coordsAcross;
402 p1 = p3 - coordsAcross;
403
404 this.coords.Add(rows[imageY][imageX]);
405 if (viewerMode)
406 {
407 this.normals.Add(new Coord());
408 this.uvs.Add(new UVCoord(widthUnit * imageX, heightUnit * imageY));
409 }
410
411 if (imageY > 0 && imageX > 0)
412 {
413 Face f1, f2;
414
415 if (viewerMode)
416 {
417 if (invert)
418 {
419 f1 = new Face(p1, p4, p3, p1, p4, p3);
420 f1.uv1 = p1;
421 f1.uv2 = p4;
422 f1.uv3 = p3;
423
424 f2 = new Face(p1, p2, p4, p1, p2, p4);
425 f2.uv1 = p1;
426 f2.uv2 = p2;
427 f2.uv3 = p4;
428 }
429 else
430 {
431 f1 = new Face(p1, p3, p4, p1, p3, p4);
432 f1.uv1 = p1;
433 f1.uv2 = p3;
434 f1.uv3 = p4;
435
436 f2 = new Face(p1, p4, p2, p1, p4, p2);
437 f2.uv1 = p1;
438 f2.uv2 = p4;
439 f2.uv3 = p2;
440 }
441 }
442 else
443 {
444 if (invert)
445 {
446 f1 = new Face(p1, p4, p3);
447 f2 = new Face(p1, p2, p4);
448 }
449 else
450 {
451 f1 = new Face(p1, p3, p4);
452 f2 = new Face(p1, p4, p2);
453 }
454 }
455
456 this.faces.Add(f1);
457 this.faces.Add(f2);
458 }
459 }
460 }
461
462 if (viewerMode)
463 calcVertexNormals(sculptType, coordsAcross, coordsDown);
464 }
465
466 /// <summary>
467 /// Duplicates a SculptMesh object. All object properties are copied by value, including lists.
468 /// </summary>
469 /// <returns></returns>
470 public SculptMesh Copy()
471 {
472 return new SculptMesh(this);
473 }
474
475 public SculptMesh(SculptMesh sm)
476 {
477 coords = new List<Coord>(sm.coords);
478 faces = new List<Face>(sm.faces);
479 viewerFaces = new List<ViewerFace>(sm.viewerFaces);
480 normals = new List<Coord>(sm.normals);
481 uvs = new List<UVCoord>(sm.uvs);
482 }
483
484 private void calcVertexNormals(SculptType sculptType, int xSize, int ySize)
485 { // compute vertex normals by summing all the surface normals of all the triangles sharing
486 // each vertex and then normalizing
487 int numFaces = this.faces.Count;
488 for (int i = 0; i < numFaces; i++)
489 {
490 Face face = this.faces[i];
491 Coord surfaceNormal = face.SurfaceNormal(this.coords);
492 this.normals[face.n1] += surfaceNormal;
493 this.normals[face.n2] += surfaceNormal;
494 this.normals[face.n3] += surfaceNormal;
495 }
496
497 int numNormals = this.normals.Count;
498 for (int i = 0; i < numNormals; i++)
499 this.normals[i] = this.normals[i].Normalize();
500
501 if (sculptType != SculptType.plane)
502 { // blend the vertex normals at the cylinder seam
503 for (int y = 0; y < ySize; y++)
504 {
505 int rowOffset = y * xSize;
506
507 this.normals[rowOffset] = this.normals[rowOffset + xSize - 1] = (this.normals[rowOffset] + this.normals[rowOffset + xSize - 1]).Normalize();
508 }
509 }
510
511 foreach (Face face in this.faces)
512 {
513 ViewerFace vf = new ViewerFace(0);
514 vf.v1 = this.coords[face.v1];
515 vf.v2 = this.coords[face.v2];
516 vf.v3 = this.coords[face.v3];
517
518 vf.coordIndex1 = face.v1;
519 vf.coordIndex2 = face.v2;
520 vf.coordIndex3 = face.v3;
521
522 vf.n1 = this.normals[face.n1];
523 vf.n2 = this.normals[face.n2];
524 vf.n3 = this.normals[face.n3];
525
526 vf.uv1 = this.uvs[face.uv1];
527 vf.uv2 = this.uvs[face.uv2];
528 vf.uv3 = this.uvs[face.uv3];
529
530 this.viewerFaces.Add(vf);
531 }
532 }
533
534 /// <summary>
535 /// Adds a value to each XYZ vertex coordinate in the mesh
536 /// </summary>
537 /// <param name="x"></param>
538 /// <param name="y"></param>
539 /// <param name="z"></param>
540 public void AddPos(float x, float y, float z)
541 {
542 int i;
543 int numVerts = this.coords.Count;
544 Coord vert;
545
546 for (i = 0; i < numVerts; i++)
547 {
548 vert = this.coords[i];
549 vert.X += x;
550 vert.Y += y;
551 vert.Z += z;
552 this.coords[i] = vert;
553 }
554
555 if (this.viewerFaces != null)
556 {
557 int numViewerFaces = this.viewerFaces.Count;
558
559 for (i = 0; i < numViewerFaces; i++)
560 {
561 ViewerFace v = this.viewerFaces[i];
562 v.AddPos(x, y, z);
563 this.viewerFaces[i] = v;
564 }
565 }
566 }
567
568 /// <summary>
569 /// Rotates the mesh
570 /// </summary>
571 /// <param name="q"></param>
572 public void AddRot(Quat q)
573 {
574 int i;
575 int numVerts = this.coords.Count;
576
577 for (i = 0; i < numVerts; i++)
578 this.coords[i] *= q;
579
580 int numNormals = this.normals.Count;
581 for (i = 0; i < numNormals; i++)
582 this.normals[i] *= q;
583
584 if (this.viewerFaces != null)
585 {
586 int numViewerFaces = this.viewerFaces.Count;
587
588 for (i = 0; i < numViewerFaces; i++)
589 {
590 ViewerFace v = this.viewerFaces[i];
591 v.v1 *= q;
592 v.v2 *= q;
593 v.v3 *= q;
594
595 v.n1 *= q;
596 v.n2 *= q;
597 v.n3 *= q;
598
599 this.viewerFaces[i] = v;
600 }
601 }
602 }
603
604 public void Scale(float x, float y, float z)
605 {
606 int i;
607 int numVerts = this.coords.Count;
608
609 Coord m = new Coord(x, y, z);
610 for (i = 0; i < numVerts; i++)
611 this.coords[i] *= m;
612
613 if (this.viewerFaces != null)
614 {
615 int numViewerFaces = this.viewerFaces.Count;
616 for (i = 0; i < numViewerFaces; i++)
617 {
618 ViewerFace v = this.viewerFaces[i];
619 v.v1 *= m;
620 v.v2 *= m;
621 v.v3 *= m;
622 this.viewerFaces[i] = v;
623 }
624 }
625 }
626
627 public void DumpRaw(String path, String name, String title)
628 {
629 if (path == null)
630 return;
631 String fileName = name + "_" + title + ".raw";
632 String completePath = System.IO.Path.Combine(path, fileName);
633 StreamWriter sw = new StreamWriter(completePath);
634
635 for (int i = 0; i < this.faces.Count; i++)
636 {
637 string s = this.coords[this.faces[i].v1].ToString();
638 s += " " + this.coords[this.faces[i].v2].ToString();
639 s += " " + this.coords[this.faces[i].v3].ToString();
640
641 sw.WriteLine(s);
642 }
643
644 sw.Close();
645 }
646 }
647}
diff --git a/OpenSim/Server/Handlers/Presence/PresenceServerPostHandler.cs b/OpenSim/Server/Handlers/Presence/PresenceServerPostHandler.cs
index 4ebf933..3104917 100644
--- a/OpenSim/Server/Handlers/Presence/PresenceServerPostHandler.cs
+++ b/OpenSim/Server/Handlers/Presence/PresenceServerPostHandler.cs
@@ -90,8 +90,6 @@ namespace OpenSim.Server.Handlers.Presence
90 return GetAgent(request); 90 return GetAgent(request);
91 case "getagents": 91 case "getagents":
92 return GetAgents(request); 92 return GetAgents(request);
93 case "sethome":
94 return SetHome(request);
95 } 93 }
96 m_log.DebugFormat("[PRESENCE HANDLER]: unknown method request: {0}", method); 94 m_log.DebugFormat("[PRESENCE HANDLER]: unknown method request: {0}", method);
97 } 95 }
@@ -140,12 +138,7 @@ namespace OpenSim.Server.Handlers.Presence
140 if (!UUID.TryParse(request["SessionID"].ToString(), out session)) 138 if (!UUID.TryParse(request["SessionID"].ToString(), out session))
141 return FailureResult(); 139 return FailureResult();
142 140
143 if (request.ContainsKey("Position") && request["Position"] != null) 141 if (m_PresenceService.LogoutAgent(session))
144 Vector3.TryParse(request["Position"].ToString(), out position);
145 if (request.ContainsKey("LookAt") && request["Position"] != null)
146 Vector3.TryParse(request["LookAt"].ToString(), out lookat);
147
148 if (m_PresenceService.LogoutAgent(session, position, lookat))
149 return SuccessResult(); 142 return SuccessResult();
150 143
151 return FailureResult(); 144 return FailureResult();
@@ -171,8 +164,6 @@ namespace OpenSim.Server.Handlers.Presence
171 { 164 {
172 UUID session = UUID.Zero; 165 UUID session = UUID.Zero;
173 UUID region = UUID.Zero; 166 UUID region = UUID.Zero;
174 Vector3 position = new Vector3(128, 128, 70);
175 Vector3 look = Vector3.Zero;
176 167
177 if (!request.ContainsKey("SessionID") || !request.ContainsKey("RegionID")) 168 if (!request.ContainsKey("SessionID") || !request.ContainsKey("RegionID"))
178 return FailureResult(); 169 return FailureResult();
@@ -183,13 +174,7 @@ namespace OpenSim.Server.Handlers.Presence
183 if (!UUID.TryParse(request["RegionID"].ToString(), out region)) 174 if (!UUID.TryParse(request["RegionID"].ToString(), out region))
184 return FailureResult(); 175 return FailureResult();
185 176
186 if (request.ContainsKey("position")) 177 if (m_PresenceService.ReportAgent(session, region))
187 Vector3.TryParse(request["position"].ToString(), out position);
188
189 if (request.ContainsKey("lookAt"))
190 Vector3.TryParse(request["lookAt"].ToString(), out look);
191
192 if (m_PresenceService.ReportAgent(session, region, position, look))
193 { 178 {
194 return SuccessResult(); 179 return SuccessResult();
195 } 180 }
@@ -318,31 +303,5 @@ namespace OpenSim.Server.Handlers.Presence
318 return ms.ToArray(); 303 return ms.ToArray();
319 } 304 }
320 305
321 byte[] SetHome(Dictionary<string, object> request)
322 {
323 UUID region = UUID.Zero;
324 Vector3 position = new Vector3(128, 128, 70);
325 Vector3 look = Vector3.Zero;
326
327 if (!request.ContainsKey("UserID") || !request.ContainsKey("RegionID"))
328 return FailureResult();
329
330 string user = request["UserID"].ToString();
331
332 if (!UUID.TryParse(request["RegionID"].ToString(), out region))
333 return FailureResult();
334
335 if (request.ContainsKey("position"))
336 Vector3.TryParse(request["position"].ToString(), out position);
337
338 if (request.ContainsKey("lookAt"))
339 Vector3.TryParse(request["lookAt"].ToString(), out look);
340
341 if (m_PresenceService.SetHomeLocation(user, region, position, look))
342 return SuccessResult();
343
344 return FailureResult();
345 }
346
347 } 306 }
348} 307}
diff --git a/OpenSim/Services/Connectors/GridUser/GridUserServiceConnector.cs b/OpenSim/Services/Connectors/GridUser/GridUserServiceConnector.cs
index 0e85067..b4500a5 100644
--- a/OpenSim/Services/Connectors/GridUser/GridUserServiceConnector.cs
+++ b/OpenSim/Services/Connectors/GridUser/GridUserServiceConnector.cs
@@ -25,14 +25,206 @@
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 log4net;
28using System; 29using System;
30using System.Collections.Generic;
31using System.IO;
32using System.Reflection;
33using Nini.Config;
34using OpenSim.Framework;
35using OpenSim.Framework.Communications;
36using OpenSim.Framework.Servers.HttpServer;
37using OpenSim.Services.Interfaces;
38using GridRegion = OpenSim.Services.Interfaces.GridRegion;
39using OpenSim.Server.Base;
40using OpenMetaverse;
29 41
30namespace OpenSim.Services.Connectors 42namespace OpenSim.Services.Connectors
31{ 43{
32 public class GridUserServiceConnector 44 public class GridUserServicesConnector : IGridUserService
33 { 45 {
34 public GridUserServiceConnector() 46 private static readonly ILog m_log =
47 LogManager.GetLogger(
48 MethodBase.GetCurrentMethod().DeclaringType);
49
50 private string m_ServerURI = String.Empty;
51
52 public GridUserServicesConnector()
53 {
54 }
55
56 public GridUserServicesConnector(string serverURI)
57 {
58 m_ServerURI = serverURI.TrimEnd('/');
59 }
60
61 public GridUserServicesConnector(IConfigSource source)
62 {
63 Initialise(source);
64 }
65
66 public virtual void Initialise(IConfigSource source)
67 {
68 IConfig gridConfig = source.Configs["GridUserService"];
69 if (gridConfig == null)
70 {
71 m_log.Error("[GRID USER CONNECTOR]: GridUserService missing from OpenSim.ini");
72 throw new Exception("GridUser connector init error");
73 }
74
75 string serviceURI = gridConfig.GetString("GridUserServerURI",
76 String.Empty);
77
78 if (serviceURI == String.Empty)
79 {
80 m_log.Error("[GRID USER CONNECTOR]: No Server URI named in section GridUserService");
81 throw new Exception("GridUser connector init error");
82 }
83 m_ServerURI = serviceURI;
84 }
85
86
87 #region IPresenceService
88
89
90 public GridUserInfo LoggedIn(string userID)
91 {
92 Dictionary<string, object> sendData = new Dictionary<string, object>();
93 //sendData["SCOPEID"] = scopeID.ToString();
94 sendData["VERSIONMIN"] = ProtocolVersions.ClientProtocolVersionMin.ToString();
95 sendData["VERSIONMAX"] = ProtocolVersions.ClientProtocolVersionMax.ToString();
96 sendData["METHOD"] = "loggedin";
97
98 sendData["UserID"] = userID;
99
100 return Get(sendData);
101
102 }
103
104 public bool LoggedOut(string userID, UUID region, Vector3 position, Vector3 lookat)
105 {
106 Dictionary<string, object> sendData = new Dictionary<string, object>();
107 //sendData["SCOPEID"] = scopeID.ToString();
108 sendData["VERSIONMIN"] = ProtocolVersions.ClientProtocolVersionMin.ToString();
109 sendData["VERSIONMAX"] = ProtocolVersions.ClientProtocolVersionMax.ToString();
110 sendData["METHOD"] = "loggedout";
111
112 return Set(sendData, userID, region, position, lookat);
113 }
114
115 public bool SetHome(string userID, UUID regionID, Vector3 position, Vector3 lookAt)
116 {
117 Dictionary<string, object> sendData = new Dictionary<string, object>();
118 //sendData["SCOPEID"] = scopeID.ToString();
119 sendData["VERSIONMIN"] = ProtocolVersions.ClientProtocolVersionMin.ToString();
120 sendData["VERSIONMAX"] = ProtocolVersions.ClientProtocolVersionMax.ToString();
121 sendData["METHOD"] = "sethome";
122
123 return Set(sendData, userID, regionID, position, lookAt);
124 }
125
126 public bool SetLastPosition(string userID, UUID regionID, Vector3 position, Vector3 lookAt)
127 {
128 Dictionary<string, object> sendData = new Dictionary<string, object>();
129 //sendData["SCOPEID"] = scopeID.ToString();
130 sendData["VERSIONMIN"] = ProtocolVersions.ClientProtocolVersionMin.ToString();
131 sendData["VERSIONMAX"] = ProtocolVersions.ClientProtocolVersionMax.ToString();
132 sendData["METHOD"] = "setposition";
133
134 return Set(sendData, userID, regionID, position, lookAt);
135 }
136
137 public GridUserInfo GetGridUserInfo(string userID)
138 {
139 Dictionary<string, object> sendData = new Dictionary<string, object>();
140 //sendData["SCOPEID"] = scopeID.ToString();
141 sendData["VERSIONMIN"] = ProtocolVersions.ClientProtocolVersionMin.ToString();
142 sendData["VERSIONMAX"] = ProtocolVersions.ClientProtocolVersionMax.ToString();
143 sendData["METHOD"] = "getgriduserinfo";
144
145 sendData["UserID"] = userID;
146
147 return Get(sendData);
148 }
149
150 #endregion
151
152 protected bool Set(Dictionary<string, object> sendData, string userID, UUID regionID, Vector3 position, Vector3 lookAt)
153 {
154 sendData["UserID"] = userID;
155 sendData["RegionID"] = regionID.ToString();
156 sendData["Position"] = position.ToString();
157 sendData["LookAt"] = lookAt.ToString();
158
159 string reqString = ServerUtils.BuildQueryString(sendData);
160 // m_log.DebugFormat("[GRID USER CONNECTOR]: queryString = {0}", reqString);
161 try
162 {
163 string reply = SynchronousRestFormsRequester.MakeRequest("POST",
164 m_ServerURI + "/griduser",
165 reqString);
166 if (reply != string.Empty)
167 {
168 Dictionary<string, object> replyData = ServerUtils.ParseXmlResponse(reply);
169
170 if (replyData.ContainsKey("result"))
171 {
172 if (replyData["result"].ToString().ToLower() == "success")
173 return true;
174 else
175 return false;
176 }
177 else
178 m_log.DebugFormat("[GRID USER CONNECTOR]: SetPosition reply data does not contain result field");
179
180 }
181 else
182 m_log.DebugFormat("[GRID USER CONNECTOR]: SetPosition received empty reply");
183 }
184 catch (Exception e)
185 {
186 m_log.DebugFormat("[GRID USER CONNECTOR]: Exception when contacting grid user server: {0}", e.Message);
187 }
188
189 return false;
190 }
191
192 protected GridUserInfo Get(Dictionary<string, object> sendData)
35 { 193 {
194 string reqString = ServerUtils.BuildQueryString(sendData);
195 // m_log.DebugFormat("[GRID USER CONNECTOR]: queryString = {0}", reqString);
196 try
197 {
198 string reply = SynchronousRestFormsRequester.MakeRequest("POST",
199 m_ServerURI + "/griduser",
200 reqString);
201 if (reply != string.Empty)
202 {
203 Dictionary<string, object> replyData = ServerUtils.ParseXmlResponse(reply);
204 GridUserInfo guinfo = null;
205
206 if ((replyData != null) && replyData.ContainsKey("result") && (replyData["result"] != null))
207 {
208 if (replyData["result"] is Dictionary<string, object>)
209 {
210 guinfo = new GridUserInfo((Dictionary<string, object>)replyData["result"]);
211 }
212 }
213
214 return guinfo;
215
216 }
217 else
218 m_log.DebugFormat("[GRID USER CONNECTOR]: Loggedin received empty reply");
219 }
220 catch (Exception e)
221 {
222 m_log.DebugFormat("[GRID USER CONNECTOR]: Exception when contacting grid user server: {0}", e.Message);
223 }
224
225 return null;
226
36 } 227 }
228
37 } 229 }
38} 230}
diff --git a/OpenSim/Services/Connectors/Presence/PresenceServiceConnector.cs b/OpenSim/Services/Connectors/Presence/PresenceServiceConnector.cs
index 23621b7..41ebeaf 100644
--- a/OpenSim/Services/Connectors/Presence/PresenceServiceConnector.cs
+++ b/OpenSim/Services/Connectors/Presence/PresenceServiceConnector.cs
@@ -132,7 +132,7 @@ namespace OpenSim.Services.Connectors
132 132
133 } 133 }
134 134
135 public bool LogoutAgent(UUID sessionID, Vector3 position, Vector3 lookat) 135 public bool LogoutAgent(UUID sessionID)
136 { 136 {
137 Dictionary<string, object> sendData = new Dictionary<string, object>(); 137 Dictionary<string, object> sendData = new Dictionary<string, object>();
138 //sendData["SCOPEID"] = scopeID.ToString(); 138 //sendData["SCOPEID"] = scopeID.ToString();
@@ -141,8 +141,6 @@ namespace OpenSim.Services.Connectors
141 sendData["METHOD"] = "logout"; 141 sendData["METHOD"] = "logout";
142 142
143 sendData["SessionID"] = sessionID.ToString(); 143 sendData["SessionID"] = sessionID.ToString();
144 sendData["Position"] = position.ToString();
145 sendData["LookAt"] = lookat.ToString();
146 144
147 string reqString = ServerUtils.BuildQueryString(sendData); 145 string reqString = ServerUtils.BuildQueryString(sendData);
148 // m_log.DebugFormat("[PRESENCE CONNECTOR]: queryString = {0}", reqString); 146 // m_log.DebugFormat("[PRESENCE CONNECTOR]: queryString = {0}", reqString);
@@ -220,7 +218,7 @@ namespace OpenSim.Services.Connectors
220 return false; 218 return false;
221 } 219 }
222 220
223 public bool ReportAgent(UUID sessionID, UUID regionID, Vector3 position, Vector3 lookAt) 221 public bool ReportAgent(UUID sessionID, UUID regionID)
224 { 222 {
225 Dictionary<string, object> sendData = new Dictionary<string, object>(); 223 Dictionary<string, object> sendData = new Dictionary<string, object>();
226 //sendData["SCOPEID"] = scopeID.ToString(); 224 //sendData["SCOPEID"] = scopeID.ToString();
@@ -230,8 +228,6 @@ namespace OpenSim.Services.Connectors
230 228
231 sendData["SessionID"] = sessionID.ToString(); 229 sendData["SessionID"] = sessionID.ToString();
232 sendData["RegionID"] = regionID.ToString(); 230 sendData["RegionID"] = regionID.ToString();
233 sendData["position"] = position.ToString();
234 sendData["lookAt"] = lookAt.ToString();
235 231
236 string reqString = ServerUtils.BuildQueryString(sendData); 232 string reqString = ServerUtils.BuildQueryString(sendData);
237 // m_log.DebugFormat("[PRESENCE CONNECTOR]: queryString = {0}", reqString); 233 // m_log.DebugFormat("[PRESENCE CONNECTOR]: queryString = {0}", reqString);
@@ -371,52 +367,6 @@ namespace OpenSim.Services.Connectors
371 } 367 }
372 368
373 369
374 public bool SetHomeLocation(string userID, UUID regionID, Vector3 position, Vector3 lookAt)
375 {
376 Dictionary<string, object> sendData = new Dictionary<string, object>();
377 //sendData["SCOPEID"] = scopeID.ToString();
378 sendData["VERSIONMIN"] = ProtocolVersions.ClientProtocolVersionMin.ToString();
379 sendData["VERSIONMAX"] = ProtocolVersions.ClientProtocolVersionMax.ToString();
380 sendData["METHOD"] = "sethome";
381
382 sendData["UserID"] = userID;
383 sendData["RegionID"] = regionID.ToString();
384 sendData["position"] = position.ToString();
385 sendData["lookAt"] = lookAt.ToString();
386
387 string reqString = ServerUtils.BuildQueryString(sendData);
388 // m_log.DebugFormat("[PRESENCE CONNECTOR]: queryString = {0}", reqString);
389 try
390 {
391 string reply = SynchronousRestFormsRequester.MakeRequest("POST",
392 m_ServerURI + "/presence",
393 reqString);
394 if (reply != string.Empty)
395 {
396 Dictionary<string, object> replyData = ServerUtils.ParseXmlResponse(reply);
397
398 if (replyData.ContainsKey("result"))
399 {
400 if (replyData["result"].ToString().ToLower() == "success")
401 return true;
402 else
403 return false;
404 }
405 else
406 m_log.DebugFormat("[PRESENCE CONNECTOR]: SetHomeLocation reply data does not contain result field");
407
408 }
409 else
410 m_log.DebugFormat("[PRESENCE CONNECTOR]: SetHomeLocation received empty reply");
411 }
412 catch (Exception e)
413 {
414 m_log.DebugFormat("[PRESENCE CONNECTOR]: Exception when contacting presence server: {0}", e.Message);
415 }
416
417 return false;
418 }
419
420 #endregion 370 #endregion
421 371
422 } 372 }
diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianPresenceServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianPresenceServiceConnector.cs
index c324272..e48b7de 100644
--- a/OpenSim/Services/Connectors/SimianGrid/SimianPresenceServiceConnector.cs
+++ b/OpenSim/Services/Connectors/SimianGrid/SimianPresenceServiceConnector.cs
@@ -51,7 +51,7 @@ namespace OpenSim.Services.Connectors.SimianGrid
51 /// message routing) to the SimianGrid backend 51 /// message routing) to the SimianGrid backend
52 /// </summary> 52 /// </summary>
53 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")] 53 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")]
54 public class SimianPresenceServiceConnector : IPresenceService, ISharedRegionModule 54 public class SimianPresenceServiceConnector : IPresenceService, IGridUserService, ISharedRegionModule
55 { 55 {
56 private static readonly ILog m_log = 56 private static readonly ILog m_log =
57 LogManager.GetLogger( 57 LogManager.GetLogger(
@@ -73,6 +73,7 @@ namespace OpenSim.Services.Connectors.SimianGrid
73 if (!String.IsNullOrEmpty(m_serverUrl)) 73 if (!String.IsNullOrEmpty(m_serverUrl))
74 { 74 {
75 scene.RegisterModuleInterface<IPresenceService>(this); 75 scene.RegisterModuleInterface<IPresenceService>(this);
76 scene.RegisterModuleInterface<IGridUserService>(this);
76 77
77 scene.EventManager.OnMakeRootAgent += MakeRootAgentHandler; 78 scene.EventManager.OnMakeRootAgent += MakeRootAgentHandler;
78 scene.EventManager.OnNewClient += NewClientHandler; 79 scene.EventManager.OnNewClient += NewClientHandler;
@@ -86,6 +87,7 @@ namespace OpenSim.Services.Connectors.SimianGrid
86 if (!String.IsNullOrEmpty(m_serverUrl)) 87 if (!String.IsNullOrEmpty(m_serverUrl))
87 { 88 {
88 scene.UnregisterModuleInterface<IPresenceService>(this); 89 scene.UnregisterModuleInterface<IPresenceService>(this);
90 scene.UnregisterModuleInterface<IGridUserService>(this);
89 91
90 scene.EventManager.OnMakeRootAgent -= MakeRootAgentHandler; 92 scene.EventManager.OnMakeRootAgent -= MakeRootAgentHandler;
91 scene.EventManager.OnNewClient -= NewClientHandler; 93 scene.EventManager.OnNewClient -= NewClientHandler;
@@ -151,7 +153,7 @@ namespace OpenSim.Services.Connectors.SimianGrid
151 return success; 153 return success;
152 } 154 }
153 155
154 public bool LogoutAgent(UUID sessionID, Vector3 position, Vector3 lookAt) 156 public bool LogoutAgent(UUID sessionID)
155 { 157 {
156 m_log.InfoFormat("[SIMIAN PRESENCE CONNECTOR]: Logout requested for agent with sessionID " + sessionID); 158 m_log.InfoFormat("[SIMIAN PRESENCE CONNECTOR]: Logout requested for agent with sessionID " + sessionID);
157 159
@@ -189,7 +191,12 @@ namespace OpenSim.Services.Connectors.SimianGrid
189 return success; 191 return success;
190 } 192 }
191 193
192 public bool ReportAgent(UUID sessionID, UUID regionID, Vector3 position, Vector3 lookAt) 194 public bool ReportAgent(UUID sessionID, UUID regionID)
195 {
196 return ReportAgent(sessionID, regionID, Vector3.Zero, Vector3.Zero);
197 }
198
199 protected bool ReportAgent(UUID sessionID, UUID regionID, Vector3 position, Vector3 lookAt)
193 { 200 {
194 //m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Updating session data for agent with sessionID " + sessionID); 201 //m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Updating session data for agent with sessionID " + sessionID);
195 202
@@ -261,7 +268,23 @@ namespace OpenSim.Services.Connectors.SimianGrid
261 return presences.ToArray(); 268 return presences.ToArray();
262 } 269 }
263 270
264 public bool SetHomeLocation(string userID, UUID regionID, Vector3 position, Vector3 lookAt) 271 #endregion IPresenceService
272
273 #region IGridUserService
274
275 public GridUserInfo LoggedIn(string userID)
276 {
277 // never implemented at the sim
278 return null;
279 }
280
281 public bool LoggedOut(string userID, UUID regionID, Vector3 lastPosition, Vector3 lastLookAt)
282 {
283 // Not needed for simian grid, event handler is doing it
284 return true;
285 }
286
287 public bool SetHome(string userID, UUID regionID, Vector3 position, Vector3 lookAt)
265 { 288 {
266 m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Setting home location for user " + userID); 289 m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Setting home location for user " + userID);
267 290
@@ -281,7 +304,35 @@ namespace OpenSim.Services.Connectors.SimianGrid
281 return success; 304 return success;
282 } 305 }
283 306
284 #endregion IPresenceService 307 public bool SetLastPosition(string userID, UUID regionID, Vector3 lastPosition, Vector3 lastLookAt)
308 {
309 // Not needed for simian grid, presence detection is doing it
310 return true;
311 }
312
313 public GridUserInfo GetGridUserInfo(string user)
314 {
315 m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Requesting session data for agent " + user);
316
317 UUID userID = new UUID(user);
318 m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Requesting user data for " + userID);
319
320 NameValueCollection requestArgs = new NameValueCollection
321 {
322 { "RequestMethod", "GetUser" },
323 { "UserID", userID.ToString() }
324 };
325
326 OSDMap userResponse = WebUtil.PostToService(m_serverUrl, requestArgs);
327 if (userResponse["Success"].AsBoolean())
328 return ResponseToGridUserInfo(userResponse);
329 else
330 m_log.Warn("[SIMIAN PRESENCE CONNECTOR]: Failed to retrieve user data for " + userID + ": " + userResponse["Message"].AsString());
331
332 return null;
333 }
334
335 #endregion
285 336
286 #region Presence Detection 337 #region Presence Detection
287 338
@@ -325,7 +376,7 @@ namespace OpenSim.Services.Connectors.SimianGrid
325 SetLastLocation(client.SessionId); 376 SetLastLocation(client.SessionId);
326 } 377 }
327 378
328 LogoutAgent(client.SessionId, Vector3.Zero, Vector3.UnitX); 379 LogoutAgent(client.SessionId);
329 } 380 }
330 } 381 }
331 382
@@ -478,6 +529,31 @@ namespace OpenSim.Services.Connectors.SimianGrid
478 return info; 529 return info;
479 } 530 }
480 531
532 private GridUserInfo ResponseToGridUserInfo(OSDMap userResponse)
533 {
534 if (userResponse != null && userResponse["User"] is OSDMap)
535 {
536
537 GridUserInfo info = new GridUserInfo();
538
539 info.Online = true;
540 info.UserID = userResponse["UserID"].AsUUID().ToString();
541 info.LastRegionID = userResponse["SceneID"].AsUUID();
542 info.LastPosition = userResponse["ScenePosition"].AsVector3();
543 info.LastLookAt = userResponse["SceneLookAt"].AsVector3();
544
545 OSDMap user = (OSDMap)userResponse["User"];
546
547 info.Login = user["LastLoginDate"].AsDate();
548 info.Logout = user["LastLogoutDate"].AsDate();
549 DeserializeLocation(user["HomeLocation"].AsString(), out info.HomeRegionID, out info.HomePosition, out info.HomeLookAt);
550
551 return info;
552 }
553
554 return null;
555 }
556
481 private string SerializeLocation(UUID regionID, Vector3 position, Vector3 lookAt) 557 private string SerializeLocation(UUID regionID, Vector3 position, Vector3 lookAt)
482 { 558 {
483 return "{" + String.Format("\"SceneID\":\"{0}\",\"Position\":\"{1}\",\"LookAt\":\"{2}\"", regionID, position, lookAt) + "}"; 559 return "{" + String.Format("\"SceneID\":\"{0}\",\"Position\":\"{1}\",\"LookAt\":\"{2}\"", regionID, position, lookAt) + "}";
diff --git a/OpenSim/Services/HypergridService/UserAgentService.cs b/OpenSim/Services/HypergridService/UserAgentService.cs
index 26f211b..3af7ef9 100644
--- a/OpenSim/Services/HypergridService/UserAgentService.cs
+++ b/OpenSim/Services/HypergridService/UserAgentService.cs
@@ -59,7 +59,7 @@ namespace OpenSim.Services.HypergridService
59 59
60 static bool m_Initialized = false; 60 static bool m_Initialized = false;
61 61
62 protected static IPresenceService m_PresenceService; 62 protected static IGridUserService m_GridUserService;
63 protected static IGridService m_GridService; 63 protected static IGridService m_GridService;
64 protected static GatekeeperServiceConnector m_GatekeeperConnector; 64 protected static GatekeeperServiceConnector m_GatekeeperConnector;
65 65
@@ -74,14 +74,14 @@ namespace OpenSim.Services.HypergridService
74 throw new Exception(String.Format("No section UserAgentService in config file")); 74 throw new Exception(String.Format("No section UserAgentService in config file"));
75 75
76 string gridService = serverConfig.GetString("GridService", String.Empty); 76 string gridService = serverConfig.GetString("GridService", String.Empty);
77 string presenceService = serverConfig.GetString("PresenceService", String.Empty); 77 string gridUserService = serverConfig.GetString("GridUserService", String.Empty);
78 78
79 if (gridService == string.Empty || presenceService == string.Empty) 79 if (gridService == string.Empty || gridUserService == string.Empty)
80 throw new Exception(String.Format("Incomplete specifications, UserAgent Service cannot function.")); 80 throw new Exception(String.Format("Incomplete specifications, UserAgent Service cannot function."));
81 81
82 Object[] args = new Object[] { config }; 82 Object[] args = new Object[] { config };
83 m_GridService = ServerUtils.LoadPlugin<IGridService>(gridService, args); 83 m_GridService = ServerUtils.LoadPlugin<IGridService>(gridService, args);
84 m_PresenceService = ServerUtils.LoadPlugin<IPresenceService>(presenceService, args); 84 m_GridUserService = ServerUtils.LoadPlugin<IGridUserService>(gridUserService, args);
85 m_GatekeeperConnector = new GatekeeperServiceConnector(); 85 m_GatekeeperConnector = new GatekeeperServiceConnector();
86 86
87 m_Initialized = true; 87 m_Initialized = true;
@@ -95,15 +95,14 @@ namespace OpenSim.Services.HypergridService
95 m_log.DebugFormat("[USER AGENT SERVICE]: Request to get home region of user {0}", userID); 95 m_log.DebugFormat("[USER AGENT SERVICE]: Request to get home region of user {0}", userID);
96 96
97 GridRegion home = null; 97 GridRegion home = null;
98 PresenceInfo[] presences = m_PresenceService.GetAgents(new string[] { userID.ToString() }); 98 GridUserInfo uinfo = m_GridUserService.GetGridUserInfo(userID.ToString());
99 if (presences != null && presences.Length > 0) 99 if (uinfo != null)
100 { 100 {
101 UUID homeID = presences[0].HomeRegionID; 101 if (uinfo.HomeRegionID != UUID.Zero)
102 if (homeID != UUID.Zero)
103 { 102 {
104 home = m_GridService.GetRegionByUUID(UUID.Zero, homeID); 103 home = m_GridService.GetRegionByUUID(UUID.Zero, uinfo.HomeRegionID);
105 position = presences[0].HomePosition; 104 position = uinfo.HomePosition;
106 lookAt = presences[0].HomeLookAt; 105 lookAt = uinfo.HomeLookAt;
107 } 106 }
108 if (home == null) 107 if (home == null)
109 { 108 {
diff --git a/OpenSim/Services/Interfaces/IGridUserService.cs b/OpenSim/Services/Interfaces/IGridUserService.cs
index a7c2c6f..e629dff 100644
--- a/OpenSim/Services/Interfaces/IGridUserService.cs
+++ b/OpenSim/Services/Interfaces/IGridUserService.cs
@@ -37,39 +37,79 @@ namespace OpenSim.Services.Interfaces
37 public class GridUserInfo 37 public class GridUserInfo
38 { 38 {
39 public string UserID; 39 public string UserID;
40
40 public UUID HomeRegionID; 41 public UUID HomeRegionID;
41 public Vector3 HomePosition; 42 public Vector3 HomePosition;
42 public Vector3 HomeLookAt; 43 public Vector3 HomeLookAt;
43 44
45 public UUID LastRegionID;
46 public Vector3 LastPosition;
47 public Vector3 LastLookAt;
48
49 public bool Online;
50 public DateTime Login;
51 public DateTime Logout;
52
44 public GridUserInfo() {} 53 public GridUserInfo() {}
45 54
46 public GridUserInfo(Dictionary<string, object> kvp) 55 public GridUserInfo(Dictionary<string, object> kvp)
47 { 56 {
48 if (kvp.ContainsKey("UserID")) 57 if (kvp.ContainsKey("UserID"))
49 UserID = kvp["UserID"].ToString(); 58 UserID = kvp["UserID"].ToString();
59
50 if (kvp.ContainsKey("HomeRegionID")) 60 if (kvp.ContainsKey("HomeRegionID"))
51 UUID.TryParse(kvp["HomeRegionID"].ToString(), out HomeRegionID); 61 UUID.TryParse(kvp["HomeRegionID"].ToString(), out HomeRegionID);
52 if (kvp.ContainsKey("HomePosition")) 62 if (kvp.ContainsKey("HomePosition"))
53 Vector3.TryParse(kvp["HomePosition"].ToString(), out HomePosition); 63 Vector3.TryParse(kvp["HomePosition"].ToString(), out HomePosition);
54 if (kvp.ContainsKey("HomeLookAt")) 64 if (kvp.ContainsKey("HomeLookAt"))
55 Vector3.TryParse(kvp["HomeLookAt"].ToString(), out HomeLookAt); 65 Vector3.TryParse(kvp["HomeLookAt"].ToString(), out HomeLookAt);
66
67 if (kvp.ContainsKey("LastRegionID"))
68 UUID.TryParse(kvp["LastRegionID"].ToString(), out HomeRegionID);
69 if (kvp.ContainsKey("LastPosition"))
70 Vector3.TryParse(kvp["LastPosition"].ToString(), out LastPosition);
71 if (kvp.ContainsKey("LastLookAt"))
72 Vector3.TryParse(kvp["LastLookAt"].ToString(), out LastLookAt);
73
74 if (kvp.ContainsKey("Login"))
75 DateTime.TryParse(kvp["Login"].ToString(), out Login);
76 if (kvp.ContainsKey("Logout"))
77 DateTime.TryParse(kvp["Logout"].ToString(), out Logout);
78 if (kvp.ContainsKey("Online"))
79 Boolean.TryParse(kvp["Online"].ToString(), out Online);
80
56 } 81 }
57 82
58 public Dictionary<string, object> ToKeyValuePairs() 83 public Dictionary<string, object> ToKeyValuePairs()
59 { 84 {
60 Dictionary<string, object> result = new Dictionary<string, object>(); 85 Dictionary<string, object> result = new Dictionary<string, object>();
61 result["UserID"] = UserID; 86 result["UserID"] = UserID;
87
62 result["HomeRegionID"] = HomeRegionID.ToString(); 88 result["HomeRegionID"] = HomeRegionID.ToString();
63 result["HomePosition"] = HomePosition.ToString(); 89 result["HomePosition"] = HomePosition.ToString();
64 result["HomeLookAt"] = HomeLookAt.ToString(); 90 result["HomeLookAt"] = HomeLookAt.ToString();
65 91
92 result["LastRegionID"] = LastRegionID.ToString();
93 result["LastPosition"] = LastPosition.ToString();
94 result["LastLookAt"] = LastLookAt.ToString();
95
96 result["Online"] = Online.ToString();
97 result["Login"] = Login.ToString();
98 result["Logout"] = Logout.ToString();
99
100
66 return result; 101 return result;
67 } 102 }
68 } 103 }
69 104
70 public interface IGridUserService 105 public interface IGridUserService
71 { 106 {
107 GridUserInfo LoggedIn(string userID);
108 bool LoggedOut(string userID, UUID regionID, Vector3 lastPosition, Vector3 lastLookAt);
109
110 bool SetHome(string userID, UUID homeID, Vector3 homePosition, Vector3 homeLookAt);
111 bool SetLastPosition(string userID, UUID regionID, Vector3 lastPosition, Vector3 lastLookAt);
112
72 GridUserInfo GetGridUserInfo(string userID); 113 GridUserInfo GetGridUserInfo(string userID);
73 bool StoreGridUserInfo(GridUserInfo info);
74 } 114 }
75} \ No newline at end of file 115} \ No newline at end of file
diff --git a/OpenSim/Services/Interfaces/IPresenceService.cs b/OpenSim/Services/Interfaces/IPresenceService.cs
index b4c1859..9687d22 100644
--- a/OpenSim/Services/Interfaces/IPresenceService.cs
+++ b/OpenSim/Services/Interfaces/IPresenceService.cs
@@ -55,23 +55,10 @@ namespace OpenSim.Services.Interfaces
55 UserID = kvp["UserID"].ToString(); 55 UserID = kvp["UserID"].ToString();
56 if (kvp.ContainsKey("RegionID")) 56 if (kvp.ContainsKey("RegionID"))
57 UUID.TryParse(kvp["RegionID"].ToString(), out RegionID); 57 UUID.TryParse(kvp["RegionID"].ToString(), out RegionID);
58 if (kvp.ContainsKey("login"))
59 DateTime.TryParse(kvp["login"].ToString(), out Login);
60 if (kvp.ContainsKey("logout"))
61 DateTime.TryParse(kvp["logout"].ToString(), out Logout);
62 if (kvp.ContainsKey("lookAt")) 58 if (kvp.ContainsKey("lookAt"))
63 Vector3.TryParse(kvp["lookAt"].ToString(), out LookAt); 59 Vector3.TryParse(kvp["lookAt"].ToString(), out LookAt);
64 if (kvp.ContainsKey("online"))
65 Boolean.TryParse(kvp["online"].ToString(), out Online);
66 if (kvp.ContainsKey("position")) 60 if (kvp.ContainsKey("position"))
67 Vector3.TryParse(kvp["position"].ToString(), out Position); 61 Vector3.TryParse(kvp["position"].ToString(), out Position);
68 if (kvp.ContainsKey("HomeRegionID"))
69 UUID.TryParse(kvp["HomeRegionID"].ToString(), out HomeRegionID);
70 if (kvp.ContainsKey("HomePosition"))
71 Vector3.TryParse(kvp["HomePosition"].ToString(), out HomePosition);
72 if (kvp.ContainsKey("HomeLookAt"))
73 Vector3.TryParse(kvp["HomeLookAt"].ToString(), out HomeLookAt);
74
75 } 62 }
76 63
77 public Dictionary<string, object> ToKeyValuePairs() 64 public Dictionary<string, object> ToKeyValuePairs()
@@ -79,14 +66,8 @@ namespace OpenSim.Services.Interfaces
79 Dictionary<string, object> result = new Dictionary<string, object>(); 66 Dictionary<string, object> result = new Dictionary<string, object>();
80 result["UserID"] = UserID; 67 result["UserID"] = UserID;
81 result["RegionID"] = RegionID.ToString(); 68 result["RegionID"] = RegionID.ToString();
82 result["online"] = Online.ToString();
83 result["login"] = Login.ToString();
84 result["logout"] = Logout.ToString();
85 result["position"] = Position.ToString(); 69 result["position"] = Position.ToString();
86 result["lookAt"] = LookAt.ToString(); 70 result["lookAt"] = LookAt.ToString();
87 result["HomeRegionID"] = HomeRegionID.ToString();
88 result["HomePosition"] = HomePosition.ToString();
89 result["HomeLookAt"] = HomeLookAt.ToString();
90 71
91 return result; 72 return result;
92 } 73 }
@@ -115,11 +96,10 @@ namespace OpenSim.Services.Interfaces
115 public interface IPresenceService 96 public interface IPresenceService
116 { 97 {
117 bool LoginAgent(string userID, UUID sessionID, UUID secureSessionID); 98 bool LoginAgent(string userID, UUID sessionID, UUID secureSessionID);
118 bool LogoutAgent(UUID sessionID, Vector3 position, Vector3 lookAt); 99 bool LogoutAgent(UUID sessionID);
119 bool LogoutRegionAgents(UUID regionID); 100 bool LogoutRegionAgents(UUID regionID);
120 101
121 bool ReportAgent(UUID sessionID, UUID regionID, Vector3 position, Vector3 lookAt); 102 bool ReportAgent(UUID sessionID, UUID regionID);
122 bool SetHomeLocation(string userID, UUID regionID, Vector3 position, Vector3 lookAt);
123 103
124 PresenceInfo GetAgent(UUID sessionID); 104 PresenceInfo GetAgent(UUID sessionID);
125 PresenceInfo[] GetAgents(string[] userIDs); 105 PresenceInfo[] GetAgents(string[] userIDs);
diff --git a/OpenSim/Services/LLLoginService/LLLoginResponse.cs b/OpenSim/Services/LLLoginService/LLLoginResponse.cs
index ee30fa3..d1dcfe7 100644
--- a/OpenSim/Services/LLLoginService/LLLoginResponse.cs
+++ b/OpenSim/Services/LLLoginService/LLLoginResponse.cs
@@ -215,7 +215,7 @@ namespace OpenSim.Services.LLLoginService
215 SetDefaultValues(); 215 SetDefaultValues();
216 } 216 }
217 217
218 public LLLoginResponse(UserAccount account, AgentCircuitData aCircuit, PresenceInfo pinfo, 218 public LLLoginResponse(UserAccount account, AgentCircuitData aCircuit, GridUserInfo pinfo,
219 GridRegion destination, List<InventoryFolderBase> invSkel, FriendInfo[] friendsList, ILibraryService libService, 219 GridRegion destination, List<InventoryFolderBase> invSkel, FriendInfo[] friendsList, ILibraryService libService,
220 string where, string startlocation, Vector3 position, Vector3 lookAt, string message, 220 string where, string startlocation, Vector3 position, Vector3 lookAt, string message,
221 GridRegion home, IPEndPoint clientIP) 221 GridRegion home, IPEndPoint clientIP)
@@ -283,7 +283,7 @@ namespace OpenSim.Services.LLLoginService
283 } 283 }
284 } 284 }
285 285
286 private void FillOutHomeData(PresenceInfo pinfo, GridRegion home) 286 private void FillOutHomeData(GridUserInfo pinfo, GridRegion home)
287 { 287 {
288 int x = 1000 * (int)Constants.RegionSize, y = 1000 * (int)Constants.RegionSize; 288 int x = 1000 * (int)Constants.RegionSize, y = 1000 * (int)Constants.RegionSize;
289 if (home != null) 289 if (home != null)
diff --git a/OpenSim/Services/LLLoginService/LLLoginService.cs b/OpenSim/Services/LLLoginService/LLLoginService.cs
index be90d38..f97222e 100644
--- a/OpenSim/Services/LLLoginService/LLLoginService.cs
+++ b/OpenSim/Services/LLLoginService/LLLoginService.cs
@@ -53,6 +53,7 @@ namespace OpenSim.Services.LLLoginService
53 private static bool Initialized = false; 53 private static bool Initialized = false;
54 54
55 protected IUserAccountService m_UserAccountService; 55 protected IUserAccountService m_UserAccountService;
56 protected IGridUserService m_GridUserService;
56 protected IAuthenticationService m_AuthenticationService; 57 protected IAuthenticationService m_AuthenticationService;
57 protected IInventoryService m_InventoryService; 58 protected IInventoryService m_InventoryService;
58 protected IGridService m_GridService; 59 protected IGridService m_GridService;
@@ -82,6 +83,7 @@ namespace OpenSim.Services.LLLoginService
82 throw new Exception(String.Format("No section LoginService in config file")); 83 throw new Exception(String.Format("No section LoginService in config file"));
83 84
84 string accountService = m_LoginServerConfig.GetString("UserAccountService", String.Empty); 85 string accountService = m_LoginServerConfig.GetString("UserAccountService", String.Empty);
86 string gridUserService = m_LoginServerConfig.GetString("GridUserService", String.Empty);
85 string agentService = m_LoginServerConfig.GetString("UserAgentService", String.Empty); 87 string agentService = m_LoginServerConfig.GetString("UserAgentService", String.Empty);
86 string authService = m_LoginServerConfig.GetString("AuthenticationService", String.Empty); 88 string authService = m_LoginServerConfig.GetString("AuthenticationService", String.Empty);
87 string invService = m_LoginServerConfig.GetString("InventoryService", String.Empty); 89 string invService = m_LoginServerConfig.GetString("InventoryService", String.Empty);
@@ -105,8 +107,10 @@ namespace OpenSim.Services.LLLoginService
105 107
106 Object[] args = new Object[] { config }; 108 Object[] args = new Object[] { config };
107 m_UserAccountService = ServerUtils.LoadPlugin<IUserAccountService>(accountService, args); 109 m_UserAccountService = ServerUtils.LoadPlugin<IUserAccountService>(accountService, args);
110 m_GridUserService = ServerUtils.LoadPlugin<IGridUserService>(gridUserService, args);
108 m_AuthenticationService = ServerUtils.LoadPlugin<IAuthenticationService>(authService, args); 111 m_AuthenticationService = ServerUtils.LoadPlugin<IAuthenticationService>(authService, args);
109 m_InventoryService = ServerUtils.LoadPlugin<IInventoryService>(invService, args); 112 m_InventoryService = ServerUtils.LoadPlugin<IInventoryService>(invService, args);
113
110 if (gridService != string.Empty) 114 if (gridService != string.Empty)
111 m_GridService = ServerUtils.LoadPlugin<IGridService>(gridService, args); 115 m_GridService = ServerUtils.LoadPlugin<IGridService>(gridService, args);
112 if (presenceService != string.Empty) 116 if (presenceService != string.Empty)
@@ -271,8 +275,6 @@ namespace OpenSim.Services.LLLoginService
271 // 275 //
272 // Login the presence 276 // Login the presence
273 // 277 //
274 PresenceInfo presence = null;
275 GridRegion home = null;
276 if (m_PresenceService != null) 278 if (m_PresenceService != null)
277 { 279 {
278 success = m_PresenceService.LoginAgent(account.PrincipalID.ToString(), session, secureSession); 280 success = m_PresenceService.LoginAgent(account.PrincipalID.ToString(), session, secureSession);
@@ -281,28 +283,35 @@ namespace OpenSim.Services.LLLoginService
281 m_log.InfoFormat("[LLOGIN SERVICE]: Login failed, reason: could not login presence"); 283 m_log.InfoFormat("[LLOGIN SERVICE]: Login failed, reason: could not login presence");
282 return LLFailedLoginResponse.GridProblem; 284 return LLFailedLoginResponse.GridProblem;
283 } 285 }
284
285 // Get the updated presence info
286 presence = m_PresenceService.GetAgent(session);
287
288 // Get the home region
289 if ((presence.HomeRegionID != UUID.Zero) && m_GridService != null)
290 {
291 home = m_GridService.GetRegionByUUID(scopeID, presence.HomeRegionID);
292 }
293 } 286 }
294 287
295 // 288 //
289 // Change Online status and get the home region
290 //
291 GridRegion home = null;
292 GridUserInfo guinfo = m_GridUserService.LoggedIn(account.PrincipalID.ToString());
293 if (guinfo != null && (guinfo.HomeRegionID != UUID.Zero) && m_GridService != null)
294 {
295 home = m_GridService.GetRegionByUUID(scopeID, guinfo.HomeRegionID);
296 }
297 if (guinfo == null)
298 {
299 // something went wrong, make something up, so that we don't have to test this anywhere else
300 guinfo = new GridUserInfo();
301 guinfo.LastPosition = guinfo.HomePosition = new Vector3(128, 128, 30);
302 }
303
304 //
296 // Find the destination region/grid 305 // Find the destination region/grid
297 // 306 //
298 string where = string.Empty; 307 string where = string.Empty;
299 Vector3 position = Vector3.Zero; 308 Vector3 position = Vector3.Zero;
300 Vector3 lookAt = Vector3.Zero; 309 Vector3 lookAt = Vector3.Zero;
301 GridRegion gatekeeper = null; 310 GridRegion gatekeeper = null;
302 GridRegion destination = FindDestination(account, scopeID, presence, session, startLocation, out gatekeeper, out where, out position, out lookAt); 311 GridRegion destination = FindDestination(account, scopeID, guinfo, session, startLocation, home, out gatekeeper, out where, out position, out lookAt);
303 if (destination == null) 312 if (destination == null)
304 { 313 {
305 m_PresenceService.LogoutAgent(session, presence.Position, presence.LookAt); 314 m_PresenceService.LogoutAgent(session);
306 m_log.InfoFormat("[LLOGIN SERVICE]: Login failed, reason: destination not found"); 315 m_log.InfoFormat("[LLOGIN SERVICE]: Login failed, reason: destination not found");
307 return LLFailedLoginResponse.GridProblem; 316 return LLFailedLoginResponse.GridProblem;
308 } 317 }
@@ -324,7 +333,7 @@ namespace OpenSim.Services.LLLoginService
324 333
325 if (aCircuit == null) 334 if (aCircuit == null)
326 { 335 {
327 m_PresenceService.LogoutAgent(session, presence.Position, presence.LookAt); 336 m_PresenceService.LogoutAgent(session);
328 m_log.InfoFormat("[LLOGIN SERVICE]: Login failed, reason: {0}", reason); 337 m_log.InfoFormat("[LLOGIN SERVICE]: Login failed, reason: {0}", reason);
329 return LLFailedLoginResponse.AuthorizationProblem; 338 return LLFailedLoginResponse.AuthorizationProblem;
330 339
@@ -340,7 +349,7 @@ namespace OpenSim.Services.LLLoginService
340 // 349 //
341 // Finally, fill out the response and return it 350 // Finally, fill out the response and return it
342 // 351 //
343 LLLoginResponse response = new LLLoginResponse(account, aCircuit, presence, destination, inventorySkel, friendsList, m_LibraryService, 352 LLLoginResponse response = new LLLoginResponse(account, aCircuit, guinfo, destination, inventorySkel, friendsList, m_LibraryService,
344 where, startLocation, position, lookAt, m_WelcomeMessage, home, clientIP); 353 where, startLocation, position, lookAt, m_WelcomeMessage, home, clientIP);
345 354
346 m_log.DebugFormat("[LLOGIN SERVICE]: All clear. Sending login response to client."); 355 m_log.DebugFormat("[LLOGIN SERVICE]: All clear. Sending login response to client.");
@@ -350,12 +359,12 @@ namespace OpenSim.Services.LLLoginService
350 { 359 {
351 m_log.WarnFormat("[LLOGIN SERVICE]: Exception processing login for {0} {1}: {2} {3}", firstName, lastName, e.ToString(), e.StackTrace); 360 m_log.WarnFormat("[LLOGIN SERVICE]: Exception processing login for {0} {1}: {2} {3}", firstName, lastName, e.ToString(), e.StackTrace);
352 if (m_PresenceService != null) 361 if (m_PresenceService != null)
353 m_PresenceService.LogoutAgent(session, new Vector3(128, 128, 0), new Vector3(0, 1, 0)); 362 m_PresenceService.LogoutAgent(session);
354 return LLFailedLoginResponse.InternalError; 363 return LLFailedLoginResponse.InternalError;
355 } 364 }
356 } 365 }
357 366
358 protected GridRegion FindDestination(UserAccount account, UUID scopeID, PresenceInfo pinfo, UUID sessionID, string startLocation, out GridRegion gatekeeper, out string where, out Vector3 position, out Vector3 lookAt) 367 protected GridRegion FindDestination(UserAccount account, UUID scopeID, GridUserInfo pinfo, UUID sessionID, string startLocation, GridRegion home, out GridRegion gatekeeper, out string where, out Vector3 position, out Vector3 lookAt)
359 { 368 {
360 m_log.DebugFormat("[LLOGIN SERVICE]: FindDestination for start location {0}", startLocation); 369 m_log.DebugFormat("[LLOGIN SERVICE]: FindDestination for start location {0}", startLocation);
361 370
@@ -377,7 +386,7 @@ namespace OpenSim.Services.LLLoginService
377 386
378 bool tryDefaults = false; 387 bool tryDefaults = false;
379 388
380 if (pinfo.HomeRegionID.Equals(UUID.Zero)) 389 if (home == null)
381 { 390 {
382 m_log.WarnFormat( 391 m_log.WarnFormat(
383 "[LLOGIN SERVICE]: User {0} {1} tried to login to a 'home' start location but they have none set", 392 "[LLOGIN SERVICE]: User {0} {1} tried to login to a 'home' start location but they have none set",
@@ -387,16 +396,10 @@ namespace OpenSim.Services.LLLoginService
387 } 396 }
388 else 397 else
389 { 398 {
390 region = m_GridService.GetRegionByUUID(scopeID, pinfo.HomeRegionID); 399 region = home;
391 400
392 if (null == region) 401 position = pinfo.HomePosition;
393 { 402 lookAt = pinfo.HomeLookAt;
394 m_log.WarnFormat(
395 "[LLOGIN SERVICE]: User {0} {1} has a recorded home region of {2} but this cannot be found by the grid service",
396 account.FirstName, account.LastName, pinfo.HomeRegionID);
397
398 tryDefaults = true;
399 }
400 } 403 }
401 404
402 if (tryDefaults) 405 if (tryDefaults)
@@ -432,7 +435,7 @@ namespace OpenSim.Services.LLLoginService
432 435
433 GridRegion region = null; 436 GridRegion region = null;
434 437
435 if (pinfo.RegionID.Equals(UUID.Zero) || (region = m_GridService.GetRegionByUUID(scopeID, pinfo.RegionID)) == null) 438 if (pinfo.LastRegionID.Equals(UUID.Zero) || (region = m_GridService.GetRegionByUUID(scopeID, pinfo.LastRegionID)) == null)
436 { 439 {
437 List<GridRegion> defaults = m_GridService.GetDefaultRegions(scopeID); 440 List<GridRegion> defaults = m_GridService.GetDefaultRegions(scopeID);
438 if (defaults != null && defaults.Count > 0) 441 if (defaults != null && defaults.Count > 0)
@@ -454,8 +457,8 @@ namespace OpenSim.Services.LLLoginService
454 } 457 }
455 else 458 else
456 { 459 {
457 position = pinfo.Position; 460 position = pinfo.LastPosition;
458 lookAt = pinfo.LookAt; 461 lookAt = pinfo.LastLookAt;
459 } 462 }
460 463
461 return region; 464 return region;
diff --git a/OpenSim/Services/PresenceService/PresenceService.cs b/OpenSim/Services/PresenceService/PresenceService.cs
index ea8d673..7e7e98e 100644
--- a/OpenSim/Services/PresenceService/PresenceService.cs
+++ b/OpenSim/Services/PresenceService/PresenceService.cs
@@ -54,8 +54,6 @@ namespace OpenSim.Services.PresenceService
54 public bool LoginAgent(string userID, UUID sessionID, 54 public bool LoginAgent(string userID, UUID sessionID,
55 UUID secureSessionID) 55 UUID secureSessionID)
56 { 56 {
57 m_Database.Prune(userID);
58
59 PresenceData[] d = m_Database.Get("UserID", userID); 57 PresenceData[] d = m_Database.Get("UserID", userID);
60 58
61 PresenceData data = new PresenceData(); 59 PresenceData data = new PresenceData();
@@ -65,24 +63,6 @@ namespace OpenSim.Services.PresenceService
65 data.SessionID = sessionID; 63 data.SessionID = sessionID;
66 data.Data = new Dictionary<string, string>(); 64 data.Data = new Dictionary<string, string>();
67 data.Data["SecureSessionID"] = secureSessionID.ToString(); 65 data.Data["SecureSessionID"] = secureSessionID.ToString();
68 data.Data["Online"] = "true";
69 data.Data["Login"] = Util.UnixTimeSinceEpoch().ToString();
70 if (d != null && d.Length > 0)
71 {
72 data.Data["HomeRegionID"] = d[0].Data["HomeRegionID"];
73 data.Data["HomePosition"] = d[0].Data["HomePosition"];
74 data.Data["HomeLookAt"] = d[0].Data["HomeLookAt"];
75 data.Data["Position"] = d[0].Data["Position"];
76 data.Data["LookAt"] = d[0].Data["LookAt"];
77
78 data.RegionID = d[0].RegionID;
79 }
80 else
81 {
82 data.Data["HomeRegionID"] = UUID.Zero.ToString();
83 data.Data["HomePosition"] = new Vector3(128, 128, 0).ToString();
84 data.Data["HomeLookAt"] = new Vector3(0, 1, 0).ToString();
85 }
86 66
87 m_Database.Store(data); 67 m_Database.Store(data);
88 68
@@ -91,28 +71,10 @@ namespace OpenSim.Services.PresenceService
91 return true; 71 return true;
92 } 72 }
93 73
94 public bool LogoutAgent(UUID sessionID, Vector3 position, Vector3 lookat) 74 public bool LogoutAgent(UUID sessionID)
95 { 75 {
96 PresenceData data = m_Database.Get(sessionID); 76 m_log.DebugFormat("[PRESENCE SERVICE]: Session {0} logout", sessionID);
97 if (data == null) 77 return m_Database.Delete("SessionID", sessionID.ToString());
98 return false;
99
100 PresenceData[] d = m_Database.Get("UserID", data.UserID);
101
102 m_log.DebugFormat("[PRESENCE SERVICE]: LogoutAgent {0} with {1} sessions currently present", data.UserID, d.Length);
103 if (d.Length > 1)
104 {
105 m_Database.Delete("UserID", data.UserID);
106 }
107
108 data.Data["Online"] = "false";
109 data.Data["Logout"] = Util.UnixTimeSinceEpoch().ToString();
110 data.Data["Position"] = position.ToString();
111 data.Data["LookAt"] = lookat.ToString();
112
113 m_Database.Store(data);
114
115 return true;
116 } 78 }
117 79
118 public bool LogoutRegionAgents(UUID regionID) 80 public bool LogoutRegionAgents(UUID regionID)
@@ -123,7 +85,7 @@ namespace OpenSim.Services.PresenceService
123 } 85 }
124 86
125 87
126 public bool ReportAgent(UUID sessionID, UUID regionID, Vector3 position, Vector3 lookAt) 88 public bool ReportAgent(UUID sessionID, UUID regionID)
127 { 89 {
128 m_log.DebugFormat("[PRESENCE SERVICE]: ReportAgent with session {0} in region {1}", sessionID, regionID); 90 m_log.DebugFormat("[PRESENCE SERVICE]: ReportAgent with session {0} in region {1}", sessionID, regionID);
129 try 91 try
@@ -134,14 +96,7 @@ namespace OpenSim.Services.PresenceService
134 if (pdata.Data == null) 96 if (pdata.Data == null)
135 return false; 97 return false;
136 98
137 if (!pdata.Data.ContainsKey("Online") || (pdata.Data.ContainsKey("Online") && pdata.Data["Online"] == "false")) 99 return m_Database.ReportAgent(sessionID, regionID);
138 {
139 m_log.WarnFormat("[PRESENCE SERVICE]: Someone tried to report presence of an agent who's not online");
140 return false;
141 }
142
143 return m_Database.ReportAgent(sessionID, regionID,
144 position.ToString(), lookAt.ToString());
145 } 100 }
146 catch (Exception e) 101 catch (Exception e)
147 { 102 {
@@ -160,22 +115,10 @@ namespace OpenSim.Services.PresenceService
160 115
161 ret.UserID = data.UserID; 116 ret.UserID = data.UserID;
162 ret.RegionID = data.RegionID; 117 ret.RegionID = data.RegionID;
163 if (data.Data.ContainsKey("Online"))
164 ret.Online = bool.Parse(data.Data["Online"]);
165 if (data.Data.ContainsKey("Login"))
166 ret.Login = Util.ToDateTime(Convert.ToInt32(data.Data["Login"]));
167 if (data.Data.ContainsKey("Logout"))
168 ret.Logout = Util.ToDateTime(Convert.ToInt32(data.Data["Logout"]));
169 if (data.Data.ContainsKey("Position")) 118 if (data.Data.ContainsKey("Position"))
170 ret.Position = Vector3.Parse(data.Data["Position"]); 119 ret.Position = Vector3.Parse(data.Data["Position"]);
171 if (data.Data.ContainsKey("LookAt")) 120 if (data.Data.ContainsKey("LookAt"))
172 ret.LookAt = Vector3.Parse(data.Data["LookAt"]); 121 ret.LookAt = Vector3.Parse(data.Data["LookAt"]);
173 if (data.Data.ContainsKey("HomeRegionID"))
174 ret.HomeRegionID = new UUID(data.Data["HomeRegionID"]);
175 if (data.Data.ContainsKey("HomePosition"))
176 ret.HomePosition = Vector3.Parse(data.Data["HomePosition"]);
177 if (data.Data.ContainsKey("HomeLookAt"))
178 ret.HomeLookAt = Vector3.Parse(data.Data["HomeLookAt"]);
179 122
180 return ret; 123 return ret;
181 } 124 }
@@ -195,16 +138,8 @@ namespace OpenSim.Services.PresenceService
195 138
196 ret.UserID = d.UserID; 139 ret.UserID = d.UserID;
197 ret.RegionID = d.RegionID; 140 ret.RegionID = d.RegionID;
198 ret.Online = bool.Parse(d.Data["Online"]);
199 ret.Login = Util.ToDateTime(Convert.ToInt32(
200 d.Data["Login"]));
201 ret.Logout = Util.ToDateTime(Convert.ToInt32(
202 d.Data["Logout"]));
203 ret.Position = Vector3.Parse(d.Data["Position"]); 141 ret.Position = Vector3.Parse(d.Data["Position"]);
204 ret.LookAt = Vector3.Parse(d.Data["LookAt"]); 142 ret.LookAt = Vector3.Parse(d.Data["LookAt"]);
205 ret.HomeRegionID = new UUID(d.Data["HomeRegionID"]);
206 ret.HomePosition = Vector3.Parse(d.Data["HomePosition"]);
207 ret.HomeLookAt = Vector3.Parse(d.Data["HomeLookAt"]);
208 143
209 info.Add(ret); 144 info.Add(ret);
210 } 145 }
@@ -214,9 +149,5 @@ namespace OpenSim.Services.PresenceService
214 return info.ToArray(); 149 return info.ToArray();
215 } 150 }
216 151
217 public bool SetHomeLocation(string userID, UUID regionID, Vector3 position, Vector3 lookAt)
218 {
219 return m_Database.SetHomeLocation(userID, regionID, position, lookAt);
220 }
221 } 152 }
222} 153}
diff --git a/OpenSim/Services/UserAccountService/GridUserService.cs b/OpenSim/Services/UserAccountService/GridUserService.cs
index c6e33bb..697ba63 100644
--- a/OpenSim/Services/UserAccountService/GridUserService.cs
+++ b/OpenSim/Services/UserAccountService/GridUserService.cs
@@ -31,6 +31,7 @@ using System.Reflection;
31using Nini.Config; 31using Nini.Config;
32using OpenSim.Data; 32using OpenSim.Data;
33using OpenSim.Services.Interfaces; 33using OpenSim.Services.Interfaces;
34using OpenSim.Framework;
34using OpenSim.Framework.Console; 35using OpenSim.Framework.Console;
35using GridRegion = OpenSim.Services.Interfaces.GridRegion; 36using GridRegion = OpenSim.Services.Interfaces.GridRegion;
36 37
@@ -50,27 +51,109 @@ namespace OpenSim.Services.UserAccountService
50 51
51 public GridUserInfo GetGridUserInfo(string userID) 52 public GridUserInfo GetGridUserInfo(string userID)
52 { 53 {
53 GridUserData d = m_Database.GetGridUserData(userID); 54 GridUserData d = m_Database.Get(userID);
54 55
56 if (d == null)
57 return null;
58
55 GridUserInfo info = new GridUserInfo(); 59 GridUserInfo info = new GridUserInfo();
56 info.UserID = d.UserID; 60 info.UserID = d.UserID;
57 info.HomeRegionID = new UUID(d.Data["HomeRegionID"]); 61 info.HomeRegionID = new UUID(d.Data["HomeRegionID"]);
58 info.HomePosition = Vector3.Parse(d.Data["HomePosition"]); 62 info.HomePosition = Vector3.Parse(d.Data["HomePosition"]);
59 info.HomeLookAt = Vector3.Parse(d.Data["HomeLookAt"]); 63 info.HomeLookAt = Vector3.Parse(d.Data["HomeLookAt"]);
60 64
65 info.LastRegionID = new UUID(d.Data["LastRegionID"]);
66 info.LastPosition = Vector3.Parse(d.Data["LastPosition"]);
67 info.LastLookAt = Vector3.Parse(d.Data["LastLookAt"]);
68
69 info.Online = bool.Parse(d.Data["Online"]);
70 info.Login = Util.ToDateTime(Convert.ToInt32(d.Data["Login"]));
71 info.Logout = Util.ToDateTime(Convert.ToInt32(d.Data["Logout"]));
72
61 return info; 73 return info;
62 } 74 }
63 75
64 public bool StoreGridUserInfo(GridUserInfo info) 76 public GridUserInfo LoggedIn(string userID)
77 {
78 m_log.DebugFormat("[GRID USER SERVICE]: User {0} is online", userID);
79 GridUserData d = m_Database.Get(userID);
80
81 if (d == null)
82 {
83 d = new GridUserData();
84 d.UserID = userID;
85 }
86
87 d.Data["Online"] = true.ToString();
88 d.Data["Login"] = Util.UnixTimeSinceEpoch().ToString();
89
90 m_Database.Store(d);
91
92 return GetGridUserInfo(userID);
93 }
94
95 public bool LoggedOut(string userID, UUID regionID, Vector3 lastPosition, Vector3 lastLookAt)
96 {
97 m_log.DebugFormat("[GRID USER SERVICE]: User {0} is offline", userID);
98 GridUserData d = m_Database.Get(userID);
99
100 if (d == null)
101 {
102 d = new GridUserData();
103 d.UserID = userID;
104 }
105
106 d.Data["Online"] = false.ToString();
107 d.Data["Logout"] = Util.UnixTimeSinceEpoch().ToString();
108 d.Data["LastRegionID"] = regionID.ToString();
109 d.Data["LastPosition"] = lastPosition.ToString();
110 d.Data["LastLookAt"] = lastLookAt.ToString();
111
112 return m_Database.Store(d);
113 }
114
115 protected bool StoreGridUserInfo(GridUserInfo info)
65 { 116 {
66 GridUserData d = new GridUserData(); 117 GridUserData d = new GridUserData();
67 118
68 d.Data["UserID"] = info.UserID;
69 d.Data["HomeRegionID"] = info.HomeRegionID.ToString(); 119 d.Data["HomeRegionID"] = info.HomeRegionID.ToString();
70 d.Data["HomePosition"] = info.HomePosition.ToString(); 120 d.Data["HomePosition"] = info.HomePosition.ToString();
71 d.Data["HomeLookAt"] = info.HomeLookAt.ToString(); 121 d.Data["HomeLookAt"] = info.HomeLookAt.ToString();
72 122
73 return m_Database.StoreGridUserData(d); 123 return m_Database.Store(d);
124 }
125
126 public bool SetHome(string userID, UUID homeID, Vector3 homePosition, Vector3 homeLookAt)
127 {
128 GridUserData d = m_Database.Get(userID);
129 if (d == null)
130 {
131 d = new GridUserData();
132 d.UserID = userID;
133 }
134
135 d.Data["HomeRegionID"] = homeID.ToString();
136 d.Data["HomePosition"] = homePosition.ToString();
137 d.Data["HomeLookAt"] = homeLookAt.ToString();
138
139 return m_Database.Store(d);
140 }
141
142 public bool SetLastPosition(string userID, UUID regionID, Vector3 lastPosition, Vector3 lastLookAt)
143 {
144 //m_log.DebugFormat("[Grid User Service]: SetLastPosition for {0}", userID);
145 GridUserData d = m_Database.Get(userID);
146 if (d == null)
147 {
148 d = new GridUserData();
149 d.UserID = userID;
150 }
151
152 d.Data["LastRegionID"] = regionID.ToString();
153 d.Data["LastPosition"] = lastPosition.ToString();
154 d.Data["LastLookAt"] = lastLookAt.ToString();
155
156 return m_Database.Store(d);
74 } 157 }
75 } 158 }
76} \ No newline at end of file 159} \ No newline at end of file
diff --git a/OpenSim/Services/UserAccountService/UserAccountService.cs b/OpenSim/Services/UserAccountService/UserAccountService.cs
index 35e2826..6923293 100644
--- a/OpenSim/Services/UserAccountService/UserAccountService.cs
+++ b/OpenSim/Services/UserAccountService/UserAccountService.cs
@@ -46,7 +46,7 @@ namespace OpenSim.Services.UserAccountService
46 46
47 protected IGridService m_GridService; 47 protected IGridService m_GridService;
48 protected IAuthenticationService m_AuthenticationService; 48 protected IAuthenticationService m_AuthenticationService;
49 protected IPresenceService m_PresenceService; 49 protected IGridUserService m_GridUserService;
50 protected IInventoryService m_InventoryService; 50 protected IInventoryService m_InventoryService;
51 51
52 public UserAccountService(IConfigSource config) 52 public UserAccountService(IConfigSource config)
@@ -69,9 +69,9 @@ namespace OpenSim.Services.UserAccountService
69 if (authServiceDll != string.Empty) 69 if (authServiceDll != string.Empty)
70 m_AuthenticationService = LoadPlugin<IAuthenticationService>(authServiceDll, new Object[] { config }); 70 m_AuthenticationService = LoadPlugin<IAuthenticationService>(authServiceDll, new Object[] { config });
71 71
72 string presenceServiceDll = userConfig.GetString("PresenceService", string.Empty); 72 string presenceServiceDll = userConfig.GetString("GridUserService", string.Empty);
73 if (presenceServiceDll != string.Empty) 73 if (presenceServiceDll != string.Empty)
74 m_PresenceService = LoadPlugin<IPresenceService>(presenceServiceDll, new Object[] { config }); 74 m_GridUserService = LoadPlugin<IGridUserService>(presenceServiceDll, new Object[] { config });
75 75
76 string invServiceDll = userConfig.GetString("InventoryService", string.Empty); 76 string invServiceDll = userConfig.GetString("InventoryService", string.Empty);
77 if (invServiceDll != string.Empty) 77 if (invServiceDll != string.Empty)
@@ -333,8 +333,8 @@ namespace OpenSim.Services.UserAccountService
333 if (defaultRegions != null && defaultRegions.Count >= 1) 333 if (defaultRegions != null && defaultRegions.Count >= 1)
334 home = defaultRegions[0]; 334 home = defaultRegions[0];
335 335
336 if (m_PresenceService != null && home != null) 336 if (m_GridUserService != null && home != null)
337 m_PresenceService.SetHomeLocation(account.PrincipalID.ToString(), home.RegionID, new Vector3(128, 128, 0), new Vector3(0, 1, 0)); 337 m_GridUserService.SetHome(account.PrincipalID.ToString(), home.RegionID, new Vector3(128, 128, 0), new Vector3(0, 1, 0));
338 else 338 else
339 m_log.WarnFormat("[USER ACCOUNT SERVICE]: Unable to set home for account {0} {1}.", 339 m_log.WarnFormat("[USER ACCOUNT SERVICE]: Unable to set home for account {0} {1}.",
340 firstName, lastName); 340 firstName, lastName);
diff --git a/OpenSim/Tests/Clients/Presence/PresenceClient.cs b/OpenSim/Tests/Clients/Presence/PresenceClient.cs
index 4f959f6..0f6b80e 100644
--- a/OpenSim/Tests/Clients/Presence/PresenceClient.cs
+++ b/OpenSim/Tests/Clients/Presence/PresenceClient.cs
@@ -77,7 +77,7 @@ namespace OpenSim.Tests.Clients.PresenceClient
77 pinfo.UserID, pinfo.Online, pinfo.RegionID, pinfo.HomeRegionID); 77 pinfo.UserID, pinfo.Online, pinfo.RegionID, pinfo.HomeRegionID);
78 78
79 System.Console.WriteLine("\n"); 79 System.Console.WriteLine("\n");
80 success = m_Connector.ReportAgent(session1, region1, new Vector3(128, 128, 128), new Vector3(4, 5, 6)); 80 success = m_Connector.ReportAgent(session1, region1);
81 if (success) 81 if (success)
82 m_log.InfoFormat("[PRESENCE CLIENT]: Successfully reported session {0} in region {1}", user1, region1); 82 m_log.InfoFormat("[PRESENCE CLIENT]: Successfully reported session {0} in region {1}", user1, region1);
83 else 83 else
@@ -90,20 +90,7 @@ namespace OpenSim.Tests.Clients.PresenceClient
90 pinfo.UserID, pinfo.Online, pinfo.RegionID, pinfo.HomeRegionID); 90 pinfo.UserID, pinfo.Online, pinfo.RegionID, pinfo.HomeRegionID);
91 91
92 System.Console.WriteLine("\n"); 92 System.Console.WriteLine("\n");
93 success = m_Connector.SetHomeLocation(user1.ToString(), region1, new Vector3(128, 128, 128), new Vector3(4, 5, 6)); 93 success = m_Connector.LogoutAgent(session1);
94 if (success)
95 m_log.InfoFormat("[PRESENCE CLIENT]: Successfully set home for user {0} in region {1}", user1, region1);
96 else
97 m_log.InfoFormat("[PRESENCE CLIENT]: failed to set home for user {0}", user1);
98 pinfo = m_Connector.GetAgent(session1);
99 if (pinfo == null)
100 m_log.InfoFormat("[PRESENCE CLIENT]: Unable to retrieve presence for {0} for third time", user1);
101 else
102 m_log.InfoFormat("[PRESENCE CLIENT]: Presence retrieved correctly: userID={0}; Online={1}; regionID={2}; homeRegion={3}",
103 pinfo.UserID, pinfo.Online, pinfo.RegionID, pinfo.HomeRegionID);
104
105 System.Console.WriteLine("\n");
106 success = m_Connector.LogoutAgent(session1, Vector3.Zero, Vector3.UnitY);
107 if (success) 94 if (success)
108 m_log.InfoFormat("[PRESENCE CLIENT]: Successfully logged out user {0}", user1); 95 m_log.InfoFormat("[PRESENCE CLIENT]: Successfully logged out user {0}", user1);
109 else 96 else
@@ -116,7 +103,7 @@ namespace OpenSim.Tests.Clients.PresenceClient
116 pinfo.UserID, pinfo.Online, pinfo.RegionID, pinfo.HomeRegionID); 103 pinfo.UserID, pinfo.Online, pinfo.RegionID, pinfo.HomeRegionID);
117 104
118 System.Console.WriteLine("\n"); 105 System.Console.WriteLine("\n");
119 success = m_Connector.ReportAgent(session1, UUID.Random(), Vector3.Zero, Vector3.Zero); 106 success = m_Connector.ReportAgent(session1, UUID.Random());
120 if (success) 107 if (success)
121 m_log.InfoFormat("[PRESENCE CLIENT]: Report agent succeeded, but this is wrong"); 108 m_log.InfoFormat("[PRESENCE CLIENT]: Report agent succeeded, but this is wrong");
122 else 109 else