public BC1Block Encode() { BC1Block ret; if( alphaMask == 0xFFFF ) { ret.PackedValue = BC1Block.TransparentValue; return ret; } QuantizeValues(); RgbF32 r0, r1; SpanValues( out r0, out r1 ); //quantize the endpoints bool weightValues = !UseUniformWeighting; if( weightValues ) { r0.R *= RInvWeight; r0.G *= GInvWeight; r0.B *= BInvWeight; r1.R *= RInvWeight; r1.G *= GInvWeight; r1.B *= BInvWeight; } var pr0 = Rgb565.Pack( r0 ); var pr1 = Rgb565.Pack( r1 ); if( alphaMask == 0 && pr0.PackedValue == pr1.PackedValue ) return new BC1Block( pr0, pr1 ); pr0.Unpack( out r0 ); pr1.Unpack( out r1 ); if( weightValues ) { r0.R *= RWeight; r0.G *= GWeight; r0.B *= BWeight; r1.R *= RWeight; r1.G *= GWeight; r1.B *= BWeight; } //interp out the steps RgbF32 s0; if( (alphaMask != 0) == (pr0.PackedValue <= pr1.PackedValue) ) { ret = new BC1Block( pr0, pr1 ); interpValues[0] = s0 = r0; interpValues[1] = r1; } else { ret = new BC1Block( pr1, pr0 ); interpValues[0] = s0 = r1; interpValues[1] = r0; } uint[] pSteps; if( alphaMask != 0 ) { pSteps = pSteps3; RgbF32.Lerp( out interpValues[2], interpValues[0], interpValues[1], 0.5F ); } else { pSteps = pSteps4; RgbF32.Lerp( out interpValues[2], interpValues[0], interpValues[1], 1.0F / 3.0F ); RgbF32.Lerp( out interpValues[3], interpValues[0], interpValues[1], 2.0F / 3.0F ); } //find the best values RgbF32 dir; dir.R = interpValues[1].R - s0.R; dir.G = interpValues[1].G - s0.G; dir.B = interpValues[1].B - s0.B; float fSteps = alphaMask != 0 ? 2 : 3; float fScale = (pr0.PackedValue != pr1.PackedValue) ? (fSteps / (dir.R * dir.R + dir.G * dir.G + dir.B * dir.B)) : 0.0F; dir.R *= fScale; dir.G *= fScale; dir.B *= fScale; bool dither = DitherRgb; if( dither ) { if( error == null ) error = new RgbF32[16]; else Array.Clear( error, 0, 16 ); } for( int i = 0; i < values.Length; i++ ) { if( (alphaMask & (1 << i)) != 0 ) { ret.PackedValue |= 3U << (32 + i * 2); } else { var cl = values[i]; if( weightValues ) { cl.R *= RWeight; cl.G *= GWeight; cl.B *= BWeight; } if( dither ) { var e = error[i]; cl.R += e.R; cl.G += e.G; cl.B += e.B; } float fDot = (cl.R - s0.R) * dir.R + (cl.G - s0.G) * dir.G + (cl.B - s0.B) * dir.B; uint iStep; if( fDot <= 0 ) iStep = 0; else if( fDot >= fSteps ) iStep = 1; else iStep = pSteps[(int)(fDot + 0.5F)]; ret.PackedValue |= (ulong)iStep << (32 + i * 2); if( dither ) { RgbF32 e, d, interp = interpValues[iStep]; d.R = cl.R - interp.R; d.G = cl.G - interp.G; d.B = cl.B - interp.B; if( (i & 3) != 3 ) { e = error[i + 1]; e.R += d.R * (7.0F / 16.0F); e.G += d.G * (7.0F / 16.0F); e.B += d.B * (7.0F / 16.0F); error[i + 1] = e; } if( i < 12 ) { if( (i & 3) != 0 ) { e = error[i + 3]; e.R += d.R * (3.0F / 16.0F); e.G += d.G * (3.0F / 16.0F); e.B += d.B * (3.0F / 16.0F); error[i + 3] = e; } e = error[i + 4]; e.R += d.R * (5.0F / 16.0F); e.G += d.G * (5.0F / 16.0F); e.B += d.B * (5.0F / 16.0F); error[i + 4] = e; if( 3 != (i & 3) ) { e = error[i + 5]; e.R += d.R * (1.0F / 16.0F); e.G += d.G * (1.0F / 16.0F); e.B += d.B * (1.0F / 16.0F); error[i + 5] = e; } } } } } return ret; }
public BC1Block Encode() { BC1Block ret; if (alphaMask == 0xFFFF) { ret.PackedValue = BC1Block.TransparentValue; return(ret); } QuantizeValues(); RgbF32 r0, r1; SpanValues(out r0, out r1); //quantize the endpoints bool weightValues = !UseUniformWeighting; if (weightValues) { r0.R *= RInvWeight; r0.G *= GInvWeight; r0.B *= BInvWeight; r1.R *= RInvWeight; r1.G *= GInvWeight; r1.B *= BInvWeight; } var pr0 = Rgb565.Pack(r0); var pr1 = Rgb565.Pack(r1); if (alphaMask == 0 && pr0.PackedValue == pr1.PackedValue) { return(new BC1Block(pr0, pr1)); } pr0.Unpack(out r0); pr1.Unpack(out r1); if (weightValues) { r0.R *= RWeight; r0.G *= GWeight; r0.B *= BWeight; r1.R *= RWeight; r1.G *= GWeight; r1.B *= BWeight; } //interp out the steps RgbF32 s0; if ((alphaMask != 0) == (pr0.PackedValue <= pr1.PackedValue)) { ret = new BC1Block(pr0, pr1); interpValues[0] = s0 = r0; interpValues[1] = r1; } else { ret = new BC1Block(pr1, pr0); interpValues[0] = s0 = r1; interpValues[1] = r0; } uint[] pSteps; if (alphaMask != 0) { pSteps = pSteps3; RgbF32.Lerp(out interpValues[2], interpValues[0], interpValues[1], 0.5F); } else { pSteps = pSteps4; RgbF32.Lerp(out interpValues[2], interpValues[0], interpValues[1], 1.0F / 3.0F); RgbF32.Lerp(out interpValues[3], interpValues[0], interpValues[1], 2.0F / 3.0F); } //find the best values RgbF32 dir; dir.R = interpValues[1].R - s0.R; dir.G = interpValues[1].G - s0.G; dir.B = interpValues[1].B - s0.B; float fSteps = alphaMask != 0 ? 2 : 3; float fScale = (pr0.PackedValue != pr1.PackedValue) ? (fSteps / (dir.R * dir.R + dir.G * dir.G + dir.B * dir.B)) : 0.0F; dir.R *= fScale; dir.G *= fScale; dir.B *= fScale; bool dither = DitherRgb; if (dither) { if (error == null) { error = new RgbF32[16]; } else { Array.Clear(error, 0, 16); } } for (int i = 0; i < values.Length; i++) { if ((alphaMask & (1 << i)) != 0) { ret.PackedValue |= 3U << (32 + i * 2); } else { var cl = values[i]; if (weightValues) { cl.R *= RWeight; cl.G *= GWeight; cl.B *= BWeight; } if (dither) { var e = error[i]; cl.R += e.R; cl.G += e.G; cl.B += e.B; } float fDot = (cl.R - s0.R) * dir.R + (cl.G - s0.G) * dir.G + (cl.B - s0.B) * dir.B; uint iStep; if (fDot <= 0) { iStep = 0; } else if (fDot >= fSteps) { iStep = 1; } else { iStep = pSteps[(int)(fDot + 0.5F)]; } ret.PackedValue |= (ulong)iStep << (32 + i * 2); if (dither) { RgbF32 e, d, interp = interpValues[iStep]; d.R = cl.R - interp.R; d.G = cl.G - interp.G; d.B = cl.B - interp.B; if ((i & 3) != 3) { e = error[i + 1]; e.R += d.R * (7.0F / 16.0F); e.G += d.G * (7.0F / 16.0F); e.B += d.B * (7.0F / 16.0F); error[i + 1] = e; } if (i < 12) { if ((i & 3) != 0) { e = error[i + 3]; e.R += d.R * (3.0F / 16.0F); e.G += d.G * (3.0F / 16.0F); e.B += d.B * (3.0F / 16.0F); error[i + 3] = e; } e = error[i + 4]; e.R += d.R * (5.0F / 16.0F); e.G += d.G * (5.0F / 16.0F); e.B += d.B * (5.0F / 16.0F); error[i + 4] = e; if (3 != (i & 3)) { e = error[i + 5]; e.R += d.R * (1.0F / 16.0F); e.G += d.G * (1.0F / 16.0F); e.B += d.B * (1.0F / 16.0F); error[i + 5] = e; } } } } } return(ret); }