Meshmerizer.cs 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818
  1. /*
  2. * Copyright (c) Contributors, http://opensimulator.org/
  3. * See CONTRIBUTORS.TXT for a full list of copyright holders.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. * * Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * * Redistributions in binary form must reproduce the above copyright
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. * * Neither the name of the OpenSim Project nor the
  13. * names of its contributors may be used to endorse or promote products
  14. * derived from this software without specific prior written permission.
  15. *
  16. * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS AS IS AND ANY
  17. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  18. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  19. * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
  20. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  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
  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
  25. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26. *
  27. */
  28. using System;
  29. using System.Collections.Generic;
  30. using OpenSim.Framework;
  31. using OpenSim.Framework.Console;
  32. using OpenSim.Region.Physics.Manager;
  33. namespace OpenSim.Region.Physics.Meshing
  34. {
  35. public class MeshmerizerPlugin : IMeshingPlugin
  36. {
  37. public MeshmerizerPlugin()
  38. {
  39. }
  40. public string GetName()
  41. {
  42. return "Meshmerizer";
  43. }
  44. public IMesher GetMesher()
  45. {
  46. return new Meshmerizer();
  47. }
  48. }
  49. public class Meshmerizer : IMesher
  50. {
  51. private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
  52. // Setting baseDir to a path will enable the dumping of raw files
  53. // raw files can be imported by blender so a visual inspection of the results can be done
  54. // const string baseDir = "rawFiles";
  55. private const string baseDir = null; //"rawFiles";
  56. private static void IntersectionParameterPD(PhysicsVector p1, PhysicsVector r1, PhysicsVector p2,
  57. PhysicsVector r2, ref float lambda, ref float mu)
  58. {
  59. // p1, p2, points on the straight
  60. // r1, r2, directional vectors of the straight. Not necessarily of length 1!
  61. // note, that l, m can be scaled such, that the range 0..1 is mapped to the area between two points,
  62. // thus allowing to decide whether an intersection is between two points
  63. float r1x = r1.X;
  64. float r1y = r1.Y;
  65. float r2x = r2.X;
  66. float r2y = r2.Y;
  67. float denom = r1y*r2x - r1x*r2y;
  68. if (denom == 0.0)
  69. {
  70. lambda = Single.NaN;
  71. mu = Single.NaN;
  72. return;
  73. }
  74. float p1x = p1.X;
  75. float p1y = p1.Y;
  76. float p2x = p2.X;
  77. float p2y = p2.Y;
  78. lambda = (-p2x*r2y + p1x*r2y + (p2y - p1y)*r2x)/denom;
  79. mu = (-p2x*r1y + p1x*r1y + (p2y - p1y)*r1x)/denom;
  80. }
  81. private static List<Triangle> FindInfluencedTriangles(List<Triangle> triangles, Vertex v)
  82. {
  83. List<Triangle> influenced = new List<Triangle>();
  84. foreach (Triangle t in triangles)
  85. {
  86. if (t.isInCircle(v.X, v.Y))
  87. {
  88. influenced.Add(t);
  89. }
  90. }
  91. return influenced;
  92. }
  93. private static void InsertVertices(List<Vertex> vertices, int usedForSeed, List<Triangle> triangles)
  94. {
  95. // This is a variant of the delaunay algorithm
  96. // each time a new vertex is inserted, all triangles that are influenced by it are deleted
  97. // and replaced by new ones including the new vertex
  98. // It is not very time efficient but easy to implement.
  99. int iCurrentVertex;
  100. int iMaxVertex = vertices.Count;
  101. for (iCurrentVertex = usedForSeed; iCurrentVertex < iMaxVertex; iCurrentVertex++)
  102. {
  103. // Background: A triangle mesh fulfills the delaunay condition if (iff!)
  104. // each circumlocutory circle (i.e. the circle that touches all three corners)
  105. // of each triangle is empty of other vertices.
  106. // Obviously a single (seeding) triangle fulfills this condition.
  107. // If we now add one vertex, we need to reconstruct all triangles, that
  108. // do not fulfill this condition with respect to the new triangle
  109. // Find the triangles that are influenced by the new vertex
  110. Vertex v = vertices[iCurrentVertex];
  111. if (v == null)
  112. continue; // Null is polygon stop marker. Ignore it
  113. List<Triangle> influencedTriangles = FindInfluencedTriangles(triangles, v);
  114. List<Simplex> simplices = new List<Simplex>();
  115. // Reconstruction phase. First step, dissolve each triangle into it's simplices,
  116. // i.e. it's "border lines"
  117. // Goal is to find "inner" borders and delete them, while the hull gets conserved.
  118. // Inner borders are special in the way that they always come twice, which is how we detect them
  119. foreach (Triangle t in influencedTriangles)
  120. {
  121. List<Simplex> newSimplices = t.GetSimplices();
  122. simplices.AddRange(newSimplices);
  123. triangles.Remove(t);
  124. }
  125. // Now sort the simplices. That will make identical ones reside side by side in the list
  126. simplices.Sort();
  127. // Look for duplicate simplices here.
  128. // Remember, they are directly side by side in the list right now,
  129. // So we only check directly neighbours
  130. int iSimplex;
  131. List<Simplex> innerSimplices = new List<Simplex>();
  132. for (iSimplex = 1; iSimplex < simplices.Count; iSimplex++) // Startindex=1, so we can refer backwards
  133. {
  134. if (simplices[iSimplex - 1].CompareTo(simplices[iSimplex]) == 0)
  135. {
  136. innerSimplices.Add(simplices[iSimplex - 1]);
  137. innerSimplices.Add(simplices[iSimplex]);
  138. }
  139. }
  140. foreach (Simplex s in innerSimplices)
  141. {
  142. simplices.Remove(s);
  143. }
  144. // each simplex still in the list belongs to the hull of the region in question
  145. // The new vertex (yes, we still deal with verices here :-) ) forms a triangle
  146. // with each of these simplices. Build the new triangles and add them to the list
  147. foreach (Simplex s in simplices)
  148. {
  149. Triangle t = new Triangle(s.v1, s.v2, vertices[iCurrentVertex]);
  150. if (!t.isDegraded())
  151. {
  152. triangles.Add(t);
  153. }
  154. }
  155. }
  156. }
  157. private static Mesh CreateBoxMesh(String primName, PrimitiveBaseShape primShape, PhysicsVector size)
  158. // Builds the z (+ and -) surfaces of a box shaped prim
  159. {
  160. UInt16 hollowFactor = primShape.ProfileHollow;
  161. UInt16 profileBegin = primShape.ProfileBegin;
  162. UInt16 profileEnd = primShape.ProfileEnd;
  163. UInt16 taperX = primShape.PathScaleX;
  164. UInt16 taperY = primShape.PathScaleY;
  165. UInt16 pathShearX = primShape.PathShearX;
  166. UInt16 pathShearY = primShape.PathShearY;
  167. //m_log.Error("pathShear:" + primShape.PathShearX.ToString() + "," + primShape.PathShearY.ToString());
  168. //m_log.Error("pathTaper:" + primShape.PathTaperX.ToString() + "," + primShape.PathTaperY.ToString());
  169. //m_log.Error("ProfileBegin:" + primShape.ProfileBegin.ToString() + "," + primShape.ProfileBegin.ToString());
  170. //m_log.Error("PathScale:" + primShape.PathScaleX.ToString() + "," + primShape.PathScaleY.ToString());
  171. // Procedure: This is based on the fact that the upper (plus) and lower (minus) Z-surface
  172. // of a block are basically the same
  173. // They may be warped differently but the shape is identical
  174. // So we only create one surface as a model and derive both plus and minus surface of the block from it
  175. // This is done in a model space where the block spans from -.5 to +.5 in X and Y
  176. // The mapping to Scene space is done later during the "extrusion" phase
  177. // Base
  178. Vertex MM = new Vertex(-0.5f, -0.5f, 0.0f);
  179. Vertex PM = new Vertex(+0.5f, -0.5f, 0.0f);
  180. Vertex PP = new Vertex(+0.5f, +0.5f, 0.0f);
  181. Vertex MP = new Vertex(-0.5f, +0.5f, 0.0f);
  182. SimpleHull outerHull = new SimpleHull();
  183. outerHull.AddVertex(MM);
  184. outerHull.AddVertex(PM);
  185. outerHull.AddVertex(PP);
  186. outerHull.AddVertex(MP);
  187. // Deal with cuts now
  188. if ((profileBegin != 0) || (profileEnd != 0))
  189. {
  190. double fProfileBeginAngle = profileBegin/50000.0*360.0;
  191. // In degree, for easier debugging and understanding
  192. fProfileBeginAngle -= (90.0 + 45.0); // for some reasons, the SL client counts from the corner -X/-Y
  193. double fProfileEndAngle = 360.0 - profileEnd/50000.0*360.0; // Pathend comes as complement to 1.0
  194. fProfileEndAngle -= (90.0 + 45.0);
  195. if (fProfileBeginAngle < fProfileEndAngle)
  196. fProfileEndAngle -= 360.0;
  197. // Note, that we don't want to cut out a triangle, even if this is a
  198. // good approximation for small cuts. Indeed we want to cut out an arc
  199. // and we approximate this arc by a polygon chain
  200. // Also note, that these vectors are of length 1.0 and thus their endpoints lay outside the model space
  201. // So it can easily be subtracted from the outer hull
  202. int iSteps = (int) (((fProfileBeginAngle - fProfileEndAngle)/45.0) + .5);
  203. // how many steps do we need with approximately 45 degree
  204. double dStepWidth = (fProfileBeginAngle - fProfileEndAngle)/iSteps;
  205. Vertex origin = new Vertex(0.0f, 0.0f, 0.0f);
  206. // Note the sequence of vertices here. It's important to have the other rotational sense than in outerHull
  207. SimpleHull cutHull = new SimpleHull();
  208. cutHull.AddVertex(origin);
  209. for (int i = 0; i < iSteps; i++)
  210. {
  211. double angle = fProfileBeginAngle - i*dStepWidth; // we count against the angle orientation!!!!
  212. Vertex v = Vertex.FromAngle(angle*Math.PI/180.0);
  213. cutHull.AddVertex(v);
  214. }
  215. Vertex legEnd = Vertex.FromAngle(fProfileEndAngle*Math.PI/180.0);
  216. // Calculated separately to avoid errors
  217. cutHull.AddVertex(legEnd);
  218. //m_log.DebugFormat("Starting cutting of the hollow shape from the prim {1}", 0, primName);
  219. SimpleHull cuttedHull = SimpleHull.SubtractHull(outerHull, cutHull);
  220. outerHull = cuttedHull;
  221. }
  222. // Deal with the hole here
  223. if (hollowFactor > 0)
  224. {
  225. float hollowFactorF = (float) hollowFactor/(float) 50000;
  226. Vertex IMM = new Vertex(-0.5f*hollowFactorF, -0.5f*hollowFactorF, 0.0f);
  227. Vertex IPM = new Vertex(+0.5f*hollowFactorF, -0.5f*hollowFactorF, 0.0f);
  228. Vertex IPP = new Vertex(+0.5f*hollowFactorF, +0.5f*hollowFactorF, 0.0f);
  229. Vertex IMP = new Vertex(-0.5f*hollowFactorF, +0.5f*hollowFactorF, 0.0f);
  230. SimpleHull holeHull = new SimpleHull();
  231. holeHull.AddVertex(IMM);
  232. holeHull.AddVertex(IMP);
  233. holeHull.AddVertex(IPP);
  234. holeHull.AddVertex(IPM);
  235. SimpleHull hollowedHull = SimpleHull.SubtractHull(outerHull, holeHull);
  236. outerHull = hollowedHull;
  237. }
  238. Mesh m = new Mesh();
  239. Vertex Seed1 = new Vertex(0.0f, -10.0f, 0.0f);
  240. Vertex Seed2 = new Vertex(-10.0f, 10.0f, 0.0f);
  241. Vertex Seed3 = new Vertex(10.0f, 10.0f, 0.0f);
  242. m.Add(Seed1);
  243. m.Add(Seed2);
  244. m.Add(Seed3);
  245. m.Add(new Triangle(Seed1, Seed2, Seed3));
  246. m.Add(outerHull.getVertices());
  247. InsertVertices(m.vertices, 3, m.triangles);
  248. m.DumpRaw(baseDir, primName, "Proto first Mesh");
  249. m.Remove(Seed1);
  250. m.Remove(Seed2);
  251. m.Remove(Seed3);
  252. m.DumpRaw(baseDir, primName, "Proto seeds removed");
  253. m.RemoveTrianglesOutside(outerHull);
  254. m.DumpRaw(baseDir, primName, "Proto outsides removed");
  255. foreach (Triangle t in m.triangles)
  256. {
  257. PhysicsVector n = t.getNormal();
  258. if (n.Z < 0.0)
  259. t.invertNormal();
  260. }
  261. Extruder extr = new Extruder();
  262. extr.size = size;
  263. if (taperX != 100)
  264. {
  265. if (taperX > 100)
  266. {
  267. extr.taperTopFactorX = 1.0f - ((float)taperX / 200);
  268. //m_log.Warn("taperTopFactorX: " + extr.taperTopFactorX.ToString());
  269. }
  270. else
  271. {
  272. extr.taperBotFactorX = 1.0f - ((100 - (float)taperX) / 100);
  273. //m_log.Warn("taperBotFactorX: " + extr.taperBotFactorX.ToString());
  274. }
  275. }
  276. if (taperY != 100)
  277. {
  278. if (taperY > 100)
  279. {
  280. extr.taperTopFactorY = 1.0f - ((float)taperY / 200);
  281. //m_log.Warn("taperTopFactorY: " + extr.taperTopFactorY.ToString());
  282. }
  283. else
  284. {
  285. extr.taperBotFactorY = 1.0f - ((100 - (float)taperY) / 100);
  286. //m_log.Warn("taperBotFactorY: " + extr.taperBotFactorY.ToString());
  287. }
  288. }
  289. if (pathShearX != 0)
  290. {
  291. if (pathShearX > 50) {
  292. // Complimentary byte. Negative values wrap around the byte. Positive values go up to 50
  293. extr.pushX = (((float)(256 - pathShearX) / 100) * -1f);
  294. // m_log.Warn("pushX: " + extr.pushX);
  295. }
  296. else
  297. {
  298. extr.pushX = (float)pathShearX / 100;
  299. // m_log.Warn("pushX: " + extr.pushX);
  300. }
  301. }
  302. if (pathShearY != 0)
  303. {
  304. if (pathShearY > 50) {
  305. // Complimentary byte. Negative values wrap around the byte. Positive values go up to 50
  306. extr.pushY = (((float)(256 - pathShearY) / 100) * -1f);
  307. //m_log.Warn("pushY: " + extr.pushY);
  308. }
  309. else
  310. {
  311. extr.pushY = (float)pathShearY / 100;
  312. //m_log.Warn("pushY: " + extr.pushY);
  313. }
  314. }
  315. Mesh result = extr.Extrude(m);
  316. result.DumpRaw(baseDir, primName, "Z extruded");
  317. return result;
  318. }
  319. private static Mesh CreateCyllinderMesh(String primName, PrimitiveBaseShape primShape, PhysicsVector size)
  320. // Builds the z (+ and -) surfaces of a box shaped prim
  321. {
  322. UInt16 hollowFactor = primShape.ProfileHollow;
  323. UInt16 profileBegin = primShape.ProfileBegin;
  324. UInt16 profileEnd = primShape.ProfileEnd;
  325. UInt16 taperX = primShape.PathScaleX;
  326. UInt16 taperY = primShape.PathScaleY;
  327. UInt16 pathShearX = primShape.PathShearX;
  328. UInt16 pathShearY = primShape.PathShearY;
  329. // Procedure: This is based on the fact that the upper (plus) and lower (minus) Z-surface
  330. // of a block are basically the same
  331. // They may be warped differently but the shape is identical
  332. // So we only create one surface as a model and derive both plus and minus surface of the block from it
  333. // This is done in a model space where the block spans from -.5 to +.5 in X and Y
  334. // The mapping to Scene space is done later during the "extrusion" phase
  335. // Base
  336. // Q1Q15 = Quadrant 1, Quadrant1, Vertex 5
  337. Vertex Q1Q15 = new Vertex(-0.35f, -0.35f, 0.0f);
  338. Vertex Q1Q16 = new Vertex(-0.30f, -0.40f, 0.0f);
  339. Vertex Q1Q17 = new Vertex(-0.24f, -0.43f, 0.0f);
  340. Vertex Q1Q18 = new Vertex(-0.18f, -0.46f, 0.0f);
  341. Vertex Q1Q19 = new Vertex(-0.11f, -0.48f, 0.0f);
  342. Vertex Q2Q10 = new Vertex(+0.0f, -0.50f, 0.0f);
  343. Vertex Q2Q11 = new Vertex(+0.11f, -0.48f, 0.0f);
  344. Vertex Q2Q12 = new Vertex(+0.18f, -0.46f, 0.0f);
  345. Vertex Q2Q13 = new Vertex(+0.24f, -0.43f, 0.0f);
  346. Vertex Q2Q14 = new Vertex(+0.30f, -0.40f, 0.0f);
  347. Vertex Q2Q15 = new Vertex(+0.35f, -0.35f, 0.0f);
  348. Vertex Q2Q16 = new Vertex(+0.40f, -0.30f, 0.0f);
  349. Vertex Q2Q17 = new Vertex(+0.43f, -0.24f, 0.0f);
  350. Vertex Q2Q18 = new Vertex(+0.46f, -0.18f, 0.0f);
  351. Vertex Q2Q19 = new Vertex(+0.48f, -0.11f, 0.0f);
  352. Vertex Q2Q20 = new Vertex(+0.50f, +0.0f, 0.0f);
  353. Vertex Q2Q21 = new Vertex(+0.48f, +0.11f, 0.0f);
  354. Vertex Q2Q22 = new Vertex(+0.46f, +0.18f, 0.0f);
  355. Vertex Q2Q23 = new Vertex(+0.43f, +0.24f, 0.0f);
  356. Vertex Q2Q24 = new Vertex(+0.40f, +0.30f, 0.0f);
  357. Vertex Q2Q25 = new Vertex(+0.35f, +0.35f, 0.0f);
  358. Vertex Q2Q26 = new Vertex(+0.30f, +0.40f, 0.0f);
  359. Vertex Q2Q27 = new Vertex(+0.24f, +0.43f, 0.0f);
  360. Vertex Q2Q28 = new Vertex(+0.18f, +0.46f, 0.0f);
  361. Vertex Q2Q29 = new Vertex(+0.11f, +0.48f, 0.0f);
  362. Vertex Q1Q20 = new Vertex(+0.0f, +0.50f, 0.0f);
  363. Vertex Q1Q21 = new Vertex(-0.11f, +0.48f, 0.0f);
  364. Vertex Q1Q22 = new Vertex(-0.18f, +0.46f, 0.0f);
  365. Vertex Q1Q23 = new Vertex(-0.24f, +0.43f, 0.0f);
  366. Vertex Q1Q24 = new Vertex(-0.30f, +0.40f, 0.0f);
  367. Vertex Q1Q25 = new Vertex(-0.35f, +0.35f, 0.0f);
  368. Vertex Q1Q26 = new Vertex(-0.40f, +0.30f, 0.0f);
  369. Vertex Q1Q27 = new Vertex(-0.43f, +0.24f, 0.0f);
  370. Vertex Q1Q28 = new Vertex(-0.46f, +0.18f, 0.0f);
  371. Vertex Q1Q29 = new Vertex(-0.48f, +0.11f, 0.0f);
  372. Vertex Q1Q10 = new Vertex(-0.50f, +0.0f, 0.0f);
  373. Vertex Q1Q11 = new Vertex(-0.48f, -0.11f, 0.0f);
  374. Vertex Q1Q12 = new Vertex(-0.46f, -0.18f, 0.0f);
  375. Vertex Q1Q13 = new Vertex(-0.43f, -0.24f, 0.0f);
  376. Vertex Q1Q14 = new Vertex(-0.40f, -0.30f, 0.0f);
  377. SimpleHull outerHull = new SimpleHull();
  378. //Clockwise around the quadrants
  379. outerHull.AddVertex(Q1Q15);
  380. outerHull.AddVertex(Q1Q16);
  381. outerHull.AddVertex(Q1Q17);
  382. outerHull.AddVertex(Q1Q18);
  383. outerHull.AddVertex(Q1Q19);
  384. outerHull.AddVertex(Q2Q10);
  385. outerHull.AddVertex(Q2Q11);
  386. outerHull.AddVertex(Q2Q12);
  387. outerHull.AddVertex(Q2Q13);
  388. outerHull.AddVertex(Q2Q14);
  389. outerHull.AddVertex(Q2Q15);
  390. outerHull.AddVertex(Q2Q16);
  391. outerHull.AddVertex(Q2Q17);
  392. outerHull.AddVertex(Q2Q18);
  393. outerHull.AddVertex(Q2Q19);
  394. outerHull.AddVertex(Q2Q20);
  395. outerHull.AddVertex(Q2Q21);
  396. outerHull.AddVertex(Q2Q22);
  397. outerHull.AddVertex(Q2Q23);
  398. outerHull.AddVertex(Q2Q24);
  399. outerHull.AddVertex(Q2Q25);
  400. outerHull.AddVertex(Q2Q26);
  401. outerHull.AddVertex(Q2Q27);
  402. outerHull.AddVertex(Q2Q28);
  403. outerHull.AddVertex(Q2Q29);
  404. outerHull.AddVertex(Q1Q20);
  405. outerHull.AddVertex(Q1Q21);
  406. outerHull.AddVertex(Q1Q22);
  407. outerHull.AddVertex(Q1Q23);
  408. outerHull.AddVertex(Q1Q24);
  409. outerHull.AddVertex(Q1Q25);
  410. outerHull.AddVertex(Q1Q26);
  411. outerHull.AddVertex(Q1Q27);
  412. outerHull.AddVertex(Q1Q28);
  413. outerHull.AddVertex(Q1Q29);
  414. outerHull.AddVertex(Q1Q10);
  415. outerHull.AddVertex(Q1Q11);
  416. outerHull.AddVertex(Q1Q12);
  417. outerHull.AddVertex(Q1Q13);
  418. outerHull.AddVertex(Q1Q14);
  419. // Deal with cuts now
  420. if ((profileBegin != 0) || (profileEnd != 0))
  421. {
  422. double fProfileBeginAngle = profileBegin / 50000.0 * 360.0;
  423. // In degree, for easier debugging and understanding
  424. //fProfileBeginAngle -= (90.0 + 45.0); // for some reasons, the SL client counts from the corner -X/-Y
  425. double fProfileEndAngle = 360.0 - profileEnd / 50000.0 * 360.0; // Pathend comes as complement to 1.0
  426. //fProfileEndAngle -= (90.0 + 45.0);
  427. if (fProfileBeginAngle < fProfileEndAngle)
  428. fProfileEndAngle -= 360.0;
  429. // Note, that we don't want to cut out a triangle, even if this is a
  430. // good approximation for small cuts. Indeed we want to cut out an arc
  431. // and we approximate this arc by a polygon chain
  432. // Also note, that these vectors are of length 1.0 and thus their endpoints lay outside the model space
  433. // So it can easily be subtracted from the outer hull
  434. int iSteps = (int)(((fProfileBeginAngle - fProfileEndAngle) / 45.0) + .5);
  435. // how many steps do we need with approximately 45 degree
  436. double dStepWidth = (fProfileBeginAngle - fProfileEndAngle) / iSteps;
  437. Vertex origin = new Vertex(0.0f, 0.0f, 0.0f);
  438. // Note the sequence of vertices here. It's important to have the other rotational sense than in outerHull
  439. SimpleHull cutHull = new SimpleHull();
  440. cutHull.AddVertex(origin);
  441. for (int i = 0; i < iSteps; i++)
  442. {
  443. double angle = fProfileBeginAngle - i * dStepWidth; // we count against the angle orientation!!!!
  444. Vertex v = Vertex.FromAngle(angle * Math.PI / 180.0);
  445. cutHull.AddVertex(v);
  446. }
  447. Vertex legEnd = Vertex.FromAngle(fProfileEndAngle * Math.PI / 180.0);
  448. // Calculated separately to avoid errors
  449. cutHull.AddVertex(legEnd);
  450. // m_log.DebugFormat("Starting cutting of the hollow shape from the prim {1}", 0, primName);
  451. SimpleHull cuttedHull = SimpleHull.SubtractHull(outerHull, cutHull);
  452. outerHull = cuttedHull;
  453. }
  454. // Deal with the hole here
  455. if (hollowFactor > 0)
  456. {
  457. float hollowFactorF = (float)hollowFactor / (float)50000;
  458. Vertex IQ1Q15 = new Vertex(-0.35f * hollowFactorF, -0.35f * hollowFactorF, 0.0f);
  459. Vertex IQ1Q16 = new Vertex(-0.30f * hollowFactorF, -0.40f * hollowFactorF, 0.0f);
  460. Vertex IQ1Q17 = new Vertex(-0.24f * hollowFactorF, -0.43f * hollowFactorF, 0.0f);
  461. Vertex IQ1Q18 = new Vertex(-0.18f * hollowFactorF, -0.46f * hollowFactorF, 0.0f);
  462. Vertex IQ1Q19 = new Vertex(-0.11f * hollowFactorF, -0.48f * hollowFactorF, 0.0f);
  463. Vertex IQ2Q10 = new Vertex(+0.0f * hollowFactorF, -0.50f * hollowFactorF, 0.0f);
  464. Vertex IQ2Q11 = new Vertex(+0.11f * hollowFactorF, -0.48f * hollowFactorF, 0.0f);
  465. Vertex IQ2Q12 = new Vertex(+0.18f * hollowFactorF, -0.46f * hollowFactorF, 0.0f);
  466. Vertex IQ2Q13 = new Vertex(+0.24f * hollowFactorF, -0.43f * hollowFactorF, 0.0f);
  467. Vertex IQ2Q14 = new Vertex(+0.30f * hollowFactorF, -0.40f * hollowFactorF, 0.0f);
  468. Vertex IQ2Q15 = new Vertex(+0.35f * hollowFactorF, -0.35f * hollowFactorF, 0.0f);
  469. Vertex IQ2Q16 = new Vertex(+0.40f * hollowFactorF, -0.30f * hollowFactorF, 0.0f);
  470. Vertex IQ2Q17 = new Vertex(+0.43f * hollowFactorF, -0.24f * hollowFactorF, 0.0f);
  471. Vertex IQ2Q18 = new Vertex(+0.46f * hollowFactorF, -0.18f * hollowFactorF, 0.0f);
  472. Vertex IQ2Q19 = new Vertex(+0.48f * hollowFactorF, -0.11f * hollowFactorF, 0.0f);
  473. Vertex IQ2Q20 = new Vertex(+0.50f * hollowFactorF, +0.0f * hollowFactorF, 0.0f);
  474. Vertex IQ2Q21 = new Vertex(+0.48f * hollowFactorF, +0.11f * hollowFactorF, 0.0f);
  475. Vertex IQ2Q22 = new Vertex(+0.46f * hollowFactorF, +0.18f * hollowFactorF, 0.0f);
  476. Vertex IQ2Q23 = new Vertex(+0.43f * hollowFactorF, +0.24f * hollowFactorF, 0.0f);
  477. Vertex IQ2Q24 = new Vertex(+0.40f * hollowFactorF, +0.30f * hollowFactorF, 0.0f);
  478. Vertex IQ2Q25 = new Vertex(+0.35f * hollowFactorF, +0.35f * hollowFactorF, 0.0f);
  479. Vertex IQ2Q26 = new Vertex(+0.30f * hollowFactorF, +0.40f * hollowFactorF, 0.0f);
  480. Vertex IQ2Q27 = new Vertex(+0.24f * hollowFactorF, +0.43f * hollowFactorF, 0.0f);
  481. Vertex IQ2Q28 = new Vertex(+0.18f * hollowFactorF, +0.46f * hollowFactorF, 0.0f);
  482. Vertex IQ2Q29 = new Vertex(+0.11f * hollowFactorF, +0.48f * hollowFactorF, 0.0f);
  483. Vertex IQ1Q20 = new Vertex(+0.0f * hollowFactorF, +0.50f * hollowFactorF, 0.0f);
  484. Vertex IQ1Q21 = new Vertex(-0.11f * hollowFactorF, +0.48f * hollowFactorF, 0.0f);
  485. Vertex IQ1Q22 = new Vertex(-0.18f * hollowFactorF, +0.46f * hollowFactorF, 0.0f);
  486. Vertex IQ1Q23 = new Vertex(-0.24f * hollowFactorF, +0.43f * hollowFactorF, 0.0f);
  487. Vertex IQ1Q24 = new Vertex(-0.30f * hollowFactorF, +0.40f * hollowFactorF, 0.0f);
  488. Vertex IQ1Q25 = new Vertex(-0.35f * hollowFactorF, +0.35f * hollowFactorF, 0.0f);
  489. Vertex IQ1Q26 = new Vertex(-0.40f * hollowFactorF, +0.30f * hollowFactorF, 0.0f);
  490. Vertex IQ1Q27 = new Vertex(-0.43f * hollowFactorF, +0.24f * hollowFactorF, 0.0f);
  491. Vertex IQ1Q28 = new Vertex(-0.46f * hollowFactorF, +0.18f * hollowFactorF, 0.0f);
  492. Vertex IQ1Q29 = new Vertex(-0.48f * hollowFactorF, +0.11f * hollowFactorF, 0.0f);
  493. Vertex IQ1Q10 = new Vertex(-0.50f * hollowFactorF, +0.0f * hollowFactorF, 0.0f);
  494. Vertex IQ1Q11 = new Vertex(-0.48f * hollowFactorF, -0.11f * hollowFactorF, 0.0f);
  495. Vertex IQ1Q12 = new Vertex(-0.46f * hollowFactorF, -0.18f * hollowFactorF, 0.0f);
  496. Vertex IQ1Q13 = new Vertex(-0.43f * hollowFactorF, -0.24f * hollowFactorF, 0.0f);
  497. Vertex IQ1Q14 = new Vertex(-0.40f * hollowFactorF, -0.30f * hollowFactorF, 0.0f);
  498. //Counter clockwise around the quadrants
  499. SimpleHull holeHull = new SimpleHull();
  500. holeHull.AddVertex(IQ1Q15);
  501. holeHull.AddVertex(IQ1Q14);
  502. holeHull.AddVertex(IQ1Q13);
  503. holeHull.AddVertex(IQ1Q12);
  504. holeHull.AddVertex(IQ1Q11);
  505. holeHull.AddVertex(IQ1Q10);
  506. holeHull.AddVertex(IQ1Q29);
  507. holeHull.AddVertex(IQ1Q28);
  508. holeHull.AddVertex(IQ1Q27);
  509. holeHull.AddVertex(IQ1Q26);
  510. holeHull.AddVertex(IQ1Q25);
  511. holeHull.AddVertex(IQ1Q24);
  512. holeHull.AddVertex(IQ1Q23);
  513. holeHull.AddVertex(IQ1Q22);
  514. holeHull.AddVertex(IQ1Q21);
  515. holeHull.AddVertex(IQ1Q20);
  516. holeHull.AddVertex(IQ2Q29);
  517. holeHull.AddVertex(IQ2Q28);
  518. holeHull.AddVertex(IQ2Q27);
  519. holeHull.AddVertex(IQ2Q26);
  520. holeHull.AddVertex(IQ2Q25);
  521. holeHull.AddVertex(IQ2Q24);
  522. holeHull.AddVertex(IQ2Q23);
  523. holeHull.AddVertex(IQ2Q22);
  524. holeHull.AddVertex(IQ2Q21);
  525. holeHull.AddVertex(IQ2Q20);
  526. holeHull.AddVertex(IQ2Q19);
  527. holeHull.AddVertex(IQ2Q18);
  528. holeHull.AddVertex(IQ2Q17);
  529. holeHull.AddVertex(IQ2Q16);
  530. holeHull.AddVertex(IQ2Q15);
  531. holeHull.AddVertex(IQ2Q14);
  532. holeHull.AddVertex(IQ2Q13);
  533. holeHull.AddVertex(IQ2Q12);
  534. holeHull.AddVertex(IQ2Q11);
  535. holeHull.AddVertex(IQ2Q10);
  536. holeHull.AddVertex(IQ1Q19);
  537. holeHull.AddVertex(IQ1Q18);
  538. holeHull.AddVertex(IQ1Q17);
  539. holeHull.AddVertex(IQ1Q16);
  540. SimpleHull hollowedHull = SimpleHull.SubtractHull(outerHull, holeHull);
  541. outerHull = hollowedHull;
  542. }
  543. Mesh m = new Mesh();
  544. Vertex Seed1 = new Vertex(0.0f, -10.0f, 0.0f);
  545. Vertex Seed2 = new Vertex(-10.0f, 10.0f, 0.0f);
  546. Vertex Seed3 = new Vertex(10.0f, 10.0f, 0.0f);
  547. m.Add(Seed1);
  548. m.Add(Seed2);
  549. m.Add(Seed3);
  550. m.Add(new Triangle(Seed1, Seed2, Seed3));
  551. m.Add(outerHull.getVertices());
  552. InsertVertices(m.vertices, 3, m.triangles);
  553. m.DumpRaw(baseDir, primName, "Proto first Mesh");
  554. m.Remove(Seed1);
  555. m.Remove(Seed2);
  556. m.Remove(Seed3);
  557. m.DumpRaw(baseDir, primName, "Proto seeds removed");
  558. m.RemoveTrianglesOutside(outerHull);
  559. m.DumpRaw(baseDir, primName, "Proto outsides removed");
  560. foreach (Triangle t in m.triangles)
  561. {
  562. PhysicsVector n = t.getNormal();
  563. if (n.Z < 0.0)
  564. t.invertNormal();
  565. }
  566. Extruder extr = new Extruder();
  567. extr.size = size;
  568. if (taperX != 100)
  569. {
  570. if (taperX > 100)
  571. {
  572. extr.taperTopFactorX = 1.0f - ((float)taperX / 200);
  573. //m_log.Warn("taperTopFactorX: " + extr.taperTopFactorX.ToString());
  574. }
  575. else
  576. {
  577. extr.taperBotFactorX = 1.0f - ((100 - (float)taperX) / 100);
  578. //m_log.Warn("taperBotFactorX: " + extr.taperBotFactorX.ToString());
  579. }
  580. }
  581. if (taperY != 100)
  582. {
  583. if (taperY > 100)
  584. {
  585. extr.taperTopFactorY = 1.0f - ((float)taperY / 200);
  586. //m_log.Warn("taperTopFactorY: " + extr.taperTopFactorY.ToString());
  587. }
  588. else
  589. {
  590. extr.taperBotFactorY = 1.0f - ((100 - (float)taperY) / 100);
  591. //m_log.Warn("taperBotFactorY: " + extr.taperBotFactorY.ToString());
  592. }
  593. }
  594. if (pathShearX != 0)
  595. {
  596. if (pathShearX > 50)
  597. {
  598. // Complimentary byte. Negative values wrap around the byte. Positive values go up to 50
  599. extr.pushX = (((float)(256 - pathShearX) / 100) * -1f);
  600. //m_log.Warn("pushX: " + extr.pushX);
  601. }
  602. else
  603. {
  604. extr.pushX = (float)pathShearX / 100;
  605. //m_log.Warn("pushX: " + extr.pushX);
  606. }
  607. }
  608. if (pathShearY != 0)
  609. {
  610. if (pathShearY > 50)
  611. {
  612. // Complimentary byte. Negative values wrap around the byte. Positive values go up to 50
  613. extr.pushY = (((float)(256 - pathShearY) / 100) * -1f);
  614. //m_log.Warn("pushY: " + extr.pushY);
  615. }
  616. else
  617. {
  618. extr.pushY = (float)pathShearY / 100;
  619. //m_log.Warn("pushY: " + extr.pushY);
  620. }
  621. }
  622. Mesh result = extr.Extrude(m);
  623. result.DumpRaw(baseDir, primName, "Z extruded");
  624. return result;
  625. }
  626. public static void CalcNormals(Mesh mesh)
  627. {
  628. int iTriangles = mesh.triangles.Count;
  629. mesh.normals = new float[iTriangles*3];
  630. int i = 0;
  631. foreach (Triangle t in mesh.triangles)
  632. {
  633. float ux, uy, uz;
  634. float vx, vy, vz;
  635. float wx, wy, wz;
  636. ux = t.v1.X;
  637. uy = t.v1.Y;
  638. uz = t.v1.Z;
  639. vx = t.v2.X;
  640. vy = t.v2.Y;
  641. vz = t.v2.Z;
  642. wx = t.v3.X;
  643. wy = t.v3.Y;
  644. wz = t.v3.Z;
  645. // Vectors for edges
  646. float e1x, e1y, e1z;
  647. float e2x, e2y, e2z;
  648. e1x = ux - vx;
  649. e1y = uy - vy;
  650. e1z = uz - vz;
  651. e2x = ux - wx;
  652. e2y = uy - wy;
  653. e2z = uz - wz;
  654. // Cross product for normal
  655. float nx, ny, nz;
  656. nx = e1y*e2z - e1z*e2y;
  657. ny = e1z*e2x - e1x*e2z;
  658. nz = e1x*e2y - e1y*e2x;
  659. // Length
  660. float l = (float) Math.Sqrt(nx*nx + ny*ny + nz*nz);
  661. // Normalized "normal"
  662. nx /= l;
  663. ny /= l;
  664. nz /= l;
  665. mesh.normals[i] = nx;
  666. mesh.normals[i + 1] = ny;
  667. mesh.normals[i + 2] = nz;
  668. i += 3;
  669. }
  670. }
  671. public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, PhysicsVector size)
  672. {
  673. Mesh mesh = null;
  674. switch (primShape.ProfileShape)
  675. {
  676. case ProfileShape.Square:
  677. mesh = CreateBoxMesh(primName, primShape, size);
  678. CalcNormals(mesh);
  679. break;
  680. case ProfileShape.Circle:
  681. if (primShape.PathCurve == (byte)Extrusion.Straight)
  682. {
  683. mesh = CreateCyllinderMesh(primName, primShape, size);
  684. CalcNormals(mesh);
  685. }
  686. break;
  687. default:
  688. mesh = CreateBoxMesh(primName, primShape, size);
  689. CalcNormals(mesh);
  690. //Set default mesh to cube otherwise it'll return
  691. // null and crash on the 'setMesh' method in the physics plugins.
  692. //mesh = null;
  693. break;
  694. }
  695. return mesh;
  696. }
  697. }
  698. }