public unsafe Bitmap TerrainToBitmap(Bitmap mapbmp)
        {
            BitmapProcessing.FastBitmap unsafeBMP = new BitmapProcessing.FastBitmap(mapbmp);
            unsafeBMP.LockBitmap();
            //DateTime start = DateTime.Now;
            //m_log.Info("[MAPTILE]: Generating Maptile Step 1: Terrain");

            // These textures should be in the AssetCache anyway, as every client conneting to this
            // region needs them. Except on start, when the map is recreated (before anyone connected),
            // and on change of the estate settings (textures and terrain values), when the map should
            // be recreated.
            RegionSettings settings = m_scene.RegionInfo.RegionSettings;

            // the four terrain colors as HSVs for interpolation
            HSV hsv1 = new HSV(computeAverageColor(settings.TerrainTexture1, defaultColor1));
            HSV hsv2 = new HSV(computeAverageColor(settings.TerrainTexture2, defaultColor2));
            HSV hsv3 = new HSV(computeAverageColor(settings.TerrainTexture3, defaultColor3));
            HSV hsv4 = new HSV(computeAverageColor(settings.TerrainTexture4, defaultColor4));

            float levelNElow = (float)settings.Elevation1NE;
            float levelNEhigh = (float)settings.Elevation2NE;

            float levelNWlow = (float)settings.Elevation1NW;
            float levelNWhigh = (float)settings.Elevation2NW;

            float levelSElow = (float)settings.Elevation1SE;
            float levelSEhigh = (float)settings.Elevation2SE;

            float levelSWlow = (float)settings.Elevation1SW;
            float levelSWhigh = (float)settings.Elevation2SW;

            float waterHeight = (float)settings.WaterHeight;

            ITerrainChannel heightmap = m_scene.RequestModuleInterface<ITerrainChannel>();
            float sizeRatio = (float)m_scene.RegionInfo.RegionSizeX / (float)Constants.RegionSize;
            for (float y = 0; y < m_scene.RegionInfo.RegionSizeY; y += sizeRatio)
            {
                float rowRatio = y / (m_scene.RegionInfo.RegionSizeY - 1); // 0 - 1, for interpolation
                for (float x = 0; x < m_scene.RegionInfo.RegionSizeX; x += sizeRatio)
                {
                    float columnRatio = x / (m_scene.RegionInfo.RegionSizeX - 1); // 0 - 1, for interpolation

                    float heightvalue = getHeight (heightmap, (int)x, (int)y);

                    if (heightvalue > waterHeight)
                    {
                        // add a bit noise for breaking up those flat colors:
                        // - a large-scale noise, for the "patches" (using an doubled s-curve for sharper contrast)
                        // - a small-scale noise, for bringing in some small scale variation
                        //float bigNoise = (float)TerrainUtil.InterpolatedNoise(x / 8.0, y / 8.0) * .5f + .5f; // map to 0.0 - 1.0
                        //float smallNoise = (float)TerrainUtil.InterpolatedNoise(x + 33, y + 43) * .5f + .5f;
                        //float hmod = heightvalue + smallNoise * 3f + S(S(bigNoise)) * 10f;
                        float hmod =
                            heightvalue; // 0 - 10

                        // find the low/high values for this point (interpolated bilinearily)
                        // (and remember, x=0,y=0 is SW)
                        float low = levelSWlow * (1f - rowRatio) * (1f - columnRatio) +
                            levelSElow * (1f - rowRatio) * columnRatio +
                            levelNWlow * rowRatio * (1f - columnRatio) +
                            levelNElow * rowRatio * columnRatio;
                        float high = levelSWhigh * (1f - rowRatio) * (1f - columnRatio) +
                            levelSEhigh * (1f - rowRatio) * columnRatio +
                            levelNWhigh * rowRatio * (1f - columnRatio) +
                            levelNEhigh * rowRatio * columnRatio;
                        if (high < low)
                        {
                            // someone tried to fool us. High value should be higher than low every time
                            float tmp = high;
                            high = low;
                            low = tmp;
                        }

                        HSV hsv;
                        if (hmod <= low) hsv = hsv1; // too low
                        else if (hmod >= high) hsv = hsv4; // too high
                        else
                        {
                            // HSV-interpolate along the colors
                            // first, rescale h to 0.0 - 1.0
                            hmod = (hmod - low) / (high - low);
                            // now we have to split: 0.00 => color1, 0.33 => color2, 0.67 => color3, 1.00 => color4
                            if (hmod < 1f / 3f) hsv = interpolateHSV (ref hsv1, ref hsv2, hmod * 3f);
                            else if (hmod < 2f / 3f) hsv = interpolateHSV (ref hsv2, ref hsv3, (hmod * 3f) - 1f);
                            else hsv = interpolateHSV (ref hsv3, ref hsv4, (hmod * 3f) - 2f);
                        }
                        //get the data from the original image
                        Color hsvColor = hsv.toColor ();
                        unsafeBMP.SetPixel ((int)(x / sizeRatio),(int)(((m_scene.RegionInfo.RegionSizeY - 1) - y) / sizeRatio), hsvColor);
                    }
                    else
                    {
                        // We're under the water level with the terrain, so paint water instead of land
                        unsafeBMP.SetPixel ((int)(x / sizeRatio), (int)(((m_scene.RegionInfo.RegionSizeY - 1) - y) / sizeRatio), WATER_COLOR);
                    }
                }
            }
            if (m_mapping != null)
            {
                SaveCache ();
                m_mapping.Clear ();
            }
            unsafeBMP.UnlockBitmap();
            //m_log.Info("[MAPTILE]: Generating Maptile Step 1: Done in " + (DateTime.Now - start).TotalSeconds + " ms");
            return unsafeBMP.Bitmap();
        }
