public override TexturePageHandle createTexturePageHandle(VTexPage page, IndirectionTexture indirectionTexture, int padding, int padding2, int textelsPerPage, int mipOffset) { PixelBox sourceBox; int mipCount = image.NumMipmaps; if (mipCount == 0) //We always have to take from the largest size { sourceBox = image.getPixelBox(0, 0); } else { sourceBox = image.getPixelBox(0, (uint)(page.mip - mipOffset)); } IntSize2 largestSupportedPageIndex = indirectionTexture.NumPages; largestSupportedPageIndex.Width >>= page.mip; largestSupportedPageIndex.Height >>= page.mip; if (page.x != 0 && page.y != 0 && page.x + 1 != largestSupportedPageIndex.Width && page.y + 1 != largestSupportedPageIndex.Height) { //Can grab a complete page from the texture sourceBox.Rect = new IntRect(page.x * textelsPerPage - padding, page.y * textelsPerPage - padding, textelsPerPage + padding2, textelsPerPage + padding2); } else { //Have to get a partial page sourceBox.Rect = new IntRect(page.x * textelsPerPage, page.y * textelsPerPage, textelsPerPage, textelsPerPage); } return(new TexturePageHandle(sourceBox, this)); }
private void fillOutLowerMips(VTexPage vTextPage, IntColor color, Func <IntColor, IntColor, bool> writePixel) { //Fill in lower (more textels) mip levels uint x = vTextPage.x; uint y = vTextPage.y; uint w = 1; uint h = 1; IntColor readPixel = new IntColor(); for (int i = vTextPage.mip - 1; i >= 0; --i) { //This is probably really slow x = x << 1; y = y << 1; w = w << 1; h = h << 1; var mipLevelBitmap = fiBitmap[i]; for (uint xi = 0; xi < w; ++xi) { for (uint yi = 0; yi < h; ++yi) { readPixel.ARGB = mipLevelBitmap.getColorAtARGB(x + xi, y + yi, 0); if (writePixel.Invoke(color, readPixel)) { mipLevelBitmap.setColorAtARGB(color.ARGB, x + xi, y + yi, 0); } } } } }
public override TexturePageHandle createTexturePageHandle(VTexPage page, IndirectionTexture indirectionTexture, int padding, int padding2, int textelsPerPage, int mipOffset) { int mip = page.mip; int x = page.x; int y = page.y; bool halfSizePages = textelsPerPage != pagedImage.PageSize; if (halfSizePages) { x /= 2; y /= 2; } var image = pagedImage.getImage(x, y, mip - mipOffset); var pixelBox = image.getPixelBox(); if (halfSizePages && image.Width == pagedImage.PageSize + padding2) { int subpageX = page.x % 2; int subpageY = page.y % 2; int offsetMultiple = (int)image.Width / 2 - padding; int halfSize = textelsPerPage + padding2; pixelBox.Rect = new Engine.IntRect(offsetMultiple * subpageX, offsetMultiple * subpageY, halfSize, halfSize); } return(new TexturePageHandle(pixelBox, this, image)); }
private bool copyToStaging(VTexPage page, StagingBufferSet buffers, IndirectionTexture indirectionTexture, OriginalTextureInfo textureUnit) { bool usedPhysicalPage = false; try { if (page.mip >= textureUnit.MipOffset) { //Load or grab from cache using (var pageHandle = textureCache.getImage(page, indirectionTexture, textureUnit, textelsPerPage, padding, padding2)) { buffers.setPhysicalPage(pageHandle.PixelBox, virtualTextureManager.getPhysicalTexture(textureUnit.TextureUnit), padding); usedPhysicalPage = true; } } else { Logging.Log.Warning("Unable to load mip map level {0} for texture {1}", page.mip - textureUnit.MipOffset, textureUnit.TextureFileName); } } catch (Exception ex) { Logging.Log.Error("{0} loading image {1}. Message: {2}", ex.GetType().Name, textureUnit.TextureFileName, ex.Message); } return(usedPhysicalPage); }
internal void processPage(float u, float v, byte mip) { ++numRequests; VTexPage page; if (mip >= highestMip) { page = new VTexPage(0, 0, (byte)(highestMip - 1), id); } else { IntSize2 mipLevelNumPages = numPages / (1 << mip); byte x = (byte)(u * mipLevelNumPages.Width); byte y = (byte)(v * mipLevelNumPages.Height); if (x == mipLevelNumPages.Width) { --x; } if (y == mipLevelNumPages.Height) { --y; } page = new VTexPage(x, y, mip, id); } if (activePages.Contains(page)) { visibleThisUpdate.Add(page); } else { addedPages.Add(page); } }
public override bool Equals(object obj) { VTexPage other = obj as VTexPage; if (other != null) { return(this.hashCode == other.hashCode); } return(false); }
private bool loadPage(VTexPage page, StagingBufferSet stagingBuffers) { bool added = false; try { //First see if we still have that page in our virtual texture pool, possible optimization to sort these to the front of the list if (physicalPageQueue.Count > 0) //Do we have pages available { PTexPage pTexPage = physicalPageQueue[0]; //The physical page candidate, do not modify before usedPhysicalPages if statement below if (loadImages(page, pTexPage, stagingBuffers)) { //Alert old texture of removal if there was one, Do not modify pTexPage above this if block, we need the old data IndirectionTexture oldIndirectionTexture = null; if (pTexPage.VirtualTexturePage != null) { if (virtualTextureManager.getIndirectionTexture(pTexPage.VirtualTexturePage.indirectionTexId, out oldIndirectionTexture)) { oldIndirectionTexture.removePhysicalPage(pTexPage); } physicalPagePool.Remove(pTexPage.VirtualTexturePage); //Be sure to remove the page from the pool if it was used previously } physicalPageQueue.RemoveAt(0); pTexPage.VirtualTexturePage = page; usedPhysicalPages.Add(page, pTexPage); //Add to new indirection texture IndirectionTexture newIndirectionTex; if (virtualTextureManager.getIndirectionTexture(page.indirectionTexId, out newIndirectionTex)) { newIndirectionTex.addPhysicalPage(pTexPage); stagingBuffers.setIndirectionTextures(oldIndirectionTexture, newIndirectionTex); } added = true; } } } catch (Exception ex) { Logging.Log.Debug("{0} loading page {1}. Message: {2}", ex.GetType().Name, page.ToString(), ex.Message); } return(added); }
/// <summary> /// Load the given image. Note that pTexPage is constant for the duration of this function call /// </summary> /// <param name="page"></param> /// <param name="pTexPage"></param> /// <returns></returns> private bool loadImages(VTexPage page, PTexPage pTexPage, StagingBufferSet stagingBuffers) { int stagingImageIndex = 0; bool usedPhysicalPage = false; IndirectionTexture indirectionTexture; if (virtualTextureManager.getIndirectionTexture(page.indirectionTexId, out indirectionTexture)) { //Fire off image loading and blitting tasks foreach (var textureUnit in indirectionTexture.OriginalTextures) { copyTostagingImageTasks[stagingImageIndex] = fireCopyToStaging(page, stagingBuffers, indirectionTexture, textureUnit); ++stagingImageIndex; } //Wait for results for (int i = 0; i < stagingImageIndex; ++i) { copyTostagingImageTasks[i].Wait(); if (copyTostagingImageTasks[i].Result) { usedPhysicalPage = true; } } //Single threaded //foreach (var textureUnit in indirectionTexture.OriginalTextures) //{ // if (copyToStaging(page, stagingBuffers, indirectionTexture, textureUnit)) // { // usedPhysicalPage = true; // } //} //Update staging buffer info stagingBuffers.Dest = new IntRect(pTexPage.x, pTexPage.y, textelsPerPhysicalPage, textelsPerPhysicalPage); } return(usedPhysicalPage); }
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)); }
private Task <bool> fireCopyToStaging(VTexPage page, StagingBufferSet buffers, IndirectionTexture indirectionTexture, OriginalTextureInfo textureUnit) { return(Task.Run(() => copyToStaging(page, buffers, indirectionTexture, textureUnit))); }
public void removeRequestedPage(VTexPage page) { addedPages.Remove(page); removedPages.Add(page); }
public void addRequestedPage(VTexPage page) { addedPages.Add(page); }
/// <summary> /// Create a texture page handle for this cache handle, the page will be selected from the given info. /// You must dispose the handle that is returned. /// </summary> /// <param name="page"></param> /// <param name="indirectionTexture"></param> /// <param name="padding"></param> /// <param name="padding2"></param> /// <param name="textelsPerPage"></param> /// <returns></returns> public abstract TexturePageHandle createTexturePageHandle(VTexPage page, IndirectionTexture indirectionTexture, int padding, int padding2, int textelsPerPage, int mipOffset);