Ejemplo n.º 1
0
        private Bitmap GetSculptMap(UUID textureID)
        {
            Bitmap sculptTexture = null;

            if (m_assetClient != null)
            {
                Asset textureAsset;
                if (m_assetClient.TryGetAsset(textureID, "image/x-j2c", out textureAsset))
                {
                    try
                    {
                        sculptTexture = (Bitmap)CSJ2K.J2kImage.FromBytes(textureAsset.Data);
                    }
                    catch (Exception ex)
                    {
                        m_log.Warn("Failed to decode sculpt texture " + textureAsset.ID + ": " + ex.Message);
                    }
                }
                else
                {
                    m_log.Warn("Failed to fetch sculpt texture asset " + textureID);
                }
            }

            return(sculptTexture);
        }
Ejemplo n.º 2
0
        public static OSDMap SerializeAppearance(IAssetClient assetClient, Primitive.TextureEntry texture, byte[] visualParams)
        {
            // Fetch all of the texture assets
            Dictionary <UUID, byte[]> textures = new Dictionary <UUID, byte[]>();

            for (int i = 0; i < texture.FaceTextures.Length; i++)
            {
                Primitive.TextureEntryFace face = texture.FaceTextures[i];
                if (face != null && face.TextureID != AppearanceManager.DEFAULT_AVATAR_TEXTURE && !textures.ContainsKey(face.TextureID))
                {
                    // Fetch this texture
                    Asset asset;
                    if (assetClient.TryGetAsset(face.TextureID, "image/x-j2c", out asset))
                    {
                        textures.Add(face.TextureID, asset.Data);
                    }
                }
            }

            OSDMap assets = new OSDMap(textures.Count);

            foreach (KeyValuePair <UUID, byte[]> kvp in textures)
            {
                assets.Add(kvp.Key.ToString(), OSD.FromBinary(kvp.Value));
            }

            return(new OSDMap
            {
                { "texture", texture.GetOSD() },
                { "parameters", OSD.FromBinary(visualParams) },
                { "assets", assets }
            });
        }
Ejemplo n.º 3
0
        private void GetTextureHandler(Capability cap, IHttpClientContext context, IHttpRequest request, IHttpResponse response)
        {
            // TODO: Change this to a config option
            const string REDIRECT_URL = null;

            // Try to parse the texture ID from the request URL
            NameValueCollection query = HttpUtility.ParseQueryString(request.Uri.Query);
            string textureStr         = query.GetOne("texture_id");

            UUID textureID;

            if (!String.IsNullOrEmpty(textureStr) && UUID.TryParse(textureStr, out textureID))
            {
                Asset texture;

                if (!String.IsNullOrEmpty(REDIRECT_URL))
                {
                    // Only try to fetch locally cached textures. Misses are redirected
                    if (m_assetClient.TryGetCachedAsset(textureID, "image/x-j2c", out texture))
                    {
                        SendTexture(request, response, texture);
                    }
                    else
                    {
                        string textureUrl = REDIRECT_URL + textureID.ToString();
                        m_log.Debug("Redirecting texture request to " + textureUrl);
                        response.Redirect(textureUrl);
                    }
                }
                else
                {
                    // Fetch locally or remotely. Misses return a 404
                    if (m_assetClient.TryGetAsset(textureID, "image/x-j2c", out texture))
                    {
                        SendTexture(request, response, texture);
                    }
                    else
                    {
                        m_log.Warn("Texture " + textureID + " not found");

                        if (m_assetClient.TryGetCachedAsset(MISSING_IMAGE, "image/x-j2c", out texture))
                        {
                            SendTexture(request, response, texture);
                        }
                        else
                        {
                            m_log.Warn("Missing image texture " + MISSING_IMAGE + " not found, returning a 404");
                            response.Status = System.Net.HttpStatusCode.NotFound;
                        }
                    }
                }
            }
            else
            {
                m_log.Warn("Failed to parse a texture_id from GetTexture request: " + request.Uri);
            }
        }
