public static Csgjs CreateSphere(Vector3 center, Vector3 size, out List <CsgSurfaceSharedData> surfaces)
        {
            size *= 0.5f;

            float            slices   = 16;
            float            stacks   = 8;
            var              polygons = new List <CsgPolygon>();
            List <CsgVertex> vertices = null;

            void AddVertex(float theta, float phi)
            {
                Vector2 uvs = new Vector2(theta, phi);

                theta *= Mathf.Pi * 2;
                theta += Mathf.PiOverTwo;
                phi   *= Mathf.Pi;
                var dir = new Vector3(
                    Mathf.Cos(theta) * Mathf.Sin(phi),
                    Mathf.Cos(phi),
                    Mathf.Sin(theta) * Mathf.Sin(phi)
                    );

                vertices.Add(new CsgVertex(center + dir * size, dir, uvs));
            }

            var sphereSurface = new CsgSurfaceSharedData("Sphere");

            for (var i = 0; i < slices; i++)
            {
                for (var j = 0; j < stacks; j++)
                {
                    vertices = new List <CsgVertex>();
                    AddVertex(i / slices, j / stacks);
                    if (j > 0)
                    {
                        AddVertex((i + 1) / slices, j / stacks);
                    }
                    if (j < stacks - 1)
                    {
                        AddVertex((i + 1) / slices, (j + 1) / stacks);
                    }
                    AddVertex(i / slices, (j + 1) / stacks);
                    polygons.Add(new CsgPolygon(vertices, sphereSurface));
                }
            }

            surfaces = new List <CsgSurfaceSharedData>(1)
            {
                sphereSurface
            };

            var csg = FromPolygons(polygons);

            // And set the shared data
            for (int i = 0; i < surfaces.Count; i++)
            {
                surfaces[i].Csgjs = csg;
            }
            return(csg);
        }
 public CsgPolygon(List <CsgVertex> vertices, CsgSurfaceSharedData shared = null, CsgPlane plane = null)
 {
     Vertices = vertices;
     Shared   = shared;
     Plane    = plane?.Clone() ?? CsgPlane.FromPoints(vertices);
 }
        public static Csgjs CreateCube(Vector3 center, Vector3 size, out List <CsgSurfaceSharedData> surfaces)
        {
            size *= 0.5f;
            Vector3[] normals = new[]
            {
                new Vector3(-1, 0, 0),
                new Vector3(+1, 0, 0),
                new Vector3(0, -1, 0),
                new Vector3(0, +1, 0),
                new Vector3(0, 0, -1),
                new Vector3(0, 0, +1)
            };
            string[] names = new[]
            {
                "Back",
                "Front",
                "Bottom",
                "Top",
                "Left",
                "Right"
            };

            Vector2[] uvs = new[]
            {
                new Vector2(1, 1),
                new Vector2(1, 0),
                new Vector2(0, 0),
                new Vector2(0, 1)
            };

            int[][] faces = new[]
            {
                new int[] { 0, 4, 6, 2 },
                new int[] { 5, 1, 3, 7 }, //
                new int[] { 0, 1, 5, 4 },
                new int[] { 3, 2, 6, 7 }, //
                new int[] { 1, 0, 2, 3 }, //
                new int[] { 4, 5, 7, 6 },
            };

            var cubeSurfaces = new List <CsgSurfaceSharedData>(faces.Length);
            var polygons     = faces
                               .Select((face, index) =>
            {
                var vertices = face.Select((i, j) =>
                {
                    Vector3 pos = center + size * new Vector3(
                        2 * (((i & 1) == 0) ? 0 : 1) - 1,
                        2 * (((i & 2) == 0) ? 0 : 1) - 1,
                        2 * (((i & 4) == 0) ? 0 : 1) - 1
                        );
                    return(new CsgVertex(pos, normals[index], uvs[j]));
                }).ToList();

                var surface = new CsgSurfaceSharedData(names[index]);
                cubeSurfaces.Add(surface);
                return(new CsgPolygon(vertices, surface));
            })
                               .ToList();

            surfaces = cubeSurfaces;

            var csg = FromPolygons(polygons);

            // And set the shared data
            for (int i = 0; i < surfaces.Count; i++)
            {
                surfaces[i].Csgjs = csg;
            }
            return(csg);
        }
        public static Csgjs CreateCylinder(Vector3 start, Vector3 end, Vector3 size, out List <CsgSurfaceSharedData> surfaces)
        {
            size *= 0.5f;

            // TODO: This does not entirely make sense for cylinders with arbitrary start and end coordinates
            start *= size.Y;
            end   *= size.Y;

            Vector3 ray          = end - start;
            float   slices       = 16;
            Vector3 axisZ        = ray.Normalized;
            bool    isY          = (Mathf.Abs(axisZ.Y) > 0.5);
            Vector3 axisX        = Vector3.Cross(new Vector3(isY ? 1 : 0, (!isY) ? 1 : 0, 0), axisZ).Normalized;
            Vector3 axisY        = Vector3.Cross(axisX, axisZ).Normalized;
            Vector3 negatedAxisZ = axisZ;

            negatedAxisZ.Negate();
            var startVertex = new CsgVertex(start, negatedAxisZ, Vector2.One * 0.5f);
            var endVertex   = new CsgVertex(end, axisZ, Vector2.One * 0.5f);

            var polygons = new List <CsgPolygon>();

            CsgVertex CreatePoint(float stack, float slice, float normalBlend, bool isSide = true)
            {
                var     angle     = slice * Mathf.Pi * 2;
                var     outVector = axisX * Mathf.Cos(angle) + axisY * Mathf.Sin(angle);
                var     pos       = start + ray * stack + outVector * size;
                var     normal    = outVector * (1 - Mathf.Abs(normalBlend)) + axisZ * normalBlend;
                Vector2 uv;

                if (isSide)
                {
                    uv = new Vector2(slice, stack);
                }
                else
                {
                    uv = new Vector2(1f - (Mathf.Cos(angle) + 1f) * 0.5f, (Mathf.Sin(angle) + 1f) * 0.5f);
                }

                return(new CsgVertex(pos, normal, uv));
            }

            var topSurface    = new CsgSurfaceSharedData("Top");
            var sideSurface   = new CsgSurfaceSharedData("Side");
            var bottomSurface = new CsgSurfaceSharedData("Bottom");

            for (var i = 0; i < slices; i++)
            {
                float t0 = i / slices;
                float t1 = (i + 1) / slices;
                // Top triangle
                polygons.Add(new CsgPolygon(new List <CsgVertex>()
                {
                    startVertex.Clone(), CreatePoint(0, t0, -1, false), CreatePoint(0, t1, -1, false)
                }, topSurface));
                // Side rectangle
                polygons.Add(new CsgPolygon(new List <CsgVertex>()
                {
                    CreatePoint(0, t1, 0), CreatePoint(0, t0, 0), CreatePoint(1, t0, 0), CreatePoint(1, t1, 0)
                }, sideSurface));
                // Bottom triangle
                polygons.Add(new CsgPolygon(new List <CsgVertex>()
                {
                    endVertex.Clone(), CreatePoint(1, t1, 1, false), CreatePoint(1, t0, 1, false)
                }, bottomSurface));
            }

            surfaces = new List <CsgSurfaceSharedData>(1)
            {
                topSurface,
                sideSurface,
                bottomSurface
            };
            var csg = FromPolygons(polygons);

            // And set the shared data
            for (int i = 0; i < surfaces.Count; i++)
            {
                surfaces[i].Csgjs = csg;
            }
            return(csg);
        }