Refactor and comment LodBufferBuilder and LodBuilder

This commit is contained in:
James Seibel
2021-09-25 18:52:53 -05:00
parent 209e2579c3
commit ad793fe17e
2 changed files with 275 additions and 238 deletions
@@ -113,10 +113,6 @@ public class LodBufferBuilder
*/
private ReentrantLock bufferLock = new ReentrantLock();
// private static final int NUMBER_OF_DIRECTION = 4;
//in order -x, +x, -z, +z
// private static final int[][] ADJ_VECTOR = new int[][]{{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
private volatile Box[][] boxCache;
private volatile PosToRenderContainer[][] setsToRender;
private volatile RegionPos center;
@@ -167,18 +163,12 @@ public class LodBufferBuilder
try
{
long treeStart = System.currentTimeMillis();
long treeEnd = System.currentTimeMillis();
long startTime = System.currentTimeMillis();
ArrayList<Callable<Boolean>> nodeToRenderThreads = new ArrayList<>(lodDim.getWidth() * lodDim.getWidth());
startBuffers(fullRegen, lodDim);
// =====================//
// RENDERING PART //
// =====================//
RegionPos playerRegionPos = new RegionPos(playerChunkPos);
if (center == null)
@@ -199,6 +189,12 @@ public class LodBufferBuilder
// this will be the center of the VBOs once they have been built
buildableCenterChunkPos = playerChunkPos;
//================================//
// create the nodeToRenderThreads //
//================================//
for (int xRegion = 0; xRegion < lodDim.getWidth(); xRegion++)
{
for (int zRegion = 0; zRegion < lodDim.getWidth(); zRegion++)
@@ -233,26 +229,19 @@ public class LodBufferBuilder
// determine how many LODs we can stack vertically
int maxVerticalData = 1;
if (LodConfig.CLIENT.worldGenerator.lodQualityMode.get() == VerticalQuality.MULTI_LOD)
{
maxVerticalData = 256;
}
// create adjData's arrays
for (Direction direction : Box.ADJ_DIRECTIONS)
{
adjData.put(direction, new long[maxVerticalData]);
}
//previous setToRender cache
if (setsToRender[xR][zR] == null)
{
setsToRender[xR][zR] = new PosToRenderContainer(minDetail, regionPos.x, regionPos.z);
}
if (boxCache[xR][zR] == null)
{
boxCache[xR][zR] = new Box();
}
PosToRenderContainer posToRender = setsToRender[xR][zR];
posToRender.clear(minDetail, regionPos.x, regionPos.z);
@@ -301,6 +290,7 @@ public class LodBufferBuilder
chunkXdist = LevelPosUtil.getChunkPos(detailLevel, xAdj) - playerChunkPos.x;
chunkZdist = LevelPosUtil.getChunkPos(detailLevel, zAdj) - playerChunkPos.z;
boolean performFaceCulling = true;
if (performFaceCulling
&& posToRender.contains(detailLevel, xAdj, zAdj)
&& (gameChunkRenderDistance < Math.abs(chunkXdist)
@@ -314,7 +304,8 @@ public class LodBufferBuilder
long data = lodDim.getData(detailLevel, xAdj, zAdj, verticalIndex);
adjData.get(direction)[verticalIndex] = data;
}
} else
}
else
{
adjData.put(direction, null);
}
@@ -333,14 +324,17 @@ public class LodBufferBuilder
} // for pos to in list to render
// the thread executed successfully
// the thread executed successfully
return true;
};
nodeToRenderThreads.add(dataToRenderThread);
}
} // region z
} // region z
long renderStart = System.currentTimeMillis();
long executeStart = System.currentTimeMillis();
// wait for all threads to finish
List<Future<Boolean>> futuresBuffer = bufferBuilderThreads.invokeAll(nodeToRenderThreads);
for (Future<Boolean> future : futuresBuffer)
@@ -353,27 +347,27 @@ public class LodBufferBuilder
return;
}
}
long renderEnd = System.currentTimeMillis();
long executeEnd = System.currentTimeMillis();
long endTime = System.currentTimeMillis();
@SuppressWarnings("unused")
long buildTime = endTime - startTime;
@SuppressWarnings("unused")
long treeTime = treeEnd - treeStart;
@SuppressWarnings("unused")
long renderingTime = renderEnd - renderStart;
// ClientProxy.LOGGER.info("Buffer Build time: " + buildTime + " ms" + '\n' +
// "Tree cutting time: " + treeTime + " ms" + '\n' +
// "Rendering time: " + renderingTime + " ms");
long executeTime = executeEnd - executeStart;
// ClientProxy.LOGGER.info("Thread Build time: " + buildTime + " ms" + '\n' +
// "thread execute time: " + executeTime + " ms");
// mark that the buildable buffers as ready to swap
switchVbos = true;
} catch (Exception e)
}
catch (Exception e)
{
ClientProxy.LOGGER.warn("\"LodNodeBufferBuilder.generateLodBuffersAsync\" ran into trouble: ");
e.printStackTrace();
} finally
}
finally
{
// regardless of if we successfully created the buffers
// we are done generating.
@@ -409,26 +403,21 @@ public class LodBufferBuilder
int numbRegionsWide = lodDimension.getWidth();
int bufferMaxCapacity;
//if(previousRegionWidth != numbRegionsWide || firstSetup)
//{
previousRegionWidth = numbRegionsWide;
buildableBuffers = new BufferBuilder[numbRegionsWide][numbRegionsWide];
buildableVbos = new VertexBuffer[numbRegionsWide][numbRegionsWide];
drawableVbos = new VertexBuffer[numbRegionsWide][numbRegionsWide];
//}
for (int x = 0; x < numbRegionsWide; x++)
{
for (int z = 0; z < numbRegionsWide; z++)
{
//if(lodDimension.isBufferToSetup(x,z))
//{
bufferMaxCapacity = lodDimension.getMemoryRequired(x, z, LodConfig.CLIENT.graphics.lodTemplate.get());
buildableBuffers[x][z] = new BufferBuilder(bufferMaxCapacity);
buildableVbos[x][z] = new VertexBuffer(LodRenderer.LOD_VERTEX_FORMAT);
drawableVbos[x][z] = new VertexBuffer(LodRenderer.LOD_VERTEX_FORMAT);
//}
}
}
@@ -517,12 +506,6 @@ public class LodBufferBuilder
}
finally
{
// make sure no buffer is bound
if (glProxy.getGlContext() == GlProxyContext.LOD_BUILDER)
{
GL15C.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
}
// make sure the context is disabled
glProxy.setGlContext(GlProxyContext.NONE);
}
@@ -55,6 +55,7 @@ import net.minecraft.block.TallGrassBlock;
import net.minecraft.block.material.MaterialColor;
import net.minecraft.client.renderer.model.BakedQuad;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.world.ClientWorld;
import net.minecraft.util.Direction;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
@@ -76,7 +77,7 @@ import net.minecraftforge.client.model.data.ModelDataMap;
*
* @author Leonardo Amato
* @author James Seibel
* @version 9-18-2021
* @version 9-25-2021
*/
public class LodBuilder
{
@@ -84,7 +85,7 @@ public class LodBuilder
private ExecutorService lodGenThreadPool = Executors.newSingleThreadExecutor(new LodThreadFactory(this.getClass().getSimpleName()));
public static final Direction[] directions = new Direction[]{Direction.UP, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.NORTH, Direction.DOWN};
public static final Direction[] directions = new Direction[] { Direction.UP, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.NORTH, Direction.DOWN };
public static final int CHUNK_DATA_WIDTH = LodUtil.CHUNK_WIDTH;
public static final int CHUNK_SECTION_HEIGHT = CHUNK_DATA_WIDTH;
public static final Heightmap.Type DEFAULT_HEIGHTMAP = Heightmap.Type.WORLD_SURFACE_WG;
@@ -94,25 +95,33 @@ public class LodBuilder
public static final ModelDataMap dataMap = new ModelDataMap.Builder().build();
/**
* If no blocks are found in the area in determineBottomPointForArea return this
*/
/** If no blocks are found in the area in determineBottomPointForArea return this */
public static final short DEFAULT_DEPTH = 0;
/**
* If no blocks are found in the area in determineHeightPointForArea return this
*/
/** If no blocks are found in the area in determineHeightPointForArea return this */
public static final short DEFAULT_HEIGHT = 0;
/** Minecraft's max light value */
public static final short DEFAULT_MAX_LIGHT = 15;
/**
* How wide LodDimensions should be in regions
*/
/** TODO is this needed / used? */
public static final boolean onlyUseFullBlock = false;
/** TODO is this needed / used? */
public static final boolean avoidSmallBlock = false;
/** How wide LodDimensions should be in regions */
public int defaultDimensionWidthInRegions = 5;
public LodBuilder()
{
}
public void generateLodNodeAsync(IChunk chunk, LodWorld lodWorld, IWorld world)
{
generateLodNodeAsync(chunk, lodWorld, world, DistanceGenerationMode.SERVER);
@@ -141,31 +150,20 @@ public class LodBuilder
DimensionType dim = world.dimensionType();
// make sure the dimension exists
LodDimension lodDim;
int playerPosX;
int playerPosZ;
if (mc.getPlayer() == null)
{
playerPosX = chunk.getPos().getMinBlockX();
playerPosZ = chunk.getPos().getMinBlockZ();
} else
{
playerPosX = (int) mc.getPlayer().getX();
playerPosZ = (int) mc.getPlayer().getZ();
}
if (lodWorld.getLodDimension(dim) == null)
{
lodDim = new LodDimension(dim, lodWorld, defaultDimensionWidthInRegions);
ThreadMapUtil.clearMaps();
lodWorld.addLodDimension(lodDim);
lodDim.treeGenerator(playerPosX, playerPosZ);
} else
}
else
{
lodDim = lodWorld.getLodDimension(dim);
}
generateLodNodeFromChunk(lodDim, chunk, new LodBuilderConfig(generationMode));
} catch (IllegalArgumentException | NullPointerException e)
}
catch (IllegalArgumentException | NullPointerException e)
{
e.printStackTrace();
// if the world changes while LODs are being generated
@@ -177,7 +175,7 @@ public class LodBuilder
}
/**
* Creates a LodChunk for a chunk in the given world.
* Creates a LodNode for a chunk in the given world.
*
* @throws IllegalArgumentException thrown if either the chunk or world is null.
*/
@@ -187,7 +185,7 @@ public class LodBuilder
}
/**
* Creates a LodChunk for a chunk in the given world.
* Creates a LodNode for a chunk in the given world.
*
* @throws IllegalArgumentException thrown if either the chunk or world is null.
*/
@@ -201,78 +199,86 @@ public class LodBuilder
int startZ;
int endX;
int endZ;
try
{
HorizontalResolution detail;
LodRegion region = lodDim.getRegion(chunk.getPos().getRegionX(), chunk.getPos().getRegionZ());
if (region == null)
return;
byte minDetailLevel = region.getMinDetailLevel();
detail = DetailDistanceUtil.getLodGenDetail(minDetailLevel);
VerticalQuality verticalQuality = LodConfig.CLIENT.worldGenerator.lodQualityMode.get();
byte detailLevel = detail.detailLevel;
int posX;
int posZ;
for (int i = 0; i < detail.dataPointLengthCount * detail.dataPointLengthCount; i++)
{
startX = detail.startX[i];
startZ = detail.startZ[i];
endX = detail.endX[i];
endZ = detail.endZ[i];
posX = LevelPosUtil.convert((byte) 0, chunk.getPos().x * 16 + startX, detail.detailLevel);
posZ = LevelPosUtil.convert((byte) 0, chunk.getPos().z * 16 + startZ, detail.detailLevel);
long[] data;
switch (verticalQuality)
{
default:
case HEIGHTMAP:
long singleData;
long[] dataToMergeSingle = createSingleDataToMerge(detail, chunk, config, startX, startZ, endX, endZ);
singleData = DataPointUtil.mergeSingleData(dataToMergeSingle);
lodDim.addData(detailLevel,
posX,
posZ,
0,
singleData,
false);
break;
case MULTI_LOD:
long[] dataToMergeVertical = createVerticalDataToMerge(detail, chunk, config, startX, startZ, endX, endZ);
data = DataPointUtil.mergeMultiData(dataToMergeVertical, DataPointUtil.worldHeight, DetailDistanceUtil.getMaxVerticalData(detailLevel));
//lodDim.clear(detailLevel, posX, posZ);
if (data != null && data.length != 0)
{
for (int verticalIndex = 0; verticalIndex < lodDim.getMaxVerticalData(detailLevel, posX, posZ); verticalIndex++)
{
if (!DataPointUtil.doesItExist(data[verticalIndex]))
break;
lodDim.addData(detailLevel,
posX,
posZ,
verticalIndex,
data[verticalIndex],
false);
}
}
break;
}
}
lodDim.updateData(LodUtil.CHUNK_DETAIL_LEVEL, chunk.getPos().x, chunk.getPos().z);
} catch (Exception e)
{
e.printStackTrace();
throw e;
}
LodRegion region = lodDim.getRegion(chunk.getPos().getRegionX(), chunk.getPos().getRegionZ());
if (region == null)
return;
// determine how many LODs to generate horizontally
HorizontalResolution detail;
byte minDetailLevel = region.getMinDetailLevel();
detail = DetailDistanceUtil.getLodGenDetail(minDetailLevel);
// determine how many LODs to generate vertically
VerticalQuality verticalQuality = LodConfig.CLIENT.worldGenerator.lodQualityMode.get();
byte detailLevel = detail.detailLevel;
// generate the LODs
int posX;
int posZ;
for (int i = 0; i < detail.dataPointLengthCount * detail.dataPointLengthCount; i++)
{
startX = detail.startX[i];
startZ = detail.startZ[i];
endX = detail.endX[i];
endZ = detail.endZ[i];
posX = LevelPosUtil.convert((byte) 0, chunk.getPos().x * 16 + startX, detail.detailLevel);
posZ = LevelPosUtil.convert((byte) 0, chunk.getPos().z * 16 + startZ, detail.detailLevel);
long[] data;
switch (verticalQuality)
{
default:
case HEIGHTMAP:
long singleData;
long[] dataToMergeSingle = createSingleDataToMerge(detail, chunk, config, startX, startZ, endX, endZ);
singleData = DataPointUtil.mergeSingleData(dataToMergeSingle);
lodDim.addData(detailLevel,
posX,
posZ,
0,
singleData,
false);
break;
case MULTI_LOD:
long[] dataToMergeVertical = createVerticalDataToMerge(detail, chunk, config, startX, startZ, endX, endZ);
data = DataPointUtil.mergeMultiData(dataToMergeVertical, DataPointUtil.worldHeight, DetailDistanceUtil.getMaxVerticalData(detailLevel));
//lodDim.clear(detailLevel, posX, posZ);
if (data != null && data.length != 0)
{
for (int verticalIndex = 0; verticalIndex < lodDim.getMaxVerticalData(detailLevel, posX, posZ); verticalIndex++)
{
if (!DataPointUtil.doesItExist(data[verticalIndex]))
break;
lodDim.addData(detailLevel,
posX,
posZ,
verticalIndex,
data[verticalIndex],
false);
}
}
break;
}
}
lodDim.updateData(LodUtil.CHUNK_DETAIL_LEVEL, chunk.getPos().x, chunk.getPos().z);
}
/**
* creates a vertical DataPoint
*/
private long[] createVerticalDataToMerge(HorizontalResolution detail, IChunk chunk, LodBuilderConfig config, int startX, int startZ, int endX, int endZ)
{
// equivalent to 2^detailLevel
int size = 1 << detail.detailLevel;
long[] dataToMerge = ThreadMapUtil.getFreshBuilderVerticalArray(size * size * DataPointUtil.worldHeight + 1, detail.detailLevel);
@@ -314,7 +320,8 @@ public class LodBuilder
while (yAbs > 0)
{
height = determineHeightPointFrom(chunk, config, xRel, zRel, yAbs, blockPos);
//If the lod is at default, then we set this as void data
// If the lod is at the default height, it must be void data
if (height == DEFAULT_HEIGHT)
{
if (topBlock)
@@ -332,7 +339,8 @@ public class LodBuilder
light = getLightValue(chunk, blockPos, hasCeiling, hasSkyLight, topBlock);
color = generateLodColor(chunk, config, xRel, yAbs, zRel, blockPos);
blockPos.set(xAbs, yAbs - 1, zAbs);
} else
}
else
{
blockPos.set(xAbs, yAbs, zAbs);
light = getLightValue(chunk, blockPos, hasCeiling, hasSkyLight, topBlock);
@@ -354,14 +362,17 @@ public class LodBuilder
/**
* Find the lowest valid point from the bottom.
* Used when creating a vertical LOD.
*/
private short determineBottomPointFrom(IChunk chunk, LodBuilderConfig config, int xRel, int zRel, int yAbs, BlockPos.Mutable blockPos)
{
short depth = DEFAULT_DEPTH;
if (config.useHeightmap)
{
// when using the generated heightmap there is no data about the lowest point
depth = 0;
} else
}
else
{
boolean voidData = true;
ChunkSection[] chunkSections = chunk.getSections();
@@ -371,6 +382,7 @@ public class LodBuilder
{
if (sectionIndex * CHUNK_DATA_WIDTH + yRel > yAbs)
continue;
blockPos.set(chunk.getPos().getMinBlockX() + xRel, sectionIndex * CHUNK_DATA_WIDTH + yRel, chunk.getPos().getMinBlockZ() + zRel);
if (!isLayerValidLodPoint(chunk, blockPos))
{
@@ -379,10 +391,9 @@ public class LodBuilder
break;
}
}
if (!voidData)
{
break;
}
}
}
return depth;
@@ -397,7 +408,8 @@ public class LodBuilder
if (config.useHeightmap)
{
height = (short) chunk.getOrCreateHeightmapUnprimed(LodUtil.DEFAULT_HEIGHTMAP).getFirstAvailable(xRel, zRel);
} else
}
else
{
boolean voidData = true;
ChunkSection[] chunkSections = chunk.getSections();
@@ -422,6 +434,9 @@ public class LodBuilder
return height;
}
/**
* Creates a single HeightMap style LOD data point.
*/
private long[] createSingleDataToMerge(HorizontalResolution detail, IChunk chunk, LodBuilderConfig config, int startX, int startZ, int endX, int endZ)
{
long[] dataToMerge = ThreadMapUtil.getBuilderArray(detail.detailLevel);
@@ -451,6 +466,7 @@ public class LodBuilder
{
dataToMerge = new long[size * size];
}
for (index = 0; index < size * size; index++)
{
xRel = Math.floorMod(index, size) + startX;
@@ -461,7 +477,7 @@ public class LodBuilder
//Calculate the height of the lod
height = determineHeightPoint(chunk, config, xRel, zRel, blockPos);
//If the lod is at default, then we set this as void data
//If the lod is at the default height it must be void
if (height == DEFAULT_HEIGHT)
{
dataToMerge[index] = DataPointUtil.createVoidDataPoint(generation);
@@ -469,20 +485,25 @@ public class LodBuilder
}
yAbs = height - 1;
// We search light on above air block
color = generateLodColor(chunk, config, xRel, yAbs, zRel, blockPos);
depth = determineBottomPoint(chunk, config, xRel, zRel, blockPos);
// get the light value from the above air block
blockPos.set(xAbs, yAbs + 1, zAbs);
light = getLightValue(chunk, blockPos, hasCeiling, hasSkyLight, true);
lightBlock = light & 0b1111;
//lightSky = (light >> 4) & 0b1111;
lightSky = 15; //default max light
lightSky = DEFAULT_MAX_LIGHT;
dataToMerge[index] = DataPointUtil.createDataPoint(height, depth, color, lightSky, lightBlock, generation);
}
return dataToMerge;
}
// =====================//
// constructor helpers //
// =====================//
@@ -497,7 +518,8 @@ public class LodBuilder
if (config.useHeightmap)
{
depth = 0;
} else
}
else
{
boolean found = false;
for (int sectionIndex = 0; sectionIndex < chunkSections.length; sectionIndex++)
@@ -512,10 +534,9 @@ public class LodBuilder
break;
}
}
if (found)
{
break;
}
}
}
return depth;
@@ -531,7 +552,8 @@ public class LodBuilder
if (config.useHeightmap)
{
height = (short) chunk.getOrCreateHeightmapUnprimed(LodUtil.DEFAULT_HEIGHTMAP).getFirstAvailable(xRel, zRel);
} else
}
else
{
boolean voidData = true;
ChunkSection[] chunkSections = chunk.getSections();
@@ -547,10 +569,9 @@ public class LodBuilder
break;
}
}
if (!voidData)
{
break;
}
}
}
return height;
@@ -570,37 +591,39 @@ public class LodBuilder
// if I don't the biomes don't show up correctly.
Biome biome = chunk.getBiomes().getNoiseBiome(xRel >> 2, yAbs >> 2, zRel >> 2);
colorInt = getColorForBiome(xRel, zRel, biome);
} else
}
else
{
int sectionIndex = Math.floorDiv(yAbs, CHUNK_SECTION_HEIGHT);
int yRel = Math.floorMod(yAbs, CHUNK_SECTION_HEIGHT);
if (chunkSections[sectionIndex] != null)
{
// the bit shift is equivalent to dividing by 4
blockPos.set(chunk.getPos().getMinBlockX() + xRel, sectionIndex * CHUNK_DATA_WIDTH + yRel, chunk.getPos().getMinBlockZ() + zRel);
//colorInt = getColorTextureForBlock(blockState, blockPos);
colorInt = getColorForBlock(chunk, blockPos);
}
if (colorInt == 0 && yAbs > 0)
{
//invisible case
// if this block is invisible, check the block below it
colorInt = generateLodColor(chunk, config, xRel, yAbs - 1, zRel, blockPos);
}
}
return colorInt;
}
/**
* Gets the light value for the given block position
*/
private int getLightValue(IChunk chunk, BlockPos.Mutable blockPos, boolean hasCeiling, boolean hasSkyLight, boolean topBlock)
{
int skyLight;
int blockLight = 0;
if (mc.getClientWorld() == null)
return 0;
IWorld world = mc.getClientWorld();
ClientWorld world = mc.getClientWorld();
//int blockBrightness = world.getBrightness(LightType.BLOCK, blockPos);
int blockBrightness = chunk.getLightEmission(blockPos);
if (hasCeiling && topBlock)
@@ -613,63 +636,72 @@ public class LodBuilder
{
skyLight = 0;
}
else if(topBlock)
else if (topBlock)
{
skyLight = 15; //default max light
} else
skyLight = DEFAULT_MAX_LIGHT;
}
else
{
if (chunk.isLightCorrect() && false)
if (chunk.isLightCorrect())
{
skyLight = world.getBrightness(LightType.SKY, blockPos);
} else
}
else
{
if (blockPos.getY() >= mc.getClientWorld().getSeaLevel()-5)
{
// we don't know what the light here is,
// lets just take a guess
if (blockPos.getY() >= mc.getClientWorld().getSeaLevel() - 5)
skyLight = 10;
} else
{
else
skyLight = 0;
}
}
}
blockLight = world.getBrightness(LightType.BLOCK, blockPos);
blockLight = LodUtil.clamp(0, blockLight + blockBrightness, 15);
blockLight = LodUtil.clamp(0, blockLight + blockBrightness, DEFAULT_MAX_LIGHT);
return blockLight + (skyLight << 4);
}
private int getColorTextureForBlock(BlockState blockState, BlockPos blockPos, boolean topTextureRequired)
/**
* Generate the color of the given block from its texture
* and store it for later use.
*/
private int getColorTextureForBlock(BlockState blockState, BlockPos blockPos, boolean useTopTexture)
{
// use the pre-generated color if we can
Block block = blockState.getBlock();
if (colorMap.containsKey(block) && toTint.containsKey(block))
return colorMap.get(block);
World world = mc.getClientWorld();
TextureAtlasSprite texture;
List<BakedQuad> quad = null;
// get the first quad we can for this block
for (Direction direction : directions)
{
quad = mc.getModelManager().getBlockModelShaper().getBlockModel(blockState).getQuads(blockState, direction, new Random(0), dataMap);
if (!quad.isEmpty())
{
break;
}
}
if (!quad.isEmpty())
{
toTint.put(block, quad.get(0).isTinted());
} else
else
toTint.put(blockState.getBlock(), false);
if (topTextureRequired && !quad.isEmpty())
{
if (useTopTexture && !quad.isEmpty())
texture = quad.get(0).getSprite();
} else
{
else
texture = mc.getModelManager().getBlockModelShaper().getTexture(blockState, world, blockPos);
}
int count = 0;
@@ -680,55 +712,73 @@ public class LodBuilder
int numberOfGreyPixel = 0;
int color;
int colorMultiplier;
for (int k = 0; k < texture.getFrameCount(); k++)
// generate the block's color
for (int frameIndex = 0; frameIndex < texture.getFrameCount(); frameIndex++)
{
for (int i = 0; i < texture.getHeight(); i++)
// textures normally use u and v instead of x and y
for (int u = 0; u < texture.getHeight(); u++)
{
for (int j = 0; j < texture.getWidth(); j++)
for (int v = 0; v < texture.getWidth(); v++)
{
if (texture.isTransparent(k, i, j))
if (texture.isTransparent(frameIndex, u, v))
continue;
color = texture.getPixelRGBA(k, i, j);
if (Math.max(Math.max(ColorUtil.getBlue(color), ColorUtil.getGreen(color)), ColorUtil.getRed(color)) < 4 + Math.min(Math.min(ColorUtil.getBlue(color), ColorUtil.getGreen(color)), ColorUtil.getRed(color)))
{
color = texture.getPixelRGBA(frameIndex, u, v);
// determine if this pixel is gray
int colorMax = Math.max(Math.max(ColorUtil.getBlue(color), ColorUtil.getGreen(color)), ColorUtil.getRed(color));
int colorMin = 4 + Math.min(Math.min(ColorUtil.getBlue(color), ColorUtil.getGreen(color)), ColorUtil.getRed(color));
boolean isGray = colorMax < colorMin;
if (isGray)
numberOfGreyPixel++;
}
// for flowers, weight their non-green color higher
if (block instanceof FlowerBlock && (!(ColorUtil.getGreen(color) > (ColorUtil.getBlue(color) + 30)) || !(ColorUtil.getGreen(color) > (ColorUtil.getRed(color) + 30))))
colorMultiplier = 5;
else
colorMultiplier = 1;
count = colorMultiplier + count;
// add to the running averages
count = colorMultiplier + count; // TODO shouldn't colorMultiplier be multiplied by?
alpha += ColorUtil.getAlpha(color) * colorMultiplier;
;
red += ColorUtil.getBlue(color) * colorMultiplier;
green += ColorUtil.getGreen(color) * colorMultiplier;
blue += ColorUtil.getRed(color) * colorMultiplier;
}
}
}
if (count == 0)
{
// this block is entirely transparent
color = 0;
} else
}
else
{
// determine the average color
alpha /= count;
red /= count;
green /= count;
blue /= count;
color = ColorUtil.rgbToInt(alpha, red, green, blue);
}
if (blockState.getBlock().equals(Blocks.TALL_GRASS))
System.out.println(ColorUtil.toString(color) + " " + numberOfGreyPixel + " " + count);
if (block instanceof TallGrassBlock || (couldHaveGrassTint(block) || couldHaveLeavesTint(block) || couldHaveWaterTint(block)) && numberOfGreyPixel / count > 0.75f)
{
// determine if this block should use the biome color tint
if (block instanceof TallGrassBlock || (useGrassTint(block) || useLeafTint(block) || useWaterTint(block)) && numberOfGreyPixel / count > 0.75f)
toTint.replace(block, true);
}
// add the newly generated block color to the map for later use
colorMap.put(block, color);
return color;
}
private boolean couldHaveGrassTint(Block block)
/** determine if the given block should use the biome's grass color */
private boolean useGrassTint(Block block)
{
return block instanceof GrassBlock
|| block instanceof BushBlock
@@ -738,33 +788,35 @@ public class LodBuilder
|| block instanceof TallGrassBlock;
}
private boolean couldHaveLeavesTint(Block block)
/** determine if the given block should use the biome's foliage color */
private boolean useLeafTint(Block block)
{
return block instanceof LeavesBlock
|| block == Blocks.VINE
|| block == Blocks.SUGAR_CANE;
}
private boolean couldHaveWaterTint(Block block)
/** determine if the given block should use the biome's water color */
private boolean useWaterTint(Block block)
{
return block == Blocks.WATER;
}
/**
* Returns a color int for the given block.
*/
/** Returns a color int for the given block. */
private int getColorForBlock(IChunk chunk, BlockPos blockPos)
{
int blockColor;
int colorInt = 0;
int xRel = blockPos.getX() - chunk.getPos().getMinBlockX();
int zRel = blockPos.getZ() - chunk.getPos().getMinBlockZ();
int x = blockPos.getX();
int y = blockPos.getY();
int z = blockPos.getZ();
Biome biome = chunk.getBiomes().getNoiseBiome(xRel >> 2, y >> 2, zRel >> 2);
int blockColor;
Biome biome = chunk.getBiomes().getNoiseBiome(xRel >> 2, y >> 2, zRel >> 2);
BlockState blockState = chunk.getBlockState(blockPos);
int colorInt = 0;
// block special cases
@@ -781,25 +833,27 @@ public class LodBuilder
blockColor = getColorTextureForBlock(blockState, blockPos, true);
if (toTint.get(blockState.getBlock()).booleanValue())
{
// leaves
if (couldHaveLeavesTint(blockState.getBlock()))
if (useLeafTint(blockState.getBlock()))
{
// leaves
colorInt = ColorUtil.multiplyRGBcolors(biome.getFoliageColor(), blockColor);
}
// grass and green plants
else if (couldHaveGrassTint(blockState.getBlock()))
else if (useGrassTint(blockState.getBlock()))
{
// grass and green plants
colorInt = ColorUtil.multiplyRGBcolors(biome.getGrassColor(x, z), blockColor);
}
// water
else if (couldHaveWaterTint(blockState.getBlock()))
else if (useWaterTint(blockState.getBlock()))
{
// water
colorInt = ColorUtil.multiplyRGBcolors(biome.getWaterColor(), blockColor);
}
} else
}
else
{
colorInt = blockColor;
}
return colorInt;
}
@@ -816,37 +870,37 @@ public class LodBuilder
case NETHER:
colorInt = LodUtil.NETHERRACK_COLOR_INT;
break;
case THEEND:
colorInt = Blocks.END_STONE.defaultBlockState().materialColor.col;
break;
case BEACH:
case DESERT:
colorInt = Blocks.SAND.defaultBlockState().materialColor.col;
break;
case EXTREME_HILLS:
colorInt = Blocks.STONE.defaultMaterialColor().col;
break;
case MUSHROOM:
colorInt = MaterialColor.COLOR_LIGHT_GRAY.col;
break;
case ICY:
colorInt = Blocks.SNOW.defaultMaterialColor().col;
break;
case MESA:
colorInt = Blocks.RED_SAND.defaultMaterialColor().col;
break;
case OCEAN:
case RIVER:
colorInt = biome.getWaterColor();
break;
case NONE:
case FOREST:
case TAIGA:
@@ -859,38 +913,36 @@ public class LodBuilder
tmp = tmp.darker();
colorInt = LodUtil.colorToInt(tmp);
break;
}
return colorInt;
}
/**
* Is the layer between the given X, Z, and dataIndex values a valid LOD point?
*/
/** Is the block at the given blockPos a valid LOD point? */
private boolean isLayerValidLodPoint(IChunk chunk, BlockPos.Mutable blockPos)
{
BlockState blockState = chunk.getBlockState(blockPos);
boolean onlyUseFullBlock = false;
boolean avoidSmallBlock = false;
if (blockState != null)
{
//blockState.isCollisionShapeFullBlock(chunk, blockPos);
// TODO this code is dead since avoidSmallBlock and onlyUseFullBlock
// are set to false and are never changed.
// should this code be changed?
if (avoidSmallBlock || onlyUseFullBlock)
{
if (!blockState.getFluidState().isEmpty())
{
return true;
}
VoxelShape voxelShape;
if (shapeMap.containsKey(blockState.getBlock()))
{
voxelShape = shapeMap.get(blockState.getBlock());
} else
}
else
{
voxelShape = blockState.getShape(chunk, blockPos);
shapeMap.put(blockState.getBlock(), voxelShape);
@@ -909,7 +961,8 @@ public class LodBuilder
{
return false;
}
} else
}
else
{
return false;
}
@@ -919,6 +972,7 @@ public class LodBuilder
&& blockState.getBlock() != Blocks.CAVE_AIR
&& blockState.getBlock() != Blocks.BARRIER;
}
return false;
}
}