public Rect DrawBrush(tk2dTileMap tileMap, tk2dTileMapEditorBrush brush, float scale, bool forceUnitSpacing, int tilesPerRow) { var dictData = GetDictDataForBrush(brush, tilesPerRow); Mesh atlasViewMesh = dictData.mesh; Rect atlasViewRect = BrushToScreenRect(dictData.rect); float width = atlasViewRect.width * scale; float height = atlasViewRect.height * scale; float maxScreenWidth = Screen.width - 16; if (width > maxScreenWidth) { height = height * maxScreenWidth / width; width = maxScreenWidth; } Rect rect = GUILayoutUtility.GetRect(width, height, GUILayout.ExpandWidth(false), GUILayout.ExpandHeight(false)); scale = width / atlasViewRect.width; lastScale = scale; if (Event.current.type == EventType.Repaint) { tileMap.spriteCollection.materials[0].SetPass(0); Matrix4x4 mat = new Matrix4x4(); var spriteDef = tileMap.spriteCollection.spriteDefinitions[0]; mat.SetTRS(new Vector3(rect.x, rect.y + height, 0), Quaternion.identity, new Vector3(scale / spriteDef.texelSize.x, -scale / spriteDef.texelSize.y, 1)); Graphics.DrawMeshNow(atlasViewMesh, mat * GUI.matrix); } return(rect); }
public tk2dTileMapScratchpad() { width = 0; height = 0; layers = new tk2dScratchpadLayer[0]; canvas = new tk2dTileMapEditorBrush(); }
public void InitBrushes(tk2dSpriteCollectionData spriteCollection) { if (defaultBrush == null || defaultBrush.Empty) { defaultBrush = new tk2dTileMapEditorBrush(); } if (brushes == null) { brushes = new List <tk2dTileMapEditorBrush>(); } if (paletteBrush == null || paletteBrush.Empty || !paletteBrush.overrideWithSpriteBounds) { paletteBrush = new tk2dTileMapEditorBrush(); paletteBrush.overrideWithSpriteBounds = true; CreateDefaultPalette(spriteCollection, paletteBrush, paletteTilesPerRow); } int spriteCount = spriteCollection.spriteDefinitions.Length; foreach (var brush in brushes) { for (int j = 0; j < brush.tiles.Length; ++j) { brush.tiles[j].spriteId = (ushort)Mathf.Clamp(brush.tiles[j].spriteId, 0, spriteCount - 1); } } if (activeBrush == null || activeBrush.Empty) { activeBrush = defaultBrush; } }
public Rect DrawBrush(tk2dTileMap tileMap, tk2dTileMapEditorBrush brush, float scale, bool forceUnitSpacing, int tilesPerRow) { var dictData = GetDictDataForBrush(brush, tilesPerRow); Mesh atlasViewMesh = dictData.mesh; Rect atlasViewRect = BrushToScreenRect(dictData.rect); float width = atlasViewRect.width * scale; float height = atlasViewRect.height * scale; float maxScreenWidth = Screen.width - 16; if (width > maxScreenWidth) { height = height * maxScreenWidth / width; width = maxScreenWidth; } Rect rect = GUILayoutUtility.GetRect(width, height, GUILayout.ExpandWidth(false), GUILayout.ExpandHeight(false)); scale = width / atlasViewRect.width; lastScale = scale; if (Event.current.type == EventType.Repaint) { tileMap.spriteCollection.materials[0].SetPass(0); Matrix4x4 mat = new Matrix4x4(); var spriteDef = tileMap.spriteCollection.spriteDefinitions[0]; mat.SetTRS(new Vector3(rect.x, rect.y + height, 0), Quaternion.identity, new Vector3(scale / spriteDef.texelSize.x, -scale / spriteDef.texelSize.y, 1)); Graphics.DrawMeshNow(atlasViewMesh, mat * GUI.matrix); } return rect; }
void SplatBrushAt(tk2dTileMapEditorBrush brush, int cx, int cy, int layer) { // only commit at the end when in rect mode if (brush.paintMode == tk2dTileMapEditorBrush.PaintMode.Random || brush.paintMode == tk2dTileMapEditorBrush.PaintMode.Edged) { return; } if (brush.type == tk2dTileMapEditorBrush.Type.MultiSelect) { // seed a rng with the current tileId and the random seed generated when mouse press is first initiated // this will give a conistent distribution per mouse press & drag // but will be unique(ish) per press var rng = new System.Random(randomSeed + cy * tileMap.width + cx); int tileId = brush.multiSelectTiles[rng.Next(brush.multiSelectTiles.Length)]; SplatTile(cx, cy, editorData.layer, tileId); } else { foreach (var tile in brush.tiles) { SplatTile(tile.x + cx, tile.y + cy, tile.layer + layer, tile.spriteId); } } }
public tk2dScratchpadGUI(tk2dTileMapSceneGUI _parent, tk2dEditor.BrushRenderer _brushRenderer, tk2dTileMapEditorBrush _workingBrush) { parent = _parent; brushRenderer = _brushRenderer; workingBrush = _workingBrush; }
void Splat() { tk2dTileMapEditorBrush activeBrush = editorData.activeBrush; switch (editorData.editMode) { case tk2dTileMapEditorData.EditMode.Paint: SplatBrushAt(activeBrush, cursorX, cursorY, editorData.layer); host.BuildIncremental(); break; case tk2dTileMapEditorData.EditMode.Color: PaintAt(vertexCursorX, vertexCursorY); host.BuildIncremental(); break; } }
void DrawTileCursor(tk2dTileMapEditorBrush brush) { float xOffsetMult, yOffsetMult; tileMap.data.GetTileOffset(out xOffsetMult, out yOffsetMult); if (brush.paintMode == tk2dTileMapEditorBrush.PaintMode.Random || brush.paintMode == tk2dTileMapEditorBrush.PaintMode.Edged || pickup || erase) { int x0 = cursorX; int y0 = cursorY; x0 = Mathf.Min(cursorX, cursorX0); y0 = Mathf.Min(cursorY, cursorY0); int x1 = Mathf.Max(cursorX, cursorX0); int y1 = Mathf.Max(cursorY, cursorY0); for (int y = y0; y <= y1; ++y) { for (int x = x0; x <= x1; ++x) { DrawCursorAt(x, y); } } } else if (brush.type == tk2dTileMapEditorBrush.Type.MultiSelect) { DrawCursorAt(cursorX, cursorY); } else { int xoffset = 0; if (tileMap.data.tileType == tk2dTileMapData.TileType.Isometric && (cursorY & 1) == 1) { xoffset = 1; } foreach (var tile in brush.tiles) { int thisRowXOffset = (((cursorY + tile.y) & 1) == 0)?xoffset:0; DrawCursorAt(cursorX + tile.x + thisRowXOffset, cursorY + tile.y); } } }
public void DrawBrushInScene(Matrix4x4 matrix, tk2dTileMapEditorBrush brush, int tilesPerRow) { var dictData = GetDictDataForBrush(brush, tilesPerRow); Mesh mesh = dictData.mesh; Vector4 clipRegion = new Vector4(-1.0e32f, -1.0e32f, 1.0e32f, 1.0e32f); Material customMaterial = tk2dSpriteThumbnailCache.GetMaterial(); customMaterial.SetColor("_Tint", new Color(1, 1, 1, tk2dTileMapToolbar.workBrushOpacity)); customMaterial.SetVector("_Clip", clipRegion); for (int i = 0; i < dictData.materials.Length; ++i) { customMaterial.mainTexture = dictData.materials[i].mainTexture; customMaterial.SetPass(0); Graphics.DrawMeshNow(mesh, matrix, i); } }
void DrawTileCursor(tk2dTileMapEditorBrush brush) { float xOffsetMult, yOffsetMult; tileMap.data.GetTileOffset(out xOffsetMult, out yOffsetMult); if (brush.paintMode == tk2dTileMapEditorBrush.PaintMode.Random || brush.paintMode == tk2dTileMapEditorBrush.PaintMode.Edged || pickup || erase) { int x0 = cursorX; int y0 = cursorY; x0 = Mathf.Min(cursorX, cursorX0); y0 = Mathf.Min(cursorY, cursorY0); int x1 = Mathf.Max(cursorX, cursorX0); int y1 = Mathf.Max(cursorY, cursorY0); for (int y = y0; y <= y1; ++y) { for (int x = x0; x <= x1; ++x) { DrawCursorAt(x, y); } } } else if (brush.type == tk2dTileMapEditorBrush.Type.MultiSelect) { DrawCursorAt(cursorX, cursorY); } else { int xoffset = 0; if (tileMap.data.tileType == tk2dTileMapData.TileType.Isometric && (cursorY & 1) == 1) xoffset = 1; foreach (var tile in brush.tiles) { int thisRowXOffset = (((cursorY + tile.y) & 1) == 0)?xoffset:0; DrawCursorAt(cursorX + tile.x + thisRowXOffset, cursorY + tile.y); } } }
public void DrawBrushInScratchpad(tk2dTileMapEditorBrush brush, Matrix4x4 matrix, bool setWorkbrushOpacity) { var dictData = GetDictDataForBrush(brush, 1000000); Mesh mesh = dictData.mesh; Rect visibleRect = tk2dSpriteThumbnailCache.VisibleRect; Vector4 clipRegion = new Vector4(visibleRect.x, visibleRect.y, visibleRect.x + visibleRect.width, visibleRect.y + visibleRect.height); Material customMaterial = tk2dSpriteThumbnailCache.GetMaterial(); customMaterial.SetColor("_Tint", new Color(1, 1, 1, setWorkbrushOpacity?tk2dTileMapToolbar.workBrushOpacity:1)); customMaterial.SetVector("_Clip", clipRegion); for (int i = 0; i < dictData.materials.Length; ++i) { customMaterial.mainTexture = dictData.materials[i].mainTexture; customMaterial.SetPass(0); Graphics.DrawMeshNow(mesh, matrix, i); } }
BrushDictData GetDictDataForBrush(tk2dTileMapEditorBrush brush, int tilesPerRow) { BrushDictData dictEntry; if (brushLookupDict.TryGetValue(brush, out dictEntry)) { if (brush.brushHash != dictEntry.brushHash) { BuildMeshForBrush(brush, dictEntry, tilesPerRow); } return(dictEntry); } else { dictEntry = new BrushDictData(); BuildMeshForBrush(brush, dictEntry, tilesPerRow); brushLookupDict[brush] = dictEntry; return(dictEntry); } }
public Rect DrawBrush(tk2dTileMap tileMap, tk2dTileMapEditorBrush brush, float scale, bool forceUnitSpacing, int tilesPerRow, Rect inRect) { var dictData = GetDictDataForBrush(brush, tilesPerRow); Mesh atlasViewMesh = dictData.mesh; Rect atlasViewRect = BrushToScreenRect(dictData.rect); Rect visibleRect = tk2dSpriteThumbnailCache.VisibleRect; visibleRect = inRect; Vector4 clipRegion = new Vector4(visibleRect.x, visibleRect.y, visibleRect.x + visibleRect.width, visibleRect.y + visibleRect.height); Material customMaterial = tk2dSpriteThumbnailCache.GetMaterial(); customMaterial.SetColor("_Tint", Color.white); customMaterial.SetVector("_Clip", clipRegion); float width = atlasViewRect.width * scale; float height = atlasViewRect.height * scale; Rect rect = GUILayoutUtility.GetRect(width, height, GUILayout.ExpandWidth(false), GUILayout.ExpandHeight(true)); scale = width / atlasViewRect.width; lastScale = scale; if (Event.current.type == EventType.Repaint) { Matrix4x4 mat = new Matrix4x4(); var spriteDef = tileMap.SpriteCollectionInst.spriteDefinitions[0]; mat.SetTRS(new Vector3(rect.x, rect.y + height, 0), Quaternion.identity, new Vector3(scale / spriteDef.texelSize.x, -scale / spriteDef.texelSize.y, 1)); for (int i = 0; i < dictData.materials.Length; ++i) { customMaterial.mainTexture = dictData.materials[i].mainTexture; customMaterial.SetPass(0); Graphics.DrawMeshNow(atlasViewMesh, mat * GUI.matrix, i); } } return(rect); }
public void CreateDefaultPalette(tk2dSpriteCollectionData spriteCollection, tk2dTileMapEditorBrush brush, int numTilesX) { List <tk2dSparseTile> tiles = new List <tk2dSparseTile>(); var spriteDefinitions = spriteCollection.spriteDefinitions; int numTilesY = spriteDefinitions.Length / numTilesX; if (numTilesY * numTilesX < spriteDefinitions.Length) { numTilesY++; } for (ushort spriteIndex = 0; spriteIndex < spriteDefinitions.Length; ++spriteIndex) { if (spriteDefinitions[spriteIndex].Valid) { tiles.Add(new tk2dSparseTile(spriteIndex % numTilesX, numTilesY - 1 - spriteIndex / numTilesX, 0, spriteIndex)); } } brush.tiles = tiles.ToArray(); brush.UpdateBrushHash(); }
public tk2dTileMapEditorBrush(tk2dTileMapEditorBrush source) { this.name = source.name; this.type = source.type; this.paintMode = source.paintMode; tiles = new tk2dSparseTile[source.tiles.Length]; for (int i = 0; i < source.tiles.Length; ++i) { tiles[i] = new tk2dSparseTile(source.tiles[i]); } multiSelectTiles = new int[source.multiSelectTiles.Length]; for (int i = 0; i < source.multiSelectTiles.Length; ++i) { multiSelectTiles[i] = source.multiSelectTiles[i]; } edgeMode = source.edgeMode; multiLayer = source.multiLayer; overrideWithSpriteBounds = source.overrideWithSpriteBounds; }
BrushDictData GetDictDataForBrush(tk2dTileMapEditorBrush brush, int tilesPerRow) { BrushDictData dictEntry; if (brushLookupDict.TryGetValue(brush, out dictEntry)) { if (brush.brushHash != dictEntry.brushHash) { BuildMeshForBrush(brush, dictEntry, tilesPerRow); } return dictEntry; } else { dictEntry = new BrushDictData(); BuildMeshForBrush(brush, dictEntry, tilesPerRow); brushLookupDict[brush] = dictEntry; return dictEntry; } }
void PickUpBrush(tk2dTileMapEditorBrush brush, bool allLayers) { int x0 = Mathf.Min(cursorX, cursorX0); int x1 = Mathf.Max(cursorX, cursorX0); int y0 = Mathf.Min(cursorY, cursorY0); int y1 = Mathf.Max(cursorY, cursorY0); int numTilesX = x1 - x0 + 1; int numTilesY = y1 - y0 + 1; List<tk2dSparseTile> sparseTile = new List<tk2dSparseTile>(); List<int> tiles = new List<int>(); int numLayers = tileMap.data.NumLayers; int startLayer = 0; int endLayer = numLayers; if (allLayers) { brush.multiLayer = true; } else { brush.multiLayer = false; startLayer = editorData.layer; endLayer = startLayer + 1; } if (tileMap.data.tileType == tk2dTileMapData.TileType.Rectangular) { for (int layer = startLayer; layer < endLayer; ++layer) { for (int y = numTilesY - 1; y >= 0; --y) { for (int x = 0; x < numTilesX; ++x) { int tile = tileMap.Layers[layer].GetTile(x0 + x, y0 + y); tiles.Add(tile); sparseTile.Add(new tk2dSparseTile(x, y, allLayers?layer:0, tile)); } } } } else if (tileMap.data.tileType == tk2dTileMapData.TileType.Isometric) { int xOffset = 0; int yOffset = 0; if ((y0 & 1) != 0) yOffset -= 1; for (int layer = startLayer; layer < endLayer; ++layer) { for (int y = numTilesY - 1; y >= 0; --y) { for (int x = 0; x < numTilesX; ++x) { int tile = tileMap.Layers[layer].GetTile(x0 + x, y0 + y); tiles.Add(tile); sparseTile.Add(new tk2dSparseTile(x + xOffset, y + yOffset, allLayers?layer:0, tile)); } } } } brush.type = tk2dTileMapEditorBrush.Type.Custom; if (numTilesX == 1 && numTilesY == 3) brush.edgeMode = tk2dTileMapEditorBrush.EdgeMode.Vertical; else if (numTilesX == 3 && numTilesY == 1) brush.edgeMode = tk2dTileMapEditorBrush.EdgeMode.Horizontal; else if (numTilesX == 3 && numTilesY == 3) brush.edgeMode = tk2dTileMapEditorBrush.EdgeMode.Square; else brush.edgeMode = tk2dTileMapEditorBrush.EdgeMode.None; brush.tiles = sparseTile.ToArray(); brush.multiSelectTiles = tiles.ToArray(); brush.UpdateBrushHash(); // Make the inspector update EditorUtility.SetDirty(tileMap); }
public void UpdateWorkingBrush() { tk2dTileMapEditorBrush workBrush = WorkingBrush; tk2dTileMapEditorBrush activeBrush = editorData.activeBrush; int rectX1 = Mathf.Min(cursorX, cursorX0); int rectX2 = Mathf.Max(cursorX, cursorX0); int rectY1 = Mathf.Min(cursorY, cursorY0); int rectY2 = Mathf.Max(cursorY, cursorY0); int xoffset = 0; if (tileMap.data.tileType == tk2dTileMapData.TileType.Isometric && (cursorY & 1) == 1) { xoffset = 1; } workBrush.tiles = new tk2dSparseTile[0]; tk2dSparseTile[] srcTiles; if (activeBrush.type != tk2dTileMapEditorBrush.Type.MultiSelect) { srcTiles = activeBrush.tiles; } else { int n = activeBrush.multiSelectTiles.Length; srcTiles = new tk2dSparseTile[n]; for (int i = 0; i < n; ++i) { srcTiles[i] = new tk2dSparseTile(i, 0, editorData.layer, activeBrush.multiSelectTiles[i]); } } if (srcTiles.Length == 0) { workBrush.UpdateBrushHash(); return; } bool flipH = tk2dTileMapToolbar.workBrushFlipX; bool flipV = tk2dTileMapToolbar.workBrushFlipY; if (tk2dTileMapToolbar.mainMode == tk2dTileMapToolbar.MainMode.Brush) { if (rectX1 == rectX2 && rectY1 == rectY2) { int nTiles = srcTiles.Length; workBrush.tiles = new tk2dSparseTile[nTiles]; for (int i = 0; i < nTiles; ++i) { int spriteId = srcTiles[i].spriteId; int tx = srcTiles[i].x; int ty = srcTiles[i].y; if (flipH) { tx = -tx; tk2dRuntime.TileMap.BuilderUtil.InvertRawTileFlag(ref spriteId, tk2dTileFlags.FlipX); } if (flipV) { ty = -ty; tk2dRuntime.TileMap.BuilderUtil.InvertRawTileFlag(ref spriteId, tk2dTileFlags.FlipY); } int thisRowXOffset = ((ty & 1) == 1) ? xoffset : 0; workBrush.tiles[i] = new tk2dSparseTile( cursorX + tx + thisRowXOffset, cursorY + ty, editorData.layer, spriteId); } } else { int gridWidth = 1 + rectX2 - rectX1; int gridHeight = 1 + rectY2 - rectY1; workBrush.tiles = new tk2dSparseTile[gridWidth * gridHeight]; // fill with tiles repeated pattern... int patternX1 = 0; int patternY1 = 0; int patternX2 = 0; int patternY2 = 0; foreach (var tile in srcTiles) { patternX1 = Mathf.Min(patternX1, tile.x); patternY1 = Mathf.Min(patternY1, tile.y); patternX2 = Mathf.Max(patternX2, tile.x); patternY2 = Mathf.Max(patternY2, tile.y); } int patternW = 1 + patternX2 - patternX1; int patternH = 1 + patternY2 - patternY1; int idx = 0; for (int y = 0; y < gridHeight; ++y) { int thisRowXOffset = ((y & 1) == 1) ? xoffset : 0; for (int x = 0; x < gridWidth; ++x) { int spriteId = srcTiles[0].spriteId; foreach (var tile in srcTiles) { if ((x % patternW) == (tile.x - patternX1) && (y % patternH) == (tile.y - patternY1)) { spriteId = tile.spriteId; break; } } if (flipH) { tk2dRuntime.TileMap.BuilderUtil.InvertRawTileFlag(ref spriteId, tk2dTileFlags.FlipX); } if (flipV) { tk2dRuntime.TileMap.BuilderUtil.InvertRawTileFlag(ref spriteId, tk2dTileFlags.FlipY); } workBrush.tiles[idx++] = new tk2dSparseTile( rectX1 + x + thisRowXOffset, rectY1 + y, editorData.layer, spriteId); } } } } if (tk2dTileMapToolbar.mainMode == tk2dTileMapToolbar.MainMode.BrushRandom) { int gridWidth = 1 + rectX2 - rectX1; int gridHeight = 1 + rectY2 - rectY1; workBrush.tiles = new tk2dSparseTile[gridWidth * gridHeight]; var rng = new System.Random(randomSeed + cursorY * tileMap.width + cursorX); int idx = 0; for (int y = 0; y < gridHeight; ++y) { int thisRowXOffset = ((y & 1) == 1) ? xoffset : 0; for (int x = 0; x < gridWidth; ++x) { int spriteId = srcTiles[rng.Next(srcTiles.Length)].spriteId; workBrush.tiles[idx++] = new tk2dSparseTile( rectX1 + x + thisRowXOffset, rectY1 + y, editorData.layer, spriteId); } } } if (scratchpadGUI.workingHere) { int scratchW, scratchH; scratchpadGUI.GetScratchpadSize(out scratchW, out scratchH); workBrush.ClipTiles(0, 0, scratchW - 1, scratchH - 1); } else { workBrush.ClipTiles(0, 0, tileMap.width - 1, tileMap.height - 1); } workBrush.SortTiles(tileMapData.sortMethod == tk2dTileMapData.SortMethod.BottomLeft || tileMapData.sortMethod == tk2dTileMapData.SortMethod.TopLeft, tileMapData.sortMethod == tk2dTileMapData.SortMethod.BottomLeft || tileMapData.sortMethod == tk2dTileMapData.SortMethod.BottomRight); workBrush.UpdateBrushHash(); }
public void DrawBrushInScene(Matrix4x4 matrix, tk2dTileMapEditorBrush brush, int tilesPerRow) { var dictData = GetDictDataForBrush(brush, tilesPerRow); Mesh mesh = dictData.mesh; Vector4 clipRegion = new Vector4(-1.0e32f, -1.0e32f, 1.0e32f, 1.0e32f); Material customMaterial = tk2dSpriteThumbnailCache.GetMaterial(); customMaterial.SetColor("_Tint", new Color(1,1,1,tk2dTileMapToolbar.workBrushOpacity)); customMaterial.SetVector("_Clip", clipRegion); for (int i = 0; i < dictData.materials.Length; ++i) { customMaterial.mainTexture = dictData.materials[i].mainTexture; customMaterial.SetPass(0); Graphics.DrawMeshNow( mesh, matrix, i ); } }
// Build a mesh for a list of given sprites void BuildMeshForBrush(tk2dTileMapEditorBrush brush, BrushDictData dictData, int tilesPerRow) { List<Vector3> vertices = new List<Vector3>(); List<Vector2> uvs = new List<Vector2>(); Dictionary<Material, List<int>> triangles = new Dictionary<Material, List<int>>(); // bounds of tile Vector3 spriteBounds = Vector3.zero; foreach (var spriteDef in spriteCollection.spriteDefinitions) { if (spriteDef.Valid) spriteBounds = Vector3.Max(spriteBounds, spriteDef.untrimmedBoundsData[1]); } Vector3 tileSize = brush.overrideWithSpriteBounds? spriteBounds: tileMap.data.tileSize; float layerOffset = 0.001f; Vector3 boundsMin = new Vector3(1.0e32f, 1.0e32f, 1.0e32f); Vector3 boundsMax = new Vector3(-1.0e32f, -1.0e32f, -1.0e32f); float tileOffsetX = 0, tileOffsetY = 0; if (!brush.overrideWithSpriteBounds) tileMap.data.GetTileOffset(out tileOffsetX, out tileOffsetY); if (brush.type == tk2dTileMapEditorBrush.Type.MultiSelect) { int tileX = 0; int tileY = brush.multiSelectTiles.Length / tilesPerRow; if ((brush.multiSelectTiles.Length % tilesPerRow) == 0) tileY -=1; foreach (var uncheckedSpriteId in brush.multiSelectTiles) { float xOffset = (tileY & 1) * tileOffsetX; // The origin of the tile in mesh space Vector3 tileOrigin = new Vector3((tileX + xOffset) * tileSize.x, tileY * tileSize.y, 0.0f); //if (brush.overrideWithSpriteBounds) { boundsMin = Vector3.Min(boundsMin, tileOrigin); boundsMax = Vector3.Max(boundsMax, tileOrigin + tileSize); } if (uncheckedSpriteId != -1) { int indexRoot = vertices.Count; int spriteId = Mathf.Clamp(uncheckedSpriteId, 0, spriteCollection.Count - 1); tk2dSpriteDefinition sprite = spriteCollection.spriteDefinitions[spriteId]; for (int j = 0; j < sprite.positions.Length; ++j) { // Offset so origin is at bottom left Vector3 v = sprite.positions[j] - tileMap.data.tileOrigin; boundsMin = Vector3.Min(boundsMin, tileOrigin + v); boundsMax = Vector3.Max(boundsMax, tileOrigin + v); vertices.Add(tileOrigin + v); uvs.Add(sprite.uvs[j]); } if (!triangles.ContainsKey(sprite.materialInst)) triangles.Add(sprite.materialInst, new List<int>()); for (int j = 0; j < sprite.indices.Length; ++j) { triangles[sprite.materialInst].Add(indexRoot + sprite.indices[j]); } } tileX += 1; if (tileX == tilesPerRow) { tileX = 0; tileY -= 1; } } } else { // the brush is centered around origin, x to the right, y up foreach (var tile in brush.tiles) { float xOffset = (tile.y & 1) * tileOffsetX; // The origin of the tile in mesh space Vector3 tileOrigin = new Vector3((tile.x + xOffset) * tileSize.x, tile.y * tileSize.y, tile.layer * layerOffset); //if (brush.overrideWithSpriteBounds) { boundsMin = Vector3.Min(boundsMin, tileOrigin); boundsMax = Vector3.Max(boundsMax, tileOrigin + tileSize); } int spriteIdx = tk2dRuntime.TileMap.BuilderUtil.GetTileFromRawTile(tile.spriteId); bool flipH = tk2dRuntime.TileMap.BuilderUtil.IsRawTileFlagSet(tile.spriteId, tk2dTileFlags.FlipX); bool flipV = tk2dRuntime.TileMap.BuilderUtil.IsRawTileFlagSet(tile.spriteId, tk2dTileFlags.FlipY); bool rot90 = tk2dRuntime.TileMap.BuilderUtil.IsRawTileFlagSet(tile.spriteId, tk2dTileFlags.Rot90); if (spriteIdx < 0 || spriteIdx >= spriteCollection.Count) continue; int indexRoot = vertices.Count; var sprite = spriteCollection.spriteDefinitions[spriteIdx]; if (brush.overrideWithSpriteBounds) { tileOrigin.x += spriteBounds.x * 0.5f - sprite.untrimmedBoundsData[0].x; tileOrigin.y += spriteBounds.y * 0.5f - sprite.untrimmedBoundsData[0].y; } for (int j = 0; j < sprite.positions.Length; ++j) { Vector3 flippedPos = tk2dRuntime.TileMap.BuilderUtil.ApplySpriteVertexTileFlags(tileMap, sprite, sprite.positions[j], flipH, flipV, rot90); // Offset so origin is at bottom left (if not using bounds) Vector3 v = flippedPos; if (!brush.overrideWithSpriteBounds) v -= tileMap.data.tileOrigin; boundsMin = Vector3.Min(boundsMin, tileOrigin + v); boundsMax = Vector3.Max(boundsMax, tileOrigin + v); vertices.Add(tileOrigin + v); uvs.Add(sprite.uvs[j]); } if (!triangles.ContainsKey(sprite.materialInst)) triangles.Add(sprite.materialInst, new List<int>()); for (int j = 0; j < sprite.indices.Length; ++j) { triangles[sprite.materialInst].Add(indexRoot + sprite.indices[j]); } } } if (dictData.mesh == null) { dictData.mesh = new Mesh(); dictData.mesh.hideFlags = HideFlags.DontSave; } Mesh mesh = dictData.mesh; mesh.Clear(); mesh.vertices = vertices.ToArray(); Color[] colors = new Color[vertices.Count]; for (int i = 0; i < vertices.Count; ++i) colors[i] = Color.white; mesh.colors = colors; mesh.uv = uvs.ToArray(); mesh.subMeshCount = triangles.Keys.Count; int subMeshId = 0; foreach (Material mtl in triangles.Keys) { mesh.SetTriangles(triangles[mtl].ToArray(), subMeshId); subMeshId++; } dictData.brush = brush; dictData.brushHash = brush.brushHash; dictData.mesh = mesh; dictData.materials = (new List<Material>(triangles.Keys)).ToArray(); dictData.rect = new Rect(boundsMin.x, boundsMin.y, boundsMax.x - boundsMin.x, boundsMax.y - boundsMin.y); }
void PickUpBrush(tk2dTileMapEditorBrush brush, bool allLayers) { int x0 = Mathf.Min(cursorX, cursorX0); int x1 = Mathf.Max(cursorX, cursorX0); int y0 = Mathf.Min(cursorY, cursorY0); int y1 = Mathf.Max(cursorY, cursorY0); int numTilesX = x1 - x0 + 1; int numTilesY = y1 - y0 + 1; List <tk2dSparseTile> sparseTile = new List <tk2dSparseTile>(); List <int> tiles = new List <int>(); int numLayers = tileMap.data.NumLayers; int startLayer = 0; int endLayer = numLayers; if (allLayers) { brush.multiLayer = true; } else { brush.multiLayer = false; startLayer = editorData.layer; endLayer = startLayer + 1; } for (int layer = startLayer; layer < endLayer; ++layer) { for (int y = numTilesY - 1; y >= 0; --y) { for (int x = 0; x < numTilesX; ++x) { int tile = tileMap.Layers[layer].GetTile(x0 + x, y0 + y); tiles.Add(tile); sparseTile.Add(new tk2dSparseTile(x, y, allLayers?layer:0, tile)); } } } brush.type = tk2dTileMapEditorBrush.Type.Custom; if (numTilesX == 1 && numTilesY == 3) { brush.edgeMode = tk2dTileMapEditorBrush.EdgeMode.Vertical; } else if (numTilesX == 3 && numTilesY == 1) { brush.edgeMode = tk2dTileMapEditorBrush.EdgeMode.Horizontal; } else if (numTilesX == 3 && numTilesY == 3) { brush.edgeMode = tk2dTileMapEditorBrush.EdgeMode.Square; } else { brush.edgeMode = tk2dTileMapEditorBrush.EdgeMode.None; } brush.tiles = sparseTile.ToArray(); brush.multiSelectTiles = tiles.ToArray(); brush.UpdateBrushHash(); // Make the inspector update EditorUtility.SetDirty(tileMap); }
public tk2dScratchpadGUI(tk2dTileMapSceneGUI _parent, tk2dEditor.BrushRenderer _brushRenderer, tk2dTileMapEditorBrush _workingBrush) { parent = _parent; brushRenderer = _brushRenderer; workingBrush = _workingBrush; }
void BuildBrush(tk2dSpriteCollectionData spriteCollection, tk2dTileMapEditorBrush brush, int tilesPerRow) { brush.multiLayer = false; if (multiSelect) { List<int> filteredTileSelection = new List<int>(); foreach (var v in tileSelection) { if (IsValidSprite(spriteCollection, v)) filteredTileSelection.Add(v); } brush.type = tk2dTileMapEditorBrush.Type.MultiSelect; brush.multiSelectTiles = filteredTileSelection.ToArray(); brush.edgeMode = tk2dTileMapEditorBrush.EdgeMode.None; brush.tiles = new tk2dSparseTile[0]; } else { int tx0 = (tileSelection_x0 < tileSelection_x1)?tileSelection_x0:tileSelection_x1; int tx1 = (tileSelection_x0 < tileSelection_x1)?tileSelection_x1:tileSelection_x0; int ty0 = (tileSelection_y0 < tileSelection_y1)?tileSelection_y0:tileSelection_y1; int ty1 = (tileSelection_y0 < tileSelection_y1)?tileSelection_y1:tileSelection_y0; int numTilesX = tx1 - tx0 + 1; int numTilesY = ty1 - ty0 + 1; int numValidTiles = 0; tileSelection.Clear(); List<tk2dSparseTile> tiles = new List<tk2dSparseTile>(); for (int y = 0; y < numTilesY; ++y) { for (int x = 0; x < numTilesX; ++x) { ushort spriteId = (ushort)((y + ty0) * tilesPerRow + (x + tx0)); if (IsValidSprite(spriteCollection, spriteId)) { tiles.Add(new tk2dSparseTile(x, numTilesY - 1 - y, 0, spriteId)); if (tileSelection.IndexOf(spriteId) == -1) tileSelection.Add(spriteId); numValidTiles++; } } } if (numTilesX == 1 && numTilesY == 3 && numValidTiles == 3) brush.edgeMode = tk2dTileMapEditorBrush.EdgeMode.Vertical; else if (numTilesX == 3 && numTilesY == 1 && numValidTiles == 3) brush.edgeMode = tk2dTileMapEditorBrush.EdgeMode.Horizontal; else if (numTilesX == 3 && numTilesY == 3 && numValidTiles == 9) brush.edgeMode = tk2dTileMapEditorBrush.EdgeMode.Square; else brush.edgeMode = tk2dTileMapEditorBrush.EdgeMode.None; brush.type = (rectSelect)?tk2dTileMapEditorBrush.Type.Rectangle:tk2dTileMapEditorBrush.Type.Single; brush.multiSelectTiles = tileSelection.ToArray(); brush.tiles = tiles.ToArray(); } brush.UpdateBrushHash(); }
public void HandleGUI(Rect rect, Rect tileSize, int tilesPerRow, tk2dSpriteCollectionData spriteCollection, tk2dTileMapEditorBrush brush) { DrawSelectedTiles(rect, tileSize, tilesPerRow); int controlID = GUIUtility.GetControlID(FocusType.Passive, rect); if (!rect.Contains(Event.current.mousePosition)) { return; } Vector2 localClickPosition = Event.current.mousePosition - new Vector2(rect.x, rect.y); Vector2 tileLocalPosition = new Vector2(localClickPosition.x / tileSize.width, localClickPosition.y / tileSize.height); int tx = (int)tileLocalPosition.x; int ty = (int)tileLocalPosition.y; switch (Event.current.GetTypeForControl(controlID)) { case EventType.MouseDown: bool multiSelectKeyDown = (Application.platform == RuntimePlatform.OSXEditor)?Event.current.command:Event.current.control; if (multiSelectKeyDown) { multiSelect = true; rectSelect = false; // Only add to selection when changing from single selection to multiselect if (tileSelection.Count == 0) { AddToSelection(tilesPerRow); } } else { Reset(); } tileSelection_x0 = tx; tileSelection_y0 = ty; tileSelection_x1 = tx; tileSelection_y1 = ty; HandleUtility.Repaint(); GUIUtility.hotControl = controlID; break; case EventType.MouseDrag: if (GUIUtility.hotControl == controlID) { tileSelection_x1 = tx; tileSelection_y1 = ty; HandleUtility.Repaint(); } break; case EventType.MouseUp: if (GUIUtility.hotControl == controlID) { if (multiSelect) { AddToSelection(tilesPerRow); } // Build brush GUIUtility.hotControl = 0; BuildBrush(spriteCollection, brush, tilesPerRow); HandleUtility.Repaint(); } break; } }
void BuildBrush(tk2dSpriteCollectionData spriteCollection, tk2dTileMapEditorBrush brush, int tilesPerRow) { brush.multiLayer = false; if (multiSelect) { List <int> filteredTileSelection = new List <int>(); foreach (var v in tileSelection) { if (IsValidSprite(spriteCollection, v)) { filteredTileSelection.Add(v); } } brush.type = tk2dTileMapEditorBrush.Type.MultiSelect; brush.multiSelectTiles = filteredTileSelection.ToArray(); brush.edgeMode = tk2dTileMapEditorBrush.EdgeMode.None; brush.tiles = new tk2dSparseTile[0]; } else { int tx0 = (tileSelection_x0 < tileSelection_x1)?tileSelection_x0:tileSelection_x1; int tx1 = (tileSelection_x0 < tileSelection_x1)?tileSelection_x1:tileSelection_x0; int ty0 = (tileSelection_y0 < tileSelection_y1)?tileSelection_y0:tileSelection_y1; int ty1 = (tileSelection_y0 < tileSelection_y1)?tileSelection_y1:tileSelection_y0; int numTilesX = tx1 - tx0 + 1; int numTilesY = ty1 - ty0 + 1; int numValidTiles = 0; tileSelection.Clear(); List <tk2dSparseTile> tiles = new List <tk2dSparseTile>(); for (int y = 0; y < numTilesY; ++y) { for (int x = 0; x < numTilesX; ++x) { ushort spriteId = (ushort)((y + ty0) * tilesPerRow + (x + tx0)); if (IsValidSprite(spriteCollection, spriteId)) { tiles.Add(new tk2dSparseTile(x, numTilesY - 1 - y, 0, spriteId)); if (tileSelection.IndexOf(spriteId) == -1) { tileSelection.Add(spriteId); } numValidTiles++; } } } if (numTilesX == 1 && numTilesY == 3 && numValidTiles == 3) { brush.edgeMode = tk2dTileMapEditorBrush.EdgeMode.Vertical; } else if (numTilesX == 3 && numTilesY == 1 && numValidTiles == 3) { brush.edgeMode = tk2dTileMapEditorBrush.EdgeMode.Horizontal; } else if (numTilesX == 3 && numTilesY == 3 && numValidTiles == 9) { brush.edgeMode = tk2dTileMapEditorBrush.EdgeMode.Square; } else { brush.edgeMode = tk2dTileMapEditorBrush.EdgeMode.None; } brush.type = (rectSelect)?tk2dTileMapEditorBrush.Type.Rectangle:tk2dTileMapEditorBrush.Type.Single; brush.multiSelectTiles = tileSelection.ToArray(); brush.tiles = tiles.ToArray(); } brush.UpdateBrushHash(); }
public void HandleGUI(Rect rect, Rect tileSize, int tilesPerRow, tk2dSpriteCollectionData spriteCollection, tk2dTileMapEditorBrush brush) { DrawSelectedTiles(rect, tileSize, tilesPerRow); int controlID = GUIUtility.GetControlID(FocusType.Passive, rect); if (!rect.Contains(Event.current.mousePosition)) { return; } Vector2 localClickPosition = Event.current.mousePosition - new Vector2(rect.x, rect.y); Vector2 tileLocalPosition = new Vector2(localClickPosition.x / tileSize.width, localClickPosition.y / tileSize.height); int tx = (int)tileLocalPosition.x; int ty = (int)tileLocalPosition.y; switch (Event.current.GetTypeForControl(controlID)) { case EventType.MouseDown: bool multiSelectKeyDown = (Application.platform == RuntimePlatform.OSXEditor)?Event.current.command:Event.current.control; if (multiSelectKeyDown) { multiSelect = true; rectSelect = false; // Only add to selection when changing from single selection to multiselect if (tileSelection.Count == 0) { AddToSelection(tilesPerRow); } } else { Reset(); } tileSelection_x0 = tx; tileSelection_y0 = ty; tileSelection_x1 = tx; tileSelection_y1 = ty; HandleUtility.Repaint(); GUIUtility.hotControl = controlID; break; case EventType.MouseDrag: if (GUIUtility.hotControl == controlID) { tileSelection_x1 = tx; tileSelection_y1 = ty; HandleUtility.Repaint(); } break; case EventType.MouseUp: if (GUIUtility.hotControl == controlID) { if (multiSelect) { AddToSelection(tilesPerRow); } // Build brush GUIUtility.hotControl = 0; BuildBrush(spriteCollection, brush, tilesPerRow); HandleUtility.Repaint(); } break; } }
void SplatBrushAt(tk2dTileMapEditorBrush brush, int cx, int cy, int layer) { // only commit at the end when in rect mode if (brush.paintMode == tk2dTileMapEditorBrush.PaintMode.Random || brush.paintMode == tk2dTileMapEditorBrush.PaintMode.Edged) { return; } if (brush.type == tk2dTileMapEditorBrush.Type.MultiSelect) { // seed a rng with the current tileId and the random seed generated when mouse press is first initiated // this will give a conistent distribution per mouse press & drag // but will be unique(ish) per press var rng = new System.Random(randomSeed + cy * tileMap.width + cx); int tileId = brush.multiSelectTiles[rng.Next(brush.multiSelectTiles.Length)]; SplatTile(cx, cy, editorData.layer, tileId); } else { int xoffset = 0; if (tileMap.data.tileType == tk2dTileMapData.TileType.Isometric && (cursorY & 1) == 1) xoffset = 1; foreach (var tile in brush.tiles) { int thisRowXOffset = (((cursorY + tile.y) & 1) == 0)?xoffset:0; SplatTile(tile.x + cx + thisRowXOffset, tile.y + cy, tile.layer + layer, tile.spriteId); } } }
public Rect GetBrushViewRect(tk2dTileMapEditorBrush brush, int tilesPerRow) { var dictData = GetDictDataForBrush(brush, tilesPerRow); return BrushToScreenRect(dictData.rect); }
void DrawTileCursor(tk2dTileMapEditorBrush brush) { float layerZ = 0.0f; if (brush.paintMode == tk2dTileMapEditorBrush.PaintMode.Random || brush.paintMode == tk2dTileMapEditorBrush.PaintMode.Edged || pickup || erase) { int x0 = cursorX; int y0 = cursorY; int tilesX = 1; int tilesY = 1; x0 = Mathf.Min(cursorX, cursorX0); int x1 = Mathf.Max(cursorX, cursorX0); y0 = Mathf.Min(cursorY, cursorY0); int y1 = Mathf.Max(cursorY, cursorY0); tilesX = x1 - x0 + 1; tilesY = y1 - y0 + 1; Vector3 p0 = new Vector3(tileMapData.tileOrigin.x + x0 * tileMapData.tileSize.x, tileMapData.tileOrigin.y + y0 * tileMapData.tileSize.y, layerZ); Vector3 p1 = new Vector3(p0.x + tileMapData.tileSize.x * tilesX, p0.y + tileMapData.tileSize.y * tilesY, 0); Vector3[] v = new Vector3[4]; v[0] = new Vector3(p0.x, p0.y, 0); v[1] = new Vector3(p1.x, p0.y, 0); v[2] = new Vector3(p1.x, p1.y, 0); v[3] = new Vector3(p0.x, p1.y, 0); for (int i = 0; i < v.Length; ++i) v[i] = tileMap.transform.TransformPoint(v[i]); Handles.DrawSolidRectangleWithOutline(v, tileSelectionFillColor, tileSelectionOutlineColor); } else if (brush.type == tk2dTileMapEditorBrush.Type.MultiSelect) { Vector3 p0 = new Vector3(tileMapData.tileOrigin.x + (cursorX) * tileMapData.tileSize.x, tileMapData.tileOrigin.y + (cursorY) * tileMapData.tileSize.y, layerZ); Vector3 p1 = new Vector3(p0.x + tileMapData.tileSize.x, p0.y + tileMapData.tileSize.y, 0); Vector3[] v = new Vector3[4]; v[0] = new Vector3(p0.x, p0.y, 0); v[1] = new Vector3(p1.x, p0.y, 0); v[2] = new Vector3(p1.x, p1.y, 0); v[3] = new Vector3(p0.x, p1.y, 0); for (int i = 0; i < v.Length; ++i) v[i] = tileMap.transform.TransformPoint(v[i]); Handles.DrawSolidRectangleWithOutline(v, tileSelectionFillColor, tileSelectionOutlineColor); } else { foreach (var tile in brush.tiles) { Vector3 p0 = new Vector3(tileMapData.tileOrigin.x + (cursorX + tile.x) * tileMapData.tileSize.x, tileMapData.tileOrigin.y + (cursorY + tile.y) * tileMapData.tileSize.y, layerZ); Vector3 p1 = new Vector3(p0.x + tileMapData.tileSize.x, p0.y + tileMapData.tileSize.y, 0); Vector3[] v = new Vector3[4]; v[0] = new Vector3(p0.x, p0.y, 0); v[1] = new Vector3(p1.x, p0.y, 0); v[2] = new Vector3(p1.x, p1.y, 0); v[3] = new Vector3(p0.x, p1.y, 0); for (int i = 0; i < v.Length; ++i) v[i] = tileMap.transform.TransformPoint(v[i]); Handles.DrawSolidRectangleWithOutline(v, tileSelectionFillColor, tileSelectionOutlineColor); } } }
public Rect DrawBrush(tk2dTileMap tileMap, tk2dTileMapEditorBrush brush, float scale, bool forceUnitSpacing, int tilesPerRow) { var dictData = GetDictDataForBrush(brush, tilesPerRow); Mesh atlasViewMesh = dictData.mesh; Rect atlasViewRect = BrushToScreenRect(dictData.rect); Rect visibleRect = tk2dSpriteThumbnailCache.VisibleRect; Vector4 clipRegion = new Vector4(visibleRect.x, visibleRect.y, visibleRect.x + visibleRect.width, visibleRect.y + visibleRect.height); Material customMaterial = tk2dSpriteThumbnailCache.GetMaterial(); customMaterial.SetColor("_Tint", Color.white); customMaterial.SetVector("_Clip", clipRegion); float width = atlasViewRect.width * scale; float height = atlasViewRect.height * scale; Rect rect = GUILayoutUtility.GetRect(width, height, GUILayout.ExpandWidth(false), GUILayout.ExpandHeight(true)); scale = width / atlasViewRect.width; lastScale = scale; if (Event.current.type == EventType.Repaint) { Matrix4x4 mat = new Matrix4x4(); var spriteDef = tileMap.SpriteCollectionInst.spriteDefinitions[0]; mat.SetTRS(new Vector3(rect.x, rect.y + height, 0), Quaternion.identity, new Vector3(scale / spriteDef.texelSize.x, -scale / spriteDef.texelSize.y, 1)); for (int i = 0; i < dictData.materials.Length; ++i) { customMaterial.mainTexture = dictData.materials[i].mainTexture; customMaterial.SetPass(0); Graphics.DrawMeshNow(atlasViewMesh, mat * GUI.matrix, i); } } return rect; }
// Build a mesh for a list of given sprites void BuildMeshForBrush(tk2dTileMapEditorBrush brush, BrushDictData dictData, int tilesPerRow) { List <Vector3> vertices = new List <Vector3>(); List <Vector2> uvs = new List <Vector2>(); Dictionary <Material, List <int> > triangles = new Dictionary <Material, List <int> >(); // bounds of tile Vector3 spriteBounds = Vector3.zero; foreach (var spriteDef in spriteCollection.spriteDefinitions) { if (spriteDef.Valid) { spriteBounds = Vector3.Max(spriteBounds, spriteDef.untrimmedBoundsData[1]); } } Vector3 tileSize = brush.overrideWithSpriteBounds? spriteBounds: tileMap.data.tileSize; float layerOffset = 0.001f; Vector3 boundsMin = new Vector3(1.0e32f, 1.0e32f, 1.0e32f); Vector3 boundsMax = new Vector3(-1.0e32f, -1.0e32f, -1.0e32f); float tileOffsetX = 0, tileOffsetY = 0; if (!brush.overrideWithSpriteBounds) { tileMap.data.GetTileOffset(out tileOffsetX, out tileOffsetY); } if (brush.type == tk2dTileMapEditorBrush.Type.MultiSelect) { int tileX = 0; int tileY = brush.multiSelectTiles.Length / tilesPerRow; if ((brush.multiSelectTiles.Length % tilesPerRow) == 0) { tileY -= 1; } foreach (var uncheckedSpriteId in brush.multiSelectTiles) { float xOffset = (tileY & 1) * tileOffsetX; // The origin of the tile in mesh space Vector3 tileOrigin = new Vector3((tileX + xOffset) * tileSize.x, tileY * tileSize.y, 0.0f); //if (brush.overrideWithSpriteBounds) { boundsMin = Vector3.Min(boundsMin, tileOrigin); boundsMax = Vector3.Max(boundsMax, tileOrigin + tileSize); } if (uncheckedSpriteId != -1) { int indexRoot = vertices.Count; int spriteId = Mathf.Clamp(uncheckedSpriteId, 0, spriteCollection.Count - 1); tk2dSpriteDefinition sprite = spriteCollection.spriteDefinitions[spriteId]; for (int j = 0; j < sprite.positions.Length; ++j) { // Offset so origin is at bottom left Vector3 v = sprite.positions[j] - tileMap.data.tileOrigin; boundsMin = Vector3.Min(boundsMin, tileOrigin + v); boundsMax = Vector3.Max(boundsMax, tileOrigin + v); vertices.Add(tileOrigin + v); uvs.Add(sprite.uvs[j]); } if (!triangles.ContainsKey(sprite.materialInst)) { triangles.Add(sprite.materialInst, new List <int>()); } for (int j = 0; j < sprite.indices.Length; ++j) { triangles[sprite.materialInst].Add(indexRoot + sprite.indices[j]); } } tileX += 1; if (tileX == tilesPerRow) { tileX = 0; tileY -= 1; } } } else { // the brush is centered around origin, x to the right, y up foreach (var tile in brush.tiles) { float xOffset = (tile.y & 1) * tileOffsetX; // The origin of the tile in mesh space Vector3 tileOrigin = new Vector3((tile.x + xOffset) * tileSize.x, tile.y * tileSize.y, tile.layer * layerOffset); //if (brush.overrideWithSpriteBounds) { boundsMin = Vector3.Min(boundsMin, tileOrigin); boundsMax = Vector3.Max(boundsMax, tileOrigin + tileSize); } int spriteIdx = tk2dRuntime.TileMap.BuilderUtil.GetTileFromRawTile(tile.spriteId); bool flipH = tk2dRuntime.TileMap.BuilderUtil.IsRawTileFlagSet(tile.spriteId, tk2dTileFlags.FlipX); bool flipV = tk2dRuntime.TileMap.BuilderUtil.IsRawTileFlagSet(tile.spriteId, tk2dTileFlags.FlipY); bool rot90 = tk2dRuntime.TileMap.BuilderUtil.IsRawTileFlagSet(tile.spriteId, tk2dTileFlags.Rot90); if (spriteIdx < 0 || spriteIdx >= spriteCollection.Count) { continue; } int indexRoot = vertices.Count; var sprite = spriteCollection.spriteDefinitions[spriteIdx]; if (brush.overrideWithSpriteBounds) { tileOrigin.x += spriteBounds.x * 0.5f - sprite.untrimmedBoundsData[0].x; tileOrigin.y += spriteBounds.y * 0.5f - sprite.untrimmedBoundsData[0].y; } for (int j = 0; j < sprite.positions.Length; ++j) { Vector3 flippedPos = tk2dRuntime.TileMap.BuilderUtil.ApplySpriteVertexTileFlags(tileMap, sprite, sprite.positions[j], flipH, flipV, rot90); // Offset so origin is at bottom left (if not using bounds) Vector3 v = flippedPos; if (!brush.overrideWithSpriteBounds) { v -= tileMap.data.tileOrigin; } boundsMin = Vector3.Min(boundsMin, tileOrigin + v); boundsMax = Vector3.Max(boundsMax, tileOrigin + v); vertices.Add(tileOrigin + v); uvs.Add(sprite.uvs[j]); } if (!triangles.ContainsKey(sprite.materialInst)) { triangles.Add(sprite.materialInst, new List <int>()); } for (int j = 0; j < sprite.indices.Length; ++j) { triangles[sprite.materialInst].Add(indexRoot + sprite.indices[j]); } } } if (dictData.mesh == null) { dictData.mesh = new Mesh(); dictData.mesh.hideFlags = HideFlags.DontSave; } Mesh mesh = dictData.mesh; mesh.Clear(); mesh.vertices = vertices.ToArray(); Color[] colors = new Color[vertices.Count]; for (int i = 0; i < vertices.Count; ++i) { colors[i] = Color.white; } mesh.colors = colors; mesh.uv = uvs.ToArray(); mesh.subMeshCount = triangles.Keys.Count; int subMeshId = 0; foreach (Material mtl in triangles.Keys) { mesh.SetTriangles(triangles[mtl].ToArray(), subMeshId); subMeshId++; } dictData.brush = brush; dictData.brushHash = brush.brushHash; dictData.mesh = mesh; dictData.materials = (new List <Material>(triangles.Keys)).ToArray(); dictData.rect = new Rect(boundsMin.x, boundsMin.y, boundsMax.x - boundsMin.x, boundsMax.y - boundsMin.y); }
public void DrawBrushInScratchpad(tk2dTileMapEditorBrush brush, Matrix4x4 matrix, bool setWorkbrushOpacity) { var dictData = GetDictDataForBrush(brush, 1000000); Mesh mesh = dictData.mesh; Rect visibleRect = tk2dSpriteThumbnailCache.VisibleRect; Vector4 clipRegion = new Vector4(visibleRect.x, visibleRect.y, visibleRect.x + visibleRect.width, visibleRect.y + visibleRect.height); Material customMaterial = tk2dSpriteThumbnailCache.GetMaterial(); customMaterial.SetColor("_Tint", new Color(1,1,1,setWorkbrushOpacity?tk2dTileMapToolbar.workBrushOpacity:1)); customMaterial.SetVector("_Clip", clipRegion); for (int i = 0; i < dictData.materials.Length; ++i) { customMaterial.mainTexture = dictData.materials[i].mainTexture; customMaterial.SetPass(0); Graphics.DrawMeshNow(mesh, matrix, i); } }
// Build a mesh for a list of given sprites void BuildMeshForBrush(tk2dTileMapEditorBrush brush, BrushDictData dictData, int tilesPerRow) { List<Vector3> vertices = new List<Vector3>(); List<Vector2> uvs = new List<Vector2>(); Dictionary<Material, List<int>> triangles = new Dictionary<Material, List<int>>(); // bounds of tile Vector3 spriteBounds = spriteCollection.FirstValidDefinition.untrimmedBoundsData[1]; Vector3 tileSize = brush.overrideWithSpriteBounds? spriteBounds: tileMap.data.tileSize; float layerOffset = 0.001f; Vector3 boundsMin = new Vector3(1.0e32f, 1.0e32f, 1.0e32f); Vector3 boundsMax = new Vector3(-1.0e32f, -1.0e32f, -1.0e32f); float tileOffsetX = 0, tileOffsetY = 0; if (!brush.overrideWithSpriteBounds) tileMap.data.GetTileOffset(out tileOffsetX, out tileOffsetY); if (brush.type == tk2dTileMapEditorBrush.Type.MultiSelect) { int tileX = 0; int tileY = brush.multiSelectTiles.Length / tilesPerRow; if ((brush.multiSelectTiles.Length % tilesPerRow) == 0) tileY -=1; foreach (var uncheckedSpriteId in brush.multiSelectTiles) { float xOffset = (tileY & 1) * tileOffsetX; // The origin of the tile in mesh space Vector3 tileOrigin = new Vector3((tileX + xOffset) * tileSize.x, tileY * tileSize.y, 0.0f); //if (brush.overrideWithSpriteBounds) { boundsMin = Vector3.Min(boundsMin, tileOrigin); boundsMax = Vector3.Max(boundsMax, tileOrigin + tileSize); } if (uncheckedSpriteId != -1) { int indexRoot = vertices.Count; int spriteId = Mathf.Clamp(uncheckedSpriteId, 0, spriteCollection.Count - 1); tk2dSpriteDefinition sprite = spriteCollection.spriteDefinitions[spriteId]; for (int j = 0; j < sprite.positions.Length; ++j) { // Sprite vertex, centered around origin Vector3 centeredSpriteVertex = sprite.positions[j] - sprite.untrimmedBoundsData[0]; // Offset so origin is at bottom left Vector3 v = centeredSpriteVertex + sprite.untrimmedBoundsData[1] * 0.5f; boundsMin = Vector3.Min(boundsMin, tileOrigin + v); boundsMax = Vector3.Max(boundsMax, tileOrigin + v); vertices.Add(tileOrigin + v); uvs.Add(sprite.uvs[j]); } if (!triangles.ContainsKey(sprite.material)) triangles.Add(sprite.material, new List<int>()); for (int j = 0; j < sprite.indices.Length; ++j) { triangles[sprite.material].Add(indexRoot + sprite.indices[j]); } } tileX += 1; if (tileX == tilesPerRow) { tileX = 0; tileY -= 1; } } } else { // the brush is centered around origin, x to the right, y up foreach (var tile in brush.tiles) { float xOffset = (tile.y & 1) * tileOffsetX; // The origin of the tile in mesh space Vector3 tileOrigin = new Vector3((tile.x + xOffset) * tileSize.x, tile.y * tileSize.y, tile.layer * layerOffset); //if (brush.overrideWithSpriteBounds) { boundsMin = Vector3.Min(boundsMin, tileOrigin); boundsMax = Vector3.Max(boundsMax, tileOrigin + tileSize); } if (tile.spriteId == -1) continue; int indexRoot = vertices.Count; tile.spriteId = (ushort)Mathf.Clamp(tile.spriteId, 0, spriteCollection.Count - 1); var sprite = spriteCollection.spriteDefinitions[tile.spriteId]; for (int j = 0; j < sprite.positions.Length; ++j) { // Sprite vertex, centered around origin Vector3 centeredSpriteVertex = sprite.positions[j] - sprite.untrimmedBoundsData[0]; // Offset so origin is at bottom left Vector3 v = centeredSpriteVertex + sprite.untrimmedBoundsData[1] * 0.5f; boundsMin = Vector3.Min(boundsMin, tileOrigin + v); boundsMax = Vector3.Max(boundsMax, tileOrigin + v); vertices.Add(tileOrigin + v); uvs.Add(sprite.uvs[j]); } if (!triangles.ContainsKey(sprite.material)) triangles.Add(sprite.material, new List<int>()); for (int j = 0; j < sprite.indices.Length; ++j) { triangles[sprite.material].Add(indexRoot + sprite.indices[j]); } } } if (dictData.mesh == null) { dictData.mesh = new Mesh(); dictData.mesh.hideFlags = HideFlags.DontSave; } Mesh mesh = dictData.mesh; mesh.Clear(); mesh.vertices = vertices.ToArray(); Color[] colors = new Color[vertices.Count]; for (int i = 0; i < vertices.Count; ++i) colors[i] = Color.white; mesh.colors = colors; mesh.uv = uvs.ToArray(); mesh.subMeshCount = triangles.Keys.Count; int subMeshId = 0; foreach (Material mtl in triangles.Keys) { mesh.SetTriangles(triangles[mtl].ToArray(), subMeshId); subMeshId++; } dictData.brush = brush; dictData.brushHash = brush.brushHash; dictData.mesh = mesh; dictData.materials = (new List<Material>(triangles.Keys)).ToArray(); dictData.rect = new Rect(boundsMin.x, boundsMin.y, boundsMax.x - boundsMin.x, boundsMax.y - boundsMin.y); }
// Build a mesh for a list of given sprites void BuildMeshForBrush(tk2dTileMapEditorBrush brush, BrushDictData dictData, int tilesPerRow) { List <Vector3> vertices = new List <Vector3>(); List <Vector2> uvs = new List <Vector2>(); Dictionary <Material, List <int> > triangles = new Dictionary <Material, List <int> >(); //Debug.Log("spriteCollection" + spriteCollection); // bounds of tile Vector3 spriteBounds = spriteCollection.FirstValidDefinition.untrimmedBoundsData[1]; Vector3 tileSize = brush.overrideWithSpriteBounds? spriteBounds: tileMap.data.tileSize; float layerOffset = 0.001f; Vector3 boundsMin = new Vector3(1.0e32f, 1.0e32f, 1.0e32f); Vector3 boundsMax = new Vector3(-1.0e32f, -1.0e32f, -1.0e32f); float tileOffsetX = 0, tileOffsetY = 0; if (!brush.overrideWithSpriteBounds) { tileMap.data.GetTileOffset(out tileOffsetX, out tileOffsetY); } if (brush.type == tk2dTileMapEditorBrush.Type.MultiSelect) { int tileX = 0; int tileY = brush.multiSelectTiles.Length / tilesPerRow; if ((brush.multiSelectTiles.Length % tilesPerRow) == 0) { tileY -= 1; } foreach (var uncheckedSpriteId in brush.multiSelectTiles) { float xOffset = (tileY & 1) * tileOffsetX; // The origin of the tile in mesh space Vector3 tileOrigin = new Vector3((tileX + xOffset) * tileSize.x, tileY * tileSize.y, 0.0f); //if (brush.overrideWithSpriteBounds) { boundsMin = Vector3.Min(boundsMin, tileOrigin); boundsMax = Vector3.Max(boundsMax, tileOrigin + tileSize); } if (uncheckedSpriteId != -1) { int indexRoot = vertices.Count; int spriteId = Mathf.Clamp(uncheckedSpriteId, 0, spriteCollection.Count - 1); tk2dSpriteDefinition sprite = spriteCollection.spriteDefinitions[spriteId]; for (int j = 0; j < sprite.positions.Length; ++j) { // Sprite vertex, centered around origin Vector3 centeredSpriteVertex = sprite.positions[j] - sprite.untrimmedBoundsData[0]; // Offset so origin is at bottom left Vector3 v = centeredSpriteVertex + sprite.untrimmedBoundsData[1] * 0.5f; boundsMin = Vector3.Min(boundsMin, tileOrigin + v); boundsMax = Vector3.Max(boundsMax, tileOrigin + v); vertices.Add(tileOrigin + v); uvs.Add(sprite.uvs[j]); } if (!triangles.ContainsKey(sprite.material)) { triangles.Add(sprite.material, new List <int>()); } for (int j = 0; j < sprite.indices.Length; ++j) { triangles[sprite.material].Add(indexRoot + sprite.indices[j]); } } tileX += 1; if (tileX == tilesPerRow) { tileX = 0; tileY -= 1; } } } else { // the brush is centered around origin, x to the right, y up foreach (var tile in brush.tiles) { float xOffset = (tile.y & 1) * tileOffsetX; // The origin of the tile in mesh space Vector3 tileOrigin = new Vector3((tile.x + xOffset) * tileSize.x, tile.y * tileSize.y, tile.layer * layerOffset); //if (brush.overrideWithSpriteBounds) { boundsMin = Vector3.Min(boundsMin, tileOrigin); boundsMax = Vector3.Max(boundsMax, tileOrigin + tileSize); } if (tile.spriteId == -1) { continue; } int indexRoot = vertices.Count; tile.spriteId = (ushort)Mathf.Clamp(tile.spriteId, 0, spriteCollection.Count - 1); var sprite = spriteCollection.spriteDefinitions[tile.spriteId]; for (int j = 0; j < sprite.positions.Length; ++j) { // Sprite vertex, centered around origin Vector3 centeredSpriteVertex = sprite.positions[j] - sprite.untrimmedBoundsData[0]; // Offset so origin is at bottom left Vector3 v = centeredSpriteVertex + sprite.untrimmedBoundsData[1] * 0.5f; boundsMin = Vector3.Min(boundsMin, tileOrigin + v); boundsMax = Vector3.Max(boundsMax, tileOrigin + v); vertices.Add(tileOrigin + v); uvs.Add(sprite.uvs[j]); } if (!triangles.ContainsKey(sprite.material)) { triangles.Add(sprite.material, new List <int>()); } for (int j = 0; j < sprite.indices.Length; ++j) { triangles[sprite.material].Add(indexRoot + sprite.indices[j]); } } } if (dictData.mesh == null) { dictData.mesh = new Mesh(); dictData.mesh.hideFlags = HideFlags.DontSave; } Mesh mesh = dictData.mesh; mesh.Clear(); mesh.vertices = vertices.ToArray(); Color[] colors = new Color[vertices.Count]; for (int i = 0; i < vertices.Count; ++i) { colors[i] = Color.white; } mesh.colors = colors; mesh.uv = uvs.ToArray(); mesh.subMeshCount = triangles.Keys.Count; int subMeshId = 0; foreach (Material mtl in triangles.Keys) { mesh.SetTriangles(triangles[mtl].ToArray(), subMeshId); subMeshId++; } dictData.brush = brush; dictData.brushHash = brush.brushHash; dictData.mesh = mesh; dictData.materials = (new List <Material>(triangles.Keys)).ToArray(); dictData.rect = new Rect(boundsMin.x, boundsMin.y, boundsMax.x - boundsMin.x, boundsMax.y - boundsMin.y); }
void CommitBrushSplats(tk2dTileMapEditorBrush brush) { if (brush.paintMode != tk2dTileMapEditorBrush.PaintMode.Random && brush.paintMode != tk2dTileMapEditorBrush.PaintMode.Edged) { return; } int x0 = Mathf.Min(cursorX, cursorX0); int x1 = Mathf.Max(cursorX, cursorX0); int y0 = Mathf.Min(cursorY, cursorY0); int y1 = Mathf.Max(cursorY, cursorY0); int tilesX = x1 - x0 + 1; int tilesY = y1 - y0 + 1; if (brush.paintMode == tk2dTileMapEditorBrush.PaintMode.Edged && brush.edgeMode != tk2dTileMapEditorBrush.EdgeMode.None) { int numSlicedTilesX = (brush.edgeMode == tk2dTileMapEditorBrush.EdgeMode.Horizontal || brush.edgeMode == tk2dTileMapEditorBrush.EdgeMode.Square)?3:1; int numSlicedTilesY = (brush.edgeMode == tk2dTileMapEditorBrush.EdgeMode.Vertical || brush.edgeMode == tk2dTileMapEditorBrush.EdgeMode.Square)?3:1; for (int x = 0; x < tilesX; ++x) { for (int y = 0; y < tilesY; ++y) { // local y, tilemap space is y up, brush is y down int ly = (tilesY - 1 - y); // collapse tiles int tx; if (numSlicedTilesX == 1 || x == 0) tx = 0; else if (x == tilesX - 1) tx = 2; else tx = 1; int ty; if (numSlicedTilesY == 1 || ly == 0) ty = 0; else if (ly == tilesY - 1) ty = 2; else ty = 1; //int spriteId = brush.multiSelectTiles[0]; int spriteId = brush.multiSelectTiles[ty * numSlicedTilesX + tx]; SplatTile(x0 + x, y0 + y, editorData.layer, spriteId); } } host.BuildIncremental(); } else { var rng = new System.Random(randomSeed); for (int x = 0; x < tilesX; ++x) { for (int y = 0; y < tilesY; ++y) { if (brush.type == tk2dTileMapEditorBrush.Type.MultiSelect || brush.type == tk2dTileMapEditorBrush.Type.Single || brush.type == tk2dTileMapEditorBrush.Type.Custom) { var spriteId = brush.multiSelectTiles[rng.Next(brush.multiSelectTiles.Length)]; SplatTile(x0 + x, y0 + y, editorData.layer, spriteId); } } } host.BuildIncremental(); } }
public void OnSceneGUI() { // Always draw the outline DrawOutline(); if (Application.isPlaying || !tileMap.AllowEdit) { return; } if (editorData.editMode != tk2dTileMapEditorData.EditMode.Paint && editorData.editMode != tk2dTileMapEditorData.EditMode.Color) { return; } if (editorData.editMode == tk2dTileMapEditorData.EditMode.Color && !tileMap.HasColorChannel()) { return; } int controlID = GUIUtility.GetControlID(tileMapHashCode, FocusType.Passive); EventType controlEventType = Event.current.GetTypeForControl(controlID); switch (controlEventType) { case EventType.MouseDown: case EventType.MouseDrag: if ((controlEventType == EventType.MouseDrag && GUIUtility.hotControl != controlID) || Event.current.button != 0) { return; } if (Event.current.type == EventType.MouseDown) { if (IsCursorInside() && !Event.current.shift) { bool pickupKeyDown = (Application.platform == RuntimePlatform.OSXEditor)?Event.current.control:Event.current.alt; bool eraseKeyDown = false; if (Application.platform == RuntimePlatform.OSXEditor) { if (Event.current.command && !Event.current.alt) { eraseKeyDown = true; } } else { eraseKeyDown = Event.current.control; } if (pickupKeyDown) { pickup = true; GUIUtility.hotControl = controlID; } else if (eraseKeyDown) { Undo.RegisterUndo(tileMap, "Erased tile map"); erase = true; GUIUtility.hotControl = controlID; } else if (!Event.current.command && !Event.current.alt && !Event.current.control) { GUIUtility.hotControl = controlID; randomSeed = Random.Range(0, int.MaxValue); Undo.RegisterUndo(tileMap, "Painted tile map"); Splat(); } } } if (Event.current.type == EventType.MouseDrag && GUIUtility.hotControl == controlID) { UpdateCursorPosition(); if (!pickup && !erase) { Splat(); } } break; case EventType.MouseUp: if (Event.current.button == 0 && GUIUtility.hotControl == controlID) { GUIUtility.hotControl = 0; if (pickup) { PickUp(); pickup = false; } else if (erase) { Erase(); erase = false; } else { CommitSplats(); } cursorX0 = cursorX; cursorY0 = cursorY; HandleUtility.Repaint(); } break; case EventType.Layout: //HandleUtility.AddDefaultControl(controlID); break; case EventType.MouseMove: UpdateCursorPosition(); cursorX0 = cursorX; cursorY0 = cursorY; break; } tk2dTileMapEditorBrush activeBrush = editorData.activeBrush; switch (editorData.editMode) { case tk2dTileMapEditorData.EditMode.Paint: DrawTileCursor(activeBrush); break; case tk2dTileMapEditorData.EditMode.Color: DrawPaintCursor(); break; } }
void PickUpBrush(tk2dTileMapEditorBrush brush, bool allLayers) { bool pickFromScratchpad = (scratchpadGUI.workingHere || scratchpadGUI.requestSelectAllTiles); int x0 = Mathf.Min(cursorX, cursorX0); int x1 = Mathf.Max(cursorX, cursorX0); int y0 = Mathf.Min(cursorY, cursorY0); int y1 = Mathf.Max(cursorY, cursorY0); if (pickFromScratchpad) { // Clamp to scratchpad int scratchW, scratchH; scratchpadGUI.GetScratchpadSize(out scratchW, out scratchH); x0 = Mathf.Clamp(x0, 0, scratchW - 1); y0 = Mathf.Clamp(y0, 0, scratchH - 1); x1 = Mathf.Clamp(x1, 0, scratchW - 1); y1 = Mathf.Clamp(y1, 0, scratchH - 1); } else { // Clamp to tilemap x0 = Mathf.Clamp(x0, 0, tileMap.width - 1); y0 = Mathf.Clamp(y0, 0, tileMap.height - 1); x1 = Mathf.Clamp(x1, 0, tileMap.width - 1); y1 = Mathf.Clamp(y1, 0, tileMap.height - 1); } int numTilesX = x1 - x0 + 1; int numTilesY = y1 - y0 + 1; List <tk2dSparseTile> sparseTile = new List <tk2dSparseTile>(); List <int> tiles = new List <int>(); int numLayers = tileMap.data.NumLayers; int startLayer = 0; int endLayer = numLayers; if (allLayers) { brush.multiLayer = true; } else { brush.multiLayer = false; startLayer = editorData.layer; endLayer = startLayer + 1; } // Scratchpad only allows one layer for now if (pickFromScratchpad) { startLayer = 0; endLayer = 1; } if (tileMap.data.tileType == tk2dTileMapData.TileType.Rectangular) { for (int layer = startLayer; layer < endLayer; ++layer) { for (int y = numTilesY - 1; y >= 0; --y) { for (int x = 0; x < numTilesX; ++x) { int tile; if (pickFromScratchpad) { tile = scratchpadGUI.GetTile(x0 + x, y0 + y, layer); } else { tile = tileMap.Layers[layer].GetRawTile(x0 + x, y0 + y); } tiles.Add(tile); sparseTile.Add(new tk2dSparseTile(x, y, allLayers?layer:0, tile)); } } } } else if (tileMap.data.tileType == tk2dTileMapData.TileType.Isometric) { int xOffset = 0; int yOffset = 0; if ((y0 & 1) != 0) { yOffset -= 1; } for (int layer = startLayer; layer < endLayer; ++layer) { for (int y = numTilesY - 1; y >= 0; --y) { for (int x = 0; x < numTilesX; ++x) { int tile; if (pickFromScratchpad) { tile = scratchpadGUI.GetTile(x0 + x, y0 + y, layer); } else { tile = tileMap.Layers[layer].GetRawTile(x0 + x, y0 + y); } tiles.Add(tile); sparseTile.Add(new tk2dSparseTile(x + xOffset, y + yOffset, allLayers?layer:0, tile)); } } } } brush.type = tk2dTileMapEditorBrush.Type.Custom; if (numTilesX == 1 && numTilesY == 3) { brush.edgeMode = tk2dTileMapEditorBrush.EdgeMode.Vertical; } else if (numTilesX == 3 && numTilesY == 1) { brush.edgeMode = tk2dTileMapEditorBrush.EdgeMode.Horizontal; } else if (numTilesX == 3 && numTilesY == 3) { brush.edgeMode = tk2dTileMapEditorBrush.EdgeMode.Square; } else { brush.edgeMode = tk2dTileMapEditorBrush.EdgeMode.None; } brush.tiles = sparseTile.ToArray(); brush.multiSelectTiles = tiles.ToArray(); brush.UpdateBrushHash(); // Make the inspector update EditorUtility.SetDirty(tileMap); }
void DrawTileCursor(tk2dTileMapEditorBrush brush) { float layerZ = 0.0f; if (brush.paintMode == tk2dTileMapEditorBrush.PaintMode.Random || brush.paintMode == tk2dTileMapEditorBrush.PaintMode.Edged || pickup || erase) { int x0 = cursorX; int y0 = cursorY; int tilesX = 1; int tilesY = 1; x0 = Mathf.Min(cursorX, cursorX0); int x1 = Mathf.Max(cursorX, cursorX0); y0 = Mathf.Min(cursorY, cursorY0); int y1 = Mathf.Max(cursorY, cursorY0); tilesX = x1 - x0 + 1; tilesY = y1 - y0 + 1; Vector3 p0 = new Vector3(tileMapData.tileOrigin.x + x0 * tileMapData.tileSize.x, tileMapData.tileOrigin.y + y0 * tileMapData.tileSize.y, layerZ); Vector3 p1 = new Vector3(p0.x + tileMapData.tileSize.x * tilesX, p0.y + tileMapData.tileSize.y * tilesY, 0); Vector3[] v = new Vector3[4]; v[0] = new Vector3(p0.x, p0.y, 0); v[1] = new Vector3(p1.x, p0.y, 0); v[2] = new Vector3(p1.x, p1.y, 0); v[3] = new Vector3(p0.x, p1.y, 0); for (int i = 0; i < v.Length; ++i) { v[i] = tileMap.transform.TransformPoint(v[i]); } Handles.DrawSolidRectangleWithOutline(v, tileSelectionFillColor, tileSelectionOutlineColor); } else if (brush.type == tk2dTileMapEditorBrush.Type.MultiSelect) { Vector3 p0 = new Vector3(tileMapData.tileOrigin.x + (cursorX) * tileMapData.tileSize.x, tileMapData.tileOrigin.y + (cursorY) * tileMapData.tileSize.y, layerZ); Vector3 p1 = new Vector3(p0.x + tileMapData.tileSize.x, p0.y + tileMapData.tileSize.y, 0); Vector3[] v = new Vector3[4]; v[0] = new Vector3(p0.x, p0.y, 0); v[1] = new Vector3(p1.x, p0.y, 0); v[2] = new Vector3(p1.x, p1.y, 0); v[3] = new Vector3(p0.x, p1.y, 0); for (int i = 0; i < v.Length; ++i) { v[i] = tileMap.transform.TransformPoint(v[i]); } Handles.DrawSolidRectangleWithOutline(v, tileSelectionFillColor, tileSelectionOutlineColor); } else { foreach (var tile in brush.tiles) { Vector3 p0 = new Vector3(tileMapData.tileOrigin.x + (cursorX + tile.x) * tileMapData.tileSize.x, tileMapData.tileOrigin.y + (cursorY + tile.y) * tileMapData.tileSize.y, layerZ); Vector3 p1 = new Vector3(p0.x + tileMapData.tileSize.x, p0.y + tileMapData.tileSize.y, 0); Vector3[] v = new Vector3[4]; v[0] = new Vector3(p0.x, p0.y, 0); v[1] = new Vector3(p1.x, p0.y, 0); v[2] = new Vector3(p1.x, p1.y, 0); v[3] = new Vector3(p0.x, p1.y, 0); for (int i = 0; i < v.Length; ++i) { v[i] = tileMap.transform.TransformPoint(v[i]); } Handles.DrawSolidRectangleWithOutline(v, tileSelectionFillColor, tileSelectionOutlineColor); } } }
public Rect GetBrushViewRect(tk2dTileMapEditorBrush brush, int tilesPerRow) { var dictData = GetDictDataForBrush(brush, tilesPerRow); return(BrushToScreenRect(dictData.rect)); }
void CommitBrushSplats(tk2dTileMapEditorBrush brush) { if (brush.paintMode != tk2dTileMapEditorBrush.PaintMode.Random && brush.paintMode != tk2dTileMapEditorBrush.PaintMode.Edged) { return; } int x0 = Mathf.Min(cursorX, cursorX0); int x1 = Mathf.Max(cursorX, cursorX0); int y0 = Mathf.Min(cursorY, cursorY0); int y1 = Mathf.Max(cursorY, cursorY0); int tilesX = x1 - x0 + 1; int tilesY = y1 - y0 + 1; if (brush.paintMode == tk2dTileMapEditorBrush.PaintMode.Edged && brush.edgeMode != tk2dTileMapEditorBrush.EdgeMode.None) { int numSlicedTilesX = (brush.edgeMode == tk2dTileMapEditorBrush.EdgeMode.Horizontal || brush.edgeMode == tk2dTileMapEditorBrush.EdgeMode.Square)?3:1; int numSlicedTilesY = (brush.edgeMode == tk2dTileMapEditorBrush.EdgeMode.Vertical || brush.edgeMode == tk2dTileMapEditorBrush.EdgeMode.Square)?3:1; for (int x = 0; x < tilesX; ++x) { for (int y = 0; y < tilesY; ++y) { // local y, tilemap space is y up, brush is y down int ly = (tilesY - 1 - y); // collapse tiles int tx; if (numSlicedTilesX == 1 || x == 0) { tx = 0; } else if (x == tilesX - 1) { tx = 2; } else { tx = 1; } int ty; if (numSlicedTilesY == 1 || ly == 0) { ty = 0; } else if (ly == tilesY - 1) { ty = 2; } else { ty = 1; } //int spriteId = brush.multiSelectTiles[0]; int spriteId = brush.multiSelectTiles[ty * numSlicedTilesX + tx]; SplatTile(x0 + x, y0 + y, editorData.layer, spriteId); } } host.BuildIncremental(); } else { var rng = new System.Random(randomSeed); for (int x = 0; x < tilesX; ++x) { for (int y = 0; y < tilesY; ++y) { if (brush.type == tk2dTileMapEditorBrush.Type.MultiSelect || brush.type == tk2dTileMapEditorBrush.Type.Single || brush.type == tk2dTileMapEditorBrush.Type.Custom) { var spriteId = brush.multiSelectTiles[rng.Next(brush.multiSelectTiles.Length)]; SplatTile(x0 + x, y0 + y, editorData.layer, spriteId); } } } host.BuildIncremental(); } }
public void CreateDefaultPalette(tk2dSpriteCollectionData spriteCollection, tk2dTileMapEditorBrush brush, int numTilesX) { List<tk2dSparseTile> tiles = new List<tk2dSparseTile>(); var spriteDefinitions = spriteCollection.spriteDefinitions; int numTilesY = spriteDefinitions.Length / numTilesX; if (numTilesY * numTilesX < spriteDefinitions.Length) numTilesY++; for (ushort spriteIndex = 0; spriteIndex < spriteDefinitions.Length; ++spriteIndex) { if (spriteDefinitions[spriteIndex].Valid) tiles.Add(new tk2dSparseTile(spriteIndex % numTilesX, numTilesY - 1 - spriteIndex / numTilesX, 0, spriteIndex)); } brush.tiles = tiles.ToArray(); brush.UpdateBrushHash(); }
public tk2dTileMapScratchpad() { width = 0; height = 0; layers = new tk2dScratchpadLayer[0]; canvas = new tk2dTileMapEditorBrush(); }
// Build a mesh for a list of given sprites void BuildMeshForBrush(tk2dTileMapEditorBrush brush, BrushDictData dictData, int tilesPerRow) { List <Vector3> vertices = new List <Vector3>(); List <Vector2> uvs = new List <Vector2>(); List <int> triangles = new List <int>(); // bounds of tile Vector3 tileSize = spriteCollection.FirstValidDefinition.untrimmedBoundsData[1]; float layerOffset = 0.001f; Vector3 boundsMin = new Vector3(1.0e32f, 1.0e32f, 1.0e32f); Vector3 boundsMax = new Vector3(-1.0e32f, -1.0e32f, -1.0e32f); if (brush.type == tk2dTileMapEditorBrush.Type.MultiSelect) { int tileX = 0; int tileY = brush.multiSelectTiles.Length / tilesPerRow; if ((brush.multiSelectTiles.Length % tilesPerRow) == 0) { tileY -= 1; } foreach (var uncheckedSpriteId in brush.multiSelectTiles) { // The origin of the tile in mesh space Vector3 tileOrigin = new Vector3(tileX * tileSize.x, tileY * tileSize.y, 0.0f); boundsMin = Vector3.Min(boundsMin, tileOrigin); boundsMax = Vector3.Max(boundsMax, tileOrigin + tileSize); if (uncheckedSpriteId != -1) { int indexRoot = vertices.Count; int spriteId = Mathf.Clamp(uncheckedSpriteId, 0, spriteCollection.Count - 1); var sprite = spriteCollection.spriteDefinitions[spriteId]; for (int j = 0; j < sprite.positions.Length; ++j) { // Sprite vertex, centered around origin Vector3 centeredSpriteVertex = sprite.positions[j] - sprite.untrimmedBoundsData[0]; // Offset so origin is at bottom left Vector3 v = centeredSpriteVertex + sprite.untrimmedBoundsData[1] * 0.5f; vertices.Add(tileOrigin + v); uvs.Add(sprite.uvs[j]); } for (int j = 0; j < sprite.indices.Length; ++j) { triangles.Add(indexRoot + sprite.indices[j]); } } tileX += 1; if (tileX == tilesPerRow) { tileX = 0; tileY -= 1; } } } else { // the brush is centered around origin, x to the right, y up foreach (var tile in brush.tiles) { // The origin of the tile in mesh space Vector3 tileOrigin = new Vector3(tile.x * tileSize.x, tile.y * tileSize.y, tile.layer * layerOffset); boundsMin = Vector3.Min(boundsMin, tileOrigin); boundsMax = Vector3.Max(boundsMax, tileOrigin + tileSize); if (tile.spriteId == -1) { continue; } int indexRoot = vertices.Count; tile.spriteId = (ushort)Mathf.Clamp(tile.spriteId, 0, spriteCollection.Count - 1); var sprite = spriteCollection.spriteDefinitions[tile.spriteId]; for (int j = 0; j < sprite.positions.Length; ++j) { // Sprite vertex, centered around origin Vector3 centeredSpriteVertex = sprite.positions[j] - sprite.untrimmedBoundsData[0]; // Offset so origin is at bottom left Vector3 v = centeredSpriteVertex + sprite.untrimmedBoundsData[1] * 0.5f; vertices.Add(tileOrigin + v); uvs.Add(sprite.uvs[j]); } for (int j = 0; j < sprite.indices.Length; ++j) { triangles.Add(indexRoot + sprite.indices[j]); } } } Mesh mesh = (dictData.mesh != null)?dictData.mesh:new Mesh(); mesh.Clear(); mesh.vertices = vertices.ToArray(); mesh.uv = uvs.ToArray(); mesh.triangles = triangles.ToArray(); dictData.brush = brush; dictData.brushHash = brush.brushHash; dictData.mesh = mesh; dictData.rect = new Rect(boundsMin.x, boundsMin.y, boundsMax.x - boundsMin.x, boundsMax.y - boundsMin.y); }
public void InitBrushes(tk2dSpriteCollectionData spriteCollection) { if (defaultBrush == null || defaultBrush.Empty) { defaultBrush = new tk2dTileMapEditorBrush(); } if (brushes == null) { brushes = new List<tk2dTileMapEditorBrush>(); } if (paletteBrush == null || paletteBrush.Empty || !paletteBrush.overrideWithSpriteBounds) { paletteBrush = new tk2dTileMapEditorBrush(); paletteBrush.overrideWithSpriteBounds = true; CreateDefaultPalette(spriteCollection, paletteBrush, paletteTilesPerRow); } int spriteCount = spriteCollection.spriteDefinitions.Length; foreach (var brush in brushes) { for (int j = 0; j < brush.tiles.Length; ++j) { brush.tiles[j].spriteId = (ushort)Mathf.Clamp(brush.tiles[j].spriteId, 0, spriteCount - 1); } } if (activeBrush == null || activeBrush.Empty) { activeBrush = defaultBrush; } }
void PickUpBrush(tk2dTileMapEditorBrush brush, bool allLayers) { bool pickFromScratchpad = (scratchpadGUI.workingHere || scratchpadGUI.requestSelectAllTiles); int x0 = Mathf.Min(cursorX, cursorX0); int x1 = Mathf.Max(cursorX, cursorX0); int y0 = Mathf.Min(cursorY, cursorY0); int y1 = Mathf.Max(cursorY, cursorY0); if (pickFromScratchpad) { // Clamp to scratchpad int scratchW, scratchH; scratchpadGUI.GetScratchpadSize(out scratchW, out scratchH); x0 = Mathf.Clamp(x0, 0, scratchW - 1); y0 = Mathf.Clamp(y0, 0, scratchH - 1); x1 = Mathf.Clamp(x1, 0, scratchW - 1); y1 = Mathf.Clamp(y1, 0, scratchH - 1); } else { // Clamp to tilemap x0 = Mathf.Clamp(x0, 0, tileMap.width - 1); y0 = Mathf.Clamp(y0, 0, tileMap.height - 1); x1 = Mathf.Clamp(x1, 0, tileMap.width - 1); y1 = Mathf.Clamp(y1, 0, tileMap.height - 1); } int numTilesX = x1 - x0 + 1; int numTilesY = y1 - y0 + 1; List<tk2dSparseTile> sparseTile = new List<tk2dSparseTile>(); List<int> tiles = new List<int>(); int numLayers = tileMap.data.NumLayers; int startLayer = 0; int endLayer = numLayers; if (allLayers) { brush.multiLayer = true; } else { brush.multiLayer = false; startLayer = editorData.layer; endLayer = startLayer + 1; } // Scratchpad only allows one layer for now if (pickFromScratchpad) { startLayer = 0; endLayer = 1; } if (tileMap.data.tileType == tk2dTileMapData.TileType.Rectangular) { for (int layer = startLayer; layer < endLayer; ++layer) { for (int y = numTilesY - 1; y >= 0; --y) { for (int x = 0; x < numTilesX; ++x) { int tile; if (pickFromScratchpad) { tile = scratchpadGUI.GetTile(x0 + x, y0 + y, layer); } else { tile = tileMap.Layers[layer].GetRawTile(x0 + x, y0 + y); } tiles.Add(tile); sparseTile.Add(new tk2dSparseTile(x, y, allLayers?layer:0, tile)); } } } } else if (tileMap.data.tileType == tk2dTileMapData.TileType.Isometric) { int xOffset = 0; int yOffset = 0; if ((y0 & 1) != 0) yOffset -= 1; for (int layer = startLayer; layer < endLayer; ++layer) { for (int y = numTilesY - 1; y >= 0; --y) { for (int x = 0; x < numTilesX; ++x) { int tile; if (pickFromScratchpad) { tile = scratchpadGUI.GetTile(x0 + x, y0 + y, layer); } else { tile = tileMap.Layers[layer].GetRawTile(x0 + x, y0 + y); } tiles.Add(tile); sparseTile.Add(new tk2dSparseTile(x + xOffset, y + yOffset, allLayers?layer:0, tile)); } } } } brush.type = tk2dTileMapEditorBrush.Type.Custom; if (numTilesX == 1 && numTilesY == 3) brush.edgeMode = tk2dTileMapEditorBrush.EdgeMode.Vertical; else if (numTilesX == 3 && numTilesY == 1) brush.edgeMode = tk2dTileMapEditorBrush.EdgeMode.Horizontal; else if (numTilesX == 3 && numTilesY == 3) brush.edgeMode = tk2dTileMapEditorBrush.EdgeMode.Square; else brush.edgeMode = tk2dTileMapEditorBrush.EdgeMode.None; brush.tiles = sparseTile.ToArray(); brush.multiSelectTiles = tiles.ToArray(); brush.UpdateBrushHash(); // Make the inspector update EditorUtility.SetDirty(tileMap); }
void DrawLoadSaveBrushSection(tk2dTileMapEditorBrush activeBrush) { // Brush load & save handling bool startedSave = false; bool prevGuiEnabled = GUI.enabled; GUILayout.BeginHorizontal(); if (showLoadSection) GUI.enabled = false; if (GUILayout.Button(showSaveSection?"Cancel":"Save")) { if (showSaveSection == false) startedSave = true; showSaveSection = !showSaveSection; if (showSaveSection) showLoadSection = false; Repaint(); } GUI.enabled = prevGuiEnabled; if (showSaveSection) GUI.enabled = false; if (GUILayout.Button(showLoadSection?"Cancel":"Load")) { showLoadSection = !showLoadSection; if (showLoadSection) showSaveSection = false; } GUI.enabled = prevGuiEnabled; GUILayout.EndHorizontal(); if (showSaveSection) { GUI.SetNextControlName("BrushNameEntry"); activeBrush.name = EditorGUILayout.TextField("Name", activeBrush.name); if (startedSave) GUI.FocusControl("BrushNameEntry"); if (GUILayout.Button("Save")) { if (activeBrush.name.Length == 0) { Debug.LogError("Active brush needs a name"); } else { bool replaced = false; for (int i = 0; i < editorData.brushes.Count; ++i) { if (editorData.brushes[i].name == activeBrush.name) { editorData.brushes[i] = new tk2dTileMapEditorBrush(activeBrush); replaced = true; } } if (!replaced) editorData.brushes.Add(new tk2dTileMapEditorBrush(activeBrush)); showSaveSection = false; } } } if (showLoadSection) { GUILayout.Space(8); if (editorData.brushes.Count == 0) GUILayout.Label("No saved brushes."); GUILayout.BeginVertical(); int deleteBrushId = -1; for (int i = 0; i < editorData.brushes.Count; ++i) { var v = editorData.brushes[i]; GUILayout.BeginHorizontal(); if (GUILayout.Button(v.name, EditorStyles.miniButton)) { showLoadSection = false; editorData.activeBrush = new tk2dTileMapEditorBrush(v); } if (GUILayout.Button("X", EditorStyles.miniButton, GUILayout.Width(16))) { deleteBrushId = i; } GUILayout.EndHorizontal(); } if (deleteBrushId != -1) { editorData.brushes.RemoveAt(deleteBrushId); Repaint(); } GUILayout.EndVertical(); } }
public tk2dTileMapEditorBrush(tk2dTileMapEditorBrush source) { this.name = source.name; this.type = source.type; this.paintMode = source.paintMode; tiles = new tk2dSparseTile[source.tiles.Length]; for (int i = 0; i < source.tiles.Length; ++i) tiles[i] = new tk2dSparseTile(source.tiles[i]); multiSelectTiles = new int[source.multiSelectTiles.Length]; for (int i = 0; i < source.multiSelectTiles.Length; ++i) multiSelectTiles[i] = source.multiSelectTiles[i]; edgeMode = source.edgeMode; multiLayer = source.multiLayer; overrideWithSpriteBounds = source.overrideWithSpriteBounds; }
void DrawLoadSaveBrushSection(tk2dTileMapEditorBrush activeBrush) { // Brush load & save handling bool startedSave = false; bool prevGuiEnabled = GUI.enabled; GUILayout.BeginHorizontal(); if (showLoadSection) GUI.enabled = false; if (GUILayout.Button(showSaveSection?"Cancel":"Save")) { if (showSaveSection == false) startedSave = true; showSaveSection = !showSaveSection; if (showSaveSection) showLoadSection = false; Repaint(); } GUI.enabled = prevGuiEnabled; if (showSaveSection) GUI.enabled = false; if (GUILayout.Button(showLoadSection?"Cancel":"Load")) { showLoadSection = !showLoadSection; if (showLoadSection) showSaveSection = false; } GUI.enabled = prevGuiEnabled; GUILayout.EndHorizontal(); if (showSaveSection) { GUI.SetNextControlName("BrushNameEntry"); activeBrush.name = EditorGUILayout.TextField("Name", activeBrush.name); if (startedSave) GUI.FocusControl("BrushNameEntry"); if (GUILayout.Button("Save")) { if (activeBrush.name.Length == 0) { Debug.LogError("Active brush needs a name"); } else { bool replaced = false; for (int i = 0; i < editorData.brushes.Count; ++i) { if (editorData.brushes[i].name == activeBrush.name) { editorData.brushes[i] = new tk2dTileMapEditorBrush(activeBrush); replaced = true; } } if (!replaced) editorData.brushes.Add(new tk2dTileMapEditorBrush(activeBrush)); showSaveSection = false; } } } if (showLoadSection) { GUILayout.Space(8); if (editorData.brushes.Count == 0) GUILayout.Label("No saved brushes."); GUILayout.BeginVertical(); int deleteBrushId = -1; for (int i = 0; i < editorData.brushes.Count; ++i) { var v = editorData.brushes[i]; GUILayout.BeginHorizontal(); if (GUILayout.Button(v.name, EditorStyles.miniButton)) { showLoadSection = false; editorData.activeBrush = new tk2dTileMapEditorBrush(v); } if (GUILayout.Button("X", EditorStyles.miniButton, GUILayout.Width(16))) { deleteBrushId = i; } GUILayout.EndHorizontal(); } if (deleteBrushId != -1) { editorData.brushes.RemoveAt(deleteBrushId); Repaint(); } GUILayout.EndVertical(); } }
// Build a mesh for a list of given sprites void BuildMeshForBrush(tk2dTileMapEditorBrush brush, BrushDictData dictData, int tilesPerRow) { List<Vector3> vertices = new List<Vector3>(); List<Vector2> uvs = new List<Vector2>(); List<int> triangles = new List<int>(); // bounds of tile Vector3 tileSize = spriteCollection.FirstValidDefinition.untrimmedBoundsData[1]; float layerOffset = 0.001f; Vector3 boundsMin = new Vector3(1.0e32f, 1.0e32f, 1.0e32f); Vector3 boundsMax = new Vector3(-1.0e32f, -1.0e32f, -1.0e32f); if (brush.type == tk2dTileMapEditorBrush.Type.MultiSelect) { int tileX = 0; int tileY = brush.multiSelectTiles.Length / tilesPerRow; if ((brush.multiSelectTiles.Length % tilesPerRow) == 0) tileY -=1; foreach (var uncheckedSpriteId in brush.multiSelectTiles) { // The origin of the tile in mesh space Vector3 tileOrigin = new Vector3(tileX * tileSize.x, tileY * tileSize.y, 0.0f); boundsMin = Vector3.Min(boundsMin, tileOrigin); boundsMax = Vector3.Max(boundsMax, tileOrigin + tileSize); if (uncheckedSpriteId != -1) { int indexRoot = vertices.Count; int spriteId = Mathf.Clamp(uncheckedSpriteId, 0, spriteCollection.Count - 1); var sprite = spriteCollection.spriteDefinitions[spriteId]; for (int j = 0; j < sprite.positions.Length; ++j) { // Sprite vertex, centered around origin Vector3 centeredSpriteVertex = sprite.positions[j] - sprite.untrimmedBoundsData[0]; // Offset so origin is at bottom left Vector3 v = centeredSpriteVertex + sprite.untrimmedBoundsData[1] * 0.5f; vertices.Add(tileOrigin + v); uvs.Add(sprite.uvs[j]); } for (int j = 0; j < sprite.indices.Length; ++j) { triangles.Add(indexRoot + sprite.indices[j]); } } tileX += 1; if (tileX == tilesPerRow) { tileX = 0; tileY -= 1; } } } else { // the brush is centered around origin, x to the right, y up foreach (var tile in brush.tiles) { // The origin of the tile in mesh space Vector3 tileOrigin = new Vector3(tile.x * tileSize.x, tile.y * tileSize.y, tile.layer * layerOffset); boundsMin = Vector3.Min(boundsMin, tileOrigin); boundsMax = Vector3.Max(boundsMax, tileOrigin + tileSize); if (tile.spriteId == -1) continue; int indexRoot = vertices.Count; tile.spriteId = (ushort)Mathf.Clamp(tile.spriteId, 0, spriteCollection.Count - 1); var sprite = spriteCollection.spriteDefinitions[tile.spriteId]; for (int j = 0; j < sprite.positions.Length; ++j) { // Sprite vertex, centered around origin Vector3 centeredSpriteVertex = sprite.positions[j] - sprite.untrimmedBoundsData[0]; // Offset so origin is at bottom left Vector3 v = centeredSpriteVertex + sprite.untrimmedBoundsData[1] * 0.5f; vertices.Add(tileOrigin + v); uvs.Add(sprite.uvs[j]); } for (int j = 0; j < sprite.indices.Length; ++j) { triangles.Add(indexRoot + sprite.indices[j]); } } } Mesh mesh = (dictData.mesh != null)?dictData.mesh:new Mesh(); mesh.Clear(); mesh.vertices = vertices.ToArray(); mesh.uv = uvs.ToArray(); mesh.triangles = triangles.ToArray(); dictData.brush = brush; dictData.brushHash = brush.brushHash; dictData.mesh = mesh; dictData.rect = new Rect(boundsMin.x, boundsMin.y, boundsMax.x - boundsMin.x, boundsMax.y - boundsMin.y); }