Ejemplo n.º 4
0
        private void GetMeshHandler(Capability cap, IHttpClientContext context, IHttpRequest request, IHttpResponse response)
        {
            // TODO: Change this to a config option
            const string REDIRECT_URL = null;

            // Try to parse the mesh ID from the request URL
            NameValueCollection query = HttpUtility.ParseQueryString(request.Uri.Query);
            string meshStr            = query.GetOne("mesh_id");

            UUID meshID;

            if (!String.IsNullOrEmpty(meshStr) && UUID.TryParse(meshStr, out meshID))
            {
                Asset mesh;

                if (!String.IsNullOrEmpty(REDIRECT_URL))
                {
                    // Only try to fetch locally cached meshes. Misses are redirected
                    if (m_assetClient.TryGetCachedAsset(meshID, "application/vnd.ll.mesh", out mesh))
                    {
                        SendMesh(request, response, mesh);
                    }
                    else
                    {
                        string meshUrl = REDIRECT_URL + meshID.ToString();
                        m_log.Debug("Redirecting mesh request to " + meshUrl);
                        response.Redirect(meshUrl);
                    }
                }
                else
                {
                    // Fetch locally or remotely. Misses return a 404
                    if (m_assetClient.TryGetAsset(meshID, "application/vnd.ll.mesh", out mesh))
                    {
                        SendMesh(request, response, mesh);
                    }
                    else
                    {
                        m_log.Warn("Mesh " + meshID + " not found, returning a 404");
                        response.Status = System.Net.HttpStatusCode.NotFound;
                    }
                }
            }
            else
            {
                m_log.Warn("Failed to parse a mesh_id from GetMesh request: " + request.Uri);
            }
        }