Exemplo n.º 2
0
        public void PaintEffect(ITerrainChannel map, UUID userID, float rx, float ry, float rz, float strength, float duration, float BrushSize, List<Scene> scene)
        {
            if (locked)
                return;
            locked = true;
            strength = TerrainUtil.MetersToSphericalStrength(BrushSize);

            int x, y;

            int xFrom = (int)(rx - BrushSize + 0.5);
            int xTo = (int)(rx + BrushSize + 0.5) + 1;
            int yFrom = (int)(ry - BrushSize + 0.5);
            int yTo = (int)(ry + BrushSize + 0.5) + 1;

            if (xFrom < 0)
                xFrom = 0;

            if (yFrom < 0)
                yFrom = 0;

            if (xTo > map.Width)
                xTo = map.Width;

            if (yTo > map.Height)
                yTo = map.Height;

            //ONLY get cached assets, since this is a local asset ONLY
            AssetBase paintAsset = map.Scene.AssetService.Get(map.Scene.RegionInfo.RegionSettings.PaintableTerrainTexture.ToString());
            if (paintAsset == null)
            {
                paintAsset = new AssetBase(map.Scene.RegionInfo.RegionSettings.PaintableTerrainTexture, "PaintableTerrainTexture-" + map.Scene.RegionInfo.RegionID, (sbyte)AssetType.Texture, UUID.Zero.ToString());
                paintAsset.Flags = AssetFlags.Deletable;
                AssetBase defaultTexture = map.Scene.AssetService.Get(RegionSettings.DEFAULT_TERRAIN_TEXTURE_2.ToString());//Nice grass
                if (defaultTexture == null)
                    //Erm... what to do!
                    return;

                paintAsset.Data = defaultTexture.Data;//Eventually we need to replace this with an interpolation of the existing textures!
            }

            AssetBase textureToApply = map.Scene.AssetService.Get(m_textureToPaint.ToString()); //The texture the client wants to paint
            if (textureToApply == null)
                return;

            Image paintiTexture = map.Scene.RequestModuleInterface<IJ2KDecoder> ().DecodeToImage (paintAsset.Data);
            if (paintiTexture == null)
                return;

            Image textureToAddiTexture = map.Scene.RequestModuleInterface<IJ2KDecoder> ().DecodeToImage (textureToApply.Data);
            if (textureToAddiTexture == null)
            {
                paintiTexture.Dispose();
                return;
            }

            BitmapProcessing.FastBitmap paintTexture = new BitmapProcessing.FastBitmap((Bitmap)paintiTexture);
            BitmapProcessing.FastBitmap textureToAddTexture = new BitmapProcessing.FastBitmap((Bitmap)textureToAddiTexture);

            paintTexture.LockBitmap();
            textureToAddTexture.LockBitmap();

            // blend in map
            for (x = xFrom; x < xTo; x++)
            {
                for (y = yFrom; y < yTo; y++)
                {
                    if (!map.Scene.Permissions.CanTerraformLand(userID, new Vector3(x, y, 0)))
                        continue;

                    Color c = textureToAddTexture.GetPixel((int)(((float)x / (float)map.Scene.RegionInfo.RegionSizeX * (float)textureToAddiTexture.Width)),
                        (int)(((float)y / (float)map.Scene.RegionInfo.RegionSizeX) * (float)textureToAddiTexture.Height));
                    Color cc = paintTexture.GetPixel((int)(((float)x / (float)map.Scene.RegionInfo.RegionSizeX) * (float)textureToAddiTexture.Width),
                        (int)(((float)y / (float)map.Scene.RegionInfo.RegionSizeX) * (float)textureToAddiTexture.Height));
                    paintTexture.SetPixel((int)(((float)x / (float)map.Scene.RegionInfo.RegionSizeX) * (float)paintiTexture.Width),
                        (int)(((float)y / (float)map.Scene.RegionInfo.RegionSizeX) * (float)paintiTexture.Height), c);
                    cc = paintTexture.GetPixel((int)(((float)x / (float)map.Scene.RegionInfo.RegionSizeX * (float)textureToAddiTexture.Width)),
                        (int)(((float)y / (float)map.Scene.RegionInfo.RegionSizeX) * (float)textureToAddiTexture.Height));
                }
            }
            map.Scene.AssetService.Delete(paintAsset.ID);
            paintTexture.UnlockBitmap();
            textureToAddTexture.UnlockBitmap();
            paintAsset.Data = OpenJPEG.EncodeFromImage(paintTexture.Bitmap(), false);
            paintAsset.Flags = AssetFlags.Deletable;
            map.Scene.RegionInfo.RegionSettings.PaintableTerrainTexture = UUID.Random();
            paintAsset.ID = map.Scene.RegionInfo.RegionSettings.PaintableTerrainTexture.ToString();
            map.Scene.AssetService.Store(paintAsset);
            map.Scene.RequestModuleInterface<IEstateModule>().sendRegionHandshakeToAll();
            locked = false;
        }
