/// <summary> /// Initializes a new instance of an AssetTexture object /// </summary> /// <param name="image">A <seealso cref="ManagedImage"/> object containing texture data</param> public AssetTexture(ManagedImage image) { Image = image; Components = 0; if ((Image.Channels & ManagedImage.ImageChannels.Color) != 0) Components += 3; if ((Image.Channels & ManagedImage.ImageChannels.Gray) != 0) ++Components; if ((Image.Channels & ManagedImage.ImageChannels.Bump) != 0) ++Components; if ((Image.Channels & ManagedImage.ImageChannels.Alpha) != 0) ++Components; }
private void DisplayResource(string resource) { Stream stream = OpenMetaverse.Helpers.GetResourceStream(resource + ".tga"); if (stream != null) { AlphaMask = LoadTGAClass.LoadTGA(stream); stream.Close(); ManagedImage managedImage = new ManagedImage(AlphaMask); // FIXME: Operate on ManagedImage instead of Bitmap pic1.Image = Oven.ModifyAlphaMask(AlphaMask, (byte)scrollWeight.Value, 0.0f); } else { MessageBox.Show("Failed to load embedded resource \"" + resource + "\"", "Baker", MessageBoxButtons.OK, MessageBoxIcon.Error); } }
public void Decode_jp2k(string filename, string decodeType, Asset asset) { var img = (AssetTexture)asset; OpenMetaverse.Imaging.ManagedImage imgImage = img.Image; if (imgImage == null) { OpenJPEG.DecodeToImage(asset.AssetData, out imgImage); } if (imgImage != null) { if (filename.ToLower().EndsWith("tga")) { File.WriteAllBytes(filename, imgImage.ExportTGA()); } else { File.WriteAllBytes(filename, imgImage.ExportRaw()); } } }
private void ApplyTint(ManagedImage dest, Color4 src) { if (dest == null) return; for (int i = 0; i < dest.Red.Length; i++) { dest.Red[i] = (byte)((dest.Red[i] * Utils.FloatToByte(src.R, 0f, 1f)) >> 8); dest.Green[i] = (byte)((dest.Green[i] * Utils.FloatToByte(src.G, 0f, 1f)) >> 8); dest.Blue[i] = (byte)((dest.Blue[i] * Utils.FloatToByte(src.B, 0f, 1f)) >> 8); } }
public ManagedImage Clone() { ManagedImage image = new ManagedImage(Width, Height, Channels); if (Red != null) image.Red = (byte[])Red.Clone(); if (Green != null) image.Green = (byte[])Green.Clone(); if (Blue != null) image.Blue = (byte[])Blue.Clone(); if (Alpha != null) image.Alpha = (byte[])Alpha.Clone(); if (Bump != null) image.Bump = (byte[])Bump.Clone(); return image; }
/// <summary> /// This method will produce a random city with the central region of the city being /// specified as a parameter. More parameters need to be made available for this method /// to produce a better quality city, note for now the minimum area for a city is a /// 3x3 grid of regions. This code is based on the original C++ version called pixel city. /// </summary> /// <param name="seed_value">Random integer seed value.</param> /// <returns>true / false indicator of success or failure.</returns> private bool doGenerate(int seed_value) { int rx, ry; // Based on the initial seed value populate the regions that this shared module // is connected to, this means first get a list of the region, determine which // region is in the center of all the regions and set this as the hotzone, or // central part of the city (this is where the tallest/largest buildings will // be created) and will extend out to cover virtually all of the connected // regions if desired. No support for aging of the buildings or the city exists // yet it is a possible course for the future of this module. // TODO // // Validate the details in the configuration file against the settings in // the database, otherwise a new user/estate/parcel could be created which will // negate any of the security systems that Aurora has in place. // First quick check to see if the module is enabled or not. if (!m_fEnabled) { m_log.Info("[CITY BUILDER]: Disabled, aborting auto generation."); return (false); } m_log.Info("[CITY BUILDER]: Auto generating the city."); // Now we need to ask some basic values for the city generation, we already have // the base seed value as this is part of the 'city generate' command, now what // about a name, position, size, densities etc. Some of this can be generated // based on the seed value, but then, it would need to be confirmed by the user // or allow them to change it. TODO move all requested data into the configuration file. if (m_UserAccountService == null) { m_UserAccountService = simulationBase.ApplicationRegistry.RequestModuleInterface<IUserAccountService>(); } // Decide where the city is to be placed within the server instance. int r = CityModule.randomValue(10); string regionCount = MainConsole.Instance.CmdPrompt("Region Count ", r.ToString()); r = Convert.ToInt32(regionCount); m_log.InfoFormat("[CITY BUILDER]: City area {0} x {1} regions ", r, r); // Needs to be changed to use the 'defualt' properties and ask about the default // estate settings that are to be used, even if it is nothing more than just a // confirmation of the settings that are in the configuration file. cityName = MainConsole.Instance.CmdPrompt("City Name ", cityName); cityOwner = MainConsole.Instance.CmdPrompt("City Owner ", cityOwner); m_DefaultUserName = cityOwner; // Make sure that the user and estate information specified in the configuration file // have been loaded and the information has either been found or has been created. m_DefaultUserAccount = m_UserAccountService.GetUserAccount(UUID.Zero, cityOwner); if (m_DefaultUserAccount == null) { m_log.InfoFormat("[CITY BUILDER]: Creating default account {0}", m_DefaultUserName); m_UserAccountService.CreateUser(m_DefaultUserName, Util.Md5Hash(m_DefaultUserPword), m_DefaultUserEmail); m_DefaultUserAccount = m_UserAccountService.GetUserAccount(UUID.Zero, m_DefaultUserName); cityOwner = m_DefaultUserName; } else m_log.InfoFormat("[CITY BUILDER]: Account found for {0}", m_DefaultUserName); // Obtain the scene manager that the server instance is using. sceneManager = simulationBase.ApplicationRegistry.RequestModuleInterface<SceneManager>(); // Construct the data instance for a city map to hold the total regions in the simulation. cityMap = new CityMap(); citySeed = seed_value; cityMap.cityRegions = new Scene[r, r]; cityMap.cityPlots = new List<BuildingPlot>(); cityMap.cityBuildings = new List<CityBuilding>(); // Construct land and estate data and update to reflect the found user or the newly created one. cityLandData = new LandData(); RegionInfo regionInfo = new RegionInfo(); regionInfo.RegionID = UUID.Random(); // Determine if the default user account as specified in City Builder's configuration file // has any predefined estates, if so, just select the first one for now. Perhaps a search of // the estates to attempt to find a match to the details from the configuration file. EstateConnector = Aurora.DataManager.DataManager.RequestPlugin<IEstateConnector>(); // Valid estate connection established. if (EstateConnector != null) { // Valid estate connector, determine if the default user account has any estates. List<EstateSettings> estates = EstateConnector.GetEstates(m_DefaultUserAccount.PrincipalID); // No estates are found, so construct a new one based on the default estate settings // from the configuration file. if (estates == null) { // No estates present so construct one. m_DefaultEstate = new EstateSettings(); m_log.InfoFormat("[CITY BUILDER]: No estates found for user {0}, constructing default estate.", m_DefaultUserAccount.Name); m_DefaultEstate.EstateOwner = m_DefaultUserAccount.PrincipalID; m_DefaultEstate.EstateName = m_DefaultEstateName; m_DefaultEstate.EstatePass = Util.Md5Hash(Util.Md5Hash(m_DefaultEstatePassword)); m_DefaultEstate.EstateID = (uint)CityModule.randomValue(1000); regionInfo.EstateSettings = EstateConnector.CreateEstate(m_DefaultEstate, regionInfo.RegionID); } else { // Estates have been found, select the first estate in the list. No checking is done // against the configuration file settings. TODO validate the estate against the // configuration file. m_DefaultEstate = estates[0]; regionInfo.EstateSettings = m_DefaultEstate; m_log.InfoFormat("[CITY BUILDER]: {0} estates found for user {1}, selecting {2}", estates.Count, m_DefaultUserAccount.Name, m_DefaultEstate.EstateName); } } else { m_log.Info("[CITY BUILDER]: No connection with server."); return (false); } // Fill in land data for the estate/owner. cityLandData.OwnerID = m_DefaultUserAccount.PrincipalID; cityLandData.Name = m_DefaultEstateName; cityLandData.GlobalID = UUID.Random(); cityLandData.GroupID = UUID.Zero; int regionPort = startPort; // Construct the region. regionInfo.RegionSizeX = cityConfig.GetInt("DefaultRegionSize", 256); regionInfo.RegionSizeY = regionInfo.RegionSizeX; regionInfo.RegionType = "Mainland"; regionInfo.ObjectCapacity = 100000; regionInfo.Startup = StartupType.Normal; regionInfo.ScopeID = UUID.Zero; IParcelServiceConnector parcelService = simulationBase.ApplicationRegistry.RequestModuleInterface<IParcelServiceConnector>(); if (parcelService == null) { m_log.Info("[CITY BUILDER]: Unable to connect to servers parcel service."); } if (r == 1) { m_log.Info("[CITY BUILDER]: Single region city."); IPAddress address = IPAddress.Parse("0.0.0.0"); regionInfo.ExternalHostName = Aurora.Framework.Utilities.GetExternalIp(); regionInfo.FindExternalAutomatically = true; regionInfo.InternalEndPoint = new IPEndPoint(address, regionPort++); cityLandData.RegionID = regionInfo.RegionID; regionInfo.RegionName = "Region00"; regionInfo.RegionLocX = (int)m_DefaultStartLocation.X; regionInfo.RegionLocY = (int)m_DefaultStartLocation.Y; if (parcelService != null) parcelService.StoreLandObject(cityLandData); if (!createRegion(0, 0, regionInfo)) { m_log.Info("[CITY BUILDER]: Failed to construct region."); return (false); } } else if (r > 1) { m_log.Info("[CITY BUILDER]: Multi-region city."); m_log.Info("[CITY BUILDER]: Finding external IP, please wait ... "); regionInfo.ExternalHostName = Aurora.Framework.Utilities.GetExternalIp(); if (regionInfo.ExternalHostName.Length <= 0) { regionInfo.FindExternalAutomatically = false; } else { m_log.InfoFormat("[CITY BUILDER]: External IP address is {0}", regionInfo.ExternalHostName); regionInfo.FindExternalAutomatically = true; } // Construct the regions for the city. regionPort = startPort; INeighborService neighbours = simulationBase.ApplicationRegistry.RequestModuleInterface<INeighborService>(); if (neighbours == null) { m_log.Info("[CITY BUILDER]: No neighbours."); } else { m_log.Info("[CITY BUILDER]: Neighbours service found."); } IPAddress address = IPAddress.Parse("0.0.0.0"); for (rx = 0; rx < r; rx++) { for (ry = 0; ry < r; ry++) { regionInfo.InternalEndPoint = new IPEndPoint(address, regionPort++); cityLandData.RegionID = regionInfo.RegionID; regionInfo.RegionName = "Region" + rx + ry; regionInfo.RegionLocX = (int)(m_DefaultStartLocation.X + rx); regionInfo.RegionLocY = (int)(m_DefaultStartLocation.Y + ry); m_log.InfoFormat("[CITY BUILDER]: '{0}' @ {1},{2}, http://{3}/", regionInfo.RegionName, regionInfo.RegionLocX, regionInfo.RegionLocY, regionInfo.InternalEndPoint); if (parcelService != null) parcelService.StoreLandObject(cityLandData); if (!createRegion(rx, ry, regionInfo)) { m_log.InfoFormat("[CITY BUILDER]: Failed to construct region at {0},{1}", rx, ry); return (false); } if (neighbours != null) { m_log.Info("[CITY BUILDER]: Informing neighbours."); neighbours.InformOurRegionsOfNewNeighbor(regionInfo); } } } } // Either generate the terrain or loading from an existing file, DEM for example. m_log.Info("[CITY BUILDER]: [TERRAIN]"); // Construct the new terrain for each region and pass the height map to it. // For the entire area covered by all of the regions construct a new terrain heightfield for it. // Also construct several maps that can be blended together in order to provide a suitablly natural // looking terrain which is not too flat or doesn't entirely consist of mountains. float[,] terrainMap; float[,] hMap1; float[,] hMap2; float[,] hMap3; float[,] hMap4; float[] bFactors = new float[4]; int size = regionInfo.RegionSizeX; int y; int x; terrainMap = new float[ size * r, size * r ]; hMap1 = new float[ size * r, size * r ]; hMap2 = new float[ size * r, size * r ]; hMap3 = new float[ size * r, size * r ]; hMap4 = new float[ size * r, size * r ]; // Set blending factors. bFactors[0] = 0.75f; bFactors[1] = 0.55f; bFactors[2] = 0.35f; bFactors[3] = 0.05f; // Generate four layers for the initial height map and then blend them together. for (x = 0; x < size; x++) { for (y = 0; y < size; y++) { for (int i = 0; i < r; i++) { for (int j = 0; j < r; j++) { hMap1[i * x, i * y] = Perlin.noise2((float)x+i, (float)y+i); hMap2[i * x, i * y] = Perlin.noise2((float)x, (float)y+i); hMap3[i * x, i * y] = Perlin.noise2((float)x+i, (float)y); hMap4[i * x, i * y] = Perlin.noise2((float)x+j, (float)y+i); terrainMap[i*x, i*y] = (hMap1[i*x, i*y] * bFactors[0]) + (hMap2[i*x, i*y] * bFactors[1]) + (hMap3[i*x, i*y] * bFactors[2]) + (hMap4[i*x, i*y] * bFactors[3]); } } } } // DEBUG code that will save the resulting terrainMap as a jpeg image. m_log.Info("[CITY BUILDER]: Debug, save terrain map (full) as a jpeg image."); ManagedImage mImage = new ManagedImage(r * size, r * size, ManagedImage.ImageChannels.Bump); // Find a way of copying the terrainMap array into the newly created image, then save // the image to disk. m_log.Info("[CITY BUILDER]: Terrain built and blended, tiling and region application."); // Set the height map of each region based on the newly created terrainMap. ITerrain terrain = null; for (rx = 0; rx < r; rx++) { for (ry = 0; ry < r; ry++) { Scene region = cityMap.cityRegions[rx, ry]; ITerrainChannel tChannel = new TerrainChannel(true, region); region.TryRequestModuleInterface<ITerrain>(out terrain); m_log.InfoFormat("[CITY BUILDER]: Region [ {0}, {1} ]", rx, ry); float[,] tile = new float[ size, size ]; for (int i = 0; i < size; i++) { for (int j = 0; i < size; j++) { tile[i, j] = terrainMap[(rx * size) + i, (ry * size) + j]; } } if (terrain != null & tile!=null) terrain.SetHeights2D(tile); // dispose of the tile now thats its not needed as a new tile is allocated next loop run. tile = null; } } // Rivers and other waterways. Randomly select a number of rivers for the entire area // and place them. int rCount = CityModule.randomValue(size / r); m_log.InfoFormat("[CITY BUILDER]: River count for entire area {0}", rCount); // From the total number of regions pick a number of regions that will be 'centers' // for the entire city, record these in the centralRegions list. m_log.Info("[CITY BUILDER]: [CENTERS]"); // ( region count * region count ) / 3 int aNum = CityModule.randomValue((cityMap.cityRegions.GetUpperBound(0) * cityMap.cityRegions.GetUpperBound(1))/3); if (aNum == 0) { aNum = 1; } m_log.InfoFormat("[CITY BUILDER]: Total regions {0}, selecting {1} regions for centers.", (r*r), aNum ); int prevRegionX = 0; int prevRegionY = 0; while ( aNum > 0 ) { int currRegionX = randomValue( cityMap.cityRegions.GetUpperBound(0) ) / 2; int currRegionY = randomValue( cityMap.cityRegions.GetUpperBound(1) ) / 2; // If the location selected is the same as the previous location try again. if (currRegionX == prevRegionX && currRegionY == prevRegionY) { aNum--; continue; } m_log.InfoFormat("[CITY BUILDER]: Region {0}, located {1},{2}", aNum, prevRegionX, prevRegionY); try { Scene region = cityMap.centralRegions[(prevRegionX * cityMap.cityRegions.GetUpperBound(0)) + prevRegionY]; if (region!=null) { cityMap.centralRegions.Add(region); } } catch { } aNum--; prevRegionX = currRegionX; prevRegionY = currRegionY; } m_log.Info("[CITY BUILDER]: [DENSITY]"); float avgDensity = 0.0f; avgDensity += cityDensities[0]; avgDensity += cityDensities[1]; avgDensity += cityDensities[2]; avgDensity += cityDensities[3]; avgDensity /= 4; // Before ANYTHING else is created construct the transport systems, priority is given // to the road network before the rail network, perhaps a configuration option to allow // for the prioritisation value of the transport system is possible. m_log.Info("[CITY BUILDER]: [FREEWAYS]"); // Construct a road system (high speed ~50-70 mph) between and around the city center regions. m_log.Info("[CITY BUILDER]: [HIGHWAYS]"); m_log.Info("[CITY BUILDER]: [STREETS]"); m_log.Info("[CITY BUILDER]: [RAILWAYS]"); m_log.InfoFormat("[CITY BUILDER]: [RESIDENTIAL DENSITY] {0}%", cityDensities[0] * 100); m_log.InfoFormat("[CITY BUILDER]: [COMMERCIAL DENSITY] {0}%", cityDensities[1] * 100); m_log.InfoFormat("[CITY BUILDER]: [CORPORATE DENSITY] {0}%", cityDensities[2] * 100); m_log.InfoFormat("[CITY BUILDER]: [INDUSTRIAL DENISTY] {0}%", cityDensities[3] * 100); m_log.InfoFormat("[CITY BUILDER]: [AVERAGE DENSITY] {0}%", avgDensity); m_log.Info("[CITY BUILDER]: [BLOCKS]"); m_log.Info("[CITY BUILDER]: [ALLOTMENT PLOTS]"); m_log.Info("[CITY BUILDER]: [BUILDINGS]"); return (true); }
private void MultiplyLayerFromAlpha(ManagedImage dest, ManagedImage src) { if (!SanitizeLayers(dest, src)) return; for (int i = 0; i < dest.Red.Length; i++) { dest.Red[i] = (byte)((dest.Red[i] * src.Alpha[i]) >> 8); dest.Green[i] = (byte)((dest.Green[i] * src.Alpha[i]) >> 8); dest.Blue[i] = (byte)((dest.Blue[i] * src.Alpha[i]) >> 8); } }
private void ApplyTint(ManagedImage dest, Color4 src) { if (dest == null) return; for (int i = 0; i < dest.Red.Length; i++) { dest.Red[i] = (byte)((dest.Red[i] * ((byte)(src.R * byte.MaxValue))) >> 8); dest.Green[i] = (byte)((dest.Green[i] * ((byte)(src.G * byte.MaxValue))) >> 8); dest.Blue[i] = (byte)((dest.Blue[i] * ((byte)(src.B * byte.MaxValue))) >> 8); } }
private void AddAlpha(ManagedImage dest, ManagedImage src) { if (!SanitizeLayers(dest, src)) return; for (int i = 0; i < dest.Alpha.Length; i++) { if (src.Alpha[i] < dest.Alpha[i]) { dest.Alpha[i] = src.Alpha[i]; } } }
/// <summary> /// /// </summary> /// <param name="encoded"></param> /// <param name="managedImage"></param> /// <returns></returns> public static bool DecodeToImage(byte[] encoded, out ManagedImage managedImage) { MarshalledImage marshalled = new MarshalledImage(); // Allocate and copy to input buffer marshalled.length = encoded.Length; lock (OpenJPEGLock) { DotNetAllocEncoded(ref marshalled); Marshal.Copy(encoded, 0, marshalled.encoded, encoded.Length); // Codec will allocate output buffer DotNetDecode(ref marshalled); int n = marshalled.width * marshalled.height; switch (marshalled.components) { case 1: // Grayscale managedImage = new ManagedImage(marshalled.width, marshalled.height, ManagedImage.ImageChannels.Color); Marshal.Copy(marshalled.decoded, managedImage.Red, 0, n); Buffer.BlockCopy(managedImage.Red, 0, managedImage.Green, 0, n); Buffer.BlockCopy(managedImage.Red, 0, managedImage.Blue, 0, n); break; case 2: // Grayscale + alpha managedImage = new ManagedImage(marshalled.width, marshalled.height, ManagedImage.ImageChannels.Color | ManagedImage.ImageChannels.Alpha); Marshal.Copy(marshalled.decoded, managedImage.Red, 0, n); Buffer.BlockCopy(managedImage.Red, 0, managedImage.Green, 0, n); Buffer.BlockCopy(managedImage.Red, 0, managedImage.Blue, 0, n); Marshal.Copy((IntPtr)(marshalled.decoded.ToInt64() + (long)n), managedImage.Alpha, 0, n); break; case 3: // RGB managedImage = new ManagedImage(marshalled.width, marshalled.height, ManagedImage.ImageChannels.Color); Marshal.Copy(marshalled.decoded, managedImage.Red, 0, n); Marshal.Copy((IntPtr)(marshalled.decoded.ToInt64() + (long)n), managedImage.Green, 0, n); Marshal.Copy((IntPtr)(marshalled.decoded.ToInt64() + (long)(n * 2)), managedImage.Blue, 0, n); break; case 4: // RGBA managedImage = new ManagedImage(marshalled.width, marshalled.height, ManagedImage.ImageChannels.Color | ManagedImage.ImageChannels.Alpha); Marshal.Copy(marshalled.decoded, managedImage.Red, 0, n); Marshal.Copy((IntPtr)(marshalled.decoded.ToInt64() + (long)n), managedImage.Green, 0, n); Marshal.Copy((IntPtr)(marshalled.decoded.ToInt64() + (long)(n * 2)), managedImage.Blue, 0, n); Marshal.Copy((IntPtr)(marshalled.decoded.ToInt64() + (long)(n * 3)), managedImage.Alpha, 0, n); break; case 5: // RGBBA managedImage = new ManagedImage(marshalled.width, marshalled.height, ManagedImage.ImageChannels.Color | ManagedImage.ImageChannels.Alpha | ManagedImage.ImageChannels.Bump); Marshal.Copy(marshalled.decoded, managedImage.Red, 0, n); Marshal.Copy((IntPtr)(marshalled.decoded.ToInt64() + (long)n), managedImage.Green, 0, n); Marshal.Copy((IntPtr)(marshalled.decoded.ToInt64() + (long)(n * 2)), managedImage.Blue, 0, n); // Bump comes before alpha in 5 channel encode Marshal.Copy((IntPtr)(marshalled.decoded.ToInt64() + (long)(n * 3)), managedImage.Bump, 0, n); Marshal.Copy((IntPtr)(marshalled.decoded.ToInt64() + (long)(n * 4)), managedImage.Alpha, 0, n); break; default: Logger.Log("Decoded image with unhandled number of components: " + marshalled.components, Helpers.LogLevel.Error); DotNetFree(ref marshalled); managedImage = null; return false; } DotNetFree(ref marshalled); } return true; }
/// <summary> /// Decode JPEG2000 data to an <seealso cref="System.Drawing.Image"/> and /// <seealso cref="ManagedImage"/> /// </summary> /// <param name="encoded">JPEG2000 encoded data</param> /// <param name="managedImage">ManagedImage object to decode to</param> /// <param name="image">Image object to decode to</param> /// <returns>True if the decode succeeds, otherwise false</returns> public static bool DecodeToImage(byte[] encoded, out ManagedImage managedImage, out Image image) { managedImage = null; image = null; if (DecodeToImage(encoded, out managedImage)) { try { image = LoadTGAClass.LoadTGA(new MemoryStream(managedImage.ExportTGA())); return true; } catch (Exception ex) { Logger.Log("Failed to export and load TGA data from decoded image", Helpers.LogLevel.Error, ex); return false; } } else { return false; } }
/// <summary> /// Encode a <seealso cref="ManagedImage"/> object into a byte array /// </summary> /// <param name="image">The <seealso cref="ManagedImage"/> object to encode</param> /// <returns>a byte array of the encoded image</returns> public static byte[] Encode(ManagedImage image) { return Encode(image, false); }
/// <summary> /// Encode a <seealso cref="ManagedImage"/> object into a byte array /// </summary> /// <param name="image">The <seealso cref="ManagedImage"/> object to encode</param> /// <param name="lossless">true to enable lossless conversion, only useful for small images ie: sculptmaps</param> /// <returns>A byte array containing the encoded Image object</returns> public static byte[] Encode(ManagedImage image, bool lossless) { if ((image.Channels & ManagedImage.ImageChannels.Color) == 0 || ((image.Channels & ManagedImage.ImageChannels.Bump) != 0 && (image.Channels & ManagedImage.ImageChannels.Alpha) == 0)) throw new ArgumentException("JPEG2000 encoding is not supported for this channel combination"); byte[] encoded = null; MarshalledImage marshalled = new MarshalledImage(); // allocate and copy to input buffer marshalled.width = image.Width; marshalled.height = image.Height; marshalled.components = 3; if ((image.Channels & ManagedImage.ImageChannels.Alpha) != 0) marshalled.components++; if ((image.Channels & ManagedImage.ImageChannels.Bump) != 0) marshalled.components++; lock (OpenJPEGLock) { if (!DotNetAllocDecoded(ref marshalled)) throw new Exception("DotNetAllocDecoded failed"); int n = image.Width * image.Height; if ((image.Channels & ManagedImage.ImageChannels.Color) != 0) { Marshal.Copy(image.Red, 0, marshalled.decoded, n); Marshal.Copy(image.Green, 0, (IntPtr)(marshalled.decoded.ToInt64() + n), n); Marshal.Copy(image.Blue, 0, (IntPtr)(marshalled.decoded.ToInt64() + n * 2), n); } if ((image.Channels & ManagedImage.ImageChannels.Alpha) != 0) Marshal.Copy(image.Alpha, 0, (IntPtr)(marshalled.decoded.ToInt64() + n * 3), n); if ((image.Channels & ManagedImage.ImageChannels.Bump) != 0) Marshal.Copy(image.Bump, 0, (IntPtr)(marshalled.decoded.ToInt64() + n * 4), n); // codec will allocate output buffer if (!DotNetEncode(ref marshalled, lossless)) throw new Exception("DotNetEncode failed"); // copy output buffer encoded = new byte[marshalled.length]; Marshal.Copy(marshalled.encoded, encoded, 0, marshalled.length); // free buffers DotNetFree(ref marshalled); } return encoded; }
public AssetTexture(ManagedImage image) { Image = image; }
public static ManagedImage LoadResourceLayer(string fileName) { try { Bitmap bitmap = null; lock (ResourceSync) { using (Stream stream = Helpers.GetResourceStream(fileName, Settings.RESOURCE_DIR)) { bitmap = LoadTGAClass.LoadTGA(stream); } } if (bitmap == null) { Logger.Log(String.Format("Failed loading resource file: {0}", fileName), Helpers.LogLevel.Error); return null; } else { ManagedImage image = new ManagedImage(bitmap); bitmap.Dispose(); return image; } } catch (Exception e) { Logger.Log(String.Format("Failed loading resource file: {0} ({1})", fileName, e.Message), Helpers.LogLevel.Error, e); return null; } }
/// <summary> /// Encode a <seealso cref="System.Drawing.Bitmap"/> object into a byte array /// </summary> /// <param name="bitmap">The source <seealso cref="System.Drawing.Bitmap"/> object to encode</param> /// <param name="lossless">true to enable lossless decoding</param> /// <returns>A byte array containing the source Bitmap object</returns> public unsafe static byte[] EncodeFromImage(Bitmap bitmap, bool lossless) { BitmapData bd; ManagedImage decoded; int bitmapWidth = bitmap.Width; int bitmapHeight = bitmap.Height; int pixelCount = bitmapWidth * bitmapHeight; int i; if ((bitmap.PixelFormat & PixelFormat.Alpha) != 0 || (bitmap.PixelFormat & PixelFormat.PAlpha) != 0) { // Four layers, RGBA decoded = new ManagedImage(bitmapWidth, bitmapHeight, ManagedImage.ImageChannels.Color | ManagedImage.ImageChannels.Alpha); bd = bitmap.LockBits(new Rectangle(0, 0, bitmapWidth, bitmapHeight), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); byte* pixel = (byte*)bd.Scan0; for (i = 0; i < pixelCount; i++) { // GDI+ gives us BGRA and we need to turn that in to RGBA decoded.Blue[i] = *(pixel++); decoded.Green[i] = *(pixel++); decoded.Red[i] = *(pixel++); decoded.Alpha[i] = *(pixel++); } } else if (bitmap.PixelFormat == PixelFormat.Format16bppGrayScale) { // One layer decoded = new ManagedImage(bitmapWidth, bitmapHeight, ManagedImage.ImageChannels.Color); bd = bitmap.LockBits(new Rectangle(0, 0, bitmapWidth, bitmapHeight), ImageLockMode.ReadOnly, PixelFormat.Format16bppGrayScale); byte* pixel = (byte*)bd.Scan0; for (i = 0; i < pixelCount; i++) { // Normalize 16-bit data down to 8-bit ushort origVal = (byte)(*(pixel) + (*(pixel + 1) << 8)); byte val = (byte)(((double)origVal / (double)UInt32.MaxValue) * (double)Byte.MaxValue); decoded.Red[i] = val; decoded.Green[i] = val; decoded.Blue[i] = val; pixel += 2; } } else { // Three layers, RGB decoded = new ManagedImage(bitmapWidth, bitmapHeight, ManagedImage.ImageChannels.Color); bd = bitmap.LockBits(new Rectangle(0, 0, bitmapWidth, bitmapHeight), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb); byte* pixel = (byte*)bd.Scan0; for (i = 0; i < pixelCount; i++) { decoded.Blue[i] = *(pixel++); decoded.Green[i] = *(pixel++); decoded.Red[i] = *(pixel++); } } bitmap.UnlockBits(bd); byte[] encoded = Encode(decoded, lossless); return encoded; }
public void Bake() { bakedTexture = new AssetTexture(new ManagedImage(bakeWidth, bakeHeight, ManagedImage.ImageChannels.Color | ManagedImage.ImageChannels.Alpha | ManagedImage.ImageChannels.Bump)); // Base color for eye bake is white, color of layer0 for others if (bakeType == BakeType.Eyes) { InitBakedLayerColor(Color4.White); } else if (textures.Count > 0) { InitBakedLayerColor(textures[0].Color); } // Do we have skin texture? bool SkinTexture = textures.Count > 0 && textures[0].Texture != null; if (bakeType == BakeType.Head) { DrawLayer(LoadResourceLayer("head_color.tga"), false); AddAlpha(bakedTexture.Image, LoadResourceLayer("head_alpha.tga")); MultiplyLayerFromAlpha(bakedTexture.Image, LoadResourceLayer("head_skingrain.tga")); } if (!SkinTexture && bakeType == BakeType.UpperBody) { DrawLayer(LoadResourceLayer("upperbody_color.tga"), false); } if (!SkinTexture && bakeType == BakeType.LowerBody) { DrawLayer(LoadResourceLayer("lowerbody_color.tga"), false); } ManagedImage alphaWearableTexture = null; // Layer each texture on top of one other, applying alpha masks as we go for (int i = 0; i < textures.Count; i++) { // Skip if we have no texture on this layer if (textures[i].Texture == null) continue; // Is this Alpha wearable and does it have an alpha channel? if (textures[i].TextureIndex >= AvatarTextureIndex.LowerAlpha && textures[i].TextureIndex <= AvatarTextureIndex.HairAlpha) { if (textures[i].Texture.Image.Alpha != null) { alphaWearableTexture = textures[i].Texture.Image.Clone(); } continue; } // Don't draw skin and tattoo on head bake first // For head bake the skin and texture are drawn last, go figure if (bakeType == BakeType.Head && (i == 0 || i == 1)) continue; ManagedImage texture = textures[i].Texture.Image.Clone(); //File.WriteAllBytes(bakeType + "-texture-layer-" + i + ".tga", texture.ExportTGA()); // Resize texture to the size of baked layer // FIXME: if texture is smaller than the layer, don't stretch it, tile it if (texture.Width != bakeWidth || texture.Height != bakeHeight) { try { texture.ResizeNearestNeighbor(bakeWidth, bakeHeight); } catch (Exception) { continue; } } // Special case for hair layer for the head bake // If we don't have skin texture, we discard hair alpha // and apply hair(i==2) pattern over the texture if (!SkinTexture && bakeType == BakeType.Head && i == 2) { if (texture.Alpha != null) { for (int j = 0; j < texture.Alpha.Length; j++) texture.Alpha[j] = (byte)255; } MultiplyLayerFromAlpha(texture, LoadResourceLayer("head_hair.tga")); } // Aply tint and alpha masks except for skin that has a texture // on layer 0 which always overrides other skin settings if (!(IsSkin && i == 0)) { ApplyTint(texture, textures[i].Color); // For hair bake, we skip all alpha masks // and use one from the texture, for both // alpha and morph layers if (bakeType == BakeType.Hair) { if (texture.Alpha != null) { bakedTexture.Image.Bump = texture.Alpha; } else { for (int j = 0; j < bakedTexture.Image.Bump.Length; j++) bakedTexture.Image.Bump[j] = byte.MaxValue; } } // Apply parametrized alpha masks else if (textures[i].AlphaMasks != null && textures[i].AlphaMasks.Count > 0) { // Combined mask for the layer, fully transparent to begin with ManagedImage combinedMask = new ManagedImage(bakeWidth, bakeHeight, ManagedImage.ImageChannels.Alpha); int addedMasks = 0; // First add mask in normal blend mode foreach (KeyValuePair<VisualAlphaParam, float> kvp in textures[i].AlphaMasks) { if (!MaskBelongsToBake(kvp.Key.TGAFile)) continue; if (kvp.Key.MultiplyBlend == false && (kvp.Value > 0f || !kvp.Key.SkipIfZero)) { ApplyAlpha(combinedMask, kvp.Key, kvp.Value); //File.WriteAllBytes(bakeType + "-layer-" + i + "-mask-" + addedMasks + ".tga", combinedMask.ExportTGA()); addedMasks++; } } // If there were no mask in normal blend mode make aplha fully opaque if (addedMasks == 0) for (int l = 0; l < combinedMask.Alpha.Length; l++) combinedMask.Alpha[l] = 255; // Add masks in multiply blend mode foreach (KeyValuePair<VisualAlphaParam, float> kvp in textures[i].AlphaMasks) { if (!MaskBelongsToBake(kvp.Key.TGAFile)) continue; if (kvp.Key.MultiplyBlend == true && (kvp.Value > 0f || !kvp.Key.SkipIfZero)) { ApplyAlpha(combinedMask, kvp.Key, kvp.Value); //File.WriteAllBytes(bakeType + "-layer-" + i + "-mask-" + addedMasks + ".tga", combinedMask.ExportTGA()); addedMasks++; } } if (addedMasks > 0) { // Apply combined alpha mask to the cloned texture AddAlpha(texture, combinedMask); } // Is this layer used for morph mask? If it is, use its // alpha as the morth for the whole bake if (Textures[i].TextureIndex == AppearanceManager.MorphLayerForBakeType(bakeType)) { bakedTexture.Image.Bump = texture.Alpha; } //File.WriteAllBytes(bakeType + "-masked-texture-" + i + ".tga", texture.ExportTGA()); } } bool useAlpha = i == 0 && (BakeType == BakeType.Skirt || BakeType == BakeType.Hair); DrawLayer(texture, useAlpha); //File.WriteAllBytes(bakeType + "-layer-" + i + ".tga", texture.ExportTGA()); } // For head and tattoo, we add skin last if (IsSkin && bakeType == BakeType.Head) { ManagedImage texture; if (textures[0].Texture != null) { texture = textures[0].Texture.Image.Clone(); if (texture.Width != bakeWidth || texture.Height != bakeHeight) { try { texture.ResizeNearestNeighbor(bakeWidth, bakeHeight); } catch (Exception) { } } DrawLayer(texture, false); } // Add head tattoo here (if available, order-dependant) if (textures.Count > 1 && textures[1].Texture != null) { texture = textures[1].Texture.Image.Clone(); if (texture.Width != bakeWidth || texture.Height != bakeHeight) { try { texture.ResizeNearestNeighbor(bakeWidth, bakeHeight); } catch (Exception) { } } DrawLayer(texture, false); } } // Apply any alpha wearable textures to make parts of the avatar disappear if (alphaWearableTexture != null) { AddAlpha(bakedTexture.Image, alphaWearableTexture); } // We are done, encode asset for finalized bake bakedTexture.Encode(); //File.WriteAllBytes(bakeType + ".tga", bakedTexture.Image.ExportTGA()); }
private bool DrawLayer(ManagedImage source, bool useSourceAlpha) { bool sourceHasColor; bool sourceHasAlpha; bool sourceHasBump; int i = 0; sourceHasColor = ((source.Channels & ManagedImage.ImageChannels.Color) != 0 && source.Red != null && source.Green != null && source.Blue != null); sourceHasAlpha = ((source.Channels & ManagedImage.ImageChannels.Alpha) != 0 && source.Alpha != null); sourceHasBump = ((source.Channels & ManagedImage.ImageChannels.Bump) != 0 && source.Bump != null); useSourceAlpha = (useSourceAlpha && sourceHasAlpha); if (source.Width != _bakeWidth || source.Height != _bakeHeight) { try { source.ResizeNearestNeighbor(_bakeWidth, _bakeHeight); } catch { return false; } } int alpha = 255; //int alphaInv = 255 - alpha; int alphaInv = 256 - alpha; byte[] bakedRed = _bakedTexture.Image.Red; byte[] bakedGreen = _bakedTexture.Image.Green; byte[] bakedBlue = _bakedTexture.Image.Blue; byte[] bakedAlpha = _bakedTexture.Image.Alpha; byte[] bakedBump = _bakedTexture.Image.Bump; byte[] sourceRed = source.Red; byte[] sourceGreen = source.Green; byte[] sourceBlue = source.Blue; byte[] sourceAlpha = null; byte[] sourceBump = null; if (sourceHasAlpha) sourceAlpha = source.Alpha; if (sourceHasBump) sourceBump = source.Bump; for (int y = 0; y < _bakeHeight; y++) { for (int x = 0; x < _bakeWidth; x++) { if (sourceHasAlpha) { alpha = sourceAlpha[i]; //alphaInv = 255 - alpha; alphaInv = 256 - alpha; } if (sourceHasColor) { bakedRed[i] = (byte)((bakedRed[i] * alphaInv + sourceRed[i] * alpha) >> 8); bakedGreen[i] = (byte)((bakedGreen[i] * alphaInv + sourceGreen[i] * alpha) >> 8); bakedBlue[i] = (byte)((bakedBlue[i] * alphaInv + sourceBlue[i] * alpha) >> 8); } if (useSourceAlpha) bakedAlpha[i] = sourceAlpha[i]; if (sourceHasBump) bakedBump[i] = sourceBump[i]; ++i; } } return true; }
private void ApplyAlpha(ManagedImage dest, VisualAlphaParam param, float val) { ManagedImage src = LoadResourceLayer(param.TGAFile); if (dest == null || src == null || src.Alpha == null) return; if ((dest.Channels & ManagedImage.ImageChannels.Alpha) == 0) { dest.ConvertChannels(ManagedImage.ImageChannels.Alpha | dest.Channels); } if (dest.Width != src.Width || dest.Height != src.Height) { try { src.ResizeNearestNeighbor(dest.Width, dest.Height); } catch (Exception) { return; } } for (int i = 0; i < dest.Alpha.Length; i++) { byte alpha = src.Alpha[i] <= ((1 - val) * 255) ? (byte)0 : (byte)255; if (alpha != 255) { } if (param.MultiplyBlend) { dest.Alpha[i] = (byte)((dest.Alpha[i] * alpha) >> 8); } else { if (alpha > dest.Alpha[i]) { dest.Alpha[i] = alpha; } } } }
public static ManagedImage LoadAlphaLayer(string fileName) { Stream stream = Helpers.GetResourceStream(fileName); if (stream != null) { try { // FIXME: It would save cycles and memory if we wrote a direct // loader to ManagedImage for these files instead of using the // TGA loader Bitmap bitmap = LoadTGAClass.LoadTGA(stream); stream.Close(); ManagedImage alphaLayer = new ManagedImage(bitmap); // Disable all layers except the alpha layer alphaLayer.Red = null; alphaLayer.Green = null; alphaLayer.Blue = null; alphaLayer.Channels = ManagedImage.ImageChannels.Alpha; return alphaLayer; } catch (Exception e) { Logger.Log(String.Format("LoadAlphaLayer() failed on file: {0} ({1}", fileName, e.Message), Helpers.LogLevel.Error, e); return null; } } else { return null; } }
private bool DrawLayer(ManagedImage source, bool addSourceAlpha) { if (source == null) return false; bool sourceHasColor; bool sourceHasAlpha; bool sourceHasBump; int i = 0; sourceHasColor = ((source.Channels & ManagedImage.ImageChannels.Color) != 0 && source.Red != null && source.Green != null && source.Blue != null); sourceHasAlpha = ((source.Channels & ManagedImage.ImageChannels.Alpha) != 0 && source.Alpha != null); sourceHasBump = ((source.Channels & ManagedImage.ImageChannels.Bump) != 0 && source.Bump != null); addSourceAlpha = (addSourceAlpha && sourceHasAlpha); byte alpha = Byte.MaxValue; byte alphaInv = (byte)(Byte.MaxValue - alpha); byte[] bakedRed = bakedTexture.Image.Red; byte[] bakedGreen = bakedTexture.Image.Green; byte[] bakedBlue = bakedTexture.Image.Blue; byte[] bakedAlpha = bakedTexture.Image.Alpha; byte[] bakedBump = bakedTexture.Image.Bump; byte[] sourceRed = source.Red; byte[] sourceGreen = source.Green; byte[] sourceBlue = source.Blue; byte[] sourceAlpha = sourceHasAlpha ? source.Alpha : null; byte[] sourceBump = sourceHasBump ? source.Bump : null; for (int y = 0; y < bakeHeight; y++) { for (int x = 0; x < bakeWidth; x++) { if (sourceHasAlpha) { alpha = sourceAlpha[i]; alphaInv = (byte)(Byte.MaxValue - alpha); } if (sourceHasColor) { bakedRed[i] = (byte)((bakedRed[i] * alphaInv + sourceRed[i] * alpha) >> 8); bakedGreen[i] = (byte)((bakedGreen[i] * alphaInv + sourceGreen[i] * alpha) >> 8); bakedBlue[i] = (byte)((bakedBlue[i] * alphaInv + sourceBlue[i] * alpha) >> 8); } if (addSourceAlpha) { if (sourceAlpha[i] < bakedAlpha[i]) { bakedAlpha[i] = sourceAlpha[i]; } } if (sourceHasBump) bakedBump[i] = sourceBump[i]; ++i; } } return true; }
public static unsafe ManagedImage LoadTGAImage(System.IO.Stream source, bool mask) { byte[] buffer = new byte[source.Length]; source.Read(buffer, 0, buffer.Length); System.IO.MemoryStream ms = new System.IO.MemoryStream(buffer); using (System.IO.BinaryReader br = new System.IO.BinaryReader(ms)) { tgaHeader header = new tgaHeader(); header.Read(br); if (header.ImageSpec.PixelDepth != 8 && header.ImageSpec.PixelDepth != 16 && header.ImageSpec.PixelDepth != 24 && header.ImageSpec.PixelDepth != 32) throw new ArgumentException("Not a supported tga file."); if (header.ImageSpec.AlphaBits > 8) throw new ArgumentException("Not a supported tga file."); if (header.ImageSpec.Width > 4096 || header.ImageSpec.Height > 4096) throw new ArgumentException("Image too large."); byte[] decoded = new byte[header.ImageSpec.Width * header.ImageSpec.Height * 4]; System.Drawing.Imaging.BitmapData bd = new System.Drawing.Imaging.BitmapData(); fixed (byte* pdecoded = &decoded[0]) { bd.Width = header.ImageSpec.Width; bd.Height = header.ImageSpec.Height; bd.PixelFormat = System.Drawing.Imaging.PixelFormat.Format32bppPArgb; bd.Stride = header.ImageSpec.Width * 4; bd.Scan0 = (IntPtr)pdecoded; switch (header.ImageSpec.PixelDepth) { case 8: decodeStandard8(bd, header, br); break; case 16: if (header.ImageSpec.AlphaBits > 0) decodeSpecial16(bd, header, br); else decodeStandard16(bd, header, br); break; case 24: if (header.ImageSpec.AlphaBits > 0) decodeSpecial24(bd, header, br); else decodeStandard24(bd, header, br); break; case 32: decodeStandard32(bd, header, br); break; default: return null; } } int n = header.ImageSpec.Width * header.ImageSpec.Height; ManagedImage image; if (mask && header.ImageSpec.AlphaBits == 0 && header.ImageSpec.PixelDepth == 8) { image = new ManagedImage(header.ImageSpec.Width, header.ImageSpec.Height, ManagedImage.ImageChannels.Alpha); int p = 3; for (int i = 0; i < n; i++) { image.Alpha[i] = decoded[p]; p += 4; } } else { image = new ManagedImage(header.ImageSpec.Width, header.ImageSpec.Height, ManagedImage.ImageChannels.Color | ManagedImage.ImageChannels.Alpha); int p = 0; for (int i = 0; i < n; i++) { image.Blue[i] = decoded[p++]; image.Green[i] = decoded[p++]; image.Red[i] = decoded[p++]; image.Alpha[i] = decoded[p++]; } } br.Close(); return image; } }
/// <summary> /// Make sure images exist, resize source if needed to match the destination /// </summary> /// <param name="dest">Destination image</param> /// <param name="src">Source image</param> /// <returns>Sanitization was succefull</returns> private bool SanitizeLayers(ManagedImage dest, ManagedImage src) { if (dest == null || src == null) return false; if ((dest.Channels & ManagedImage.ImageChannels.Alpha) == 0) { dest.ConvertChannels(dest.Channels | ManagedImage.ImageChannels.Alpha); } if (dest.Width != src.Width || dest.Height != src.Height) { try { src.ResizeNearestNeighbor(dest.Width, dest.Height); } catch (Exception) { return false; } } return true; }
public static unsafe ManagedImage LoadTGAImage(System.IO.Stream source, bool mask) { byte[] buffer = new byte[source.Length]; source.Read(buffer, 0, buffer.Length); System.IO.MemoryStream ms = new System.IO.MemoryStream(buffer); using (System.IO.BinaryReader br = new System.IO.BinaryReader(ms)) { tgaHeader header = new tgaHeader(); header.Read(br); if (header.ImageSpec.PixelDepth != 8 && header.ImageSpec.PixelDepth != 16 && header.ImageSpec.PixelDepth != 24 && header.ImageSpec.PixelDepth != 32) { throw new ArgumentException("Not a supported tga file."); } if (header.ImageSpec.AlphaBits > 8) { throw new ArgumentException("Not a supported tga file."); } if (header.ImageSpec.Width > 4096 || header.ImageSpec.Height > 4096) { throw new ArgumentException("Image too large."); } byte[] decoded = new byte[header.ImageSpec.Width * header.ImageSpec.Height * 4]; System.Drawing.Imaging.BitmapData bd = new System.Drawing.Imaging.BitmapData(); fixed(byte *pdecoded = &decoded[0]) { bd.Width = header.ImageSpec.Width; bd.Height = header.ImageSpec.Height; bd.PixelFormat = System.Drawing.Imaging.PixelFormat.Format32bppPArgb; bd.Stride = header.ImageSpec.Width * 4; bd.Scan0 = (IntPtr)pdecoded; switch (header.ImageSpec.PixelDepth) { case 8: decodeStandard8(bd, header, br); break; case 16: if (header.ImageSpec.AlphaBits > 0) { decodeSpecial16(bd, header, br); } else { decodeStandard16(bd, header, br); } break; case 24: if (header.ImageSpec.AlphaBits > 0) { decodeSpecial24(bd, header, br); } else { decodeStandard24(bd, header, br); } break; case 32: decodeStandard32(bd, header, br); break; default: return(null); } } int n = header.ImageSpec.Width * header.ImageSpec.Height; ManagedImage image; if (mask && header.ImageSpec.AlphaBits == 0 && header.ImageSpec.PixelDepth == 8) { image = new ManagedImage(header.ImageSpec.Width, header.ImageSpec.Height, ManagedImage.ImageChannels.Alpha); int p = 3; for (int i = 0; i < n; i++) { image.Alpha[i] = decoded[p]; p += 4; } } else { image = new ManagedImage(header.ImageSpec.Width, header.ImageSpec.Height, ManagedImage.ImageChannels.Color | ManagedImage.ImageChannels.Alpha); int p = 0; for (int i = 0; i < n; i++) { image.Blue[i] = decoded[p++]; image.Green[i] = decoded[p++]; image.Red[i] = decoded[p++]; image.Alpha[i] = decoded[p++]; } } br.Close(); return(image); } }