Ejemplo n.º 5
0
        private void TransferRequestHandler(Packet packet, LLAgent agent)
        {
            TransferRequestPacket request = (TransferRequestPacket)packet;

            ChannelType channel = (ChannelType)request.TransferInfo.ChannelType;
            SourceType  source  = (SourceType)request.TransferInfo.SourceType;

            if (channel == ChannelType.Asset)
            {
                if (source == SourceType.Asset)
                {
                    // Parse the request
                    UUID      assetID     = new UUID(request.TransferInfo.Params, 0);
                    AssetType type        = (AssetType)(sbyte)Utils.BytesToInt(request.TransferInfo.Params, 16);
                    string    contentType = LLUtil.LLAssetTypeToContentType((int)type);

                    // Permission check
                    if (!CanDownloadInventory(agent, type, assetID))
                    {
                        TransferNotFound(agent, request.TransferInfo.TransferID, assetID, type);
                        return;
                    }

                    // Check if we have this asset
                    Asset asset;
                    if (m_assets.TryGetAsset(assetID, contentType, out asset))
                    {
                        TransferDownload(agent, request.TransferInfo.TransferID, assetID, type, asset);
                    }
                    else
                    {
                        TransferNotFound(agent, request.TransferInfo.TransferID, assetID, type);
                    }
                }
                else if (source == SourceType.SimInventoryItem)
                {
                    //UUID agentID = new UUID(request.TransferInfo.Params, 0);
                    //UUID sessionID = new UUID(request.TransferInfo.Params, 16);
                    //UUID ownerID = new UUID(request.TransferInfo.Params, 32);
                    UUID      taskID      = new UUID(request.TransferInfo.Params, 48);
                    UUID      itemID      = new UUID(request.TransferInfo.Params, 64);
                    UUID      assetID     = new UUID(request.TransferInfo.Params, 80);
                    AssetType type        = (AssetType)(sbyte)Utils.BytesToInt(request.TransferInfo.Params, 96);
                    string    contentType = LLUtil.LLAssetTypeToContentType((int)type);

                    if (taskID != UUID.Zero)
                    {
                        // Task (prim) inventory request permission check
                        if (!CanDownloadTaskInventory(agent, type, taskID, itemID))
                        {
                            TransferNotFound(agent, request.TransferInfo.TransferID, assetID, type);
                            return;
                        }
                    }
                    else
                    {
                        // Agent inventory request permission check
                        if (!CanDownloadInventory(agent, type, assetID))
                        {
                            TransferNotFound(agent, request.TransferInfo.TransferID, assetID, type);
                            return;
                        }
                    }

                    // Check if we have this asset
                    Asset asset;
                    if (m_assets.TryGetAsset(assetID, contentType, out asset))
                    {
                        TransferDownload(agent, request.TransferInfo.TransferID, assetID, type, asset);
                    }
                    else
                    {
                        TransferNotFound(agent, request.TransferInfo.TransferID, assetID, type);
                    }
                }
                else if (source == SourceType.SimEstate)
                {
                    //UUID agentID = new UUID(request.TransferInfo.Params, 0);
                    //UUID sessionID = new UUID(request.TransferInfo.Params, 16);
                    //EstateAssetType type = (EstateAssetType)Utils.BytesToInt(request.TransferInfo.Params, 32);

                    m_log.Warn("Don't know what to do with an estate asset transfer request");
                }
                else
                {
                    m_log.WarnFormat(
                        "Received a TransferRequest that we don't know how to handle. Channel: {0}, Source: {1}",
                        channel, source);
                }
            }
            else
            {
                m_log.WarnFormat(
                    "Received a TransferRequest that we don't know how to handle. Channel: {0}, Source: {1}",
                    channel, source);
            }
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Builds a composited terrain texture given the region texture
        /// and heightmap settings
        /// </summary>
        /// <param name="heightmap">Terrain heightmap</param>
        /// <param name="regionInfo">Region information including terrain texture parameters</param>
        /// <returns>A composited 256x256 RGB texture ready for rendering</returns>
        /// <remarks>Based on the algorithm described at http://opensimulator.org/wiki/Terrain_Splatting
        /// </remarks>
        public static Bitmap Splat(float[] heightmap, UUID[] textureIDs, float[] startHeights, float[] heightRanges, Vector3d regionPosition, IAssetClient assetClient)
        {
            Debug.Assert(heightmap.Length == 256 * 256);
            Debug.Assert(textureIDs.Length == 4);
            Debug.Assert(startHeights.Length == 4);
            Debug.Assert(heightRanges.Length == 4);

            // Swap empty terrain textureIDs with default IDs
            for (int i = 0; i < textureIDs.Length; i++)
            {
                if (textureIDs[i] == UUID.Zero)
                    textureIDs[i] = DEFAULT_TERRAIN_DETAIL[i];
            }

            #region Texture Fetching

            Bitmap[] detailTexture = new Bitmap[4];

            if (assetClient != null)
            {
                for (int i = 0; i < 4; i++)
                {
                    Asset asset;
                    UUID cacheID = UUID.Combine(TEXTURE_CACHE_MAGIC, textureIDs[i]);

                    // Try to fetch a cached copy of the decoded/resized version of this texture
                    if (assetClient.TryGetCachedAsset(cacheID, "image/png", out asset))
                    {
                        try
                        {
                            using (System.IO.MemoryStream stream = new System.IO.MemoryStream(asset.Data))
                                detailTexture[i] = (Bitmap)Image.FromStream(stream);
                        }
                        catch (Exception ex)
                        {
                            m_log.Warn("Failed to decode cached terrain texture " + cacheID +
                                " (textureID: " + textureIDs[i] + "): " + ex.Message);
                        }
                    }

                    if (detailTexture[i] == null)
                    {
                        // Try to fetch the original JPEG2000 texture, resize if needed, and cache as PNG
                        if (assetClient.TryGetAsset(textureIDs[i], "image/x-j2c", out asset))
                        {
                            try { detailTexture[i] = (Bitmap)CSJ2K.J2kImage.FromBytes(asset.Data); }
                            catch (Exception ex)
                            {
                                m_log.Warn("Failed to decode terrain texture " + asset.ID + ": " + ex.Message);
                            }
                        }

                        if (detailTexture[i] != null)
                        {
                            Bitmap bitmap = detailTexture[i];

                            // Make sure this texture is the correct size, otherwise resize
                            if (bitmap.Width != 256 || bitmap.Height != 256)
                                bitmap = Util.ResizeImage(bitmap, 256, 256);

                            // Save the decoded and resized texture to the cache
                            byte[] data;
                            using (System.IO.MemoryStream stream = new System.IO.MemoryStream())
                            {
                                bitmap.Save(stream, ImageFormat.Png);
                                data = stream.ToArray();
                            }

                            assetClient.StoreAsset(
                                new Asset
                                {
                                    ContentType = "image/png",
                                    CreationDate = DateTime.UtcNow,
                                    CreatorID = UUID.Zero,
                                    Data = data,
                                    ID = cacheID,
                                    Local = true,
                                    Temporary = true
                                }
                            );
                        }
                    }
                }
            }

            // Fill in any missing textures with a solid color
            for (int i = 0; i < 4; i++)
            {
                if (detailTexture[i] == null)
                {
                    // Create a solid color texture for this layer
                    detailTexture[i] = new Bitmap(256, 256, PixelFormat.Format24bppRgb);
                    using (Graphics gfx = Graphics.FromImage(detailTexture[i]))
                    {
                        using (SolidBrush brush = new SolidBrush(DEFAULT_TERRAIN_COLOR[i]))
                            gfx.FillRectangle(brush, 0, 0, 256, 256);
                    }
                }
            }

            #endregion Texture Fetching

            #region Layer Map

            float[] layermap = new float[256 * 256];

            for (int y = 0; y < 256; y++)
            {
                for (int x = 0; x < 256; x++)
                {
                    float height = heightmap[y * 256 + x];

                    float pctX = (float)x / 255f;
                    float pctY = (float)y / 255f;

                    // Use bilinear interpolation between the four corners of start height and
                    // height range to select the current values at this position
                    float startHeight = Util.Bilinear(
                        startHeights[0],
                        startHeights[2],
                        startHeights[1],
                        startHeights[3],
                        pctX, pctY);
                    startHeight = Utils.Clamp(startHeight, 0f, 255f);

                    float heightRange = Util.Bilinear(
                        heightRanges[0],
                        heightRanges[2],
                        heightRanges[1],
                        heightRanges[3],
                        pctX, pctY);
                    heightRange = Utils.Clamp(heightRange, 0f, 255f);

                    // Generate two frequencies of perlin noise based on our global position
                    // The magic values were taken from http://opensimulator.org/wiki/Terrain_Splatting
                    Vector3 vec = new Vector3
                    (
                        ((float)regionPosition.X + x) * 0.20319f,
                        ((float)regionPosition.Y + y) * 0.20319f,
                        height * 0.25f
                    );

                    float lowFreq = Perlin.noise2(vec.X * 0.222222f, vec.Y * 0.222222f) * 6.5f;
                    float highFreq = Perlin.turbulence2(vec.X, vec.Y, 2f) * 2.25f;
                    float noise = (lowFreq + highFreq) * 2f;

                    // Combine the current height, generated noise, start height, and height range parameters, then scale all of it
                    float layer = ((height + noise - startHeight) / heightRange) * 4f;
                    if (Single.IsNaN(layer)) layer = 0f;
                    layermap[y * 256 + x] = Utils.Clamp(layer, 0f, 3f);
                }
            }

            #endregion Layer Map

            #region Texture Compositing

            Bitmap output = new Bitmap(256, 256, PixelFormat.Format24bppRgb);
            BitmapData outputData = output.LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb);

            unsafe
            {
                // Get handles to all of the texture data arrays
                BitmapData[] datas = new BitmapData[]
                {
                    detailTexture[0].LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.ReadOnly, detailTexture[0].PixelFormat),
                    detailTexture[1].LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.ReadOnly, detailTexture[1].PixelFormat),
                    detailTexture[2].LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.ReadOnly, detailTexture[2].PixelFormat),
                    detailTexture[3].LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.ReadOnly, detailTexture[3].PixelFormat)
                };

                int[] comps = new int[]
                {
                    (datas[0].PixelFormat == PixelFormat.Format32bppArgb) ? 4 : 3,
                    (datas[1].PixelFormat == PixelFormat.Format32bppArgb) ? 4 : 3,
                    (datas[2].PixelFormat == PixelFormat.Format32bppArgb) ? 4 : 3,
                    (datas[3].PixelFormat == PixelFormat.Format32bppArgb) ? 4 : 3
                };

                for (int y = 0; y < 256; y++)
                {
                    for (int x = 0; x < 256; x++)
                    {
                        float layer = layermap[y * 256 + x];

                        // Select two textures
                        int l0 = (int)Math.Floor(layer);
                        int l1 = Math.Min(l0 + 1, 3);

                        byte* ptrA = (byte*)datas[l0].Scan0 + y * datas[l0].Stride + x * comps[l0];
                        byte* ptrB = (byte*)datas[l1].Scan0 + y * datas[l1].Stride + x * comps[l1];
                        byte* ptrO = (byte*)outputData.Scan0 + y * outputData.Stride + x * 3;

                        float aB = *(ptrA + 0);
                        float aG = *(ptrA + 1);
                        float aR = *(ptrA + 2);

                        float bB = *(ptrB + 0);
                        float bG = *(ptrB + 1);
                        float bR = *(ptrB + 2);

                        float layerDiff = layer - l0;

                        // Interpolate between the two selected textures
                        *(ptrO + 0) = (byte)Math.Floor(aB + layerDiff * (bB - aB));
                        *(ptrO + 1) = (byte)Math.Floor(aG + layerDiff * (bG - aG));
                        *(ptrO + 2) = (byte)Math.Floor(aR + layerDiff * (bR - aR));
                    }
                }

                for (int i = 0; i < 4; i++)
                    detailTexture[i].UnlockBits(datas[i]);
            }

            output.UnlockBits(outputData);

            // We generated the texture upside down, so flip it
            output.RotateFlip(RotateFlipType.RotateNoneFlipY);

            #endregion Texture Compositing

            return output;
        }