Exemplo n.º 3
0
 public Bitmap Shade (Bitmap source, Color shade, float percent, bool greyScale)
 {
     BitmapProcessing.FastBitmap b = new BitmapProcessing.FastBitmap (source);
     b.LockBitmap ();
     for (int y = 0; y < source.Height; y++)
     {
         for (int x = 0; x < source.Width; x++)
         {
             Color c = b.GetPixel (x, y);
             if (greyScale)
             {
                 int luma = (int)(c.R * 0.3 + c.G * 0.59 + c.B * 0.11);
                 b.SetPixel (x, y, Color.FromArgb (c.A, luma, luma, luma));
             }
             else
             {
                 float amtFrom = 1 - percent;
                 int lumaR = (int)(c.R * amtFrom + shade.R * percent);
                 int lumaG = (int)(c.G * amtFrom + shade.G * percent);
                 int lumaB = (int)(c.B * amtFrom + shade.B * percent);
                 b.SetPixel (x, y, Color.FromArgb (c.A, lumaR, lumaG, lumaB));
             }
         }
     }
     b.UnlockBitmap ();
     return b.Bitmap();
 }
Exemplo n.º 4
0
        public unsafe Bitmap TerrainToBitmap(Bitmap mapbmp)
        {
            BitmapProcessing.FastBitmap unsafeBMP = new BitmapProcessing.FastBitmap(mapbmp);
            unsafeBMP.LockBitmap();
            //DateTime start = DateTime.Now;
            //m_log.Info("[MAPTILE]: Generating Maptile Step 1: Terrain");

            // These textures should be in the AssetCache anyway, as every client conneting to this
            // region needs them. Except on start, when the map is recreated (before anyone connected),
            // and on change of the estate settings (textures and terrain values), when the map should
            // be recreated.
            RegionSettings settings = m_scene.RegionInfo.RegionSettings;

            // the four terrain colors as HSVs for interpolation
            HSV hsv1 = new HSV(computeAverageColor(settings.TerrainTexture1, defaultColor1));
            HSV hsv2 = new HSV(computeAverageColor(settings.TerrainTexture2, defaultColor2));
            HSV hsv3 = new HSV(computeAverageColor(settings.TerrainTexture3, defaultColor3));
            HSV hsv4 = new HSV(computeAverageColor(settings.TerrainTexture4, defaultColor4));

            float levelNElow  = (float)settings.Elevation1NE;
            float levelNEhigh = (float)settings.Elevation2NE;

            float levelNWlow  = (float)settings.Elevation1NW;
            float levelNWhigh = (float)settings.Elevation2NW;

            float levelSElow  = (float)settings.Elevation1SE;
            float levelSEhigh = (float)settings.Elevation2SE;

            float levelSWlow  = (float)settings.Elevation1SW;
            float levelSWhigh = (float)settings.Elevation2SW;

            float waterHeight = (float)settings.WaterHeight;

            ITerrainChannel heightmap = m_scene.RequestModuleInterface <ITerrainChannel>();
            float           sizeRatio = (float)m_scene.RegionInfo.RegionSizeX / (float)Constants.RegionSize;

            for (float y = 0; y < m_scene.RegionInfo.RegionSizeY; y += sizeRatio)
            {
                float rowRatio = y / (m_scene.RegionInfo.RegionSizeY - 1); // 0 - 1, for interpolation
                for (float x = 0; x < m_scene.RegionInfo.RegionSizeX; x += sizeRatio)
                {
                    float columnRatio = x / (m_scene.RegionInfo.RegionSizeX - 1); // 0 - 1, for interpolation

                    float heightvalue = getHeight(heightmap, (int)x, (int)y);

                    if (heightvalue > waterHeight)
                    {
                        // add a bit noise for breaking up those flat colors:
                        // - a large-scale noise, for the "patches" (using an doubled s-curve for sharper contrast)
                        // - a small-scale noise, for bringing in some small scale variation
                        //float bigNoise = (float)TerrainUtil.InterpolatedNoise(x / 8.0, y / 8.0) * .5f + .5f; // map to 0.0 - 1.0
                        //float smallNoise = (float)TerrainUtil.InterpolatedNoise(x + 33, y + 43) * .5f + .5f;
                        //float hmod = heightvalue + smallNoise * 3f + S(S(bigNoise)) * 10f;
                        float hmod =
                            heightvalue; // 0 - 10

                        // find the low/high values for this point (interpolated bilinearily)
                        // (and remember, x=0,y=0 is SW)
                        float low = levelSWlow * (1f - rowRatio) * (1f - columnRatio) +
                                    levelSElow * (1f - rowRatio) * columnRatio +
                                    levelNWlow * rowRatio * (1f - columnRatio) +
                                    levelNElow * rowRatio * columnRatio;
                        float high = levelSWhigh * (1f - rowRatio) * (1f - columnRatio) +
                                     levelSEhigh * (1f - rowRatio) * columnRatio +
                                     levelNWhigh * rowRatio * (1f - columnRatio) +
                                     levelNEhigh * rowRatio * columnRatio;
                        if (high < low)
                        {
                            // someone tried to fool us. High value should be higher than low every time
                            float tmp = high;
                            high = low;
                            low  = tmp;
                        }

                        HSV hsv;
                        if (hmod <= low)
                        {
                            hsv = hsv1;              // too low
                        }
                        else if (hmod >= high)
                        {
                            hsv = hsv4;                    // too high
                        }
                        else
                        {
                            // HSV-interpolate along the colors
                            // first, rescale h to 0.0 - 1.0
                            hmod = (hmod - low) / (high - low);
                            // now we have to split: 0.00 => color1, 0.33 => color2, 0.67 => color3, 1.00 => color4
                            if (hmod < 1f / 3f)
                            {
                                hsv = interpolateHSV(ref hsv1, ref hsv2, hmod * 3f);
                            }
                            else if (hmod < 2f / 3f)
                            {
                                hsv = interpolateHSV(ref hsv2, ref hsv3, (hmod * 3f) - 1f);
                            }
                            else
                            {
                                hsv = interpolateHSV(ref hsv3, ref hsv4, (hmod * 3f) - 2f);
                            }
                        }
                        //get the data from the original image
                        Color hsvColor = hsv.toColor();
                        unsafeBMP.SetPixel((int)(x / sizeRatio), (int)(((m_scene.RegionInfo.RegionSizeY - 1) - y) / sizeRatio), hsvColor);
                    }
                    else
                    {
                        // We're under the water level with the terrain, so paint water instead of land
                        unsafeBMP.SetPixel((int)(x / sizeRatio), (int)(((m_scene.RegionInfo.RegionSizeY - 1) - y) / sizeRatio), WATER_COLOR);
                    }
                }
            }
            if (m_mapping != null)
            {
                m_mapping.Clear();
            }
            unsafeBMP.UnlockBitmap();
            //m_log.Info("[MAPTILE]: Generating Maptile Step 1: Done in " + (DateTime.Now - start).TotalSeconds + " ms");
            return(unsafeBMP.Bitmap());
        }
