using System; using UnityEngine; [AddComponentMenu("MegaShapes/Hose New")] [ExecuteInEditMode] [RequireComponent(typeof(MeshFilter))] [RequireComponent(typeof(MeshRenderer))] public class MegaHoseNew : MonoBehaviour { public bool freecreate = true; public bool updatemesh = true; private const float HalfIntMax = 16383.5f; private const float PIover2 = (float)Math.PI / 2f; private const float EPSILON = 0.0001f; public MegaSpline hosespline = new MegaSpline(); private Mesh mesh; public Vector3[] verts = new Vector3[1]; public Vector2[] uvs = new Vector2[1]; public int[] faces = new int[1]; public Vector3[] normals; public bool optimize; public bool calctangents; public bool recalcCollider; public bool calcnormals; public bool capends = true; public GameObject custnode2; public GameObject custnode; public Vector3 offset = Vector3.zero; public Vector3 offset1 = Vector3.zero; public Vector3 rotate = Vector3.zero; public Vector3 rotate1 = Vector3.zero; public Vector3 scale = Vector3.one; public Vector3 scale1 = Vector3.one; public int endsmethod; public float noreflength = 1f; public int segments = 45; public MegaHoseSmooth smooth; public MegaHoseType wiretype; public float rnddia = 0.2f; public int rndsides = 8; public float rndrot; public float rectwidth = 0.2f; public float rectdepth = 0.2f; public float rectfillet; public int rectfilletsides; public float rectrotangle; public float dsecwidth = 0.2f; public float dsecdepth = 0.2f; public float dsecfillet; public int dsecfilletsides; public int dsecrndsides = 4; public float dsecrotangle; public bool mapmemapme = true; public bool flexon; public float flexstart = 0.1f; public float flexstop = 0.9f; public int flexcycles = 5; public float flexdiameter = -0.2f; public float tension1 = 10f; public float tension2 = 10f; public bool usebulgecurve; public AnimationCurve bulge = new AnimationCurve(new Keyframe(0f, 0f), new Keyframe(1f, 0f)); public float bulgeamount = 1f; public float bulgeoffset; public Vector2 uvscale = Vector2.one; public bool animatebulge; public float bulgespeed; public float minbulge = -1f; public float maxbulge = 2f; public bool usesizecurve; public AnimationCurve size = new AnimationCurve(new Keyframe(0f, 1f), new Keyframe(1f, 1f)); public bool displayspline = true; private bool visible = true; public bool InvisibleUpdate; public bool dolateupdate; private Vector3 endp1 = Vector3.zero; private Vector3 endp2 = Vector3.zero; private Vector3 endr1 = Vector3.zero; private Vector3 endr2 = Vector3.zero; public Vector3[] SaveVertex; public Vector2[] SaveUV; public Vector3[] SaveNormals; public bool rebuildcross = true; public int NvertsPerRing; public int Nverts; public Vector3 up = Vector3.up; private Vector3 starty = Vector3.zero; public Matrix4x4 Tlocal = Matrix4x4.identity; private Matrix4x4 wtm1; private MeshCollider meshCol; [ContextMenu("Help")] public void Help() { Application.OpenURL("http://www.west-racing.com/mf/?page_id=3436"); } private void Awake() { updatemesh = true; rebuildcross = true; Rebuild(); } private void Reset() { Rebuild(); } private void OnBecameVisible() { visible = true; } private void OnBecameInvisible() { visible = false; } public void SetEndTarget(int end, GameObject target) { if (end == 0) { custnode = target; } else { custnode2 = target; } updatemesh = true; } public void Rebuild() { MeshFilter component = GetComponent(); if (component != null) { Mesh mesh = component.sharedMesh; if (mesh == null) { mesh = (component.sharedMesh = new Mesh()); } if (mesh != null) { BuildMesh(); } } } private void MakeSaveVertex(int NvertsPerRing, int nfillets, int nsides, MegaHoseType wtype) { switch (wtype) { case MegaHoseType.Round: { float num31 = (float)Math.PI * 2f / (float)(NvertsPerRing - 1); float num32 = rnddia; num32 *= 0.5f; for (int m = 0; m < NvertsPerRing; m++) { float f5 = (float)(m + 1) * num31; SaveVertex[m] = new Vector3(num32 * Mathf.Cos(f5), num32 * Mathf.Sin(f5), 0f); } break; } case MegaHoseType.Rectangle: { int num17 = 0; int num18 = 1 + nfillets; int num19 = 2 * num18; int num20 = num18 + num19; float num21 = rectwidth * 0.5f; float num22 = rectdepth * 0.5f; float num23 = rectfillet; if (num23 < 0f) { num23 = 0f; } if (nfillets > 0) { float num24 = num21 - num23; float num25 = num22 - num23; float num26 = 0f - num24; float num27 = 0f - num25; SaveVertex[0] = new Vector3(num21, num25, 0f); SaveVertex[nfillets] = new Vector3(num24, num22, 0f); SaveVertex[num18] = new Vector3(num26, num22, 0f); SaveVertex[num18 + nfillets] = new Vector3(0f - num21, num25, 0f); SaveVertex[num19] = new Vector3(0f - num21, num27, 0f); SaveVertex[num19 + nfillets] = new Vector3(num26, 0f - num22, 0f); SaveVertex[num20] = new Vector3(num24, 0f - num22, 0f); SaveVertex[num20 + nfillets] = new Vector3(num21, num27, 0f); if (nfillets > 1) { float num28 = (float)Math.PI / 2f / (float)nfillets; num17 = 1; for (int l = 0; l < nfillets - 1; l++) { float f4 = (float)(l + 1) * num28; float num29 = num23 * Mathf.Cos(f4); float num30 = num23 * Mathf.Sin(f4); SaveVertex[num17] = new Vector3(num24 + num29, num25 + num30, 0f); SaveVertex[num17 + num18] = new Vector3(num26 - num30, num25 + num29, 0f); SaveVertex[num17 + num19] = new Vector3(num26 - num29, num27 - num30, 0f); SaveVertex[num17 + num20] = new Vector3(num24 + num30, num27 - num29, 0f); num17++; } } SaveVertex[SaveVertex.Length - 1] = SaveVertex[0]; } else if (smooth == MegaHoseSmooth.SMOOTHNONE) { SaveVertex[num17++] = new Vector3(num21, num22, 0f); SaveVertex[num17++] = new Vector3(0f - num21, num22, 0f); SaveVertex[num17++] = new Vector3(0f - num21, num22, 0f); SaveVertex[num17++] = new Vector3(0f - num21, 0f - num22, 0f); SaveVertex[num17++] = new Vector3(0f - num21, 0f - num22, 0f); SaveVertex[num17++] = new Vector3(num21, 0f - num22, 0f); SaveVertex[num17++] = new Vector3(num21, 0f - num22, 0f); SaveVertex[num17++] = new Vector3(num21, num22, 0f); } else { SaveVertex[num17++] = new Vector3(num21, num22, 0f); SaveVertex[num17++] = new Vector3(0f - num21, num22, 0f); SaveVertex[num17++] = new Vector3(0f - num21, 0f - num22, 0f); SaveVertex[num17++] = new Vector3(num21, 0f - num22, 0f); SaveVertex[num17++] = new Vector3(num21, num22, 0f); } break; } default: { int num = 0; float num2 = (float)Math.PI / (float)nsides; float num3 = dsecwidth * 0.5f; float num4 = dsecdepth * 0.5f; float num5 = dsecfillet; if (num5 < 0f) { num5 = 0f; } float num6 = num4 - num3; if (nfillets > 0) { float num7 = num4 - num5; float num8 = 0f - num7; float num9 = num3 - num5; int num10 = 1 + nfillets; int num11 = num10 + 1 + nsides; SaveVertex[0] = new Vector3(num3, num7, 0f); SaveVertex[nfillets] = new Vector3(num9, num4, 0f); SaveVertex[num10] = new Vector3(num6, num4, 0f); SaveVertex[num10 + nsides] = new Vector3(num6, 0f - num4, 0f); SaveVertex[num11] = new Vector3(num9, 0f - num4, 0f); SaveVertex[num11 + nfillets] = new Vector3(num3, num8, 0f); if (nfillets > 1) { float num12 = (float)Math.PI / 2f / (float)nfillets; num = 1; for (int i = 0; i < nfillets - 1; i++) { float f = (float)(i + 1) * num12; float num13 = num5 * Mathf.Cos(f); float num14 = num5 * Mathf.Sin(f); SaveVertex[num] = new Vector3(num9 + num13, num7 + num14, 0f); SaveVertex[num + num11] = new Vector3(num9 + num14, num8 - num13, 0f); num++; } } num = 1 + num10; for (int j = 0; j < nsides - 1; j++) { float f2 = (float)(j + 1) * num2; float y = num4 * Mathf.Cos(f2); float num15 = num4 * Mathf.Sin(f2); SaveVertex[num] = new Vector3(num6 - num15, y, 0f); num++; } } else { SaveVertex[num] = new Vector3(num3, num4, 0f); num++; SaveVertex[num] = new Vector3(num6, num4, 0f); num++; for (int k = 0; k < nsides - 1; k++) { float f3 = (float)(k + 1) * num2; float y2 = num4 * Mathf.Cos(f3); float num16 = num4 * Mathf.Sin(f3); SaveVertex[num] = new Vector3(num6 - num16, y2, 0f); num++; } SaveVertex[num] = new Vector3(num6, 0f - num4, 0f); num++; SaveVertex[num] = new Vector3(num3, 0f - num4, 0f); num++; } SaveVertex[SaveVertex.Length - 1] = SaveVertex[0]; break; } } float num33 = 0f; Vector3 vector = Vector3.zero; for (int n = 0; n < NvertsPerRing; n++) { if (n > 0) { num33 += (SaveVertex[n] - vector).magnitude; } SaveUV[n] = new Vector2(0f, num33 * uvscale.y); vector = SaveVertex[n]; } for (int num34 = 0; num34 < NvertsPerRing; num34++) { SaveUV[num34].y /= num33; } float num35 = 0f; switch (wtype) { case MegaHoseType.Round: num35 = rndrot; break; case MegaHoseType.Rectangle: num35 = rectrotangle; break; case MegaHoseType.DSection: num35 = dsecrotangle; break; } if (num35 != 0f) { num35 *= (float)Math.PI / 180f; float num36 = Mathf.Cos(num35); float num37 = Mathf.Sin(num35); for (int num38 = 0; num38 < NvertsPerRing; num38++) { float x = SaveVertex[num38].x * num36 - SaveVertex[num38].y * num37; float y3 = SaveVertex[num38].x * num37 + SaveVertex[num38].y * num36; SaveVertex[num38].x = x; SaveVertex[num38].y = y3; } } if (calcnormals) { for (int num39 = 0; num39 < NvertsPerRing; num39++) { int num40 = (num39 + 1) % NvertsPerRing; Vector3 normalized = (SaveVertex[num40] - SaveVertex[num39]).normalized; SaveNormals[num39] = new Vector3(normalized.y, 0f - normalized.x, 0f); } } } private void FixHoseFillet() { float f = rectwidth; float f2 = rectdepth; float num = rectfillet; float num2 = 0.5f * Mathf.Abs(f2); float num3 = 0.5f * Mathf.Abs(f); float num4 = ((!(num2 > num3)) ? num2 : num3); if (num > num4) { rectfillet = num4; } } private float RND11() { float num = UnityEngine.Random.Range(0f, 32768f) - 16383.5f; return num / 16383.5f; } private void Mult1X3(Vector3 A, Matrix4x4 B, ref Vector3 C) { C[0] = A[0] * B[0, 0] + A[1] * B[0, 1] + A[2] * B[0, 2]; C[1] = A[0] * B[1, 0] + A[1] * B[1, 1] + A[2] * B[1, 2]; C[2] = A[0] * B[2, 0] + A[1] * B[2, 1] + A[2] * B[2, 2]; } private void Mult1X4(Vector4 A, Matrix4x4 B, ref Vector4 C) { C[0] = A[0] * B[0, 0] + A[1] * B[0, 1] + A[2] * B[0, 2] + A[3] * B[0, 3]; C[1] = A[0] * B[1, 0] + A[1] * B[1, 1] + A[2] * B[1, 2] + A[3] * B[1, 3]; C[2] = A[0] * B[2, 0] + A[1] * B[2, 1] + A[2] * B[2, 2] + A[3] * B[2, 3]; C[3] = A[0] * B[3, 0] + A[1] * B[3, 1] + A[2] * B[3, 2] + A[3] * B[3, 3]; } private void SetUpRotation(Vector3 Q, Vector3 W, float Theta, ref Matrix4x4 Rq) { Vector3 C = Vector3.zero; Matrix4x4 identity = Matrix4x4.identity; float num = W[0] * W[0]; float num2 = W[1] * W[1]; float num3 = W[2] * W[2]; float num4 = W[0] * W[1]; float num5 = W[0] * W[2]; float num6 = W[1] * W[2]; float num7 = Mathf.Cos(Theta); float num8 = 1f - num7; float num9 = Mathf.Sin(Theta); identity[0, 0] = num + (1f - num) * num7; identity[1, 0] = num4 * num8 + W[2] * num9; identity[2, 0] = num5 * num8 - W[1] * num9; identity[0, 1] = num4 * num8 - W[2] * num9; identity[1, 1] = num2 + (1f - num2) * num7; identity[2, 1] = num6 * num8 + W[0] * num9; identity[0, 2] = num5 * num8 + W[1] * num9; identity[1, 2] = num6 * num8 - W[0] * num9; identity[2, 2] = num3 + (1f - num3) * num7; Mult1X3(Q, identity, ref C); Rq.SetColumn(0, identity.GetColumn(0)); Rq.SetColumn(1, identity.GetColumn(1)); Rq.SetColumn(2, identity.GetColumn(2)); Rq[0, 3] = Q[0] - C.x; Rq[1, 3] = Q[1] - C.y; Rq[2, 3] = Q[2] - C.z; float num10 = (Rq[3, 2] = 0f); num10 = (Rq[3, 1] = num10); Rq[3, 0] = num10; Rq[3, 3] = 1f; } private void RotateOnePoint(ref Vector3 Pin, Vector3 Q, Vector3 W, float Theta) { Matrix4x4 Rq = Matrix4x4.identity; Vector4 C = Vector3.zero; SetUpRotation(Q, W, Theta, ref Rq); Vector4 a = Pin; a[3] = 1f; Mult1X4(a, Rq, ref C); Pin = C; } private void Update() { if (animatebulge) { bulgeoffset += bulgespeed * Time.deltaTime; if (bulgeoffset > maxbulge) { bulgeoffset -= maxbulge - minbulge; } if (bulgeoffset < minbulge) { bulgeoffset += maxbulge - minbulge; } updatemesh = true; } if ((bool)custnode) { if (custnode.transform.position != endp1) { endp1 = custnode.transform.position; updatemesh = true; } if (custnode.transform.eulerAngles != endr1) { endr1 = custnode.transform.eulerAngles; updatemesh = true; } } if ((bool)custnode2) { if (custnode2.transform.position != endp2) { endp1 = custnode2.transform.position; updatemesh = true; } if (custnode2.transform.eulerAngles != endr2) { endr2 = custnode2.transform.eulerAngles; updatemesh = true; } } if (!dolateupdate && (visible || InvisibleUpdate) && updatemesh) { updatemesh = false; BuildMesh(); } } private void LateUpdate() { if (dolateupdate && (visible || InvisibleUpdate) && updatemesh) { updatemesh = false; BuildMesh(); } } private void CalcSpline() { starty = custnode.transform.up; Quaternion quaternion = custnode.transform.rotation * Quaternion.Euler(rotate); Quaternion quaternion2 = custnode2.transform.rotation * Quaternion.Euler(rotate1); Vector3 vector = tension1 * (quaternion * Vector3.forward); Vector3 vector2 = tension2 * (quaternion2 * Vector3.forward); Vector3 vector3 = base.transform.worldToLocalMatrix.MultiplyPoint3x4(custnode.transform.position + custnode.transform.TransformDirection(offset)); Vector3 vector4 = base.transform.worldToLocalMatrix.MultiplyPoint3x4(custnode2.transform.position + custnode2.transform.TransformDirection(offset1)); hosespline.knots[0].p = vector3; hosespline.knots[0].invec = vector3 - vector; hosespline.knots[0].outvec = vector3 + vector; hosespline.knots[1].p = vector4; hosespline.knots[1].invec = vector4 + vector2; hosespline.knots[1].outvec = vector4 - vector2; hosespline.CalcLength(); } public Matrix4x4 GetSplineMat(MegaSpline spline, float alpha, bool interp, ref Vector3 lastup) { int k = -1; Vector3 p = spline.InterpCurve3D(alpha, interp, ref k); alpha += 0.01f; if (spline.closed) { alpha %= 1f; } Vector3 forward = spline.InterpCurve3D(alpha, interp, ref k); Vector3 vector = default(Vector3); forward.x = (vector.x = forward.x - p.x); forward.y = (vector.y = forward.y - p.y); forward.z = (vector.z = forward.z - p.z); MegaMatrix.SetTR(ref wtm1, p, Quaternion.LookRotation(forward, lastup)); vector = vector.normalized; Vector3 lhs = Vector3.Cross(vector, lastup); lastup = Vector3.Cross(lhs, vector); return wtm1; } private void BuildMesh() { if (!mesh) { mesh = GetComponent().sharedMesh; if (mesh == null) { updatemesh = true; return; } } if (hosespline.knots.Count == 0) { hosespline.AddKnot(Vector3.zero, Vector3.zero, Vector3.zero); hosespline.AddKnot(Vector3.zero, Vector3.zero, Vector3.zero); } FixHoseFillet(); bool flag = freecreate; if (!flag && (!custnode || !custnode2)) { flag = true; } if ((bool)custnode && (bool)custnode2) { flag = false; } float num = 0f; Tlocal = Matrix4x4.identity; starty = Vector3.zero; if (flag) { num = noreflength; } else { starty = custnode.transform.up; CalcSpline(); num = Vector3.Distance(custnode.transform.position, custnode2.transform.position); } MegaHoseType megaHoseType = wiretype; int num2 = segments; if (num2 < 3) { num2 = 3; } if (rebuildcross) { rebuildcross = false; int num3 = 0; int num4 = 0; switch (megaHoseType) { case MegaHoseType.Round: NvertsPerRing = rndsides; if (NvertsPerRing < 3) { NvertsPerRing = 3; } break; case MegaHoseType.Rectangle: num3 = rectfilletsides; if (num3 < 0) { num3 = 0; } if (smooth == MegaHoseSmooth.SMOOTHNONE) { NvertsPerRing = ((num3 <= 0) ? 8 : (8 + 4 * (num3 - 1))); } else { NvertsPerRing = ((num3 <= 0) ? 4 : (8 + 4 * (num3 - 1))); } break; default: { num3 = dsecfilletsides; if (num3 < 0) { num3 = 0; } num4 = dsecrndsides; if (num4 < 2) { num4 = 2; } int num5 = num4 - 1; NvertsPerRing = ((num3 <= 0) ? (4 + num5) : (6 + num5 + 2 * (num3 - 1))); break; } } NvertsPerRing++; int num6 = 0; Nverts = (num2 + 1) * (NvertsPerRing + 1); if (capends) { Nverts += 2; } int nvertsPerRing = NvertsPerRing; int num7 = 6 * NvertsPerRing; num6 = num2 * num7; if (capends) { num6 += 2 * nvertsPerRing; } if (SaveVertex == null || SaveVertex.Length != NvertsPerRing) { SaveVertex = new Vector3[NvertsPerRing]; SaveUV = new Vector2[NvertsPerRing]; } if (calcnormals && (SaveNormals == null || SaveNormals.Length != NvertsPerRing)) { SaveNormals = new Vector3[NvertsPerRing]; } MakeSaveVertex(NvertsPerRing, num3, num4, megaHoseType); if (verts == null || verts.Length != Nverts) { verts = new Vector3[Nverts]; uvs = new Vector2[Nverts]; faces = new int[num6 * 3]; } if (calcnormals && (normals == null || normals.Length != Nverts)) { normals = new Vector3[Nverts]; } } if (Nverts == 0) { return; } bool flag2 = mapmemapme; int num8 = 0; int num9 = Nverts - 1; int num10 = num9 - 1; int nvertsPerRing2 = NvertsPerRing; int num11 = num2 + 1; float num12 = flexstart; float num13 = flexstop; int num14 = flexcycles; float num15 = flexdiameter; Vector2 zero = Vector2.zero; Matrix4x4 identity = Matrix4x4.identity; Matrix4x4 mat = Matrix4x4.identity; Vector3 lastup = starty; float num16 = 1f; for (int i = 0; i < num11; i++) { float num17 = (float)i / (float)num2; Vector3 vector; if (flag) { vector = new Vector3(0f, 0f, num * num17); } else { int k = 0; vector = hosespline.InterpCurve3D(num17, true, ref k); } identity = GetSplineMat(hosespline, num17, true, ref lastup); if (!flag) { identity = Tlocal * identity; } if (calcnormals) { mat = identity; MegaMatrix.NoTrans(ref mat); } float num20; if (num17 > num12 && num17 < num13 && flexon) { float num18 = num13 - num12; if (num18 < 0.01f) { num18 = 0.01f; } float num19 = (num17 - num12) / num18; float f = (float)num14 * num19 * ((float)Math.PI * 2f) + (float)Math.PI / 2f; num20 = 1f + num15 * (1f - Mathf.Sin(f)); } else { num20 = 0f; } if (usebulgecurve) { num20 = ((num20 != 0f) ? (num20 + bulge.Evaluate(num17 + bulgeoffset) * bulgeamount) : (1f + bulge.Evaluate(num17 + bulgeoffset) * bulgeamount)); } if (usesizecurve) { num16 = size.Evaluate(num17); } zero.x = 0.999999f * num17 * uvscale.x; for (int j = 0; j < NvertsPerRing; j++) { int num21 = j; if (flag2) { zero.y = SaveUV[num21].y; uvs[num8] = zero; } if (num20 != 0f) { verts[num8] = identity.MultiplyPoint(num16 * num20 * SaveVertex[num21]); } else { verts[num8] = identity.MultiplyPoint(num16 * SaveVertex[num21]); } if (calcnormals) { normals[num8] = mat.MultiplyPoint(SaveNormals[num21]).normalized; } num8++; } if (flag2) { } if (!capends) { continue; } if (i == 0) { verts[num10] = ((!flag) ? Tlocal.MultiplyPoint(vector) : vector); if (flag2) { uvs[num10] = Vector3.zero; } } else if (i == num2) { verts[num9] = ((!flag) ? Tlocal.MultiplyPoint(vector) : vector); if (flag2) { uvs[num9] = Vector3.zero; } } } int num22 = 0; int num23 = num10; if (capends) { for (int l = 0; l < NvertsPerRing - 1; l++) { int num24 = l; int num25 = ((l >= nvertsPerRing2) ? (num24 - nvertsPerRing2) : (num24 + 1)); faces[num22++] = num25; faces[num22++] = num24; faces[num22++] = num23; } } int nvertsPerRing3 = NvertsPerRing; for (int m = 0; m < num2; m++) { for (int n = 0; n < NvertsPerRing - 1; n++) { int num24 = m * nvertsPerRing3 + n; int num25 = num24 + 1; int num26 = num24 + nvertsPerRing3; num23 = num25 + nvertsPerRing3; faces[num22++] = num24; faces[num22++] = num25; faces[num22++] = num23; faces[num22++] = num24; faces[num22++] = num23; faces[num22++] = num26; } } int num27 = num2 * nvertsPerRing3; num23 = Nverts - 1; if (capends) { for (int num28 = 0; num28 < NvertsPerRing - 1; num28++) { int num24 = num28 + num27; int num25 = ((num28 >= nvertsPerRing2) ? (num24 - nvertsPerRing2) : (num24 + 1)); faces[num22++] = num24; faces[num22++] = num25; faces[num22++] = num23; } } mesh.Clear(); mesh.subMeshCount = 1; mesh.vertices = verts; mesh.uv = uvs; mesh.triangles = faces; if (calcnormals) { mesh.normals = normals; } else { mesh.RecalculateNormals(); } mesh.RecalculateBounds(); if (optimize) { } if (calctangents) { MegaUtils.BuildTangents(mesh); } if (recalcCollider) { if (meshCol == null) { meshCol = GetComponent(); } if (meshCol != null) { meshCol.sharedMesh = null; meshCol.sharedMesh = mesh; } } } public void CalcMatrix(ref Matrix4x4 mat, float incr) { mat = Tlocal; } private static float findmappos(float curpos) { float num; return num = (((num = curpos) < 0f) ? 0f : ((!(num > 1f)) ? num : 1f)); } private void DisplayNormals() { } public Vector3 GetPosition(float alpha) { Matrix4x4 matrix4x = base.transform.localToWorldMatrix * Tlocal; int k = 0; return matrix4x.MultiplyPoint(hosespline.InterpCurve3D(alpha, true, ref k)); } }