Ejemplo n.º 7
0
        private void EnqueueRequest(LLAgent agent, UUID textureID, sbyte discardLevel, float priority, uint packetNumber, uint sequenceNumber)
        {
            J2KImage image;

            // Look up this texture download
            lock (m_priorityQueue)
                m_queuedTextures.TryGetValue(textureID, out image);

            if (image != null)
            {
                // Update for an existing texture request
                if (discardLevel == -1 && priority == 0f)
                {
                    //m_log.Debug("[TEX]: (CAN) ID=" + textureID);

                    try
                    {
                        lock (m_priorityQueue)
                        {
                            m_priorityQueue.Delete(image.PriorityQueueHandle);
                            m_queuedTextures.Remove(textureID);
                        }
                    }
                    catch (Exception) { }
                }
                else
                {
                    //m_log.DebugFormat("[TEX]: (UPD) ID={0}: D={1}, S={2}, P={3}", textureID, discardLevel, packetNumber, priority);

                    // Check the packet sequence to make sure this update isn't older than
                    // one we've already received
                    if (sequenceNumber > image.LastSequence)
                    {
                        // Update the sequence number of the last RequestImage packet
                        image.LastSequence = sequenceNumber;

                        //Update the requested discard level
                        image.DiscardLevel = discardLevel;

                        //Update the requested packet number
                        image.StartPacket = Math.Max(1, packetNumber);

                        //Update the requested priority
                        image.Priority = priority;

                        // Update the start/end offsets for this request
                        image.UpdateOffsets();

                        UpdateImageInQueue(image);
                    }
                }
            }
            else
            {
                // New texture request
                if (discardLevel == -1 && priority == 0f)
                {
                    //m_log.DebugFormat("[TEX]: (IGN) ID={0}", textureID);
                }
                else
                {
                    //m_log.DebugFormat("[TEX]: (NEW) ID={0}: D={1}, S={2}, P={3}", textureID, discardLevel, packetNumber, priority);

                    Asset asset;
                    if (m_assetClient.TryGetAsset(textureID, "image/x-j2c", out asset))
                    {
                        image = new J2KImage(m_udp, asset, agent, discardLevel, Math.Max(1, packetNumber), priority);

                        // Update the start/end offsets for this request
                        image.UpdateOffsets();

                        // Add this download to the priority queue
                        UpdateImageInQueue(image);
                    }
                    else
                    {
                        ImageNotInDatabasePacket missing = new ImageNotInDatabasePacket();
                        missing.ImageID.ID = textureID;
                        m_udp.SendPacket(agent, missing, ThrottleCategory.Asset, true);
                    }
                }
            }
        }
