From de05a5f674b20ff8909c48dd77fad815c048e1b7 Mon Sep 17 00:00:00 2001 From: James Seibel Date: Sat, 27 Jul 2024 16:25:27 -0500 Subject: [PATCH] Refactor and cleanup ClientBlockStateCache --- .../block/cache/ClientBlockDetailMap.java | 27 +- .../block/cache/ClientBlockStateCache.java | 391 ++++++++++-------- 2 files changed, 241 insertions(+), 177 deletions(-) diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/cache/ClientBlockDetailMap.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/cache/ClientBlockDetailMap.java index e05b1a966..6fb510855 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/cache/ClientBlockDetailMap.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/cache/ClientBlockDetailMap.java @@ -29,20 +29,29 @@ import java.util.concurrent.ConcurrentHashMap; public class ClientBlockDetailMap { private final ConcurrentHashMap blockCache = new ConcurrentHashMap<>(); - //private final ConcurrentHashMap<#if MC_VER < MC_1_18_2 Biome #else Holder #endif, Biome> biomeMap = new ConcurrentHashMap<>(); private final ClientLevelWrapper level; + + + + //=============// + // constructor // + //=============// + public ClientBlockDetailMap(ClientLevelWrapper level) { this.level = level; } - public ClientBlockStateCache getBlockStateData(BlockState state, DhBlockPos pos) - { //TODO: Allow a per pos unique setting - return blockCache.computeIfAbsent(state, (s) -> new ClientBlockStateCache(s, level, pos)); - } - public void clear() { blockCache.clear(); } + + //=========// + // methods // + //=========// + + public ClientBlockStateCache getBlockStateData(BlockState blockState) + { return this.blockCache.computeIfAbsent(blockState, (block) -> new ClientBlockStateCache(block, this.level)); } public int getColor(BlockState state, BiomeWrapper biome, DhBlockPos pos) - { - return getBlockStateData(state, pos).getAndResolveFaceColor(biome, pos); - } + { return this.getBlockStateData(state).getAndResolveFaceColor(biome, pos); } + + public void clear() { this.blockCache.clear(); } + } diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/cache/ClientBlockStateCache.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/cache/ClientBlockStateCache.java index 52b81458c..673d975cb 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/cache/ClientBlockStateCache.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/cache/ClientBlockStateCache.java @@ -50,7 +50,9 @@ import java.util.HashSet; import java.util.List; /** - * @version 2022-9-16 + * This keeps track of the color each block state should be for a given level. + * + * @see ColorUtil */ public class ClientBlockStateCache { @@ -59,62 +61,42 @@ public class ClientBlockStateCache private static final HashSet BLOCK_STATES_THAT_NEED_LEVEL = new HashSet<>(); private static final HashSet BROKEN_BLOCK_STATES = new HashSet<>(); + /** This is the order each direction on a block is processed when attempting to get the texture/color */ + private static final Direction[] COLOR_RESOLUTION_DIRECTION_ORDER = { Direction.UP, Direction.NORTH, Direction.EAST, Direction.WEST, Direction.SOUTH, Direction.DOWN }; + + private static final int FLOWER_COLOR_SCALE = 5; + + + #if MC_VER < MC_1_19_2 - public static final Random random = new Random(0); + private static final Random random = new Random(0); #else - public static final RandomSource random = RandomSource.create(); + private static final RandomSource random = RandomSource.create(); #endif - public final IClientLevelWrapper levelWrapper; - public final BlockState blockState; - public final LevelReader level; - public final BlockPos pos; + private final IClientLevelWrapper levelWrapper; + private final BlockState blockState; + private final LevelReader level; + + private boolean isColorResolved = false; + private int baseColor = 0; + private boolean needShade = true; + private boolean needPostTinting = false; + private int tintIndex = 0; - public ClientBlockStateCache(BlockState blockState, IClientLevelWrapper samplingLevel, DhBlockPos samplingPos) - { - this.blockState = blockState; - this.levelWrapper = samplingLevel; - this.level = (LevelReader) samplingLevel.getWrappedMcObject(); - this.pos = McObjectConverter.Convert(samplingPos); - this.resolveColors(); - //LOGGER.info("ClientBlocKCache created for {}", blockState); - } + //===========// + // constants // + //===========// - boolean isColorResolved = false; - int baseColor = 0; //TODO: Impl per-face color - boolean needShade = true; - boolean needPostTinting = false; - int tintIndex = 0; + private static final int MIN_SRGB_BITS = 0x39000000; // 2^(-13) + private static final int MAX_SRGB_BITS = 0x3f7fffff; // 1.0 - f32::EPSILON + private static final float MIN_SRGB_BOUND = Float.intBitsToFloat(MIN_SRGB_BITS); + private static final float MAX_SRGB_BOUND = Float.intBitsToFloat(MAX_SRGB_BITS); - - public static final int FLOWER_COLOR_SCALE = 5; - - enum ColorMode - { - Default, - Flower, - Leaves, - Chisel, - Glass; - static ColorMode getColorMode(Block b) + private static final int[] linearToSrgbTable = new int[] { - if (b instanceof LeavesBlock) return Leaves; - if (b instanceof FlowerBlock) return Flower; - if (b.toString().contains("glass")) return Glass; - if (b.toString().equals("Block{chiselsandbits:chiseled}")) return Chisel; - return Default; - } - } - - //Way to efficiently do this was suggested by IMS from sodium. This is where those numbers and support code was lifted from. - private static final int MIN_BITS = 0x39000000; // 2^(-13) - private static final int MAX_BITS = 0x3f7fffff; // 1.0 - f32::EPSILON - private static final float MIN_BOUND = Float.intBitsToFloat(MIN_BITS); - private static final float MAX_BOUND = Float.intBitsToFloat(MAX_BITS); - - private static final int[] linearToSrgbTable = new int[] { 0x0073000d, 0x007a000d, 0x0080000d, 0x0087000d, 0x008d000d, 0x0094000d, 0x009a000d, 0x00a1000d, 0x00a7001a, 0x00b4001a, 0x00c1001a, 0x00ce001a, 0x00da001a, 0x00e7001a, 0x00f4001a, 0x0101001a, 0x010e0033, 0x01280033, 0x01410033, 0x015b0033, 0x01750033, 0x018f0033, 0x01a80033, 0x01c20033, @@ -128,81 +110,131 @@ public class ClientBlockStateCache 0x31d105b0, 0x34a80555, 0x37520507, 0x39d504c5, 0x3c37048b, 0x3e7c0458, 0x40a8042a, 0x42bd0401, 0x44c20798, 0x488e071e, 0x4c1c06b6, 0x4f76065d, 0x52a50610, 0x55ac05cc, 0x5892058f, 0x5b590559, 0x5e0c0a23, 0x631c0980, 0x67db08f6, 0x6c55087f, 0x70940818, 0x74a007bd, 0x787d076c, 0x7c330723, - }; + }; - private static final float[] srgbToLinearTable = new float[] { - 0.0f, 0.000303527f, 0.000607054f, 0.00091058103f, 0.001214108f, 0.001517635f, 0.0018211621f, 0.002124689f, - 0.002428216f, 0.002731743f, 0.00303527f, 0.0033465356f, 0.003676507f, 0.004024717f, 0.004391442f, - 0.0047769533f, 0.005181517f, 0.0056053917f, 0.0060488326f, 0.006512091f, 0.00699541f, 0.0074990317f, - 0.008023192f, 0.008568125f, 0.009134057f, 0.009721218f, 0.010329823f, 0.010960094f, 0.011612245f, - 0.012286487f, 0.012983031f, 0.013702081f, 0.014443844f, 0.015208514f, 0.015996292f, 0.016807375f, - 0.017641952f, 0.018500218f, 0.019382361f, 0.020288562f, 0.02121901f, 0.022173883f, 0.023153365f, - 0.02415763f, 0.025186857f, 0.026241222f, 0.027320892f, 0.028426038f, 0.029556843f, 0.03071345f, 0.03189604f, - 0.033104774f, 0.03433981f, 0.035601325f, 0.036889452f, 0.038204376f, 0.039546248f, 0.04091521f, 0.042311423f, - 0.043735042f, 0.045186214f, 0.046665095f, 0.048171833f, 0.049706575f, 0.051269468f, 0.052860655f, 0.05448028f, - 0.056128494f, 0.057805434f, 0.05951124f, 0.06124607f, 0.06301003f, 0.06480328f, 0.06662595f, 0.06847818f, - 0.07036011f, 0.07227186f, 0.07421358f, 0.07618539f, 0.07818743f, 0.08021983f, 0.082282715f, 0.084376216f, - 0.086500466f, 0.088655606f, 0.09084173f, 0.09305898f, 0.095307484f, 0.09758736f, 0.09989874f, 0.10224175f, - 0.10461649f, 0.10702311f, 0.10946172f, 0.111932434f, 0.11443538f, 0.116970696f, 0.11953845f, 0.12213881f, - 0.12477186f, 0.12743773f, 0.13013652f, 0.13286836f, 0.13563336f, 0.13843165f, 0.14126332f, 0.1441285f, - 0.1470273f, 0.14995982f, 0.15292618f, 0.1559265f, 0.15896086f, 0.16202943f, 0.16513224f, 0.16826946f, - 0.17144115f, 0.17464745f, 0.17788847f, 0.1811643f, 0.18447503f, 0.1878208f, 0.19120172f, 0.19461787f, - 0.19806935f, 0.2015563f, 0.20507877f, 0.2086369f, 0.21223079f, 0.21586053f, 0.21952623f, 0.22322798f, - 0.22696589f, 0.23074007f, 0.23455065f, 0.23839766f, 0.2422812f, 0.2462014f, 0.25015837f, 0.25415218f, - 0.2581829f, 0.26225072f, 0.26635566f, 0.27049786f, 0.27467737f, 0.27889434f, 0.2831488f, 0.2874409f, - 0.2917707f, 0.29613832f, 0.30054384f, 0.30498737f, 0.30946895f, 0.31398875f, 0.31854683f, 0.32314324f, - 0.32777813f, 0.33245158f, 0.33716366f, 0.34191445f, 0.3467041f, 0.3515327f, 0.35640025f, 0.36130688f, - 0.3662527f, 0.37123778f, 0.37626222f, 0.3813261f, 0.38642952f, 0.39157256f, 0.3967553f, 0.40197787f, - 0.4072403f, 0.4125427f, 0.41788515f, 0.42326775f, 0.42869055f, 0.4341537f, 0.43965724f, 0.44520125f, - 0.45078585f, 0.45641106f, 0.46207705f, 0.46778384f, 0.47353154f, 0.47932023f, 0.48514998f, 0.4910209f, - 0.49693304f, 0.5028866f, 0.50888145f, 0.5149178f, 0.5209957f, 0.52711535f, 0.5332766f, 0.5394797f, - 0.5457247f, 0.5520116f, 0.5583406f, 0.5647117f, 0.57112503f, 0.57758063f, 0.5840786f, 0.590619f, 0.597202f, - 0.60382754f, 0.61049575f, 0.61720675f, 0.62396055f, 0.63075733f, 0.637597f, 0.6444799f, 0.6514058f, - 0.65837497f, 0.66538745f, 0.67244333f, 0.6795426f, 0.68668544f, 0.69387203f, 0.70110214f, 0.70837605f, - 0.7156938f, 0.72305536f, 0.730461f, 0.7379107f, 0.7454045f, 0.75294244f, 0.76052475f, 0.7681514f, 0.77582246f, - 0.78353804f, 0.79129815f, 0.79910296f, 0.8069525f, 0.8148468f, 0.822786f, 0.8307701f, 0.83879924f, 0.84687346f, - 0.8549928f, 0.8631574f, 0.87136734f, 0.8796226f, 0.8879232f, 0.89626956f, 0.90466136f, 0.913099f, 0.92158204f, - 0.93011117f, 0.9386859f, 0.9473069f, 0.9559735f, 0.9646866f, 0.9734455f, 0.98225087f, 0.9911022f, 1.0f - }; - - private static int linearToSrgb(float c) { - if (!(c > MIN_BOUND)) { - c = MIN_BOUND; - } - - if (c > MAX_BOUND) { - c = MAX_BOUND; - } - int inputBits = Float.floatToRawIntBits(c); - int entry = linearToSrgbTable[((inputBits - MIN_BITS) >> 20)]; - - int bias = (entry >>> 16) << 9; - int scale = entry & 0xffff; - int t = (inputBits >>> 12) & 0xff; - - return (bias + (scale * t)) >>> 16; - } - ////////////// + private static final float[] srgbToLinearTable = new float[] + { + 0.0f, 0.000303527f, 0.000607054f, 0.00091058103f, 0.001214108f, 0.001517635f, 0.0018211621f, 0.002124689f, + 0.002428216f, 0.002731743f, 0.00303527f, 0.0033465356f, 0.003676507f, 0.004024717f, 0.004391442f, + 0.0047769533f, 0.005181517f, 0.0056053917f, 0.0060488326f, 0.006512091f, 0.00699541f, 0.0074990317f, + 0.008023192f, 0.008568125f, 0.009134057f, 0.009721218f, 0.010329823f, 0.010960094f, 0.011612245f, + 0.012286487f, 0.012983031f, 0.013702081f, 0.014443844f, 0.015208514f, 0.015996292f, 0.016807375f, + 0.017641952f, 0.018500218f, 0.019382361f, 0.020288562f, 0.02121901f, 0.022173883f, 0.023153365f, + 0.02415763f, 0.025186857f, 0.026241222f, 0.027320892f, 0.028426038f, 0.029556843f, 0.03071345f, 0.03189604f, + 0.033104774f, 0.03433981f, 0.035601325f, 0.036889452f, 0.038204376f, 0.039546248f, 0.04091521f, 0.042311423f, + 0.043735042f, 0.045186214f, 0.046665095f, 0.048171833f, 0.049706575f, 0.051269468f, 0.052860655f, 0.05448028f, + 0.056128494f, 0.057805434f, 0.05951124f, 0.06124607f, 0.06301003f, 0.06480328f, 0.06662595f, 0.06847818f, + 0.07036011f, 0.07227186f, 0.07421358f, 0.07618539f, 0.07818743f, 0.08021983f, 0.082282715f, 0.084376216f, + 0.086500466f, 0.088655606f, 0.09084173f, 0.09305898f, 0.095307484f, 0.09758736f, 0.09989874f, 0.10224175f, + 0.10461649f, 0.10702311f, 0.10946172f, 0.111932434f, 0.11443538f, 0.116970696f, 0.11953845f, 0.12213881f, + 0.12477186f, 0.12743773f, 0.13013652f, 0.13286836f, 0.13563336f, 0.13843165f, 0.14126332f, 0.1441285f, + 0.1470273f, 0.14995982f, 0.15292618f, 0.1559265f, 0.15896086f, 0.16202943f, 0.16513224f, 0.16826946f, + 0.17144115f, 0.17464745f, 0.17788847f, 0.1811643f, 0.18447503f, 0.1878208f, 0.19120172f, 0.19461787f, + 0.19806935f, 0.2015563f, 0.20507877f, 0.2086369f, 0.21223079f, 0.21586053f, 0.21952623f, 0.22322798f, + 0.22696589f, 0.23074007f, 0.23455065f, 0.23839766f, 0.2422812f, 0.2462014f, 0.25015837f, 0.25415218f, + 0.2581829f, 0.26225072f, 0.26635566f, 0.27049786f, 0.27467737f, 0.27889434f, 0.2831488f, 0.2874409f, + 0.2917707f, 0.29613832f, 0.30054384f, 0.30498737f, 0.30946895f, 0.31398875f, 0.31854683f, 0.32314324f, + 0.32777813f, 0.33245158f, 0.33716366f, 0.34191445f, 0.3467041f, 0.3515327f, 0.35640025f, 0.36130688f, + 0.3662527f, 0.37123778f, 0.37626222f, 0.3813261f, 0.38642952f, 0.39157256f, 0.3967553f, 0.40197787f, + 0.4072403f, 0.4125427f, 0.41788515f, 0.42326775f, 0.42869055f, 0.4341537f, 0.43965724f, 0.44520125f, + 0.45078585f, 0.45641106f, 0.46207705f, 0.46778384f, 0.47353154f, 0.47932023f, 0.48514998f, 0.4910209f, + 0.49693304f, 0.5028866f, 0.50888145f, 0.5149178f, 0.5209957f, 0.52711535f, 0.5332766f, 0.5394797f, + 0.5457247f, 0.5520116f, 0.5583406f, 0.5647117f, 0.57112503f, 0.57758063f, 0.5840786f, 0.590619f, 0.597202f, + 0.60382754f, 0.61049575f, 0.61720675f, 0.62396055f, 0.63075733f, 0.637597f, 0.6444799f, 0.6514058f, + 0.65837497f, 0.66538745f, 0.67244333f, 0.6795426f, 0.68668544f, 0.69387203f, 0.70110214f, 0.70837605f, + 0.7156938f, 0.72305536f, 0.730461f, 0.7379107f, 0.7454045f, 0.75294244f, 0.76052475f, 0.7681514f, 0.77582246f, + 0.78353804f, 0.79129815f, 0.79910296f, 0.8069525f, 0.8148468f, 0.822786f, 0.8307701f, 0.83879924f, 0.84687346f, + 0.8549928f, 0.8631574f, 0.87136734f, 0.8796226f, 0.8879232f, 0.89626956f, 0.90466136f, 0.913099f, 0.92158204f, + 0.93011117f, 0.9386859f, 0.9473069f, 0.9559735f, 0.9646866f, 0.9734455f, 0.98225087f, 0.9911022f, 1.0f + }; - private static int getWidth(TextureAtlasSprite texture) + + + //=============// + // constructor // + //=============// + + public ClientBlockStateCache(BlockState blockState, IClientLevelWrapper samplingLevel) { - #if MC_VER < MC_1_19_4 - return texture.getWidth(); - #else - return texture.contents().width(); - #endif + this.blockState = blockState; + this.levelWrapper = samplingLevel; + this.level = (LevelReader) samplingLevel.getWrappedMcObject(); + this.resolveColors(); } - private static int getHeight(TextureAtlasSprite texture) + + + //===================// + // color calculation // + //===================// + + private void resolveColors() { - #if MC_VER < MC_1_19_4 - return texture.getHeight(); - #else - return texture.contents().height(); - #endif + if (this.isColorResolved) + { + return; + } + + if (this.blockState.getFluidState().isEmpty()) + { + // look for the first non-empty direction + List quads = null; + for (Direction direction : COLOR_RESOLUTION_DIRECTION_ORDER) + { + quads = Minecraft.getInstance().getModelManager().getBlockModelShaper(). + // TODO getQuads sometimes throws a "makeThreadingException", is there anything we can do about that? + // Note: this isn't a critical issue, it just prints an ugly error and the render data will need to be regenerated. + getBlockModel(this.blockState).getQuads(this.blockState, direction, random); + + if (quads != null && !quads.isEmpty() + && !( + this.blockState.getBlock() instanceof RotatedPillarBlock + && direction == Direction.UP + ) + ) + { + break; + } + } + + if (quads == null || quads.isEmpty()) + { + quads = Minecraft.getInstance().getModelManager().getBlockModelShaper(). + getBlockModel(this.blockState).getQuads(this.blockState, null, random); + } + + if (quads != null && !quads.isEmpty()) + { + this.needPostTinting = quads.get(0).isTinted(); + this.needShade = quads.get(0).isShade(); + this.tintIndex = quads.get(0).getTintIndex(); + this.baseColor = calculateColorFromTexture( + #if MC_VER < MC_1_17_1 quads.get(0).sprite, + #else quads.get(0).getSprite(), #endif + ColorMode.getColorMode(this.blockState.getBlock())); + } + else + { + // Backup method. + this.needPostTinting = false; + this.needShade = false; + this.tintIndex = 0; + this.baseColor = calculateColorFromTexture(Minecraft.getInstance().getModelManager().getBlockModelShaper().getParticleIcon(this.blockState), + ColorMode.getColorMode(this.blockState.getBlock())); + } + } + else + { + // Liquid Block + this.needPostTinting = true; + this.needShade = false; + this.tintIndex = 0; + this.baseColor = calculateColorFromTexture(Minecraft.getInstance().getModelManager().getBlockModelShaper().getParticleIcon(this.blockState), + ColorMode.getColorMode(this.blockState.getBlock())); + } + + this.isColorResolved = true; } - - //TODO: Perhaps make this not just use the first frame? private static int calculateColorFromTexture(TextureAtlasSprite texture, ColorMode colorMode) { @@ -212,13 +244,15 @@ public class ClientBlockStateCache double green = 0; double blue = 0; int tempColor; - //make Chiseled block not render. Since ColorMode is set per block, you only need to check it once + + // don't render Chiseled blocks. + // Since ColorMode is set per block, you only need to check this once. if (colorMode != ColorMode.Chisel) { // textures normally use u and v instead of x and y - for (int v = 0; v < getHeight(texture); v++) + for (int v = 0; v < getTextureHeight(texture); v++) { - for (int u = 0; u < getWidth(texture); u++) + for (int u = 0; u < getTextureWidth(texture); u++) { //note: Minecraft color format is: 0xAA BB GG RR //________ DH mod color format is: 0xAA RR GG BB @@ -270,8 +304,10 @@ public class ClientBlockStateCache } if (count == 0) + { // this block is entirely transparent tempColor = ColorUtil.rgbToInt(0, 255, 255, 255); + } else { // determine the average color @@ -281,6 +317,7 @@ public class ClientBlockStateCache linearToSrgb((float) (green / (double) alpha)), linearToSrgb((float) (blue / (double) alpha))); } + //check if not missing texture if (tempColor == ColorUtil.rgbToInt(255, 182, 0, 182)) { @@ -289,61 +326,53 @@ public class ClientBlockStateCache } return tempColor; } - private static final Direction[] DIRECTION_ORDER = {Direction.UP, Direction.NORTH, Direction.EAST, Direction.WEST, Direction.SOUTH, Direction.DOWN}; - - private void resolveColors() + private static int getTextureWidth(TextureAtlasSprite texture) { - if (isColorResolved) return; - if (blockState.getFluidState().isEmpty()) - { - List quads = null; - for (Direction direction : DIRECTION_ORDER) - { - quads = Minecraft.getInstance().getModelManager().getBlockModelShaper(). - getBlockModel(blockState).getQuads(blockState, direction, random); // TODO getQuads sometimes throws a "makeThreadingException", is there anything we can do about that? Note: this isn't a critical issue, it just prints an ugly error and the render data will need to be regenered. - if (quads != null && !quads.isEmpty() && - !(blockState.getBlock() instanceof RotatedPillarBlock && direction == Direction.UP)) - break; - } ; - if (quads == null || quads.isEmpty()) - { - quads = Minecraft.getInstance().getModelManager().getBlockModelShaper(). - getBlockModel(blockState).getQuads(blockState, null, random); - } - if (quads != null && !quads.isEmpty()) - { - needPostTinting = quads.get(0).isTinted(); - needShade = quads.get(0).isShade(); - tintIndex = quads.get(0).getTintIndex(); - baseColor = calculateColorFromTexture( - #if MC_VER < MC_1_17_1 quads.get(0).sprite, - #else quads.get(0).getSprite(), #endif - ColorMode.getColorMode(blockState.getBlock())); - } - else - { // Backup method. - needPostTinting = false; - needShade = false; - tintIndex = 0; - baseColor = calculateColorFromTexture(Minecraft.getInstance().getModelManager().getBlockModelShaper().getParticleIcon(blockState), - ColorMode.getColorMode(blockState.getBlock())); - } - } - else - { // Liquid Block - needPostTinting = true; - needShade = false; - tintIndex = 0; - baseColor = calculateColorFromTexture(Minecraft.getInstance().getModelManager().getBlockModelShaper().getParticleIcon(blockState), - ColorMode.getColorMode(blockState.getBlock())); - } - isColorResolved = true; + #if MC_VER < MC_1_19_4 + return texture.getWidth(); + #else + return texture.contents().width(); + #endif } + private static int getTextureHeight(TextureAtlasSprite texture) + { + #if MC_VER < MC_1_19_4 + return texture.getHeight(); + #else + return texture.contents().height(); + #endif + } + /** + * This method was suggested by IMS from the Iris/Sodium team. + * That's where the numbers and code are based. + */ + private static int linearToSrgb(float c) + { + if (!(c > MIN_SRGB_BOUND)) { + c = MIN_SRGB_BOUND; + } + + if (c > MAX_SRGB_BOUND) { + c = MAX_SRGB_BOUND; + } + int inputBits = Float.floatToRawIntBits(c); + int entry = linearToSrgbTable[((inputBits - MIN_SRGB_BITS) >> 20)]; + + int bias = (entry >>> 16) << 9; + int scale = entry & 0xffff; + int t = (inputBits >>> 12) & 0xff; + + return (bias + (scale * t)) >>> 16; + } + + + + //===============// + // public getter // + //===============// public int getAndResolveFaceColor(BiomeWrapper biome, DhBlockPos pos) { - // FIXME: impl per-face colors - // only get the tint if the block needs to be tinted if (!this.needPostTinting) { @@ -409,4 +438,30 @@ public class ClientBlockStateCache } } + + + //================// + // helper classes // + //================// + + enum ColorMode + { + Default, + Flower, + Leaves, + Chisel, + Glass; + + static ColorMode getColorMode(Block block) + { + if (block instanceof LeavesBlock) return Leaves; + if (block instanceof FlowerBlock) return Flower; + if (block.toString().contains("glass")) return Glass; + if (block.toString().equals("Block{chiselsandbits:chiseled}")) return Chisel; + return Default; + } + } + + + }