aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs75
-rw-r--r--OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs25
-rw-r--r--OpenSim/Region/Framework/Scenes/Scene.Inventory.cs25
-rw-r--r--OpenSim/Region/Framework/Scenes/Scene.cs14
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneGraph.cs53
-rw-r--r--OpenSim/Region/Framework/Scenes/ScenePresence.cs15
-rw-r--r--OpenSim/Region/Physics/Meshing/PrimMesher.cs4403
-rw-r--r--OpenSim/Region/Physics/Meshing/SculptMesh.cs1272
8 files changed, 2961 insertions, 2921 deletions
diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs
index 3c2cc42..f54e41a 100644
--- a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs
@@ -168,6 +168,81 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
168 168
169 return true; 169 return true;
170 } 170 }
171
172 public UUID RezSingleAttachmentFromInventory(IClientAPI remoteClient, UUID itemID, uint AttachmentPt)
173 {
174 m_log.DebugFormat("[ATTACHMENTS MODULE]: Rezzing single attachment from item {0} for {1}", itemID, remoteClient.Name);
175
176 return RezSingleAttachmentFromInventory(remoteClient, itemID, AttachmentPt, true);
177 }
178
179 public UUID RezSingleAttachmentFromInventory(
180 IClientAPI remoteClient, UUID itemID, uint AttachmentPt, bool updateInventoryStatus)
181 {
182 SceneObjectGroup att = RezSingleAttachmentFromInventoryInternal(remoteClient, itemID, AttachmentPt);
183
184 if (updateInventoryStatus)
185 {
186 if (att == null)
187 {
188 ShowDetachInUserInventory(itemID, remoteClient);
189 }
190
191 SetAttachmentInventoryStatus(att, remoteClient, itemID, AttachmentPt);
192 }
193
194 if (null == att)
195 return UUID.Zero;
196 else
197 return att.UUID;
198 }
199
200 protected SceneObjectGroup RezSingleAttachmentFromInventoryInternal(
201 IClientAPI remoteClient, UUID itemID, uint AttachmentPt)
202 {
203 IInventoryAccessModule invAccess = m_scene.RequestModuleInterface<IInventoryAccessModule>();
204 if (invAccess != null)
205 {
206 SceneObjectGroup objatt = invAccess.RezObject(remoteClient,
207 itemID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true,
208 false, false, remoteClient.AgentId, true);
209
210// m_log.DebugFormat(
211// "[ATTACHMENTS MODULE]: Retrieved single object {0} for attachment to {1} on point {2}",
212// objatt.Name, remoteClient.Name, AttachmentPt);
213
214 if (objatt != null)
215 {
216 bool tainted = false;
217 if (AttachmentPt != 0 && AttachmentPt != objatt.GetAttachmentPoint())
218 tainted = true;
219
220 AttachObject(
221 remoteClient, objatt.LocalId, AttachmentPt, Quaternion.Identity, objatt.AbsolutePosition, false);
222 //objatt.ScheduleGroupForFullUpdate();
223
224 if (tainted)
225 objatt.HasGroupChanged = true;
226
227 // Fire after attach, so we don't get messy perms dialogs
228 // 3 == AttachedRez
229 objatt.CreateScriptInstances(0, true, m_scene.DefaultScriptEngine, 3);
230
231 // Do this last so that event listeners have access to all the effects of the attachment
232 m_scene.EventManager.TriggerOnAttach(objatt.LocalId, itemID, remoteClient.AgentId);
233 }
234 else
235 {
236 m_log.WarnFormat(
237 "[ATTACHMENTS MODULE]: Could not retrieve item {0} for attaching to avatar {1} at point {2}",
238 itemID, remoteClient.Name, AttachmentPt);
239 }
240
241 return objatt;
242 }
243
244 return null;
245 }
171 246
172 public UUID SetAttachmentInventoryStatus( 247 public UUID SetAttachmentInventoryStatus(
173 SceneObjectGroup att, IClientAPI remoteClient, UUID itemID, uint AttachmentPt) 248 SceneObjectGroup att, IClientAPI remoteClient, UUID itemID, uint AttachmentPt)
diff --git a/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs b/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs
index 21c1056..0222b02 100644
--- a/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs
+++ b/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs
@@ -56,7 +56,30 @@ namespace OpenSim.Region.Framework.Interfaces
56 /// <param name="silent"></param> 56 /// <param name="silent"></param>
57 /// <returns>true if the object was successfully attached, false otherwise</returns> 57 /// <returns>true if the object was successfully attached, false otherwise</returns>
58 bool AttachObject( 58 bool AttachObject(
59 IClientAPI remoteClient, uint objectLocalID, uint AttachmentPt, Quaternion rot, Vector3 attachPos, bool silent); 59 IClientAPI remoteClient, uint objectLocalID, uint AttachmentPt, Quaternion rot, Vector3 attachPos, bool silent);
60
61 /// <summary>
62 /// Rez an attachment from user inventory and change inventory status to match.
63 /// </summary>
64 /// <param name="remoteClient"></param>
65 /// <param name="itemID"></param>
66 /// <param name="AttachmentPt"></param>
67 /// <returns>The scene object that was attached. Null if the scene object could not be found</returns>
68 UUID RezSingleAttachmentFromInventory(IClientAPI remoteClient, UUID itemID, uint AttachmentPt);
69
70 /// <summary>
71 /// Rez an attachment from user inventory
72 /// </summary>
73 /// <param name="remoteClient"></param>
74 /// <param name="itemID"></param>
75 /// <param name="AttachmentPt"></param>
76 /// <param name="updateinventoryStatus">
77 /// If true, we also update the user's inventory to show that the attachment is set. If false, we do not.
78 /// False is required so that we don't attempt to update information when a user enters a scene with the
79 /// attachment already correctly set up in inventory.
80 /// <returns>The uuid of the scene object that was attached. Null if the scene object could not be found</returns>
81 UUID RezSingleAttachmentFromInventory(
82 IClientAPI remoteClient, UUID itemID, uint AttachmentPt, bool updateInventoryStatus);
60 83
61 /// <summary> 84 /// <summary>
62 /// Update the user inventory to the attachment of an item 85 /// Update the user inventory to the attachment of an item
diff --git a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs
index 7277527..41533a1 100644
--- a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs
@@ -1842,35 +1842,12 @@ namespace OpenSim.Region.Framework.Scenes
1842 EventManager.TriggerOnAttach(localID, itemID, avatarID); 1842 EventManager.TriggerOnAttach(localID, itemID, avatarID);
1843 } 1843 }
1844 1844
1845 /// <summary>
1846 /// Called when the client receives a request to rez a single attachment on to the avatar from inventory
1847 /// (RezSingleAttachmentFromInv packet).
1848 /// </summary>
1849 /// <param name="remoteClient"></param>
1850 /// <param name="itemID"></param>
1851 /// <param name="AttachmentPt"></param>
1852 /// <returns></returns>
1853 public UUID RezSingleAttachment(IClientAPI remoteClient, UUID itemID, uint AttachmentPt)
1854 {
1855 m_log.DebugFormat("[USER INVENTORY]: Rezzing single attachment from item {0} for {1}", itemID, remoteClient.Name);
1856
1857 SceneObjectGroup att = m_sceneGraph.RezSingleAttachment(remoteClient, itemID, AttachmentPt);
1858
1859 if (att == null)
1860 {
1861 AttachmentsModule.ShowDetachInUserInventory(itemID, remoteClient);
1862 return UUID.Zero;
1863 }
1864
1865 return AttachmentsModule.SetAttachmentInventoryStatus(att, remoteClient, itemID, AttachmentPt);
1866 }
1867
1868 public void RezMultipleAttachments(IClientAPI remoteClient, RezMultipleAttachmentsFromInvPacket.HeaderDataBlock header, 1845 public void RezMultipleAttachments(IClientAPI remoteClient, RezMultipleAttachmentsFromInvPacket.HeaderDataBlock header,
1869 RezMultipleAttachmentsFromInvPacket.ObjectDataBlock[] objects) 1846 RezMultipleAttachmentsFromInvPacket.ObjectDataBlock[] objects)
1870 { 1847 {
1871 foreach (RezMultipleAttachmentsFromInvPacket.ObjectDataBlock obj in objects) 1848 foreach (RezMultipleAttachmentsFromInvPacket.ObjectDataBlock obj in objects)
1872 { 1849 {
1873 RezSingleAttachment(remoteClient, obj.ItemID, obj.AttachmentPt); 1850 AttachmentsModule.RezSingleAttachmentFromInventory(remoteClient, obj.ItemID, obj.AttachmentPt);
1874 } 1851 }
1875 } 1852 }
1876 1853
diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs
index d4d134f..c510dc8 100644
--- a/OpenSim/Region/Framework/Scenes/Scene.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.cs
@@ -2338,10 +2338,10 @@ namespace OpenSim.Region.Framework.Scenes
2338 //m_log.DebugFormat(" >>> IncomingCreateObject(userID, itemID) <<< {0} {1}", userID, itemID); 2338 //m_log.DebugFormat(" >>> IncomingCreateObject(userID, itemID) <<< {0} {1}", userID, itemID);
2339 2339
2340 ScenePresence sp = GetScenePresence(userID); 2340 ScenePresence sp = GetScenePresence(userID);
2341 if (sp != null) 2341 if (sp != null && AttachmentsModule != null)
2342 { 2342 {
2343 uint attPt = (uint)sp.Appearance.GetAttachpoint(itemID); 2343 uint attPt = (uint)sp.Appearance.GetAttachpoint(itemID);
2344 m_sceneGraph.RezSingleAttachment(sp.ControllingClient, itemID, attPt); 2344 AttachmentsModule.RezSingleAttachmentFromInventory(sp.ControllingClient, itemID, attPt);
2345 } 2345 }
2346 2346
2347 return false; 2347 return false;
@@ -2642,13 +2642,13 @@ namespace OpenSim.Region.Framework.Scenes
2642 } 2642 }
2643 2643
2644 public virtual void SubscribeToClientAttachmentEvents(IClientAPI client) 2644 public virtual void SubscribeToClientAttachmentEvents(IClientAPI client)
2645 { 2645 {
2646 client.OnRezSingleAttachmentFromInv += RezSingleAttachment;
2647 client.OnRezMultipleAttachmentsFromInv += RezMultipleAttachments; 2646 client.OnRezMultipleAttachmentsFromInv += RezMultipleAttachments;
2648 client.OnObjectDetach += m_sceneGraph.DetachObject; 2647 client.OnObjectDetach += m_sceneGraph.DetachObject;
2649 2648
2650 if (AttachmentsModule != null) 2649 if (AttachmentsModule != null)
2651 { 2650 {
2651 client.OnRezSingleAttachmentFromInv += AttachmentsModule.RezSingleAttachmentFromInventory;
2652 client.OnObjectAttach += AttachmentsModule.AttachObject; 2652 client.OnObjectAttach += AttachmentsModule.AttachObject;
2653 client.OnDetachAttachmentIntoInv += AttachmentsModule.ShowDetachInUserInventory; 2653 client.OnDetachAttachmentIntoInv += AttachmentsModule.ShowDetachInUserInventory;
2654 } 2654 }
@@ -2799,12 +2799,12 @@ namespace OpenSim.Region.Framework.Scenes
2799 2799
2800 public virtual void UnSubscribeToClientAttachmentEvents(IClientAPI client) 2800 public virtual void UnSubscribeToClientAttachmentEvents(IClientAPI client)
2801 { 2801 {
2802 client.OnRezMultipleAttachmentsFromInv -= RezMultipleAttachments; 2802 client.OnRezMultipleAttachmentsFromInv -= RezMultipleAttachments;
2803 client.OnRezSingleAttachmentFromInv -= RezSingleAttachment;
2804 client.OnObjectDetach -= m_sceneGraph.DetachObject; 2803 client.OnObjectDetach -= m_sceneGraph.DetachObject;
2805 2804
2806 if (AttachmentsModule != null) 2805 if (AttachmentsModule != null)
2807 { 2806 {
2807 client.OnRezSingleAttachmentFromInv -= AttachmentsModule.RezSingleAttachmentFromInventory;
2808 client.OnObjectAttach -= AttachmentsModule.AttachObject; 2808 client.OnObjectAttach -= AttachmentsModule.AttachObject;
2809 client.OnDetachAttachmentIntoInv -= AttachmentsModule.ShowDetachInUserInventory; 2809 client.OnDetachAttachmentIntoInv -= AttachmentsModule.ShowDetachInUserInventory;
2810 } 2810 }
diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs
index a88d456..d944834 100644
--- a/OpenSim/Region/Framework/Scenes/SceneGraph.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneGraph.cs
@@ -486,59 +486,6 @@ namespace OpenSim.Region.Framework.Scenes
486 } 486 }
487 } 487 }
488 488
489 /// <summary>
490 /// Rez an attachment
491 /// </summary>
492 /// <param name="remoteClient"></param>
493 /// <param name="itemID"></param>
494 /// <param name="AttachmentPt"></param>
495 /// <returns>The scene object that was attached. Null if the scene object could not be found</returns>
496 public SceneObjectGroup RezSingleAttachment(IClientAPI remoteClient, UUID itemID, uint AttachmentPt)
497 {
498 IInventoryAccessModule invAccess = m_parentScene.RequestModuleInterface<IInventoryAccessModule>();
499 if (invAccess != null)
500 {
501 SceneObjectGroup objatt = invAccess.RezObject(remoteClient,
502 itemID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true,
503 false, false, remoteClient.AgentId, true);
504
505// m_log.DebugFormat(
506// "[SCENE GRAPH]: Retrieved single object {0} for attachment to {1} on point {2}",
507// objatt.Name, remoteClient.Name, AttachmentPt);
508
509 if (objatt != null)
510 {
511 bool tainted = false;
512 if (AttachmentPt != 0 && AttachmentPt != objatt.GetAttachmentPoint())
513 tainted = true;
514
515 m_parentScene.AttachmentsModule.AttachObject(
516 remoteClient, objatt.LocalId, AttachmentPt, Quaternion.Identity, objatt.AbsolutePosition, false);
517 //objatt.ScheduleGroupForFullUpdate();
518
519 if (tainted)
520 objatt.HasGroupChanged = true;
521
522 // Fire after attach, so we don't get messy perms dialogs
523 // 3 == AttachedRez
524 objatt.CreateScriptInstances(0, true, m_parentScene.DefaultScriptEngine, 3);
525
526 // Do this last so that event listeners have access to all the effects of the attachment
527 m_parentScene.EventManager.TriggerOnAttach(objatt.LocalId, itemID, remoteClient.AgentId);
528 }
529 else
530 {
531 m_log.WarnFormat(
532 "[SCENE GRAPH]: Could not retrieve item {0} for attaching to avatar {1} at point {2}",
533 itemID, remoteClient.Name, AttachmentPt);
534 }
535
536 return objatt;
537 }
538
539 return null;
540 }
541
542 protected internal ScenePresence CreateAndAddChildScenePresence(IClientAPI client, AvatarAppearance appearance) 489 protected internal ScenePresence CreateAndAddChildScenePresence(IClientAPI client, AvatarAppearance appearance)
543 { 490 {
544 ScenePresence newAvatar = null; 491 ScenePresence newAvatar = null;
diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
index 7661f1e..6f16ff3 100644
--- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs
+++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
@@ -676,7 +676,8 @@ namespace OpenSim.Region.Framework.Scenes
676 676
677 UserAccount account = m_scene.UserAccountService.GetUserAccount(m_scene.RegionInfo.ScopeID, m_uuid); 677 UserAccount account = m_scene.UserAccountService.GetUserAccount(m_scene.RegionInfo.ScopeID, m_uuid);
678 678
679 m_userLevel = account.UserLevel; 679 if (account != null)
680 m_userLevel = account.UserLevel;
680 681
681 IGroupsModule gm = m_scene.RequestModuleInterface<IGroupsModule>(); 682 IGroupsModule gm = m_scene.RequestModuleInterface<IGroupsModule>();
682 if (gm != null) 683 if (gm != null)
@@ -3738,7 +3739,7 @@ namespace OpenSim.Region.Framework.Scenes
3738 { 3739 {
3739 if (null == m_appearance) 3740 if (null == m_appearance)
3740 { 3741 {
3741 m_log.WarnFormat("[ATTACHMENT] Appearance has not been initialized for agent {0}", UUID); 3742 m_log.WarnFormat("[ATTACHMENT]: Appearance has not been initialized for agent {0}", UUID);
3742 return; 3743 return;
3743 } 3744 }
3744 3745
@@ -3762,12 +3763,12 @@ namespace OpenSim.Region.Framework.Scenes
3762 try 3763 try
3763 { 3764 {
3764 // Rez from inventory 3765 // Rez from inventory
3765 UUID asset = m_scene.RezSingleAttachment(ControllingClient, 3766 UUID asset
3766 itemID, (uint)p); 3767 = m_scene.AttachmentsModule.RezSingleAttachmentFromInventory(ControllingClient, itemID, (uint)p);
3767
3768 m_log.InfoFormat("[ATTACHMENT]: Rezzed attachment in point {0} from item {1} and asset {2} ({3})",
3769 p, itemID, assetID, asset);
3770 3768
3769 m_log.InfoFormat(
3770 "[ATTACHMENT]: Rezzed attachment in point {0} from item {1} and asset {2} ({3})",
3771 p, itemID, assetID, asset);
3771 } 3772 }
3772 catch (Exception e) 3773 catch (Exception e)
3773 { 3774 {
diff --git a/OpenSim/Region/Physics/Meshing/PrimMesher.cs b/OpenSim/Region/Physics/Meshing/PrimMesher.cs
index 2a213c3..6e9654b 100644
--- a/OpenSim/Region/Physics/Meshing/PrimMesher.cs
+++ b/OpenSim/Region/Physics/Meshing/PrimMesher.cs
@@ -1,2202 +1,2201 @@
1/* 1/*
2 * Copyright (c) Contributors 2 * Copyright (c) Contributors
3 * See CONTRIBUTORS.TXT for a full list of copyright holders. 3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 * 4 *
5 * Redistribution and use in source and binary forms, with or without 5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met: 6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright 7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer. 8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright 9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the 10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution. 11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the 12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products 13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission. 14 * derived from this software without specific prior written permission.
15 * 15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY 16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY 19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27 27
28using System; 28using System;
29using System.Collections.Generic; 29using System.Collections.Generic;
30using System.Text; 30using System.Text;
31using System.IO; 31using System.IO;
32 32
33namespace PrimMesher 33namespace PrimMesher
34{ 34{
35 public struct Quat 35 public struct Quat
36 { 36 {
37 /// <summary>X value</summary> 37 /// <summary>X value</summary>
38 public float X; 38 public float X;
39 /// <summary>Y value</summary> 39 /// <summary>Y value</summary>
40 public float Y; 40 public float Y;
41 /// <summary>Z value</summary> 41 /// <summary>Z value</summary>
42 public float Z; 42 public float Z;
43 /// <summary>W value</summary> 43 /// <summary>W value</summary>
44 public float W; 44 public float W;
45 45
46 public Quat(float x, float y, float z, float w) 46 public Quat(float x, float y, float z, float w)
47 { 47 {
48 X = x; 48 X = x;
49 Y = y; 49 Y = y;
50 Z = z; 50 Z = z;
51 W = w; 51 W = w;
52 } 52 }
53 53
54 public Quat(Coord axis, float angle) 54 public Quat(Coord axis, float angle)
55 { 55 {
56 axis = axis.Normalize(); 56 axis = axis.Normalize();
57 57
58 angle *= 0.5f; 58 angle *= 0.5f;
59 float c = (float)Math.Cos(angle); 59 float c = (float)Math.Cos(angle);
60 float s = (float)Math.Sin(angle); 60 float s = (float)Math.Sin(angle);
61 61
62 X = axis.X * s; 62 X = axis.X * s;
63 Y = axis.Y * s; 63 Y = axis.Y * s;
64 Z = axis.Z * s; 64 Z = axis.Z * s;
65 W = c; 65 W = c;
66 66
67 Normalize(); 67 Normalize();
68 } 68 }
69 69
70 public float Length() 70 public float Length()
71 { 71 {
72 return (float)Math.Sqrt(X * X + Y * Y + Z * Z + W * W); 72 return (float)Math.Sqrt(X * X + Y * Y + Z * Z + W * W);
73 } 73 }
74 74
75 public Quat Normalize() 75 public Quat Normalize()
76 { 76 {
77 const float MAG_THRESHOLD = 0.0000001f; 77 const float MAG_THRESHOLD = 0.0000001f;
78 float mag = Length(); 78 float mag = Length();
79 79
80 // Catch very small rounding errors when normalizing 80 // Catch very small rounding errors when normalizing
81 if (mag > MAG_THRESHOLD) 81 if (mag > MAG_THRESHOLD)
82 { 82 {
83 float oomag = 1f / mag; 83 float oomag = 1f / mag;
84 X *= oomag; 84 X *= oomag;
85 Y *= oomag; 85 Y *= oomag;
86 Z *= oomag; 86 Z *= oomag;
87 W *= oomag; 87 W *= oomag;
88 } 88 }
89 else 89 else
90 { 90 {
91 X = 0f; 91 X = 0f;
92 Y = 0f; 92 Y = 0f;
93 Z = 0f; 93 Z = 0f;
94 W = 1f; 94 W = 1f;
95 } 95 }
96 96
97 return this; 97 return this;
98 } 98 }
99 99
100 public static Quat operator *(Quat q1, Quat q2) 100 public static Quat operator *(Quat q1, Quat q2)
101 { 101 {
102 float x = q1.W * q2.X + q1.X * q2.W + q1.Y * q2.Z - q1.Z * q2.Y; 102 float x = q1.W * q2.X + q1.X * q2.W + q1.Y * q2.Z - q1.Z * q2.Y;
103 float y = q1.W * q2.Y - q1.X * q2.Z + q1.Y * q2.W + q1.Z * q2.X; 103 float y = q1.W * q2.Y - q1.X * q2.Z + q1.Y * q2.W + q1.Z * q2.X;
104 float z = q1.W * q2.Z + q1.X * q2.Y - q1.Y * q2.X + q1.Z * q2.W; 104 float z = q1.W * q2.Z + q1.X * q2.Y - q1.Y * q2.X + q1.Z * q2.W;
105 float w = q1.W * q2.W - q1.X * q2.X - q1.Y * q2.Y - q1.Z * q2.Z; 105 float w = q1.W * q2.W - q1.X * q2.X - q1.Y * q2.Y - q1.Z * q2.Z;
106 return new Quat(x, y, z, w); 106 return new Quat(x, y, z, w);
107 } 107 }
108 108
109 public override string ToString() 109 public override string ToString()
110 { 110 {
111 return "< X: " + this.X.ToString() + ", Y: " + this.Y.ToString() + ", Z: " + this.Z.ToString() + ", W: " + this.W.ToString() + ">"; 111 return "< X: " + this.X.ToString() + ", Y: " + this.Y.ToString() + ", Z: " + this.Z.ToString() + ", W: " + this.W.ToString() + ">";
112 } 112 }
113 } 113 }
114 114
115 public struct Coord 115 public struct Coord
116 { 116 {
117 public float X; 117 public float X;
118 public float Y; 118 public float Y;
119 public float Z; 119 public float Z;
120 120
121 public Coord(float x, float y, float z) 121 public Coord(float x, float y, float z)
122 { 122 {
123 this.X = x; 123 this.X = x;
124 this.Y = y; 124 this.Y = y;
125 this.Z = z; 125 this.Z = z;
126 } 126 }
127 127
128 public float Length() 128 public float Length()
129 { 129 {
130 return (float)Math.Sqrt(this.X * this.X + this.Y * this.Y + this.Z * this.Z); 130 return (float)Math.Sqrt(this.X * this.X + this.Y * this.Y + this.Z * this.Z);
131 } 131 }
132 132
133 public Coord Invert() 133 public Coord Invert()
134 { 134 {
135 this.X = -this.X; 135 this.X = -this.X;
136 this.Y = -this.Y; 136 this.Y = -this.Y;
137 this.Z = -this.Z; 137 this.Z = -this.Z;
138 138
139 return this; 139 return this;
140 } 140 }
141 141
142 public Coord Normalize() 142 public Coord Normalize()
143 { 143 {
144 const float MAG_THRESHOLD = 0.0000001f; 144 const float MAG_THRESHOLD = 0.0000001f;
145 float mag = Length(); 145 float mag = Length();
146 146
147 // Catch very small rounding errors when normalizing 147 // Catch very small rounding errors when normalizing
148 if (mag > MAG_THRESHOLD) 148 if (mag > MAG_THRESHOLD)
149 { 149 {
150 float oomag = 1.0f / mag; 150 float oomag = 1.0f / mag;
151 this.X *= oomag; 151 this.X *= oomag;
152 this.Y *= oomag; 152 this.Y *= oomag;
153 this.Z *= oomag; 153 this.Z *= oomag;
154 } 154 }
155 else 155 else
156 { 156 {
157 this.X = 0.0f; 157 this.X = 0.0f;
158 this.Y = 0.0f; 158 this.Y = 0.0f;
159 this.Z = 0.0f; 159 this.Z = 0.0f;
160 } 160 }
161 161
162 return this; 162 return this;
163 } 163 }
164 164
165 public override string ToString() 165 public override string ToString()
166 { 166 {
167 return this.X.ToString() + " " + this.Y.ToString() + " " + this.Z.ToString(); 167 return this.X.ToString() + " " + this.Y.ToString() + " " + this.Z.ToString();
168 } 168 }
169 169
170 public static Coord Cross(Coord c1, Coord c2) 170 public static Coord Cross(Coord c1, Coord c2)
171 { 171 {
172 return new Coord( 172 return new Coord(
173 c1.Y * c2.Z - c2.Y * c1.Z, 173 c1.Y * c2.Z - c2.Y * c1.Z,
174 c1.Z * c2.X - c2.Z * c1.X, 174 c1.Z * c2.X - c2.Z * c1.X,
175 c1.X * c2.Y - c2.X * c1.Y 175 c1.X * c2.Y - c2.X * c1.Y
176 ); 176 );
177 } 177 }
178 178
179 public static Coord operator +(Coord v, Coord a) 179 public static Coord operator +(Coord v, Coord a)
180 { 180 {
181 return new Coord(v.X + a.X, v.Y + a.Y, v.Z + a.Z); 181 return new Coord(v.X + a.X, v.Y + a.Y, v.Z + a.Z);
182 } 182 }
183 183
184 public static Coord operator *(Coord v, Coord m) 184 public static Coord operator *(Coord v, Coord m)
185 { 185 {
186 return new Coord(v.X * m.X, v.Y * m.Y, v.Z * m.Z); 186 return new Coord(v.X * m.X, v.Y * m.Y, v.Z * m.Z);
187 } 187 }
188 188
189 public static Coord operator *(Coord v, Quat q) 189 public static Coord operator *(Coord v, Quat q)
190 { 190 {
191 // From http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/transforms/ 191 // From http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/transforms/
192 192
193 Coord c2 = new Coord(0.0f, 0.0f, 0.0f); 193 Coord c2 = new Coord(0.0f, 0.0f, 0.0f);
194 194
195 c2.X = q.W * q.W * v.X + 195 c2.X = q.W * q.W * v.X +
196 2f * q.Y * q.W * v.Z - 196 2f * q.Y * q.W * v.Z -
197 2f * q.Z * q.W * v.Y + 197 2f * q.Z * q.W * v.Y +
198 q.X * q.X * v.X + 198 q.X * q.X * v.X +
199 2f * q.Y * q.X * v.Y + 199 2f * q.Y * q.X * v.Y +
200 2f * q.Z * q.X * v.Z - 200 2f * q.Z * q.X * v.Z -
201 q.Z * q.Z * v.X - 201 q.Z * q.Z * v.X -
202 q.Y * q.Y * v.X; 202 q.Y * q.Y * v.X;
203 203
204 c2.Y = 204 c2.Y =
205 2f * q.X * q.Y * v.X + 205 2f * q.X * q.Y * v.X +
206 q.Y * q.Y * v.Y + 206 q.Y * q.Y * v.Y +
207 2f * q.Z * q.Y * v.Z + 207 2f * q.Z * q.Y * v.Z +
208 2f * q.W * q.Z * v.X - 208 2f * q.W * q.Z * v.X -
209 q.Z * q.Z * v.Y + 209 q.Z * q.Z * v.Y +
210 q.W * q.W * v.Y - 210 q.W * q.W * v.Y -
211 2f * q.X * q.W * v.Z - 211 2f * q.X * q.W * v.Z -
212 q.X * q.X * v.Y; 212 q.X * q.X * v.Y;
213 213
214 c2.Z = 214 c2.Z =
215 2f * q.X * q.Z * v.X + 215 2f * q.X * q.Z * v.X +
216 2f * q.Y * q.Z * v.Y + 216 2f * q.Y * q.Z * v.Y +
217 q.Z * q.Z * v.Z - 217 q.Z * q.Z * v.Z -
218 2f * q.W * q.Y * v.X - 218 2f * q.W * q.Y * v.X -
219 q.Y * q.Y * v.Z + 219 q.Y * q.Y * v.Z +
220 2f * q.W * q.X * v.Y - 220 2f * q.W * q.X * v.Y -
221 q.X * q.X * v.Z + 221 q.X * q.X * v.Z +
222 q.W * q.W * v.Z; 222 q.W * q.W * v.Z;
223 223
224 return c2; 224 return c2;
225 } 225 }
226 } 226 }
227 227
228 public struct UVCoord 228 public struct UVCoord
229 { 229 {
230 public float U; 230 public float U;
231 public float V; 231 public float V;
232 232
233 233
234 public UVCoord(float u, float v) 234 public UVCoord(float u, float v)
235 { 235 {
236 this.U = u; 236 this.U = u;
237 this.V = v; 237 this.V = v;
238 } 238 }
239 } 239 }
240 240
241 public struct Face 241 public struct Face
242 { 242 {
243 public int primFace; 243 public int primFace;
244 244
245 // vertices 245 // vertices
246 public int v1; 246 public int v1;
247 public int v2; 247 public int v2;
248 public int v3; 248 public int v3;
249 249
250 //normals 250 //normals
251 public int n1; 251 public int n1;
252 public int n2; 252 public int n2;
253 public int n3; 253 public int n3;
254 254
255 // uvs 255 // uvs
256 public int uv1; 256 public int uv1;
257 public int uv2; 257 public int uv2;
258 public int uv3; 258 public int uv3;
259 259
260 260
261 public Face(int v1, int v2, int v3) 261 public Face(int v1, int v2, int v3)
262 { 262 {
263 primFace = 0; 263 primFace = 0;
264 264
265 this.v1 = v1; 265 this.v1 = v1;
266 this.v2 = v2; 266 this.v2 = v2;
267 this.v3 = v3; 267 this.v3 = v3;
268 268
269 this.n1 = 0; 269 this.n1 = 0;
270 this.n2 = 0; 270 this.n2 = 0;
271 this.n3 = 0; 271 this.n3 = 0;
272 272
273 this.uv1 = 0; 273 this.uv1 = 0;
274 this.uv2 = 0; 274 this.uv2 = 0;
275 this.uv3 = 0; 275 this.uv3 = 0;
276 276
277 } 277 }
278 278
279 public Face(int v1, int v2, int v3, int n1, int n2, int n3) 279 public Face(int v1, int v2, int v3, int n1, int n2, int n3)
280 { 280 {
281 primFace = 0; 281 primFace = 0;
282 282
283 this.v1 = v1; 283 this.v1 = v1;
284 this.v2 = v2; 284 this.v2 = v2;
285 this.v3 = v3; 285 this.v3 = v3;
286 286
287 this.n1 = n1; 287 this.n1 = n1;
288 this.n2 = n2; 288 this.n2 = n2;
289 this.n3 = n3; 289 this.n3 = n3;
290 290
291 this.uv1 = 0; 291 this.uv1 = 0;
292 this.uv2 = 0; 292 this.uv2 = 0;
293 this.uv3 = 0; 293 this.uv3 = 0;
294 } 294 }
295 295
296 public Coord SurfaceNormal(List<Coord> coordList) 296 public Coord SurfaceNormal(List<Coord> coordList)
297 { 297 {
298 Coord c1 = coordList[this.v1]; 298 Coord c1 = coordList[this.v1];
299 Coord c2 = coordList[this.v2]; 299 Coord c2 = coordList[this.v2];
300 Coord c3 = coordList[this.v3]; 300 Coord c3 = coordList[this.v3];
301 301
302 Coord edge1 = new Coord(c2.X - c1.X, c2.Y - c1.Y, c2.Z - c1.Z); 302 Coord edge1 = new Coord(c2.X - c1.X, c2.Y - c1.Y, c2.Z - c1.Z);
303 Coord edge2 = new Coord(c3.X - c1.X, c3.Y - c1.Y, c3.Z - c1.Z); 303 Coord edge2 = new Coord(c3.X - c1.X, c3.Y - c1.Y, c3.Z - c1.Z);
304 304
305 return Coord.Cross(edge1, edge2).Normalize(); 305 return Coord.Cross(edge1, edge2).Normalize();
306 } 306 }
307 } 307 }
308 308
309 public struct ViewerFace 309 public struct ViewerFace
310 { 310 {
311 public int primFaceNumber; 311 public int primFaceNumber;
312 312
313 public Coord v1; 313 public Coord v1;
314 public Coord v2; 314 public Coord v2;
315 public Coord v3; 315 public Coord v3;
316 316
317 public int coordIndex1; 317 public int coordIndex1;
318 public int coordIndex2; 318 public int coordIndex2;
319 public int coordIndex3; 319 public int coordIndex3;
320 320
321 public Coord n1; 321 public Coord n1;
322 public Coord n2; 322 public Coord n2;
323 public Coord n3; 323 public Coord n3;
324 324
325 public UVCoord uv1; 325 public UVCoord uv1;
326 public UVCoord uv2; 326 public UVCoord uv2;
327 public UVCoord uv3; 327 public UVCoord uv3;
328 328
329 public ViewerFace(int primFaceNumber) 329 public ViewerFace(int primFaceNumber)
330 { 330 {
331 this.primFaceNumber = primFaceNumber; 331 this.primFaceNumber = primFaceNumber;
332 332
333 this.v1 = new Coord(); 333 this.v1 = new Coord();
334 this.v2 = new Coord(); 334 this.v2 = new Coord();
335 this.v3 = new Coord(); 335 this.v3 = new Coord();
336 336
337 this.coordIndex1 = this.coordIndex2 = this.coordIndex3 = -1; // -1 means not assigned yet 337 this.coordIndex1 = this.coordIndex2 = this.coordIndex3 = -1; // -1 means not assigned yet
338 338
339 this.n1 = new Coord(); 339 this.n1 = new Coord();
340 this.n2 = new Coord(); 340 this.n2 = new Coord();
341 this.n3 = new Coord(); 341 this.n3 = new Coord();
342 342
343 this.uv1 = new UVCoord(); 343 this.uv1 = new UVCoord();
344 this.uv2 = new UVCoord(); 344 this.uv2 = new UVCoord();
345 this.uv3 = new UVCoord(); 345 this.uv3 = new UVCoord();
346 } 346 }
347 347
348 public void Scale(float x, float y, float z) 348 public void Scale(float x, float y, float z)
349 { 349 {
350 this.v1.X *= x; 350 this.v1.X *= x;
351 this.v1.Y *= y; 351 this.v1.Y *= y;
352 this.v1.Z *= z; 352 this.v1.Z *= z;
353 353
354 this.v2.X *= x; 354 this.v2.X *= x;
355 this.v2.Y *= y; 355 this.v2.Y *= y;
356 this.v2.Z *= z; 356 this.v2.Z *= z;
357 357
358 this.v3.X *= x; 358 this.v3.X *= x;
359 this.v3.Y *= y; 359 this.v3.Y *= y;
360 this.v3.Z *= z; 360 this.v3.Z *= z;
361 } 361 }
362 362
363 public void AddPos(float x, float y, float z) 363 public void AddPos(float x, float y, float z)
364 { 364 {
365 this.v1.X += x; 365 this.v1.X += x;
366 this.v2.X += x; 366 this.v2.X += x;
367 this.v3.X += x; 367 this.v3.X += x;
368 368
369 this.v1.Y += y; 369 this.v1.Y += y;
370 this.v2.Y += y; 370 this.v2.Y += y;
371 this.v3.Y += y; 371 this.v3.Y += y;
372 372
373 this.v1.Z += z; 373 this.v1.Z += z;
374 this.v2.Z += z; 374 this.v2.Z += z;
375 this.v3.Z += z; 375 this.v3.Z += z;
376 } 376 }
377 377
378 public void AddRot(Quat q) 378 public void AddRot(Quat q)
379 { 379 {
380 this.v1 *= q; 380 this.v1 *= q;
381 this.v2 *= q; 381 this.v2 *= q;
382 this.v3 *= q; 382 this.v3 *= q;
383 383
384 this.n1 *= q; 384 this.n1 *= q;
385 this.n2 *= q; 385 this.n2 *= q;
386 this.n3 *= q; 386 this.n3 *= q;
387 } 387 }
388 388
389 public void CalcSurfaceNormal() 389 public void CalcSurfaceNormal()
390 { 390 {
391 391
392 Coord edge1 = new Coord(this.v2.X - this.v1.X, this.v2.Y - this.v1.Y, this.v2.Z - this.v1.Z); 392 Coord edge1 = new Coord(this.v2.X - this.v1.X, this.v2.Y - this.v1.Y, this.v2.Z - this.v1.Z);
393 Coord edge2 = new Coord(this.v3.X - this.v1.X, this.v3.Y - this.v1.Y, this.v3.Z - this.v1.Z); 393 Coord edge2 = new Coord(this.v3.X - this.v1.X, this.v3.Y - this.v1.Y, this.v3.Z - this.v1.Z);
394 394
395 this.n1 = this.n2 = this.n3 = Coord.Cross(edge1, edge2).Normalize(); 395 this.n1 = this.n2 = this.n3 = Coord.Cross(edge1, edge2).Normalize();
396 } 396 }
397 } 397 }
398 398
399 internal struct Angle 399 internal struct Angle
400 { 400 {
401 internal float angle; 401 internal float angle;
402 internal float X; 402 internal float X;
403 internal float Y; 403 internal float Y;
404 404
405 internal Angle(float angle, float x, float y) 405 internal Angle(float angle, float x, float y)
406 { 406 {
407 this.angle = angle; 407 this.angle = angle;
408 this.X = x; 408 this.X = x;
409 this.Y = y; 409 this.Y = y;
410 } 410 }
411 } 411 }
412 412
413 internal class AngleList 413 internal class AngleList
414 { 414 {
415 private float iX, iY; // intersection point 415 private float iX, iY; // intersection point
416 416
417 private static Angle[] angles3 = 417 private static Angle[] angles3 =
418 { 418 {
419 new Angle(0.0f, 1.0f, 0.0f), 419 new Angle(0.0f, 1.0f, 0.0f),
420 new Angle(0.33333333333333333f, -0.5f, 0.86602540378443871f), 420 new Angle(0.33333333333333333f, -0.5f, 0.86602540378443871f),
421 new Angle(0.66666666666666667f, -0.5f, -0.86602540378443837f), 421 new Angle(0.66666666666666667f, -0.5f, -0.86602540378443837f),
422 new Angle(1.0f, 1.0f, 0.0f) 422 new Angle(1.0f, 1.0f, 0.0f)
423 }; 423 };
424 424
425 private static Coord[] normals3 = 425 private static Coord[] normals3 =
426 { 426 {
427 new Coord(0.25f, 0.4330127019f, 0.0f).Normalize(), 427 new Coord(0.25f, 0.4330127019f, 0.0f).Normalize(),
428 new Coord(-0.5f, 0.0f, 0.0f).Normalize(), 428 new Coord(-0.5f, 0.0f, 0.0f).Normalize(),
429 new Coord(0.25f, -0.4330127019f, 0.0f).Normalize(), 429 new Coord(0.25f, -0.4330127019f, 0.0f).Normalize(),
430 new Coord(0.25f, 0.4330127019f, 0.0f).Normalize() 430 new Coord(0.25f, 0.4330127019f, 0.0f).Normalize()
431 }; 431 };
432 432
433 private static Angle[] angles4 = 433 private static Angle[] angles4 =
434 { 434 {
435 new Angle(0.0f, 1.0f, 0.0f), 435 new Angle(0.0f, 1.0f, 0.0f),
436 new Angle(0.25f, 0.0f, 1.0f), 436 new Angle(0.25f, 0.0f, 1.0f),
437 new Angle(0.5f, -1.0f, 0.0f), 437 new Angle(0.5f, -1.0f, 0.0f),
438 new Angle(0.75f, 0.0f, -1.0f), 438 new Angle(0.75f, 0.0f, -1.0f),
439 new Angle(1.0f, 1.0f, 0.0f) 439 new Angle(1.0f, 1.0f, 0.0f)
440 }; 440 };
441 441
442 private static Coord[] normals4 = 442 private static Coord[] normals4 =
443 { 443 {
444 new Coord(0.5f, 0.5f, 0.0f).Normalize(), 444 new Coord(0.5f, 0.5f, 0.0f).Normalize(),
445 new Coord(-0.5f, 0.5f, 0.0f).Normalize(), 445 new Coord(-0.5f, 0.5f, 0.0f).Normalize(),
446 new Coord(-0.5f, -0.5f, 0.0f).Normalize(), 446 new Coord(-0.5f, -0.5f, 0.0f).Normalize(),
447 new Coord(0.5f, -0.5f, 0.0f).Normalize(), 447 new Coord(0.5f, -0.5f, 0.0f).Normalize(),
448 new Coord(0.5f, 0.5f, 0.0f).Normalize() 448 new Coord(0.5f, 0.5f, 0.0f).Normalize()
449 }; 449 };
450 450
451 private static Angle[] angles24 = 451 private static Angle[] angles24 =
452 { 452 {
453 new Angle(0.0f, 1.0f, 0.0f), 453 new Angle(0.0f, 1.0f, 0.0f),
454 new Angle(0.041666666666666664f, 0.96592582628906831f, 0.25881904510252074f), 454 new Angle(0.041666666666666664f, 0.96592582628906831f, 0.25881904510252074f),
455 new Angle(0.083333333333333329f, 0.86602540378443871f, 0.5f), 455 new Angle(0.083333333333333329f, 0.86602540378443871f, 0.5f),
456 new Angle(0.125f, 0.70710678118654757f, 0.70710678118654746f), 456 new Angle(0.125f, 0.70710678118654757f, 0.70710678118654746f),
457 new Angle(0.16666666666666667f, 0.5f, 0.8660254037844386f), 457 new Angle(0.16666666666666667f, 0.5f, 0.8660254037844386f),
458 new Angle(0.20833333333333331f, 0.25881904510252096f, 0.9659258262890682f), 458 new Angle(0.20833333333333331f, 0.25881904510252096f, 0.9659258262890682f),
459 new Angle(0.25f, 0.0f, 1.0f), 459 new Angle(0.25f, 0.0f, 1.0f),
460 new Angle(0.29166666666666663f, -0.25881904510252063f, 0.96592582628906831f), 460 new Angle(0.29166666666666663f, -0.25881904510252063f, 0.96592582628906831f),
461 new Angle(0.33333333333333333f, -0.5f, 0.86602540378443871f), 461 new Angle(0.33333333333333333f, -0.5f, 0.86602540378443871f),
462 new Angle(0.375f, -0.70710678118654746f, 0.70710678118654757f), 462 new Angle(0.375f, -0.70710678118654746f, 0.70710678118654757f),
463 new Angle(0.41666666666666663f, -0.86602540378443849f, 0.5f), 463 new Angle(0.41666666666666663f, -0.86602540378443849f, 0.5f),
464 new Angle(0.45833333333333331f, -0.9659258262890682f, 0.25881904510252102f), 464 new Angle(0.45833333333333331f, -0.9659258262890682f, 0.25881904510252102f),
465 new Angle(0.5f, -1.0f, 0.0f), 465 new Angle(0.5f, -1.0f, 0.0f),
466 new Angle(0.54166666666666663f, -0.96592582628906842f, -0.25881904510252035f), 466 new Angle(0.54166666666666663f, -0.96592582628906842f, -0.25881904510252035f),
467 new Angle(0.58333333333333326f, -0.86602540378443882f, -0.5f), 467 new Angle(0.58333333333333326f, -0.86602540378443882f, -0.5f),
468 new Angle(0.62499999999999989f, -0.70710678118654791f, -0.70710678118654713f), 468 new Angle(0.62499999999999989f, -0.70710678118654791f, -0.70710678118654713f),
469 new Angle(0.66666666666666667f, -0.5f, -0.86602540378443837f), 469 new Angle(0.66666666666666667f, -0.5f, -0.86602540378443837f),
470 new Angle(0.70833333333333326f, -0.25881904510252152f, -0.96592582628906809f), 470 new Angle(0.70833333333333326f, -0.25881904510252152f, -0.96592582628906809f),
471 new Angle(0.75f, 0.0f, -1.0f), 471 new Angle(0.75f, 0.0f, -1.0f),
472 new Angle(0.79166666666666663f, 0.2588190451025203f, -0.96592582628906842f), 472 new Angle(0.79166666666666663f, 0.2588190451025203f, -0.96592582628906842f),
473 new Angle(0.83333333333333326f, 0.5f, -0.86602540378443904f), 473 new Angle(0.83333333333333326f, 0.5f, -0.86602540378443904f),
474 new Angle(0.875f, 0.70710678118654735f, -0.70710678118654768f), 474 new Angle(0.875f, 0.70710678118654735f, -0.70710678118654768f),
475 new Angle(0.91666666666666663f, 0.86602540378443837f, -0.5f), 475 new Angle(0.91666666666666663f, 0.86602540378443837f, -0.5f),
476 new Angle(0.95833333333333326f, 0.96592582628906809f, -0.25881904510252157f), 476 new Angle(0.95833333333333326f, 0.96592582628906809f, -0.25881904510252157f),
477 new Angle(1.0f, 1.0f, 0.0f) 477 new Angle(1.0f, 1.0f, 0.0f)
478 }; 478 };
479 479
480 private Angle interpolatePoints(float newPoint, Angle p1, Angle p2) 480 private Angle interpolatePoints(float newPoint, Angle p1, Angle p2)
481 { 481 {
482 float m = (newPoint - p1.angle) / (p2.angle - p1.angle); 482 float m = (newPoint - p1.angle) / (p2.angle - p1.angle);
483 return new Angle(newPoint, p1.X + m * (p2.X - p1.X), p1.Y + m * (p2.Y - p1.Y)); 483 return new Angle(newPoint, p1.X + m * (p2.X - p1.X), p1.Y + m * (p2.Y - p1.Y));
484 } 484 }
485 485
486 private void intersection(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4) 486 private void intersection(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)
487 { // ref: http://local.wasp.uwa.edu.au/~pbourke/geometry/lineline2d/ 487 { // ref: http://local.wasp.uwa.edu.au/~pbourke/geometry/lineline2d/
488 double denom = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1); 488 double denom = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1);
489 double uaNumerator = (x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3); 489 double uaNumerator = (x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3);
490 490
491 if (denom != 0.0) 491 if (denom != 0.0)
492 { 492 {
493 double ua = uaNumerator / denom; 493 double ua = uaNumerator / denom;
494 iX = (float)(x1 + ua * (x2 - x1)); 494 iX = (float)(x1 + ua * (x2 - x1));
495 iY = (float)(y1 + ua * (y2 - y1)); 495 iY = (float)(y1 + ua * (y2 - y1));
496 } 496 }
497 } 497 }
498 498
499 internal List<Angle> angles; 499 internal List<Angle> angles;
500 internal List<Coord> normals; 500 internal List<Coord> normals;
501 501
502 internal void makeAngles(int sides, float startAngle, float stopAngle) 502 internal void makeAngles(int sides, float startAngle, float stopAngle)
503 { 503 {
504 angles = new List<Angle>(); 504 angles = new List<Angle>();
505 normals = new List<Coord>(); 505 normals = new List<Coord>();
506 506
507 double twoPi = System.Math.PI * 2.0; 507 double twoPi = System.Math.PI * 2.0;
508 float twoPiInv = 1.0f / (float)twoPi; 508 float twoPiInv = 1.0f / (float)twoPi;
509 509
510 if (sides < 1) 510 if (sides < 1)
511 throw new Exception("number of sides not greater than zero"); 511 throw new Exception("number of sides not greater than zero");
512 if (stopAngle <= startAngle) 512 if (stopAngle <= startAngle)
513 throw new Exception("stopAngle not greater than startAngle"); 513 throw new Exception("stopAngle not greater than startAngle");
514 514
515 if ((sides == 3 || sides == 4 || sides == 24)) 515 if ((sides == 3 || sides == 4 || sides == 24))
516 { 516 {
517 startAngle *= twoPiInv; 517 startAngle *= twoPiInv;
518 stopAngle *= twoPiInv; 518 stopAngle *= twoPiInv;
519 519
520 Angle[] sourceAngles; 520 Angle[] sourceAngles;
521 if (sides == 3) 521 if (sides == 3)
522 sourceAngles = angles3; 522 sourceAngles = angles3;
523 else if (sides == 4) 523 else if (sides == 4)
524 sourceAngles = angles4; 524 sourceAngles = angles4;
525 else sourceAngles = angles24; 525 else sourceAngles = angles24;
526 526
527 int startAngleIndex = (int)(startAngle * sides); 527 int startAngleIndex = (int)(startAngle * sides);
528 int endAngleIndex = sourceAngles.Length - 1; 528 int endAngleIndex = sourceAngles.Length - 1;
529 if (stopAngle < 1.0f) 529 if (stopAngle < 1.0f)
530 endAngleIndex = (int)(stopAngle * sides) + 1; 530 endAngleIndex = (int)(stopAngle * sides) + 1;
531 if (endAngleIndex == startAngleIndex) 531 if (endAngleIndex == startAngleIndex)
532 endAngleIndex++; 532 endAngleIndex++;
533 533
534 for (int angleIndex = startAngleIndex; angleIndex < endAngleIndex + 1; angleIndex++) 534 for (int angleIndex = startAngleIndex; angleIndex < endAngleIndex + 1; angleIndex++)
535 { 535 {
536 angles.Add(sourceAngles[angleIndex]); 536 angles.Add(sourceAngles[angleIndex]);
537 if (sides == 3) 537 if (sides == 3)
538 normals.Add(normals3[angleIndex]); 538 normals.Add(normals3[angleIndex]);
539 else if (sides == 4) 539 else if (sides == 4)
540 normals.Add(normals4[angleIndex]); 540 normals.Add(normals4[angleIndex]);
541 } 541 }
542 542
543 if (startAngle > 0.0f) 543 if (startAngle > 0.0f)
544 angles[0] = interpolatePoints(startAngle, angles[0], angles[1]); 544 angles[0] = interpolatePoints(startAngle, angles[0], angles[1]);
545 545
546 if (stopAngle < 1.0f) 546 if (stopAngle < 1.0f)
547 { 547 {
548 int lastAngleIndex = angles.Count - 1; 548 int lastAngleIndex = angles.Count - 1;
549 angles[lastAngleIndex] = interpolatePoints(stopAngle, angles[lastAngleIndex - 1], angles[lastAngleIndex]); 549 angles[lastAngleIndex] = interpolatePoints(stopAngle, angles[lastAngleIndex - 1], angles[lastAngleIndex]);
550 } 550 }
551 } 551 }
552 else 552 else
553 { 553 {
554 double stepSize = twoPi / sides; 554 double stepSize = twoPi / sides;
555 555
556 int startStep = (int)(startAngle / stepSize); 556 int startStep = (int)(startAngle / stepSize);
557 double angle = stepSize * startStep; 557 double angle = stepSize * startStep;
558 int step = startStep; 558 int step = startStep;
559 double stopAngleTest = stopAngle; 559 double stopAngleTest = stopAngle;
560 if (stopAngle < twoPi) 560 if (stopAngle < twoPi)
561 { 561 {
562 stopAngleTest = stepSize * ((int)(stopAngle / stepSize) + 1); 562 stopAngleTest = stepSize * ((int)(stopAngle / stepSize) + 1);
563 if (stopAngleTest < stopAngle) 563 if (stopAngleTest < stopAngle)
564 stopAngleTest += stepSize; 564 stopAngleTest += stepSize;
565 if (stopAngleTest > twoPi) 565 if (stopAngleTest > twoPi)
566 stopAngleTest = twoPi; 566 stopAngleTest = twoPi;
567 } 567 }
568 568
569 while (angle <= stopAngleTest) 569 while (angle <= stopAngleTest)
570 { 570 {
571 Angle newAngle; 571 Angle newAngle;
572 newAngle.angle = (float)angle; 572 newAngle.angle = (float)angle;
573 newAngle.X = (float)System.Math.Cos(angle); 573 newAngle.X = (float)System.Math.Cos(angle);
574 newAngle.Y = (float)System.Math.Sin(angle); 574 newAngle.Y = (float)System.Math.Sin(angle);
575 angles.Add(newAngle); 575 angles.Add(newAngle);
576 step += 1; 576 step += 1;
577 angle = stepSize * step; 577 angle = stepSize * step;
578 } 578 }
579 579
580 if (startAngle > angles[0].angle) 580 if (startAngle > angles[0].angle)
581 { 581 {
582 Angle newAngle; 582 Angle newAngle;
583 intersection(angles[0].X, angles[0].Y, angles[1].X, angles[1].Y, 0.0f, 0.0f, (float)Math.Cos(startAngle), (float)Math.Sin(startAngle)); 583 intersection(angles[0].X, angles[0].Y, angles[1].X, angles[1].Y, 0.0f, 0.0f, (float)Math.Cos(startAngle), (float)Math.Sin(startAngle));
584 newAngle.angle = startAngle; 584 newAngle.angle = startAngle;
585 newAngle.X = iX; 585 newAngle.X = iX;
586 newAngle.Y = iY; 586 newAngle.Y = iY;
587 angles[0] = newAngle; 587 angles[0] = newAngle;
588 } 588 }
589 589
590 int index = angles.Count - 1; 590 int index = angles.Count - 1;
591 if (stopAngle < angles[index].angle) 591 if (stopAngle < angles[index].angle)
592 { 592 {
593 Angle newAngle; 593 Angle newAngle;
594 intersection(angles[index - 1].X, angles[index - 1].Y, angles[index].X, angles[index].Y, 0.0f, 0.0f, (float)Math.Cos(stopAngle), (float)Math.Sin(stopAngle)); 594 intersection(angles[index - 1].X, angles[index - 1].Y, angles[index].X, angles[index].Y, 0.0f, 0.0f, (float)Math.Cos(stopAngle), (float)Math.Sin(stopAngle));
595 newAngle.angle = stopAngle; 595 newAngle.angle = stopAngle;
596 newAngle.X = iX; 596 newAngle.X = iX;
597 newAngle.Y = iY; 597 newAngle.Y = iY;
598 angles[index] = newAngle; 598 angles[index] = newAngle;
599 } 599 }
600 } 600 }
601 } 601 }
602 } 602 }
603 603
604 /// <summary> 604 /// <summary>
605 /// generates a profile for extrusion 605 /// generates a profile for extrusion
606 /// </summary> 606 /// </summary>
607 internal class Profile 607 internal class Profile
608 { 608 {
609 private const float twoPi = 2.0f * (float)Math.PI; 609 private const float twoPi = 2.0f * (float)Math.PI;
610 610
611 internal string errorMessage = null; 611 internal string errorMessage = null;
612 612
613 internal List<Coord> coords; 613 internal List<Coord> coords;
614 internal List<Face> faces; 614 internal List<Face> faces;
615 internal List<Coord> vertexNormals; 615 internal List<Coord> vertexNormals;
616 internal List<float> us; 616 internal List<float> us;
617 internal List<UVCoord> faceUVs; 617 internal List<UVCoord> faceUVs;
618 internal List<int> faceNumbers; 618 internal List<int> faceNumbers;
619 619
620 // use these for making individual meshes for each prim face 620 // use these for making individual meshes for each prim face
621 internal List<int> outerCoordIndices = null; 621 internal List<int> outerCoordIndices = null;
622 internal List<int> hollowCoordIndices = null; 622 internal List<int> hollowCoordIndices = null;
623 internal List<int> cut1CoordIndices = null; 623 internal List<int> cut1CoordIndices = null;
624 internal List<int> cut2CoordIndices = null; 624 internal List<int> cut2CoordIndices = null;
625 625
626 internal Coord faceNormal = new Coord(0.0f, 0.0f, 1.0f); 626 internal Coord faceNormal = new Coord(0.0f, 0.0f, 1.0f);
627 internal Coord cutNormal1 = new Coord(); 627 internal Coord cutNormal1 = new Coord();
628 internal Coord cutNormal2 = new Coord(); 628 internal Coord cutNormal2 = new Coord();
629 629
630 internal int numOuterVerts = 0; 630 internal int numOuterVerts = 0;
631 internal int numHollowVerts = 0; 631 internal int numHollowVerts = 0;
632 632
633 internal bool calcVertexNormals = false; 633 internal bool calcVertexNormals = false;
634 internal int bottomFaceNumber = 0; 634 internal int bottomFaceNumber = 0;
635 internal int numPrimFaces = 0; 635 internal int numPrimFaces = 0;
636 636
637 internal Profile() 637 internal Profile()
638 { 638 {
639 this.coords = new List<Coord>(); 639 this.coords = new List<Coord>();
640 this.faces = new List<Face>(); 640 this.faces = new List<Face>();
641 this.vertexNormals = new List<Coord>(); 641 this.vertexNormals = new List<Coord>();
642 this.us = new List<float>(); 642 this.us = new List<float>();
643 this.faceUVs = new List<UVCoord>(); 643 this.faceUVs = new List<UVCoord>();
644 this.faceNumbers = new List<int>(); 644 this.faceNumbers = new List<int>();
645 } 645 }
646 646
647 internal Profile(int sides, float profileStart, float profileEnd, float hollow, int hollowSides, bool createFaces, bool calcVertexNormals) 647 internal Profile(int sides, float profileStart, float profileEnd, float hollow, int hollowSides, bool createFaces, bool calcVertexNormals)
648 { 648 {
649 this.calcVertexNormals = calcVertexNormals; 649 this.calcVertexNormals = calcVertexNormals;
650 this.coords = new List<Coord>(); 650 this.coords = new List<Coord>();
651 this.faces = new List<Face>(); 651 this.faces = new List<Face>();
652 this.vertexNormals = new List<Coord>(); 652 this.vertexNormals = new List<Coord>();
653 this.us = new List<float>(); 653 this.us = new List<float>();
654 this.faceUVs = new List<UVCoord>(); 654 this.faceUVs = new List<UVCoord>();
655 this.faceNumbers = new List<int>(); 655 this.faceNumbers = new List<int>();
656 656
657 Coord center = new Coord(0.0f, 0.0f, 0.0f); 657 Coord center = new Coord(0.0f, 0.0f, 0.0f);
658 //bool hasCenter = false; 658 //bool hasCenter = false;
659 659
660 List<Coord> hollowCoords = new List<Coord>(); 660 List<Coord> hollowCoords = new List<Coord>();
661 List<Coord> hollowNormals = new List<Coord>(); 661 List<Coord> hollowNormals = new List<Coord>();
662 List<float> hollowUs = new List<float>(); 662 List<float> hollowUs = new List<float>();
663 663
664 if (calcVertexNormals) 664 if (calcVertexNormals)
665 { 665 {
666 this.outerCoordIndices = new List<int>(); 666 this.outerCoordIndices = new List<int>();
667 this.hollowCoordIndices = new List<int>(); 667 this.hollowCoordIndices = new List<int>();
668 this.cut1CoordIndices = new List<int>(); 668 this.cut1CoordIndices = new List<int>();
669 this.cut2CoordIndices = new List<int>(); 669 this.cut2CoordIndices = new List<int>();
670 } 670 }
671 671
672 bool hasHollow = (hollow > 0.0f); 672 bool hasHollow = (hollow > 0.0f);
673 673
674 bool hasProfileCut = (profileStart > 0.0f || profileEnd < 1.0f); 674 bool hasProfileCut = (profileStart > 0.0f || profileEnd < 1.0f);
675 675
676 AngleList angles = new AngleList(); 676 AngleList angles = new AngleList();
677 AngleList hollowAngles = new AngleList(); 677 AngleList hollowAngles = new AngleList();
678 678
679 float xScale = 0.5f; 679 float xScale = 0.5f;
680 float yScale = 0.5f; 680 float yScale = 0.5f;
681 if (sides == 4) // corners of a square are sqrt(2) from center 681 if (sides == 4) // corners of a square are sqrt(2) from center
682 { 682 {
683 xScale = 0.707f; 683 xScale = 0.707f;
684 yScale = 0.707f; 684 yScale = 0.707f;
685 } 685 }
686 686
687 float startAngle = profileStart * twoPi; 687 float startAngle = profileStart * twoPi;
688 float stopAngle = profileEnd * twoPi; 688 float stopAngle = profileEnd * twoPi;
689 689
690 try { angles.makeAngles(sides, startAngle, stopAngle); } 690 try { angles.makeAngles(sides, startAngle, stopAngle); }
691 catch (Exception ex) 691 catch (Exception ex)
692 { 692 {
693 693
694 errorMessage = "makeAngles failed: Exception: " + ex.ToString() 694 errorMessage = "makeAngles failed: Exception: " + ex.ToString()
695 + "\nsides: " + sides.ToString() + " startAngle: " + startAngle.ToString() + " stopAngle: " + stopAngle.ToString(); 695 + "\nsides: " + sides.ToString() + " startAngle: " + startAngle.ToString() + " stopAngle: " + stopAngle.ToString();
696 696
697 return; 697 return;
698 } 698 }
699 699
700 this.numOuterVerts = angles.angles.Count; 700 this.numOuterVerts = angles.angles.Count;
701 701
702 // flag to create as few triangles as possible for 3 or 4 side profile 702 // flag to create as few triangles as possible for 3 or 4 side profile
703 bool simpleFace = (sides < 5 && !hasHollow && !hasProfileCut); 703 bool simpleFace = (sides < 5 && !hasHollow && !hasProfileCut);
704 704
705 if (hasHollow) 705 if (hasHollow)
706 { 706 {
707 if (sides == hollowSides) 707 if (sides == hollowSides)
708 hollowAngles = angles; 708 hollowAngles = angles;
709 else 709 else
710 { 710 {
711 try { hollowAngles.makeAngles(hollowSides, startAngle, stopAngle); } 711 try { hollowAngles.makeAngles(hollowSides, startAngle, stopAngle); }
712 catch (Exception ex) 712 catch (Exception ex)
713 { 713 {
714 errorMessage = "makeAngles failed: Exception: " + ex.ToString() 714 errorMessage = "makeAngles failed: Exception: " + ex.ToString()
715 + "\nsides: " + sides.ToString() + " startAngle: " + startAngle.ToString() + " stopAngle: " + stopAngle.ToString(); 715 + "\nsides: " + sides.ToString() + " startAngle: " + startAngle.ToString() + " stopAngle: " + stopAngle.ToString();
716 716
717 return; 717 return;
718 } 718 }
719 } 719 }
720 this.numHollowVerts = hollowAngles.angles.Count; 720 this.numHollowVerts = hollowAngles.angles.Count;
721 } 721 }
722 else if (!simpleFace) 722 else if (!simpleFace)
723 { 723 {
724 this.coords.Add(center); 724 this.coords.Add(center);
725 //hasCenter = true; 725 //hasCenter = true;
726 if (this.calcVertexNormals) 726 if (this.calcVertexNormals)
727 this.vertexNormals.Add(new Coord(0.0f, 0.0f, 1.0f)); 727 this.vertexNormals.Add(new Coord(0.0f, 0.0f, 1.0f));
728 this.us.Add(0.0f); 728 this.us.Add(0.0f);
729 } 729 }
730 730
731 float z = 0.0f; 731 float z = 0.0f;
732 732
733 Angle angle; 733 Angle angle;
734 Coord newVert = new Coord(); 734 Coord newVert = new Coord();
735 if (hasHollow && hollowSides != sides) 735 if (hasHollow && hollowSides != sides)
736 { 736 {
737 int numHollowAngles = hollowAngles.angles.Count; 737 int numHollowAngles = hollowAngles.angles.Count;
738 for (int i = 0; i < numHollowAngles; i++) 738 for (int i = 0; i < numHollowAngles; i++)
739 { 739 {
740 angle = hollowAngles.angles[i]; 740 angle = hollowAngles.angles[i];
741 newVert.X = hollow * xScale * angle.X; 741 newVert.X = hollow * xScale * angle.X;
742 newVert.Y = hollow * yScale * angle.Y; 742 newVert.Y = hollow * yScale * angle.Y;
743 newVert.Z = z; 743 newVert.Z = z;
744 744
745 hollowCoords.Add(newVert); 745 hollowCoords.Add(newVert);
746 if (this.calcVertexNormals) 746 if (this.calcVertexNormals)
747 { 747 {
748 if (hollowSides < 5) 748 if (hollowSides < 5)
749 hollowNormals.Add(hollowAngles.normals[i].Invert()); 749 hollowNormals.Add(hollowAngles.normals[i].Invert());
750 else 750 else
751 hollowNormals.Add(new Coord(-angle.X, -angle.Y, 0.0f)); 751 hollowNormals.Add(new Coord(-angle.X, -angle.Y, 0.0f));
752 752
753 hollowUs.Add(angle.angle * hollow); 753 hollowUs.Add(angle.angle * hollow);
754 } 754 }
755 } 755 }
756 } 756 }
757 757
758 int index = 0; 758 int index = 0;
759 int numAngles = angles.angles.Count; 759 int numAngles = angles.angles.Count;
760 760
761 for (int i = 0; i < numAngles; i++) 761 for (int i = 0; i < numAngles; i++)
762 { 762 {
763 angle = angles.angles[i]; 763 angle = angles.angles[i];
764 newVert.X = angle.X * xScale; 764 newVert.X = angle.X * xScale;
765 newVert.Y = angle.Y * yScale; 765 newVert.Y = angle.Y * yScale;
766 newVert.Z = z; 766 newVert.Z = z;
767 this.coords.Add(newVert); 767 this.coords.Add(newVert);
768 if (this.calcVertexNormals) 768 if (this.calcVertexNormals)
769 { 769 {
770 this.outerCoordIndices.Add(this.coords.Count - 1); 770 this.outerCoordIndices.Add(this.coords.Count - 1);
771 771
772 if (sides < 5) 772 if (sides < 5)
773 { 773 {
774 this.vertexNormals.Add(angles.normals[i]); 774 this.vertexNormals.Add(angles.normals[i]);
775 float u = angle.angle; 775 float u = angle.angle;
776 this.us.Add(u); 776 this.us.Add(u);
777 } 777 }
778 else 778 else
779 { 779 {
780 this.vertexNormals.Add(new Coord(angle.X, angle.Y, 0.0f)); 780 this.vertexNormals.Add(new Coord(angle.X, angle.Y, 0.0f));
781 this.us.Add(angle.angle); 781 this.us.Add(angle.angle);
782 } 782 }
783 } 783 }
784 784
785 if (hasHollow) 785 if (hasHollow)
786 { 786 {
787 if (hollowSides == sides) 787 if (hollowSides == sides)
788 { 788 {
789 newVert.X *= hollow; 789 newVert.X *= hollow;
790 newVert.Y *= hollow; 790 newVert.Y *= hollow;
791 newVert.Z = z; 791 newVert.Z = z;
792 hollowCoords.Add(newVert); 792 hollowCoords.Add(newVert);
793 if (this.calcVertexNormals) 793 if (this.calcVertexNormals)
794 { 794 {
795 if (sides < 5) 795 if (sides < 5)
796 { 796 {
797 hollowNormals.Add(angles.normals[i].Invert()); 797 hollowNormals.Add(angles.normals[i].Invert());
798 } 798 }
799 799
800 else 800 else
801 hollowNormals.Add(new Coord(-angle.X, -angle.Y, 0.0f)); 801 hollowNormals.Add(new Coord(-angle.X, -angle.Y, 0.0f));
802 802
803 hollowUs.Add(angle.angle * hollow); 803 hollowUs.Add(angle.angle * hollow);
804 } 804 }
805 } 805 }
806 } 806 }
807 else if (!simpleFace && createFaces && angle.angle > 0.0001f) 807 else if (!simpleFace && createFaces && angle.angle > 0.0001f)
808 { 808 {
809 Face newFace = new Face(); 809 Face newFace = new Face();
810 newFace.v1 = 0; 810 newFace.v1 = 0;
811 newFace.v2 = index; 811 newFace.v2 = index;
812 newFace.v3 = index + 1; 812 newFace.v3 = index + 1;
813 813
814 this.faces.Add(newFace); 814 this.faces.Add(newFace);
815 } 815 }
816 index += 1; 816 index += 1;
817 } 817 }
818 818
819 if (hasHollow) 819 if (hasHollow)
820 { 820 {
821 hollowCoords.Reverse(); 821 hollowCoords.Reverse();
822 if (this.calcVertexNormals) 822 if (this.calcVertexNormals)
823 { 823 {
824 hollowNormals.Reverse(); 824 hollowNormals.Reverse();
825 hollowUs.Reverse(); 825 hollowUs.Reverse();
826 } 826 }
827 827
828 if (createFaces) 828 if (createFaces)
829 { 829 {
830 int numOuterVerts = this.coords.Count; 830 //int numOuterVerts = this.coords.Count;
831 int numHollowVerts = hollowCoords.Count; 831 //numOuterVerts = this.coords.Count;
832 int numTotalVerts = numOuterVerts + numHollowVerts; 832 //int numHollowVerts = hollowCoords.Count;
833 833 int numTotalVerts = this.numOuterVerts + this.numHollowVerts;
834 if (numOuterVerts == numHollowVerts) 834
835 { 835 if (this.numOuterVerts == this.numHollowVerts)
836 Face newFace = new Face(); 836 {
837 837 Face newFace = new Face();
838 for (int coordIndex = 0; coordIndex < numOuterVerts - 1; coordIndex++) 838
839 { 839 for (int coordIndex = 0; coordIndex < this.numOuterVerts - 1; coordIndex++)
840 newFace.v1 = coordIndex; 840 {
841 newFace.v2 = coordIndex + 1; 841 newFace.v1 = coordIndex;
842 newFace.v3 = numTotalVerts - coordIndex - 1; 842 newFace.v2 = coordIndex + 1;
843 this.faces.Add(newFace); 843 newFace.v3 = numTotalVerts - coordIndex - 1;
844 844 this.faces.Add(newFace);
845 newFace.v1 = coordIndex + 1; 845
846 newFace.v2 = numTotalVerts - coordIndex - 2; 846 newFace.v1 = coordIndex + 1;
847 newFace.v3 = numTotalVerts - coordIndex - 1; 847 newFace.v2 = numTotalVerts - coordIndex - 2;
848 this.faces.Add(newFace); 848 newFace.v3 = numTotalVerts - coordIndex - 1;
849 } 849 this.faces.Add(newFace);
850 } 850 }
851 else 851 }
852 { 852 else
853 if (numOuterVerts < numHollowVerts) 853 {
854 { 854 if (this.numOuterVerts < this.numHollowVerts)
855 Face newFace = new Face(); 855 {
856 int j = 0; // j is the index for outer vertices 856 Face newFace = new Face();
857 int maxJ = numOuterVerts - 1; 857 int j = 0; // j is the index for outer vertices
858 for (int i = 0; i < numHollowVerts; i++) // i is the index for inner vertices 858 int maxJ = this.numOuterVerts - 1;
859 { 859 for (int i = 0; i < this.numHollowVerts; i++) // i is the index for inner vertices
860 if (j < maxJ) 860 {
861 if (angles.angles[j + 1].angle - hollowAngles.angles[i].angle < hollowAngles.angles[i].angle - angles.angles[j].angle + 0.000001f) 861 if (j < maxJ)
862 { 862 if (angles.angles[j + 1].angle - hollowAngles.angles[i].angle < hollowAngles.angles[i].angle - angles.angles[j].angle + 0.000001f)
863 newFace.v1 = numTotalVerts - i - 1; 863 {
864 newFace.v2 = j; 864 newFace.v1 = numTotalVerts - i - 1;
865 newFace.v3 = j + 1; 865 newFace.v2 = j;
866 866 newFace.v3 = j + 1;
867 this.faces.Add(newFace); 867
868 j += 1; 868 this.faces.Add(newFace);
869 } 869 j += 1;
870 870 }
871 newFace.v1 = j; 871
872 newFace.v2 = numTotalVerts - i - 2; 872 newFace.v1 = j;
873 newFace.v3 = numTotalVerts - i - 1; 873 newFace.v2 = numTotalVerts - i - 2;
874 874 newFace.v3 = numTotalVerts - i - 1;
875 this.faces.Add(newFace); 875
876 } 876 this.faces.Add(newFace);
877 } 877 }
878 else // numHollowVerts < numOuterVerts 878 }
879 { 879 else // numHollowVerts < numOuterVerts
880 Face newFace = new Face(); 880 {
881 int j = 0; // j is the index for inner vertices 881 Face newFace = new Face();
882 int maxJ = numHollowVerts - 1; 882 int j = 0; // j is the index for inner vertices
883 for (int i = 0; i < numOuterVerts; i++) 883 int maxJ = this.numHollowVerts - 1;
884 { 884 for (int i = 0; i < this.numOuterVerts; i++)
885 if (j < maxJ) 885 {
886 if (hollowAngles.angles[j + 1].angle - angles.angles[i].angle < angles.angles[i].angle - hollowAngles.angles[j].angle + 0.000001f) 886 if (j < maxJ)
887 { 887 if (hollowAngles.angles[j + 1].angle - angles.angles[i].angle < angles.angles[i].angle - hollowAngles.angles[j].angle + 0.000001f)
888 newFace.v1 = i; 888 {
889 newFace.v2 = numTotalVerts - j - 2; 889 newFace.v1 = i;
890 newFace.v3 = numTotalVerts - j - 1; 890 newFace.v2 = numTotalVerts - j - 2;
891 891 newFace.v3 = numTotalVerts - j - 1;
892 this.faces.Add(newFace); 892
893 j += 1; 893 this.faces.Add(newFace);
894 } 894 j += 1;
895 895 }
896 newFace.v1 = numTotalVerts - j - 1; 896
897 newFace.v2 = i; 897 newFace.v1 = numTotalVerts - j - 1;
898 newFace.v3 = i + 1; 898 newFace.v2 = i;
899 899 newFace.v3 = i + 1;
900 this.faces.Add(newFace); 900
901 } 901 this.faces.Add(newFace);
902 } 902 }
903 } 903 }
904 } 904 }
905 905 }
906 if (calcVertexNormals) 906
907 { 907 if (calcVertexNormals)
908 foreach (Coord hc in hollowCoords) 908 {
909 { 909 foreach (Coord hc in hollowCoords)
910 this.coords.Add(hc); 910 {
911 hollowCoordIndices.Add(this.coords.Count - 1); 911 this.coords.Add(hc);
912 } 912 hollowCoordIndices.Add(this.coords.Count - 1);
913 } 913 }
914 else 914 }
915 this.coords.AddRange(hollowCoords); 915 else
916 916 this.coords.AddRange(hollowCoords);
917 if (this.calcVertexNormals) 917
918 { 918 if (this.calcVertexNormals)
919 this.vertexNormals.AddRange(hollowNormals); 919 {
920 this.us.AddRange(hollowUs); 920 this.vertexNormals.AddRange(hollowNormals);
921 921 this.us.AddRange(hollowUs);
922 } 922
923 } 923 }
924 924 }
925 if (simpleFace && createFaces) 925
926 { 926 if (simpleFace && createFaces)
927 if (sides == 3) 927 {
928 this.faces.Add(new Face(0, 1, 2)); 928 if (sides == 3)
929 else if (sides == 4) 929 this.faces.Add(new Face(0, 1, 2));
930 { 930 else if (sides == 4)
931 this.faces.Add(new Face(0, 1, 2)); 931 {
932 this.faces.Add(new Face(0, 2, 3)); 932 this.faces.Add(new Face(0, 1, 2));
933 } 933 this.faces.Add(new Face(0, 2, 3));
934 } 934 }
935 935 }
936 if (calcVertexNormals && hasProfileCut) 936
937 { 937 if (calcVertexNormals && hasProfileCut)
938 if (hasHollow) 938 {
939 { 939 if (hasHollow)
940 int lastOuterVertIndex = this.numOuterVerts - 1; 940 {
941 941 int lastOuterVertIndex = this.numOuterVerts - 1;
942 this.cut1CoordIndices.Add(0); 942
943 this.cut1CoordIndices.Add(this.coords.Count - 1); 943 this.cut1CoordIndices.Add(0);
944 944 this.cut1CoordIndices.Add(this.coords.Count - 1);
945 this.cut2CoordIndices.Add(lastOuterVertIndex + 1); 945
946 this.cut2CoordIndices.Add(lastOuterVertIndex); 946 this.cut2CoordIndices.Add(lastOuterVertIndex + 1);
947 947 this.cut2CoordIndices.Add(lastOuterVertIndex);
948 this.cutNormal1.X = this.coords[0].Y - this.coords[this.coords.Count - 1].Y; 948
949 this.cutNormal1.Y = -(this.coords[0].X - this.coords[this.coords.Count - 1].X); 949 this.cutNormal1.X = this.coords[0].Y - this.coords[this.coords.Count - 1].Y;
950 950 this.cutNormal1.Y = -(this.coords[0].X - this.coords[this.coords.Count - 1].X);
951 this.cutNormal2.X = this.coords[lastOuterVertIndex + 1].Y - this.coords[lastOuterVertIndex].Y; 951
952 this.cutNormal2.Y = -(this.coords[lastOuterVertIndex + 1].X - this.coords[lastOuterVertIndex].X); 952 this.cutNormal2.X = this.coords[lastOuterVertIndex + 1].Y - this.coords[lastOuterVertIndex].Y;
953 } 953 this.cutNormal2.Y = -(this.coords[lastOuterVertIndex + 1].X - this.coords[lastOuterVertIndex].X);
954 954 }
955 else 955
956 { 956 else
957 this.cutNormal1.X = this.vertexNormals[1].Y; 957 {
958 this.cutNormal1.Y = -this.vertexNormals[1].X; 958 this.cutNormal1.X = this.vertexNormals[1].Y;
959 959 this.cutNormal1.Y = -this.vertexNormals[1].X;
960 this.cutNormal2.X = -this.vertexNormals[this.vertexNormals.Count - 2].Y; 960
961 this.cutNormal2.Y = this.vertexNormals[this.vertexNormals.Count - 2].X; 961 this.cutNormal2.X = -this.vertexNormals[this.vertexNormals.Count - 2].Y;
962 962 this.cutNormal2.Y = this.vertexNormals[this.vertexNormals.Count - 2].X;
963 } 963
964 this.cutNormal1.Normalize(); 964 }
965 this.cutNormal2.Normalize(); 965 this.cutNormal1.Normalize();
966 } 966 this.cutNormal2.Normalize();
967 967 }
968 this.MakeFaceUVs(); 968
969 969 this.MakeFaceUVs();
970 hollowCoords = null; 970
971 hollowNormals = null; 971 hollowCoords = null;
972 hollowUs = null; 972 hollowNormals = null;
973 973 hollowUs = null;
974 if (calcVertexNormals) 974
975 { // calculate prim face numbers 975 if (calcVertexNormals)
976 976 { // calculate prim face numbers
977 // face number order is top, outer, hollow, bottom, start cut, end cut 977
978 // I know it's ugly but so is the whole concept of prim face numbers 978 // face number order is top, outer, hollow, bottom, start cut, end cut
979 979 // I know it's ugly but so is the whole concept of prim face numbers
980 int faceNum = 1; // start with outer faces 980
981 int startVert = hasProfileCut && !hasHollow ? 1 : 0; 981 int faceNum = 1; // start with outer faces
982 if (startVert > 0) 982 int startVert = hasProfileCut && !hasHollow ? 1 : 0;
983 this.faceNumbers.Add(-1); 983 if (startVert > 0)
984 for (int i = 0; i < numOuterVerts - 1; i++) 984 this.faceNumbers.Add(-1);
985 this.faceNumbers.Add(sides < 5 ? faceNum++ : faceNum); 985 for (int i = 0; i < this.numOuterVerts - 1; i++)
986 986 this.faceNumbers.Add(sides < 5 ? faceNum++ : faceNum);
987 //if (!hasHollow && !hasProfileCut) 987
988 // this.bottomFaceNumber = faceNum++; 988 //if (!hasHollow && !hasProfileCut)
989 989 // this.bottomFaceNumber = faceNum++;
990 this.faceNumbers.Add(hasProfileCut ? -1 : faceNum++); 990
991 991 this.faceNumbers.Add(hasProfileCut ? -1 : faceNum++);
992 if (sides > 4 && (hasHollow || hasProfileCut)) 992
993 faceNum++; 993 if (sides > 4 && (hasHollow || hasProfileCut))
994 994 faceNum++;
995 if (hasHollow) 995
996 { 996 if (hasHollow)
997 for (int i = 0; i < numHollowVerts; i++) 997 {
998 this.faceNumbers.Add(faceNum); 998 for (int i = 0; i < this.numHollowVerts; i++)
999 999 this.faceNumbers.Add(faceNum);
1000 faceNum++; 1000
1001 } 1001 faceNum++;
1002 //if (hasProfileCut || hasHollow) 1002 }
1003 // this.bottomFaceNumber = faceNum++; 1003 //if (hasProfileCut || hasHollow)
1004 this.bottomFaceNumber = faceNum++; 1004 // this.bottomFaceNumber = faceNum++;
1005 1005 this.bottomFaceNumber = faceNum++;
1006 if (hasHollow && hasProfileCut) 1006
1007 this.faceNumbers.Add(faceNum++); 1007 if (hasHollow && hasProfileCut)
1008 for (int i = 0; i < this.faceNumbers.Count; i++) 1008 this.faceNumbers.Add(faceNum++);
1009 if (this.faceNumbers[i] == -1) 1009 for (int i = 0; i < this.faceNumbers.Count; i++)
1010 this.faceNumbers[i] = faceNum++; 1010 if (this.faceNumbers[i] == -1)
1011 1011 this.faceNumbers[i] = faceNum++;
1012 1012
1013 this.numPrimFaces = faceNum; 1013
1014 } 1014 this.numPrimFaces = faceNum;
1015 1015 }
1016 } 1016
1017 1017 }
1018 internal void MakeFaceUVs() 1018
1019 { 1019 internal void MakeFaceUVs()
1020 this.faceUVs = new List<UVCoord>(); 1020 {
1021 foreach (Coord c in this.coords) 1021 this.faceUVs = new List<UVCoord>();
1022 this.faceUVs.Add(new UVCoord(1.0f - (0.5f + c.X), 1.0f - (0.5f - c.Y))); 1022 foreach (Coord c in this.coords)
1023 } 1023 this.faceUVs.Add(new UVCoord(0.5f + c.X, 0.5f - c.Y));
1024 1024 }
1025 internal Profile Copy() 1025
1026 { 1026 internal Profile Copy()
1027 return this.Copy(true); 1027 {
1028 } 1028 return this.Copy(true);
1029 1029 }
1030 internal Profile Copy(bool needFaces) 1030
1031 { 1031 internal Profile Copy(bool needFaces)
1032 Profile copy = new Profile(); 1032 {
1033 1033 Profile copy = new Profile();
1034 copy.coords.AddRange(this.coords); 1034
1035 copy.faceUVs.AddRange(this.faceUVs); 1035 copy.coords.AddRange(this.coords);
1036 1036 copy.faceUVs.AddRange(this.faceUVs);
1037 if (needFaces) 1037
1038 copy.faces.AddRange(this.faces); 1038 if (needFaces)
1039 if ((copy.calcVertexNormals = this.calcVertexNormals) == true) 1039 copy.faces.AddRange(this.faces);
1040 { 1040 if ((copy.calcVertexNormals = this.calcVertexNormals) == true)
1041 copy.vertexNormals.AddRange(this.vertexNormals); 1041 {
1042 copy.faceNormal = this.faceNormal; 1042 copy.vertexNormals.AddRange(this.vertexNormals);
1043 copy.cutNormal1 = this.cutNormal1; 1043 copy.faceNormal = this.faceNormal;
1044 copy.cutNormal2 = this.cutNormal2; 1044 copy.cutNormal1 = this.cutNormal1;
1045 copy.us.AddRange(this.us); 1045 copy.cutNormal2 = this.cutNormal2;
1046 copy.faceNumbers.AddRange(this.faceNumbers); 1046 copy.us.AddRange(this.us);
1047 1047 copy.faceNumbers.AddRange(this.faceNumbers);
1048 copy.cut1CoordIndices = new List<int>(this.cut1CoordIndices); 1048
1049 copy.cut2CoordIndices = new List<int>(this.cut2CoordIndices); 1049 copy.cut1CoordIndices = new List<int>(this.cut1CoordIndices);
1050 copy.hollowCoordIndices = new List<int>(this.hollowCoordIndices); 1050 copy.cut2CoordIndices = new List<int>(this.cut2CoordIndices);
1051 copy.outerCoordIndices = new List<int>(this.outerCoordIndices); 1051 copy.hollowCoordIndices = new List<int>(this.hollowCoordIndices);
1052 } 1052 copy.outerCoordIndices = new List<int>(this.outerCoordIndices);
1053 copy.numOuterVerts = this.numOuterVerts; 1053 }
1054 copy.numHollowVerts = this.numHollowVerts; 1054 copy.numOuterVerts = this.numOuterVerts;
1055 1055 copy.numHollowVerts = this.numHollowVerts;
1056 return copy; 1056
1057 } 1057 return copy;
1058 1058 }
1059 internal void AddPos(Coord v) 1059
1060 { 1060 internal void AddPos(Coord v)
1061 this.AddPos(v.X, v.Y, v.Z); 1061 {
1062 } 1062 this.AddPos(v.X, v.Y, v.Z);
1063 1063 }
1064 internal void AddPos(float x, float y, float z) 1064
1065 { 1065 internal void AddPos(float x, float y, float z)
1066 int i; 1066 {
1067 int numVerts = this.coords.Count; 1067 int i;
1068 Coord vert; 1068 int numVerts = this.coords.Count;
1069 1069 Coord vert;
1070 for (i = 0; i < numVerts; i++) 1070
1071 { 1071 for (i = 0; i < numVerts; i++)
1072 vert = this.coords[i]; 1072 {
1073 vert.X += x; 1073 vert = this.coords[i];
1074 vert.Y += y; 1074 vert.X += x;
1075 vert.Z += z; 1075 vert.Y += y;
1076 this.coords[i] = vert; 1076 vert.Z += z;
1077 } 1077 this.coords[i] = vert;
1078 } 1078 }
1079 1079 }
1080 internal void AddRot(Quat q) 1080
1081 { 1081 internal void AddRot(Quat q)
1082 int i; 1082 {
1083 int numVerts = this.coords.Count; 1083 int i;
1084 1084 int numVerts = this.coords.Count;
1085 for (i = 0; i < numVerts; i++) 1085
1086 this.coords[i] *= q; 1086 for (i = 0; i < numVerts; i++)
1087 1087 this.coords[i] *= q;
1088 if (this.calcVertexNormals) 1088
1089 { 1089 if (this.calcVertexNormals)
1090 int numNormals = this.vertexNormals.Count; 1090 {
1091 for (i = 0; i < numNormals; i++) 1091 int numNormals = this.vertexNormals.Count;
1092 this.vertexNormals[i] *= q; 1092 for (i = 0; i < numNormals; i++)
1093 1093 this.vertexNormals[i] *= q;
1094 this.faceNormal *= q; 1094
1095 this.cutNormal1 *= q; 1095 this.faceNormal *= q;
1096 this.cutNormal2 *= q; 1096 this.cutNormal1 *= q;
1097 1097 this.cutNormal2 *= q;
1098 } 1098
1099 } 1099 }
1100 1100 }
1101 internal void Scale(float x, float y) 1101
1102 { 1102 internal void Scale(float x, float y)
1103 int i; 1103 {
1104 int numVerts = this.coords.Count; 1104 int i;
1105 Coord vert; 1105 int numVerts = this.coords.Count;
1106 1106 Coord vert;
1107 for (i = 0; i < numVerts; i++) 1107
1108 { 1108 for (i = 0; i < numVerts; i++)
1109 vert = this.coords[i]; 1109 {
1110 vert.X *= x; 1110 vert = this.coords[i];
1111 vert.Y *= y; 1111 vert.X *= x;
1112 this.coords[i] = vert; 1112 vert.Y *= y;
1113 } 1113 this.coords[i] = vert;
1114 } 1114 }
1115 1115 }
1116 /// <summary> 1116
1117 /// Changes order of the vertex indices and negates the center vertex normal. Does not alter vertex normals of radial vertices 1117 /// <summary>
1118 /// </summary> 1118 /// Changes order of the vertex indices and negates the center vertex normal. Does not alter vertex normals of radial vertices
1119 internal void FlipNormals() 1119 /// </summary>
1120 { 1120 internal void FlipNormals()
1121 int i; 1121 {
1122 int numFaces = this.faces.Count; 1122 int i;
1123 Face tmpFace; 1123 int numFaces = this.faces.Count;
1124 int tmp; 1124 Face tmpFace;
1125 1125 int tmp;
1126 for (i = 0; i < numFaces; i++) 1126
1127 { 1127 for (i = 0; i < numFaces; i++)
1128 tmpFace = this.faces[i]; 1128 {
1129 tmp = tmpFace.v3; 1129 tmpFace = this.faces[i];
1130 tmpFace.v3 = tmpFace.v1; 1130 tmp = tmpFace.v3;
1131 tmpFace.v1 = tmp; 1131 tmpFace.v3 = tmpFace.v1;
1132 this.faces[i] = tmpFace; 1132 tmpFace.v1 = tmp;
1133 } 1133 this.faces[i] = tmpFace;
1134 1134 }
1135 if (this.calcVertexNormals) 1135
1136 { 1136 if (this.calcVertexNormals)
1137 int normalCount = this.vertexNormals.Count; 1137 {
1138 if (normalCount > 0) 1138 int normalCount = this.vertexNormals.Count;
1139 { 1139 if (normalCount > 0)
1140 Coord n = this.vertexNormals[normalCount - 1]; 1140 {
1141 n.Z = -n.Z; 1141 Coord n = this.vertexNormals[normalCount - 1];
1142 this.vertexNormals[normalCount - 1] = n; 1142 n.Z = -n.Z;
1143 } 1143 this.vertexNormals[normalCount - 1] = n;
1144 } 1144 }
1145 1145 }
1146 this.faceNormal.X = -this.faceNormal.X; 1146
1147 this.faceNormal.Y = -this.faceNormal.Y; 1147 this.faceNormal.X = -this.faceNormal.X;
1148 this.faceNormal.Z = -this.faceNormal.Z; 1148 this.faceNormal.Y = -this.faceNormal.Y;
1149 1149 this.faceNormal.Z = -this.faceNormal.Z;
1150 int numfaceUVs = this.faceUVs.Count; 1150
1151 for (i = 0; i < numfaceUVs; i++) 1151 int numfaceUVs = this.faceUVs.Count;
1152 { 1152 for (i = 0; i < numfaceUVs; i++)
1153 UVCoord uv = this.faceUVs[i]; 1153 {
1154 uv.V = 1.0f - uv.V; 1154 UVCoord uv = this.faceUVs[i];
1155 this.faceUVs[i] = uv; 1155 uv.V = 1.0f - uv.V;
1156 } 1156 this.faceUVs[i] = uv;
1157 } 1157 }
1158 1158 }
1159 internal void AddValue2FaceVertexIndices(int num) 1159
1160 { 1160 internal void AddValue2FaceVertexIndices(int num)
1161 int numFaces = this.faces.Count; 1161 {
1162 Face tmpFace; 1162 int numFaces = this.faces.Count;
1163 for (int i = 0; i < numFaces; i++) 1163 Face tmpFace;
1164 { 1164 for (int i = 0; i < numFaces; i++)
1165 tmpFace = this.faces[i]; 1165 {
1166 tmpFace.v1 += num; 1166 tmpFace = this.faces[i];
1167 tmpFace.v2 += num; 1167 tmpFace.v1 += num;
1168 tmpFace.v3 += num; 1168 tmpFace.v2 += num;
1169 1169 tmpFace.v3 += num;
1170 this.faces[i] = tmpFace; 1170
1171 } 1171 this.faces[i] = tmpFace;
1172 } 1172 }
1173 1173 }
1174 internal void AddValue2FaceNormalIndices(int num) 1174
1175 { 1175 internal void AddValue2FaceNormalIndices(int num)
1176 if (this.calcVertexNormals) 1176 {
1177 { 1177 if (this.calcVertexNormals)
1178 int numFaces = this.faces.Count; 1178 {
1179 Face tmpFace; 1179 int numFaces = this.faces.Count;
1180 for (int i = 0; i < numFaces; i++) 1180 Face tmpFace;
1181 { 1181 for (int i = 0; i < numFaces; i++)
1182 tmpFace = this.faces[i]; 1182 {
1183 tmpFace.n1 += num; 1183 tmpFace = this.faces[i];
1184 tmpFace.n2 += num; 1184 tmpFace.n1 += num;
1185 tmpFace.n3 += num; 1185 tmpFace.n2 += num;
1186 1186 tmpFace.n3 += num;
1187 this.faces[i] = tmpFace; 1187
1188 } 1188 this.faces[i] = tmpFace;
1189 } 1189 }
1190 } 1190 }
1191 1191 }
1192 internal void DumpRaw(String path, String name, String title) 1192
1193 { 1193 internal void DumpRaw(String path, String name, String title)
1194 if (path == null) 1194 {
1195 return; 1195 if (path == null)
1196 String fileName = name + "_" + title + ".raw"; 1196 return;
1197 String completePath = System.IO.Path.Combine(path, fileName); 1197 String fileName = name + "_" + title + ".raw";
1198 StreamWriter sw = new StreamWriter(completePath); 1198 String completePath = System.IO.Path.Combine(path, fileName);
1199 1199 StreamWriter sw = new StreamWriter(completePath);
1200 for (int i = 0; i < this.faces.Count; i++) 1200
1201 { 1201 for (int i = 0; i < this.faces.Count; i++)
1202 string s = this.coords[this.faces[i].v1].ToString(); 1202 {
1203 s += " " + this.coords[this.faces[i].v2].ToString(); 1203 string s = this.coords[this.faces[i].v1].ToString();
1204 s += " " + this.coords[this.faces[i].v3].ToString(); 1204 s += " " + this.coords[this.faces[i].v2].ToString();
1205 1205 s += " " + this.coords[this.faces[i].v3].ToString();
1206 sw.WriteLine(s); 1206
1207 } 1207 sw.WriteLine(s);
1208 1208 }
1209 sw.Close(); 1209
1210 } 1210 sw.Close();
1211 } 1211 }
1212 1212 }
1213 public struct PathNode 1213
1214 { 1214 public struct PathNode
1215 public Coord position; 1215 {
1216 public Quat rotation; 1216 public Coord position;
1217 public float xScale; 1217 public Quat rotation;
1218 public float yScale; 1218 public float xScale;
1219 public float percentOfPath; 1219 public float yScale;
1220 } 1220 public float percentOfPath;
1221 1221 }
1222 public enum PathType { Linear = 0, Circular = 1, Flexible = 2 } 1222
1223 1223 public enum PathType { Linear = 0, Circular = 1, Flexible = 2 }
1224 public class Path 1224
1225 { 1225 public class Path
1226 public List<PathNode> pathNodes = new List<PathNode>(); 1226 {
1227 1227 public List<PathNode> pathNodes = new List<PathNode>();
1228 public float twistBegin = 0.0f; 1228
1229 public float twistEnd = 0.0f; 1229 public float twistBegin = 0.0f;
1230 public float topShearX = 0.0f; 1230 public float twistEnd = 0.0f;
1231 public float topShearY = 0.0f; 1231 public float topShearX = 0.0f;
1232 public float pathCutBegin = 0.0f; 1232 public float topShearY = 0.0f;
1233 public float pathCutEnd = 1.0f; 1233 public float pathCutBegin = 0.0f;
1234 public float dimpleBegin = 0.0f; 1234 public float pathCutEnd = 1.0f;
1235 public float dimpleEnd = 1.0f; 1235 public float dimpleBegin = 0.0f;
1236 public float skew = 0.0f; 1236 public float dimpleEnd = 1.0f;
1237 public float holeSizeX = 1.0f; // called pathScaleX in pbs 1237 public float skew = 0.0f;
1238 public float holeSizeY = 0.25f; 1238 public float holeSizeX = 1.0f; // called pathScaleX in pbs
1239 public float taperX = 0.0f; 1239 public float holeSizeY = 0.25f;
1240 public float taperY = 0.0f; 1240 public float taperX = 0.0f;
1241 public float radius = 0.0f; 1241 public float taperY = 0.0f;
1242 public float revolutions = 1.0f; 1242 public float radius = 0.0f;
1243 public int stepsPerRevolution = 24; 1243 public float revolutions = 1.0f;
1244 1244 public int stepsPerRevolution = 24;
1245 private const float twoPi = 2.0f * (float)Math.PI; 1245
1246 1246 private const float twoPi = 2.0f * (float)Math.PI;
1247 public void Create(PathType pathType, int steps) 1247
1248 { 1248 public void Create(PathType pathType, int steps)
1249 if (pathType == PathType.Linear || pathType == PathType.Flexible) 1249 {
1250 { 1250 if (pathType == PathType.Linear || pathType == PathType.Flexible)
1251 int step = 0; 1251 {
1252 1252 int step = 0;
1253 float length = this.pathCutEnd - this.pathCutBegin; 1253
1254 float twistTotal = twistEnd - twistBegin; 1254 float length = this.pathCutEnd - this.pathCutBegin;
1255 float twistTotalAbs = Math.Abs(twistTotal); 1255 float twistTotal = twistEnd - twistBegin;
1256 if (twistTotalAbs > 0.01f) 1256 float twistTotalAbs = Math.Abs(twistTotal);
1257 steps += (int)(twistTotalAbs * 3.66); // dahlia's magic number 1257 if (twistTotalAbs > 0.01f)
1258 1258 steps += (int)(twistTotalAbs * 3.66); // dahlia's magic number
1259 float start = -0.5f; 1259
1260 float stepSize = length / (float)steps; 1260 float start = -0.5f;
1261 float percentOfPathMultiplier = stepSize; 1261 float stepSize = length / (float)steps;
1262 float xOffset = 0.0f; 1262 float percentOfPathMultiplier = stepSize;
1263 float yOffset = 0.0f; 1263 float xOffset = 0.0f;
1264 float zOffset = start; 1264 float yOffset = 0.0f;
1265 float xOffsetStepIncrement = this.topShearX / steps; 1265 float zOffset = start;
1266 float yOffsetStepIncrement = this.topShearY / steps; 1266 float xOffsetStepIncrement = this.topShearX / steps;
1267 1267 float yOffsetStepIncrement = this.topShearY / steps;
1268 float percentOfPath = this.pathCutBegin; 1268
1269 zOffset += percentOfPath; 1269 float percentOfPath = this.pathCutBegin;
1270 1270 zOffset += percentOfPath;
1271 // sanity checks 1271
1272 1272 // sanity checks
1273 bool done = false; 1273
1274 1274 bool done = false;
1275 while (!done) 1275
1276 { 1276 while (!done)
1277 PathNode newNode = new PathNode(); 1277 {
1278 1278 PathNode newNode = new PathNode();
1279 newNode.xScale = 1.0f; 1279
1280 if (this.taperX == 0.0f) 1280 newNode.xScale = 1.0f;
1281 newNode.xScale = 1.0f; 1281 if (this.taperX == 0.0f)
1282 else if (this.taperX > 0.0f) 1282 newNode.xScale = 1.0f;
1283 newNode.xScale = 1.0f - percentOfPath * this.taperX; 1283 else if (this.taperX > 0.0f)
1284 else newNode.xScale = 1.0f + (1.0f - percentOfPath) * this.taperX; 1284 newNode.xScale = 1.0f - percentOfPath * this.taperX;
1285 1285 else newNode.xScale = 1.0f + (1.0f - percentOfPath) * this.taperX;
1286 newNode.yScale = 1.0f; 1286
1287 if (this.taperY == 0.0f) 1287 newNode.yScale = 1.0f;
1288 newNode.yScale = 1.0f; 1288 if (this.taperY == 0.0f)
1289 else if (this.taperY > 0.0f) 1289 newNode.yScale = 1.0f;
1290 newNode.yScale = 1.0f - percentOfPath * this.taperY; 1290 else if (this.taperY > 0.0f)
1291 else newNode.yScale = 1.0f + (1.0f - percentOfPath) * this.taperY; 1291 newNode.yScale = 1.0f - percentOfPath * this.taperY;
1292 1292 else newNode.yScale = 1.0f + (1.0f - percentOfPath) * this.taperY;
1293 float twist = twistBegin + twistTotal * percentOfPath; 1293
1294 1294 float twist = twistBegin + twistTotal * percentOfPath;
1295 newNode.rotation = new Quat(new Coord(0.0f, 0.0f, 1.0f), twist); 1295
1296 newNode.position = new Coord(xOffset, yOffset, zOffset); 1296 newNode.rotation = new Quat(new Coord(0.0f, 0.0f, 1.0f), twist);
1297 newNode.percentOfPath = percentOfPath; 1297 newNode.position = new Coord(xOffset, yOffset, zOffset);
1298 1298 newNode.percentOfPath = percentOfPath;
1299 pathNodes.Add(newNode); 1299
1300 1300 pathNodes.Add(newNode);
1301 if (step < steps) 1301
1302 { 1302 if (step < steps)
1303 step += 1; 1303 {
1304 percentOfPath += percentOfPathMultiplier; 1304 step += 1;
1305 xOffset += xOffsetStepIncrement; 1305 percentOfPath += percentOfPathMultiplier;
1306 yOffset += yOffsetStepIncrement; 1306 xOffset += xOffsetStepIncrement;
1307 zOffset += stepSize; 1307 yOffset += yOffsetStepIncrement;
1308 if (percentOfPath > this.pathCutEnd) 1308 zOffset += stepSize;
1309 done = true; 1309 if (percentOfPath > this.pathCutEnd)
1310 } 1310 done = true;
1311 else done = true; 1311 }
1312 } 1312 else done = true;
1313 } // end of linear path code 1313 }
1314 1314 } // end of linear path code
1315 else // pathType == Circular 1315
1316 { 1316 else // pathType == Circular
1317 float twistTotal = twistEnd - twistBegin; 1317 {
1318 1318 float twistTotal = twistEnd - twistBegin;
1319 // if the profile has a lot of twist, add more layers otherwise the layers may overlap 1319
1320 // and the resulting mesh may be quite inaccurate. This method is arbitrary and doesn't 1320 // if the profile has a lot of twist, add more layers otherwise the layers may overlap
1321 // accurately match the viewer 1321 // and the resulting mesh may be quite inaccurate. This method is arbitrary and doesn't
1322 float twistTotalAbs = Math.Abs(twistTotal); 1322 // accurately match the viewer
1323 if (twistTotalAbs > 0.01f) 1323 float twistTotalAbs = Math.Abs(twistTotal);
1324 { 1324 if (twistTotalAbs > 0.01f)
1325 if (twistTotalAbs > Math.PI * 1.5f) 1325 {
1326 steps *= 2; 1326 if (twistTotalAbs > Math.PI * 1.5f)
1327 if (twistTotalAbs > Math.PI * 3.0f) 1327 steps *= 2;
1328 steps *= 2; 1328 if (twistTotalAbs > Math.PI * 3.0f)
1329 } 1329 steps *= 2;
1330 1330 }
1331 float yPathScale = this.holeSizeY * 0.5f; 1331
1332 float pathLength = this.pathCutEnd - this.pathCutBegin; 1332 float yPathScale = this.holeSizeY * 0.5f;
1333 float totalSkew = this.skew * 2.0f * pathLength; 1333 float pathLength = this.pathCutEnd - this.pathCutBegin;
1334 float skewStart = this.pathCutBegin * 2.0f * this.skew - this.skew; 1334 float totalSkew = this.skew * 2.0f * pathLength;
1335 float xOffsetTopShearXFactor = this.topShearX * (0.25f + 0.5f * (0.5f - this.holeSizeY)); 1335 float skewStart = this.pathCutBegin * 2.0f * this.skew - this.skew;
1336 float yShearCompensation = 1.0f + Math.Abs(this.topShearY) * 0.25f; 1336 float xOffsetTopShearXFactor = this.topShearX * (0.25f + 0.5f * (0.5f - this.holeSizeY));
1337 1337 float yShearCompensation = 1.0f + Math.Abs(this.topShearY) * 0.25f;
1338 // It's not quite clear what pushY (Y top shear) does, but subtracting it from the start and end 1338
1339 // angles appears to approximate it's effects on path cut. Likewise, adding it to the angle used 1339 // It's not quite clear what pushY (Y top shear) does, but subtracting it from the start and end
1340 // to calculate the sine for generating the path radius appears to approximate it's effects there 1340 // angles appears to approximate it's effects on path cut. Likewise, adding it to the angle used
1341 // too, but there are some subtle differences in the radius which are noticeable as the prim size 1341 // to calculate the sine for generating the path radius appears to approximate it's effects there
1342 // increases and it may affect megaprims quite a bit. The effect of the Y top shear parameter on 1342 // too, but there are some subtle differences in the radius which are noticeable as the prim size
1343 // the meshes generated with this technique appear nearly identical in shape to the same prims when 1343 // increases and it may affect megaprims quite a bit. The effect of the Y top shear parameter on
1344 // displayed by the viewer. 1344 // the meshes generated with this technique appear nearly identical in shape to the same prims when
1345 1345 // displayed by the viewer.
1346 float startAngle = (twoPi * this.pathCutBegin * this.revolutions) - this.topShearY * 0.9f; 1346
1347 float endAngle = (twoPi * this.pathCutEnd * this.revolutions) - this.topShearY * 0.9f; 1347 float startAngle = (twoPi * this.pathCutBegin * this.revolutions) - this.topShearY * 0.9f;
1348 float stepSize = twoPi / this.stepsPerRevolution; 1348 float endAngle = (twoPi * this.pathCutEnd * this.revolutions) - this.topShearY * 0.9f;
1349 1349 float stepSize = twoPi / this.stepsPerRevolution;
1350 int step = (int)(startAngle / stepSize); 1350
1351// int firstStep = step; 1351 int step = (int)(startAngle / stepSize);
1352 float angle = startAngle; 1352 float angle = startAngle;
1353 1353
1354 bool done = false; 1354 bool done = false;
1355 while (!done) // loop through the length of the path and add the layers 1355 while (!done) // loop through the length of the path and add the layers
1356 { 1356 {
1357 PathNode newNode = new PathNode(); 1357 PathNode newNode = new PathNode();
1358 1358
1359 float xProfileScale = (1.0f - Math.Abs(this.skew)) * this.holeSizeX; 1359 float xProfileScale = (1.0f - Math.Abs(this.skew)) * this.holeSizeX;
1360 float yProfileScale = this.holeSizeY; 1360 float yProfileScale = this.holeSizeY;
1361 1361
1362 float percentOfPath = angle / (twoPi * this.revolutions); 1362 float percentOfPath = angle / (twoPi * this.revolutions);
1363 float percentOfAngles = (angle - startAngle) / (endAngle - startAngle); 1363 float percentOfAngles = (angle - startAngle) / (endAngle - startAngle);
1364 1364
1365 if (this.taperX > 0.01f) 1365 if (this.taperX > 0.01f)
1366 xProfileScale *= 1.0f - percentOfPath * this.taperX; 1366 xProfileScale *= 1.0f - percentOfPath * this.taperX;
1367 else if (this.taperX < -0.01f) 1367 else if (this.taperX < -0.01f)
1368 xProfileScale *= 1.0f + (1.0f - percentOfPath) * this.taperX; 1368 xProfileScale *= 1.0f + (1.0f - percentOfPath) * this.taperX;
1369 1369
1370 if (this.taperY > 0.01f) 1370 if (this.taperY > 0.01f)
1371 yProfileScale *= 1.0f - percentOfPath * this.taperY; 1371 yProfileScale *= 1.0f - percentOfPath * this.taperY;
1372 else if (this.taperY < -0.01f) 1372 else if (this.taperY < -0.01f)
1373 yProfileScale *= 1.0f + (1.0f - percentOfPath) * this.taperY; 1373 yProfileScale *= 1.0f + (1.0f - percentOfPath) * this.taperY;
1374 1374
1375 newNode.xScale = xProfileScale; 1375 newNode.xScale = xProfileScale;
1376 newNode.yScale = yProfileScale; 1376 newNode.yScale = yProfileScale;
1377 1377
1378 float radiusScale = 1.0f; 1378 float radiusScale = 1.0f;
1379 if (this.radius > 0.001f) 1379 if (this.radius > 0.001f)
1380 radiusScale = 1.0f - this.radius * percentOfPath; 1380 radiusScale = 1.0f - this.radius * percentOfPath;
1381 else if (this.radius < 0.001f) 1381 else if (this.radius < 0.001f)
1382 radiusScale = 1.0f + this.radius * (1.0f - percentOfPath); 1382 radiusScale = 1.0f + this.radius * (1.0f - percentOfPath);
1383 1383
1384 float twist = twistBegin + twistTotal * percentOfPath; 1384 float twist = twistBegin + twistTotal * percentOfPath;
1385 1385
1386 float xOffset = 0.5f * (skewStart + totalSkew * percentOfAngles); 1386 float xOffset = 0.5f * (skewStart + totalSkew * percentOfAngles);
1387 xOffset += (float)Math.Sin(angle) * xOffsetTopShearXFactor; 1387 xOffset += (float)Math.Sin(angle) * xOffsetTopShearXFactor;
1388 1388
1389 float yOffset = yShearCompensation * (float)Math.Cos(angle) * (0.5f - yPathScale) * radiusScale; 1389 float yOffset = yShearCompensation * (float)Math.Cos(angle) * (0.5f - yPathScale) * radiusScale;
1390 1390
1391 float zOffset = (float)Math.Sin(angle + this.topShearY) * (0.5f - yPathScale) * radiusScale; 1391 float zOffset = (float)Math.Sin(angle + this.topShearY) * (0.5f - yPathScale) * radiusScale;
1392 1392
1393 newNode.position = new Coord(xOffset, yOffset, zOffset); 1393 newNode.position = new Coord(xOffset, yOffset, zOffset);
1394 1394
1395 // now orient the rotation of the profile layer relative to it's position on the path 1395 // now orient the rotation of the profile layer relative to it's position on the path
1396 // adding taperY to the angle used to generate the quat appears to approximate the viewer 1396 // adding taperY to the angle used to generate the quat appears to approximate the viewer
1397 1397
1398 newNode.rotation = new Quat(new Coord(1.0f, 0.0f, 0.0f), angle + this.topShearY); 1398 newNode.rotation = new Quat(new Coord(1.0f, 0.0f, 0.0f), angle + this.topShearY);
1399 1399
1400 // next apply twist rotation to the profile layer 1400 // next apply twist rotation to the profile layer
1401 if (twistTotal != 0.0f || twistBegin != 0.0f) 1401 if (twistTotal != 0.0f || twistBegin != 0.0f)
1402 newNode.rotation *= new Quat(new Coord(0.0f, 0.0f, 1.0f), twist); 1402 newNode.rotation *= new Quat(new Coord(0.0f, 0.0f, 1.0f), twist);
1403 1403
1404 newNode.percentOfPath = percentOfPath; 1404 newNode.percentOfPath = percentOfPath;
1405 1405
1406 pathNodes.Add(newNode); 1406 pathNodes.Add(newNode);
1407 1407
1408 // calculate terms for next iteration 1408 // calculate terms for next iteration
1409 // calculate the angle for the next iteration of the loop 1409 // calculate the angle for the next iteration of the loop
1410 1410
1411 if (angle >= endAngle - 0.01) 1411 if (angle >= endAngle - 0.01)
1412 done = true; 1412 done = true;
1413 else 1413 else
1414 { 1414 {
1415 step += 1; 1415 step += 1;
1416 angle = stepSize * step; 1416 angle = stepSize * step;
1417 if (angle > endAngle) 1417 if (angle > endAngle)
1418 angle = endAngle; 1418 angle = endAngle;
1419 } 1419 }
1420 } 1420 }
1421 } 1421 }
1422 } 1422 }
1423 } 1423 }
1424 1424
1425 public class PrimMesh 1425 public class PrimMesh
1426 { 1426 {
1427 public string errorMessage = ""; 1427 public string errorMessage = "";
1428 private const float twoPi = 2.0f * (float)Math.PI; 1428 private const float twoPi = 2.0f * (float)Math.PI;
1429 1429
1430 public List<Coord> coords; 1430 public List<Coord> coords;
1431 public List<Coord> normals; 1431 public List<Coord> normals;
1432 public List<Face> faces; 1432 public List<Face> faces;
1433 1433
1434 public List<ViewerFace> viewerFaces; 1434 public List<ViewerFace> viewerFaces;
1435 1435
1436 private int sides = 4; 1436 private int sides = 4;
1437 private int hollowSides = 4; 1437 private int hollowSides = 4;
1438 private float profileStart = 0.0f; 1438 private float profileStart = 0.0f;
1439 private float profileEnd = 1.0f; 1439 private float profileEnd = 1.0f;
1440 private float hollow = 0.0f; 1440 private float hollow = 0.0f;
1441 public int twistBegin = 0; 1441 public int twistBegin = 0;
1442 public int twistEnd = 0; 1442 public int twistEnd = 0;
1443 public float topShearX = 0.0f; 1443 public float topShearX = 0.0f;
1444 public float topShearY = 0.0f; 1444 public float topShearY = 0.0f;
1445 public float pathCutBegin = 0.0f; 1445 public float pathCutBegin = 0.0f;
1446 public float pathCutEnd = 1.0f; 1446 public float pathCutEnd = 1.0f;
1447 public float dimpleBegin = 0.0f; 1447 public float dimpleBegin = 0.0f;
1448 public float dimpleEnd = 1.0f; 1448 public float dimpleEnd = 1.0f;
1449 public float skew = 0.0f; 1449 public float skew = 0.0f;
1450 public float holeSizeX = 1.0f; // called pathScaleX in pbs 1450 public float holeSizeX = 1.0f; // called pathScaleX in pbs
1451 public float holeSizeY = 0.25f; 1451 public float holeSizeY = 0.25f;
1452 public float taperX = 0.0f; 1452 public float taperX = 0.0f;
1453 public float taperY = 0.0f; 1453 public float taperY = 0.0f;
1454 public float radius = 0.0f; 1454 public float radius = 0.0f;
1455 public float revolutions = 1.0f; 1455 public float revolutions = 1.0f;
1456 public int stepsPerRevolution = 24; 1456 public int stepsPerRevolution = 24;
1457 1457
1458 private bool hasProfileCut = false; 1458 private bool hasProfileCut = false;
1459 private bool hasHollow = false; 1459 private bool hasHollow = false;
1460 public bool calcVertexNormals = false; 1460 public bool calcVertexNormals = false;
1461 private bool normalsProcessed = false; 1461 private bool normalsProcessed = false;
1462 public bool viewerMode = false; 1462 public bool viewerMode = false;
1463 1463
1464 public int numPrimFaces = 0; 1464 public int numPrimFaces = 0;
1465 1465
1466 /// <summary> 1466 /// <summary>
1467 /// Human readable string representation of the parameters used to create a mesh. 1467 /// Human readable string representation of the parameters used to create a mesh.
1468 /// </summary> 1468 /// </summary>
1469 /// <returns></returns> 1469 /// <returns></returns>
1470 public string ParamsToDisplayString() 1470 public string ParamsToDisplayString()
1471 { 1471 {
1472 string s = ""; 1472 string s = "";
1473 s += "sides..................: " + this.sides.ToString(); 1473 s += "sides..................: " + this.sides.ToString();
1474 s += "\nhollowSides..........: " + this.hollowSides.ToString(); 1474 s += "\nhollowSides..........: " + this.hollowSides.ToString();
1475 s += "\nprofileStart.........: " + this.profileStart.ToString(); 1475 s += "\nprofileStart.........: " + this.profileStart.ToString();
1476 s += "\nprofileEnd...........: " + this.profileEnd.ToString(); 1476 s += "\nprofileEnd...........: " + this.profileEnd.ToString();
1477 s += "\nhollow...............: " + this.hollow.ToString(); 1477 s += "\nhollow...............: " + this.hollow.ToString();
1478 s += "\ntwistBegin...........: " + this.twistBegin.ToString(); 1478 s += "\ntwistBegin...........: " + this.twistBegin.ToString();
1479 s += "\ntwistEnd.............: " + this.twistEnd.ToString(); 1479 s += "\ntwistEnd.............: " + this.twistEnd.ToString();
1480 s += "\ntopShearX............: " + this.topShearX.ToString(); 1480 s += "\ntopShearX............: " + this.topShearX.ToString();
1481 s += "\ntopShearY............: " + this.topShearY.ToString(); 1481 s += "\ntopShearY............: " + this.topShearY.ToString();
1482 s += "\npathCutBegin.........: " + this.pathCutBegin.ToString(); 1482 s += "\npathCutBegin.........: " + this.pathCutBegin.ToString();
1483 s += "\npathCutEnd...........: " + this.pathCutEnd.ToString(); 1483 s += "\npathCutEnd...........: " + this.pathCutEnd.ToString();
1484 s += "\ndimpleBegin..........: " + this.dimpleBegin.ToString(); 1484 s += "\ndimpleBegin..........: " + this.dimpleBegin.ToString();
1485 s += "\ndimpleEnd............: " + this.dimpleEnd.ToString(); 1485 s += "\ndimpleEnd............: " + this.dimpleEnd.ToString();
1486 s += "\nskew.................: " + this.skew.ToString(); 1486 s += "\nskew.................: " + this.skew.ToString();
1487 s += "\nholeSizeX............: " + this.holeSizeX.ToString(); 1487 s += "\nholeSizeX............: " + this.holeSizeX.ToString();
1488 s += "\nholeSizeY............: " + this.holeSizeY.ToString(); 1488 s += "\nholeSizeY............: " + this.holeSizeY.ToString();
1489 s += "\ntaperX...............: " + this.taperX.ToString(); 1489 s += "\ntaperX...............: " + this.taperX.ToString();
1490 s += "\ntaperY...............: " + this.taperY.ToString(); 1490 s += "\ntaperY...............: " + this.taperY.ToString();
1491 s += "\nradius...............: " + this.radius.ToString(); 1491 s += "\nradius...............: " + this.radius.ToString();
1492 s += "\nrevolutions..........: " + this.revolutions.ToString(); 1492 s += "\nrevolutions..........: " + this.revolutions.ToString();
1493 s += "\nstepsPerRevolution...: " + this.stepsPerRevolution.ToString(); 1493 s += "\nstepsPerRevolution...: " + this.stepsPerRevolution.ToString();
1494 1494
1495 return s; 1495 return s;
1496 } 1496 }
1497 1497
1498 /// <summary> 1498 /// <summary>
1499 /// Constructs a PrimMesh object and creates the profile for extrusion. 1499 /// Constructs a PrimMesh object and creates the profile for extrusion.
1500 /// </summary> 1500 /// </summary>
1501 /// <param name="sides"></param> 1501 /// <param name="sides"></param>
1502 /// <param name="profileStart"></param> 1502 /// <param name="profileStart"></param>
1503 /// <param name="profileEnd"></param> 1503 /// <param name="profileEnd"></param>
1504 /// <param name="hollow"></param> 1504 /// <param name="hollow"></param>
1505 /// <param name="hollowSides"></param> 1505 /// <param name="hollowSides"></param>
1506 public PrimMesh(int sides, float profileStart, float profileEnd, float hollow, int hollowSides) 1506 public PrimMesh(int sides, float profileStart, float profileEnd, float hollow, int hollowSides)
1507 { 1507 {
1508 this.coords = new List<Coord>(); 1508 this.coords = new List<Coord>();
1509 this.faces = new List<Face>(); 1509 this.faces = new List<Face>();
1510 1510
1511 this.sides = sides; 1511 this.sides = sides;
1512 this.profileStart = profileStart; 1512 this.profileStart = profileStart;
1513 this.profileEnd = profileEnd; 1513 this.profileEnd = profileEnd;
1514 this.hollow = hollow; 1514 this.hollow = hollow;
1515 this.hollowSides = hollowSides; 1515 this.hollowSides = hollowSides;
1516 1516
1517 if (sides < 3) 1517 if (sides < 3)
1518 this.sides = 3; 1518 this.sides = 3;
1519 if (hollowSides < 3) 1519 if (hollowSides < 3)
1520 this.hollowSides = 3; 1520 this.hollowSides = 3;
1521 if (profileStart < 0.0f) 1521 if (profileStart < 0.0f)
1522 this.profileStart = 0.0f; 1522 this.profileStart = 0.0f;
1523 if (profileEnd > 1.0f) 1523 if (profileEnd > 1.0f)
1524 this.profileEnd = 1.0f; 1524 this.profileEnd = 1.0f;
1525 if (profileEnd < 0.02f) 1525 if (profileEnd < 0.02f)
1526 this.profileEnd = 0.02f; 1526 this.profileEnd = 0.02f;
1527 if (profileStart >= profileEnd) 1527 if (profileStart >= profileEnd)
1528 this.profileStart = profileEnd - 0.02f; 1528 this.profileStart = profileEnd - 0.02f;
1529 if (hollow > 0.99f) 1529 if (hollow > 0.99f)
1530 this.hollow = 0.99f; 1530 this.hollow = 0.99f;
1531 if (hollow < 0.0f) 1531 if (hollow < 0.0f)
1532 this.hollow = 0.0f; 1532 this.hollow = 0.0f;
1533 1533
1534 this.hasProfileCut = (this.profileStart > 0.0f || this.profileEnd < 1.0f); 1534 this.hasProfileCut = (this.profileStart > 0.0f || this.profileEnd < 1.0f);
1535 this.hasHollow = (this.hollow > 0.001f); 1535 this.hasHollow = (this.hollow > 0.001f);
1536 } 1536 }
1537 1537
1538 /// <summary> 1538 /// <summary>
1539 /// Extrudes a profile along a path. 1539 /// Extrudes a profile along a path.
1540 /// </summary> 1540 /// </summary>
1541 public void Extrude(PathType pathType) 1541 public void Extrude(PathType pathType)
1542 { 1542 {
1543 this.coords = new List<Coord>(); 1543 this.coords = new List<Coord>();
1544 this.faces = new List<Face>(); 1544 this.faces = new List<Face>();
1545 1545
1546 if (this.viewerMode) 1546 if (this.viewerMode)
1547 { 1547 {
1548 this.viewerFaces = new List<ViewerFace>(); 1548 this.viewerFaces = new List<ViewerFace>();
1549 this.calcVertexNormals = true; 1549 this.calcVertexNormals = true;
1550 } 1550 }
1551 1551
1552 if (this.calcVertexNormals) 1552 if (this.calcVertexNormals)
1553 this.normals = new List<Coord>(); 1553 this.normals = new List<Coord>();
1554 1554
1555 int steps = 1; 1555 int steps = 1;
1556 1556
1557 float length = this.pathCutEnd - this.pathCutBegin; 1557 float length = this.pathCutEnd - this.pathCutBegin;
1558 normalsProcessed = false; 1558 normalsProcessed = false;
1559 1559
1560 if (this.viewerMode && this.sides == 3) 1560 if (this.viewerMode && this.sides == 3)
1561 { 1561 {
1562 // prisms don't taper well so add some vertical resolution 1562 // prisms don't taper well so add some vertical resolution
1563 // other prims may benefit from this but just do prisms for now 1563 // other prims may benefit from this but just do prisms for now
1564 if (Math.Abs(this.taperX) > 0.01 || Math.Abs(this.taperY) > 0.01) 1564 if (Math.Abs(this.taperX) > 0.01 || Math.Abs(this.taperY) > 0.01)
1565 steps = (int)(steps * 4.5 * length); 1565 steps = (int)(steps * 4.5 * length);
1566 } 1566 }
1567 1567
1568 1568
1569 float twistBegin = this.twistBegin / 360.0f * twoPi; 1569 float twistBegin = this.twistBegin / 360.0f * twoPi;
1570 float twistEnd = this.twistEnd / 360.0f * twoPi; 1570 float twistEnd = this.twistEnd / 360.0f * twoPi;
1571 float twistTotal = twistEnd - twistBegin; 1571 float twistTotal = twistEnd - twistBegin;
1572 float twistTotalAbs = Math.Abs(twistTotal); 1572 float twistTotalAbs = Math.Abs(twistTotal);
1573 if (twistTotalAbs > 0.01f) 1573 if (twistTotalAbs > 0.01f)
1574 steps += (int)(twistTotalAbs * 3.66); // dahlia's magic number 1574 steps += (int)(twistTotalAbs * 3.66); // dahlia's magic number
1575 1575
1576 float hollow = this.hollow; 1576 float hollow = this.hollow;
1577 1577
1578 // sanity checks 1578 // sanity checks
1579 float initialProfileRot = 0.0f; 1579 float initialProfileRot = 0.0f;
1580 if (pathType == PathType.Circular) 1580 if (pathType == PathType.Circular)
1581 { 1581 {
1582 if (this.sides == 3) 1582 if (this.sides == 3)
1583 { 1583 {
1584 initialProfileRot = (float)Math.PI; 1584 initialProfileRot = (float)Math.PI;
1585 if (this.hollowSides == 4) 1585 if (this.hollowSides == 4)
1586 { 1586 {
1587 if (hollow > 0.7f) 1587 if (hollow > 0.7f)
1588 hollow = 0.7f; 1588 hollow = 0.7f;
1589 hollow *= 0.707f; 1589 hollow *= 0.707f;
1590 } 1590 }
1591 else hollow *= 0.5f; 1591 else hollow *= 0.5f;
1592 } 1592 }
1593 else if (this.sides == 4) 1593 else if (this.sides == 4)
1594 { 1594 {
1595 initialProfileRot = 0.25f * (float)Math.PI; 1595 initialProfileRot = 0.25f * (float)Math.PI;
1596 if (this.hollowSides != 4) 1596 if (this.hollowSides != 4)
1597 hollow *= 0.707f; 1597 hollow *= 0.707f;
1598 } 1598 }
1599 else if (this.sides > 4) 1599 else if (this.sides > 4)
1600 { 1600 {
1601 initialProfileRot = (float)Math.PI; 1601 initialProfileRot = (float)Math.PI;
1602 if (this.hollowSides == 4) 1602 if (this.hollowSides == 4)
1603 { 1603 {
1604 if (hollow > 0.7f) 1604 if (hollow > 0.7f)
1605 hollow = 0.7f; 1605 hollow = 0.7f;
1606 hollow /= 0.7f; 1606 hollow /= 0.7f;
1607 } 1607 }
1608 } 1608 }
1609 } 1609 }
1610 else 1610 else
1611 { 1611 {
1612 if (this.sides == 3) 1612 if (this.sides == 3)
1613 { 1613 {
1614 if (this.hollowSides == 4) 1614 if (this.hollowSides == 4)
1615 { 1615 {
1616 if (hollow > 0.7f) 1616 if (hollow > 0.7f)
1617 hollow = 0.7f; 1617 hollow = 0.7f;
1618 hollow *= 0.707f; 1618 hollow *= 0.707f;
1619 } 1619 }
1620 else hollow *= 0.5f; 1620 else hollow *= 0.5f;
1621 } 1621 }
1622 else if (this.sides == 4) 1622 else if (this.sides == 4)
1623 { 1623 {
1624 initialProfileRot = 1.25f * (float)Math.PI; 1624 initialProfileRot = 1.25f * (float)Math.PI;
1625 if (this.hollowSides != 4) 1625 if (this.hollowSides != 4)
1626 hollow *= 0.707f; 1626 hollow *= 0.707f;
1627 } 1627 }
1628 else if (this.sides == 24 && this.hollowSides == 4) 1628 else if (this.sides == 24 && this.hollowSides == 4)
1629 hollow *= 1.414f; 1629 hollow *= 1.414f;
1630 } 1630 }
1631 1631
1632 Profile profile = new Profile(this.sides, this.profileStart, this.profileEnd, hollow, this.hollowSides, true, calcVertexNormals); 1632 Profile profile = new Profile(this.sides, this.profileStart, this.profileEnd, hollow, this.hollowSides, true, calcVertexNormals);
1633 this.errorMessage = profile.errorMessage; 1633 this.errorMessage = profile.errorMessage;
1634 1634
1635 this.numPrimFaces = profile.numPrimFaces; 1635 this.numPrimFaces = profile.numPrimFaces;
1636 1636
1637 int cut1Vert = -1; 1637 int cut1Vert = -1;
1638 int cut2Vert = -1; 1638 int cut2Vert = -1;
1639 if (hasProfileCut) 1639 if (hasProfileCut)
1640 { 1640 {
1641 cut1Vert = hasHollow ? profile.coords.Count - 1 : 0; 1641 cut1Vert = hasHollow ? profile.coords.Count - 1 : 0;
1642 cut2Vert = hasHollow ? profile.numOuterVerts - 1 : profile.numOuterVerts; 1642 cut2Vert = hasHollow ? profile.numOuterVerts - 1 : profile.numOuterVerts;
1643 } 1643 }
1644 1644
1645 if (initialProfileRot != 0.0f) 1645 if (initialProfileRot != 0.0f)
1646 { 1646 {
1647 profile.AddRot(new Quat(new Coord(0.0f, 0.0f, 1.0f), initialProfileRot)); 1647 profile.AddRot(new Quat(new Coord(0.0f, 0.0f, 1.0f), initialProfileRot));
1648 if (viewerMode) 1648 if (viewerMode)
1649 profile.MakeFaceUVs(); 1649 profile.MakeFaceUVs();
1650 } 1650 }
1651 1651
1652 Coord lastCutNormal1 = new Coord(); 1652 Coord lastCutNormal1 = new Coord();
1653 Coord lastCutNormal2 = new Coord(); 1653 Coord lastCutNormal2 = new Coord();
1654 float lastV = 1.0f; 1654 float lastV = 1.0f;
1655 1655
1656 Path path = new Path(); 1656 Path path = new Path();
1657 path.twistBegin = twistBegin; 1657 path.twistBegin = twistBegin;
1658 path.twistEnd = twistEnd; 1658 path.twistEnd = twistEnd;
1659 path.topShearX = topShearX; 1659 path.topShearX = topShearX;
1660 path.topShearY = topShearY; 1660 path.topShearY = topShearY;
1661 path.pathCutBegin = pathCutBegin; 1661 path.pathCutBegin = pathCutBegin;
1662 path.pathCutEnd = pathCutEnd; 1662 path.pathCutEnd = pathCutEnd;
1663 path.dimpleBegin = dimpleBegin; 1663 path.dimpleBegin = dimpleBegin;
1664 path.dimpleEnd = dimpleEnd; 1664 path.dimpleEnd = dimpleEnd;
1665 path.skew = skew; 1665 path.skew = skew;
1666 path.holeSizeX = holeSizeX; 1666 path.holeSizeX = holeSizeX;
1667 path.holeSizeY = holeSizeY; 1667 path.holeSizeY = holeSizeY;
1668 path.taperX = taperX; 1668 path.taperX = taperX;
1669 path.taperY = taperY; 1669 path.taperY = taperY;
1670 path.radius = radius; 1670 path.radius = radius;
1671 path.revolutions = revolutions; 1671 path.revolutions = revolutions;
1672 path.stepsPerRevolution = stepsPerRevolution; 1672 path.stepsPerRevolution = stepsPerRevolution;
1673 1673
1674 path.Create(pathType, steps); 1674 path.Create(pathType, steps);
1675 1675
1676 bool needEndFaces = false; 1676 bool needEndFaces = false;
1677 if (pathType == PathType.Circular) 1677 if (pathType == PathType.Circular)
1678 { 1678 {
1679 needEndFaces = false; 1679 needEndFaces = false;
1680 if (this.pathCutBegin != 0.0f || this.pathCutEnd != 1.0f) 1680 if (this.pathCutBegin != 0.0f || this.pathCutEnd != 1.0f)
1681 needEndFaces = true; 1681 needEndFaces = true;
1682 else if (this.taperX != 0.0f || this.taperY != 0.0f) 1682 else if (this.taperX != 0.0f || this.taperY != 0.0f)
1683 needEndFaces = true; 1683 needEndFaces = true;
1684 else if (this.skew != 0.0f) 1684 else if (this.skew != 0.0f)
1685 needEndFaces = true; 1685 needEndFaces = true;
1686 else if (twistTotal != 0.0f) 1686 else if (twistTotal != 0.0f)
1687 needEndFaces = true; 1687 needEndFaces = true;
1688 else if (this.radius != 0.0f) 1688 else if (this.radius != 0.0f)
1689 needEndFaces = true; 1689 needEndFaces = true;
1690 } 1690 }
1691 else needEndFaces = true; 1691 else needEndFaces = true;
1692 1692
1693 for (int nodeIndex = 0; nodeIndex < path.pathNodes.Count; nodeIndex++) 1693 for (int nodeIndex = 0; nodeIndex < path.pathNodes.Count; nodeIndex++)
1694 { 1694 {
1695 PathNode node = path.pathNodes[nodeIndex]; 1695 PathNode node = path.pathNodes[nodeIndex];
1696 Profile newLayer = profile.Copy(); 1696 Profile newLayer = profile.Copy();
1697 newLayer.Scale(node.xScale, node.yScale); 1697 newLayer.Scale(node.xScale, node.yScale);
1698 1698
1699 newLayer.AddRot(node.rotation); 1699 newLayer.AddRot(node.rotation);
1700 newLayer.AddPos(node.position); 1700 newLayer.AddPos(node.position);
1701 1701
1702 if (needEndFaces && nodeIndex == 0) 1702 if (needEndFaces && nodeIndex == 0)
1703 { 1703 {
1704 newLayer.FlipNormals(); 1704 newLayer.FlipNormals();
1705 1705
1706 // add the top faces to the viewerFaces list here 1706 // add the top faces to the viewerFaces list here
1707 if (this.viewerMode) 1707 if (this.viewerMode)
1708 { 1708 {
1709 Coord faceNormal = newLayer.faceNormal; 1709 Coord faceNormal = newLayer.faceNormal;
1710 ViewerFace newViewerFace = new ViewerFace(profile.bottomFaceNumber); 1710 ViewerFace newViewerFace = new ViewerFace(profile.bottomFaceNumber);
1711 int numFaces = newLayer.faces.Count; 1711 int numFaces = newLayer.faces.Count;
1712 List<Face> faces = newLayer.faces; 1712 List<Face> faces = newLayer.faces;
1713 1713
1714 for (int i = 0; i < numFaces; i++) 1714 for (int i = 0; i < numFaces; i++)
1715 { 1715 {
1716 Face face = faces[i]; 1716 Face face = faces[i];
1717 newViewerFace.v1 = newLayer.coords[face.v1]; 1717 newViewerFace.v1 = newLayer.coords[face.v1];
1718 newViewerFace.v2 = newLayer.coords[face.v2]; 1718 newViewerFace.v2 = newLayer.coords[face.v2];
1719 newViewerFace.v3 = newLayer.coords[face.v3]; 1719 newViewerFace.v3 = newLayer.coords[face.v3];
1720 1720
1721 newViewerFace.coordIndex1 = face.v1; 1721 newViewerFace.coordIndex1 = face.v1;
1722 newViewerFace.coordIndex2 = face.v2; 1722 newViewerFace.coordIndex2 = face.v2;
1723 newViewerFace.coordIndex3 = face.v3; 1723 newViewerFace.coordIndex3 = face.v3;
1724 1724
1725 newViewerFace.n1 = faceNormal; 1725 newViewerFace.n1 = faceNormal;
1726 newViewerFace.n2 = faceNormal; 1726 newViewerFace.n2 = faceNormal;
1727 newViewerFace.n3 = faceNormal; 1727 newViewerFace.n3 = faceNormal;
1728 1728
1729 newViewerFace.uv1 = newLayer.faceUVs[face.v1]; 1729 newViewerFace.uv1 = newLayer.faceUVs[face.v1];
1730 newViewerFace.uv2 = newLayer.faceUVs[face.v2]; 1730 newViewerFace.uv2 = newLayer.faceUVs[face.v2];
1731 newViewerFace.uv3 = newLayer.faceUVs[face.v3]; 1731 newViewerFace.uv3 = newLayer.faceUVs[face.v3];
1732 1732
1733 this.viewerFaces.Add(newViewerFace); 1733 this.viewerFaces.Add(newViewerFace);
1734 } 1734 }
1735 } 1735 }
1736 } // if (nodeIndex == 0) 1736 } // if (nodeIndex == 0)
1737 1737
1738 // append this layer 1738 // append this layer
1739 1739
1740 int coordsLen = this.coords.Count; 1740 int coordsLen = this.coords.Count;
1741// int lastCoordsLen = coordsLen; 1741 newLayer.AddValue2FaceVertexIndices(coordsLen);
1742 newLayer.AddValue2FaceVertexIndices(coordsLen); 1742
1743 1743 this.coords.AddRange(newLayer.coords);
1744 this.coords.AddRange(newLayer.coords); 1744
1745 1745 if (this.calcVertexNormals)
1746 if (this.calcVertexNormals) 1746 {
1747 { 1747 newLayer.AddValue2FaceNormalIndices(this.normals.Count);
1748 newLayer.AddValue2FaceNormalIndices(this.normals.Count); 1748 this.normals.AddRange(newLayer.vertexNormals);
1749 this.normals.AddRange(newLayer.vertexNormals); 1749 }
1750 } 1750
1751 1751 if (node.percentOfPath < this.pathCutBegin + 0.01f || node.percentOfPath > this.pathCutEnd - 0.01f)
1752 if (node.percentOfPath < this.pathCutBegin + 0.01f || node.percentOfPath > this.pathCutEnd - 0.01f) 1752 this.faces.AddRange(newLayer.faces);
1753 this.faces.AddRange(newLayer.faces); 1753
1754 1754 // fill faces between layers
1755 // fill faces between layers 1755
1756 1756 int numVerts = newLayer.coords.Count;
1757 int numVerts = newLayer.coords.Count; 1757 Face newFace = new Face();
1758 Face newFace = new Face(); 1758
1759 1759 if (nodeIndex > 0)
1760 if (nodeIndex > 0) 1760 {
1761 { 1761 int startVert = coordsLen + 1;
1762 int startVert = coordsLen + 1; 1762 int endVert = this.coords.Count;
1763 int endVert = this.coords.Count; 1763
1764 1764 if (sides < 5 || this.hasProfileCut || hollow > 0.0f)
1765 if (sides < 5 || this.hasProfileCut || hollow > 0.0f) 1765 startVert--;
1766 startVert--; 1766
1767 1767 for (int i = startVert; i < endVert; i++)
1768 for (int i = startVert; i < endVert; i++) 1768 {
1769 { 1769 int iNext = i + 1;
1770 int iNext = i + 1; 1770 if (i == endVert - 1)
1771 if (i == endVert - 1) 1771 iNext = startVert;
1772 iNext = startVert; 1772
1773 1773 int whichVert = i - startVert;
1774 int whichVert = i - startVert; 1774
1775 1775 newFace.v1 = i;
1776 newFace.v1 = i; 1776 newFace.v2 = i - numVerts;
1777 newFace.v2 = i - numVerts; 1777 newFace.v3 = iNext - numVerts;
1778 newFace.v3 = iNext - numVerts; 1778 this.faces.Add(newFace);
1779 this.faces.Add(newFace); 1779
1780 1780 newFace.v2 = iNext - numVerts;
1781 newFace.v2 = iNext - numVerts; 1781 newFace.v3 = iNext;
1782 newFace.v3 = iNext; 1782 this.faces.Add(newFace);
1783 this.faces.Add(newFace); 1783
1784 1784 if (this.viewerMode)
1785 if (this.viewerMode) 1785 {
1786 { 1786 // add the side faces to the list of viewerFaces here
1787 // add the side faces to the list of viewerFaces here 1787
1788 1788 int primFaceNum = profile.faceNumbers[whichVert];
1789 int primFaceNum = profile.faceNumbers[whichVert]; 1789 if (!needEndFaces)
1790 if (!needEndFaces) 1790 primFaceNum -= 1;
1791 primFaceNum -= 1; 1791
1792 1792 ViewerFace newViewerFace1 = new ViewerFace(primFaceNum);
1793 ViewerFace newViewerFace1 = new ViewerFace(primFaceNum); 1793 ViewerFace newViewerFace2 = new ViewerFace(primFaceNum);
1794 ViewerFace newViewerFace2 = new ViewerFace(primFaceNum); 1794
1795 1795 float u1 = newLayer.us[whichVert];
1796 float u1 = newLayer.us[whichVert]; 1796 float u2 = 1.0f;
1797 float u2 = 1.0f; 1797 if (whichVert < newLayer.us.Count - 1)
1798 if (whichVert < newLayer.us.Count - 1) 1798 u2 = newLayer.us[whichVert + 1];
1799 u2 = newLayer.us[whichVert + 1]; 1799
1800 1800 if (whichVert == cut1Vert || whichVert == cut2Vert)
1801 if (whichVert == cut1Vert || whichVert == cut2Vert) 1801 {
1802 { 1802 u1 = 0.0f;
1803 u1 = 0.0f; 1803 u2 = 1.0f;
1804 u2 = 1.0f; 1804 }
1805 } 1805 else if (sides < 5)
1806 else if (sides < 5) 1806 {
1807 { 1807 if (whichVert < profile.numOuterVerts)
1808 if (whichVert < profile.numOuterVerts) 1808 { // boxes and prisms have one texture face per side of the prim, so the U values have to be scaled
1809 { // boxes and prisms have one texture face per side of the prim, so the U values have to be scaled 1809 // to reflect the entire texture width
1810 // to reflect the entire texture width 1810 u1 *= sides;
1811 u1 *= sides; 1811 u2 *= sides;
1812 u2 *= sides; 1812 u2 -= (int)u1;
1813 u2 -= (int)u1; 1813 u1 -= (int)u1;
1814 u1 -= (int)u1; 1814 if (u2 < 0.1f)
1815 if (u2 < 0.1f) 1815 u2 = 1.0f;
1816 u2 = 1.0f; 1816 }
1817 } 1817 else if (whichVert > profile.coords.Count - profile.numHollowVerts - 1)
1818 else if (whichVert > profile.coords.Count - profile.numHollowVerts - 1) 1818 {
1819 { 1819 u1 *= 2.0f;
1820 u1 *= 2.0f; 1820 u2 *= 2.0f;
1821 u2 *= 2.0f; 1821 }
1822 } 1822 }
1823 } 1823
1824 1824 newViewerFace1.uv1.U = u1;
1825 newViewerFace1.uv1.U = u1; 1825 newViewerFace1.uv2.U = u1;
1826 newViewerFace1.uv2.U = u1; 1826 newViewerFace1.uv3.U = u2;
1827 newViewerFace1.uv3.U = u2; 1827
1828 1828 newViewerFace1.uv1.V = 1.0f - node.percentOfPath;
1829 newViewerFace1.uv1.V = 1.0f - node.percentOfPath; 1829 newViewerFace1.uv2.V = lastV;
1830 newViewerFace1.uv2.V = lastV; 1830 newViewerFace1.uv3.V = lastV;
1831 newViewerFace1.uv3.V = lastV; 1831
1832 1832 newViewerFace2.uv1.U = u1;
1833 newViewerFace2.uv1.U = u1; 1833 newViewerFace2.uv2.U = u2;
1834 newViewerFace2.uv2.U = u2; 1834 newViewerFace2.uv3.U = u2;
1835 newViewerFace2.uv3.U = u2; 1835
1836 1836 newViewerFace2.uv1.V = 1.0f - node.percentOfPath;
1837 newViewerFace2.uv1.V = 1.0f - node.percentOfPath; 1837 newViewerFace2.uv2.V = lastV;
1838 newViewerFace2.uv2.V = lastV; 1838 newViewerFace2.uv3.V = 1.0f - node.percentOfPath;
1839 newViewerFace2.uv3.V = 1.0f - node.percentOfPath; 1839
1840 1840 newViewerFace1.v1 = this.coords[i];
1841 newViewerFace1.v1 = this.coords[i]; 1841 newViewerFace1.v2 = this.coords[i - numVerts];
1842 newViewerFace1.v2 = this.coords[i - numVerts]; 1842 newViewerFace1.v3 = this.coords[iNext - numVerts];
1843 newViewerFace1.v3 = this.coords[iNext - numVerts]; 1843
1844 1844 newViewerFace2.v1 = this.coords[i];
1845 newViewerFace2.v1 = this.coords[i]; 1845 newViewerFace2.v2 = this.coords[iNext - numVerts];
1846 newViewerFace2.v2 = this.coords[iNext - numVerts]; 1846 newViewerFace2.v3 = this.coords[iNext];
1847 newViewerFace2.v3 = this.coords[iNext]; 1847
1848 1848 newViewerFace1.coordIndex1 = i;
1849 newViewerFace1.coordIndex1 = i; 1849 newViewerFace1.coordIndex2 = i - numVerts;
1850 newViewerFace1.coordIndex2 = i - numVerts; 1850 newViewerFace1.coordIndex3 = iNext - numVerts;
1851 newViewerFace1.coordIndex3 = iNext - numVerts; 1851
1852 1852 newViewerFace2.coordIndex1 = i;
1853 newViewerFace2.coordIndex1 = i; 1853 newViewerFace2.coordIndex2 = iNext - numVerts;
1854 newViewerFace2.coordIndex2 = iNext - numVerts; 1854 newViewerFace2.coordIndex3 = iNext;
1855 newViewerFace2.coordIndex3 = iNext; 1855
1856 1856 // profile cut faces
1857 // profile cut faces 1857 if (whichVert == cut1Vert)
1858 if (whichVert == cut1Vert) 1858 {
1859 { 1859 newViewerFace1.n1 = newLayer.cutNormal1;
1860 newViewerFace1.n1 = newLayer.cutNormal1; 1860 newViewerFace1.n2 = newViewerFace1.n3 = lastCutNormal1;
1861 newViewerFace1.n2 = newViewerFace1.n3 = lastCutNormal1; 1861
1862 1862 newViewerFace2.n1 = newViewerFace2.n3 = newLayer.cutNormal1;
1863 newViewerFace2.n1 = newViewerFace2.n3 = newLayer.cutNormal1; 1863 newViewerFace2.n2 = lastCutNormal1;
1864 newViewerFace2.n2 = lastCutNormal1; 1864 }
1865 } 1865 else if (whichVert == cut2Vert)
1866 else if (whichVert == cut2Vert) 1866 {
1867 { 1867 newViewerFace1.n1 = newLayer.cutNormal2;
1868 newViewerFace1.n1 = newLayer.cutNormal2; 1868 newViewerFace1.n2 = newViewerFace1.n3 = lastCutNormal2;
1869 newViewerFace1.n2 = newViewerFace1.n3 = lastCutNormal2; 1869
1870 1870 newViewerFace2.n1 = newViewerFace2.n3 = newLayer.cutNormal2;
1871 newViewerFace2.n1 = newViewerFace2.n3 = newLayer.cutNormal2; 1871 newViewerFace2.n2 = lastCutNormal2;
1872 newViewerFace2.n2 = lastCutNormal2; 1872 }
1873 } 1873
1874 1874 else // outer and hollow faces
1875 else // outer and hollow faces 1875 {
1876 { 1876 if ((sides < 5 && whichVert < newLayer.numOuterVerts) || (hollowSides < 5 && whichVert >= newLayer.numOuterVerts))
1877 if ((sides < 5 && whichVert < newLayer.numOuterVerts) || (hollowSides < 5 && whichVert >= newLayer.numOuterVerts)) 1877 { // looks terrible when path is twisted... need vertex normals here
1878 { // looks terrible when path is twisted... need vertex normals here 1878 newViewerFace1.CalcSurfaceNormal();
1879 newViewerFace1.CalcSurfaceNormal(); 1879 newViewerFace2.CalcSurfaceNormal();
1880 newViewerFace2.CalcSurfaceNormal(); 1880 }
1881 } 1881 else
1882 else 1882 {
1883 { 1883 newViewerFace1.n1 = this.normals[i];
1884 newViewerFace1.n1 = this.normals[i]; 1884 newViewerFace1.n2 = this.normals[i - numVerts];
1885 newViewerFace1.n2 = this.normals[i - numVerts]; 1885 newViewerFace1.n3 = this.normals[iNext - numVerts];
1886 newViewerFace1.n3 = this.normals[iNext - numVerts]; 1886
1887 1887 newViewerFace2.n1 = this.normals[i];
1888 newViewerFace2.n1 = this.normals[i]; 1888 newViewerFace2.n2 = this.normals[iNext - numVerts];
1889 newViewerFace2.n2 = this.normals[iNext - numVerts]; 1889 newViewerFace2.n3 = this.normals[iNext];
1890 newViewerFace2.n3 = this.normals[iNext]; 1890 }
1891 } 1891 }
1892 } 1892
1893 1893 this.viewerFaces.Add(newViewerFace1);
1894 this.viewerFaces.Add(newViewerFace1); 1894 this.viewerFaces.Add(newViewerFace2);
1895 this.viewerFaces.Add(newViewerFace2); 1895
1896 1896 }
1897 } 1897 }
1898 } 1898 }
1899 } 1899
1900 1900 lastCutNormal1 = newLayer.cutNormal1;
1901 lastCutNormal1 = newLayer.cutNormal1; 1901 lastCutNormal2 = newLayer.cutNormal2;
1902 lastCutNormal2 = newLayer.cutNormal2; 1902 lastV = 1.0f - node.percentOfPath;
1903 lastV = 1.0f - node.percentOfPath; 1903
1904 1904 if (needEndFaces && nodeIndex == path.pathNodes.Count - 1 && viewerMode)
1905 if (needEndFaces && nodeIndex == path.pathNodes.Count - 1 && viewerMode) 1905 {
1906 { 1906 // add the top faces to the viewerFaces list here
1907 // add the top faces to the viewerFaces list here 1907 Coord faceNormal = newLayer.faceNormal;
1908 Coord faceNormal = newLayer.faceNormal; 1908 ViewerFace newViewerFace = new ViewerFace();
1909 ViewerFace newViewerFace = new ViewerFace(); 1909 newViewerFace.primFaceNumber = 0;
1910 newViewerFace.primFaceNumber = 0; 1910 int numFaces = newLayer.faces.Count;
1911 int numFaces = newLayer.faces.Count; 1911 List<Face> faces = newLayer.faces;
1912 List<Face> faces = newLayer.faces; 1912
1913 1913 for (int i = 0; i < numFaces; i++)
1914 for (int i = 0; i < numFaces; i++) 1914 {
1915 { 1915 Face face = faces[i];
1916 Face face = faces[i]; 1916 newViewerFace.v1 = newLayer.coords[face.v1 - coordsLen];
1917 newViewerFace.v1 = newLayer.coords[face.v1 - coordsLen]; 1917 newViewerFace.v2 = newLayer.coords[face.v2 - coordsLen];
1918 newViewerFace.v2 = newLayer.coords[face.v2 - coordsLen]; 1918 newViewerFace.v3 = newLayer.coords[face.v3 - coordsLen];
1919 newViewerFace.v3 = newLayer.coords[face.v3 - coordsLen]; 1919
1920 1920 newViewerFace.coordIndex1 = face.v1 - coordsLen;
1921 newViewerFace.coordIndex1 = face.v1 - coordsLen; 1921 newViewerFace.coordIndex2 = face.v2 - coordsLen;
1922 newViewerFace.coordIndex2 = face.v2 - coordsLen; 1922 newViewerFace.coordIndex3 = face.v3 - coordsLen;
1923 newViewerFace.coordIndex3 = face.v3 - coordsLen; 1923
1924 1924 newViewerFace.n1 = faceNormal;
1925 newViewerFace.n1 = faceNormal; 1925 newViewerFace.n2 = faceNormal;
1926 newViewerFace.n2 = faceNormal; 1926 newViewerFace.n3 = faceNormal;
1927 newViewerFace.n3 = faceNormal; 1927
1928 1928 newViewerFace.uv1 = newLayer.faceUVs[face.v1 - coordsLen];
1929 newViewerFace.uv1 = newLayer.faceUVs[face.v1 - coordsLen]; 1929 newViewerFace.uv2 = newLayer.faceUVs[face.v2 - coordsLen];
1930 newViewerFace.uv2 = newLayer.faceUVs[face.v2 - coordsLen]; 1930 newViewerFace.uv3 = newLayer.faceUVs[face.v3 - coordsLen];
1931 newViewerFace.uv3 = newLayer.faceUVs[face.v3 - coordsLen]; 1931
1932 1932 this.viewerFaces.Add(newViewerFace);
1933 this.viewerFaces.Add(newViewerFace); 1933 }
1934 } 1934 }
1935 } 1935
1936 1936
1937 1937 } // for (int nodeIndex = 0; nodeIndex < path.pathNodes.Count; nodeIndex++)
1938 } // for (int nodeIndex = 0; nodeIndex < path.pathNodes.Count; nodeIndex++) 1938
1939 1939 }
1940 } 1940
1941 1941
1942 1942 /// <summary>
1943 /// <summary> 1943 /// DEPRICATED - use Extrude(PathType.Linear) instead
1944 /// DEPRICATED - use Extrude(PathType.Linear) instead 1944 /// Extrudes a profile along a straight line path. Used for prim types box, cylinder, and prism.
1945 /// Extrudes a profile along a straight line path. Used for prim types box, cylinder, and prism. 1945 /// </summary>
1946 /// </summary> 1946 ///
1947 /// 1947 public void ExtrudeLinear()
1948 public void ExtrudeLinear() 1948 {
1949 { 1949 this.Extrude(PathType.Linear);
1950 this.Extrude(PathType.Linear); 1950 }
1951 } 1951
1952 1952
1953 1953 /// <summary>
1954 /// <summary> 1954 /// DEPRICATED - use Extrude(PathType.Circular) instead
1955 /// DEPRICATED - use Extrude(PathType.Circular) instead 1955 /// Extrude a profile into a circular path prim mesh. Used for prim types torus, tube, and ring.
1956 /// Extrude a profile into a circular path prim mesh. Used for prim types torus, tube, and ring. 1956 /// </summary>
1957 /// </summary> 1957 ///
1958 /// 1958 public void ExtrudeCircular()
1959 public void ExtrudeCircular() 1959 {
1960 { 1960 this.Extrude(PathType.Circular);
1961 this.Extrude(PathType.Circular); 1961 }
1962 } 1962
1963 1963
1964 1964 private Coord SurfaceNormal(Coord c1, Coord c2, Coord c3)
1965 private Coord SurfaceNormal(Coord c1, Coord c2, Coord c3) 1965 {
1966 { 1966 Coord edge1 = new Coord(c2.X - c1.X, c2.Y - c1.Y, c2.Z - c1.Z);
1967 Coord edge1 = new Coord(c2.X - c1.X, c2.Y - c1.Y, c2.Z - c1.Z); 1967 Coord edge2 = new Coord(c3.X - c1.X, c3.Y - c1.Y, c3.Z - c1.Z);
1968 Coord edge2 = new Coord(c3.X - c1.X, c3.Y - c1.Y, c3.Z - c1.Z); 1968
1969 1969 Coord normal = Coord.Cross(edge1, edge2);
1970 Coord normal = Coord.Cross(edge1, edge2); 1970
1971 1971 normal.Normalize();
1972 normal.Normalize(); 1972
1973 1973 return normal;
1974 return normal; 1974 }
1975 } 1975
1976 1976 private Coord SurfaceNormal(Face face)
1977 private Coord SurfaceNormal(Face face) 1977 {
1978 { 1978 return SurfaceNormal(this.coords[face.v1], this.coords[face.v2], this.coords[face.v3]);
1979 return SurfaceNormal(this.coords[face.v1], this.coords[face.v2], this.coords[face.v3]); 1979 }
1980 } 1980
1981 1981 /// <summary>
1982 /// <summary> 1982 /// Calculate the surface normal for a face in the list of faces
1983 /// Calculate the surface normal for a face in the list of faces 1983 /// </summary>
1984 /// </summary> 1984 /// <param name="faceIndex"></param>
1985 /// <param name="faceIndex"></param> 1985 /// <returns></returns>
1986 /// <returns></returns> 1986 public Coord SurfaceNormal(int faceIndex)
1987 public Coord SurfaceNormal(int faceIndex) 1987 {
1988 { 1988 int numFaces = this.faces.Count;
1989 int numFaces = this.faces.Count; 1989 if (faceIndex < 0 || faceIndex >= numFaces)
1990 if (faceIndex < 0 || faceIndex >= numFaces) 1990 throw new Exception("faceIndex out of range");
1991 throw new Exception("faceIndex out of range"); 1991
1992 1992 return SurfaceNormal(this.faces[faceIndex]);
1993 return SurfaceNormal(this.faces[faceIndex]); 1993 }
1994 } 1994
1995 1995 /// <summary>
1996 /// <summary> 1996 /// Duplicates a PrimMesh object. All object properties are copied by value, including lists.
1997 /// Duplicates a PrimMesh object. All object properties are copied by value, including lists. 1997 /// </summary>
1998 /// </summary> 1998 /// <returns></returns>
1999 /// <returns></returns> 1999 public PrimMesh Copy()
2000 public PrimMesh Copy() 2000 {
2001 { 2001 PrimMesh copy = new PrimMesh(this.sides, this.profileStart, this.profileEnd, this.hollow, this.hollowSides);
2002 PrimMesh copy = new PrimMesh(this.sides, this.profileStart, this.profileEnd, this.hollow, this.hollowSides); 2002 copy.twistBegin = this.twistBegin;
2003 copy.twistBegin = this.twistBegin; 2003 copy.twistEnd = this.twistEnd;
2004 copy.twistEnd = this.twistEnd; 2004 copy.topShearX = this.topShearX;
2005 copy.topShearX = this.topShearX; 2005 copy.topShearY = this.topShearY;
2006 copy.topShearY = this.topShearY; 2006 copy.pathCutBegin = this.pathCutBegin;
2007 copy.pathCutBegin = this.pathCutBegin; 2007 copy.pathCutEnd = this.pathCutEnd;
2008 copy.pathCutEnd = this.pathCutEnd; 2008 copy.dimpleBegin = this.dimpleBegin;
2009 copy.dimpleBegin = this.dimpleBegin; 2009 copy.dimpleEnd = this.dimpleEnd;
2010 copy.dimpleEnd = this.dimpleEnd; 2010 copy.skew = this.skew;
2011 copy.skew = this.skew; 2011 copy.holeSizeX = this.holeSizeX;
2012 copy.holeSizeX = this.holeSizeX; 2012 copy.holeSizeY = this.holeSizeY;
2013 copy.holeSizeY = this.holeSizeY; 2013 copy.taperX = this.taperX;
2014 copy.taperX = this.taperX; 2014 copy.taperY = this.taperY;
2015 copy.taperY = this.taperY; 2015 copy.radius = this.radius;
2016 copy.radius = this.radius; 2016 copy.revolutions = this.revolutions;
2017 copy.revolutions = this.revolutions; 2017 copy.stepsPerRevolution = this.stepsPerRevolution;
2018 copy.stepsPerRevolution = this.stepsPerRevolution; 2018 copy.calcVertexNormals = this.calcVertexNormals;
2019 copy.calcVertexNormals = this.calcVertexNormals; 2019 copy.normalsProcessed = this.normalsProcessed;
2020 copy.normalsProcessed = this.normalsProcessed; 2020 copy.viewerMode = this.viewerMode;
2021 copy.viewerMode = this.viewerMode; 2021 copy.numPrimFaces = this.numPrimFaces;
2022 copy.numPrimFaces = this.numPrimFaces; 2022 copy.errorMessage = this.errorMessage;
2023 copy.errorMessage = this.errorMessage; 2023
2024 2024 copy.coords = new List<Coord>(this.coords);
2025 copy.coords = new List<Coord>(this.coords); 2025 copy.faces = new List<Face>(this.faces);
2026 copy.faces = new List<Face>(this.faces); 2026 copy.viewerFaces = new List<ViewerFace>(this.viewerFaces);
2027 copy.viewerFaces = new List<ViewerFace>(this.viewerFaces); 2027 copy.normals = new List<Coord>(this.normals);
2028 copy.normals = new List<Coord>(this.normals); 2028
2029 2029 return copy;
2030 return copy; 2030 }
2031 } 2031
2032 2032 /// <summary>
2033 /// <summary> 2033 /// Calculate surface normals for all of the faces in the list of faces in this mesh
2034 /// Calculate surface normals for all of the faces in the list of faces in this mesh 2034 /// </summary>
2035 /// </summary> 2035 public void CalcNormals()
2036 public void CalcNormals() 2036 {
2037 { 2037 if (normalsProcessed)
2038 if (normalsProcessed) 2038 return;
2039 return; 2039
2040 2040 normalsProcessed = true;
2041 normalsProcessed = true; 2041
2042 2042 int numFaces = faces.Count;
2043 int numFaces = faces.Count; 2043
2044 2044 if (!this.calcVertexNormals)
2045 if (!this.calcVertexNormals) 2045 this.normals = new List<Coord>();
2046 this.normals = new List<Coord>(); 2046
2047 2047 for (int i = 0; i < numFaces; i++)
2048 for (int i = 0; i < numFaces; i++) 2048 {
2049 { 2049 Face face = faces[i];
2050 Face face = faces[i]; 2050
2051 2051 this.normals.Add(SurfaceNormal(i).Normalize());
2052 this.normals.Add(SurfaceNormal(i).Normalize()); 2052
2053 2053 int normIndex = normals.Count - 1;
2054 int normIndex = normals.Count - 1; 2054 face.n1 = normIndex;
2055 face.n1 = normIndex; 2055 face.n2 = normIndex;
2056 face.n2 = normIndex; 2056 face.n3 = normIndex;
2057 face.n3 = normIndex; 2057
2058 2058 this.faces[i] = face;
2059 this.faces[i] = face; 2059 }
2060 } 2060 }
2061 } 2061
2062 2062 /// <summary>
2063 /// <summary> 2063 /// Adds a value to each XYZ vertex coordinate in the mesh
2064 /// Adds a value to each XYZ vertex coordinate in the mesh 2064 /// </summary>
2065 /// </summary> 2065 /// <param name="x"></param>
2066 /// <param name="x"></param> 2066 /// <param name="y"></param>
2067 /// <param name="y"></param> 2067 /// <param name="z"></param>
2068 /// <param name="z"></param> 2068 public void AddPos(float x, float y, float z)
2069 public void AddPos(float x, float y, float z) 2069 {
2070 { 2070 int i;
2071 int i; 2071 int numVerts = this.coords.Count;
2072 int numVerts = this.coords.Count; 2072 Coord vert;
2073 Coord vert; 2073
2074 2074 for (i = 0; i < numVerts; i++)
2075 for (i = 0; i < numVerts; i++) 2075 {
2076 { 2076 vert = this.coords[i];
2077 vert = this.coords[i]; 2077 vert.X += x;
2078 vert.X += x; 2078 vert.Y += y;
2079 vert.Y += y; 2079 vert.Z += z;
2080 vert.Z += z; 2080 this.coords[i] = vert;
2081 this.coords[i] = vert; 2081 }
2082 } 2082
2083 2083 if (this.viewerFaces != null)
2084 if (this.viewerFaces != null) 2084 {
2085 { 2085 int numViewerFaces = this.viewerFaces.Count;
2086 int numViewerFaces = this.viewerFaces.Count; 2086
2087 2087 for (i = 0; i < numViewerFaces; i++)
2088 for (i = 0; i < numViewerFaces; i++) 2088 {
2089 { 2089 ViewerFace v = this.viewerFaces[i];
2090 ViewerFace v = this.viewerFaces[i]; 2090 v.AddPos(x, y, z);
2091 v.AddPos(x, y, z); 2091 this.viewerFaces[i] = v;
2092 this.viewerFaces[i] = v; 2092 }
2093 } 2093 }
2094 } 2094 }
2095 } 2095
2096 2096 /// <summary>
2097 /// <summary> 2097 /// Rotates the mesh
2098 /// Rotates the mesh 2098 /// </summary>
2099 /// </summary> 2099 /// <param name="q"></param>
2100 /// <param name="q"></param> 2100 public void AddRot(Quat q)
2101 public void AddRot(Quat q) 2101 {
2102 { 2102 int i;
2103 int i; 2103 int numVerts = this.coords.Count;
2104 int numVerts = this.coords.Count; 2104
2105 2105 for (i = 0; i < numVerts; i++)
2106 for (i = 0; i < numVerts; i++) 2106 this.coords[i] *= q;
2107 this.coords[i] *= q; 2107
2108 2108 if (this.normals != null)
2109 if (this.normals != null) 2109 {
2110 { 2110 int numNormals = this.normals.Count;
2111 int numNormals = this.normals.Count; 2111 for (i = 0; i < numNormals; i++)
2112 for (i = 0; i < numNormals; i++) 2112 this.normals[i] *= q;
2113 this.normals[i] *= q; 2113 }
2114 } 2114
2115 2115 if (this.viewerFaces != null)
2116 if (this.viewerFaces != null) 2116 {
2117 { 2117 int numViewerFaces = this.viewerFaces.Count;
2118 int numViewerFaces = this.viewerFaces.Count; 2118
2119 2119 for (i = 0; i < numViewerFaces; i++)
2120 for (i = 0; i < numViewerFaces; i++) 2120 {
2121 { 2121 ViewerFace v = this.viewerFaces[i];
2122 ViewerFace v = this.viewerFaces[i]; 2122 v.v1 *= q;
2123 v.v1 *= q; 2123 v.v2 *= q;
2124 v.v2 *= q; 2124 v.v3 *= q;
2125 v.v3 *= q; 2125
2126 2126 v.n1 *= q;
2127 v.n1 *= q; 2127 v.n2 *= q;
2128 v.n2 *= q; 2128 v.n3 *= q;
2129 v.n3 *= q; 2129 this.viewerFaces[i] = v;
2130 this.viewerFaces[i] = v; 2130 }
2131 } 2131 }
2132 } 2132 }
2133 } 2133
2134 2134#if VERTEX_INDEXER
2135#if VERTEX_INDEXER 2135 public VertexIndexer GetVertexIndexer()
2136 public VertexIndexer GetVertexIndexer() 2136 {
2137 { 2137 if (this.viewerMode && this.viewerFaces.Count > 0)
2138 if (this.viewerMode && this.viewerFaces.Count > 0) 2138 return new VertexIndexer(this);
2139 return new VertexIndexer(this); 2139 return null;
2140 return null; 2140 }
2141 } 2141#endif
2142#endif 2142
2143 2143 /// <summary>
2144 /// <summary> 2144 /// Scales the mesh
2145 /// Scales the mesh 2145 /// </summary>
2146 /// </summary> 2146 /// <param name="x"></param>
2147 /// <param name="x"></param> 2147 /// <param name="y"></param>
2148 /// <param name="y"></param> 2148 /// <param name="z"></param>
2149 /// <param name="z"></param> 2149 public void Scale(float x, float y, float z)
2150 public void Scale(float x, float y, float z) 2150 {
2151 { 2151 int i;
2152 int i; 2152 int numVerts = this.coords.Count;
2153 int numVerts = this.coords.Count; 2153 //Coord vert;
2154 //Coord vert; 2154
2155 2155 Coord m = new Coord(x, y, z);
2156 Coord m = new Coord(x, y, z); 2156 for (i = 0; i < numVerts; i++)
2157 for (i = 0; i < numVerts; i++) 2157 this.coords[i] *= m;
2158 this.coords[i] *= m; 2158
2159 2159 if (this.viewerFaces != null)
2160 if (this.viewerFaces != null) 2160 {
2161 { 2161 int numViewerFaces = this.viewerFaces.Count;
2162 int numViewerFaces = this.viewerFaces.Count; 2162 for (i = 0; i < numViewerFaces; i++)
2163 for (i = 0; i < numViewerFaces; i++) 2163 {
2164 { 2164 ViewerFace v = this.viewerFaces[i];
2165 ViewerFace v = this.viewerFaces[i]; 2165 v.v1 *= m;
2166 v.v1 *= m; 2166 v.v2 *= m;
2167 v.v2 *= m; 2167 v.v3 *= m;
2168 v.v3 *= m; 2168 this.viewerFaces[i] = v;
2169 this.viewerFaces[i] = v; 2169 }
2170 } 2170
2171 2171 }
2172 } 2172
2173 2173 }
2174 } 2174
2175 2175 /// <summary>
2176 /// <summary> 2176 /// Dumps the mesh to a Blender compatible "Raw" format file
2177 /// Dumps the mesh to a Blender compatible "Raw" format file 2177 /// </summary>
2178 /// </summary> 2178 /// <param name="path"></param>
2179 /// <param name="path"></param> 2179 /// <param name="name"></param>
2180 /// <param name="name"></param> 2180 /// <param name="title"></param>
2181 /// <param name="title"></param> 2181 public void DumpRaw(String path, String name, String title)
2182 public void DumpRaw(String path, String name, String title) 2182 {
2183 { 2183 if (path == null)
2184 if (path == null) 2184 return;
2185 return; 2185 String fileName = name + "_" + title + ".raw";
2186 String fileName = name + "_" + title + ".raw"; 2186 String completePath = System.IO.Path.Combine(path, fileName);
2187 String completePath = System.IO.Path.Combine(path, fileName); 2187 StreamWriter sw = new StreamWriter(completePath);
2188 StreamWriter sw = new StreamWriter(completePath); 2188
2189 2189 for (int i = 0; i < this.faces.Count; i++)
2190 for (int i = 0; i < this.faces.Count; i++) 2190 {
2191 { 2191 string s = this.coords[this.faces[i].v1].ToString();
2192 string s = this.coords[this.faces[i].v1].ToString(); 2192 s += " " + this.coords[this.faces[i].v2].ToString();
2193 s += " " + this.coords[this.faces[i].v2].ToString(); 2193 s += " " + this.coords[this.faces[i].v3].ToString();
2194 s += " " + this.coords[this.faces[i].v3].ToString(); 2194
2195 2195 sw.WriteLine(s);
2196 sw.WriteLine(s); 2196 }
2197 } 2197
2198 2198 sw.Close();
2199 sw.Close(); 2199 }
2200 } 2200 }
2201 } 2201}
2202}
diff --git a/OpenSim/Region/Physics/Meshing/SculptMesh.cs b/OpenSim/Region/Physics/Meshing/SculptMesh.cs
index 4dc6e2e..11b6cd4 100644
--- a/OpenSim/Region/Physics/Meshing/SculptMesh.cs
+++ b/OpenSim/Region/Physics/Meshing/SculptMesh.cs
@@ -1,627 +1,645 @@
1/* 1/*
2 * Copyright (c) Contributors 2 * Copyright (c) Contributors
3 * See CONTRIBUTORS.TXT for a full list of copyright holders. 3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 * 4 *
5 * Redistribution and use in source and binary forms, with or without 5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met: 6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright 7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer. 8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright 9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the 10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution. 11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the 12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products 13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission. 14 * derived from this software without specific prior written permission.
15 * 15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY 16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY 19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27 27
28// to build without references to System.Drawing, comment this out 28// to build without references to System.Drawing, comment this out
29#define SYSTEM_DRAWING 29#define SYSTEM_DRAWING
30 30
31using System; 31using System;
32using System.Collections.Generic; 32using System.Collections.Generic;
33using System.Text; 33using System.Text;
34using System.IO; 34using System.IO;
35 35
36#if SYSTEM_DRAWING 36#if SYSTEM_DRAWING
37using System.Drawing; 37using System.Drawing;
38using System.Drawing.Imaging; 38using System.Drawing.Imaging;
39#endif 39#endif
40 40
41namespace PrimMesher 41namespace PrimMesher
42{ 42{
43 43
44 public class SculptMesh 44 public class SculptMesh
45 { 45 {
46 public List<Coord> coords; 46 public List<Coord> coords;
47 public List<Face> faces; 47 public List<Face> faces;
48 48
49 public List<ViewerFace> viewerFaces; 49 public List<ViewerFace> viewerFaces;
50 public List<Coord> normals; 50 public List<Coord> normals;
51 public List<UVCoord> uvs; 51 public List<UVCoord> uvs;
52 52
53 public enum SculptType { sphere = 1, torus = 2, plane = 3, cylinder = 4 }; 53 public enum SculptType { sphere = 1, torus = 2, plane = 3, cylinder = 4 };
54 54
55#if SYSTEM_DRAWING 55#if SYSTEM_DRAWING
56 // private Bitmap ScaleImage(Bitmap srcImage, float scale) 56 private Bitmap ScaleImage(Bitmap srcImage, float scale, bool removeAlpha)
57 // { 57 {
58 // int sourceWidth = srcImage.Width; 58 int sourceWidth = srcImage.Width;
59 // int sourceHeight = srcImage.Height; 59 int sourceHeight = srcImage.Height;
60 // int sourceX = 0; 60 int sourceX = 0;
61 // int sourceY = 0; 61 int sourceY = 0;
62 62
63 // int destX = 0; 63 int destX = 0;
64 // int destY = 0; 64 int destY = 0;
65 // int destWidth = (int)(srcImage.Width * scale); 65 int destWidth = (int)(srcImage.Width * scale);
66 // int destHeight = (int)(srcImage.Height * scale); 66 int destHeight = (int)(srcImage.Height * scale);
67 67
68 // if (srcImage.PixelFormat == PixelFormat.Format32bppArgb) 68 Bitmap scaledImage;
69 // for (int y = 0; y < srcImage.Height; y++) 69
70 // for (int x = 0; x < srcImage.Width; x++) 70 if (removeAlpha)
71 // { 71 {
72 // Color c = srcImage.GetPixel(x, y); 72 if (srcImage.PixelFormat == PixelFormat.Format32bppArgb)
73 // srcImage.SetPixel(x, y, Color.FromArgb(255, c.R, c.G, c.B)); 73 for (int y = 0; y < srcImage.Height; y++)
74 // } 74 for (int x = 0; x < srcImage.Width; x++)
75 75 {
76 // Bitmap scaledImage = new Bitmap(destWidth, destHeight, 76 Color c = srcImage.GetPixel(x, y);
77 // PixelFormat.Format24bppRgb); 77 srcImage.SetPixel(x, y, Color.FromArgb(255, c.R, c.G, c.B));
78 78 }
79 // scaledImage.SetResolution(96.0f, 96.0f); 79
80 80 scaledImage = new Bitmap(destWidth, destHeight,
81 // Graphics grPhoto = Graphics.FromImage(scaledImage); 81 PixelFormat.Format24bppRgb);
82 // grPhoto.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.Low; 82 }
83 83 else
84 // grPhoto.DrawImage(srcImage, 84 scaledImage = new Bitmap(srcImage, destWidth, destHeight);
85 // new Rectangle(destX, destY, destWidth, destHeight), 85
86 // new Rectangle(sourceX, sourceY, sourceWidth, sourceHeight), 86 scaledImage.SetResolution(96.0f, 96.0f);
87 // GraphicsUnit.Pixel); 87
88 88 Graphics grPhoto = Graphics.FromImage(scaledImage);
89 // grPhoto.Dispose(); 89 grPhoto.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.Low;
90 // return scaledImage; 90
91 // } 91 grPhoto.DrawImage(srcImage,
92 92 new Rectangle(destX, destY, destWidth, destHeight),
93 93 new Rectangle(sourceX, sourceY, sourceWidth, sourceHeight),
94 public SculptMesh SculptMeshFromFile(string fileName, SculptType sculptType, int lod, bool viewerMode) 94 GraphicsUnit.Pixel);
95 { 95
96 Bitmap bitmap = (Bitmap)Bitmap.FromFile(fileName); 96 grPhoto.Dispose();
97 SculptMesh sculptMesh = new SculptMesh(bitmap, sculptType, lod, viewerMode); 97 return scaledImage;
98 bitmap.Dispose(); 98 }
99 return sculptMesh; 99
100 } 100
101 101 public SculptMesh SculptMeshFromFile(string fileName, SculptType sculptType, int lod, bool viewerMode)
102 public SculptMesh(string fileName, int sculptType, int lod, int viewerMode, int mirror, int invert) 102 {
103 { 103 Bitmap bitmap = (Bitmap)Bitmap.FromFile(fileName);
104 Bitmap bitmap = (Bitmap)Bitmap.FromFile(fileName); 104 SculptMesh sculptMesh = new SculptMesh(bitmap, sculptType, lod, viewerMode);
105 _SculptMesh(bitmap, (SculptType)sculptType, lod, viewerMode != 0, mirror != 0, invert != 0); 105 bitmap.Dispose();
106 bitmap.Dispose(); 106 return sculptMesh;
107 } 107 }
108#endif 108
109 109 public SculptMesh(string fileName, int sculptType, int lod, int viewerMode, int mirror, int invert)
110 /// <summary> 110 {
111 /// ** Experimental ** May disappear from future versions ** not recommeneded for use in applications 111 Bitmap bitmap = (Bitmap)Bitmap.FromFile(fileName);
112 /// Construct a sculpt mesh from a 2D array of floats 112 _SculptMesh(bitmap, (SculptType)sculptType, lod, viewerMode != 0, mirror != 0, invert != 0);
113 /// </summary> 113 bitmap.Dispose();
114 /// <param name="zMap"></param> 114 }
115 /// <param name="xBegin"></param> 115#endif
116 /// <param name="xEnd"></param> 116
117 /// <param name="yBegin"></param> 117 /// <summary>
118 /// <param name="yEnd"></param> 118 /// ** Experimental ** May disappear from future versions ** not recommeneded for use in applications
119 /// <param name="viewerMode"></param> 119 /// Construct a sculpt mesh from a 2D array of floats
120 public SculptMesh(float[,] zMap, float xBegin, float xEnd, float yBegin, float yEnd, bool viewerMode) 120 /// </summary>
121 { 121 /// <param name="zMap"></param>
122 float xStep, yStep; 122 /// <param name="xBegin"></param>
123 float uStep, vStep; 123 /// <param name="xEnd"></param>
124 124 /// <param name="yBegin"></param>
125 int numYElements = zMap.GetLength(0); 125 /// <param name="yEnd"></param>
126 int numXElements = zMap.GetLength(1); 126 /// <param name="viewerMode"></param>
127 127 public SculptMesh(float[,] zMap, float xBegin, float xEnd, float yBegin, float yEnd, bool viewerMode)
128 try 128 {
129 { 129 float xStep, yStep;
130 xStep = (xEnd - xBegin) / (float)(numXElements - 1); 130 float uStep, vStep;
131 yStep = (yEnd - yBegin) / (float)(numYElements - 1); 131
132 132 int numYElements = zMap.GetLength(0);
133 uStep = 1.0f / (numXElements - 1); 133 int numXElements = zMap.GetLength(1);
134 vStep = 1.0f / (numYElements - 1); 134
135 } 135 try
136 catch (DivideByZeroException) 136 {
137 { 137 xStep = (xEnd - xBegin) / (float)(numXElements - 1);
138 return; 138 yStep = (yEnd - yBegin) / (float)(numYElements - 1);
139 } 139
140 140 uStep = 1.0f / (numXElements - 1);
141 coords = new List<Coord>(); 141 vStep = 1.0f / (numYElements - 1);
142 faces = new List<Face>(); 142 }
143 normals = new List<Coord>(); 143 catch (DivideByZeroException)
144 uvs = new List<UVCoord>(); 144 {
145 145 return;
146 viewerFaces = new List<ViewerFace>(); 146 }
147 147
148 int p1, p2, p3, p4; 148 coords = new List<Coord>();
149 149 faces = new List<Face>();
150 int x, y; 150 normals = new List<Coord>();
151 int xStart = 0, yStart = 0; 151 uvs = new List<UVCoord>();
152 152
153 for (y = yStart; y < numYElements; y++) 153 viewerFaces = new List<ViewerFace>();
154 { 154
155 int rowOffset = y * numXElements; 155 int p1, p2, p3, p4;
156 156
157 for (x = xStart; x < numXElements; x++) 157 int x, y;
158 { 158 int xStart = 0, yStart = 0;
159 /* 159
160 * p1-----p2 160 for (y = yStart; y < numYElements; y++)
161 * | \ f2 | 161 {
162 * | \ | 162 int rowOffset = y * numXElements;
163 * | f1 \| 163
164 * p3-----p4 164 for (x = xStart; x < numXElements; x++)
165 */ 165 {
166 166 /*
167 p4 = rowOffset + x; 167 * p1-----p2
168 p3 = p4 - 1; 168 * | \ f2 |
169 169 * | \ |
170 p2 = p4 - numXElements; 170 * | f1 \|
171 p1 = p3 - numXElements; 171 * p3-----p4
172 172 */
173 Coord c = new Coord(xBegin + x * xStep, yBegin + y * yStep, zMap[y, x]); 173
174 this.coords.Add(c); 174 p4 = rowOffset + x;
175 if (viewerMode) 175 p3 = p4 - 1;
176 { 176
177 this.normals.Add(new Coord()); 177 p2 = p4 - numXElements;
178 this.uvs.Add(new UVCoord(uStep * x, 1.0f - vStep * y)); 178 p1 = p3 - numXElements;
179 } 179
180 180 Coord c = new Coord(xBegin + x * xStep, yBegin + y * yStep, zMap[y, x]);
181 if (y > 0 && x > 0) 181 this.coords.Add(c);
182 { 182 if (viewerMode)
183 Face f1, f2; 183 {
184 184 this.normals.Add(new Coord());
185 if (viewerMode) 185 this.uvs.Add(new UVCoord(uStep * x, 1.0f - vStep * y));
186 { 186 }
187 f1 = new Face(p1, p4, p3, p1, p4, p3); 187
188 f1.uv1 = p1; 188 if (y > 0 && x > 0)
189 f1.uv2 = p4; 189 {
190 f1.uv3 = p3; 190 Face f1, f2;
191 191
192 f2 = new Face(p1, p2, p4, p1, p2, p4); 192 if (viewerMode)
193 f2.uv1 = p1; 193 {
194 f2.uv2 = p2; 194 f1 = new Face(p1, p4, p3, p1, p4, p3);
195 f2.uv3 = p4; 195 f1.uv1 = p1;
196 } 196 f1.uv2 = p4;
197 else 197 f1.uv3 = p3;
198 { 198
199 f1 = new Face(p1, p4, p3); 199 f2 = new Face(p1, p2, p4, p1, p2, p4);
200 f2 = new Face(p1, p2, p4); 200 f2.uv1 = p1;
201 } 201 f2.uv2 = p2;
202 202 f2.uv3 = p4;
203 this.faces.Add(f1); 203 }
204 this.faces.Add(f2); 204 else
205 } 205 {
206 } 206 f1 = new Face(p1, p4, p3);
207 } 207 f2 = new Face(p1, p2, p4);
208 208 }
209 if (viewerMode) 209
210 calcVertexNormals(SculptType.plane, numXElements, numYElements); 210 this.faces.Add(f1);
211 } 211 this.faces.Add(f2);
212 212 }
213#if SYSTEM_DRAWING 213 }
214 public SculptMesh(Bitmap sculptBitmap, SculptType sculptType, int lod, bool viewerMode) 214 }
215 { 215
216 _SculptMesh(sculptBitmap, sculptType, lod, viewerMode, false, false); 216 if (viewerMode)
217 } 217 calcVertexNormals(SculptType.plane, numXElements, numYElements);
218 218 }
219 public SculptMesh(Bitmap sculptBitmap, SculptType sculptType, int lod, bool viewerMode, bool mirror, bool invert) 219
220 { 220#if SYSTEM_DRAWING
221 _SculptMesh(sculptBitmap, sculptType, lod, viewerMode, mirror, invert); 221 public SculptMesh(Bitmap sculptBitmap, SculptType sculptType, int lod, bool viewerMode)
222 } 222 {
223#endif 223 _SculptMesh(sculptBitmap, sculptType, lod, viewerMode, false, false);
224 224 }
225 public SculptMesh(List<List<Coord>> rows, SculptType sculptType, bool viewerMode, bool mirror, bool invert) 225
226 { 226 public SculptMesh(Bitmap sculptBitmap, SculptType sculptType, int lod, bool viewerMode, bool mirror, bool invert)
227 _SculptMesh(rows, sculptType, viewerMode, mirror, invert); 227 {
228 } 228 _SculptMesh(sculptBitmap, sculptType, lod, viewerMode, mirror, invert);
229 229 }
230#if SYSTEM_DRAWING 230#endif
231 /// <summary> 231
232 /// converts a bitmap to a list of lists of coords, while scaling the image. 232 public SculptMesh(List<List<Coord>> rows, SculptType sculptType, bool viewerMode, bool mirror, bool invert)
233 /// the scaling is done in floating point so as to allow for reduced vertex position 233 {
234 /// quantization as the position will be averaged between pixel values. this routine will 234 _SculptMesh(rows, sculptType, viewerMode, mirror, invert);
235 /// likely fail if the bitmap width and height are not powers of 2. 235 }
236 /// </summary> 236
237 /// <param name="bitmap"></param> 237#if SYSTEM_DRAWING
238 /// <param name="scale"></param> 238 /// <summary>
239 /// <param name="mirror"></param> 239 /// converts a bitmap to a list of lists of coords, while scaling the image.
240 /// <returns></returns> 240 /// the scaling is done in floating point so as to allow for reduced vertex position
241 private List<List<Coord>> bitmap2Coords(Bitmap bitmap, int scale, bool mirror) 241 /// quantization as the position will be averaged between pixel values. this routine will
242 { 242 /// likely fail if the bitmap width and height are not powers of 2.
243 int numRows = bitmap.Height / scale; 243 /// </summary>
244 int numCols = bitmap.Width / scale; 244 /// <param name="bitmap"></param>
245 List<List<Coord>> rows = new List<List<Coord>>(numRows); 245 /// <param name="scale"></param>
246 246 /// <param name="mirror"></param>
247 float pixScale = 1.0f / (scale * scale); 247 /// <returns></returns>
248 pixScale /= 255; 248 private List<List<Coord>> bitmap2Coords(Bitmap bitmap, int scale, bool mirror)
249 249 {
250 int imageX, imageY = 0; 250 int numRows = bitmap.Height / scale;
251 251 int numCols = bitmap.Width / scale;
252 int rowNdx, colNdx; 252 List<List<Coord>> rows = new List<List<Coord>>(numRows);
253 253
254 for (rowNdx = 0; rowNdx < numRows; rowNdx++) 254 float pixScale = 1.0f / (scale * scale);
255 { 255 pixScale /= 255;
256 List<Coord> row = new List<Coord>(numCols); 256
257 for (colNdx = 0; colNdx < numCols; colNdx++) 257 int imageX, imageY = 0;
258 { 258
259 imageX = colNdx * scale; 259 int rowNdx, colNdx;
260 int imageYStart = rowNdx * scale; 260
261 int imageYEnd = imageYStart + scale; 261 for (rowNdx = 0; rowNdx < numRows; rowNdx++)
262 int imageXEnd = imageX + scale; 262 {
263 float rSum = 0.0f; 263 List<Coord> row = new List<Coord>(numCols);
264 float gSum = 0.0f; 264 for (colNdx = 0; colNdx < numCols; colNdx++)
265 float bSum = 0.0f; 265 {
266 for (; imageX < imageXEnd; imageX++) 266 imageX = colNdx * scale;
267 { 267 int imageYStart = rowNdx * scale;
268 for (imageY = imageYStart; imageY < imageYEnd; imageY++) 268 int imageYEnd = imageYStart + scale;
269 { 269 int imageXEnd = imageX + scale;
270 Color c = bitmap.GetPixel(imageX, imageY); 270 float rSum = 0.0f;
271 rSum += c.R; 271 float gSum = 0.0f;
272 gSum += c.G; 272 float bSum = 0.0f;
273 bSum += c.B; 273 for (; imageX < imageXEnd; imageX++)
274 } 274 {
275 } 275 for (imageY = imageYStart; imageY < imageYEnd; imageY++)
276 if (mirror) 276 {
277 row.Add(new Coord(-(rSum * pixScale - 0.5f), gSum * pixScale - 0.5f, bSum * pixScale - 0.5f)); 277 Color c = bitmap.GetPixel(imageX, imageY);
278 else 278 if (c.A != 255)
279 row.Add(new Coord(rSum * pixScale - 0.5f, gSum * pixScale - 0.5f, bSum * pixScale - 0.5f)); 279 {
280 280 bitmap.SetPixel(imageX, imageY, Color.FromArgb(255, c.R, c.G, c.B));
281 } 281 c = bitmap.GetPixel(imageX, imageY);
282 rows.Add(row); 282 }
283 } 283 rSum += c.R;
284 return rows; 284 gSum += c.G;
285 } 285 bSum += c.B;
286 286 }
287 287 }
288 void _SculptMesh(Bitmap sculptBitmap, SculptType sculptType, int lod, bool viewerMode, bool mirror, bool invert) 288 if (mirror)
289 { 289 row.Add(new Coord(-(rSum * pixScale - 0.5f), gSum * pixScale - 0.5f, bSum * pixScale - 0.5f));
290 coords = new List<Coord>(); 290 else
291 faces = new List<Face>(); 291 row.Add(new Coord(rSum * pixScale - 0.5f, gSum * pixScale - 0.5f, bSum * pixScale - 0.5f));
292 normals = new List<Coord>(); 292
293 uvs = new List<UVCoord>(); 293 }
294 294 rows.Add(row);
295 sculptType = (SculptType)(((int)sculptType) & 0x07); 295 }
296 296 return rows;
297 if (mirror) 297 }
298 if (sculptType == SculptType.plane) 298
299 invert = !invert; 299
300 300 void _SculptMesh(Bitmap sculptBitmap, SculptType sculptType, int lod, bool viewerMode, bool mirror, bool invert)
301 float sourceScaleFactor = (float)(lod) / (float)Math.Sqrt(sculptBitmap.Width * sculptBitmap.Height); 301 {
302 302 coords = new List<Coord>();
303 int scale = (int)(1.0f / sourceScaleFactor); 303 faces = new List<Face>();
304 if (scale < 1) scale = 1; 304 normals = new List<Coord>();
305 305 uvs = new List<UVCoord>();
306 _SculptMesh(bitmap2Coords(sculptBitmap, scale, mirror), sculptType, viewerMode, mirror, invert); 306
307 } 307 sculptType = (SculptType)(((int)sculptType) & 0x07);
308#endif 308
309 309 if (mirror)
310 310 if (sculptType == SculptType.plane)
311 void _SculptMesh(List<List<Coord>> rows, SculptType sculptType, bool viewerMode, bool mirror, bool invert) 311 invert = !invert;
312 { 312
313 coords = new List<Coord>(); 313 float sculptBitmapLod = (float)Math.Sqrt(sculptBitmap.Width * sculptBitmap.Height);
314 faces = new List<Face>(); 314
315 normals = new List<Coord>(); 315 float sourceScaleFactor = (float)(lod) / sculptBitmapLod;
316 uvs = new List<UVCoord>(); 316
317 317 float fScale = 1.0f / sourceScaleFactor;
318 sculptType = (SculptType)(((int)sculptType) & 0x07); 318
319 319 int iScale = (int)fScale;
320 if (mirror) 320 if (iScale < 1) iScale = 1;
321 if (sculptType == SculptType.plane) 321 if (iScale > 2 && iScale % 2 == 0)
322 invert = !invert; 322 _SculptMesh(bitmap2Coords(ScaleImage(sculptBitmap, 64.0f / sculptBitmapLod, true), 64 / lod, mirror), sculptType, viewerMode, mirror, invert);
323 323 else
324 viewerFaces = new List<ViewerFace>(); 324 _SculptMesh(bitmap2Coords(sculptBitmap, iScale, mirror), sculptType, viewerMode, mirror, invert);
325 325 }
326 int width = rows[0].Count; 326#endif
327 327
328 int p1, p2, p3, p4; 328
329 329 void _SculptMesh(List<List<Coord>> rows, SculptType sculptType, bool viewerMode, bool mirror, bool invert)
330 int imageX, imageY; 330 {
331 331 coords = new List<Coord>();
332 if (sculptType != SculptType.plane) 332 faces = new List<Face>();
333 { 333 normals = new List<Coord>();
334 for (int rowNdx = 0; rowNdx < rows.Count; rowNdx++) 334 uvs = new List<UVCoord>();
335 rows[rowNdx].Add(rows[rowNdx][0]); 335
336 } 336 sculptType = (SculptType)(((int)sculptType) & 0x07);
337 337
338 Coord topPole = rows[0][width / 2]; 338 if (mirror)
339 Coord bottomPole = rows[rows.Count - 1][width / 2]; 339 if (sculptType == SculptType.plane)
340 340 invert = !invert;
341 if (sculptType == SculptType.sphere) 341
342 { 342 viewerFaces = new List<ViewerFace>();
343 int count = rows[0].Count; 343
344 List<Coord> topPoleRow = new List<Coord>(count); 344 int width = rows[0].Count;
345 List<Coord> bottomPoleRow = new List<Coord>(count); 345
346 346 int p1, p2, p3, p4;
347 for (int i = 0; i < count; i++) 347
348 { 348 int imageX, imageY;
349 topPoleRow.Add(topPole); 349
350 bottomPoleRow.Add(bottomPole); 350 if (sculptType != SculptType.plane)
351 } 351 {
352 rows.Insert(0, topPoleRow); 352 for (int rowNdx = 0; rowNdx < rows.Count; rowNdx++)
353 rows.Add(bottomPoleRow); 353 rows[rowNdx].Add(rows[rowNdx][0]);
354 } 354 }
355 else if (sculptType == SculptType.torus) 355
356 rows.Add(rows[0]); 356 Coord topPole = rows[0][width / 2];
357 357 Coord bottomPole = rows[rows.Count - 1][width / 2];
358 int coordsDown = rows.Count; 358
359 int coordsAcross = rows[0].Count; 359 if (sculptType == SculptType.sphere)
360 360 {
361 float widthUnit = 1.0f / (coordsAcross - 1); 361 int count = rows[0].Count;
362 float heightUnit = 1.0f / (coordsDown - 1); 362 List<Coord> topPoleRow = new List<Coord>(count);
363 363 List<Coord> bottomPoleRow = new List<Coord>(count);
364 for (imageY = 0; imageY < coordsDown; imageY++) 364
365 { 365 for (int i = 0; i < count; i++)
366 int rowOffset = imageY * coordsAcross; 366 {
367 367 topPoleRow.Add(topPole);
368 for (imageX = 0; imageX < coordsAcross; imageX++) 368 bottomPoleRow.Add(bottomPole);
369 { 369 }
370 /* 370 rows.Insert(0, topPoleRow);
371 * p1-----p2 371 rows.Add(bottomPoleRow);
372 * | \ f2 | 372 }
373 * | \ | 373 else if (sculptType == SculptType.torus)
374 * | f1 \| 374 rows.Add(rows[0]);
375 * p3-----p4 375
376 */ 376 int coordsDown = rows.Count;
377 377 int coordsAcross = rows[0].Count;
378 p4 = rowOffset + imageX; 378
379 p3 = p4 - 1; 379 float widthUnit = 1.0f / (coordsAcross - 1);
380 380 float heightUnit = 1.0f / (coordsDown - 1);
381 p2 = p4 - coordsAcross; 381
382 p1 = p3 - coordsAcross; 382 for (imageY = 0; imageY < coordsDown; imageY++)
383 383 {
384 this.coords.Add(rows[imageY][imageX]); 384 int rowOffset = imageY * coordsAcross;
385 if (viewerMode) 385
386 { 386 for (imageX = 0; imageX < coordsAcross; imageX++)
387 this.normals.Add(new Coord()); 387 {
388 this.uvs.Add(new UVCoord(widthUnit * imageX, heightUnit * imageY)); 388 /*
389 } 389 * p1-----p2
390 390 * | \ f2 |
391 if (imageY > 0 && imageX > 0) 391 * | \ |
392 { 392 * | f1 \|
393 Face f1, f2; 393 * p3-----p4
394 394 */
395 if (viewerMode) 395
396 { 396 p4 = rowOffset + imageX;
397 if (invert) 397 p3 = p4 - 1;
398 { 398
399 f1 = new Face(p1, p4, p3, p1, p4, p3); 399 p2 = p4 - coordsAcross;
400 f1.uv1 = p1; 400 p1 = p3 - coordsAcross;
401 f1.uv2 = p4; 401
402 f1.uv3 = p3; 402 this.coords.Add(rows[imageY][imageX]);
403 403 if (viewerMode)
404 f2 = new Face(p1, p2, p4, p1, p2, p4); 404 {
405 f2.uv1 = p1; 405 this.normals.Add(new Coord());
406 f2.uv2 = p2; 406 this.uvs.Add(new UVCoord(widthUnit * imageX, heightUnit * imageY));
407 f2.uv3 = p4; 407 }
408 } 408
409 else 409 if (imageY > 0 && imageX > 0)
410 { 410 {
411 f1 = new Face(p1, p3, p4, p1, p3, p4); 411 Face f1, f2;
412 f1.uv1 = p1; 412
413 f1.uv2 = p3; 413 if (viewerMode)
414 f1.uv3 = p4; 414 {
415 415 if (invert)
416 f2 = new Face(p1, p4, p2, p1, p4, p2); 416 {
417 f2.uv1 = p1; 417 f1 = new Face(p1, p4, p3, p1, p4, p3);
418 f2.uv2 = p4; 418 f1.uv1 = p1;
419 f2.uv3 = p2; 419 f1.uv2 = p4;
420 } 420 f1.uv3 = p3;
421 } 421
422 else 422 f2 = new Face(p1, p2, p4, p1, p2, p4);
423 { 423 f2.uv1 = p1;
424 if (invert) 424 f2.uv2 = p2;
425 { 425 f2.uv3 = p4;
426 f1 = new Face(p1, p4, p3); 426 }
427 f2 = new Face(p1, p2, p4); 427 else
428 } 428 {
429 else 429 f1 = new Face(p1, p3, p4, p1, p3, p4);
430 { 430 f1.uv1 = p1;
431 f1 = new Face(p1, p3, p4); 431 f1.uv2 = p3;
432 f2 = new Face(p1, p4, p2); 432 f1.uv3 = p4;
433 } 433
434 } 434 f2 = new Face(p1, p4, p2, p1, p4, p2);
435 435 f2.uv1 = p1;
436 this.faces.Add(f1); 436 f2.uv2 = p4;
437 this.faces.Add(f2); 437 f2.uv3 = p2;
438 } 438 }
439 } 439 }
440 } 440 else
441 441 {
442 if (viewerMode) 442 if (invert)
443 calcVertexNormals(sculptType, coordsAcross, coordsDown); 443 {
444 } 444 f1 = new Face(p1, p4, p3);
445 445 f2 = new Face(p1, p2, p4);
446 /// <summary> 446 }
447 /// Duplicates a SculptMesh object. All object properties are copied by value, including lists. 447 else
448 /// </summary> 448 {
449 /// <returns></returns> 449 f1 = new Face(p1, p3, p4);
450 public SculptMesh Copy() 450 f2 = new Face(p1, p4, p2);
451 { 451 }
452 return new SculptMesh(this); 452 }
453 } 453
454 454 this.faces.Add(f1);
455 public SculptMesh(SculptMesh sm) 455 this.faces.Add(f2);
456 { 456 }
457 coords = new List<Coord>(sm.coords); 457 }
458 faces = new List<Face>(sm.faces); 458 }
459 viewerFaces = new List<ViewerFace>(sm.viewerFaces); 459
460 normals = new List<Coord>(sm.normals); 460 if (viewerMode)
461 uvs = new List<UVCoord>(sm.uvs); 461 calcVertexNormals(sculptType, coordsAcross, coordsDown);
462 } 462 }
463 463
464 private void calcVertexNormals(SculptType sculptType, int xSize, int ySize) 464 /// <summary>
465 { // compute vertex normals by summing all the surface normals of all the triangles sharing 465 /// Duplicates a SculptMesh object. All object properties are copied by value, including lists.
466 // each vertex and then normalizing 466 /// </summary>
467 int numFaces = this.faces.Count; 467 /// <returns></returns>
468 for (int i = 0; i < numFaces; i++) 468 public SculptMesh Copy()
469 { 469 {
470 Face face = this.faces[i]; 470 return new SculptMesh(this);
471 Coord surfaceNormal = face.SurfaceNormal(this.coords); 471 }
472 this.normals[face.n1] += surfaceNormal; 472
473 this.normals[face.n2] += surfaceNormal; 473 public SculptMesh(SculptMesh sm)
474 this.normals[face.n3] += surfaceNormal; 474 {
475 } 475 coords = new List<Coord>(sm.coords);
476 476 faces = new List<Face>(sm.faces);
477 int numNormals = this.normals.Count; 477 viewerFaces = new List<ViewerFace>(sm.viewerFaces);
478 for (int i = 0; i < numNormals; i++) 478 normals = new List<Coord>(sm.normals);
479 this.normals[i] = this.normals[i].Normalize(); 479 uvs = new List<UVCoord>(sm.uvs);
480 480 }
481 if (sculptType != SculptType.plane) 481
482 { // blend the vertex normals at the cylinder seam 482 private void calcVertexNormals(SculptType sculptType, int xSize, int ySize)
483 for (int y = 0; y < ySize; y++) 483 { // compute vertex normals by summing all the surface normals of all the triangles sharing
484 { 484 // each vertex and then normalizing
485 int rowOffset = y * xSize; 485 int numFaces = this.faces.Count;
486 486 for (int i = 0; i < numFaces; i++)
487 this.normals[rowOffset] = this.normals[rowOffset + xSize - 1] = (this.normals[rowOffset] + this.normals[rowOffset + xSize - 1]).Normalize(); 487 {
488 } 488 Face face = this.faces[i];
489 } 489 Coord surfaceNormal = face.SurfaceNormal(this.coords);
490 490 this.normals[face.n1] += surfaceNormal;
491 foreach (Face face in this.faces) 491 this.normals[face.n2] += surfaceNormal;
492 { 492 this.normals[face.n3] += surfaceNormal;
493 ViewerFace vf = new ViewerFace(0); 493 }
494 vf.v1 = this.coords[face.v1]; 494
495 vf.v2 = this.coords[face.v2]; 495 int numNormals = this.normals.Count;
496 vf.v3 = this.coords[face.v3]; 496 for (int i = 0; i < numNormals; i++)
497 497 this.normals[i] = this.normals[i].Normalize();
498 vf.coordIndex1 = face.v1; 498
499 vf.coordIndex2 = face.v2; 499 if (sculptType != SculptType.plane)
500 vf.coordIndex3 = face.v3; 500 { // blend the vertex normals at the cylinder seam
501 501 for (int y = 0; y < ySize; y++)
502 vf.n1 = this.normals[face.n1]; 502 {
503 vf.n2 = this.normals[face.n2]; 503 int rowOffset = y * xSize;
504 vf.n3 = this.normals[face.n3]; 504
505 505 this.normals[rowOffset] = this.normals[rowOffset + xSize - 1] = (this.normals[rowOffset] + this.normals[rowOffset + xSize - 1]).Normalize();
506 vf.uv1 = this.uvs[face.uv1]; 506 }
507 vf.uv2 = this.uvs[face.uv2]; 507 }
508 vf.uv3 = this.uvs[face.uv3]; 508
509 509 foreach (Face face in this.faces)
510 this.viewerFaces.Add(vf); 510 {
511 } 511 ViewerFace vf = new ViewerFace(0);
512 } 512 vf.v1 = this.coords[face.v1];
513 513 vf.v2 = this.coords[face.v2];
514 /// <summary> 514 vf.v3 = this.coords[face.v3];
515 /// Adds a value to each XYZ vertex coordinate in the mesh 515
516 /// </summary> 516 vf.coordIndex1 = face.v1;
517 /// <param name="x"></param> 517 vf.coordIndex2 = face.v2;
518 /// <param name="y"></param> 518 vf.coordIndex3 = face.v3;
519 /// <param name="z"></param> 519
520 public void AddPos(float x, float y, float z) 520 vf.n1 = this.normals[face.n1];
521 { 521 vf.n2 = this.normals[face.n2];
522 int i; 522 vf.n3 = this.normals[face.n3];
523 int numVerts = this.coords.Count; 523
524 Coord vert; 524 vf.uv1 = this.uvs[face.uv1];
525 525 vf.uv2 = this.uvs[face.uv2];
526 for (i = 0; i < numVerts; i++) 526 vf.uv3 = this.uvs[face.uv3];
527 { 527
528 vert = this.coords[i]; 528 this.viewerFaces.Add(vf);
529 vert.X += x; 529 }
530 vert.Y += y; 530 }
531 vert.Z += z; 531
532 this.coords[i] = vert; 532 /// <summary>
533 } 533 /// Adds a value to each XYZ vertex coordinate in the mesh
534 534 /// </summary>
535 if (this.viewerFaces != null) 535 /// <param name="x"></param>
536 { 536 /// <param name="y"></param>
537 int numViewerFaces = this.viewerFaces.Count; 537 /// <param name="z"></param>
538 538 public void AddPos(float x, float y, float z)
539 for (i = 0; i < numViewerFaces; i++) 539 {
540 { 540 int i;
541 ViewerFace v = this.viewerFaces[i]; 541 int numVerts = this.coords.Count;
542 v.AddPos(x, y, z); 542 Coord vert;
543 this.viewerFaces[i] = v; 543
544 } 544 for (i = 0; i < numVerts; i++)
545 } 545 {
546 } 546 vert = this.coords[i];
547 547 vert.X += x;
548 /// <summary> 548 vert.Y += y;
549 /// Rotates the mesh 549 vert.Z += z;
550 /// </summary> 550 this.coords[i] = vert;
551 /// <param name="q"></param> 551 }
552 public void AddRot(Quat q) 552
553 { 553 if (this.viewerFaces != null)
554 int i; 554 {
555 int numVerts = this.coords.Count; 555 int numViewerFaces = this.viewerFaces.Count;
556 556
557 for (i = 0; i < numVerts; i++) 557 for (i = 0; i < numViewerFaces; i++)
558 this.coords[i] *= q; 558 {
559 559 ViewerFace v = this.viewerFaces[i];
560 int numNormals = this.normals.Count; 560 v.AddPos(x, y, z);
561 for (i = 0; i < numNormals; i++) 561 this.viewerFaces[i] = v;
562 this.normals[i] *= q; 562 }
563 563 }
564 if (this.viewerFaces != null) 564 }
565 { 565
566 int numViewerFaces = this.viewerFaces.Count; 566 /// <summary>
567 567 /// Rotates the mesh
568 for (i = 0; i < numViewerFaces; i++) 568 /// </summary>
569 { 569 /// <param name="q"></param>
570 ViewerFace v = this.viewerFaces[i]; 570 public void AddRot(Quat q)
571 v.v1 *= q; 571 {
572 v.v2 *= q; 572 int i;
573 v.v3 *= q; 573 int numVerts = this.coords.Count;
574 574
575 v.n1 *= q; 575 for (i = 0; i < numVerts; i++)
576 v.n2 *= q; 576 this.coords[i] *= q;
577 v.n3 *= q; 577
578 578 int numNormals = this.normals.Count;
579 this.viewerFaces[i] = v; 579 for (i = 0; i < numNormals; i++)
580 } 580 this.normals[i] *= q;
581 } 581
582 } 582 if (this.viewerFaces != null)
583 583 {
584 public void Scale(float x, float y, float z) 584 int numViewerFaces = this.viewerFaces.Count;
585 { 585
586 int i; 586 for (i = 0; i < numViewerFaces; i++)
587 int numVerts = this.coords.Count; 587 {
588 588 ViewerFace v = this.viewerFaces[i];
589 Coord m = new Coord(x, y, z); 589 v.v1 *= q;
590 for (i = 0; i < numVerts; i++) 590 v.v2 *= q;
591 this.coords[i] *= m; 591 v.v3 *= q;
592 592
593 if (this.viewerFaces != null) 593 v.n1 *= q;
594 { 594 v.n2 *= q;
595 int numViewerFaces = this.viewerFaces.Count; 595 v.n3 *= q;
596 for (i = 0; i < numViewerFaces; i++) 596
597 { 597 this.viewerFaces[i] = v;
598 ViewerFace v = this.viewerFaces[i]; 598 }
599 v.v1 *= m; 599 }
600 v.v2 *= m; 600 }
601 v.v3 *= m; 601
602 this.viewerFaces[i] = v; 602 public void Scale(float x, float y, float z)
603 } 603 {
604 } 604 int i;
605 } 605 int numVerts = this.coords.Count;
606 606
607 public void DumpRaw(String path, String name, String title) 607 Coord m = new Coord(x, y, z);
608 { 608 for (i = 0; i < numVerts; i++)
609 if (path == null) 609 this.coords[i] *= m;
610 return; 610
611 String fileName = name + "_" + title + ".raw"; 611 if (this.viewerFaces != null)
612 String completePath = System.IO.Path.Combine(path, fileName); 612 {
613 StreamWriter sw = new StreamWriter(completePath); 613 int numViewerFaces = this.viewerFaces.Count;
614 614 for (i = 0; i < numViewerFaces; i++)
615 for (int i = 0; i < this.faces.Count; i++) 615 {
616 { 616 ViewerFace v = this.viewerFaces[i];
617 string s = this.coords[this.faces[i].v1].ToString(); 617 v.v1 *= m;
618 s += " " + this.coords[this.faces[i].v2].ToString(); 618 v.v2 *= m;
619 s += " " + this.coords[this.faces[i].v3].ToString(); 619 v.v3 *= m;
620 620 this.viewerFaces[i] = v;
621 sw.WriteLine(s); 621 }
622 } 622 }
623 623 }
624 sw.Close(); 624
625 } 625 public void DumpRaw(String path, String name, String title)
626 } 626 {
627} 627 if (path == null)
628 return;
629 String fileName = name + "_" + title + ".raw";
630 String completePath = System.IO.Path.Combine(path, fileName);
631 StreamWriter sw = new StreamWriter(completePath);
632
633 for (int i = 0; i < this.faces.Count; i++)
634 {
635 string s = this.coords[this.faces[i].v1].ToString();
636 s += " " + this.coords[this.faces[i].v2].ToString();
637 s += " " + this.coords[this.faces[i].v3].ToString();
638
639 sw.WriteLine(s);
640 }
641
642 sw.Close();
643 }
644 }
645}