Ejemplo n.º 8
0
        public bool RezScript(UUID sourceItemID, UUID sourceAssetID, ISceneEntity hostObject, int scriptStartParam)
        {
            if (m_assetClient == null)
            {
                m_log.Error("Cannot rez script " + sourceItemID + " without an IAssetClient");
                return(false);
            }

            Asset sourceAsset, binaryAsset;

            // Try to fetch the script source code asset
            if (m_assetClient.TryGetAsset(sourceAssetID, "application/vnd.ll.lsltext", out sourceAsset))
            {
                // The script binary assetID is the MD5 hash of the source to avoid lots of duplicate compiles
                UUID scriptBinaryAssetID = new UUID(Utils.MD5(sourceAsset.Data), 0);

                if (m_assetClient.TryGetAsset(scriptBinaryAssetID, "application/vnd.ll.lslbyte", out binaryAsset))
                {
                    m_log.Debug("Using existing compile for scriptID " + sourceItemID);

                    // Create an AppDomain for this script and post the entry point event to the queue
                    StartScript(sourceItemID, sourceAssetID, hostObject, binaryAsset.Data);
                }
                else
                {
                    #region Compile Script

                    ScriptCompiler converter = new ScriptCompiler(m_scene);
                    string         csText    =
                        "using System;\nusing System.Collections.Generic;\n" +
                        "using OpenMetaverse;\nusing Simian.Scripting.Linden;\n\n" +
                        "namespace SecondLife {\n    public class Script : LSLScriptBase {\n" +
                        converter.Convert(Encoding.UTF8.GetString(sourceAsset.Data)) +
                        "    }\n}\n";
                    string[] convertWarnings = converter.GetWarnings();

                    CompilerParameters parameters = new CompilerParameters();
                    parameters.IncludeDebugInformation = false;
                    parameters.CompilerOptions         = "/optimize";
                    parameters.ReferencedAssemblies.Add("OpenMetaverseTypes.dll");
                    parameters.ReferencedAssemblies.Add("Simian.Scripting.Linden.dll");
                    parameters.GenerateExecutable    = false;
                    parameters.GenerateInMemory      = false;
                    parameters.TreatWarningsAsErrors = false;

                    CompilerResults results;
                    lock (m_csCodeProvider)
                        results = m_csCodeProvider.CompileAssemblyFromSource(parameters, csText);

                    #endregion Compile Script

                    if (convertWarnings.Length == 0 && !results.Errors.HasErrors)
                    {
                        #region Binary Storage

                        // Get the bytecode of the compiled assembly
                        byte[] scriptBinary = File.ReadAllBytes(results.PathToAssembly);
                        File.Delete(results.PathToAssembly);

                        // Save the assembly to the asset store
                        m_assetClient.StoreAsset(new Asset
                        {
                            ContentType  = "application/vnd.ll.lslbyte",
                            CreatorID    = hostObject.OwnerID,
                            Data         = scriptBinary,
                            ID           = scriptBinaryAssetID,
                            Local        = true,
                            Temporary    = true,
                            CreationDate = DateTime.UtcNow
                        });

                        #endregion Binary Storage

                        // Create an AppDomain for this script and post the entry point event to the queue
                        StartScript(sourceItemID, sourceAssetID, hostObject, scriptBinary);
                        return(true);
                    }
                    else
                    {
                        #region Compile Error Handling

                        int    displayErrors = 5;
                        string errtext       = String.Empty;

                        foreach (string warning in convertWarnings)
                        {
                            // Show 5 errors max
                            if (displayErrors <= 0)
                            {
                                break;
                            }
                            --displayErrors;

                            // Treat converter warnings as errors
                            errtext += "Error: " + warning + "\n";
                        }

                        foreach (CompilerError compErr in results.Errors)
                        {
                            // Show 5 errors max
                            if (displayErrors <= 0)
                            {
                                break;
                            }
                            --displayErrors;

                            string severity = compErr.IsWarning ? "Warning" : "Error";
                            KeyValuePair <int, int> lslPos = FindErrorPosition(compErr.Line, compErr.Column, converter.PositionMap);
                            string text = compErr.ErrorText;

                            // Use LSL type names
                            text = ReplaceTypes(compErr.ErrorText);

                            // The Second Life viewer's script editor begins
                            // counting lines and columns at 0, so we subtract 1.
                            errtext += String.Format("Line ({0},{1}): {4} {2}: {3}\n",
                                                     lslPos.Key - 1, lslPos.Value - 1,
                                                     compErr.ErrorNumber, text, severity);
                        }

                        IScenePresence presence;
                        if (m_scene.TryGetPresence(hostObject.OwnerID, out presence))
                        {
                            m_scene.PresenceAlert(this, presence, "Script saved with warnings, check debug window!");
                        }

                        m_scene.EntityChat(this, hostObject, 0f, errtext, 0, EntityChatType.Debug);

                        #endregion Compile Error Handling
                    }
                }
            }
            else
            {
                m_log.Warn("Couldn't find script source asset " + sourceAssetID);
            }

            return(false);
        }
