readonly int[] sizes; // This stores the sizes of various mip levels #endregion Fields #region Constructors public PageIndexer( VirtualTextureInfo info ) { this.info = info; mipcount = MathExtensions.Log2(info.PageTableSize) + 1; sizes = new int[mipcount]; for( int i = 0; i < mipcount; ++i ) sizes[i] = ( info.VirtualTextureSize / info.TileSize ) >> i; offsets = new int[mipcount]; Count = 0; for( int i = 0; i < mipcount; ++i ) { offsets[i] = Count; Count += sizes[i] * sizes[i]; } // Calculate reverse mapping reverse = new Page[Count]; for( int i = 0; i < mipcount; ++i ) { int size = sizes[i]; for( int y = 0; y < size; ++y ) for( int x = 0; x < size; ++x ) { Page page = new Page( x, y, i ); reverse[this[page]] = page; } } }
public void Add( Page request, Point mapping ) { int scale = 1 << request.Mip; // Same as pow( 2, mip ) int x = request.X * scale; int y = request.Y * scale; Quadtree node = this; while( request.Mip < node.Level ) { for( int i = 0; i < 4; ++i ) { Rectangle rect = GetRectangle( node, i ); if( rect.Contains( x, y ) ) { // Create a new one if needed if( node.Children[i] == null ) { node.Children[i] = new Quadtree( rect, node.Level-1 ); node = node.Children[i]; break; } // Otherwise traverse the tree else { node = node.Children[i]; break; } } } } // We have created the correct node, now set the mapping node.Mapping = mapping; }
public void Remove( Page request ) { int index; Quadtree node = FindPage( this, request, out index ); if( node != null ) node.Children[index] = null; }
static Quadtree FindPage( Quadtree node, Page request, out int index ) { int scale = 1 << request.Mip; // Same as pow( 2, mip ) int x = request.X * scale; int y = request.Y * scale; // Find the parent of the child we want to remove bool exitloop = false; while( !exitloop ) { exitloop = true; for( int i = 0; i < 4; ++i ) { if( node.Children[i] != null && node.Children[i].Rectangle.Contains( x, y ) ) { // We found it if( request.Mip == node.Level-1 ) { index = i; return node; } // Check the children else { node = node.Children[i]; exitloop = false; } } } } // We couldn't find it so it must not exist anymore index = -1; return null; }
// Schedule a load if not already loaded or loading public bool Request( Page request ) { if( !loading.Contains( request ) ) { Point pt = Point.Empty; if( !lru.TryGetValue( request, false, out pt ) ) { loading.Add( request ); loader.Submit( request ); return true; } } return false; }
void LoadComplete( Page page, byte[] data ) { loading.Remove( page ); // Find a place in the atlas for the data Point pt = Point.Empty; if( current == count*count ) pt = lru.RemoveLast(); else { pt = new Point( current % count, current / count ); ++current; if( current == count * count ) Console.WriteLine("Atlas Full, using LRU"); } atlas.UploadPage( pt, data ); lru.Add( page, pt ); // Signal that we added a page Added( page, pt ); }
// Update the pages's position in the lru public bool Touch( Page page ) { if( !loading.Contains( page ) ) { Point pt = Point.Empty; return lru.TryGetValue( page, true, out pt ); } return false; }
public int this[Page page] { get { if( page.Mip < 0 || page.Mip >= mipcount ) throw new Exception( "Page is not valid" ); int offset = offsets[page.Mip]; int stride = sizes[page.Mip]; return offset + page.Y * stride + page.X; } }
public bool IsValid( Page page ) { if( page.Mip < 0 ) { LastError = string.Format( "Mip level smaller than zero ({0}).", page ); return false; } else if( page.Mip >= mipcount ) { LastError = string.Format( "Mip level larger than max ({1}), ({0}).", page, mipcount ); return false; } if( page.X < 0 ) { LastError = string.Format( "X smaller than zero ({0}).", page ); return false; } else if( page.X >= sizes[page.Mip] ) { LastError = string.Format( "X larger than max ({1}), ({0}).", page, sizes[page.Mip] ); return false; } if( page.Y < 0 ) { LastError = string.Format( "Y smaller than zero ({0}).", page ); return false; } else if( page.Y >= sizes[page.Mip] ) { LastError = string.Format( "Y larger than max ({1}), ({0}).", page, sizes[page.Mip] ); return false; } return true; }
public void Submit( Page request ) { ReadState state = new ReadState(); state.Page = request; readthread.Enqueue( state ); #if DEBUG //Console.WriteLine("Requested: {0}", state.Page ); #endif }
void CopyColor( byte[] image, Page request ) { byte[][] colors = { new byte[] { 0, 0, 255, 255 }, new byte[] { 0, 255, 255, 255 }, new byte[] { 255, 0, 0, 255 }, new byte[] { 255, 0, 255, 255 }, new byte[] { 255, 255, 0, 255 }, new byte[] { 64, 64, 192, 255 }, new byte[] { 64, 192, 64, 255 }, new byte[] { 64, 192, 192, 255 }, new byte[] { 192, 64, 64, 255 }, new byte[] { 192, 64, 192, 255 }, new byte[] { 192, 192, 64, 255 }, new byte[] { 0, 255, 0, 255 } }; int pagesize = info.PageSize; for( int y = 0; y < pagesize; ++y ) for( int x = 0; x < pagesize; ++x ) { image[(y*pagesize+x)*VirtualTexture.ChannelCount+0] = colors[request.Mip][0]; image[(y*pagesize+x)*VirtualTexture.ChannelCount+1] = colors[request.Mip][1]; image[(y*pagesize+x)*VirtualTexture.ChannelCount+2] = colors[request.Mip][2]; image[(y*pagesize+x)*VirtualTexture.ChannelCount+3] = colors[request.Mip][3]; } }