private void ExportDds(string filename, NutTexture tex) { Dds dds = new Dds(); dds.FromNutTexture(tex); dds.Save(filename); }
private void SetGeneralAndDimensionsText(NutTexture tex) { textureIdTB.Text = tex.ToString(); formatLabel.Text = "Format: " + (tex.pixelInternalFormat == PixelInternalFormat.Rgba ? "" + tex.pixelFormat : "" + tex.pixelInternalFormat); widthLabel.Text = "Width: " + tex.Width; heightLabel.Text = "Height:" + tex.Height; }
private void ExportPng(string filename, NutTexture tex) { if (tex.surfaces[0].mipmaps.Count > 1) { MessageBox.Show("Note: Textures exported as PNG do not preserve mipmaps."); } switch (tex.pixelFormat) { case OpenTK.Graphics.OpenGL.PixelFormat.Rgba: Pixel.fromRGBA(new FileData(tex.surfaces[0].mipmaps[0]), tex.Width, tex.Height).Save(filename); break; case OpenTK.Graphics.OpenGL.PixelFormat.AbgrExt: Pixel.fromABGR(new FileData(tex.surfaces[0].mipmaps[0]), tex.Width, tex.Height).Save(filename); break; case OpenTK.Graphics.OpenGL.PixelFormat.Bgra: Pixel.fromBGRA(new FileData(tex.surfaces[0].mipmaps[0]), tex.Width, tex.Height).Save(filename); break; default: RenderTextureToPng(tex, filename, true, true, true, true); break; } }
private void ImportBack(string filename) { if (dontModify) { return; } NutTexture tex = textureFromFile[filename]; try { Dds dds = new Dds(new FileData(filename)); NutTexture ntex = dds.ToNutTexture(); tex.Height = ntex.Height; tex.Width = ntex.Width; tex.pixelInternalFormat = ntex.pixelInternalFormat; tex.surfaces = ntex.surfaces; tex.pixelFormat = ntex.pixelFormat; //GL.DeleteTexture(NUT.glTexByHashId[tex.HASHID]); currentNut.glTexByHashId.Remove(tex.HashId); currentNut.glTexByHashId.Add(tex.HashId, NUT.CreateTexture2D(tex)); FillForm(); textureListBox.SelectedItem = tex; glControl1.Invalidate(); } catch { Console.WriteLine("Could not be open for editing"); } }
public static Texture2D CreateTexture2D(NutTexture nutTexture, int surfaceIndex = 0) { bool compressedFormatWithMipMaps = TextureFormatTools.IsCompressed(nutTexture.pixelInternalFormat); List <byte[]> mipmaps = nutTexture.surfaces[surfaceIndex].mipmaps; if (compressedFormatWithMipMaps) { // HACK: Skip loading mipmaps for non square textures for now. // The existing mipmaps don't display properly for some reason. if (nutTexture.surfaces[0].mipmaps.Count > 1 && nutTexture.isDds && (nutTexture.Width == nutTexture.Height)) { // Reading mipmaps past the first level is only supported for DDS currently. Texture2D texture = new Texture2D(); texture.LoadImageData(nutTexture.Width, nutTexture.Height, nutTexture.surfaces[surfaceIndex].mipmaps, (InternalFormat)nutTexture.pixelInternalFormat); return(texture); } else { // Only load the first level and generate the rest. Texture2D texture = new Texture2D(); texture.LoadImageData(nutTexture.Width, nutTexture.Height, mipmaps[0], (InternalFormat)nutTexture.pixelInternalFormat); return(texture); } } else { // Uncompressed. Texture2D texture = new Texture2D(); texture.LoadImageData(nutTexture.Width, nutTexture.Height, mipmaps[0], new TextureFormatUncompressed(nutTexture.pixelInternalFormat, nutTexture.pixelFormat, nutTexture.pixelType)); return(texture); } }
public static void RegenerateMipmapsFromTexture2D(NutTexture tex) { if (!TextureFormatTools.IsCompressed(tex.pixelInternalFormat)) { return; } Rendering.OpenTkSharedResources.dummyResourceWindow.MakeCurrent(); // Create an OpenGL texture with generated mipmaps. Texture2D texture2D = new Texture2D(); texture2D.LoadImageData(tex.Width, tex.Height, tex.surfaces[0].mipmaps[0], (InternalFormat)tex.pixelInternalFormat); texture2D.Bind(); for (int i = 0; i < tex.surfaces[0].mipmaps.Count; i++) { // Get the image size for the current mip level of the bound texture. int imageSize; GL.GetTexLevelParameter(TextureTarget.Texture2D, i, GetTextureParameter.TextureCompressedImageSize, out imageSize); byte[] mipLevelData = new byte[imageSize]; // Replace the Nut texture with the OpenGL texture's data. GL.GetCompressedTexImage(TextureTarget.Texture2D, i, mipLevelData); tex.surfaces[0].mipmaps[i] = mipLevelData; } }
private void SetCubeMapText(NutTexture tex) { // Display the current face instead of mip map information. mipmapGroupBox.Text = "Cube Map Faces"; SetCurrentCubeMapFaceLabel(mipLevelTrackBar.Value); mipLevelTrackBar.Maximum = tex.surfaces.Count - 1; minMipLevelLabel.Text = ""; maxMipLevelLabel.Text = ""; }
private void RemoveToolStripMenuItem1_Click_1(object sender, EventArgs e) { if (textureListBox.SelectedIndex >= 0 && currentNut != null) { NutTexture tex = ((NutTexture)textureListBox.SelectedItem); currentNut.glTexByHashId.Remove(tex.HashId); currentNut.Nodes.Remove(tex); FillForm(); } }
public bool getTextureByID(int hash, out NutTexture suc) { suc = null; foreach (NutTexture t in Nodes) { if (t.HashId == hash) { suc = t; return(true); } } return(false); }
private void SetMipMapText(NutTexture tex) { // Display the total mip maps. mipmapGroupBox.Text = "Mipmaps"; mipLevelLabel.Text = "Mip Level"; mipLevelTrackBar.Maximum = tex.surfaces[0].mipmaps.Count - 1; int newMipLevel = Math.Min(currentMipLevel, mipLevelTrackBar.Maximum); mipLevelTrackBar.Value = newMipLevel; minMipLevelLabel.Text = "1"; maxMipLevelLabel.Text = "Total:" + tex.surfaces[0].mipmaps.Count + ""; }
private void replaceToolStripMenuItem_Click(object sender, EventArgs e) { if (currentNut == null || textureListBox.SelectedItem == null) { return; } using (var ofd = new OpenFileDialog()) { NutTexture texture = (NutTexture)(textureListBox.SelectedItem); ofd.Filter = "Supported Formats|*.dds;*.png|" + "DirectDraw Surface (.dds)|*.dds|" + "Portable Network Graphics (.png)|*.png|" + "All files(*.*)|*.*"; if (ofd.ShowDialog() == DialogResult.OK) { NutTexture newTexture = null; string extension = Path.GetExtension(ofd.FileName).ToLowerInvariant(); if (extension == ".dds") { Dds dds = new Dds(new FileData(ofd.FileName)); newTexture = dds.ToNutTexture(); } else if (extension == ".png") { newTexture = FromPng(ofd.FileName, 1); } else { return; } texture.Height = newTexture.Height; texture.Width = newTexture.Width; texture.pixelInternalFormat = newTexture.pixelInternalFormat; texture.surfaces = newTexture.surfaces; texture.pixelFormat = newTexture.pixelFormat; Edited = true; //GL.DeleteTexture(NUT.glTexByHashId[texture.HASHID]); currentNut.glTexByHashId.Remove(texture.HashId); currentNut.glTexByHashId.Add(texture.HashId, NUT.CreateTexture2D(texture)); FillForm(); } } }
private void RenderTextureToPng(NutTexture nutTexture, string outputPath, bool r = true, bool g = true, bool b = true, bool a = false) { if (OpenTkSharedResources.SetupStatus != OpenTkSharedResources.SharedResourceStatus.Initialized || glControl1 == null) { return; } // Load the OpenGL texture and export the image data. Texture2D texture = (Texture2D)currentNut.glTexByHashId[nutTexture.HashId]; using (Bitmap image = Rendering.TextureToBitmap.RenderBitmap(texture, r, g, b, a)) { image.Save(outputPath); } }
private void mipLevelTrackBar_Scroll(object sender, EventArgs e) { NutTexture tex = ((NutTexture)textureListBox.SelectedItem); if (tex.surfaces.Count == 6) { // Create a new texture for the selected surface at the first mip level. currentMipLevel = 0; SetCurrentCubeMapFaceLabel(mipLevelTrackBar.Value); textureToRender = NUT.CreateTexture2D(tex, mipLevelTrackBar.Value); } else { // Regular texture. currentMipLevel = mipLevelTrackBar.Value; } glControl1.Invalidate(); }
private void exportTextureToolStripMenuItem_Click(object sender, EventArgs e) { if (currentNut == null || textureListBox.SelectedItem == null) { return; } using (var sfd = new SaveFileDialog()) { NutTexture tex = (NutTexture)(textureListBox.SelectedItem); sfd.FileName = tex.ToString() + ".dds"; // OpenGL is used for simplifying conversion to PNG. if (OpenTkSharedResources.SetupStatus == OpenTkSharedResources.SharedResourceStatus.Initialized) { sfd.Filter = "Supported Formats|*.dds;*.png|" + "DirectDraw Surface (.dds)|*.dds|" + "Portable Network Graphics (.png)|*.png|" + "All files(*.*)|*.*"; } else { sfd.Filter = "DirectDraw Surface (.dds)|*.dds|" + "All files(*.*)|*.*"; } if (sfd.ShowDialog() == DialogResult.OK) { string extension = Path.GetExtension(sfd.FileName).ToLowerInvariant(); if (extension == ".dds") { ExportDds(sfd.FileName, tex); } else if (extension == ".png") { ExportPng(sfd.FileName, tex); } } } }
public void ConvertToDdsNut(bool regenerateMipMaps = true) { for (int i = 0; i < Nodes.Count; i++) { NutTexture originalTexture = (NutTexture)Nodes[i]; // Reading/writing mipmaps is only supported for DDS textures, // so we will need to convert all the textures. Dds dds = new Dds(originalTexture); NutTexture ddsTexture = dds.ToNutTexture(); ddsTexture.HashId = originalTexture.HashId; if (regenerateMipMaps) { RegenerateMipmapsFromTexture2D(ddsTexture); } Nodes[i] = ddsTexture; } }
public static TextureCubeMap CreateTextureCubeMap(NutTexture t) { if (TextureFormatTools.IsCompressed(t.pixelInternalFormat)) { // Compressed cubemap with mipmaps. TextureCubeMap texture = new TextureCubeMap(); texture.LoadImageData(t.Width, (InternalFormat)t.pixelInternalFormat, t.surfaces[0].mipmaps, t.surfaces[1].mipmaps, t.surfaces[2].mipmaps, t.surfaces[3].mipmaps, t.surfaces[4].mipmaps, t.surfaces[5].mipmaps); return(texture); } else { // Uncompressed cube map with no mipmaps. TextureCubeMap texture = new TextureCubeMap(); texture.LoadImageData(t.Width, new TextureFormatUncompressed(t.pixelInternalFormat, t.pixelFormat, t.pixelType), t.surfaces[0].mipmaps[0], t.surfaces[1].mipmaps[0], t.surfaces[2].mipmaps[0], t.surfaces[3].mipmaps[0], t.surfaces[4].mipmaps[0], t.surfaces[5].mipmaps[0]); return(texture); } }
private void RegenerateMipMaps_Click(object sender, EventArgs e) { if (OpenTkSharedResources.SetupStatus != OpenTkSharedResources.SharedResourceStatus.Initialized) { return; } if (textureListBox.SelectedItem != null) { NutTexture tex = ((NutTexture)textureListBox.SelectedItem); NUT.RegenerateMipmapsFromTexture2D(tex); // Render the selected texture again. currentNut.RefreshGlTexturesByHashId(); if (currentNut.glTexByHashId.ContainsKey(tex.HashId)) { textureToRender = currentNut.glTexByHashId[tex.HashId]; } glControl1.Invalidate(); } }
public static NutTexture FromPng(string fname, int mipcount) { Bitmap bmp = new Bitmap(fname); NutTexture tex = new NutTexture(); tex.surfaces.Add(new TextureSurface()); tex.surfaces[0].mipmaps.Add(FromPng(bmp)); for (int i = 1; i < mipcount; i++) { if (bmp.Width / (int)Math.Pow(2, i) < 4 || bmp.Height / (int)Math.Pow(2, i) < 4) { break; } tex.surfaces[0].mipmaps.Add(FromPng(Pixel.ResizeImage(bmp, bmp.Width / (int)Math.Pow(2, i), bmp.Height / (int)Math.Pow(2, i)))); } tex.Width = bmp.Width; tex.Height = bmp.Height; tex.pixelInternalFormat = PixelInternalFormat.Rgba; tex.pixelFormat = OpenTK.Graphics.OpenGL.PixelFormat.Rgba; return(tex); }
private void textureListBox_SelectedIndexChanged(object sender, EventArgs e) { if (textureListBox.SelectedIndex >= 0) { NutTexture tex = ((NutTexture)textureListBox.SelectedItem); if (tex == null) { return; } // Render the selected texture. if (currentNut.glTexByHashId.ContainsKey(tex.HashId)) { textureToRender = currentNut.glTexByHashId[tex.HashId]; } SetGeneralAndDimensionsText(tex); if (tex.surfaces.Count == 6) { SetCubeMapText(tex); if (OpenTkSharedResources.SetupStatus == OpenTkSharedResources.SharedResourceStatus.Initialized) { RenderTools.dummyTextures[Filetypes.Models.Nuds.NudEnums.DummyTexture.StageMapHigh] = NUT.CreateTextureCubeMap(tex); } } else { SetMipMapText(tex); } } else { SetDefaultGeneralAndDimensionsText(); } // Render on index changed rather than every frame. glControl1.Invalidate(); }
private NUT ReplaceTexture(NutTexture tex, int width, int height, NUT nut) { if (tex.Width == width && tex.Height == height) { tex.HashId = 0x280052B7; if (nut != null && nut.Nodes.Count > 0) { tex.HashId = ((NutTexture)nut.Nodes[0]).HashId; } if (nut == null) { nut = new NUT(); } nut.Nodes.Clear(); nut.glTexByHashId.Clear(); nut.Nodes.Add(tex); nut.glTexByHashId.Add(tex.HashId, NUT.CreateTexture2D(tex)); } else { MessageBox.Show("Dimensions must be " + width + "x" + height); } return(nut); }
public void ReadNTP3(FileData d) { d.Seek(0x6); ushort count = d.ReadUShort(); d.Skip(0x8); int headerPtr = 0x10; for (ushort i = 0; i < count; ++i) { d.Seek(headerPtr); NutTexture tex = new NutTexture(); tex.isDds = true; tex.pixelInternalFormat = PixelInternalFormat.Rgba32ui; int totalSize = d.ReadInt(); d.Skip(4); int dataSize = d.ReadInt(); int headerSize = d.ReadUShort(); d.Skip(2); //It might seem that mipmapCount and pixelFormat would be shorts, but they're bytes because they stay in the same place regardless of endianness d.Skip(1); byte mipmapCount = d.ReadByte(); d.Skip(1); tex.setPixelFormatFromNutFormat(d.ReadByte()); tex.Width = d.ReadUShort(); tex.Height = d.ReadUShort(); d.Skip(4); //0 in dds nuts (like NTP3) and 1 in gtx nuts; texture type? uint caps2 = d.ReadUInt(); bool isCubemap = false; byte surfaceCount = 1; if ((caps2 & (uint)Dds.Ddscaps2.Cubemap) == (uint)Dds.Ddscaps2.Cubemap) { //Only supporting all six faces if ((caps2 & (uint)Dds.Ddscaps2.CubemapAllfaces) == (uint)Dds.Ddscaps2.CubemapAllfaces) { isCubemap = true; surfaceCount = 6; } else { throw new NotImplementedException($"Unsupported cubemap face amount for texture {i} with hash 0x{tex.HashId:X}. Six faces are required."); } } int dataOffset = 0; if (Version < 0x0200) { dataOffset = headerPtr + headerSize; d.ReadInt(); } else if (Version >= 0x0200) { dataOffset = d.ReadInt() + headerPtr; } d.ReadInt(); d.ReadInt(); d.ReadInt(); //The size of a single cubemap face (discounting mipmaps). I don't know why it is repeated. If mipmaps are present, this is also specified in the mipSize section anyway. int cmapSize1 = 0; int cmapSize2 = 0; if (isCubemap) { cmapSize1 = d.ReadInt(); cmapSize2 = d.ReadInt(); d.Skip(8); } int[] mipSizes = new int[mipmapCount]; if (mipmapCount == 1) { if (isCubemap) { mipSizes[0] = cmapSize1; } else { mipSizes[0] = dataSize; } } else { for (byte mipLevel = 0; mipLevel < mipmapCount; ++mipLevel) { mipSizes[mipLevel] = d.ReadInt(); } d.Align(0x10); } d.Skip(0x10); //eXt data - always the same d.Skip(4); //GIDX d.ReadInt(); //Always 0x10 tex.HashId = d.ReadInt(); d.Skip(4); // padding align 8 for (byte surfaceLevel = 0; surfaceLevel < surfaceCount; ++surfaceLevel) { TextureSurface surface = new TextureSurface(); for (byte mipLevel = 0; mipLevel < mipmapCount; ++mipLevel) { byte[] texArray = d.GetSection(dataOffset, mipSizes[mipLevel]); surface.mipmaps.Add(texArray); dataOffset += mipSizes[mipLevel]; } tex.surfaces.Add(surface); } if (tex.getNutFormat() == 14 || tex.getNutFormat() == 17) { tex.SwapChannelOrderUp(); } if (Version < 0x0200) { headerPtr += totalSize; } else if (Version >= 0x0200) { headerPtr += headerSize; } Nodes.Add(tex); } }
public void FromNutTexture(NutTexture tex) { header = new Header(); header.flags = (uint)(Ddsd.Caps | Ddsd.Height | Ddsd.Width | Ddsd.Pixelformat | Ddsd.Mipmapcount | Ddsd.Linearsize); header.width = (uint)tex.Width; header.height = (uint)tex.Height; header.pitchOrLinearSize = (uint)tex.ImageSize; header.mipmapCount = (uint)tex.surfaces[0].mipmaps.Count; header.caps2 = tex.DdsCaps2; bool isCubemap = (header.caps2 & (uint)Ddscaps2.Cubemap) == (uint)Ddscaps2.Cubemap; header.caps = (uint)Ddscaps.Texture; if (header.mipmapCount > 1) { header.caps |= (uint)(Ddscaps.Complex | Ddscaps.Mipmap); } if (isCubemap) { header.caps |= (uint)Ddscaps.Complex; } switch (tex.pixelInternalFormat) { case PixelInternalFormat.CompressedRgbaS3tcDxt1Ext: header.ddspf.fourCc = 0x31545844; header.ddspf.flags = (uint)Ddpf.Fourcc; break; case PixelInternalFormat.CompressedRgbaS3tcDxt3Ext: header.ddspf.fourCc = 0x33545844; header.ddspf.flags = (uint)Ddpf.Fourcc; break; case PixelInternalFormat.CompressedRgbaS3tcDxt5Ext: header.ddspf.fourCc = 0x35545844; header.ddspf.flags = (uint)Ddpf.Fourcc; break; case PixelInternalFormat.CompressedRedRgtc1: header.ddspf.fourCc = 0x31495441; header.ddspf.flags = (uint)Ddpf.Fourcc; break; case PixelInternalFormat.CompressedRgRgtc2: header.ddspf.fourCc = 0x32495441; header.ddspf.flags = (uint)Ddpf.Fourcc; break; case PixelInternalFormat.Rgba: header.ddspf.fourCc = 0x00000000; if (tex.pixelFormat == OpenTK.Graphics.OpenGL.PixelFormat.Rgba) { header.ddspf.flags = (uint)(Ddpf.Rgb | Ddpf.Alphapixels); header.ddspf.rgbBitCount = 0x8 * 4; header.ddspf.rBitMask = 0x000000FF; header.ddspf.gBitMask = 0x0000FF00; header.ddspf.bBitMask = 0x00FF0000; header.ddspf.aBitMask = 0xFF000000; } break; default: throw new NotImplementedException($"Unknown pixel format 0x{tex.pixelInternalFormat:X}"); } List <byte> d = new List <byte>(); foreach (byte[] b in tex.GetAllMipmaps()) { d.AddRange(b); } bdata = d.ToArray(); }
private void LetsDance(object sender, EventArgs e) { Control c = MainForm.Instance.GetActiveModelViewport(); if (!(c is ModelViewport)) { return; } ModelViewport view = (ModelViewport)c; view.currentMode = ModelViewport.Mode.Normal; NUT n = null; if (((MenuItem)sender).GetContextMenu().SourceControl == stock_90_renderer) { n = stock90; } if (((MenuItem)sender).GetContextMenu().SourceControl == chr_00_renderer) { n = chr00; } if (((MenuItem)sender).GetContextMenu().SourceControl == chr_11_renderer) { n = chr11; } if (((MenuItem)sender).GetContextMenu().SourceControl == chr_13_renderer) { n = chr13; } if (n == null) { return; } byte[] data = RenderTools.DXT5ScreenShot(view.glViewport, view.shootX, view.shootY, view.shootWidth, view.shootHeight); int id = n.Nodes.Count > 0 ? ((NutTexture)n.Nodes[0]).HashId : 0x280052B7; n.Nodes.Clear(); n.glTexByHashId.Clear(); NutTexture tex = new NutTexture(); tex.Width = view.shootWidth; tex.Height = view.shootHeight; tex.surfaces.Add(new TextureSurface()); tex.surfaces[0].mipmaps.Add(FlipDxt5(data, tex.Width, tex.Height)); tex.pixelInternalFormat = PixelInternalFormat.CompressedRgbaS3tcDxt5Ext; tex.HashId = id; n.Nodes.Add(tex); n.glTexByHashId.Add(tex.HashId, NUT.CreateTexture2D(tex)); ((MenuItem)sender).GetContextMenu().SourceControl.Invalidate(); if (((MenuItem)sender).GetContextMenu().SourceControl == stock_90_renderer) { if (stock90Loc != null) { stock90.Save(stock90Loc); } } if (((MenuItem)sender).GetContextMenu().SourceControl == chr_00_renderer) { if (chr00Loc != null) { chr00.Save(chr00Loc); } } if (((MenuItem)sender).GetContextMenu().SourceControl == chr_11_renderer) { if (chr11Loc != null) { chr11.Save(chr13Loc); } } if (((MenuItem)sender).GetContextMenu().SourceControl == chr_13_renderer) { if (chr13Loc != null) { chr13.Save(chr13Loc); } } }
private void ImportNutFromFolder(object sender, EventArgs e) { using (FolderSelectDialog f = new FolderSelectDialog()) { if (f.ShowDialog() == DialogResult.OK) { Edited = true; if (!Directory.Exists(f.SelectedPath)) { Directory.CreateDirectory(f.SelectedPath); } NUT nut; nut = currentNut; foreach (var texPath in Directory.GetFiles(f.SelectedPath)) { string extension = Path.GetExtension(texPath).ToLowerInvariant(); if (!(extension == ".dds" || extension == ".png")) { continue; } int texId; bool isTex = int.TryParse(Path.GetFileNameWithoutExtension(texPath), NumberStyles.HexNumber, new CultureInfo("en-US"), out texId); NutTexture texture = null; if (isTex) { foreach (NutTexture tex in nut.Nodes) { if (tex.HashId == texId) { texture = tex; } } } if (texture == null) { //new texture NutTexture tex = null; if (extension == ".dds") { Dds dds = new Dds(new FileData(texPath)); tex = dds.ToNutTexture(); } else if (extension == ".png") { tex = FromPng(texPath, 1); } if (isTex) { tex.HashId = texId; } else { tex.HashId = nut.Nodes.Count; } nut.Nodes.Add(tex); currentNut.glTexByHashId.Add(tex.HashId, NUT.CreateTexture2D(tex)); FillForm(); } else { //existing texture NutTexture tex = texture; NutTexture ntex = null; if (extension == ".dds") { Dds dds = new Dds(new FileData(texPath)); ntex = dds.ToNutTexture(); } else if (extension == ".png") { ntex = FromPng(texPath, 1); } tex.Height = ntex.Height; tex.Width = ntex.Width; tex.pixelInternalFormat = ntex.pixelInternalFormat; tex.surfaces = ntex.surfaces; tex.pixelFormat = ntex.pixelFormat; //GL.DeleteTexture(NUT.glTexByHashId[tex.HASHID]); currentNut.glTexByHashId.Remove(tex.HashId); currentNut.glTexByHashId.Add(tex.HashId, NUT.CreateTexture2D(tex)); FillForm(); } } if (!Runtime.textureContainers.Contains(nut)) { Runtime.textureContainers.Add(nut); } } } FillForm(); }
public void ReadNTWU(FileData d) { d.Seek(0x6); ushort count = d.ReadUShort(); d.Skip(0x8); int headerPtr = 0x10; for (ushort i = 0; i < count; ++i) { d.Seek(headerPtr); NutTexture tex = new NutTexture(); tex.pixelInternalFormat = PixelInternalFormat.Rgba32ui; int totalSize = d.ReadInt(); d.Skip(4); int dataSize = d.ReadInt(); int headerSize = d.ReadUShort(); d.Skip(2); d.Skip(1); byte mipmapCount = d.ReadByte(); d.Skip(1); tex.setPixelFormatFromNutFormat(d.ReadByte()); tex.Width = d.ReadUShort(); tex.Height = d.ReadUShort(); d.ReadInt(); //Always 1? uint caps2 = d.ReadUInt(); bool isCubemap = false; byte surfaceCount = 1; if ((caps2 & (uint)Dds.Ddscaps2.Cubemap) == (uint)Dds.Ddscaps2.Cubemap) { //Only supporting all six faces if ((caps2 & (uint)Dds.Ddscaps2.CubemapAllfaces) == (uint)Dds.Ddscaps2.CubemapAllfaces) { isCubemap = true; surfaceCount = 6; } else { throw new NotImplementedException($"Unsupported cubemap face amount for texture {i} with hash 0x{tex.HashId:X}. Six faces are required."); } } int dataOffset = d.ReadInt() + headerPtr; int mipDataOffset = d.ReadInt() + headerPtr; int gtxHeaderOffset = d.ReadInt() + headerPtr; d.ReadInt(); int cmapSize1 = 0; int cmapSize2 = 0; if (isCubemap) { cmapSize1 = d.ReadInt(); cmapSize2 = d.ReadInt(); d.Skip(8); } int imageSize = 0; //Total size of first mipmap of every surface int mipSize = 0; //Total size of mipmaps other than the first of every surface if (mipmapCount == 1) { if (isCubemap) { imageSize = cmapSize1; } else { imageSize = dataSize; } } else { imageSize = d.ReadInt(); mipSize = d.ReadInt(); d.Skip((mipmapCount - 2) * 4); d.Align(0x10); } d.Skip(0x10); //eXt data - always the same d.Skip(4); //GIDX d.ReadInt(); //Always 0x10 tex.HashId = d.ReadInt(); d.Skip(4); // padding align 8 d.Seek(gtxHeaderOffset); Gtx.Gx2Surface gtxHeader = new Gtx.Gx2Surface(); gtxHeader.dim = d.ReadInt(); gtxHeader.width = d.ReadInt(); gtxHeader.height = d.ReadInt(); gtxHeader.depth = d.ReadInt(); gtxHeader.numMips = d.ReadInt(); gtxHeader.format = d.ReadInt(); gtxHeader.aa = d.ReadInt(); gtxHeader.use = d.ReadInt(); gtxHeader.imageSize = d.ReadInt(); gtxHeader.imagePtr = d.ReadInt(); gtxHeader.mipSize = d.ReadInt(); gtxHeader.mipPtr = d.ReadInt(); gtxHeader.tileMode = d.ReadInt(); gtxHeader.swizzle = d.ReadInt(); gtxHeader.alignment = d.ReadInt(); gtxHeader.pitch = d.ReadInt(); //mipOffsets[0] is not in this list and is simply the start of the data (dataOffset) //mipOffsets[1] is relative to the start of the data (dataOffset + mipOffsets[1]) //Other mipOffsets are relative to mipOffset[1] (dataOffset + mipOffsets[1] + mipOffsets[i]) int[] mipOffsets = new int[mipmapCount]; mipOffsets[0] = 0; for (byte mipLevel = 1; mipLevel < mipmapCount; ++mipLevel) { mipOffsets[mipLevel] = 0; mipOffsets[mipLevel] = mipOffsets[1] + d.ReadInt(); } for (byte surfaceLevel = 0; surfaceLevel < surfaceCount; ++surfaceLevel) { tex.surfaces.Add(new TextureSurface()); } int w = tex.Width, h = tex.Height; for (byte mipLevel = 0; mipLevel < mipmapCount; ++mipLevel) { int p = gtxHeader.pitch / (gtxHeader.width / w); int size; if (mipmapCount == 1) { size = imageSize; } else if (mipLevel + 1 == mipmapCount) { size = (mipSize + mipOffsets[1]) - mipOffsets[mipLevel]; } else { size = mipOffsets[mipLevel + 1] - mipOffsets[mipLevel]; } size /= surfaceCount; for (byte surfaceLevel = 0; surfaceLevel < surfaceCount; ++surfaceLevel) { gtxHeader.data = d.GetSection(dataOffset + mipOffsets[mipLevel] + (size * surfaceLevel), size); //Real size //Leave the below line commented for now because it breaks RGBA textures //size = ((w + 3) >> 2) * ((h + 3) >> 2) * (GTX.getBPP(gtxHeader.format) / 8); if (size < (Gtx.GetBpp(gtxHeader.format) / 8)) { size = (Gtx.GetBpp(gtxHeader.format) / 8); } byte[] deswiz = Gtx.SwizzleBc( gtxHeader.data, w, h, gtxHeader.format, gtxHeader.tileMode, p, gtxHeader.swizzle ); tex.surfaces[surfaceLevel].mipmaps.Add(new FileData(deswiz).GetSection(0, size)); } w /= 2; h /= 2; if (w < 1) { w = 1; } if (h < 1) { h = 1; } } headerPtr += headerSize; Nodes.Add(tex); } }
private void importToolStripMenuItem_Click(object sender, EventArgs e) { if (currentNut == null) { return; } using (var ofd = new OpenFileDialog()) { ofd.Filter = "Supported Formats|*.dds;*.png|" + "DirectDraw Surface (.dds)|*.dds|" + "Portable Network Graphics (.png)|*.png|" + "All files(*.*)|*.*"; if (ofd.ShowDialog() == DialogResult.OK) { int texId; bool isTex = int.TryParse(Path.GetFileNameWithoutExtension(ofd.FileName), NumberStyles.HexNumber, new CultureInfo("en-US"), out texId); if (isTex) { foreach (NutTexture te in currentNut.Nodes) { if (texId == te.HashId) { isTex = false; } } } NutTexture tex = null; string extension = Path.GetExtension(ofd.FileName).ToLowerInvariant(); if (extension == ".dds") { Dds dds = new Dds(new FileData(ofd.FileName)); tex = dds.ToNutTexture(); } else if (extension == ".png") { tex = FromPng(ofd.FileName, 1); } else { return; } Edited = true; if (isTex) { tex.HashId = texId; } else { tex.HashId = 0x40FFFF00 | (currentNut.Nodes.Count); } // Replace OpenGL texture. if (currentNut.glTexByHashId.ContainsKey(tex.HashId)) { currentNut.glTexByHashId.Remove(tex.HashId); } currentNut.glTexByHashId.Add(tex.HashId, NUT.CreateTexture2D(tex)); currentNut.Nodes.Add(tex); FillForm(); } } }
public Dds(NutTexture tex) { FromNutTexture(tex); }
private void RenderTexture(bool justRenderAlpha = false) { if (OpenTkSharedResources.SetupStatus != OpenTkSharedResources.SharedResourceStatus.Initialized) { return; } if (!tabControl1.SelectedTab.Text.Equals("Textures")) { return; } if (!OpenTkSharedResources.shaders["Texture"].LinkStatusIsOk) { return; } // Get the selected NUT texture. NutTexture nutTexture = null; Texture displayTexture = null; if (currentMaterialList[currentMatIndex].HasProperty("NU_materialHash") && texturesListView.SelectedIndices.Count > 0) { int hash = currentMaterialList[currentMatIndex].textures[texturesListView.SelectedIndices[0]].hash; // Display dummy textures from resources. if (Enum.IsDefined(typeof(NudEnums.DummyTexture), hash)) { displayTexture = RenderTools.dummyTextures[(NudEnums.DummyTexture)hash]; } else { foreach (NUT n in Runtime.textureContainers) { if (n.glTexByHashId.ContainsKey(hash)) { n.getTextureByID(hash, out nutTexture); displayTexture = n.glTexByHashId[hash]; break; } } } } // We can't share these vaos across both contexts. if (justRenderAlpha) { texAlphaGlControl.MakeCurrent(); Mesh3D screenTriangle = ScreenDrawing.CreateScreenTriangle(); GL.Viewport(texAlphaGlControl.ClientRectangle); if (displayTexture != null) { ScreenDrawing.DrawTexturedQuad(displayTexture, 1, 1, screenTriangle, false, false, false, true); } texAlphaGlControl.SwapBuffers(); } else { texRgbGlControl.MakeCurrent(); Mesh3D screenTriangle = ScreenDrawing.CreateScreenTriangle(); GL.Viewport(texRgbGlControl.ClientRectangle); if (displayTexture != null) { ScreenDrawing.DrawTexturedQuad(displayTexture, 1, 1, screenTriangle); } texRgbGlControl.SwapBuffers(); } }
public NutTexture ToNutTexture() { NutTexture tex = new NutTexture(); tex.isDds = true; tex.HashId = 0x48415348; tex.Height = (int)header.height; tex.Width = (int)header.width; byte surfaceCount = 1; bool isCubemap = (header.caps2 & (uint)Ddscaps2.Cubemap) == (uint)Ddscaps2.Cubemap; if (isCubemap) { if ((header.caps2 & (uint)Ddscaps2.CubemapAllfaces) == (uint)Ddscaps2.CubemapAllfaces) { surfaceCount = 6; } else { throw new NotImplementedException($"Unsupported cubemap face amount for texture. Six faces are required."); } } bool isBlock = true; switch (header.ddspf.fourCc) { case 0x00000000: //RGBA isBlock = false; tex.pixelInternalFormat = PixelInternalFormat.Rgba; tex.pixelFormat = OpenTK.Graphics.OpenGL.PixelFormat.Rgba; break; case 0x31545844: //DXT1 tex.pixelInternalFormat = PixelInternalFormat.CompressedRgbaS3tcDxt1Ext; break; case 0x33545844: //DXT3 tex.pixelInternalFormat = PixelInternalFormat.CompressedRgbaS3tcDxt3Ext; break; case 0x35545844: //DXT5 tex.pixelInternalFormat = PixelInternalFormat.CompressedRgbaS3tcDxt5Ext; break; case 0x31495441: //ATI1 case 0x55344342: //BC4U tex.pixelInternalFormat = PixelInternalFormat.CompressedRedRgtc1; break; case 0x32495441: //ATI2 case 0x55354342: //BC5U tex.pixelInternalFormat = PixelInternalFormat.CompressedRgRgtc2; break; default: MessageBox.Show("Unsupported DDS format - 0x" + header.ddspf.fourCc.ToString("x")); break; } uint formatSize = GetFormatSize(header.ddspf.fourCc); FileData d = new FileData(bdata); if (header.mipmapCount == 0) { header.mipmapCount = 1; } uint off = 0; for (byte i = 0; i < surfaceCount; ++i) { TextureSurface surface = new TextureSurface(); uint w = header.width, h = header.height; for (int j = 0; j < header.mipmapCount; ++j) { //If texture is DXT5 and isn't square, limit the mipmaps to an amount such that width and height are each always >= 4 if (tex.pixelInternalFormat == PixelInternalFormat.CompressedRgbaS3tcDxt5Ext && tex.Width != tex.Height && (w < 4 || h < 4)) { break; } uint s = (w * h); //Total pixels if (isBlock) { s = (uint)(s * ((float)formatSize / 0x10)); //Bytes per 16 pixels if (s < formatSize) //Make sure it's at least one block { s = formatSize; } } else { s = (uint)(s * (formatSize)); //Bytes per pixel } w /= 2; h /= 2; surface.mipmaps.Add(d.GetSection((int)off, (int)s)); off += s; } tex.surfaces.Add(surface); } return(tex); }