/// <summary> /// Add a texture to the cache, this will return a TextureCacheHandle that you MUST dispose /// when you aren't using it anymore. /// </summary> /// <param name="textureName"></param> /// <param name="image"></param> private TextureCacheHandle Add(string textureName, PagedImage image) { lock (syncObject) { TextureCacheHandle handle; UInt64 imageSize = image.Size; if (imageSize < maxCacheSize) //Image itself can fit { while (currentCacheSize + imageSize > maxCacheSize && lastAccessedOrder.Last != null) { //Drop oldest images until there is enough space String last = lastAccessedOrder.Last.Value; lastAccessedOrder.RemoveLast(); var destroyImage = loadedImages[last]; loadedImages.Remove(last); currentCacheSize -= destroyImage.Size; destroyImage.destroyIfPossible(); } currentCacheSize += image.Size; handle = new PagedImageCacheHandle(image, false); loadedImages.Add(textureName, handle); lastAccessedOrder.AddFirst(textureName); } else { handle = new PagedImageCacheHandle(image, true); } handle.checkout(); return(handle); } }
//private unsafe byte getColor(int x, int y, FreeImageBitmap src, Channel channel) //{ // int bpp = 4; // if (src.PixelFormat == FreeImageAPI.PixelFormat.Format24bppRgb) // { // bpp = 3; // } // byte* pixel = (byte*)src.Bits.ToPointer(); // pixel += (src.Pitch * (src.Height - y - 1) + x) * bpp; // switch (channel) // { // case Channel.Alpha: // return pixel[3]; // case Channel.Red: // return pixel[2]; // case Channel.Green: // return pixel[1]; // case Channel.Blue: // return pixel[0]; // } // throw new NotSupportedException(); //Won't get here //} private async Task saveUncompressed(String sourceFile, String destFile, bool lossless, FREE_IMAGE_FILTER filter, ImagePageSizeStrategy pageSizeStrategy, Action <FreeImageBitmap> afterResize = null) { await Task.Run(() => { if ((outputFormats & OutputFormats.Uncompressed) != 0) { Log.Info("Creating paged data for {0}", sourceFile); using (FreeImageBitmap source = FreeImageBitmap.FromFile(sourceFile)) { using (var stream = File.Open(String.Format(PagedTextureNameFormat, destFile), FileMode.Create, FileAccess.ReadWrite)) { PagedImage.fromBitmap(source, 128, 1, stream, PagedImage.ImageType.WEBP, maxSize, lossless, filter, pageSizeStrategy, afterResize); } } } }); }
internal TexturePageHandle getImage(VTexPage page, IndirectionTexture indirectionTexture, OriginalTextureInfo textureUnit, int textelsPerPage, int padding, int padding2) { String textureName; if (texturesArePaged) { textureName = textureUnit.TextureFileName; } else { textureName = String.Format("{0}_{1}", textureUnit.TextureFileName, indirectionTexture.RealTextureSize.Width >> page.mip); } TextureCacheHandle cacheHandle; if (!this.TryGetValue(textureName, out cacheHandle)) { String file = textureUnit.TextureFileName; if (texturesArePaged) //Paged Images { //using (var perfMon = new LogPerformanceBlock(String.Format("Loaded image {0} in {{0}} ms", file), Logging.LogLevel.Info, "TextureCache")) //{ PagedImage pagedImage = new PagedImage(); pagedImage.load(() => VirtualFileSystem.Instance.openStream(file, Engine.Resources.FileMode.Open, Engine.Resources.FileAccess.Read)); cacheHandle = this.Add(textureName, pagedImage); //} } else //Normal Images { String extension = Path.GetExtension(file); String directFile = textureUnit.TextureFileName.Substring(0, file.Length - extension.Length); directFile = String.Format("{0}_{1}{2}", directFile, indirectionTexture.RealTextureSize.Width >> page.mip, extension); if (VirtualFileSystem.Instance.exists(directFile)) { var image = doLoadImage(extension, directFile); cacheHandle = this.Add(textureName, image); } else { //Not using cache for full size images, this is a rare case that we are not really supporting right now Image image = doLoadImage(extension, textureUnit.TextureFileName); //If we aren't mip 0 resize accordingly if (page.mip > image.NumMipmaps && page.mip != 0) { using (Image original = image) { image = new Image(original.Width >> page.mip, original.Height >> page.mip, original.Depth, original.Format, original.NumFaces, original.NumMipmaps); using (var src = original.getPixelBox()) { using (var dest = image.getPixelBox()) { Image.Scale(src, dest, Image.Filter.FILTER_BILINEAR); } } } } cacheHandle = this.Add(textureName, image); } } } return(cacheHandle.createTexturePageHandle(page, indirectionTexture, padding, padding2, textelsPerPage, textureUnit.MipOffset)); }
public PagedImageCacheHandle(PagedImage pagedImage, bool destroyOnNoRef) : base(destroyOnNoRef) { this.pagedImage = pagedImage; }
public void extractPage(FreeImageBitmap image, int padding, Stream stream, PagedImage pagedImage, int pageSize, IntSize2 fullPageSize, int size, FREE_IMAGE_FORMAT outputFormat, FREE_IMAGE_SAVE_FLAGS saveFlags) { IntRect serialImageRect = new IntRect(); MemoryStream[] memoryStreams = new MemoryStream[size]; FreeImageBitmap[] pages = new FreeImageBitmap[size]; try { for (int i = 0; i < size; ++i) { memoryStreams[i] = new MemoryStream(); pages[i] = new FreeImageBitmap(fullPageSize.Width, fullPageSize.Height, FreeImageAPI.PixelFormat.Format32bppArgb); } //Calculate pages as tiles, always repeat outer limits for (int y = 0; y < size; ++y) { serialImageRect.Height = pageSize; serialImageRect.Top = y * pageSize; Parallel.For(0, size, x => //for (int x = 0; x < size; ++x) { IntRect imageRect = serialImageRect; imageRect.Width = pageSize; imageRect.Left = x * pageSize; using (var pageBox = pages[x].createPixelBox(PixelFormat.PF_A8R8G8B8)) { pageBox.Top += (uint)padding; pageBox.Bottom -= (uint)padding; pageBox.Left += (uint)padding; pageBox.Right -= (uint)padding; using (var imageBox = image.createPixelBox()) { imageBox.Left = (uint)imageRect.Left; imageBox.Right = (uint)imageRect.Right; imageBox.Top = (uint)imageRect.Top; imageBox.Bottom = (uint)imageRect.Bottom; PixelBox.BulkPixelConversion(imageBox, pageBox); } padFillColor(image, padding, pageSize, fullPageSize, imageRect, pageBox); } //int startPos = (int)stream.Position; pages[x].RotateFlip(RotateFlipType.RotateNoneFlipY); //Have to flip the page over for ogre to be happy pages[x].Save(memoryStreams[x], outputFormat, saveFlags); //pages[x].saveToFile($"page/page{image.Width}_x{x}y_{y}.bmp", FREE_IMAGE_FORMAT.FIF_BMP); memoryStreams[x].Position = 0; //++pagedImage.numImages; //pagedImage.pages.Add(new ImageInfo(startPos, (int)(stream.Position))); }); //} for (int x = 0; x < size; ++x) { int startPos = (int)stream.Position; //page.RotateFlip(RotateFlipType.RotateNoneFlipY); //Have to flip the page over for ogre to be happy //page.Save(stream, outputFormat, saveFlags); memoryStreams[x].CopyTo(stream); ++pagedImage.NumImages; pagedImage.Pages.Add(new PagedImage.ImageInfo(startPos, (int)(stream.Position))); memoryStreams[x].Dispose(); memoryStreams[x] = new MemoryStream(); } } } finally { for (int i = 0; i < size; ++i) { memoryStreams[i].Dispose(); pages[i].Dispose(); } } }
public void extractPage(FreeImageBitmap image, int padding, Stream stream, PagedImage pagedImage, int pageSize, IntSize2 fullPageSize, int size, FREE_IMAGE_FORMAT outputFormat, FREE_IMAGE_SAVE_FLAGS saveFlags) { bool topSide, bottomSide; IntRect serialImageRect = new IntRect(); MemoryStream[] memoryStreams = new MemoryStream[size]; FreeImageBitmap[] pages = new FreeImageBitmap[size]; try { for (int i = 0; i < size; ++i) { memoryStreams[i] = new MemoryStream(); pages[i] = new FreeImageBitmap(fullPageSize.Width, fullPageSize.Height, FreeImageAPI.PixelFormat.Format32bppArgb); } //Calculate pages, note that there is overlap by padding between them this is intentional for (int y = 0; y < size; ++y) { serialImageRect.Height = fullPageSize.Height; serialImageRect.Top = y * pageSize - padding; topSide = serialImageRect.Top < 0; if (topSide) { serialImageRect.Top = 0; serialImageRect.Height -= padding; } bottomSide = serialImageRect.Bottom > image.Height; if (bottomSide) { if (topSide) { //Take entire image serialImageRect.Top = 0; serialImageRect.Height = image.Height; } else { //Extra row on top, bottom flush with texture bottom will add extra pixel row on bottom will add extra pixel row on bottom below serialImageRect.Top = image.Height - pageSize - padding; serialImageRect.Height -= padding; } } Parallel.For(0, size, x => //for (int x = 0; x < size; ++x) { bool leftSide, rightSide; IntRect imageRect = serialImageRect; imageRect.Width = fullPageSize.Width; imageRect.Left = x * pageSize - padding; leftSide = imageRect.Left < 0; if (leftSide) { imageRect.Left = 0; imageRect.Width -= padding; } rightSide = imageRect.Right > image.Width; if (rightSide) { if (leftSide) { //Take entire image imageRect.Left = 0; imageRect.Width = image.Width; } else { //Extra row on left, right flush with texture right will add extra pixel row on right below imageRect.Left = image.Width - pageSize - padding; imageRect.Width -= padding; } } using (var pageBox = pages[x].createPixelBox(PixelFormat.PF_A8R8G8B8)) { if (topSide) { pageBox.Top += (uint)padding; } if (bottomSide) { pageBox.Bottom -= (uint)padding; } if (leftSide) { pageBox.Left += (uint)padding; } if (rightSide) { pageBox.Right -= (uint)padding; } using (var imageBox = image.createPixelBox()) { imageBox.Left = (uint)imageRect.Left; imageBox.Right = (uint)imageRect.Right; imageBox.Top = (uint)imageRect.Top; imageBox.Bottom = (uint)imageRect.Bottom; PixelBox.BulkPixelConversion(imageBox, pageBox); } if (topSide) { using (PixelBox altSrcBox = image.createPixelBox()) { pageBox.Top = 0; pageBox.Bottom = (uint)padding; pageBox.Left = (uint)padding; pageBox.Right = (uint)(fullPageSize.Width - padding); altSrcBox.Top = (uint)imageRect.Top; altSrcBox.Bottom = (uint)(imageRect.Top + padding); altSrcBox.Left = (uint)imageRect.Left; altSrcBox.Right = (uint)(imageRect.Left + pageSize); PixelBox.BulkPixelConversion(altSrcBox, pageBox); } } if (bottomSide) { using (PixelBox altSrcBox = image.createPixelBox()) { pageBox.Top = (uint)(fullPageSize.Height - padding); pageBox.Bottom = (uint)fullPageSize.Height; pageBox.Left = (uint)padding; pageBox.Right = (uint)(fullPageSize.Width - padding); altSrcBox.Top = (uint)(imageRect.Bottom - padding); altSrcBox.Bottom = (uint)imageRect.Bottom; altSrcBox.Left = (uint)imageRect.Left; altSrcBox.Right = (uint)(imageRect.Left + pageSize); PixelBox.BulkPixelConversion(altSrcBox, pageBox); } } if (leftSide) { using (PixelBox altSrcBox = image.createPixelBox()) { pageBox.Top = (uint)padding; pageBox.Bottom = (uint)(fullPageSize.Height - padding); pageBox.Left = 0; pageBox.Right = (uint)padding; altSrcBox.Top = (uint)imageRect.Top; altSrcBox.Bottom = (uint)(imageRect.Top + pageSize); altSrcBox.Left = (uint)imageRect.Left; altSrcBox.Right = (uint)(imageRect.Left + padding); PixelBox.BulkPixelConversion(altSrcBox, pageBox); } } if (rightSide) { using (PixelBox altSrcBox = image.createPixelBox()) { pageBox.Top = (uint)padding; pageBox.Bottom = (uint)(fullPageSize.Height - padding); pageBox.Left = (uint)(fullPageSize.Width - padding); pageBox.Right = (uint)fullPageSize.Width; altSrcBox.Top = (uint)imageRect.Top; altSrcBox.Bottom = (uint)(imageRect.Top + pageSize); altSrcBox.Left = (uint)(imageRect.Right - padding); altSrcBox.Right = (uint)imageRect.Right; PixelBox.BulkPixelConversion(altSrcBox, pageBox); } } } //int startPos = (int)stream.Position; pages[x].RotateFlip(RotateFlipType.RotateNoneFlipY); //Have to flip the page over for ogre to be happy pages[x].Save(memoryStreams[x], outputFormat, saveFlags); memoryStreams[x].Position = 0; //++pagedImage.numImages; //pagedImage.pages.Add(new ImageInfo(startPos, (int)(stream.Position))); }); //} for (int x = 0; x < size; ++x) { int startPos = (int)stream.Position; //page.RotateFlip(RotateFlipType.RotateNoneFlipY); //Have to flip the page over for ogre to be happy //page.Save(stream, outputFormat, saveFlags); memoryStreams[x].CopyTo(stream); ++pagedImage.NumImages; pagedImage.Pages.Add(new PagedImage.ImageInfo(startPos, (int)(stream.Position))); memoryStreams[x].Dispose(); memoryStreams[x] = new MemoryStream(); } } } finally { for (int i = 0; i < size; ++i) { memoryStreams[i].Dispose(); pages[i].Dispose(); } } }