Exemplo n.º 5
0
        private void Draw(string data, UUID id, string extraParams)
        {
            // We need to cater for old scripts that didnt use extraParams neatly, they use either an integer size which represents both width and height, or setalpha
            // we will now support multiple comma seperated params in the form  width:256,height:512,alpha:255
            int width = 256;
            int height = 256;
            int alpha = 255; // 0 is transparent
            Color bgColour = Color.White;  // Default background color
            char altDataDelim = ';';
            
            char[] paramDelimiter = { ',' };
            char[] nvpDelimiter = { ':' };
           
            extraParams = extraParams.Trim();
            extraParams = extraParams.ToLower();
            
            string[] nvps = extraParams.Split(paramDelimiter);
            
            int temp = -1;
            foreach (string pair in nvps)
            {
                string[] nvp = pair.Split(nvpDelimiter);
                string name = "";
                string value = "";
                
                if (nvp[0] != null)
                {
                    name = nvp[0].Trim();
                }
                
                if (nvp.Length == 2)
                {
                    value = nvp[1].Trim();
                }
                
                switch (name)
                {
                    case "width":
                        temp = parseIntParam(value);
                        if (temp != -1)
                        {
                            if (temp < 1)
                            {
                                width = 1;
                            }
                            else if (temp > 2048)
                            {
                                width = 2048;
                            }
                            else
                            {
                                width = temp;
                            }
                        }
                        break;
                    case "height":
                        temp = parseIntParam(value);
                        if (temp != -1)
                        {
                            if (temp < 1)
                            {
                                height = 1;
                            }
                            else if (temp > 2048)
                            {
                                height = 2048;
                            }
                            else
                            {
                                height = temp;
                            }
                        }
                        break;
                     case "alpha":
                          temp = parseIntParam(value);
                          if (temp != -1)
                          {
                              if (temp < 0)
                              {
                                  alpha = 0;
                              }
                              else if (temp > 255)
                              {
                                  alpha = 255;
                              }
                              else
                              {
                                  alpha = temp;
                              }
                          }
                          // Allow a bitmap w/o the alpha component to be created
                          else if (value.ToLower() == "false") {
                               alpha = 256;
                          }
                          break;
                     case "bgcolour":
                     case "bgcolor":
                         int hex = 0;
                         if (Int32.TryParse(value, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out hex))
                         {
                             bgColour = Color.FromArgb(hex);
                         } 
                         else
                         {
                             bgColour = Color.FromName(value);
                         }
                         break;
                     case "altdatadelim":
                         altDataDelim = value.ToCharArray()[0];
                         break;
                     case "":
                         // blank string has been passed do nothing just use defaults
                     break;
                     default: // this is all for backwards compat, all a bit ugly hopfully can be removed in future
                         // could be either set alpha or just an int
                         if (name == "setalpha")
                         {
                             alpha = 0; // set the texture to have transparent background (maintains backwards compat)
                         }
                         else
                         {
                             // this function used to accept an int on its own that represented both 
                             // width and height, this is to maintain backwards compat, could be removed
                             // but would break existing scripts
                             temp = parseIntParam(name);
                             if (temp != -1)
                             {
                                 if (temp > 1024)
                                    temp = 1024;
                                    
                                 if (temp < 128)
                                     temp = 128;
                                  
                                 width = temp;
                                 height = temp;
                             }
                         }
                     break;
                }
            }

            Bitmap bitmap;
            
            if (alpha == 256)
            {
                bitmap = new Bitmap(width, height, PixelFormat.Format32bppRgb);
            }
            else
            {
                bitmap = new Bitmap(width, height, PixelFormat.Format32bppArgb);
            }

            Graphics graph = Graphics.FromImage(bitmap);
            // this is really just to save people filling the 
            // background color in their scripts, only do when fully opaque
            if (alpha >= 255)
            {
                graph.FillRectangle(new SolidBrush(bgColour), 0, 0, width, height); 
            }

            BitmapProcessing.FastBitmap fastBitmap = new BitmapProcessing.FastBitmap(bitmap);
            fastBitmap.LockBitmap();
            for (int w = 0; w < bitmap.Width; w++)
            {
                if (alpha <= 255) 
                {
                    for (int h = 0; h < bitmap.Height; h++)
                    {
                        fastBitmap.SetPixel(w, h, Color.FromArgb(alpha, fastBitmap.GetPixel(w, h)));
                    }
                }
            }
            fastBitmap.UnlockBitmap();
            bitmap = fastBitmap.Bitmap();

            graph.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
            graph.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
            graph.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAliasGridFit;
            GDIDraw(data, graph, altDataDelim);

            byte[] imageJ2000 = new byte[0];

            try
            {
                imageJ2000 = OpenJPEG.EncodeFromImage(bitmap, false);
            }
            catch (Exception)
            {
                m_log.Error(
                    "[VECTORRENDERMODULE]: OpenJpeg Encode Failed.  Empty byte data returned!");
            }

            m_textureManager.ReturnData(id, imageJ2000);
        }
