public override bool Compile(GameAssetType gameAsset, Uri baseUri, BinaryAsset asset, XmlNode node, GameDefinition game, string trace, ref int position, out string ErrorDescription) { List <TerrainTextureTileRuntime> tiles = new List <TerrainTextureTileRuntime>(); List <XmlNode> nodes = new List <XmlNode>(); foreach (XmlNode childNode in node.ChildNodes) { if (childNode.Name == "Tile") { nodes.Add(childNode); } } FileHelper.SetInt(nodes.Count, 4, asset.Content); BinaryAsset tileList = new BinaryAsset(12 * nodes.Count); asset.SubAssets.Add(8, tileList); DDSFile[,] textureList = new DDSFile[nodes.Count, 2]; BinaryAsset baseAsset = new BinaryAsset(0); BinaryAsset normalAsset = new BinaryAsset(0); uint positionX = 16; uint positionY = 16; uint nextY = 0; for (int idx = 0; idx < nodes.Count; ++idx) { FileHelper.SetUInt(uint.Parse(nodes[idx].Attributes["TextureID"].Value), idx * 12, tileList.Content); string baseTexture = nodes[idx].Attributes["BaseTexture"].Value; baseTexture = baseTexture.Substring(baseTexture.LastIndexOf(Path.DirectorySeparatorChar) + 1); baseTexture = baseTexture.Substring(baseTexture.LastIndexOf('/') + 1); baseTexture = baseTexture.Substring(0, baseTexture.LastIndexOf('.')); string baseTexturePath = Macro.Terrain + baseTexture + ".dds"; if (!IOFile.Exists(baseTexturePath)) { ErrorDescription = string.Format("{0} doesn't exist.", baseTexturePath); return(false); } using (FileStream textureStream = new FileStream(baseTexturePath, FileMode.Open, FileAccess.Read, FileShare.Read)) { using (BinaryReader textureReader = new BinaryReader(textureStream)) { textureList[idx, 0] = new DDSFile(textureReader.ReadBytes((int)(textureStream.Length))); } } string normalTexture = nodes[idx].Attributes["NormalTexture"].Value; normalTexture = normalTexture.Substring(normalTexture.LastIndexOf(Path.DirectorySeparatorChar) + 1); normalTexture = normalTexture.Substring(normalTexture.LastIndexOf('/') + 1); normalTexture = normalTexture.Substring(0, normalTexture.LastIndexOf('.')); string normalTexturePath = Macro.Terrain + normalTexture + ".dds"; if (!IOFile.Exists(normalTexturePath)) { ErrorDescription = string.Format("{0} doesn't exist.", normalTexturePath); return(false); } using (FileStream textureStream = new FileStream(normalTexturePath, FileMode.Open, FileAccess.Read, FileShare.Read)) { using (BinaryReader textureReader = new BinaryReader(textureStream)) { textureList[idx, 1] = new DDSFile(textureReader.ReadBytes((int)(textureStream.Length))); } } } // fixed width, automatically calculated height ushort atlasSize = 576; ushort atlasHeight = 0; /* * foreach (XmlAttribute attribute in node.Attributes) * { * switch (attribute.Name) * { * case "AtlasSize": * atlasSize = ushort.Parse(attribute.Value); * break; * } * } */ byte[] baseContent = new byte[0]; byte[] normalContent = new byte[0]; uint rowHeight = 0; for (int tileIdx = 0; tileIdx < textureList.Length >> 1; ++tileIdx) { uint size = textureList[tileIdx, 0].Header.Height; rowHeight = Math.Max(size + 32, rowHeight); if (positionX + size + 16 > atlasSize) { positionX = 16; positionY += nextY; rowHeight = size + 32; } if (positionY + size + 16 > atlasHeight) { atlasHeight += atlasSize; Array.Resize(ref baseContent, atlasSize * 4 * atlasHeight); Array.Resize(ref normalContent, atlasSize * 4 * atlasHeight); } byte[] color = textureList[tileIdx, 0].Content.GetColor(size, size); byte[] normal = textureList[tileIdx, 1].Content.GetColor(size, size); for (int idy = -16; idy < size + 16; ++idy) { for (int idx = -16; idx < size + 16; ++idx) { int tileY = idy; if (tileY < 0) { tileY = (int)(size + tileY); } else if (tileY >= size) { tileY = (int)(tileY - size); } int tileX = idx; if (tileX < 0) { tileX = (int)(size + tileX); } else if (tileX >= size) { tileX = (int)(tileX - size); } baseContent[(positionY + idy) * atlasSize * 4 + (positionX + idx) * 4] = color[tileY * size * 4 + tileX * 4]; baseContent[(positionY + idy) * atlasSize * 4 + (positionX + idx) * 4 + 1] = color[tileY * size * 4 + tileX * 4 + 1]; baseContent[(positionY + idy) * atlasSize * 4 + (positionX + idx) * 4 + 2] = color[tileY * size * 4 + tileX * 4 + 2]; baseContent[(positionY + idy) * atlasSize * 4 + (positionX + idx) * 4 + 3] = color[tileY * size * 4 + tileX * 4 + 3]; normalContent[(positionY + idy) * atlasSize * 4 + (positionX + idx) * 4] = normal[tileY * size * 4 + tileX * 4]; normalContent[(positionY + idy) * atlasSize * 4 + (positionX + idx) * 4 + 1] = normal[tileY * size * 4 + tileX * 4 + 1]; normalContent[(positionY + idy) * atlasSize * 4 + (positionX + idx) * 4 + 2] = normal[tileY * size * 4 + tileX * 4 + 2]; normalContent[(positionY + idy) * atlasSize * 4 + (positionX + idx) * 4 + 3] = normal[tileY * size * 4 + tileX * 4 + 3]; } } FileHelper.SetUShort((ushort)positionX, 12 * tileIdx + 4, tileList.Content); FileHelper.SetUShort((ushort)positionY, 12 * tileIdx + 6, tileList.Content); FileHelper.SetUShort((ushort)(positionX + size), 12 * tileIdx + 8, tileList.Content); FileHelper.SetUShort((ushort)(positionY + size), 12 * tileIdx + 10, tileList.Content); positionX += size + 32; nextY = Math.Max(size + 32, nextY); } bool hasAlpha = false; for (int idx = 0; idx < nodes.Count; ++idx) { if (textureList[idx, 0].HasAlpha()) { hasAlpha = true; break; } } DDSFile baseAtlas = null; if (hasAlpha) { baseAtlas = new DDSFile(atlasSize, atlasHeight, 5, DDSType.DXT5, baseContent); } else { baseAtlas = new DDSFile(atlasSize, atlasHeight, 5, DDSType.DXT1, baseContent); } hasAlpha = false; for (int idx = 0; idx < nodes.Count; ++idx) { if (textureList[idx, 1].HasAlpha()) { hasAlpha = true; break; } } DDSFile normalAtlas = null; if (hasAlpha) { normalAtlas = new DDSFile(atlasSize, atlasHeight, 5, DDSType.A1R5G5B5, normalContent); } else { normalAtlas = new DDSFile(atlasSize, atlasHeight, 5, DDSType.R5G6B5, normalContent); } baseAsset.Content = baseAtlas.Binary; asset.SubAssets.Add(0x0C, baseAsset); FileHelper.SetInt(baseAsset.Content.Length, 0x10, asset.Content); normalAsset.Content = normalAtlas.Binary; asset.SubAssets.Add(0x14, normalAsset); FileHelper.SetInt(normalAsset.Content.Length, 0x18, asset.Content); ErrorDescription = string.Empty; return(true); }