Replies: 2 comments · 8 replies
|
By the title I'm assuming you're working with the 3.0 branch. Depending on what you're wanting to achieve, there are a couple of places you should take a look at: Texture formats | ktx, ktx2, dds, etc.If you want to add a new texture format, such as Valve Texture Format (.vtf), which acts as a container for different types of pixel data (rgb32, bc1, bc2 etc.), that can be achieved by creating your own class that implements the // Valve texture format file
public class VtfFile : ITextureFileFormat<VtfFile>
{
public bool SupportsLdr => true;
public bool SupportsHdr => true;
public bool SupportsCubeMap => true;
public bool SupportsMipMaps => true;
public bool SupportsArrays => true;
// Pixel and metadata members go here
private VtfMetadata metadata;
private VtfPixeldata pixeldata;
public bool IsSupportedFormat(CompressionFormat format)
{
// return whether the given CompressionFormat is valid for this file type
}
public void FromTextureData(BCnTextureData textureData)
{
// Take the raw pixel data from BCnTextureData class, and convert it to a Valve Texture Format specific container
}
public BCnTextureData ToTextureData()
{
// Inverse of the above operation. Take a look at KtxFile.cs for an example
}
public void ReadFromStream(Stream inputStream)
{
// Read raw bytes from a file stream and populate the metadata and pixeldata fields
}
public void WriteToStream(Stream outputStream)
{
// Write raw bytes to the file stream in the correct way for vtf files
}
}Then you can use the new format like so: public void EncodeVtfFile()
{
using Image<Rgba32> image = Image.Load<Rgba32>("example.png");
BcEncoder encoder = new BcEncoder();
encoder.OutputOptions.GenerateMipMaps = true;
encoder.OutputOptions.Quality = CompressionQuality.Balanced;
encoder.OutputOptions.Format = CompressionFormat.Bc1;
// Open a file to write to
using FileStream fs = File.OpenWrite("example.vtf");
// Create a BCnTextureData with the compressed data
BCnTextureData textureData = encoder.Encode(image);
// Convert BCnTextureData to Vtf file
VtfFile valveFile = new VtfFile();
valveFile.FromTextureData(textureData);
// Write to file
valveFile.WriteToStream(fs);
// Or, all of the above in one operation
// encoder.EncodeToStream<VtfFile>(image, fs);
}
public void DecodeVtfFile()
{
using FileStream fs = File.OpenRead("compressed_bc1.ktx");
BcDecoder decoder = new BcDecoder();
// Read vtf file from stream
VtfFile valveFile = ITextureFileFormat<VtfFile>.Read(fs);
// Convert to BCnTextureData
BCnTextureData encodedData = valveFile.ToTextureData();
// Decode to raw Rgba32 data
BCnTextureData decodedData = decoder.Decode(encodedData, CompressionFormat.Rgba32);
// Get raw pixel data as bytes
byte[] rawByteData = decodedData.Mips[0][0,0].Data;
// Save to png
decodedData.AsImageRgba32().SaveAsPng("output.png");
// Or easier like this
// using Image<Rgba32> image = decoder.Decode<VtfFile>(fs).AsImageRgba32();
// image.SaveAsPng("output.png");
}Pixel formats | Rgba32, Bc1, ETC1, ASTC etc.If you want to add one of these you need to first add a new enum for it in the This is a bit more involved, so take a look at how the other formats are implemented, like BC1 for block compressed formats, and Rgba32 for raw pixel formats. If it's a block compressed format, you need a encoder and decoder class for it. These should be added to the Raw pixel formats just work (TM) without encoder/decoder classes, if they're setup correctly. For example below is the encoder and decoder classes for ATC (Adreno Texture Compression), which is just BC1 with extra steps. [StructLayout(LayoutKind.Sequential)]
internal struct AtcBlock
{
public ColorB5G5R5M1Packed color0;
public ColorB5G6R5Packed color1;
public uint colorIndices;
public int this[int index]
{
readonly get => (int)(colorIndices >> (index * 2)) & 0b11;
set
{
colorIndices = (uint)(colorIndices & ~(0b11 << (index * 2)));
var val = value & 0b11;
colorIndices = colorIndices | ((uint)val << (index * 2));
}
}
public readonly RawBlock4X4RgbaFloat Decode()
{
var output = new RawBlock4X4RgbaFloat();
var pixels = output.AsSpan;
var color0 = this.color0.ToColorRgbaFloat();
var color1 = this.color1.ToColorRgbaFloat();
int mode = this.color0.Mode;
Span<ColorRgbaFloat> colorsMode1 = stackalloc ColorRgbaFloat[] {
new ColorRgbaFloat(0, 0, 0),
color0.InterpolateFourthAtc(color1, 1),
color0,
color1
};
for (var i = 0; i < pixels.Length; i++)
{
var colorIndex = this[i];
var color = mode == 0 ? color0.InterpolateThird(color1, colorIndex) : colorsMode1[colorIndex];
pixels[i] = color;
}
return output;
}
}
internal unsafe class AtcBlockEncoder : BaseBcBlockEncoder<AtcBlock, RgbEncodingContext>
{
private static readonly Bc1BlockEncoder bc1BlockEncoder = new Bc1BlockEncoder(false, false);
public AtcBlockEncoder()
{
}
public override AtcBlock EncodeBlock(in RgbEncodingContext context)
{
var atcBlock = new AtcBlock();
// EncodeBlock with BC1 first
Bc1Block bc1Block = bc1BlockEncoder.EncodeBlock(context);
// Atc specific modifications to BC1
// According to http://www.guildsoftware.com/papers/2012.Converting.DXTC.to.ATC.pdf
// Change color0 from rgb565 to rgb555 with method 0
atcBlock.color0 = new ColorB5G5R5M1Packed(bc1Block.color0.R, bc1Block.color0.G, bc1Block.color0.B);
atcBlock.color1 = bc1Block.color1;
// Remap color indices from BC1 to ATC
var remap = stackalloc byte[] { 0, 3, 1, 2 };
for (var i = 0; i < 16; i++)
{
atcBlock[i] = remap[bc1Block[i]];
}
return atcBlock;
}
}
internal class AtcDecoder : BaseBcBlockDecoder<AtcBlock>
{
protected override RawBlock4X4RgbaFloat DecodeBlock(AtcBlock block)
{
return block.Decode();
}
}For block-compressed formats, the encoder takes in a block of raw pixel values (4x4 only, for now) and outputs a struct that represents the internal data for that type of compressed block. These structs have the same memory layout as the block would have in file or gpu memory, so you can write these structs directly to the file or byte stream. The decoder takes the compressed block and converts it to a 4x4 block of raw float rgb data. Everything else is automagically handled by the rest of the code, like mipmaps, pixel preprocessing, alpha premultiplication etc. Let me know if you need more help! |
|
I really dont know what could be the issue, the BC1 data seems fine to me but OGL thinks its just black |
Uh oh!
There was an error while loading. Please reload this page.
Hi, I'm trying to implement my own format(s) as extensions using the
ITextureFileFormatinterface.For now im stuck trying to write the Block Compressed data and the mipmaps yet i cant seem to find where the magick happens. I saw the
MipMapperclass yet it looks like it only outputsRgbaFloatimage dataBig thanks for help in advance
All reactions