2018-09-08 19:51:50 +02:00
|
|
|
|
using System;
|
|
|
|
|
using System.Diagnostics;
|
|
|
|
|
|
|
|
|
|
namespace Ryujinx.Graphics.Texture
|
|
|
|
|
{
|
|
|
|
|
class ASTCPixel
|
|
|
|
|
{
|
|
|
|
|
public short R { get; set; }
|
|
|
|
|
public short G { get; set; }
|
|
|
|
|
public short B { get; set; }
|
|
|
|
|
public short A { get; set; }
|
|
|
|
|
|
|
|
|
|
byte[] BitDepth = new byte[4];
|
|
|
|
|
|
|
|
|
|
public ASTCPixel(short _A, short _R, short _G, short _B)
|
|
|
|
|
{
|
|
|
|
|
A = _A;
|
|
|
|
|
R = _R;
|
|
|
|
|
G = _G;
|
|
|
|
|
B = _B;
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < 4; i++)
|
|
|
|
|
BitDepth[i] = 8;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void ClampByte()
|
|
|
|
|
{
|
|
|
|
|
R = Math.Min(Math.Max(R, (short)0), (short)255);
|
|
|
|
|
G = Math.Min(Math.Max(G, (short)0), (short)255);
|
|
|
|
|
B = Math.Min(Math.Max(B, (short)0), (short)255);
|
|
|
|
|
A = Math.Min(Math.Max(A, (short)0), (short)255);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public short GetComponent(int Index)
|
|
|
|
|
{
|
|
|
|
|
switch(Index)
|
|
|
|
|
{
|
|
|
|
|
case 0: return A;
|
|
|
|
|
case 1: return R;
|
|
|
|
|
case 2: return G;
|
|
|
|
|
case 3: return B;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void SetComponent(int Index, int Value)
|
|
|
|
|
{
|
|
|
|
|
switch (Index)
|
|
|
|
|
{
|
|
|
|
|
case 0:
|
|
|
|
|
A = (short)Value;
|
|
|
|
|
break;
|
|
|
|
|
case 1:
|
|
|
|
|
R = (short)Value;
|
|
|
|
|
break;
|
|
|
|
|
case 2:
|
|
|
|
|
G = (short)Value;
|
|
|
|
|
break;
|
|
|
|
|
case 3:
|
|
|
|
|
B = (short)Value;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void ChangeBitDepth(byte[] Depth)
|
|
|
|
|
{
|
|
|
|
|
for(int i = 0; i< 4; i++)
|
|
|
|
|
{
|
|
|
|
|
int Value = ChangeBitDepth(GetComponent(i), BitDepth[i], Depth[i]);
|
|
|
|
|
|
|
|
|
|
SetComponent(i, Value);
|
|
|
|
|
BitDepth[i] = Depth[i];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
short ChangeBitDepth(short Value, byte OldDepth, byte NewDepth)
|
|
|
|
|
{
|
|
|
|
|
Debug.Assert(NewDepth <= 8);
|
|
|
|
|
Debug.Assert(OldDepth <= 8);
|
|
|
|
|
|
|
|
|
|
if (OldDepth == NewDepth)
|
|
|
|
|
{
|
|
|
|
|
// Do nothing
|
|
|
|
|
return Value;
|
|
|
|
|
}
|
|
|
|
|
else if (OldDepth == 0 && NewDepth != 0)
|
|
|
|
|
{
|
|
|
|
|
return (short)((1 << NewDepth) - 1);
|
|
|
|
|
}
|
|
|
|
|
else if (NewDepth > OldDepth)
|
|
|
|
|
{
|
|
|
|
|
return (short)BitArrayStream.Replicate(Value, OldDepth, NewDepth);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// oldDepth > newDepth
|
|
|
|
|
if (NewDepth == 0)
|
|
|
|
|
{
|
|
|
|
|
return 0xFF;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
byte BitsWasted = (byte)(OldDepth - NewDepth);
|
|
|
|
|
short TempValue = Value;
|
|
|
|
|
|
|
|
|
|
TempValue = (short)((TempValue + (1 << (BitsWasted - 1))) >> BitsWasted);
|
|
|
|
|
TempValue = Math.Min(Math.Max((short)0, TempValue), (short)((1 << NewDepth) - 1));
|
|
|
|
|
|
|
|
|
|
return (byte)(TempValue);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public int Pack()
|
|
|
|
|
{
|
|
|
|
|
ASTCPixel NewPixel = new ASTCPixel(A, R, G, B);
|
|
|
|
|
byte[] eightBitDepth = { 8, 8, 8, 8 };
|
|
|
|
|
|
|
|
|
|
NewPixel.ChangeBitDepth(eightBitDepth);
|
|
|
|
|
|
|
|
|
|
return (byte)NewPixel.A << 24 |
|
|
|
|
|
(byte)NewPixel.B << 16 |
|
|
|
|
|
(byte)NewPixel.G << 8 |
|
|
|
|
|
(byte)NewPixel.R << 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Adds more precision to the blue channel as described
|
|
|
|
|
// in C.2.14
|
|
|
|
|
public static ASTCPixel BlueContract(int a, int r, int g, int b)
|
|
|
|
|
{
|
|
|
|
|
return new ASTCPixel((short)(a),
|
|
|
|
|
(short)((r + b) >> 1),
|
|
|
|
|
(short)((g + b) >> 1),
|
|
|
|
|
(short)(b));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|