Ejemplo n.º 9
0
        /// <summary>
        /// Builds a composited terrain texture given the region texture
        /// and heightmap settings
        /// </summary>
        /// <param name="heightmap">Terrain heightmap</param>
        /// <param name="regionInfo">Region information including terrain texture parameters</param>
        /// <returns>A composited 256x256 RGB texture ready for rendering</returns>
        /// <remarks>Based on the algorithm described at http://opensimulator.org/wiki/Terrain_Splatting
        /// </remarks>
        public static Bitmap Splat(float[] heightmap, UUID[] textureIDs, float[] startHeights, float[] heightRanges, Vector3d regionPosition, IAssetClient assetClient)
        {
            Debug.Assert(heightmap.Length == 256 * 256);
            Debug.Assert(textureIDs.Length == 4);
            Debug.Assert(startHeights.Length == 4);
            Debug.Assert(heightRanges.Length == 4);

            // Swap empty terrain textureIDs with default IDs
            for (int i = 0; i < textureIDs.Length; i++)
            {
                if (textureIDs[i] == UUID.Zero)
                {
                    textureIDs[i] = DEFAULT_TERRAIN_DETAIL[i];
                }
            }

            #region Texture Fetching

            Bitmap[] detailTexture = new Bitmap[4];

            if (assetClient != null)
            {
                for (int i = 0; i < 4; i++)
                {
                    Asset asset;
                    UUID  cacheID = UUID.Combine(TEXTURE_CACHE_MAGIC, textureIDs[i]);

                    // Try to fetch a cached copy of the decoded/resized version of this texture
                    if (assetClient.TryGetCachedAsset(cacheID, "image/png", out asset))
                    {
                        try
                        {
                            using (System.IO.MemoryStream stream = new System.IO.MemoryStream(asset.Data))
                                detailTexture[i] = (Bitmap)Image.FromStream(stream);
                        }
                        catch (Exception ex)
                        {
                            m_log.Warn("Failed to decode cached terrain texture " + cacheID +
                                       " (textureID: " + textureIDs[i] + "): " + ex.Message);
                        }
                    }

                    if (detailTexture[i] == null)
                    {
                        // Try to fetch the original JPEG2000 texture, resize if needed, and cache as PNG
                        if (assetClient.TryGetAsset(textureIDs[i], "image/x-j2c", out asset))
                        {
                            try { detailTexture[i] = (Bitmap)CSJ2K.J2kImage.FromBytes(asset.Data); }
                            catch (Exception ex)
                            {
                                m_log.Warn("Failed to decode terrain texture " + asset.ID + ": " + ex.Message);
                            }
                        }

                        if (detailTexture[i] != null)
                        {
                            Bitmap bitmap = detailTexture[i];

                            // Make sure this texture is the correct size, otherwise resize
                            if (bitmap.Width != 256 || bitmap.Height != 256)
                            {
                                bitmap = Util.ResizeImage(bitmap, 256, 256);
                            }

                            // Save the decoded and resized texture to the cache
                            byte[] data;
                            using (System.IO.MemoryStream stream = new System.IO.MemoryStream())
                            {
                                bitmap.Save(stream, ImageFormat.Png);
                                data = stream.ToArray();
                            }

                            assetClient.StoreAsset(
                                new Asset
                            {
                                ContentType  = "image/png",
                                CreationDate = DateTime.UtcNow,
                                CreatorID    = UUID.Zero,
                                Data         = data,
                                ID           = cacheID,
                                Local        = true,
                                Temporary    = true
                            }
                                );
                        }
                    }
                }
            }

            // Fill in any missing textures with a solid color
            for (int i = 0; i < 4; i++)
            {
                if (detailTexture[i] == null)
                {
                    // Create a solid color texture for this layer
                    detailTexture[i] = new Bitmap(256, 256, PixelFormat.Format24bppRgb);
                    using (Graphics gfx = Graphics.FromImage(detailTexture[i]))
                    {
                        using (SolidBrush brush = new SolidBrush(DEFAULT_TERRAIN_COLOR[i]))
                            gfx.FillRectangle(brush, 0, 0, 256, 256);
                    }
                }
            }

            #endregion Texture Fetching

            #region Layer Map

            float[] layermap = new float[256 * 256];

            for (int y = 0; y < 256; y++)
            {
                for (int x = 0; x < 256; x++)
                {
                    float height = heightmap[y * 256 + x];

                    float pctX = (float)x / 255f;
                    float pctY = (float)y / 255f;

                    // Use bilinear interpolation between the four corners of start height and
                    // height range to select the current values at this position
                    float startHeight = Util.Bilinear(
                        startHeights[0],
                        startHeights[2],
                        startHeights[1],
                        startHeights[3],
                        pctX, pctY);
                    startHeight = Utils.Clamp(startHeight, 0f, 255f);

                    float heightRange = Util.Bilinear(
                        heightRanges[0],
                        heightRanges[2],
                        heightRanges[1],
                        heightRanges[3],
                        pctX, pctY);
                    heightRange = Utils.Clamp(heightRange, 0f, 255f);

                    // Generate two frequencies of perlin noise based on our global position
                    // The magic values were taken from http://opensimulator.org/wiki/Terrain_Splatting
                    Vector3 vec = new Vector3
                                  (
                        ((float)regionPosition.X + x) * 0.20319f,
                        ((float)regionPosition.Y + y) * 0.20319f,
                        height * 0.25f
                                  );

                    float lowFreq  = Perlin.noise2(vec.X * 0.222222f, vec.Y * 0.222222f) * 6.5f;
                    float highFreq = Perlin.turbulence2(vec.X, vec.Y, 2f) * 2.25f;
                    float noise    = (lowFreq + highFreq) * 2f;

                    // Combine the current height, generated noise, start height, and height range parameters, then scale all of it
                    float layer = ((height + noise - startHeight) / heightRange) * 4f;
                    if (Single.IsNaN(layer))
                    {
                        layer = 0f;
                    }
                    layermap[y * 256 + x] = Utils.Clamp(layer, 0f, 3f);
                }
            }

            #endregion Layer Map

            #region Texture Compositing

            Bitmap     output     = new Bitmap(256, 256, PixelFormat.Format24bppRgb);
            BitmapData outputData = output.LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb);

            unsafe
            {
                // Get handles to all of the texture data arrays
                BitmapData[] datas = new BitmapData[]
                {
                    detailTexture[0].LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.ReadOnly, detailTexture[0].PixelFormat),
                    detailTexture[1].LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.ReadOnly, detailTexture[1].PixelFormat),
                    detailTexture[2].LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.ReadOnly, detailTexture[2].PixelFormat),
                    detailTexture[3].LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.ReadOnly, detailTexture[3].PixelFormat)
                };

                int[] comps = new int[]
                {
                    (datas[0].PixelFormat == PixelFormat.Format32bppArgb) ? 4 : 3,
                    (datas[1].PixelFormat == PixelFormat.Format32bppArgb) ? 4 : 3,
                    (datas[2].PixelFormat == PixelFormat.Format32bppArgb) ? 4 : 3,
                    (datas[3].PixelFormat == PixelFormat.Format32bppArgb) ? 4 : 3
                };

                for (int y = 0; y < 256; y++)
                {
                    for (int x = 0; x < 256; x++)
                    {
                        float layer = layermap[y * 256 + x];

                        // Select two textures
                        int l0 = (int)Math.Floor(layer);
                        int l1 = Math.Min(l0 + 1, 3);

                        byte *ptrA = (byte *)datas[l0].Scan0 + y * datas[l0].Stride + x * comps[l0];
                        byte *ptrB = (byte *)datas[l1].Scan0 + y * datas[l1].Stride + x * comps[l1];
                        byte *ptrO = (byte *)outputData.Scan0 + y * outputData.Stride + x * 3;

                        float aB = *(ptrA + 0);
                        float aG = *(ptrA + 1);
                        float aR = *(ptrA + 2);

                        float bB = *(ptrB + 0);
                        float bG = *(ptrB + 1);
                        float bR = *(ptrB + 2);

                        float layerDiff = layer - l0;

                        // Interpolate between the two selected textures
                        *(ptrO + 0) = (byte)Math.Floor(aB + layerDiff * (bB - aB));
                        *(ptrO + 1) = (byte)Math.Floor(aG + layerDiff * (bG - aG));
                        *(ptrO + 2) = (byte)Math.Floor(aR + layerDiff * (bR - aR));
                    }
                }

                for (int i = 0; i < 4; i++)
                {
                    detailTexture[i].UnlockBits(datas[i]);
                }
            }

            output.UnlockBits(outputData);

            // We generated the texture upside down, so flip it
            output.RotateFlip(RotateFlipType.RotateNoneFlipY);

            #endregion Texture Compositing

            return(output);
        }