public void Init(RoadSegment p, RoadSegmentValues vals, MeshCrossection shape, Material mat)
    {
        this.parentScript     = p;
        this.values           = vals;
        this.materialToAssign = mat;
        this.shape2D          = shape;

        GenerateMeshAndInit();
    }
    public override void OnInspectorGUI()
    {
        mCross = target as MeshCrossection;

        if (GUILayout.Button("Set Normals"))
        {
            Undo.RecordObject(mCross, "SetNormals");
            mCross.SetNormals();
            EditorUtility.SetDirty(mCross);
        }
        base.OnInspectorGUI();
    }
    public void GenerateMeshAndInit(bool useScaleAsOffset = false, MeshCrossection parentC = null)
    {
        if (subMeshes != null)
        {
            for (int i = 0; i < subMeshes.Count; i++)
            {
                subMeshes[i].GenerateMeshAndInit(!scaleSubmeshes, shape2D);
            }
        }

        values.mesh      = new Mesh();
        values.mesh.name = "GeneratedMesh";
        GetComponent <MeshFilter>().sharedMesh   = values.mesh;
        GetComponent <MeshCollider>().sharedMesh = values.mesh;

        SetMeshMaterial();

        GenerateMesh(useScaleAsOffset, parentC);
    }
    public void CreateNewSubmesh()
    {
        GameObject         go      = new GameObject();
        RoadSegmentSubmesh submesh = go.AddComponent <RoadSegmentSubmesh>();

        submesh.Init(this, values, newShape, newMaterial);
        go.transform.parent        = transform;
        go.transform.localRotation = Quaternion.identity;
        go.transform.localPosition = Vector3.zero;
        newShape    = null;
        newMaterial = null;

        if (subMeshes == null)
        {
            subMeshes = new List <RoadSegmentSubmesh>();
        }

        subMeshes.Add(submesh);
    }
    public void DisplayMeshMenu()
    {
        EditorGUILayout.BeginHorizontal();
        GUILayout.Label("Base road mesh: ");
        MeshCrossection shape = values.road.shape2D;

        shape = EditorGUILayout.ObjectField(values.road.shape2D, typeof(MeshCrossection), true) as MeshCrossection;
        if (shape != values.road.shape2D)
        {
            values.road.shape2D = shape;
            if (values.road.materialToAssign != null)
            {
                values.road.GenerateMeshAndInit();
            }
        }
        EditorGUILayout.EndHorizontal();
        EditorGUILayout.BeginHorizontal();
        GUILayout.Label("Base road material: ");
        Material m = values.road.materialToAssign;

        m = EditorGUILayout.ObjectField(values.road.materialToAssign, typeof(Material), false) as Material;
        if (m != values.road.materialToAssign)
        {
            values.road.materialToAssign = m;
            if (values.road.shape2D != null)
            {
                values.road.GenerateMeshAndInit();
            }
        }
        EditorGUILayout.EndHorizontal();
        // add in submeshes when buttons are pressed

        if (values.isAssigningSubmesh)
        {
            GUILayout.Label("");
            EditorGUI.indentLevel++;
            EditorGUILayout.BeginHorizontal();
            GUILayout.Label("New submesh: ");
            MeshCrossection s = values.newShapeToAdd;
            s = EditorGUILayout.ObjectField(values.newShapeToAdd, typeof(MeshCrossection), false) as MeshCrossection;
            if (s != values.newShapeToAdd)
            {
                values.newShapeToAdd = s;
            }
            EditorGUILayout.EndHorizontal();

            EditorGUILayout.BeginHorizontal();
            GUILayout.Label("Submesh material: ");
            Material mN = values.newMaterialToAdd;
            mN = EditorGUILayout.ObjectField(values.newMaterialToAdd, typeof(Material), false) as Material;
            if (mN != values.newMaterialToAdd)
            {
                values.newMaterialToAdd = mN;
            }
            EditorGUILayout.EndHorizontal();
            EditorGUILayout.BeginHorizontal();
            if (values.newShapeToAdd == null || values.newMaterialToAdd == null)
            {
                EditorGUILayout.HelpBox("Make sure you assign a new MeshCrossection AND a new material.", MessageType.Error);
            }
            else
            {
                if (GUILayout.Button("Add submesh", GUILayout.Height(bigButtonHeight)))
                {
                    values.road.AddNewSubmesh(values.newShapeToAdd, values.newMaterialToAdd);
                    values.isAssigningSubmesh = false;
                }
            }
            if (GUILayout.Button("Cancel", GUILayout.Height(bigButtonHeight)))
            {
                values.isAssigningSubmesh = false;
            }
            EditorGUILayout.EndHorizontal();
            EditorGUI.indentLevel--;
        }
        else
        {
            EditorGUILayout.BeginVertical();
            EditorGUILayout.BeginHorizontal();
            GUILayout.FlexibleSpace();
            if (GUILayout.Button("Add new submesh", GUILayout.Height(smallButtonHeight), GUILayout.Width(smallButtonWidth)))
            {
                values.isAssigningSubmesh = true;
            }
            GUILayout.FlexibleSpace();
            EditorGUILayout.EndHorizontal();
            EditorGUILayout.EndVertical();
        }
        GUILayout.Label("");
    }
    private void GenerateMesh(bool useScaleAsOffset = false, MeshCrossection parentC = null)
    {
        values.mesh.Clear();

        float          uSpan   = shape2D.GetLinesLength();
        List <Vector3> verts   = new List <Vector3>();
        List <Vector3> normals = new List <Vector3>();
        List <Vector2> uvs     = new List <Vector2>();

        for (int currentEdgeRing = 0; currentEdgeRing < values.edgeRingCount; currentEdgeRing++)
        {
            float splineLength = values.spline.GetSplineLength(10f);
            float t            = currentEdgeRing / (values.edgeRingCount - 1f);

            if (values.scaleToEnd)
            {
                values.scale = Mathf.Lerp(values.scaleAtStart, values.scaleAtEnd, t);
            }
            else if (values.scaleByCurve)
            {
                values.scale = values.scaleCurve.Evaluate(t);
            }
            else
            {
                values.scale = values.scaleAtStart;
            }

            values.scaleToEnd = (values.scaleAtEnd != values.scaleAtStart);

            float         multiplier = (values.useMultiplier) ? values.scale : 1f;
            OrientedPoint op         = values.spline.GetOrientedPoint(t);

            Vector3 innerNeg = new Vector3();
            Vector3 innerPos = new Vector3();

            if (scaleSubmeshes && parentC != null)
            {
                int   inNeg = -1;
                int   inPos = -1;
                float inP   = 100000f;
                float inN   = -100000f;
                for (int u = 0; u < parentC.VertexCount; u++)
                {
                    float xpos = parentC.vertices[u].point.x;
                    if (xpos >= inN)
                    {
                        inN   = xpos;
                        inNeg = u;
                    }
                    if (xpos <= inP)
                    {
                        inP   = xpos;
                        inPos = u;
                    }
                }

                innerNeg = parentC.vertices[inNeg].point * transform.lossyScale;
                innerPos = parentC.vertices[inPos].point * transform.lossyScale;
            }

            for (int i = 0; i < shape2D.VertexCount; i++)
            {
                Vector3 p = (Vector3)(shape2D.vertices[i].point);

                if (!useScaleAsOffset)
                {
                    p.x = ((values.scaleX) ? p.x * values.scale : p.x) * transform.lossyScale.x;
                    p.y = ((values.scaleY) ? p.y * values.scale : p.y) * transform.lossyScale.y;
                    p.z = ((values.scaleZ) ? p.z * values.scale : p.z) * transform.lossyScale.z;
                }
                else
                {
                    p.x = (p.x == 0) ? p.x : ((p.x < 0) ? p.x - values.scale : p.x + values.scale) * transform.lossyScale.x;
                    p.y = ((values.scaleY) ? p.y * values.scale : p.y) * transform.lossyScale.y;
                    p.z = ((values.scaleZ) ? p.z * values.scale : p.z) * transform.lossyScale.z;
                    if (p.x < 0)
                    {
                        float o = (innerNeg * values.scale).x;
                        p.x = (p.x - o) + innerNeg.x + (values.scale * transform.lossyScale.x);
                    }
                    else if (p.x > 0)
                    {
                        float o = (innerPos * values.scale).x;
                        p.x = (p.x - o) + innerPos.x - (values.scale * transform.lossyScale.x);
                    }
                }
                verts.Add(transform.InverseTransformPoint(op.LocalToWorldPosition(p * multiplier) + values.localOffset));

                normals.Add(op.LocalToWorldVector((Vector3)(shape2D.vertices[i].normal)));

                uvs.Add(
                    new Vector2(values.uvOffset.x + (currentEdgeRing / (float)values.edgeRingCount - 1) *
                                values.uMultiplier, values.uvOffset.y + (i / (float)shape2D.VertexCount) *
                                splineLength / uSpan * (1 / values.uvRepeatScale)
                                ));
            }
        }

        List <int> triangleIndices = new List <int>();

        for (int r = 0; r < values.edgeRingCount - 1; r++)
        {
            int rootIndex     = r * shape2D.VertexCount;
            int rootIndexNext = (r + 1) * shape2D.VertexCount;

            for (int l = 0; l < shape2D.LineCount; l += 2)
            {
                int lineIndexA = shape2D.lines[l];
                int lineIndexB = shape2D.lines[l + 1];

                int currentA = rootIndex + lineIndexA;
                int currentB = rootIndex + lineIndexB;

                int nextA = rootIndexNext + lineIndexA;
                int nextB = rootIndexNext + lineIndexB;

                // tri 1
                triangleIndices.Add(currentA);
                triangleIndices.Add(nextA);
                triangleIndices.Add(nextB);
                // tri 2
                triangleIndices.Add(currentA);
                triangleIndices.Add(nextB);
                triangleIndices.Add(currentB);
            }
        }

        values.mesh.SetVertices(verts);
        values.mesh.SetNormals(normals);
        values.mesh.SetTriangles(triangleIndices, 0);
        values.mesh.RecalculateBounds();
        values.mesh.RecalculateNormals();
        values.mesh.RecalculateTangents();
        values.mesh.uv = uvs.ToArray();
        GetComponent <MeshCollider>().sharedMesh = values.mesh;
        gameObject.layer = values.layerToAssign;
    }
 public void AddNewSubmesh(MeshCrossection m, Material mat)
 {
     newShape    = m;
     newMaterial = mat;
     CreateNewSubmesh();
 }