Exemplo n.º 6
0
        public void PaintEffect(ITerrainChannel map, UUID userID, float rx, float ry, float rz, float strength, float duration, float BrushSize, List <Scene> scene)
        {
            if (locked)
            {
                return;
            }
            locked   = true;
            strength = TerrainUtil.MetersToSphericalStrength(BrushSize);

            int x, y;

            int xFrom = (int)(rx - BrushSize + 0.5);
            int xTo   = (int)(rx + BrushSize + 0.5) + 1;
            int yFrom = (int)(ry - BrushSize + 0.5);
            int yTo   = (int)(ry + BrushSize + 0.5) + 1;

            if (xFrom < 0)
            {
                xFrom = 0;
            }

            if (yFrom < 0)
            {
                yFrom = 0;
            }

            if (xTo > map.Width)
            {
                xTo = map.Width;
            }

            if (yTo > map.Height)
            {
                yTo = map.Height;
            }

            //ONLY get cached assets, since this is a local asset ONLY
            AssetBase paintAsset = map.Scene.AssetService.Get(map.Scene.RegionInfo.RegionSettings.PaintableTerrainTexture.ToString());

            if (paintAsset == null)
            {
                paintAsset       = new AssetBase(map.Scene.RegionInfo.RegionSettings.PaintableTerrainTexture, "PaintableTerrainTexture-" + map.Scene.RegionInfo.RegionID, (sbyte)AssetType.Texture, UUID.Zero.ToString());
                paintAsset.Flags = AssetFlags.Deletable;
                AssetBase defaultTexture = map.Scene.AssetService.Get(RegionSettings.DEFAULT_TERRAIN_TEXTURE_2.ToString());//Nice grass
                if (defaultTexture == null)
                {
                    //Erm... what to do!
                    return;
                }

                paintAsset.Data = defaultTexture.Data;//Eventually we need to replace this with an interpolation of the existing textures!
            }

            AssetBase textureToApply = map.Scene.AssetService.Get(m_textureToPaint.ToString()); //The texture the client wants to paint

            if (textureToApply == null)
            {
                return;
            }

            Image paintiTexture = map.Scene.RequestModuleInterface <IJ2KDecoder> ().DecodeToImage(paintAsset.Data);

            if (paintiTexture == null)
            {
                return;
            }

            Image textureToAddiTexture = map.Scene.RequestModuleInterface <IJ2KDecoder> ().DecodeToImage(textureToApply.Data);

            if (textureToAddiTexture == null)
            {
                paintiTexture.Dispose();
                return;
            }

            BitmapProcessing.FastBitmap paintTexture        = new BitmapProcessing.FastBitmap((Bitmap)paintiTexture);
            BitmapProcessing.FastBitmap textureToAddTexture = new BitmapProcessing.FastBitmap((Bitmap)textureToAddiTexture);

            paintTexture.LockBitmap();
            textureToAddTexture.LockBitmap();

            // blend in map
            for (x = xFrom; x < xTo; x++)
            {
                for (y = yFrom; y < yTo; y++)
                {
                    if (!map.Scene.Permissions.CanTerraformLand(userID, new Vector3(x, y, 0)))
                    {
                        continue;
                    }

                    Color c = textureToAddTexture.GetPixel((int)(((float)x / (float)map.Scene.RegionInfo.RegionSizeX * (float)textureToAddiTexture.Width)),
                                                           (int)(((float)y / (float)map.Scene.RegionInfo.RegionSizeX) * (float)textureToAddiTexture.Height));
                    Color cc = paintTexture.GetPixel((int)(((float)x / (float)map.Scene.RegionInfo.RegionSizeX) * (float)textureToAddiTexture.Width),
                                                     (int)(((float)y / (float)map.Scene.RegionInfo.RegionSizeX) * (float)textureToAddiTexture.Height));
                    paintTexture.SetPixel((int)(((float)x / (float)map.Scene.RegionInfo.RegionSizeX) * (float)paintiTexture.Width),
                                          (int)(((float)y / (float)map.Scene.RegionInfo.RegionSizeX) * (float)paintiTexture.Height), c);
                    cc = paintTexture.GetPixel((int)(((float)x / (float)map.Scene.RegionInfo.RegionSizeX * (float)textureToAddiTexture.Width)),
                                               (int)(((float)y / (float)map.Scene.RegionInfo.RegionSizeX) * (float)textureToAddiTexture.Height));
                }
            }
            map.Scene.AssetService.Delete(paintAsset.ID);
            paintTexture.UnlockBitmap();
            textureToAddTexture.UnlockBitmap();
            paintAsset.Data  = OpenJPEG.EncodeFromImage(paintTexture.Bitmap(), false);
            paintAsset.Flags = AssetFlags.Deletable;
            map.Scene.RegionInfo.RegionSettings.PaintableTerrainTexture = UUID.Random();
            paintAsset.ID = map.Scene.RegionInfo.RegionSettings.PaintableTerrainTexture.ToString();
            map.Scene.AssetService.Store(paintAsset);
            map.Scene.RequestModuleInterface <IEstateModule>().sendRegionHandshakeToAll();
            locked = false;
        }