2025-11-24 22:52:51 +03:00

655 lines
37 KiB
Java

/*
* Decompiled with CFR 0.152.
*
* Could not load the following classes:
* it.unimi.dsi.fastutil.longs.Long2FloatLinkedOpenHashMap
* it.unimi.dsi.fastutil.longs.Long2IntLinkedOpenHashMap
*/
package net.minecraft.client.renderer.block;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import it.unimi.dsi.fastutil.longs.Long2FloatLinkedOpenHashMap;
import it.unimi.dsi.fastutil.longs.Long2IntLinkedOpenHashMap;
import java.util.List;
import net.minecraft.CrashReport;
import net.minecraft.CrashReportCategory;
import net.minecraft.ReportedException;
import net.minecraft.client.Minecraft;
import net.minecraft.client.color.block.BlockColors;
import net.minecraft.client.renderer.LevelRenderer;
import net.minecraft.client.renderer.block.model.BakedQuad;
import net.minecraft.client.renderer.block.model.BlockModelPart;
import net.minecraft.client.renderer.block.model.BlockStateModel;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.Vec3i;
import net.minecraft.util.ARGB;
import net.minecraft.util.Mth;
import net.minecraft.util.RandomSource;
import net.minecraft.util.Util;
import net.minecraft.world.level.BlockAndTintGetter;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
public class ModelBlockRenderer {
private static final Direction[] DIRECTIONS = Direction.values();
private final BlockColors blockColors;
private static final int CACHE_SIZE = 100;
private static final ThreadLocal<Cache> CACHE = ThreadLocal.withInitial(Cache::new);
public ModelBlockRenderer(BlockColors blockColors) {
this.blockColors = blockColors;
}
public void tesselateBlock(BlockAndTintGetter level, List<BlockModelPart> parts, BlockState blockState, BlockPos pos, PoseStack poseStack, VertexConsumer builder, boolean cull, int overlayCoords) {
if (parts.isEmpty()) {
return;
}
boolean useAO = Minecraft.useAmbientOcclusion() && blockState.getLightEmission() == 0 && parts.getFirst().useAmbientOcclusion();
poseStack.translate(blockState.getOffset(pos));
try {
if (useAO) {
this.tesselateWithAO(level, parts, blockState, pos, poseStack, builder, cull, overlayCoords);
} else {
this.tesselateWithoutAO(level, parts, blockState, pos, poseStack, builder, cull, overlayCoords);
}
}
catch (Throwable t) {
CrashReport report = CrashReport.forThrowable(t, "Tesselating block model");
CrashReportCategory category = report.addCategory("Block model being tesselated");
CrashReportCategory.populateBlockDetails(category, level, pos, blockState);
category.setDetail("Using AO", useAO);
throw new ReportedException(report);
}
}
private static boolean shouldRenderFace(BlockAndTintGetter level, BlockState state, boolean cullEnabled, Direction direction, BlockPos neighborPos) {
if (!cullEnabled) {
return true;
}
BlockState neighborState = level.getBlockState(neighborPos);
return Block.shouldRenderFace(state, neighborState, direction);
}
public void tesselateWithAO(BlockAndTintGetter level, List<BlockModelPart> parts, BlockState state, BlockPos pos, PoseStack poseStack, VertexConsumer builder, boolean cull, int overlayCoords) {
AmbientOcclusionRenderStorage scratch = new AmbientOcclusionRenderStorage();
int cacheValid = 0;
int shouldRenderFaceCache = 0;
for (BlockModelPart part : parts) {
for (Direction direction : DIRECTIONS) {
List<BakedQuad> culledQuads;
boolean shouldRenderFace;
int cacheMask = 1 << direction.ordinal();
boolean validCacheForDirection = (cacheValid & cacheMask) == 1;
boolean bl = shouldRenderFace = (shouldRenderFaceCache & cacheMask) == 1;
if (validCacheForDirection && !shouldRenderFace || (culledQuads = part.getQuads(direction)).isEmpty()) continue;
if (!validCacheForDirection) {
shouldRenderFace = ModelBlockRenderer.shouldRenderFace(level, state, cull, direction, scratch.scratchPos.setWithOffset((Vec3i)pos, direction));
cacheValid |= cacheMask;
if (shouldRenderFace) {
shouldRenderFaceCache |= cacheMask;
}
}
if (!shouldRenderFace) continue;
this.renderModelFaceAO(level, state, pos, poseStack, builder, culledQuads, scratch, overlayCoords);
}
List<BakedQuad> unculledQuads = part.getQuads(null);
if (unculledQuads.isEmpty()) continue;
this.renderModelFaceAO(level, state, pos, poseStack, builder, unculledQuads, scratch, overlayCoords);
}
}
public void tesselateWithoutAO(BlockAndTintGetter level, List<BlockModelPart> parts, BlockState state, BlockPos pos, PoseStack poseStack, VertexConsumer builder, boolean cull, int overlayCoords) {
CommonRenderStorage scratch = new CommonRenderStorage();
int cacheValid = 0;
int shouldRenderFaceCache = 0;
for (BlockModelPart part : parts) {
for (Direction direction : DIRECTIONS) {
List<BakedQuad> culledQuads;
boolean shouldRenderFace;
int cacheMask = 1 << direction.ordinal();
boolean validCacheForDirection = (cacheValid & cacheMask) == 1;
boolean bl = shouldRenderFace = (shouldRenderFaceCache & cacheMask) == 1;
if (validCacheForDirection && !shouldRenderFace || (culledQuads = part.getQuads(direction)).isEmpty()) continue;
BlockPos.MutableBlockPos relativePos = scratch.scratchPos.setWithOffset((Vec3i)pos, direction);
if (!validCacheForDirection) {
shouldRenderFace = ModelBlockRenderer.shouldRenderFace(level, state, cull, direction, relativePos);
cacheValid |= cacheMask;
if (shouldRenderFace) {
shouldRenderFaceCache |= cacheMask;
}
}
if (!shouldRenderFace) continue;
int lightColor = scratch.cache.getLightColor(state, level, relativePos);
this.renderModelFaceFlat(level, state, pos, lightColor, overlayCoords, false, poseStack, builder, culledQuads, scratch);
}
List<BakedQuad> unculledQuads = part.getQuads(null);
if (unculledQuads.isEmpty()) continue;
this.renderModelFaceFlat(level, state, pos, -1, overlayCoords, true, poseStack, builder, unculledQuads, scratch);
}
}
private void renderModelFaceAO(BlockAndTintGetter level, BlockState state, BlockPos pos, PoseStack poseStack, VertexConsumer builder, List<BakedQuad> quads, AmbientOcclusionRenderStorage storage, int overlayCoords) {
for (BakedQuad quad : quads) {
ModelBlockRenderer.calculateShape(level, state, pos, quad.vertices(), quad.direction(), storage);
storage.calculate(level, state, pos, quad.direction(), quad.shade());
this.putQuadData(level, state, pos, builder, poseStack.last(), quad, storage, overlayCoords);
}
}
private void putQuadData(BlockAndTintGetter level, BlockState state, BlockPos pos, VertexConsumer builder, PoseStack.Pose pose, BakedQuad quad, CommonRenderStorage renderStorage, int overlayCoords) {
float b;
float g;
float r;
int tintIndex = quad.tintIndex();
if (tintIndex != -1) {
int tintColor;
if (renderStorage.tintCacheIndex == tintIndex) {
tintColor = renderStorage.tintCacheValue;
} else {
tintColor = this.blockColors.getColor(state, level, pos, tintIndex);
renderStorage.tintCacheIndex = tintIndex;
renderStorage.tintCacheValue = tintColor;
}
r = ARGB.redFloat(tintColor);
g = ARGB.greenFloat(tintColor);
b = ARGB.blueFloat(tintColor);
} else {
r = 1.0f;
g = 1.0f;
b = 1.0f;
}
builder.putBulkData(pose, quad, renderStorage.brightness, r, g, b, 1.0f, renderStorage.lightmap, overlayCoords, true);
}
private static void calculateShape(BlockAndTintGetter level, BlockState state, BlockPos pos, int[] vertices, Direction direction, CommonRenderStorage storage) {
float minX = 32.0f;
float minY = 32.0f;
float minZ = 32.0f;
float maxX = -32.0f;
float maxY = -32.0f;
float maxZ = -32.0f;
for (int i = 0; i < 4; ++i) {
float x = Float.intBitsToFloat(vertices[i * 8]);
float y = Float.intBitsToFloat(vertices[i * 8 + 1]);
float z = Float.intBitsToFloat(vertices[i * 8 + 2]);
minX = Math.min(minX, x);
minY = Math.min(minY, y);
minZ = Math.min(minZ, z);
maxX = Math.max(maxX, x);
maxY = Math.max(maxY, y);
maxZ = Math.max(maxZ, z);
}
if (storage instanceof AmbientOcclusionRenderStorage) {
AmbientOcclusionRenderStorage aoStorage = (AmbientOcclusionRenderStorage)storage;
aoStorage.faceShape[SizeInfo.WEST.index] = minX;
aoStorage.faceShape[SizeInfo.EAST.index] = maxX;
aoStorage.faceShape[SizeInfo.DOWN.index] = minY;
aoStorage.faceShape[SizeInfo.UP.index] = maxY;
aoStorage.faceShape[SizeInfo.NORTH.index] = minZ;
aoStorage.faceShape[SizeInfo.SOUTH.index] = maxZ;
aoStorage.faceShape[SizeInfo.FLIP_WEST.index] = 1.0f - minX;
aoStorage.faceShape[SizeInfo.FLIP_EAST.index] = 1.0f - maxX;
aoStorage.faceShape[SizeInfo.FLIP_DOWN.index] = 1.0f - minY;
aoStorage.faceShape[SizeInfo.FLIP_UP.index] = 1.0f - maxY;
aoStorage.faceShape[SizeInfo.FLIP_NORTH.index] = 1.0f - minZ;
aoStorage.faceShape[SizeInfo.FLIP_SOUTH.index] = 1.0f - maxZ;
}
float minEpsilon = 1.0E-4f;
float maxEpsilon = 0.9999f;
storage.facePartial = switch (direction) {
default -> throw new MatchException(null, null);
case Direction.DOWN, Direction.UP -> {
if (minX >= 1.0E-4f || minZ >= 1.0E-4f || maxX <= 0.9999f || maxZ <= 0.9999f) {
yield true;
}
yield false;
}
case Direction.NORTH, Direction.SOUTH -> {
if (minX >= 1.0E-4f || minY >= 1.0E-4f || maxX <= 0.9999f || maxY <= 0.9999f) {
yield true;
}
yield false;
}
case Direction.WEST, Direction.EAST -> minY >= 1.0E-4f || minZ >= 1.0E-4f || maxY <= 0.9999f || maxZ <= 0.9999f;
};
storage.faceCubic = switch (direction) {
default -> throw new MatchException(null, null);
case Direction.DOWN -> {
if (minY == maxY && (minY < 1.0E-4f || state.isCollisionShapeFullBlock(level, pos))) {
yield true;
}
yield false;
}
case Direction.UP -> {
if (minY == maxY && (maxY > 0.9999f || state.isCollisionShapeFullBlock(level, pos))) {
yield true;
}
yield false;
}
case Direction.NORTH -> {
if (minZ == maxZ && (minZ < 1.0E-4f || state.isCollisionShapeFullBlock(level, pos))) {
yield true;
}
yield false;
}
case Direction.SOUTH -> {
if (minZ == maxZ && (maxZ > 0.9999f || state.isCollisionShapeFullBlock(level, pos))) {
yield true;
}
yield false;
}
case Direction.WEST -> {
if (minX == maxX && (minX < 1.0E-4f || state.isCollisionShapeFullBlock(level, pos))) {
yield true;
}
yield false;
}
case Direction.EAST -> minX == maxX && (maxX > 0.9999f || state.isCollisionShapeFullBlock(level, pos));
};
}
private void renderModelFaceFlat(BlockAndTintGetter level, BlockState state, BlockPos pos, int lightColor, int overlayCoords, boolean checkLight, PoseStack poseStack, VertexConsumer builder, List<BakedQuad> quads, CommonRenderStorage shapeState) {
for (BakedQuad quad : quads) {
float directionalBrightness;
if (checkLight) {
ModelBlockRenderer.calculateShape(level, state, pos, quad.vertices(), quad.direction(), shapeState);
BlockPos lightPos = shapeState.faceCubic ? shapeState.scratchPos.setWithOffset((Vec3i)pos, quad.direction()) : pos;
lightColor = shapeState.cache.getLightColor(state, level, lightPos);
}
shapeState.brightness[0] = directionalBrightness = level.getShade(quad.direction(), quad.shade());
shapeState.brightness[1] = directionalBrightness;
shapeState.brightness[2] = directionalBrightness;
shapeState.brightness[3] = directionalBrightness;
shapeState.lightmap[0] = lightColor;
shapeState.lightmap[1] = lightColor;
shapeState.lightmap[2] = lightColor;
shapeState.lightmap[3] = lightColor;
this.putQuadData(level, state, pos, builder, poseStack.last(), quad, shapeState, overlayCoords);
}
}
public static void renderModel(PoseStack.Pose pose, VertexConsumer builder, BlockStateModel model, float r, float g, float b, int lightCoords, int overlayCoords) {
for (BlockModelPart part : model.collectParts(RandomSource.create(42L))) {
for (Direction direction : DIRECTIONS) {
ModelBlockRenderer.renderQuadList(pose, builder, r, g, b, part.getQuads(direction), lightCoords, overlayCoords);
}
ModelBlockRenderer.renderQuadList(pose, builder, r, g, b, part.getQuads(null), lightCoords, overlayCoords);
}
}
private static void renderQuadList(PoseStack.Pose pose, VertexConsumer builder, float r, float g, float b, List<BakedQuad> quads, int lightCoords, int overlayCoords) {
for (BakedQuad quad : quads) {
float blue;
float green;
float red;
if (quad.isTinted()) {
red = Mth.clamp(r, 0.0f, 1.0f);
green = Mth.clamp(g, 0.0f, 1.0f);
blue = Mth.clamp(b, 0.0f, 1.0f);
} else {
red = 1.0f;
green = 1.0f;
blue = 1.0f;
}
builder.putBulkData(pose, quad, red, green, blue, 1.0f, lightCoords, overlayCoords);
}
}
public static void enableCaching() {
CACHE.get().enable();
}
public static void clearCache() {
CACHE.get().disable();
}
private static class AmbientOcclusionRenderStorage
extends CommonRenderStorage {
private final float[] faceShape = new float[SizeInfo.COUNT];
public void calculate(BlockAndTintGetter level, BlockState state, BlockPos centerPosition, Direction direction, boolean shade) {
int lightCorner13;
float shadeCorner13;
int lightCorner12;
float shadeCorner12;
int lightCorner03;
float shadeCorner03;
int lightCorner02;
float shadeCorner02;
boolean translucent3;
BlockPos basePosition = this.faceCubic ? centerPosition.relative(direction) : centerPosition;
AdjacencyInfo info = AdjacencyInfo.fromFacing(direction);
BlockPos.MutableBlockPos pos = this.scratchPos;
pos.setWithOffset((Vec3i)basePosition, info.corners[0]);
BlockState state0 = level.getBlockState(pos);
int light0 = this.cache.getLightColor(state0, level, pos);
float shade0 = this.cache.getShadeBrightness(state0, level, pos);
pos.setWithOffset((Vec3i)basePosition, info.corners[1]);
BlockState state1 = level.getBlockState(pos);
int light1 = this.cache.getLightColor(state1, level, pos);
float shade1 = this.cache.getShadeBrightness(state1, level, pos);
pos.setWithOffset((Vec3i)basePosition, info.corners[2]);
BlockState state2 = level.getBlockState(pos);
int light2 = this.cache.getLightColor(state2, level, pos);
float shade2 = this.cache.getShadeBrightness(state2, level, pos);
pos.setWithOffset((Vec3i)basePosition, info.corners[3]);
BlockState state3 = level.getBlockState(pos);
int light3 = this.cache.getLightColor(state3, level, pos);
float shade3 = this.cache.getShadeBrightness(state3, level, pos);
BlockState corner0 = level.getBlockState(pos.setWithOffset((Vec3i)basePosition, info.corners[0]).move(direction));
boolean translucent0 = !corner0.isViewBlocking(level, pos) || corner0.getLightBlock() == 0;
BlockState corner1 = level.getBlockState(pos.setWithOffset((Vec3i)basePosition, info.corners[1]).move(direction));
boolean translucent1 = !corner1.isViewBlocking(level, pos) || corner1.getLightBlock() == 0;
BlockState corner2 = level.getBlockState(pos.setWithOffset((Vec3i)basePosition, info.corners[2]).move(direction));
boolean translucent2 = !corner2.isViewBlocking(level, pos) || corner2.getLightBlock() == 0;
BlockState corner3 = level.getBlockState(pos.setWithOffset((Vec3i)basePosition, info.corners[3]).move(direction));
boolean bl = translucent3 = !corner3.isViewBlocking(level, pos) || corner3.getLightBlock() == 0;
if (translucent2 || translucent0) {
pos.setWithOffset((Vec3i)basePosition, info.corners[0]).move(info.corners[2]);
BlockState state02 = level.getBlockState(pos);
shadeCorner02 = this.cache.getShadeBrightness(state02, level, pos);
lightCorner02 = this.cache.getLightColor(state02, level, pos);
} else {
shadeCorner02 = shade0;
lightCorner02 = light0;
}
if (translucent3 || translucent0) {
pos.setWithOffset((Vec3i)basePosition, info.corners[0]).move(info.corners[3]);
BlockState state03 = level.getBlockState(pos);
shadeCorner03 = this.cache.getShadeBrightness(state03, level, pos);
lightCorner03 = this.cache.getLightColor(state03, level, pos);
} else {
shadeCorner03 = shade0;
lightCorner03 = light0;
}
if (translucent2 || translucent1) {
pos.setWithOffset((Vec3i)basePosition, info.corners[1]).move(info.corners[2]);
BlockState state12 = level.getBlockState(pos);
shadeCorner12 = this.cache.getShadeBrightness(state12, level, pos);
lightCorner12 = this.cache.getLightColor(state12, level, pos);
} else {
shadeCorner12 = shade0;
lightCorner12 = light0;
}
if (translucent3 || translucent1) {
pos.setWithOffset((Vec3i)basePosition, info.corners[1]).move(info.corners[3]);
BlockState state13 = level.getBlockState(pos);
shadeCorner13 = this.cache.getShadeBrightness(state13, level, pos);
lightCorner13 = this.cache.getLightColor(state13, level, pos);
} else {
shadeCorner13 = shade0;
lightCorner13 = light0;
}
int lightCenter = this.cache.getLightColor(state, level, centerPosition);
pos.setWithOffset((Vec3i)centerPosition, direction);
BlockState nextState = level.getBlockState(pos);
if (this.faceCubic || !nextState.isSolidRender()) {
lightCenter = this.cache.getLightColor(nextState, level, pos);
}
float shadeCenter = this.faceCubic ? this.cache.getShadeBrightness(level.getBlockState(basePosition), level, basePosition) : this.cache.getShadeBrightness(level.getBlockState(centerPosition), level, centerPosition);
AmbientVertexRemap remap = AmbientVertexRemap.fromFacing(direction);
if (!this.facePartial || !info.doNonCubicWeight) {
float lightLevel1 = (shade3 + shade0 + shadeCorner03 + shadeCenter) * 0.25f;
float lightLevel2 = (shade2 + shade0 + shadeCorner02 + shadeCenter) * 0.25f;
float lightLevel3 = (shade2 + shade1 + shadeCorner12 + shadeCenter) * 0.25f;
float lightLevel4 = (shade3 + shade1 + shadeCorner13 + shadeCenter) * 0.25f;
this.lightmap[remap.vert0] = AmbientOcclusionRenderStorage.blend(light3, light0, lightCorner03, lightCenter);
this.lightmap[remap.vert1] = AmbientOcclusionRenderStorage.blend(light2, light0, lightCorner02, lightCenter);
this.lightmap[remap.vert2] = AmbientOcclusionRenderStorage.blend(light2, light1, lightCorner12, lightCenter);
this.lightmap[remap.vert3] = AmbientOcclusionRenderStorage.blend(light3, light1, lightCorner13, lightCenter);
this.brightness[remap.vert0] = lightLevel1;
this.brightness[remap.vert1] = lightLevel2;
this.brightness[remap.vert2] = lightLevel3;
this.brightness[remap.vert3] = lightLevel4;
} else {
float tempShade1 = (shade3 + shade0 + shadeCorner03 + shadeCenter) * 0.25f;
float tempShade2 = (shade2 + shade0 + shadeCorner02 + shadeCenter) * 0.25f;
float tempShade3 = (shade2 + shade1 + shadeCorner12 + shadeCenter) * 0.25f;
float tempShade4 = (shade3 + shade1 + shadeCorner13 + shadeCenter) * 0.25f;
float vert0weight01 = this.faceShape[info.vert0Weights[0].index] * this.faceShape[info.vert0Weights[1].index];
float vert0weight23 = this.faceShape[info.vert0Weights[2].index] * this.faceShape[info.vert0Weights[3].index];
float vert0weight45 = this.faceShape[info.vert0Weights[4].index] * this.faceShape[info.vert0Weights[5].index];
float vert0weight67 = this.faceShape[info.vert0Weights[6].index] * this.faceShape[info.vert0Weights[7].index];
float vert1weight01 = this.faceShape[info.vert1Weights[0].index] * this.faceShape[info.vert1Weights[1].index];
float vert1weight23 = this.faceShape[info.vert1Weights[2].index] * this.faceShape[info.vert1Weights[3].index];
float vert1weight45 = this.faceShape[info.vert1Weights[4].index] * this.faceShape[info.vert1Weights[5].index];
float vert1weight67 = this.faceShape[info.vert1Weights[6].index] * this.faceShape[info.vert1Weights[7].index];
float vert2weight01 = this.faceShape[info.vert2Weights[0].index] * this.faceShape[info.vert2Weights[1].index];
float vert2weight23 = this.faceShape[info.vert2Weights[2].index] * this.faceShape[info.vert2Weights[3].index];
float vert2weight45 = this.faceShape[info.vert2Weights[4].index] * this.faceShape[info.vert2Weights[5].index];
float vert2weight67 = this.faceShape[info.vert2Weights[6].index] * this.faceShape[info.vert2Weights[7].index];
float vert3weight01 = this.faceShape[info.vert3Weights[0].index] * this.faceShape[info.vert3Weights[1].index];
float vert3weight23 = this.faceShape[info.vert3Weights[2].index] * this.faceShape[info.vert3Weights[3].index];
float vert3weight45 = this.faceShape[info.vert3Weights[4].index] * this.faceShape[info.vert3Weights[5].index];
float vert3weight67 = this.faceShape[info.vert3Weights[6].index] * this.faceShape[info.vert3Weights[7].index];
this.brightness[remap.vert0] = Math.clamp(tempShade1 * vert0weight01 + tempShade2 * vert0weight23 + tempShade3 * vert0weight45 + tempShade4 * vert0weight67, 0.0f, 1.0f);
this.brightness[remap.vert1] = Math.clamp(tempShade1 * vert1weight01 + tempShade2 * vert1weight23 + tempShade3 * vert1weight45 + tempShade4 * vert1weight67, 0.0f, 1.0f);
this.brightness[remap.vert2] = Math.clamp(tempShade1 * vert2weight01 + tempShade2 * vert2weight23 + tempShade3 * vert2weight45 + tempShade4 * vert2weight67, 0.0f, 1.0f);
this.brightness[remap.vert3] = Math.clamp(tempShade1 * vert3weight01 + tempShade2 * vert3weight23 + tempShade3 * vert3weight45 + tempShade4 * vert3weight67, 0.0f, 1.0f);
int _tc1 = AmbientOcclusionRenderStorage.blend(light3, light0, lightCorner03, lightCenter);
int _tc2 = AmbientOcclusionRenderStorage.blend(light2, light0, lightCorner02, lightCenter);
int _tc3 = AmbientOcclusionRenderStorage.blend(light2, light1, lightCorner12, lightCenter);
int _tc4 = AmbientOcclusionRenderStorage.blend(light3, light1, lightCorner13, lightCenter);
this.lightmap[remap.vert0] = AmbientOcclusionRenderStorage.blend(_tc1, _tc2, _tc3, _tc4, vert0weight01, vert0weight23, vert0weight45, vert0weight67);
this.lightmap[remap.vert1] = AmbientOcclusionRenderStorage.blend(_tc1, _tc2, _tc3, _tc4, vert1weight01, vert1weight23, vert1weight45, vert1weight67);
this.lightmap[remap.vert2] = AmbientOcclusionRenderStorage.blend(_tc1, _tc2, _tc3, _tc4, vert2weight01, vert2weight23, vert2weight45, vert2weight67);
this.lightmap[remap.vert3] = AmbientOcclusionRenderStorage.blend(_tc1, _tc2, _tc3, _tc4, vert3weight01, vert3weight23, vert3weight45, vert3weight67);
}
float directionalBrightness = level.getShade(direction, shade);
int i = 0;
while (i < this.brightness.length) {
int n = i++;
this.brightness[n] = this.brightness[n] * directionalBrightness;
}
}
private static int blend(int a, int b, int c, int def) {
if (a == 0) {
a = def;
}
if (b == 0) {
b = def;
}
if (c == 0) {
c = def;
}
return a + b + c + def >> 2 & 0xFF00FF;
}
private static int blend(int a, int b, int c, int d, float fa, float fb, float fc, float fd) {
int top = (int)((float)(a >> 16 & 0xFF) * fa + (float)(b >> 16 & 0xFF) * fb + (float)(c >> 16 & 0xFF) * fc + (float)(d >> 16 & 0xFF) * fd) & 0xFF;
int bottom = (int)((float)(a & 0xFF) * fa + (float)(b & 0xFF) * fb + (float)(c & 0xFF) * fc + (float)(d & 0xFF) * fd) & 0xFF;
return top << 16 | bottom;
}
}
private static class CommonRenderStorage {
public final BlockPos.MutableBlockPos scratchPos = new BlockPos.MutableBlockPos();
public boolean faceCubic;
public boolean facePartial;
public final float[] brightness = new float[4];
public final int[] lightmap = new int[4];
public int tintCacheIndex = -1;
public int tintCacheValue;
public final Cache cache = CACHE.get();
private CommonRenderStorage() {
}
}
private static class Cache {
private boolean enabled;
private final Long2IntLinkedOpenHashMap colorCache = Util.make(() -> {
Long2IntLinkedOpenHashMap map = new Long2IntLinkedOpenHashMap(100, 0.25f){
protected void rehash(int newN) {
}
};
map.defaultReturnValue(Integer.MAX_VALUE);
return map;
});
private final Long2FloatLinkedOpenHashMap brightnessCache = Util.make(() -> {
Long2FloatLinkedOpenHashMap map = new Long2FloatLinkedOpenHashMap(100, 0.25f){
protected void rehash(int newN) {
}
};
map.defaultReturnValue(Float.NaN);
return map;
});
private final LevelRenderer.BrightnessGetter cachedBrightnessGetter = (level, pos) -> {
long key = pos.asLong();
int cached = this.colorCache.get(key);
if (cached != Integer.MAX_VALUE) {
return cached;
}
int value = LevelRenderer.BrightnessGetter.DEFAULT.packedBrightness(level, pos);
if (this.colorCache.size() == 100) {
this.colorCache.removeFirstInt();
}
this.colorCache.put(key, value);
return value;
};
private Cache() {
}
public void enable() {
this.enabled = true;
}
public void disable() {
this.enabled = false;
this.colorCache.clear();
this.brightnessCache.clear();
}
public int getLightColor(BlockState state, BlockAndTintGetter level, BlockPos pos) {
return LevelRenderer.getLightColor(this.enabled ? this.cachedBrightnessGetter : LevelRenderer.BrightnessGetter.DEFAULT, level, state, pos);
}
public float getShadeBrightness(BlockState state, BlockAndTintGetter level, BlockPos pos) {
float cached;
long key = pos.asLong();
if (this.enabled && !Float.isNaN(cached = this.brightnessCache.get(key))) {
return cached;
}
float brightness = state.getShadeBrightness(level, pos);
if (this.enabled) {
if (this.brightnessCache.size() == 100) {
this.brightnessCache.removeFirstFloat();
}
this.brightnessCache.put(key, brightness);
}
return brightness;
}
}
protected static enum SizeInfo {
DOWN(0),
UP(1),
NORTH(2),
SOUTH(3),
WEST(4),
EAST(5),
FLIP_DOWN(6),
FLIP_UP(7),
FLIP_NORTH(8),
FLIP_SOUTH(9),
FLIP_WEST(10),
FLIP_EAST(11);
public static final int COUNT;
private final int index;
private SizeInfo(int index) {
this.index = index;
}
static {
COUNT = SizeInfo.values().length;
}
}
protected static enum AdjacencyInfo {
DOWN(new Direction[]{Direction.WEST, Direction.EAST, Direction.NORTH, Direction.SOUTH}, 0.5f, true, new SizeInfo[]{SizeInfo.FLIP_WEST, SizeInfo.SOUTH, SizeInfo.FLIP_WEST, SizeInfo.FLIP_SOUTH, SizeInfo.WEST, SizeInfo.FLIP_SOUTH, SizeInfo.WEST, SizeInfo.SOUTH}, new SizeInfo[]{SizeInfo.FLIP_WEST, SizeInfo.NORTH, SizeInfo.FLIP_WEST, SizeInfo.FLIP_NORTH, SizeInfo.WEST, SizeInfo.FLIP_NORTH, SizeInfo.WEST, SizeInfo.NORTH}, new SizeInfo[]{SizeInfo.FLIP_EAST, SizeInfo.NORTH, SizeInfo.FLIP_EAST, SizeInfo.FLIP_NORTH, SizeInfo.EAST, SizeInfo.FLIP_NORTH, SizeInfo.EAST, SizeInfo.NORTH}, new SizeInfo[]{SizeInfo.FLIP_EAST, SizeInfo.SOUTH, SizeInfo.FLIP_EAST, SizeInfo.FLIP_SOUTH, SizeInfo.EAST, SizeInfo.FLIP_SOUTH, SizeInfo.EAST, SizeInfo.SOUTH}),
UP(new Direction[]{Direction.EAST, Direction.WEST, Direction.NORTH, Direction.SOUTH}, 1.0f, true, new SizeInfo[]{SizeInfo.EAST, SizeInfo.SOUTH, SizeInfo.EAST, SizeInfo.FLIP_SOUTH, SizeInfo.FLIP_EAST, SizeInfo.FLIP_SOUTH, SizeInfo.FLIP_EAST, SizeInfo.SOUTH}, new SizeInfo[]{SizeInfo.EAST, SizeInfo.NORTH, SizeInfo.EAST, SizeInfo.FLIP_NORTH, SizeInfo.FLIP_EAST, SizeInfo.FLIP_NORTH, SizeInfo.FLIP_EAST, SizeInfo.NORTH}, new SizeInfo[]{SizeInfo.WEST, SizeInfo.NORTH, SizeInfo.WEST, SizeInfo.FLIP_NORTH, SizeInfo.FLIP_WEST, SizeInfo.FLIP_NORTH, SizeInfo.FLIP_WEST, SizeInfo.NORTH}, new SizeInfo[]{SizeInfo.WEST, SizeInfo.SOUTH, SizeInfo.WEST, SizeInfo.FLIP_SOUTH, SizeInfo.FLIP_WEST, SizeInfo.FLIP_SOUTH, SizeInfo.FLIP_WEST, SizeInfo.SOUTH}),
NORTH(new Direction[]{Direction.UP, Direction.DOWN, Direction.EAST, Direction.WEST}, 0.8f, true, new SizeInfo[]{SizeInfo.UP, SizeInfo.FLIP_WEST, SizeInfo.UP, SizeInfo.WEST, SizeInfo.FLIP_UP, SizeInfo.WEST, SizeInfo.FLIP_UP, SizeInfo.FLIP_WEST}, new SizeInfo[]{SizeInfo.UP, SizeInfo.FLIP_EAST, SizeInfo.UP, SizeInfo.EAST, SizeInfo.FLIP_UP, SizeInfo.EAST, SizeInfo.FLIP_UP, SizeInfo.FLIP_EAST}, new SizeInfo[]{SizeInfo.DOWN, SizeInfo.FLIP_EAST, SizeInfo.DOWN, SizeInfo.EAST, SizeInfo.FLIP_DOWN, SizeInfo.EAST, SizeInfo.FLIP_DOWN, SizeInfo.FLIP_EAST}, new SizeInfo[]{SizeInfo.DOWN, SizeInfo.FLIP_WEST, SizeInfo.DOWN, SizeInfo.WEST, SizeInfo.FLIP_DOWN, SizeInfo.WEST, SizeInfo.FLIP_DOWN, SizeInfo.FLIP_WEST}),
SOUTH(new Direction[]{Direction.WEST, Direction.EAST, Direction.DOWN, Direction.UP}, 0.8f, true, new SizeInfo[]{SizeInfo.UP, SizeInfo.FLIP_WEST, SizeInfo.FLIP_UP, SizeInfo.FLIP_WEST, SizeInfo.FLIP_UP, SizeInfo.WEST, SizeInfo.UP, SizeInfo.WEST}, new SizeInfo[]{SizeInfo.DOWN, SizeInfo.FLIP_WEST, SizeInfo.FLIP_DOWN, SizeInfo.FLIP_WEST, SizeInfo.FLIP_DOWN, SizeInfo.WEST, SizeInfo.DOWN, SizeInfo.WEST}, new SizeInfo[]{SizeInfo.DOWN, SizeInfo.FLIP_EAST, SizeInfo.FLIP_DOWN, SizeInfo.FLIP_EAST, SizeInfo.FLIP_DOWN, SizeInfo.EAST, SizeInfo.DOWN, SizeInfo.EAST}, new SizeInfo[]{SizeInfo.UP, SizeInfo.FLIP_EAST, SizeInfo.FLIP_UP, SizeInfo.FLIP_EAST, SizeInfo.FLIP_UP, SizeInfo.EAST, SizeInfo.UP, SizeInfo.EAST}),
WEST(new Direction[]{Direction.UP, Direction.DOWN, Direction.NORTH, Direction.SOUTH}, 0.6f, true, new SizeInfo[]{SizeInfo.UP, SizeInfo.SOUTH, SizeInfo.UP, SizeInfo.FLIP_SOUTH, SizeInfo.FLIP_UP, SizeInfo.FLIP_SOUTH, SizeInfo.FLIP_UP, SizeInfo.SOUTH}, new SizeInfo[]{SizeInfo.UP, SizeInfo.NORTH, SizeInfo.UP, SizeInfo.FLIP_NORTH, SizeInfo.FLIP_UP, SizeInfo.FLIP_NORTH, SizeInfo.FLIP_UP, SizeInfo.NORTH}, new SizeInfo[]{SizeInfo.DOWN, SizeInfo.NORTH, SizeInfo.DOWN, SizeInfo.FLIP_NORTH, SizeInfo.FLIP_DOWN, SizeInfo.FLIP_NORTH, SizeInfo.FLIP_DOWN, SizeInfo.NORTH}, new SizeInfo[]{SizeInfo.DOWN, SizeInfo.SOUTH, SizeInfo.DOWN, SizeInfo.FLIP_SOUTH, SizeInfo.FLIP_DOWN, SizeInfo.FLIP_SOUTH, SizeInfo.FLIP_DOWN, SizeInfo.SOUTH}),
EAST(new Direction[]{Direction.DOWN, Direction.UP, Direction.NORTH, Direction.SOUTH}, 0.6f, true, new SizeInfo[]{SizeInfo.FLIP_DOWN, SizeInfo.SOUTH, SizeInfo.FLIP_DOWN, SizeInfo.FLIP_SOUTH, SizeInfo.DOWN, SizeInfo.FLIP_SOUTH, SizeInfo.DOWN, SizeInfo.SOUTH}, new SizeInfo[]{SizeInfo.FLIP_DOWN, SizeInfo.NORTH, SizeInfo.FLIP_DOWN, SizeInfo.FLIP_NORTH, SizeInfo.DOWN, SizeInfo.FLIP_NORTH, SizeInfo.DOWN, SizeInfo.NORTH}, new SizeInfo[]{SizeInfo.FLIP_UP, SizeInfo.NORTH, SizeInfo.FLIP_UP, SizeInfo.FLIP_NORTH, SizeInfo.UP, SizeInfo.FLIP_NORTH, SizeInfo.UP, SizeInfo.NORTH}, new SizeInfo[]{SizeInfo.FLIP_UP, SizeInfo.SOUTH, SizeInfo.FLIP_UP, SizeInfo.FLIP_SOUTH, SizeInfo.UP, SizeInfo.FLIP_SOUTH, SizeInfo.UP, SizeInfo.SOUTH});
private final Direction[] corners;
private final boolean doNonCubicWeight;
private final SizeInfo[] vert0Weights;
private final SizeInfo[] vert1Weights;
private final SizeInfo[] vert2Weights;
private final SizeInfo[] vert3Weights;
private static final AdjacencyInfo[] BY_FACING;
private AdjacencyInfo(Direction[] corners, float shadeWeight, boolean doNonCubicWeight, SizeInfo[] vert0Weights, SizeInfo[] vert1Weights, SizeInfo[] vert2Weights, SizeInfo[] vert3Weights) {
this.corners = corners;
this.doNonCubicWeight = doNonCubicWeight;
this.vert0Weights = vert0Weights;
this.vert1Weights = vert1Weights;
this.vert2Weights = vert2Weights;
this.vert3Weights = vert3Weights;
}
public static AdjacencyInfo fromFacing(Direction direction) {
return BY_FACING[direction.get3DDataValue()];
}
static {
BY_FACING = Util.make(new AdjacencyInfo[6], map -> {
map[Direction.DOWN.get3DDataValue()] = DOWN;
map[Direction.UP.get3DDataValue()] = UP;
map[Direction.NORTH.get3DDataValue()] = NORTH;
map[Direction.SOUTH.get3DDataValue()] = SOUTH;
map[Direction.WEST.get3DDataValue()] = WEST;
map[Direction.EAST.get3DDataValue()] = EAST;
});
}
}
private static enum AmbientVertexRemap {
DOWN(0, 1, 2, 3),
UP(2, 3, 0, 1),
NORTH(3, 0, 1, 2),
SOUTH(0, 1, 2, 3),
WEST(3, 0, 1, 2),
EAST(1, 2, 3, 0);
private final int vert0;
private final int vert1;
private final int vert2;
private final int vert3;
private static final AmbientVertexRemap[] BY_FACING;
private AmbientVertexRemap(int vert0, int vert1, int vert2, int vert3) {
this.vert0 = vert0;
this.vert1 = vert1;
this.vert2 = vert2;
this.vert3 = vert3;
}
public static AmbientVertexRemap fromFacing(Direction direction) {
return BY_FACING[direction.get3DDataValue()];
}
static {
BY_FACING = Util.make(new AmbientVertexRemap[6], map -> {
map[Direction.DOWN.get3DDataValue()] = DOWN;
map[Direction.UP.get3DDataValue()] = UP;
map[Direction.NORTH.get3DDataValue()] = NORTH;
map[Direction.SOUTH.get3DDataValue()] = SOUTH;
map[Direction.WEST.get3DDataValue()] = WEST;
map[Direction.EAST.get3DDataValue()] = EAST;
});
}
}
}