public Bitmap Shade (Bitmap source, Color shade, float percent, bool greyScale) { FastBitmap bmp = new FastBitmap (source); bmp.LockBitmap (); for (int y = 0; y < source.Height; y++) { for (int x = 0; x < source.Width; x++) { Color c = bmp.GetPixel (x, y); if (greyScale) { int luma = (int)(c.R * 0.3 + c.G * 0.59 + c.B * 0.11); bmp.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); bmp.SetPixel (x, y, Color.FromArgb (c.A, lumaR, lumaG, lumaB)); } } } bmp.UnlockBitmap (); return bmp.Bitmap (); }
void Draw (string data, UUID id, string extraParams) { // We need to cater for old scripts that didn't use extraParams neatly, they use either an integer size which represents both width and height, or setalpha // we will now support multiple comma separated parameters 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; bgColour = int.TryParse (value, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out hex) ? Color.FromArgb (hex) : Color.FromName (value); break; case "altdatadelim": altDataDelim = value [0]; break; case "": // blank string has been passed do nothing just use defaults break; default: // this is all for backwards compatibility, all a bit ugly hopefully 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 compatibility) } else { // this function used to accept an int on its own that represented both // width and height, this is to maintain backwards compatibility, 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; bitmap = alpha == 256 ? new Bitmap (width, height, PixelFormat.Format32bppRgb) : 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); } FastBitmap fastBitmap = new FastBitmap (bitmap); fastBitmap.LockBitmap (); try { 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))); } } } } catch { MainConsole.Instance.Error ( "[Vector rendering]: FastBMP encode Failed!"); } fastBitmap.UnlockBitmap (); bitmap = fastBitmap.Bitmap (); graph.SmoothingMode = SmoothingMode.AntiAlias; graph.CompositingQuality = CompositingQuality.HighQuality; graph.TextRenderingHint = TextRenderingHint.AntiAliasGridFit; GDIDraw (data, graph, altDataDelim); graph.Dispose (); byte [] imageJ2000 = new byte [0]; try { imageJ2000 = OpenJPEG.EncodeFromImage (bitmap, false); } catch (Exception) { MainConsole.Instance.Error ( "[Vector rendering]: OpenJpeg Encode Failed. Empty byte data returned!"); } m_textureManager.ReturnData (id, imageJ2000); }
public Bitmap TerrainToBitmap (Bitmap mapbmp) { FastBitmap unsafeBMP = new FastBitmap (mapbmp); unsafeBMP.LockBitmap (); //DateTime start = DateTime.Now; //MainConsole.Instance.Info("[MAPTILE]: Generating Maptile Step 1: Terrain"); // These textures should be in the AssetCache anyway, as every client connecting 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 = 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 (); //MainConsole.Instance.Info("[MAPTILE]: Generating Maptile Step 1: Done in " + (DateTime.Now - start).TotalSeconds + " ms"); return unsafeBMP.Bitmap (); }