static void UpdateVertexCache(tk2dSpriteCollection gen, float scale, tk2dEditor.Atlas.Data[] packers, tk2dSpriteCollectionData coll, List<SpriteLut> spriteLuts) { for (int i = 0; i < sourceTextures.Length; ++i) { SpriteLut _lut = null; for (int j = 0; j < spriteLuts.Count; ++j) { if (spriteLuts[j].source == i) { _lut = spriteLuts[j]; break; } } int padAmount = GetPadAmount(gen, i); tk2dSpriteCollectionDefinition thisTexParam = gen.textureParams[i]; tk2dEditor.Atlas.Data packer = null; tk2dEditor.Atlas.Entry atlasEntry = null; int atlasIndex = 0; foreach (var p in packers) { if ((atlasEntry = p.FindEntryWithIndex(_lut.atlasIndex)) != null) { packer = p; break; } ++atlasIndex; } float fwidth = packer.width; float fheight = packer.height; int tx = atlasEntry.x + padAmount, ty = atlasEntry.y + padAmount, tw = atlasEntry.w - padAmount * 2, th = atlasEntry.h - padAmount * 2; int sd_y = packer.height - ty - th; float uvOffsetX = 0.001f / fwidth; float uvOffsetY = 0.001f / fheight; Vector2 v0 = new Vector2(tx / fwidth + uvOffsetX, 1.0f - (sd_y + th) / fheight + uvOffsetY); Vector2 v1 = new Vector2((tx + tw) / fwidth - uvOffsetX, 1.0f - sd_y / fheight - uvOffsetY); Mesh mesh = null; Transform meshTransform = null; GameObject instantiated = null; Vector3 colliderOrigin = new Vector3(); if (thisTexParam.overrideMesh) { // Disabled instantiated = GameObject.Instantiate(thisTexParam.overrideMesh) as GameObject; MeshFilter meshFilter = instantiated.GetComponentInChildren<MeshFilter>(); if (meshFilter == null) { Debug.LogError("Unable to find mesh"); GameObject.DestroyImmediate(instantiated); } else { mesh = meshFilter.sharedMesh; meshTransform = meshFilter.gameObject.transform; } } Vector3 untrimmedPos0 = Vector3.zero, untrimmedPos1 = Vector3.one; if (mesh) { coll.spriteDefinitions[i].positions = new Vector3[mesh.vertices.Length]; coll.spriteDefinitions[i].uvs = new Vector2[mesh.vertices.Length]; for (int j = 0; j < mesh.vertices.Length; ++j) { coll.spriteDefinitions[i].positions[j] = meshTransform.TransformPoint(mesh.vertices[j]); coll.spriteDefinitions[i].uvs[j] = new Vector2(v0.x + (v1.x - v0.x) * mesh.uv[j].x, v0.y + (v1.y - v0.y) * mesh.uv[j].y); } coll.spriteDefinitions[i].indices = new int[mesh.triangles.Length]; for (int j = 0; j < mesh.triangles.Length; ++j) { coll.spriteDefinitions[i].indices[j] = mesh.triangles[j]; } GameObject.DestroyImmediate(instantiated); } else { Texture2D thisTextureRef = sourceTextures[i]; int texHeightI = thisTextureRef?thisTextureRef.height:2; int texWidthI = thisTextureRef?thisTextureRef.width:2; float texHeight = texHeightI; float texWidth = texWidthI; float h = thisTextureRef?thisTextureRef.height:64; float w = thisTextureRef?thisTextureRef.width:64; h *= thisTexParam.scale.y; w *= thisTexParam.scale.x; float scaleX = w * scale; float scaleY = h * scale; // anchor coordinate system is (0, 0) = top left, to keep it the same as photoshop, etc. switch (thisTexParam.anchor) { case tk2dSpriteCollectionDefinition.Anchor.LowerLeft: thisTexParam.anchorX = 0; thisTexParam.anchorY = texHeightI; break; case tk2dSpriteCollectionDefinition.Anchor.LowerCenter: thisTexParam.anchorX = texWidthI / 2; thisTexParam.anchorY = texHeightI; break; case tk2dSpriteCollectionDefinition.Anchor.LowerRight: thisTexParam.anchorX = texWidthI; thisTexParam.anchorY = texHeightI; break; case tk2dSpriteCollectionDefinition.Anchor.MiddleLeft: thisTexParam.anchorX = 0; thisTexParam.anchorY = texHeightI / 2; break; case tk2dSpriteCollectionDefinition.Anchor.MiddleCenter: thisTexParam.anchorX = texWidthI / 2; thisTexParam.anchorY = texHeightI / 2; break; case tk2dSpriteCollectionDefinition.Anchor.MiddleRight: thisTexParam.anchorX = texWidthI; thisTexParam.anchorY = texHeightI / 2; break; case tk2dSpriteCollectionDefinition.Anchor.UpperLeft: thisTexParam.anchorX = 0; thisTexParam.anchorY = 0; break; case tk2dSpriteCollectionDefinition.Anchor.UpperCenter: thisTexParam.anchorX = texWidthI / 2; thisTexParam.anchorY = 0; break; case tk2dSpriteCollectionDefinition.Anchor.UpperRight: thisTexParam.anchorX = texWidthI; thisTexParam.anchorY = 0; break; } Vector3 pos0 = new Vector3(-thisTexParam.anchorX * thisTexParam.scale.x * scale, 0, -(h - thisTexParam.anchorY * thisTexParam.scale.y) * scale); colliderOrigin = new Vector3(pos0.x, pos0.z, 0.0f); Vector3 pos1 = pos0 + new Vector3(scaleX, 0, scaleY); untrimmedPos0 = new Vector3(pos0.x, pos0.z); untrimmedPos1 = new Vector3(pos1.x, pos1.z); List<Vector3> positions = new List<Vector3>(); List<Vector2> uvs = new List<Vector2>(); // build mesh if (_lut.isSplit) { coll.spriteDefinitions[i].flipped = false; // each split could be rotated, but not consistently for (int j = 0; j < spriteLuts.Count; ++j) { if (spriteLuts[j].source == i) { _lut = spriteLuts[j]; int thisAtlasIndex = 0; foreach (var p in packers) { if ((atlasEntry = p.FindEntryWithIndex(_lut.atlasIndex)) != null) { packer = p; break; } ++thisAtlasIndex; } if (thisAtlasIndex != atlasIndex) { // This is a serious problem, dicing is not supported when multi atlas output is selected Debug.Break(); } fwidth = packer.width; fheight = packer.height; tx = atlasEntry.x + padAmount; ty = atlasEntry.y + padAmount; tw = atlasEntry.w - padAmount * 2; th = atlasEntry.h - padAmount * 2; sd_y = packer.height - ty - th; v0 = new Vector2(tx / fwidth + uvOffsetX, 1.0f - (sd_y + th) / fheight + uvOffsetY); v1 = new Vector2((tx + tw) / fwidth - uvOffsetX, 1.0f - sd_y / fheight - uvOffsetY); float x0 = _lut.rx / texWidth; float y0 = _lut.ry / texHeight; float x1 = (_lut.rx + _lut.rw) / texWidth; float y1 = (_lut.ry + _lut.rh) / texHeight; Vector3 dpos0 = new Vector3(Mathf.Lerp(pos0.x, pos1.x, x0), 0.0f, Mathf.Lerp(pos0.z, pos1.z, y0)); Vector3 dpos1 = new Vector3(Mathf.Lerp(pos0.x, pos1.x, x1), 0.0f, Mathf.Lerp(pos0.z, pos1.z, y1)); positions.Add(new Vector3(dpos0.x, dpos0.z, 0)); positions.Add(new Vector3(dpos1.x, dpos0.z, 0)); positions.Add(new Vector3(dpos0.x, dpos1.z, 0)); positions.Add(new Vector3(dpos1.x, dpos1.z, 0)); if (atlasEntry.flipped) { uvs.Add(new Vector2(v0.x,v0.y)); uvs.Add(new Vector2(v0.x,v1.y)); uvs.Add(new Vector2(v1.x,v0.y)); uvs.Add(new Vector2(v1.x,v1.y)); } else { uvs.Add(new Vector2(v0.x,v0.y)); uvs.Add(new Vector2(v1.x,v0.y)); uvs.Add(new Vector2(v0.x,v1.y)); uvs.Add(new Vector2(v1.x,v1.y)); } } } } else if (thisTexParam.customSpriteGeometry) { coll.spriteDefinitions[i].flipped = atlasEntry.flipped; List<int> indices = new List<int>(); foreach (var island in thisTexParam.geometryIslands) { int baseIndex = positions.Count; for (int x = 0; x < island.points.Length; ++x) { var v = island.points[x]; Vector2 origin = new Vector2(pos0.x, pos0.z); positions.Add(new Vector2(v.x * thisTexParam.scale.x, (texHeight - v.y) * thisTexParam.scale.y) * scale + new Vector2(origin.x, origin.y)); tx = atlasEntry.x + padAmount; ty = atlasEntry.y + padAmount; tw = atlasEntry.w - padAmount * 2; th = atlasEntry.h - padAmount * 2; //v0 = new Vector2(tx / fwidth + uvOffsetX, 1.0f - (sd_y + th) / fheight + uvOffsetY); //v1 = new Vector2((tx + tw) / fwidth - uvOffsetX, 1.0f - sd_y / fheight - uvOffsetY); Vector2 uv = new Vector2(); if (atlasEntry.flipped) { uv.x = (tx - _lut.ry + texHeight - v.y) / fwidth + uvOffsetX; uv.y = (ty - _lut.rx + v.x) / fheight + uvOffsetY; } else { uv.x = (tx - _lut.rx + v.x) / fwidth + uvOffsetX; uv.y = (ty - _lut.ry + texHeight - v.y) / fheight + uvOffsetY ; } uvs.Add(uv); } tk2dEditor.Triangulator triangulator = new tk2dEditor.Triangulator(island.points); int[] localIndices = triangulator.Triangulate(); //for (int x = localIndices.Length - 1; x >= 0; --x) for (int x = 0; x < localIndices.Length; x += 3) { indices.Add(baseIndex + localIndices[x + 2]); indices.Add(baseIndex + localIndices[x + 1]); indices.Add(baseIndex + localIndices[x + 0]); } } coll.spriteDefinitions[i].indices = indices.ToArray(); } else { coll.spriteDefinitions[i].flipped = atlasEntry.flipped; float x0 = _lut.rx / texWidth; float y0 = _lut.ry / texHeight; float x1 = (_lut.rx + _lut.rw) / texWidth; float y1 = (_lut.ry + _lut.rh) / texHeight; Vector3 dpos0 = new Vector3(Mathf.Lerp(pos0.x, pos1.x, x0), 0.0f, Mathf.Lerp(pos0.z, pos1.z, y0)); Vector3 dpos1 = new Vector3(Mathf.Lerp(pos0.x, pos1.x, x1), 0.0f, Mathf.Lerp(pos0.z, pos1.z, y1)); positions.Add(new Vector3(dpos0.x, dpos0.z, 0)); positions.Add(new Vector3(dpos1.x, dpos0.z, 0)); positions.Add(new Vector3(dpos0.x, dpos1.z, 0)); positions.Add(new Vector3(dpos1.x, dpos1.z, 0)); if (atlasEntry.flipped) { uvs.Add(new Vector2(v0.x,v0.y)); uvs.Add(new Vector2(v0.x,v1.y)); uvs.Add(new Vector2(v1.x,v0.y)); uvs.Add(new Vector2(v1.x,v1.y)); } else { uvs.Add(new Vector2(v0.x,v0.y)); uvs.Add(new Vector2(v1.x,v0.y)); uvs.Add(new Vector2(v0.x,v1.y)); uvs.Add(new Vector2(v1.x,v1.y)); } } // build sprite definition if (!thisTexParam.customSpriteGeometry) { coll.spriteDefinitions[i].indices = new int[ 6 * (positions.Count / 4) ]; for (int j = 0; j < positions.Count / 4; ++j) { coll.spriteDefinitions[i].indices[j * 6 + 0] = j * 4 + 0; coll.spriteDefinitions[i].indices[j * 6 + 1] = j * 4 + 3; coll.spriteDefinitions[i].indices[j * 6 + 2] = j * 4 + 1; coll.spriteDefinitions[i].indices[j * 6 + 3] = j * 4 + 2; coll.spriteDefinitions[i].indices[j * 6 + 4] = j * 4 + 3; coll.spriteDefinitions[i].indices[j * 6 + 5] = j * 4 + 0; } coll.spriteDefinitions[i].complexGeometry = false; } else { coll.spriteDefinitions[i].complexGeometry = true; } // This doesn't seem to be necessary in UNITY_3_5_3 #if (UNITY_3_0 || UNITY_3_1 || UNITY_3_2 || UNITY_3_3 || UNITY_3_4 || UNITY_3_5_0 || UNITY_3_5_1 || UNITY_3_5_2) if (positions.Count > 0) { // http://forum.unity3d.com/threads/98781-Compute-mesh-inertia-tensor-failed-for-one-of-the-actor-Behaves-differently-in-3.4 Vector3 p = positions[positions.Count - 1]; p.z -= 0.001f; positions[positions.Count - 1] = p; } #endif coll.spriteDefinitions[i].positions = new Vector3[positions.Count]; coll.spriteDefinitions[i].uvs = new Vector2[uvs.Count]; for (int j = 0; j < positions.Count; ++j) { coll.spriteDefinitions[i].positions[j] = positions[j]; coll.spriteDefinitions[i].uvs[j] = uvs[j]; } // empty out to a sensible default, which corresponds to what Unity does by default coll.spriteDefinitions[i].normals = new Vector3[0]; coll.spriteDefinitions[i].tangents = new Vector4[0]; // fill out tangents and normals if (gen.normalGenerationMode != tk2dSpriteCollection.NormalGenerationMode.None) { Mesh tmpMesh = new Mesh(); tmpMesh.vertices = coll.spriteDefinitions[i].positions; tmpMesh.uv = coll.spriteDefinitions[i].uvs; tmpMesh.triangles = coll.spriteDefinitions[i].indices; tmpMesh.RecalculateNormals(); coll.spriteDefinitions[i].normals = tmpMesh.normals; if (gen.normalGenerationMode != tk2dSpriteCollection.NormalGenerationMode.NormalsOnly) { coll.spriteDefinitions[i].tangents = tmpMesh.tangents; } } } // fixup in case something went wrong if (coll.allowMultipleAtlases) { coll.spriteDefinitions[i].material = gen.atlasMaterials[atlasIndex]; } else { coll.spriteDefinitions[i].material = gen.altMaterials[thisTexParam.materialId]; coll.spriteDefinitions[i].materialId = thisTexParam.materialId; if (coll.spriteDefinitions[i].material == null) // fall back gracefully in case something went wrong { coll.spriteDefinitions[i].material = gen.atlasMaterials[atlasIndex]; coll.spriteDefinitions[i].materialId = 0; } } Vector3 boundsMin = new Vector3(1.0e32f, 1.0e32f, 1.0e32f); Vector3 boundsMax = new Vector3(-1.0e32f, -1.0e32f, -1.0e32f); foreach (Vector3 v in coll.spriteDefinitions[i].positions) { boundsMin = Vector3.Min(boundsMin, v); boundsMax = Vector3.Max(boundsMax, v); } coll.spriteDefinitions[i].boundsData = new Vector3[2]; coll.spriteDefinitions[i].boundsData[0] = (boundsMax + boundsMin) / 2.0f; coll.spriteDefinitions[i].boundsData[1] = (boundsMax - boundsMin); // this is the dimension of exactly one pixel, scaled to match sprite dimensions and scale coll.spriteDefinitions[i].texelSize = new Vector3(scale * thisTexParam.scale.x, scale * thisTexParam.scale.y, 0.0f); coll.spriteDefinitions[i].untrimmedBoundsData = new Vector3[2]; if (mesh) { // custom meshes aren't trimmed, the untrimmed bounds are exactly the same as the regular ones coll.spriteDefinitions[i].untrimmedBoundsData[0] = coll.spriteDefinitions[i].boundsData[0]; coll.spriteDefinitions[i].untrimmedBoundsData[1] = coll.spriteDefinitions[i].boundsData[1]; } else { boundsMin = Vector3.Min(untrimmedPos0, untrimmedPos1); boundsMax = Vector3.Max(untrimmedPos0, untrimmedPos1); coll.spriteDefinitions[i].untrimmedBoundsData[0] = (boundsMax + boundsMin) / 2.0f; coll.spriteDefinitions[i].untrimmedBoundsData[1] = (boundsMax - boundsMin); } coll.spriteDefinitions[i].name = gen.textureParams[i].name; // Generate collider data here UpdateColliderData(gen, scale, coll, i, colliderOrigin); } }
static void UpdateColliderData(tk2dSpriteCollection gen, float scale, tk2dSpriteCollectionData coll, int spriteIndex, Vector3 origin) { var colliderType = gen.textureParams[spriteIndex].colliderType; var def = coll.spriteDefinitions[spriteIndex]; var src = gen.textureParams[spriteIndex]; def.colliderVertices = null; def.colliderIndicesFwd = null; def.colliderIndicesBack = null; float texHeight = 0; if (src.extractRegion) { texHeight = src.regionH; } else { texHeight = gen.textureParams[spriteIndex].texture?gen.textureParams[spriteIndex].texture.height:2.0f; } if (colliderType == tk2dSpriteCollectionDefinition.ColliderType.BoxTrimmed) { def.colliderVertices = new Vector3[2]; def.colliderVertices[0] = def.boundsData[0]; def.colliderVertices[1] = def.boundsData[1] * 0.5f; // extents is 1/2x size def.colliderVertices[1].z = gen.physicsDepth; def.colliderType = tk2dSpriteDefinition.ColliderType.Box; } else if (colliderType == tk2dSpriteCollectionDefinition.ColliderType.BoxCustom) { Vector2 v0 = new Vector3(src.boxColliderMin.x * src.scale.x, (texHeight - src.boxColliderMax.y) * src.scale.y) * scale + origin; Vector2 v1 = new Vector3(src.boxColliderMax.x * src.scale.x, (texHeight - src.boxColliderMin.y) * src.scale.y) * scale + origin; def.colliderVertices = new Vector3[2]; def.colliderVertices[0] = (v0 + v1) * 0.5f; def.colliderVertices[1] = (v1 - v0) * 0.5f; def.colliderVertices[1].z = gen.physicsDepth; def.colliderType = tk2dSpriteDefinition.ColliderType.Box; } else if (colliderType == tk2dSpriteCollectionDefinition.ColliderType.Polygon) { List<Vector3> meshVertices = new List<Vector3>(); List<int> meshIndicesFwd = new List<int>(); foreach (var island in src.polyColliderIslands) { List<Vector2> points = new List<Vector2>(); List<Vector2> points2D = new List<Vector2>(); // List all points for (int i = 0; i < island.points.Length; ++i) { Vector2 v = island.points[i]; points.Add(new Vector2(v.x * src.scale.x, (texHeight - v.y) * src.scale.y) * scale + new Vector2(origin.x, origin.y)); } int baseIndex = meshVertices.Count; for (int i = 0; i < points.Count; ++i) { meshVertices.Add( new Vector3(points[i].x, points[i].y, -gen.physicsDepth) ); meshVertices.Add( new Vector3(points[i].x, points[i].y, gen.physicsDepth) ); points2D.Add( new Vector2(points[i].x, points[i].y) ); } // body int numPoints = island.connected?points.Count:(points.Count - 1); for (int i = 0; i < numPoints; ++i) { int i0 = i * 2; int i1 = i0 + 1; int i2 = ((i + 1)%island.points.Length) * 2; int i3 = i2 + 1; // Classify primary edge direction, and flip accordingly bool flipIndices = false; Vector2 grad = points2D[i] - points2D[(i + 1) % points2D.Count]; if (Mathf.Abs(grad.x) < Mathf.Abs(grad.y)) { flipIndices = (grad.y > 0.0f); } else { flipIndices = (grad.x > 0.0f); } if (flipIndices) { meshIndicesFwd.Add(baseIndex + i2); meshIndicesFwd.Add(baseIndex + i3); meshIndicesFwd.Add(baseIndex + i0); meshIndicesFwd.Add(baseIndex + i0); meshIndicesFwd.Add(baseIndex + i3); meshIndicesFwd.Add(baseIndex + i1); } else { meshIndicesFwd.Add(baseIndex + i2); meshIndicesFwd.Add(baseIndex + i1); meshIndicesFwd.Add(baseIndex + i0); meshIndicesFwd.Add(baseIndex + i2); meshIndicesFwd.Add(baseIndex + i3); meshIndicesFwd.Add(baseIndex + i1); } } // cap if allowed and necessary var cap = src.polyColliderCap; if (island.connected && cap != tk2dSpriteCollectionDefinition.PolygonColliderCap.None) { tk2dEditor.Triangulator triangulator = new tk2dEditor.Triangulator(points2D.ToArray()); int[] indices = triangulator.Triangulate(); if (cap == tk2dSpriteCollectionDefinition.PolygonColliderCap.Front || cap == tk2dSpriteCollectionDefinition.PolygonColliderCap.FrontAndBack) { for (int i = 0; i < indices.Length; ++i) meshIndicesFwd.Add(baseIndex + indices[i] * 2); } if (cap == tk2dSpriteCollectionDefinition.PolygonColliderCap.Back || cap == tk2dSpriteCollectionDefinition.PolygonColliderCap.FrontAndBack) { for (int i = 0; i < indices.Length; i += 3) { meshIndicesFwd.Add(baseIndex + indices[i + 2] * 2 + 1); meshIndicesFwd.Add(baseIndex + indices[i + 1] * 2 + 1); meshIndicesFwd.Add(baseIndex + indices[i + 0] * 2 + 1); } } } } int[] meshIndicesBack = new int[meshIndicesFwd.Count]; for (int i = 0; i < meshIndicesFwd.Count; i += 3) { meshIndicesBack[i + 0] = meshIndicesFwd[i + 2]; meshIndicesBack[i + 1] = meshIndicesFwd[i + 1]; meshIndicesBack[i + 2] = meshIndicesFwd[i + 0]; } def.colliderVertices = meshVertices.ToArray(); def.colliderIndicesFwd = meshIndicesFwd.ToArray(); def.colliderIndicesBack = meshIndicesBack; def.colliderConvex = src.colliderConvex; def.colliderType = tk2dSpriteDefinition.ColliderType.Mesh; def.colliderSmoothSphereCollisions = src.colliderSmoothSphereCollisions; } else if (colliderType == tk2dSpriteCollectionDefinition.ColliderType.ForceNone) { def.colliderType = tk2dSpriteDefinition.ColliderType.None; } else if (colliderType == tk2dSpriteCollectionDefinition.ColliderType.UserDefined) { def.colliderType = tk2dSpriteDefinition.ColliderType.Unset; } }