void SendTexture(Agent agent, AssetTexture texture, int discardLevel, int packet, float priority)
        {
            ImageDownload download = new ImageDownload(texture, agent, discardLevel, priority, packet);

            Logger.DebugLog(String.Format(
                "[Periscope] Starting new texture transfer for {0}, DiscardLevel: {1}, Priority: {2}, Start: {3}, End: {4}, Total: {5}",
                texture.AssetID, discardLevel, priority, download.CurrentPacket, download.StopPacket, download.TexturePacketCount()));

            // Send initial data
            ImageDataPacket data = new ImageDataPacket();
            data.ImageID.Codec = (byte)ImageCodec.J2C;
            data.ImageID.ID = download.Texture.AssetID;
            data.ImageID.Packets = (ushort)download.TexturePacketCount();
            data.ImageID.Size = (uint)download.Texture.AssetData.Length;

            // The first bytes of the image are always sent in the ImageData packet
            data.ImageData = new ImageDataPacket.ImageDataBlock();
            int imageDataSize = (download.Texture.AssetData.Length >= ImageDownload.FIRST_IMAGE_PACKET_SIZE) ?
                ImageDownload.FIRST_IMAGE_PACKET_SIZE : download.Texture.AssetData.Length;
            try
            {
                data.ImageData.Data = new byte[imageDataSize];
                Buffer.BlockCopy(download.Texture.AssetData, 0, data.ImageData.Data, 0, imageDataSize);
            }
            catch (Exception ex)
            {
                Logger.Log(String.Format("{0}: imageDataSize={1}", ex.Message, imageDataSize),
                    Helpers.LogLevel.Error);
            }

            server.UDP.SendPacket(agent.Avatar.ID, data, PacketCategory.Texture);

            // Check if ImagePacket packets need to be sent to complete this transfer
            if (download.CurrentPacket <= download.StopPacket)
            {
                // Insert this download into the dictionary
                lock (currentDownloads)
                    currentDownloads[texture.AssetID] = download;

                // Send all of the remaining packets
                ThreadPool.QueueUserWorkItem(
                    delegate(object obj)
                    {
                        while (download.CurrentPacket <= download.StopPacket)
                        {
                            if (download.Priority == 0.0f && download.DiscardLevel == -1)
                                break;

                            lock (download)
                            {
                                int imagePacketSize = (download.CurrentPacket == download.TexturePacketCount() - 1) ?
                                    download.LastPacketSize() : ImageDownload.IMAGE_PACKET_SIZE;

                                ImagePacketPacket transfer = new ImagePacketPacket();
                                transfer.ImageID.ID = texture.AssetID;
                                transfer.ImageID.Packet = (ushort)download.CurrentPacket;
                                transfer.ImageData.Data = new byte[imagePacketSize];

                                try
                                {
                                    Buffer.BlockCopy(download.Texture.AssetData, download.CurrentBytePosition(),
                                        transfer.ImageData.Data, 0, imagePacketSize);
                                }
                                catch (Exception ex)
                                {
                                    Logger.Log(String.Format(
                                        "{0}: CurrentBytePosition()={1}, AssetData.Length={2} imagePacketSize={3}",
                                        ex.Message, download.CurrentBytePosition(), download.Texture.AssetData.Length,
                                        imagePacketSize), Helpers.LogLevel.Error);
                                }

                                server.UDP.SendPacket(agent.Avatar.ID, transfer, PacketCategory.Texture);

                                ++download.CurrentPacket;
                            }
                        }

                        Logger.DebugLog("Completed image transfer for " + texture.AssetID.ToString());

                        // Transfer is complete, remove the reference
                        lock (currentDownloads)
                            currentDownloads.Remove(texture.AssetID);
                    }
                );
            }
        }