private warp_Texture GetTexture(UUID id) { warp_Texture ret = null; byte[] asset = m_scene.AssetService.GetData(id.ToString()); if (asset != null) { IJ2KDecoder imgDecoder = m_scene.RequestModuleInterface <IJ2KDecoder>(); try { using (Bitmap img = (Bitmap)imgDecoder.DecodeToImage(asset)) { ret = new warp_Texture(img); img.Dispose(); } } catch (Exception e) { m_log.Warn(string.Format("[WARP 3D IMAGE MODULE]: Failed to decode asset {0}, exception ", id), e); } } return(ret); }
warp_Texture GetTexture(UUID id) { warp_Texture ret = null; if (id == UUID.Zero) { id = (UUID)Constants.MISSING_TEXTURE_ID; } byte [] assetData = m_scene.AssetService.GetData(id.ToString(), false); // suppress warnings here if (assetData == null || assetData.Length == 0) { assetData = m_scene.AssetService.GetData(Constants.MISSING_TEXTURE_ID); // not found, replace with something identifable } if (assetData != null && assetData.Length > 0) { IJ2KDecoder imgDecoder = m_scene.RequestModuleInterface <IJ2KDecoder> (); Bitmap img = (Bitmap)imgDecoder.DecodeToImage(assetData); if (img != null) { ret = new warp_Texture(img); img.Dispose(); return(ret); } } MainConsole.Instance.Debug("[WarpTile generator]: Gettexture returning null, asset id: " + id); return(ret); }
private byte[] ConvertTextureData(AssetBase texture, string format) { MainConsole.Instance.DebugFormat("[GETTEXTURE]: Converting texture {0} to {1}", texture.ID, format); byte[] data = new byte[0]; MemoryStream imgstream = new MemoryStream(); Image image = null; try { // Taking our jpeg2000 data, decoding it, then saving it to a byte array with regular data image = m_j2kDecoder.DecodeToImage(texture.Data); if (image == null) { return(data); } // Save to bitmap image = new Bitmap(image); EncoderParameters myEncoderParameters = new EncoderParameters(); myEncoderParameters.Param[0] = new EncoderParameter(Encoder.Quality, 95L); // Save bitmap to stream ImageCodecInfo codec = GetEncoderInfo("image/" + format); if (codec != null) { image.Save(imgstream, codec, myEncoderParameters); // Write the stream to a byte array for output data = imgstream.ToArray(); } else { MainConsole.Instance.WarnFormat("[GETTEXTURE]: No such codec {0}", format); } } catch (Exception e) { MainConsole.Instance.WarnFormat("[GETTEXTURE]: Unable to convert texture {0} to {1}: {2}", texture.ID, format, e.Message); } finally { // Reclaim memory, these are unmanaged resources // If we encountered an exception, one or more of these will be null if (image != null) { image.Dispose(); } image = null; imgstream.Close(); imgstream = null; } return(data); }
private warp_Texture GetTexture(UUID id) { warp_Texture ret = null; byte[] asset = m_scene.AssetService.GetData(id.ToString()); if (asset != null) { IJ2KDecoder imgDecoder = m_scene.RequestModuleInterface <IJ2KDecoder>(); Bitmap img = (Bitmap)imgDecoder.DecodeToImage(asset); if (img != null) { return(new warp_Texture(img)); } } return(ret); }
private warp_Texture GetTexture(UUID id) { warp_Texture ret = null; AssetBase asset = m_scene.AssetService.Get(id.ToString()); if (asset != null) { IJ2KDecoder imgDecoder = m_scene.RequestModuleInterface <IJ2KDecoder>(); Bitmap img = (Bitmap)imgDecoder.DecodeToImage(asset.Data); if (img != null) { ret = new warp_Texture(img); img.Dispose(); } asset.Dispose(); } return(ret); }
public Image GetTexture(UUID TextureID) { if (TextureID == UUID.Zero) //Send white instead of null { TextureID = Util.BLANK_TEXTURE_UUID; } byte[] asset = m_assetService.GetData(TextureID.ToString()); if (asset == null || m_decoder == null) { return(new Bitmap(1, 1)); } Image image = m_decoder.DecodeToImage(asset); if (image != null) { return(image); } else { return(new Bitmap(1, 1)); } }
/// <summary> /// Generate a mesh from the sculpt data the accompanies a prim. /// </summary> /// <param name="primName"></param> /// <param name="primShape"></param> /// <param name="size"></param> /// <param name="lod"></param> /// <param name="key"></param> /// <returns>created mesh or null if invalid</returns> Mesh GenerateFromPrimSculptData(string primName, PrimitiveBaseShape primShape, Vector3 size, float lod, ulong key) { SculptMesh sculptMesh; Image idata = null; string decodedSculptFileName = ""; if (cacheSculptMaps && primShape.SculptTexture != UUID.Zero) { decodedSculptFileName = System.IO.Path.Combine(decodedSculptMapPath, "smap_" + primShape.SculptTexture); try { if (File.Exists(decodedSculptFileName)) { idata = Image.FromFile(decodedSculptFileName); } } catch (Exception e) { MainConsole.Instance.Error("[Sculpt]: unable to load cached sculpt map " + decodedSculptFileName + " " + e); } //if (idata != null) // MainConsole.Instance.Debug("[SCULPT]: loaded cached map asset for map ID: " + primShape.SculptTexture.ToString()); } if (idata == null) { if (primShape.SculptData == null || primShape.SculptData.Length == 0) { return(null); } try { idata = m_j2kDecoder.DecodeToImage(primShape.SculptData); if (idata != null && cacheSculptMaps && (cacheSculptAlphaMaps || (((ImageFlags)(idata.Flags) & ImageFlags.HasAlpha) == 0))) { try { idata.Save(decodedSculptFileName, ImageFormat.MemoryBmp); } catch (Exception e) { MainConsole.Instance.Error("[Sculpt]: unable to cache sculpt map " + decodedSculptFileName + " " + e); } } } catch (DllNotFoundException) { MainConsole.Instance.Error( "[Physics]: OpenJpeg is not installed correctly on this system. Physics Proxy generation failed.\n" + "Often times this is because of an old version of GLIBC. You must have version 2.4 or above!"); return(null); } catch (IndexOutOfRangeException) { MainConsole.Instance.Error( "[Physics]: OpenJpeg was unable to decode this. Physics Proxy generation failed"); return(null); } catch (Exception ex) { MainConsole.Instance.Error( "[Physics]: Unable to generate a Sculpty physics proxy. Sculpty texture decode failed: " + ex); return(null); } } SculptMesh.SculptType sculptType; switch ((SculptType)primShape.SculptType) { case SculptType.Cylinder: sculptType = SculptMesh.SculptType.cylinder; break; case SculptType.Plane: sculptType = SculptMesh.SculptType.plane; break; case SculptType.Torus: sculptType = SculptMesh.SculptType.torus; break; case SculptType.Sphere: sculptType = SculptMesh.SculptType.sphere; break; default: sculptType = SculptMesh.SculptType.plane; break; } bool mirror = ((primShape.SculptType & 128) != 0); bool invert = ((primShape.SculptType & 64) != 0); if (idata == null) { return(null); } sculptMesh = new SculptMesh((Bitmap)idata, sculptType, (int)lod, false, mirror, invert); idata.Dispose(); #if SPAM sculptMesh.DumpRaw(baseDir, primName, "primMesh"); #endif sculptMesh.Scale(size.X, size.Y, size.Z); var coords = sculptMesh.coords; var faces = sculptMesh.faces; Mesh mesh = new Mesh(key); mesh.Set(coords, faces); coords.Clear(); faces.Clear(); // debug info only //Console.Write ("S"); return(mesh); }
byte [] ProcessGetTexture(string path, Stream request, OSHttpRequest httpRequest, OSHttpResponse httpResponse) { // MainConsole.Instance.DebugFormat("[GETTEXTURE]: called in {0}", m_scene.RegionInfo.RegionName); // Try to parse the texture ID from the request URL NameValueCollection query = HttpUtility.ParseQueryString(httpRequest.Url.Query); string textureStr = query.GetOne("texture_id"); string format = query.GetOne("format"); if (m_assetService == null) { httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound; return(MainServer.BlankResponse); } UUID textureID; if (!string.IsNullOrEmpty(textureStr) && UUID.TryParse(textureStr, out textureID)) { string [] formats; if (!string.IsNullOrEmpty(format)) { formats = new [] { format.ToLower() } } ; else { formats = WebUtils.GetPreferredImageTypes(httpRequest.Headers.Get("Accept")); if (formats.Length == 0) { formats = new [] { DefaultFormat } } ; // default } // OK, we have an array with preferred formats, possibly with only one entry byte [] response; foreach (string f in formats) { if (FetchTexture(httpRequest, httpResponse, textureID, f, out response)) { return(response); } } } // null or invalid UUID MainConsole.Instance.Warn("[AssetCAPS]: Failed to parse a texture_id from GetTexture request: " + httpRequest.Url); httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound; return(MainServer.BlankResponse); } /// <summary> /// </summary> /// <param name="httpRequest"></param> /// <param name="httpResponse"></param> /// <param name="textureID"></param> /// <param name="format"></param> /// <param name="response"></param> /// <returns>False for "caller try another codec"; true otherwise</returns> bool FetchTexture(OSHttpRequest httpRequest, OSHttpResponse httpResponse, UUID textureID, string format, out byte [] response) { // MainConsole.Instance.DebugFormat("[GETTEXTURE]: {0} with requested format {1}", textureID, format); AssetBase texture; string fullID = textureID.ToString(); if (format != DefaultFormat) { fullID = fullID + "-" + format; } if (!string.IsNullOrEmpty(redirect_URL)) { // Only try to fetch locally cached textures. Misses are redirected texture = m_assetService.GetCached(fullID); if (texture != null) { if (texture.Type != (sbyte)AssetType.Texture && // not actually a texture texture.Type != (sbyte)AssetType.Unknown && // .. but valid texture.Type != (sbyte)AssetType.Simstate) { httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound; response = MainServer.BlankResponse; return(true); } response = WriteTextureData(httpRequest, httpResponse, texture, format); return(true); } string textureUrl = redirect_URL + textureID; MainConsole.Instance.Debug("[AssetCAPS]: Redirecting texture request to " + textureUrl); httpResponse.RedirectLocation = textureUrl; response = MainServer.BlankResponse; return(true); } // no redirect // try the cache texture = m_assetService.GetCached(fullID); if (texture == null) { // MainConsole.Instance.DebugFormat("[Get texture]: texture was not in the cache"); // Fetch locally or remotely. Misses return a 404 texture = m_assetService.Get(textureID.ToString()); if (texture != null) { if (texture.Type != (sbyte)AssetType.Texture && texture.Type != (sbyte)AssetType.Unknown && texture.Type != (sbyte)AssetType.Simstate) { httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound; response = MainServer.BlankResponse; texture.Dispose(); return(true); } if (format == DefaultFormat) { try { response = WriteTextureData(httpRequest, httpResponse, texture, format); } catch { response = MainServer.BlankResponse; } texture.Dispose(); return(true); } AssetBase newTexture = new AssetBase(texture.ID + "-" + format, texture.Name, AssetType.Texture, texture.CreatorID) { Data = ConvertTextureData(texture, format) }; if (newTexture.Data.Length == 0) // unable to convert { response = MainServer.BlankResponse; texture.Dispose(); newTexture.Dispose(); return(false); // !!! Caller try another codec, please! } newTexture.Flags = AssetFlags.Collectable | AssetFlags.Temporary; newTexture.ID = m_assetService.Store(newTexture); try { response = WriteTextureData(httpRequest, httpResponse, newTexture, format); } catch { response = MainServer.BlankResponse; } newTexture.Dispose(); texture.Dispose(); return(true); } // nothing found... replace with the 'missing_texture" texture // try the cache first texture = m_assetService.GetCached(Constants.MISSING_TEXTURE_ID); if (texture == null) { texture = m_assetService.Get(Constants.MISSING_TEXTURE_ID); // not in local cache... } if (texture != null) { if (format == DefaultFormat) { MainConsole.Instance.Debug("[AssetCAPS]: Texture " + textureID + " replaced with default 'missing' texture"); response = WriteTextureData(httpRequest, httpResponse, texture, format); texture.Dispose(); return(true); } } // texture not found and we have no 'missing texture'?? // ... or if all else fails... MainConsole.Instance.Warn("[AssetCAPS]: Texture " + textureID + " not found (no default)"); httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound; response = MainServer.BlankResponse; return(true); } // found the texture in the cache if (texture.Type != (sbyte)AssetType.Texture && texture.Type != (sbyte)AssetType.Unknown && texture.Type != (sbyte)AssetType.Simstate) { httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound; response = MainServer.BlankResponse; return(true); } // the best result... // MainConsole.Instance.DebugFormat("[GETTEXTURE]: texture was in the cache"); response = WriteTextureData(httpRequest, httpResponse, texture, format); return(true); } byte [] WriteTextureData(OSHttpRequest request, OSHttpResponse response, AssetBase texture, string format) { string range = request.Headers.GetOne("Range"); // MainConsole.Instance.DebugFormat("[GETTEXTURE]: Range {0}", range); if (!string.IsNullOrEmpty(range)) // JP2's only { // Range request int start, end; if (TryParseRange(range, out start, out end)) { // Before clamping start make sure we can satisfy it in order to avoid // sending back the last byte instead of an error status if (start >= texture.Data.Length) { response.StatusCode = (int)System.Net.HttpStatusCode.RequestedRangeNotSatisfiable; return(MainServer.BlankResponse); } // Handle the case where portions of the range are missing. if (start == -1) { start = 0; } if (end == -1) { end = int.MaxValue; } end = Utils.Clamp(end, 0, texture.Data.Length - 1); start = Utils.Clamp(start, 0, end); int len = end - start + 1; // MainConsole.Instance.Debug("Serving " + start + " to " + end + " of " + texture.Data.Length + " bytes for texture " + texture.ID); if (len < texture.Data.Length) { response.StatusCode = (int)System.Net.HttpStatusCode.PartialContent; } else { response.StatusCode = (int)System.Net.HttpStatusCode.OK; } response.ContentType = texture.TypeString; response.AddHeader("Content-Range", string.Format("bytes {0}-{1}/{2}", start, end, texture.Data.Length)); byte [] array = new byte [len]; Array.Copy(texture.Data, start, array, 0, len); return(array); } MainConsole.Instance.Warn("[AssetCAPS]: Malformed Range header: " + range); response.StatusCode = (int)System.Net.HttpStatusCode.BadRequest; return(MainServer.BlankResponse); } // Full content request response.StatusCode = (int)System.Net.HttpStatusCode.OK; response.ContentType = texture.TypeString; if (format == DefaultFormat) { response.ContentType = texture.TypeString; } else { response.ContentType = "image/" + format; } return(texture.Data); } /* * <summary> * Parse a range header. * </summary> * <remarks> * As per http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html, * this obeys range headers with two values (e.g. 533-4165) and no second value (e.g. 533-). * Where there is no value, -1 is returned. Also handles a range like (-4165) where -1 is * returned for the starting value.</remarks> * <returns></returns> * <param name='header'></param> * <param name='start'>Undefined if the parse fails.</param> * <param name='end'>Undefined if the parse fails.</param> */ bool TryParseRange(string header, out int start, out int end) { start = end = -1; if (!header.StartsWith("bytes=", StringComparison.Ordinal)) { return(false); } string [] rangeValues = header.Substring(6).Split('-'); if (rangeValues.Length != 2) { return(false); } if (rangeValues [0] != "") { if (!int.TryParse(rangeValues [0], out start)) { return(false); } } if (rangeValues [1] != "") { if (!int.TryParse(rangeValues [1], out end)) { return(false); } } return(true); } byte [] ConvertTextureData(AssetBase texture, string format) { MainConsole.Instance.DebugFormat("[AssetCAPS]: Converting texture {0} to {1}", texture.ID, format); byte [] data = new byte [0]; MemoryStream imgstream = new MemoryStream(); Image image = null; try { // Taking our jpeg2000 data, decoding it, then saving it to a byte array with regular data image = m_j2kDecoder.DecodeToImage(texture.Data); if (image == null) { return(data); } // Save to bitmap image = new Bitmap(image); EncoderParameters myEncoderParameters = new EncoderParameters(); myEncoderParameters.Param [0] = new EncoderParameter(Encoder.Quality, 95L); // Save bitmap to stream try { ImageCodecInfo codec = GetEncoderInfo("image/" + format); if (codec != null) { image.Save(imgstream, codec, myEncoderParameters); // Write the stream to a byte array for output data = imgstream.ToArray(); } else { MainConsole.Instance.WarnFormat("[AssetCAPS]: No such codec {0}", format); } } catch { MainConsole.Instance.ErrorFormat("[AssetCAPS]: Unable to retrieve codec {0}", format); } myEncoderParameters.Dispose(); } catch (Exception e) { MainConsole.Instance.WarnFormat("[AssetCAPS]: Unable to convert texture {0} to {1}: {2}", texture.ID, format, e.Message); } finally { // Reclaim memory, these are unmanaged resources // If we encountered an exception, one or more of these will be null if (image != null) { image.Dispose(); } imgstream.Close(); } return(data); }
Bitmap BuildMapTile(int regionX, int regionY, List <GridRegion> regions) { if (regions == null) { int maxRegionSize = m_gridService.GetMaxRegionSize(); if (maxRegionSize == 0) { maxRegionSize = Constants.MaxRegionSize; } regions = m_gridService.GetRegionRange( null, (regionX * Constants.RegionSize) - maxRegionSize, (regionX * Constants.RegionSize) + maxRegionSize, (regionY * Constants.RegionSize) - maxRegionSize, (regionY * Constants.RegionSize) + maxRegionSize); } List <Image> bitImages = new List <Image>(); List <GridRegion> badRegions = new List <GridRegion>(); Rectangle mapRect = new Rectangle(regionX * Constants.RegionSize, regionY * Constants.RegionSize, Constants.RegionSize, Constants.RegionSize); foreach (GridRegion r in regions) { Rectangle regionRect = new Rectangle(r.RegionLocX, r.RegionLocY, r.RegionSizeX, r.RegionSizeY); if (!mapRect.IntersectsWith(regionRect)) { badRegions.Add(r); } } foreach (GridRegion r in badRegions) { regions.Remove(r); } badRegions.Clear(); IJ2KDecoder decoder = m_registry.RequestModuleInterface <IJ2KDecoder>(); foreach (GridRegion r in regions) { byte[] texAsset = null; if (m_assetService.GetExists(r.TerrainMapImage.ToString())) { texAsset = m_assetService.GetData(r.TerrainMapImage.ToString()); } if (texAsset != null) { Image image = decoder.DecodeToImage(texAsset); if (image != null) { bitImages.Add(image); } else { badRegions.Add(r); } } else { badRegions.Add(r); } } foreach (GridRegion r in badRegions) { regions.Remove(r); } if (regions.Count == 0) { lock (m_blankTiles.BlankTiles) m_blankTiles.BlankTiles.Add(Util.IntsToUlong(regionX, regionY)); return(m_blankRegionTile); } const int SizeOfImage = Constants.RegionSize; // 256 Bitmap mapTexture = new Bitmap(SizeOfImage, SizeOfImage); using (Graphics g = Graphics.FromImage(mapTexture)) { SolidBrush sea = new SolidBrush(Color.FromArgb(29, 71, 95)); g.FillRectangle(sea, 0, 0, SizeOfImage, SizeOfImage); for (int i = 0; i < regions.Count; i++) { //Find the offsets first float x = (regions[i].RegionLocX - (regionX * (float)Constants.RegionSize)) / Constants.RegionSize; float y = (regions[i].RegionLocY - (regionY * (float)Constants.RegionSize)) / Constants.RegionSize; y += (regions[i].RegionSizeY - Constants.RegionSize) / Constants.RegionSize; float xx = (x * (SizeOfImage)); float yy = SizeOfImage - (y * (SizeOfImage) + (SizeOfImage)); g.DrawImage(bitImages[i], xx, yy, (int)(SizeOfImage * ((float)regions[i].RegionSizeX / Constants.RegionSize)), (int)(SizeOfImage * (regions[i].RegionSizeY / (float)Constants.RegionSize))); // y origin is top } } foreach (var bmp in bitImages) { bmp.Dispose(); } CacheMapTexture(1, regionX, regionY, mapTexture); //mapTexture = ResizeBitmap(mapTexture, 128, 128); return(mapTexture); }
public byte[] MapRequest(string path, Stream request, OSHttpRequest httpRequest, OSHttpResponse httpResponse) { //Remove the /MapService/ string uri = httpRequest.RawUrl.Remove(0, 12); if (!uri.StartsWith("map", StringComparison.Ordinal)) { if (uri == "") { string resp = "<ListBucketResult xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\">" + "<Name>map.secondlife.com</Name>" + "<Prefix/>" + "<Marker/>" + "<MaxKeys>1000</MaxKeys>" + "<IsTruncated>true</IsTruncated>"; // TODO: Why specific (was 1000)? Assumes the center of the map is here. // Should this be relative to the view?? i.e a passed map center location var txSize = m_mapcenter_x * Constants.RegionSize; var tySize = m_mapcenter_x * Constants.RegionSize; var etSize = 8 * Constants.RegionSize; List <GridRegion> regions = m_gridService.GetRegionRange( null, (txSize - etSize), (txSize + etSize), (tySize - etSize), (tySize + etSize)); foreach (var region in regions) { resp += "<Contents><Key>map-1-" + region.RegionLocX / Constants.RegionSize + "-" + region.RegionLocY / Constants.RegionSize + "-objects.jpg</Key>" + "<LastModified>2012-07-09T21:26:32.000Z</LastModified></Contents>"; } resp += "</ListBucketResult>"; httpResponse.ContentType = "application/xml"; return(System.Text.Encoding.UTF8.GetBytes(resp)); } using (MemoryStream imgstream = new MemoryStream()) { GridRegion region = m_gridService.GetRegionByName(null, uri.Remove(4)); if (region == null) { region = m_gridService.GetRegionByUUID(null, OpenMetaverse.UUID.Parse(uri.Remove(uri.Length - 4))); } // non-async because we know we have the asset immediately. byte[] mapasset = null; if (m_assetService.GetExists(region.TerrainMapImage.ToString())) { mapasset = m_assetService.GetData(region.TerrainMapImage.ToString()); } if (mapasset != null) { try { Image image = m_j2kDecoder.DecodeToImage(mapasset); if (image == null) { return(new byte[0]); } // Decode image to System.Drawing.Image EncoderParameters myEncoderParameters = new EncoderParameters(); myEncoderParameters.Param[0] = new EncoderParameter(Encoder.Quality, 95L); var encInfo = GetEncoderInfo("image/jpeg"); if (encInfo != null) { // Save bitmap to stream image.Save(imgstream, encInfo, myEncoderParameters); } image.Dispose(); myEncoderParameters.Dispose(); // Write the stream to a byte array for output return(imgstream.ToArray()); } catch { } } } return(new byte[0]); } string[] splitUri = uri.Split('-'); byte[] jpeg = FindCachedImage(uri); if (jpeg.Length != 0) { httpResponse.ContentType = "image/jpeg"; return(jpeg); } try { int mapLayer = int.Parse(uri.Substring(4, 1)); int regionX = int.Parse(splitUri[2]); int regionY = int.Parse(splitUri[3]); int distance = (int)Math.Pow(2, mapLayer); int maxRegionSize = m_gridService.GetMaxRegionSize(); if (maxRegionSize == 0) { maxRegionSize = Constants.MaxRegionSize; } List <GridRegion> regions = m_gridService.GetRegionRange( null, ((regionX) * Constants.RegionSize) - maxRegionSize, ((regionX + distance) * Constants.RegionSize) + maxRegionSize, ((regionY) * Constants.RegionSize) - maxRegionSize, ((regionY + distance) * Constants.RegionSize) + maxRegionSize); Bitmap mapTexture = BuildMapTile(mapLayer, regionX, regionY, regions); jpeg = CacheMapTexture(mapLayer, regionX, regionY, mapTexture); DisposeTexture(mapTexture); } catch { } httpResponse.ContentType = "image/jpeg"; return(jpeg); }
/// <summary> /// Builds a composited terrain texture given the region texture /// and heightmap settings /// </summary> /// <param name="terrain">Terrain heightmap</param> /// <param name="regionInfo">Region information including terrain texture parameters</param> /// <returns>A 256x256 square RGB texture ready for rendering</returns> /// <remarks>Based on the algorithm described at http://opensimulator.org/wiki/Terrain_Splatting /// Note we create a 256x256 dimension texture even if the actual terrain is larger. /// </remarks> public static Bitmap Splat(ITerrainChannel terrain, UUID[] textureIDs, float[] startHeights, float[] heightRanges, uint regionPositionX, uint regionPositionY, IAssetService assetService, IJ2KDecoder decoder, bool textureTerrain, bool averagetextureTerrain, int twidth, int theight) { Debug.Assert(textureIDs.Length == 4); Debug.Assert(startHeights.Length == 4); Debug.Assert(heightRanges.Length == 4); Bitmap[] detailTexture = new Bitmap[4]; byte[] mapColorsRed = new byte[4]; byte[] mapColorsGreen = new byte[4]; byte[] mapColorsBlue = new byte[4]; bool usecolors = false; if (textureTerrain) { // 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 if (assetService != null) { for (int i = 0; i < 4; i++) { AssetBase asset = null; // asset cache indexes are strings string cacheName = "MAP" + textureIDs[i].ToString(); // Try to fetch a cached copy of the decoded/resized version of this texture asset = assetService.GetCached(cacheName); if (asset != null) { try { using (System.IO.MemoryStream stream = new System.IO.MemoryStream(asset.Data)) detailTexture[i] = (Bitmap)Image.FromStream(stream); if (detailTexture[i].PixelFormat != PixelFormat.Format24bppRgb || detailTexture[i].Width != 16 || detailTexture[i].Height != 16) { detailTexture[i].Dispose(); detailTexture[i] = null; } } catch (Exception ex) { m_log.Warn("Failed to decode cached terrain patch texture" + textureIDs[i] + "): " + ex.Message); } } if (detailTexture[i] == null) { // Try to fetch the original JPEG2000 texture, resize if needed, and cache as PNG asset = assetService.Get(textureIDs[i].ToString()); if (asset != null) { try { detailTexture[i] = (Bitmap)decoder.DecodeToImage(asset.Data); } catch (Exception ex) { m_log.Warn("Failed to decode terrain texture " + asset.ID + ": " + ex.Message); } } if (detailTexture[i] != null) { if (detailTexture[i].PixelFormat != PixelFormat.Format24bppRgb || detailTexture[i].Width != 16 || detailTexture[i].Height != 16) { using (Bitmap origBitmap = detailTexture[i]) detailTexture[i] = Util.ResizeImageSolid(origBitmap, 16, 16); } // Save the decoded and resized texture to the cache byte[] data; using (System.IO.MemoryStream stream = new System.IO.MemoryStream()) { detailTexture[i].Save(stream, ImageFormat.Png); data = stream.ToArray(); } // Cache a PNG copy of this terrain texture AssetBase newAsset = new AssetBase { Data = data, Description = "PNG", Flags = AssetFlags.Collectable, FullID = UUID.Zero, ID = cacheName, Local = true, Name = String.Empty, Temporary = true, Type = (sbyte)AssetType.Unknown }; newAsset.Metadata.ContentType = "image/png"; assetService.Store(newAsset); } } } } #endregion Texture Fetching if (averagetextureTerrain) { for (int t = 0; t < 4; t++) { usecolors = true; if (detailTexture[t] == null) { mapColorsRed[t] = DEFAULT_TERRAIN_COLOR[t].R; mapColorsGreen[t] = DEFAULT_TERRAIN_COLOR[t].G; mapColorsBlue[t] = DEFAULT_TERRAIN_COLOR[t].B; continue; } int npixeis = 0; int cR = 0; int cG = 0; int cB = 0; BitmapData bmdata = detailTexture[t].LockBits(new Rectangle(0, 0, 16, 16), ImageLockMode.ReadOnly, detailTexture[t].PixelFormat); npixeis = bmdata.Height * bmdata.Width; int ylen = bmdata.Height * bmdata.Stride; unsafe { for (int y = 0; y < ylen; y += bmdata.Stride) { byte *ptrc = (byte *)bmdata.Scan0 + y; for (int x = 0; x < bmdata.Width; ++x) { cR += *(ptrc++); cG += *(ptrc++); cB += *(ptrc++); } } } detailTexture[t].UnlockBits(bmdata); detailTexture[t].Dispose(); mapColorsRed[t] = (byte)Util.Clamp(cR / npixeis, 0, 255); mapColorsGreen[t] = (byte)Util.Clamp(cG / npixeis, 0, 255); mapColorsBlue[t] = (byte)Util.Clamp(cB / npixeis, 0, 255); } } else { // Fill in any missing textures with a solid color for (int i = 0; i < 4; i++) { if (detailTexture[i] == null) { m_log.DebugFormat("{0} Missing terrain texture for layer {1}. Filling with solid default color", LogHeader, i); // Create a solid color texture for this layer detailTexture[i] = new Bitmap(16, 16, PixelFormat.Format24bppRgb); using (Graphics gfx = Graphics.FromImage(detailTexture[i])) { using (SolidBrush brush = new SolidBrush(DEFAULT_TERRAIN_COLOR[i])) gfx.FillRectangle(brush, 0, 0, 16, 16); } } else { if (detailTexture[i].Width != 16 || detailTexture[i].Height != 16) { using (Bitmap origBitmap = detailTexture[i]) detailTexture[i] = Util.ResizeImageSolid(origBitmap, 16, 16); } } } } } else { usecolors = true; for (int t = 0; t < 4; t++) { mapColorsRed[t] = DEFAULT_TERRAIN_COLOR[t].R; mapColorsGreen[t] = DEFAULT_TERRAIN_COLOR[t].G; mapColorsBlue[t] = DEFAULT_TERRAIN_COLOR[t].B; } } #region Layer Map float xFactor = terrain.Width / twidth; float yFactor = terrain.Height / theight; #endregion Layer Map #region Texture Compositing Bitmap output = new Bitmap(twidth, theight, PixelFormat.Format24bppRgb); BitmapData outputData = output.LockBits(new Rectangle(0, 0, twidth, theight), ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb); // Unsafe work as we lock down the source textures for quicker access and access the // pixel data directly float invtwitdthMinus1 = 1.0f / (twidth - 1); float invtheightMinus1 = 1.0f / (theight - 1); int ty; int tx; float pctx; float pcty; float height; float layer; float layerDiff; int l0; int l1; uint yglobalpos; if (usecolors) { float a; float b; unsafe { byte *ptrO; for (int y = 0; y < theight; ++y) { pcty = y * invtheightMinus1; ptrO = (byte *)outputData.Scan0 + y * outputData.Stride; ty = (int)(y * yFactor); yglobalpos = (uint)ty + regionPositionY; for (int x = 0; x < twidth; ++x) { tx = (int)(x * xFactor); pctx = x * invtwitdthMinus1; height = (float)terrain[tx, ty]; layer = getLayerTex(height, pctx, pcty, (uint)tx + regionPositionX, yglobalpos, startHeights, heightRanges); // Select two textures l0 = (int)layer; l1 = Math.Min(l0 + 1, 3); layerDiff = layer - l0; a = mapColorsRed[l0]; b = mapColorsRed[l1]; *(ptrO++) = (byte)(a + layerDiff * (b - a)); a = mapColorsGreen[l0]; b = mapColorsGreen[l1]; *(ptrO++) = (byte)(a + layerDiff * (b - a)); a = mapColorsBlue[l0]; b = mapColorsBlue[l1]; *(ptrO++) = (byte)(a + layerDiff * (b - a)); } } } } else { float aB; float aG; float aR; float bB; float bG; float bR; unsafe { // Get handles to all of the texture data arrays BitmapData[] datas = new BitmapData[] { detailTexture[0].LockBits(new Rectangle(0, 0, 16, 16), ImageLockMode.ReadOnly, detailTexture[0].PixelFormat), detailTexture[1].LockBits(new Rectangle(0, 0, 16, 16), ImageLockMode.ReadOnly, detailTexture[1].PixelFormat), detailTexture[2].LockBits(new Rectangle(0, 0, 16, 16), ImageLockMode.ReadOnly, detailTexture[2].PixelFormat), detailTexture[3].LockBits(new Rectangle(0, 0, 16, 16), ImageLockMode.ReadOnly, detailTexture[3].PixelFormat) }; byte *ptr; byte *ptrO; for (int y = 0; y < theight; y++) { pcty = y * invtheightMinus1; int ypatch = ((int)(y * yFactor) & 0x0f) * datas[0].Stride; ptrO = (byte *)outputData.Scan0 + y * outputData.Stride; ty = (int)(y * yFactor); yglobalpos = (uint)ty + regionPositionY; for (int x = 0; x < twidth; x++) { tx = (int)(x * xFactor); pctx = x * invtwitdthMinus1; height = (float)terrain[tx, ty]; layer = getLayerTex(height, pctx, pcty, (uint)tx + regionPositionX, yglobalpos, startHeights, heightRanges); // Select two textures l0 = (int)layer; layerDiff = layer - l0; int patchOffset = (tx & 0x0f) * 3 + ypatch; ptr = (byte *)datas[l0].Scan0 + patchOffset; aB = *(ptr++); aG = *(ptr++); aR = *(ptr); l1 = Math.Min(l0 + 1, 3); ptr = (byte *)datas[l1].Scan0 + patchOffset; bB = *(ptr++); bG = *(ptr++); bR = *(ptr); // Interpolate between the two selected textures *(ptrO++) = (byte)(aB + layerDiff * (bB - aB)); *(ptrO++) = (byte)(aG + layerDiff * (bG - aG)); *(ptrO++) = (byte)(aR + layerDiff * (bR - aR)); } } for (int i = 0; i < detailTexture.Length; i++) { detailTexture[i].UnlockBits(datas[i]); } } for (int i = 0; i < detailTexture.Length; i++) { if (detailTexture[i] != null) { detailTexture[i].Dispose(); } } } output.UnlockBits(outputData); //output.Save("terr.png",ImageFormat.Png); #endregion Texture Compositing return(output); }
void CreatePrim(WarpRenderer renderer, ISceneChildEntity prim, bool texturePrims) { try { if ((PCode)prim.Shape.PCode != PCode.Prim) { return; } if (prim.Scale.LengthSquared() < MIN_PRIM_SIZE * MIN_PRIM_SIZE) { return; } Primitive omvPrim = prim.Shape.ToOmvPrimitive(prim.OffsetPosition, prim.GetRotationOffset()); FacetedMesh renderMesh = null; // Are we dealing with a sculptie or mesh? if (omvPrim.Sculpt != null && omvPrim.Sculpt.SculptTexture != UUID.Zero) { // Try fetching the asset byte [] sculptAsset = m_scene.AssetService.GetData(omvPrim.Sculpt.SculptTexture.ToString()); if (sculptAsset != null) { // Is it a mesh? if (omvPrim.Sculpt.Type == SculptType.Mesh) { AssetMesh meshAsset = new AssetMesh(omvPrim.Sculpt.SculptTexture, sculptAsset); FacetedMesh.TryDecodeFromAsset(omvPrim, meshAsset, DetailLevel.Highest, out renderMesh); meshAsset = null; } else // It's sculptie { Image sculpt = m_imgDecoder.DecodeToImage(sculptAsset); if (sculpt != null) { renderMesh = m_primMesher.GenerateFacetedSculptMesh(omvPrim, (Bitmap)sculpt, DetailLevel.Medium); sculpt.Dispose(); } } sculptAsset = null; } else { // missing sculpt data... replace with something renderMesh = m_primMesher.GenerateFacetedMesh(omvPrim, DetailLevel.Medium); } } else // Prim { renderMesh = m_primMesher.GenerateFacetedMesh(omvPrim, DetailLevel.Medium); } if (renderMesh == null) { return; } warp_Vector primPos = ConvertVector(prim.GetWorldPosition()); warp_Quaternion primRot = ConvertQuaternion(prim.GetRotationOffset()); warp_Matrix m = warp_Matrix.quaternionMatrix(primRot); if (prim.ParentID != 0) { ISceneEntity group = m_scene.GetGroupByPrim(prim.LocalId); if (group != null) { m.transform(warp_Matrix.quaternionMatrix(ConvertQuaternion(group.RootChild.GetRotationOffset()))); } } warp_Vector primScale = ConvertVector(prim.Scale); string primID = prim.UUID.ToString(); // Create the prim faces for (int i = 0; i < renderMesh.Faces.Count; i++) { Face renderFace = renderMesh.Faces [i]; string meshName = primID + "-Face-" + i; warp_Object faceObj = new warp_Object(renderFace.Vertices.Count, renderFace.Indices.Count / 3); foreach (Vertex v in renderFace.Vertices) { warp_Vector pos = ConvertVector(v.Position); warp_Vector norm = ConvertVector(v.Normal); if (prim.Shape.SculptTexture == UUID.Zero) { norm = norm.reverse(); } warp_Vertex vert = new warp_Vertex(pos, norm, v.TexCoord.X, v.TexCoord.Y); faceObj.addVertex(vert); } for (int j = 0; j < renderFace.Indices.Count;) { faceObj.addTriangle( renderFace.Indices [j++], renderFace.Indices [j++], renderFace.Indices [j++]); } Primitive.TextureEntryFace teFace = prim.Shape.Textures.GetFace((uint)i); string materialName; Color4 faceColor = GetFaceColor(teFace); if (texturePrims && (prim.Scale.LengthSquared() > m_texturePrimSize)) { materialName = GetOrCreateMaterial(renderer, faceColor, teFace.TextureID); } else { materialName = GetOrCreateMaterial(renderer, faceColor); } faceObj.transform(m); faceObj.setPos(primPos); faceObj.scaleSelf(primScale.x, primScale.y, primScale.z); renderer.Scene.addObject(meshName, faceObj); renderer.SetObjectMaterial(meshName, materialName); faceObj = null; } renderMesh.Faces.Clear(); renderMesh = null; } catch (Exception ex) { MainConsole.Instance.Warn("[WarpTile generator]: Exception creating prim, " + ex); } }
private Mesh CreateMeshFromPrimMesher(string primName, PrimitiveBaseShape primShape, Vector3 size, float lod, ulong key) { PrimMesh primMesh; SculptMesh sculptMesh; List <Coord> coords = new List <Coord>(); List <Face> faces = new List <Face>(); Image idata = null; string decodedSculptFileName = ""; if (primShape.SculptEntry) { if (((SculptType)primShape.SculptType & SculptType.Mesh) == SculptType.Mesh) { if (!UseMeshesPhysicsMesh) { return(null); } MainConsole.Instance.Debug("[MESH]: experimental mesh proxy generation"); OSD meshOsd = null; if (primShape.SculptData == null || primShape.SculptData.Length <= 0) { //MainConsole.Instance.Error("[MESH]: asset data is zero length"); return(null); } long start = 0; using (MemoryStream data = new MemoryStream(primShape.SculptData)) { try { meshOsd = OSDParser.DeserializeLLSDBinary(data); } catch (Exception e) { MainConsole.Instance.Error("[MESH]: Exception deserializing mesh asset header:" + e); } start = data.Position; } if (meshOsd is OSDMap) { OSDMap map = (OSDMap)meshOsd; OSDMap physicsParms = new OSDMap(); if (map.ContainsKey("physics_cached")) { OSD cachedMeshMap = map["physics_cached"]; // cached data from Aurora Mesh cachedMesh = new Mesh(key); cachedMesh.Deserialize(cachedMeshMap); cachedMesh.WasCached = true; return(cachedMesh); //Return here, we found all of the info right here } if (map.ContainsKey("physics_shape")) { physicsParms = (OSDMap)map["physics_shape"]; // old asset format } if (physicsParms.Count == 0 && map.ContainsKey("physics_mesh")) { physicsParms = (OSDMap)map["physics_mesh"]; // new asset format } if (physicsParms.Count == 0 && map.ContainsKey("physics_convex")) { // convex hull format, which we can't read, so instead // read the highest lod that exists, and use it instead physicsParms = (OSDMap)map["high_lod"]; } int physOffset = physicsParms["offset"].AsInteger() + (int)start; int physSize = physicsParms["size"].AsInteger(); if (physOffset < 0 || physSize == 0) { return(null); // no mesh data in asset } OSD decodedMeshOsd = new OSD(); byte[] meshBytes = new byte[physSize]; Buffer.BlockCopy(primShape.SculptData, physOffset, meshBytes, 0, physSize); try { using (MemoryStream inMs = new MemoryStream(meshBytes)) { using (MemoryStream outMs = new MemoryStream()) { using (ZOutputStream zOut = new ZOutputStream(outMs)) { byte[] readBuffer = new byte[2048]; int readLen = 0; while ((readLen = inMs.Read(readBuffer, 0, readBuffer.Length)) > 0) { zOut.Write(readBuffer, 0, readLen); } zOut.Flush(); outMs.Seek(0, SeekOrigin.Begin); byte[] decompressedBuf = outMs.GetBuffer(); decodedMeshOsd = OSDParser.DeserializeLLSDBinary(decompressedBuf); } } } } catch (Exception e) { MainConsole.Instance.Error("[MESH]: exception decoding physical mesh: " + e); return(null); } OSDArray decodedMeshOsdArray = null; // physics_shape is an array of OSDMaps, one for each submesh if (decodedMeshOsd is OSDArray) { decodedMeshOsdArray = (OSDArray)decodedMeshOsd; foreach (OSD subMeshOsd in decodedMeshOsdArray) { if (subMeshOsd is OSDMap) { OSDMap subMeshMap = (OSDMap)subMeshOsd; // As per http://wiki.secondlife.com/wiki/Mesh/Mesh_Asset_Format, some Mesh Level // of Detail Blocks (maps) contain just a NoGeometry key to signal there is no // geometry for this submesh. if (subMeshMap.ContainsKey("NoGeometry") && (subMeshMap["NoGeometry"])) { continue; } Vector3 posMax = new Vector3(0.5f, 0.5f, 0.5f); Vector3 posMin = new Vector3(-0.5f, -0.5f, -0.5f); if (subMeshMap.ContainsKey("PositionDomain")) //Optional, so leave the max and min values otherwise { posMax = ((OSDMap)subMeshMap["PositionDomain"])["Max"].AsVector3(); posMin = ((OSDMap)subMeshMap["PositionDomain"])["Min"].AsVector3(); } ushort faceIndexOffset = (ushort)coords.Count; byte[] posBytes = subMeshMap["Position"].AsBinary(); for (int i = 0; i < posBytes.Length; i += 6) { ushort uX = Utils.BytesToUInt16(posBytes, i); ushort uY = Utils.BytesToUInt16(posBytes, i + 2); ushort uZ = Utils.BytesToUInt16(posBytes, i + 4); Coord c = new Coord( Utils.UInt16ToFloat(uX, posMin.X, posMax.X) * size.X, Utils.UInt16ToFloat(uY, posMin.Y, posMax.Y) * size.Y, Utils.UInt16ToFloat(uZ, posMin.Z, posMax.Z) * size.Z); coords.Add(c); } byte[] triangleBytes = subMeshMap["TriangleList"].AsBinary(); for (int i = 0; i < triangleBytes.Length; i += 6) { ushort v1 = (ushort)(Utils.BytesToUInt16(triangleBytes, i) + faceIndexOffset); ushort v2 = (ushort)(Utils.BytesToUInt16(triangleBytes, i + 2) + faceIndexOffset); ushort v3 = (ushort)(Utils.BytesToUInt16(triangleBytes, i + 4) + faceIndexOffset); Face f = new Face(v1, v2, v3); faces.Add(f); } } } } } } else { if (cacheSculptMaps && primShape.SculptTexture != UUID.Zero) { decodedSculptFileName = System.IO.Path.Combine(decodedSculptMapPath, "smap_" + primShape.SculptTexture.ToString()); try { if (File.Exists(decodedSculptFileName)) { idata = Image.FromFile(decodedSculptFileName); } } catch (Exception e) { MainConsole.Instance.Error("[SCULPT]: unable to load cached sculpt map " + decodedSculptFileName + " " + e); } //if (idata != null) // MainConsole.Instance.Debug("[SCULPT]: loaded cached map asset for map ID: " + primShape.SculptTexture.ToString()); } if (idata == null) { if (primShape.SculptData == null || primShape.SculptData.Length == 0) { return(null); } try { idata = m_j2kDecoder.DecodeToImage(primShape.SculptData); if (idata != null && cacheSculptMaps && (cacheSculptAlphaMaps || (((ImageFlags)(idata.Flags) & ImageFlags.HasAlpha) == 0))) { try { idata.Save(decodedSculptFileName, ImageFormat.MemoryBmp); } catch (Exception e) { MainConsole.Instance.Error("[SCULPT]: unable to cache sculpt map " + decodedSculptFileName + " " + e); } } } catch (DllNotFoundException) { MainConsole.Instance.Error( "[PHYSICS]: OpenJpeg is not installed correctly on this system. Physics Proxy generation failed. Often times this is because of an old version of GLIBC. You must have version 2.4 or above!"); return(null); } catch (IndexOutOfRangeException) { MainConsole.Instance.Error( "[PHYSICS]: OpenJpeg was unable to decode this. Physics Proxy generation failed"); return(null); } catch (Exception ex) { MainConsole.Instance.Error( "[PHYSICS]: Unable to generate a Sculpty physics proxy. Sculpty texture decode failed: " + ex); return(null); } } SculptMesh.SculptType sculptType; switch ((SculptType)primShape.SculptType) { case SculptType.Cylinder: sculptType = SculptMesh.SculptType.cylinder; break; case SculptType.Plane: sculptType = SculptMesh.SculptType.plane; break; case SculptType.Torus: sculptType = SculptMesh.SculptType.torus; break; case SculptType.Sphere: sculptType = SculptMesh.SculptType.sphere; break; default: sculptType = SculptMesh.SculptType.plane; break; } bool mirror = ((primShape.SculptType & 128) != 0); bool invert = ((primShape.SculptType & 64) != 0); if (idata == null) { return(null); } sculptMesh = new SculptMesh((Bitmap)idata, sculptType, (int)lod, false, mirror, invert); idata.Dispose(); idata = null; sculptMesh.DumpRaw(baseDir, primName, "primMesh"); sculptMesh.Scale(size.X, size.Y, size.Z); coords = sculptMesh.coords; faces = sculptMesh.faces; } } else { float pathShearX = primShape.PathShearX < 128 ? primShape.PathShearX * 0.01f : (primShape.PathShearX - 256) * 0.01f; float pathShearY = primShape.PathShearY < 128 ? primShape.PathShearY * 0.01f : (primShape.PathShearY - 256) * 0.01f; float pathBegin = primShape.PathBegin * 2.0e-5f; float pathEnd = 1.0f - primShape.PathEnd * 2.0e-5f; float pathScaleX = (primShape.PathScaleX - 100) * 0.01f; float pathScaleY = (primShape.PathScaleY - 100) * 0.01f; float profileBegin = primShape.ProfileBegin * 2.0e-5f; float profileEnd = 1.0f - primShape.ProfileEnd * 2.0e-5f; float profileHollow = primShape.ProfileHollow * 2.0e-5f; if (profileHollow > 0.95f) { if (profileHollow > 0.99f) { profileHollow = 0.99f; } float sizeX = primShape.Scale.X - (primShape.Scale.X * profileHollow); if (sizeX < 0.1f) //If its > 0.1, its fine to mesh at the small hollow { profileHollow = 0.95f + (sizeX / 2); //Scale the rest by how large the size of the prim is } } int sides = 4; switch ((primShape.ProfileCurve & 0x07)) { case (byte)ProfileShape.EquilateralTriangle: sides = 3; break; case (byte)ProfileShape.Circle: sides = 24; break; case (byte)ProfileShape.HalfCircle: sides = 24; profileBegin = 0.5f * profileBegin + 0.5f; profileEnd = 0.5f * profileEnd + 0.5f; break; } int hollowSides = sides; switch (primShape.HollowShape) { case HollowShape.Circle: hollowSides = 24; break; case HollowShape.Square: hollowSides = 4; break; case HollowShape.Triangle: hollowSides = 3; break; } primMesh = new PrimMesh(sides, profileBegin, profileEnd, profileHollow, hollowSides); if (primMesh.errorMessage != null) { if (primMesh.errorMessage.Length > 0) { MainConsole.Instance.Error("[ERROR] " + primMesh.errorMessage); } } primMesh.topShearX = pathShearX; primMesh.topShearY = pathShearY; primMesh.pathCutBegin = pathBegin; primMesh.pathCutEnd = pathEnd; if (primShape.PathCurve == (byte)Extrusion.Straight || primShape.PathCurve == (byte)Extrusion.Flexible) { primMesh.twistBegin = primShape.PathTwistBegin * 18 / 10; primMesh.twistEnd = primShape.PathTwist * 18 / 10; primMesh.taperX = pathScaleX; primMesh.taperY = pathScaleY; if (profileBegin < 0.0f || profileBegin >= profileEnd || profileEnd > 1.0f) { ReportPrimError("*** CORRUPT PRIM!! ***", primName, primMesh); if (profileBegin < 0.0f) { profileBegin = 0.0f; } if (profileEnd > 1.0f) { profileEnd = 1.0f; } } #if SPAM MainConsole.Instance.Debug("****** PrimMesh Parameters (Linear) ******\n" + primMesh.ParamsToDisplayString()); #endif try { primMesh.Extrude(primShape.PathCurve == (byte)Extrusion.Straight ? PathType.Linear : PathType.Flexible); } catch (Exception ex) { ReportPrimError("Extrusion failure: exception: " + ex, primName, primMesh); return(null); } } else { primMesh.holeSizeX = (200 - primShape.PathScaleX) * 0.01f; primMesh.holeSizeY = (200 - primShape.PathScaleY) * 0.01f; primMesh.radius = 0.01f * primShape.PathRadiusOffset; primMesh.revolutions = 1.0f + 0.015f * primShape.PathRevolutions; primMesh.skew = 0.01f * primShape.PathSkew; primMesh.twistBegin = primShape.PathTwistBegin * 36 / 10; primMesh.twistEnd = primShape.PathTwist * 36 / 10; primMesh.taperX = primShape.PathTaperX * 0.01f; primMesh.taperY = primShape.PathTaperY * 0.01f; if (profileBegin < 0.0f || profileBegin >= profileEnd || profileEnd > 1.0f) { ReportPrimError("*** CORRUPT PRIM!! ***", primName, primMesh); if (profileBegin < 0.0f) { profileBegin = 0.0f; } if (profileEnd > 1.0f) { profileEnd = 1.0f; } } #if SPAM MainConsole.Instance.Debug("****** PrimMesh Parameters (Circular) ******\n" + primMesh.ParamsToDisplayString()); #endif try { primMesh.Extrude(PathType.Circular); } catch (Exception ex) { ReportPrimError("Extrusion failure: exception: " + ex, primName, primMesh); return(null); } } primMesh.DumpRaw(baseDir, primName, "primMesh"); primMesh.Scale(size.X, size.Y, size.Z); coords = primMesh.coords; faces = primMesh.faces; primMesh = null; } Mesh mesh = new Mesh(key); //mesh.m_triangles = faces; //mesh.m_vertices = coords; // Add the corresponding triangles to the mesh mesh.Set(coords, faces); coords.Clear(); faces.Clear(); coords = null; faces = null; return(mesh); }
public Hashtable MapRequest(Hashtable request) { Hashtable reply = new Hashtable(); string uri = request["uri"].ToString(); //Remove the /MapService/ uri = uri.Remove(0, 12); if (!uri.StartsWith("map")) { if (uri == "") { string resp = "<ListBucketResult xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\">" + "<Name>map.secondlife.com</Name>" + "<Prefix/>" + "<Marker/>" + "<MaxKeys>1000</MaxKeys>" + "<IsTruncated>true</IsTruncated>"; List <GridRegion> regions = m_gridService.GetRegionRange(null, (1000 * Constants.RegionSize) - (8 * Constants.RegionSize), (1000 * Constants.RegionSize) + (8 * Constants.RegionSize), (1000 * Constants.RegionSize) - (8 * Constants.RegionSize), (1000 * Constants.RegionSize) + (8 * Constants.RegionSize)); foreach (var region in regions) { resp += "<Contents><Key>map-1-" + region.RegionLocX / 256 + "-" + region.RegionLocY / 256 + "-objects.jpg</Key>" + "<LastModified>2012-07-09T21:26:32.000Z</LastModified></Contents>"; } resp += "</ListBucketResult>"; reply["str_response_string"] = resp; reply["int_response_code"] = 200; reply["content_type"] = "application/xml"; return(reply); } return(null); } string[] splitUri = uri.Split('-'); byte[] jpeg = FindCachedImage(uri); if (jpeg.Length != 0) { reply["str_response_string"] = Convert.ToBase64String(jpeg); reply["int_response_code"] = 200; reply["content_type"] = "image/jpeg"; return(reply); } try { int mapLayer = int.Parse(uri.Substring(4, 1)); int mapView = (int)Math.Pow(2, (mapLayer - 1)); int regionX = int.Parse(splitUri[2]); int regionY = int.Parse(splitUri[3]); int maxRegionSize = m_gridService.GetMaxRegionSize(); if (maxRegionSize == 0) { maxRegionSize = 8192; } List <GridRegion> regions = m_gridService.GetRegionRange(null, (regionX * Constants.RegionSize) - maxRegionSize, (regionX * Constants.RegionSize) + maxRegionSize, (regionY * Constants.RegionSize) - maxRegionSize, (regionY * Constants.RegionSize) + maxRegionSize); List <Image> bitImages = new List <Image>(); List <GridRegion> badRegions = new List <GridRegion>(); IJ2KDecoder decoder = m_registry.RequestModuleInterface <IJ2KDecoder>(); foreach (GridRegion r in regions) { AssetBase texAsset = m_assetService.Get(r.TerrainMapImage.ToString()); if (texAsset != null) { Image image = decoder.DecodeToImage(texAsset.Data); if (image != null) { bitImages.Add(image); } else { badRegions.Add(r); } } else { badRegions.Add(r); } } foreach (GridRegion r in badRegions) { regions.Remove(r); } const int SizeOfImage = 256; using (Bitmap mapTexture = new Bitmap(SizeOfImage, SizeOfImage)) { using (Graphics g = Graphics.FromImage(mapTexture)) { SolidBrush sea = new SolidBrush(Color.FromArgb(29, 71, 95)); g.FillRectangle(sea, 0, 0, SizeOfImage, SizeOfImage); for (int i = 0; i < regions.Count; i++) { //Find the offsets first float x = (regions[i].RegionLocX - (regionX * (float)Constants.RegionSize)) / Constants.RegionSize; float y = (regions[i].RegionLocY - (regionY * (float)Constants.RegionSize)) / Constants.RegionSize; y += (regions[i].RegionSizeX - Constants.RegionSize) / Constants.RegionSize; float xx = (float)(x * (SizeOfImage / mapView)); float yy = SizeOfImage - (y * (SizeOfImage / mapView) + (SizeOfImage / (mapView))); g.DrawImage(bitImages[i], xx, yy, (int)(SizeOfImage / (float)mapView * ((float)regions[i].RegionSizeX / Constants.RegionSize)), (int)(SizeOfImage / (float)mapView * (regions[i].RegionSizeY / (float)Constants.RegionSize))); // y origin is top } } foreach (var bmp in bitImages) { bmp.Dispose(); } EncoderParameters myEncoderParameters = new EncoderParameters(); myEncoderParameters.Param[0] = new EncoderParameter(Encoder.Quality, 95L); using (MemoryStream imgstream = new MemoryStream()) { // Save bitmap to stream mapTexture.Save(imgstream, GetEncoderInfo("image/jpeg"), myEncoderParameters); // Write the stream to a byte array for output jpeg = imgstream.ToArray(); } SaveCachedImage(uri, jpeg); } } catch { } if (jpeg.Length == 0 && splitUri.Length > 1 && splitUri[1].Length > 1) { using (MemoryStream imgstream = new MemoryStream()) { GridRegion region = m_registry.RequestModuleInterface <IGridService>().GetRegionByName(null, splitUri[1].Remove (4)); if (region == null) { return(null); } // non-async because we know we have the asset immediately. AssetBase mapasset = m_assetService.Get(region.TerrainMapImage.ToString()); if (mapasset != null) { Image image; ManagedImage mImage; if (!OpenJPEG.DecodeToImage(mapasset.Data, out mImage, out image) || image == null) { return(null); } // Decode image to System.Drawing.Image EncoderParameters myEncoderParameters = new EncoderParameters(); myEncoderParameters.Param[0] = new EncoderParameter(Encoder.Quality, 95L); // Save bitmap to stream image.Save(imgstream, GetEncoderInfo("image/jpeg"), myEncoderParameters); // Write the stream to a byte array for output jpeg = imgstream.ToArray(); SaveCachedImage(uri, jpeg); mapasset.Dispose(); image.Dispose(); } } } reply["str_response_string"] = Convert.ToBase64String(jpeg); reply["int_response_code"] = 200; reply["content_type"] = "image/jpeg"; return(reply); }
private void CreatePrim(WarpRenderer renderer, SceneObjectPart prim, bool useTextures) { const float MIN_SIZE_SQUARE = 4f; if ((PCode)prim.Shape.PCode != PCode.Prim) { return; } float primScaleLenSquared = prim.Scale.LengthSquared(); if (primScaleLenSquared < MIN_SIZE_SQUARE) { return; } FacetedMesh renderMesh = null; Primitive omvPrim = prim.Shape.ToOmvPrimitive(prim.OffsetPosition, prim.RotationOffset); if (m_renderMeshes) { if (omvPrim.Sculpt != null && omvPrim.Sculpt.SculptTexture != UUID.Zero) { // Try fetchinng the asset byte[] sculptAsset = m_scene.AssetService.GetData(omvPrim.Sculpt.SculptTexture.ToString()); if (sculptAsset != null) { // Is it a mesh? if (omvPrim.Sculpt.Type == SculptType.Mesh) { AssetMesh meshAsset = new AssetMesh(omvPrim.Sculpt.SculptTexture, sculptAsset); FacetedMesh.TryDecodeFromAsset(omvPrim, meshAsset, DetailLevel.Highest, out renderMesh); meshAsset = null; } else // It's sculptie { IJ2KDecoder imgDecoder = m_scene.RequestModuleInterface <IJ2KDecoder>(); if (imgDecoder != null) { Image sculpt = imgDecoder.DecodeToImage(sculptAsset); if (sculpt != null) { renderMesh = m_primMesher.GenerateFacetedSculptMesh(omvPrim, (Bitmap)sculpt, DetailLevel.Medium); sculpt.Dispose(); } } } } } } // If not a mesh or sculptie, try the regular mesher if (renderMesh == null) { renderMesh = m_primMesher.GenerateFacetedMesh(omvPrim, DetailLevel.Medium); } if (renderMesh == null) { return; } string primID = prim.UUID.ToString(); // Create the prim faces // TODO: Implement the useTextures flag behavior for (int i = 0; i < renderMesh.Faces.Count; i++) { Face face = renderMesh.Faces[i]; string meshName = primID + i.ToString(); // Avoid adding duplicate meshes to the scene if (renderer.Scene.objectData.ContainsKey(meshName)) { continue; } warp_Object faceObj = new warp_Object(); for (int j = 0; j < face.Vertices.Count; j++) { Vertex v = face.Vertices[j]; warp_Vector pos = ConvertVector(v.Position); warp_Vertex vert = new warp_Vertex(pos, v.TexCoord.X, v.TexCoord.Y); faceObj.addVertex(vert); } for (int j = 0; j < face.Indices.Count; j += 3) { faceObj.addTriangle( face.Indices[j + 0], face.Indices[j + 1], face.Indices[j + 2]); } Primitive.TextureEntryFace teFace = prim.Shape.Textures.GetFace((uint)i); Color4 faceColor = GetFaceColor(teFace); string materialName = String.Empty; if (m_texturePrims && primScaleLenSquared > m_texturePrimSize * m_texturePrimSize) { materialName = GetOrCreateMaterial(renderer, faceColor, teFace.TextureID); } else { materialName = GetOrCreateMaterial(renderer, faceColor); } warp_Vector primPos = ConvertVector(prim.GetWorldPosition()); warp_Quaternion primRot = ConvertQuaternion(prim.GetWorldRotation()); warp_Matrix m = warp_Matrix.quaternionMatrix(primRot); faceObj.transform(m); faceObj.setPos(primPos); faceObj.scaleSelf(prim.Scale.X, prim.Scale.Z, prim.Scale.Y); renderer.Scene.addObject(meshName, faceObj); renderer.SetObjectMaterial(meshName, materialName); } }
private void CreatePrim(WarpRenderer renderer, SceneObjectPart prim) { if ((PCode)prim.Shape.PCode != PCode.Prim) { return; } Vector3 ppos = prim.GetWorldPosition(); if (ppos.Z < m_renderMinHeight || ppos.Z > m_renderMaxHeight) { return; } warp_Vector primPos = ConvertVector(ppos); warp_Quaternion primRot = ConvertQuaternion(prim.GetWorldRotation()); warp_Matrix m = warp_Matrix.quaternionMatrix(primRot); float screenFactor = renderer.Scene.EstimateBoxProjectedArea(primPos, ConvertVector(prim.Scale), m); if (screenFactor < 0) { return; } const float log2inv = -1.442695f; int p2 = (int)((float)Math.Log(screenFactor) * log2inv * 0.25 - 1); if (p2 < 0) { p2 = 0; } else if (p2 > 3) { p2 = 3; } DetailLevel lod = (DetailLevel)(3 - p2); FacetedMesh renderMesh = null; Primitive omvPrim = prim.Shape.ToOmvPrimitive(prim.OffsetPosition, prim.RotationOffset); if (m_renderMeshes) { if (omvPrim.Sculpt != null && omvPrim.Sculpt.SculptTexture != UUID.Zero) { // Try fetchinng the asset AssetBase sculptAsset = m_scene.AssetService.Get(omvPrim.Sculpt.SculptTexture.ToString()); if (sculptAsset != null) { // Is it a mesh? if (omvPrim.Sculpt.Type == SculptType.Mesh) { AssetMesh meshAsset = new AssetMesh(omvPrim.Sculpt.SculptTexture, sculptAsset.Data); FacetedMesh.TryDecodeFromAsset(omvPrim, meshAsset, lod, out renderMesh); meshAsset = null; } else // It's sculptie { if (m_imgDecoder != null) { Image sculpt = m_imgDecoder.DecodeToImage(sculptAsset.Data); if (sculpt != null) { renderMesh = m_primMesher.GenerateFacetedSculptMesh(omvPrim, (Bitmap)sculpt, lod); sculpt.Dispose(); } } } } else { m_log.WarnFormat("[Warp3D] failed to get mesh or sculpt asset {0} of prim {1} at {2}", omvPrim.Sculpt.SculptTexture.ToString(), prim.Name, prim.GetWorldPosition().ToString()); } } } // If not a mesh or sculptie, try the regular mesher if (renderMesh == null) { renderMesh = m_primMesher.GenerateFacetedMesh(omvPrim, lod); } if (renderMesh == null) { return; } string primID = prim.UUID.ToString(); // Create the prim faces // TODO: Implement the useTextures flag behavior for (int i = 0; i < renderMesh.Faces.Count; i++) { Face face = renderMesh.Faces[i]; string meshName = primID + i.ToString(); // Avoid adding duplicate meshes to the scene if (renderer.Scene.objectData.ContainsKey(meshName)) { continue; } warp_Object faceObj = new warp_Object(); Primitive.TextureEntryFace teFace = prim.Shape.Textures.GetFace((uint)i); Color4 faceColor = teFace.RGBA; if (faceColor.A == 0) { continue; } string materialName = string.Empty; if (m_texturePrims) { // if(lod > DetailLevel.Low) { // materialName = GetOrCreateMaterial(renderer, faceColor, teFace.TextureID, lod == DetailLevel.Low); materialName = GetOrCreateMaterial(renderer, faceColor, teFace.TextureID, false, prim); if (String.IsNullOrEmpty(materialName)) { continue; } int c = renderer.Scene.material(materialName).getColor(); if ((c & warp_Color.MASKALPHA) == 0) { continue; } } } else { materialName = GetOrCreateMaterial(renderer, faceColor); } if (renderer.Scene.material(materialName).getTexture() == null) { // uv map details dont not matter for color; for (int j = 0; j < face.Vertices.Count; j++) { Vertex v = face.Vertices[j]; warp_Vector pos = ConvertVector(v.Position); warp_Vertex vert = new warp_Vertex(pos, v.TexCoord.X, v.TexCoord.Y); faceObj.addVertex(vert); } } else { float tu; float tv; float offsetu = teFace.OffsetU + 0.5f; float offsetv = teFace.OffsetV + 0.5f; float scaleu = teFace.RepeatU; float scalev = teFace.RepeatV; float rotation = teFace.Rotation; float rc = 0; float rs = 0; if (rotation != 0) { rc = (float)Math.Cos(rotation); rs = (float)Math.Sin(rotation); } for (int j = 0; j < face.Vertices.Count; j++) { warp_Vertex vert; Vertex v = face.Vertices[j]; warp_Vector pos = ConvertVector(v.Position); if (teFace.TexMapType == MappingType.Planar) { UVPlanarMap(v, prim.Scale, out tu, out tv); } else { tu = v.TexCoord.X - 0.5f; tv = 0.5f - v.TexCoord.Y; } if (rotation != 0) { float tur = tu * rc - tv * rs; float tvr = tu * rs + tv * rc; tur *= scaleu; tur += offsetu; tvr *= scalev; tvr += offsetv; vert = new warp_Vertex(pos, tur, tvr); } else { tu *= scaleu; tu += offsetu; tv *= scalev; tv += offsetv; vert = new warp_Vertex(pos, tu, tv); } faceObj.addVertex(vert); } } for (int j = 0; j < face.Indices.Count; j += 3) { faceObj.addTriangle( face.Indices[j + 0], face.Indices[j + 1], face.Indices[j + 2]); } faceObj.scaleSelf(prim.Scale.X, prim.Scale.Z, prim.Scale.Y); faceObj.transform(m); faceObj.setPos(primPos); renderer.Scene.addObject(meshName, faceObj); renderer.SetObjectMaterial(meshName, materialName); } }
public static Color4 GetAverageColor(UUID textureID, byte [] j2kData, IScene scene) { ulong r = 0; ulong g = 0; ulong b = 0; ulong a = 0; Bitmap bitmap = null; try { if (j2kData.Length == 0) { return(new Color4(1.0f, 0.0f, 1.0f, 1.0f)); } IJ2KDecoder decoder = scene.RequestModuleInterface <IJ2KDecoder> (); bitmap = (Bitmap)decoder.DecodeToImage(j2kData); if (bitmap == null) { return(new Color4(1.0f, 0.0f, 0.5f, 1.0f)); } j2kData = null; int width = bitmap.Width; int height = bitmap.Height; BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, bitmap.PixelFormat); int pixelBytes = (bitmap.PixelFormat == PixelFormat.Format24bppRgb) ? 3 : 4; bool hasAlpha = (pixelBytes == 4); // Sum up the individual channels unsafe { for (int y = 0; y < height; y++) { byte *row = (byte *)bitmapData.Scan0 + (y * bitmapData.Stride); for (int x = 0; x < width; x++) { b += row [x * pixelBytes + 0]; g += row [x * pixelBytes + 1]; r += row [x * pixelBytes + 2]; if (hasAlpha) { a += row [x * pixelBytes + 3]; } } } } // Get the averages for each channel const decimal OO_255 = 1m / 255m; decimal totalPixels = (width * height); decimal rm = (r / totalPixels) * OO_255; decimal gm = (g / totalPixels) * OO_255; decimal bm = (b / totalPixels) * OO_255; decimal am; if (hasAlpha) { am = (a / totalPixels) * OO_255; } else { am = 1m; } return(new Color4((float)rm, (float)gm, (float)bm, (float)am)); } catch (Exception ex) { MainConsole.Instance.WarnFormat("[WarpTile generator]: Error decoding JPEG2000 texture {0} ({1} bytes): {2}", textureID, j2kData.Length, ex.Message); return(new Color4(0.5f, 0.5f, 0.5f, 1.0f)); } finally { if (bitmap != null) { bitmap.Dispose(); } } }
public void ShadeWorld(string[] cmd) { if (MainConsole.Instance.ConsoleScene == null) { MainConsole.Instance.Output("Select a scene first"); return; } bool greyScale = MainConsole.Instance.Prompt("Greyscale (yes or no)?").ToLower() == "yes"; int R = 0; int G = 0; int B = 0; float percent = 0; if (!greyScale) { R = int.Parse(MainConsole.Instance.Prompt("R color (0 - 255)")); G = int.Parse(MainConsole.Instance.Prompt("G color (0 - 255)")); B = int.Parse(MainConsole.Instance.Prompt("B color (0 - 255)")); percent = float.Parse(MainConsole.Instance.Prompt("Percent to merge in the shade (0 - 100)")); } if (percent > 1) { percent /= 100; } Color shader = Color.FromArgb(R, G, B); IJ2KDecoder j2kDecoder = MainConsole.Instance.ConsoleScene.RequestModuleInterface <IJ2KDecoder>(); ISceneEntity[] entities = MainConsole.Instance.ConsoleScene.Entities.GetEntities(); foreach (ISceneEntity entity in entities) { foreach (ISceneChildEntity child in entity.ChildrenEntities()) { UUID[] textures = GetTextures(child.Shape.Textures); foreach (UUID t in textures) { if (m_previouslyConverted.ContainsKey(t)) { child.Shape.Textures = SetTexture(child.Shape, m_previouslyConverted[t], t); } else { AssetBase a = MainConsole.Instance.ConsoleScene.AssetService.Get(t.ToString()); if (a != null) { Bitmap texture = (Bitmap)j2kDecoder.DecodeToImage(a.Data); if (texture == null) { continue; } a.ID = UUID.Random(); texture = Shade(texture, shader, percent, greyScale); a.Data = OpenJPEG.EncodeFromImage(texture, false); texture.Dispose(); a.ID = MainConsole.Instance.ConsoleScene.AssetService.Store(a); child.Shape.Textures = SetTexture(child.Shape, a.ID, t); m_previouslyConverted.Add(t, a.ID); m_revertConverted.Add(a.ID, t); } } } } } }
public void ShadeWorld(IScene scene, string [] cmd) { bool greyScale = MainConsole.Instance.Prompt("Greyscale (yes or no)?").ToLower() == "yes"; int R = 0; int G = 0; int B = 0; float percent = 0; if (!greyScale) { R = int.Parse(MainConsole.Instance.Prompt("R color (0 - 255)")); G = int.Parse(MainConsole.Instance.Prompt("G color (0 - 255)")); B = int.Parse(MainConsole.Instance.Prompt("B color (0 - 255)")); percent = float.Parse(MainConsole.Instance.Prompt("Percent to merge in the shade (0 - 100)")); } if (percent > 1) { percent /= 100; } Color shader = Color.FromArgb(R, G, B); IJ2KDecoder j2kDecoder = scene.RequestModuleInterface <IJ2KDecoder> (); ISceneEntity [] entities = scene.Entities.GetEntities(); foreach (ISceneEntity entity in entities) { foreach (ISceneChildEntity child in entity.ChildrenEntities()) { UUID [] textures = GetTextures(child.Shape.Textures); foreach (UUID t in textures) { if (m_previouslyConverted.ContainsKey(t)) { child.Shape.Textures = SetTexture(child.Shape, m_previouslyConverted [t], t); } else { AssetBase asset = scene.AssetService.Get(t.ToString()); if (asset != null) { Bitmap texture = null; try { texture = (Bitmap)j2kDecoder.DecodeToImage(asset.Data); } catch { } if (texture == null) { asset.Dispose(); continue; } asset.ID = UUID.Random(); try { texture = Shade(texture, shader, percent, greyScale); } catch { asset.Dispose(); continue; // cannot convert this one... } asset.Data = OpenJPEG.EncodeFromImage(texture, false); asset.Description = t.ToString(); texture.Dispose(); asset.ID = scene.AssetService.Store(asset); child.Shape.Textures = SetTexture(child.Shape, asset.ID, t); m_previouslyConverted.Add(t, asset.ID); m_revertConverted.Add(asset.ID, t); asset.Dispose(); } } } } } MainConsole.Instance.Warn("[Shader]: WARNING: You may not be able to revert this once you restart the instance"); }