/
BC2ABlockEncoder.cs
120 lines (91 loc) · 2.42 KB
/
BC2ABlockEncoder.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
using System;
namespace BCn
{
public class BC2ABlockEncoder
{
public bool Dither { get; set; }
/// <summary>
/// Loads a block of values for subsequent encoding.
/// </summary>
/// <param name="values">The values to encode.</param>
/// <param name="index">The index to start reading values.</param>
/// <param name="rowPitch">The pitch between rows of values.</param>
/// <param name="colPitch">The pitch between subsequent values within a row.</param>
public void LoadBlock( float[] values, int index = 0,
int rowPitch = 4, int colPitch = 1 )
{
var target = this.values;
if( rowPitch == 4 && colPitch == 1 )
{
//get the fast case out of the way
Array.Copy( values, index, target, 0, 16 );
return;
}
int i = index;
target[0] = values[i];
target[1] = values[i += colPitch];
target[2] = values[i += colPitch];
target[3] = values[i += colPitch];
i = index += rowPitch;
target[4] = values[i];
target[5] = values[i += colPitch];
target[6] = values[i += colPitch];
target[7] = values[i += colPitch];
i = index += rowPitch;
target[8] = values[i];
target[9] = values[i += colPitch];
target[10] = values[i += colPitch];
target[11] = values[i += colPitch];
i = index + rowPitch;
target[12] = values[i];
target[13] = values[i += colPitch];
target[14] = values[i += colPitch];
target[15] = values[i += colPitch];
}
public BC2ABlock Encode()
{
//clamp the values into range
for( int i = 0; i < 16; i++ )
{
var v = values[i];
if( v < 0 ) values[i] = 0;
else if( v > 1 ) values[i] = 1;
}
//encode, optionally dithering as we go
bool dither = Dither;
BC2ABlock ret = new BC2ABlock();
if( dither )
{
if( error == null )
error = new float[16];
else
Array.Clear( error, 0, 16 );
}
for( int i = 0; i < values.Length; i++ )
{
float v = values[i];
if( dither )
v += error[i];
int u = (int)(v * 15F + 0.5F);
ret.PackedValue|= (ulong)u << (i * 4);
if( dither )
{
float d = v - u * (1F / 15F);
if( (i & 3) != 3 )
error[i + 1] += d * (7F / 16F);
if( i < 12 )
{
if( (i & 3) != 0 )
error[i + 3] += d * (3F / 16F);
error[i + 4] += d * (5F / 16F);
if( (i & 3) != 3 )
error[i + 5] += d * (1F / 16F);
}
}
}
return ret;
}
private float[] values = new float[16];
private float[] error;
}
}