/// <summary> /// /// </summary> /// <param name="address0"></param> /// <param name="address1"></param> /// <param name="address2"></param> /// <param name="address3"></param> /// <returns></returns> public bool IsAnyExists(VTAddress address0, VTAddress address1, VTAddress address2, VTAddress address3) { return(pages.Contains(address0) || pages.Contains(address1) || pages.Contains(address2) || pages.Contains(address3)); }
/// <summary> /// Generate one big texture where all textures are presented. /// </summary> void GenerateFallbackImage(BuildContext buildContext, VTTextureTable pageTable, int sourceMipLevel, IStorage storage) { int pageSize = VTConfig.PageSize; int numPages = VTConfig.VirtualPageCount >> sourceMipLevel; int fallbackSize = VTConfig.TextureSize >> sourceMipLevel; Image fallbackImage = new Image(fallbackSize, fallbackSize, Color.Black); for (int pageX = 0; pageX < numPages; pageX++) { for (int pageY = 0; pageY < numPages; pageY++) { var addr = new VTAddress(pageX, pageY, sourceMipLevel); var image = pageTable.LoadPage(addr, storage); for (int x = 0; x < pageSize; x++) { for (int y = 0; y < pageSize; y++) { int u = pageX * pageSize + x; int v = pageY * pageSize + y; fallbackImage.Write(u, v, image.Sample(x, y)); } } } } Image.SaveTga(fallbackImage, storage.OpenWrite("fallback.tga")); }
/// <summary> /// /// </summary> /// <param name="address"></param> /// <param name="storage"></param> /// <param name="tile"></param> public void SaveTile(VTAddress address, IStorage storage, VTTile tile) { var name = address.GetFileNameWithoutExtension("") + ".tile"; tile.Write(storage.OpenWrite(name)); //tile.WriteDebug( storage.OpenWrite(name + ".tga") ); }
/// <summary> /// Creates instance of VTTile /// </summary> public VTTile(VTAddress address) { this.address = address; var size = VTConfig.PageSizeBordered; colorData = new Image(size, size); normalData = new Image(size, size); specularData = new Image(size, size); }
/// <summary> /// /// </summary> /// <param name="address"></param> /// <param name="baseDir"></param> /// <returns></returns> public Image LoadPage(VTAddress address, IStorage storage) { if (pages.Contains(address)) { var path = address.GetFileNameWithoutExtension("C.tga"); var image = Image.LoadTga(storage.OpenRead(path)); return(image); } else { return(new Image(VTConfig.PageSize, VTConfig.PageSize, Color.Black)); } }
/// <summary> /// /// </summary> /// <param name="context"></param> /// <param name="pageTable"></param> public void SplitIntoPages(BuildContext context, VTTextureTable pageTable, IStorage storage) { var pageSize = VTConfig.PageSize; var pageSizeBorder = VTConfig.PageSizeBordered; var border = VTConfig.PageBorderWidth; var colorMap = LoadTexture(BaseColor, Color.Gray); var normalMap = LoadTexture(NormalMap, Color.FlatNormals); var roughness = LoadTexture(Roughness, Color.Black); var metallic = LoadTexture(Metallic, Color.Black); var emission = LoadTexture(Emission, Color.Black); var pageCountX = colorMap.Width / pageSize; var pageCountY = colorMap.Height / pageSize; for (int x = 0; x < pageCountX; x++) { for (int y = 0; y < pageCountY; y++) { var pageC = new Image(pageSizeBorder, pageSizeBorder); var pageN = new Image(pageSizeBorder, pageSizeBorder); var pageS = new Image(pageSizeBorder, pageSizeBorder); for (int i = 0; i < pageSizeBorder; i++) { for (int j = 0; j < pageSizeBorder; j++) { int srcX = x * pageSize + i - border; int srcY = y * pageSize + j - border; var c = colorMap.SampleClamp(srcX, srcY); var n = normalMap.SampleClamp(srcX, srcY); var r = roughness.SampleClamp(srcX, srcY).R; var m = metallic.SampleClamp(srcX, srcY).R; var e = emission.SampleClamp(srcX, srcY).R; pageC.Write(i, j, c); pageN.Write(i, j, n); pageS.Write(i, j, new Color(r, m, e, (byte)255)); } } var address = new VTAddress((short)(x + AddressX), (short)(y + AddressY), 0); var tile = new VTTile(address, pageC, pageN, pageS); pageTable.SaveTile(address, storage, tile); } } }
/// <summary> /// /// </summary> /// <param name="texelX"></param> /// <param name="texelY"></param> /// <param name="mipLevel"></param> /// <returns></returns> void SampleMegatextureQ4(TileSamplerCache cache, int texelX, int texelY, int mipLevel, ref Color a, ref Color b, ref Color c) { int textureSize = VTConfig.TextureSize >> mipLevel; texelX = MathUtil.Clamp(0, texelX, textureSize); texelY = MathUtil.Clamp(0, texelY, textureSize); int pageX = texelX / VTConfig.PageSize; int pageY = texelY / VTConfig.PageSize; int x = texelX % VTConfig.PageSize; int y = texelY % VTConfig.PageSize; int pbw = VTConfig.PageBorderWidth; var address = new VTAddress(pageX, pageY, mipLevel); cache.LoadImage(address).SampleQ4(x + pbw, y + pbw, ref a, ref b, ref c); }
/// <summary> /// Create instance of tile from three images. Images must be the same size and has equal width and height. /// Width and height must be equal VTConfig.PageBorderWidth /// </summary> /// <param name="a"></param> /// <param name="b"></param> /// <param name="c"></param> public VTTile(VTAddress address, Image a, Image b, Image c) { this.address = address; if (a.Width != a.Height && a.Width != VTConfig.PageSizeBordered) { throw new ArgumentException("Image width and height must be equal " + VTConfig.PageBorderWidth); } if (b.Width != a.Height && b.Width != VTConfig.PageSizeBordered) { throw new ArgumentException("Image width and height must be equal " + VTConfig.PageBorderWidth); } if (c.Width != a.Height && c.Width != VTConfig.PageSizeBordered) { throw new ArgumentException("Image width and height must be equal " + VTConfig.PageBorderWidth); } colorData = a; normalData = b; specularData = c; }
/// <summary> /// /// </summary> /// <param name="address"></param> /// <returns></returns> public VTTile LoadImage(VTAddress address) { VTTile tile; if (!cache.TryGetValue(address, out tile)) { var path = address.GetFileNameWithoutExtension(".tile"); if (storage.FileExists(path)) { tile = new VTTile(address); tile.Read(storage.OpenFile(path, FileMode.Open, FileAccess.Read)); } else { tile = new VTTile(address); tile.Clear(Color.Black); } cache.Add(address, tile); } return(tile); }
/// <summary> /// http://d.hatena.ne.jp/hanecci/20140218/p3 /// </summary> /// <returns></returns> public void GetFeedback(VTAddress[] feedbackData) { if (feedbackData == null) { throw new ArgumentNullException("feedbackData"); } if (feedbackData.Length < linearSize) { throw new ArgumentException("feedbackData.Length < " + linearSize.ToString()); } GetData(feedbackDataRaw); for (int i = 0; i < linearSize; i++) { var vaRaw = MathUtil.UnpackRGB10A2(feedbackDataRaw[i]); var pageX = (short)vaRaw.X; var pageY = (short)vaRaw.Y; var mipLevel = (short)vaRaw.Z; feedbackData[i] = new VTAddress(pageX, pageY, mipLevel); } }
/// <summary> /// /// </summary> /// <param name="address"></param> /// <param name="baseDir"></param> /// <param name="image"></param> public void SavePage(VTAddress address, IStorage storage, Image image, string postFix) { var name = address.GetFileNameWithoutExtension(postFix) + ".tga"; Image.SaveTga(image, storage.OpenWrite(name)); }
/// <summary> /// Generates mip levels for all tiles. /// </summary> /// <param name="buildContext"></param> /// <param name="pageTable"></param> /// <param name="sourceMipLevel"></param> /// <param name="mapStorage"></param> void GenerateMipLevels(BuildContext buildContext, VTTextureTable pageTable, int sourceMipLevel, IStorage mapStorage) { if (sourceMipLevel >= VTConfig.MipCount) { throw new ArgumentOutOfRangeException("mipLevel"); } //int count = VTConfig.VirtualPageCount >> sourceMipLevel; int sizeB = VTConfig.PageSizeBordered; var cache = new TileSamplerCache(mapStorage); foreach (var vttex in pageTable.SourceTextures) { if (!vttex.TilesDirty) { continue; } int startX = RoundDown2(vttex.AddressX, sourceMipLevel); int startY = RoundDown2(vttex.AddressY, sourceMipLevel); int wTiles = (vttex.Width / VTConfig.PageSize); int hTiles = (vttex.Width / VTConfig.PageSize); int endExX = RoundUp2(vttex.AddressX + wTiles, sourceMipLevel); int endExY = RoundUp2(vttex.AddressY + hTiles, sourceMipLevel); for (int pageX = startX; pageX < endExX; pageX += 2) { for (int pageY = startY; pageY < endExY; pageY += 2) { var address00 = new VTAddress(pageX + 0, pageY + 0, sourceMipLevel); var address01 = new VTAddress(pageX + 0, pageY + 1, sourceMipLevel); var address10 = new VTAddress(pageX + 1, pageY + 0, sourceMipLevel); var address11 = new VTAddress(pageX + 1, pageY + 1, sourceMipLevel); // there are no images touching target mip-level. // NOTE: we can skip images that are touched by border. //if ( !pageTable.IsAnyExists( address00, address01, address10, address11 ) ) { // continue; //} var address = new VTAddress(pageX / 2, pageY / 2, sourceMipLevel + 1); var tile = new VTTile(address); var offsetX = (pageX) * VTConfig.PageSize; var offsetY = (pageY) * VTConfig.PageSize; var border = VTConfig.PageBorderWidth; var colorValue = Color.Zero; var normalValue = Color.Zero; var specularValue = Color.Zero; for (int x = 0; x < sizeB; x++) { for (int y = 0; y < sizeB; y++) { int srcX = offsetX + x * 2 - border * 2; int srcY = offsetY + y * 2 - border * 2; SampleMegatextureQ4(cache, srcX, srcY, sourceMipLevel, ref colorValue, ref normalValue, ref specularValue); tile.SetValues(x, y, ref colorValue, ref normalValue, ref specularValue); } } pageTable.SaveTile(address, mapStorage, tile); } } } }