Refactor, comment, and clean up everything
This adds comments to almost every class, removes a few classes that weren't being used, improves the names of a number of methods, and does a bunch of random polishing/cleaning.
This commit is contained in:
@@ -16,6 +16,10 @@ import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
|
||||
import net.minecraftforge.fml.relauncher.IFMLLoadingPlugin;
|
||||
|
||||
/**
|
||||
* Initialize and setup the Mod.
|
||||
* <br>
|
||||
* If you are looking for the real start of the mod
|
||||
* check out the ClientProxy.
|
||||
*
|
||||
* @author James Seibel
|
||||
* @version 02-07-2021
|
||||
|
||||
@@ -5,7 +5,6 @@ import java.util.concurrent.Callable;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import com.backsun.lod.objects.NearFarBuffer;
|
||||
import com.backsun.lod.renderer.RenderUtil;
|
||||
import com.backsun.lod.util.enums.FogDistance;
|
||||
|
||||
import net.minecraft.client.renderer.BufferBuilder;
|
||||
@@ -13,10 +12,12 @@ import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
|
||||
import net.minecraft.util.math.AxisAlignedBB;
|
||||
|
||||
/**
|
||||
*
|
||||
* This object is used to create NearFarBuffer objects
|
||||
* in a thread independent way, so multiple of these objects can be
|
||||
* created and executed in parallel to populate BufferBuilders.
|
||||
*
|
||||
* @author James Seibel
|
||||
* @version 02-21-2021
|
||||
* @version 02-22-2021
|
||||
*/
|
||||
public class BuildBufferThread implements Callable<NearFarBuffer>
|
||||
{
|
||||
@@ -70,6 +71,9 @@ public class BuildBufferThread implements Callable<NearFarBuffer>
|
||||
int blue;
|
||||
int alpha;
|
||||
|
||||
// this is done if the FogDistance is either
|
||||
// NEAR or FAR, if it is NEAR_AND_FAR
|
||||
// the buffer is determined for each LOD
|
||||
if (distanceMode == FogDistance.NEAR)
|
||||
{
|
||||
currentBuffer = nearBuffer;
|
||||
@@ -97,10 +101,10 @@ public class BuildBufferThread implements Callable<NearFarBuffer>
|
||||
blue = colors[i][j].getBlue();
|
||||
alpha = colors[i][j].getAlpha();
|
||||
|
||||
// choose which buffer to add these LODs too
|
||||
|
||||
if (distanceMode == FogDistance.NEAR_AND_FAR)
|
||||
{
|
||||
if (RenderUtil.isCoordinateInNearFogArea(i, j, numbChunksWide / 2))
|
||||
if (isCoordinateInNearFogArea(i, j, numbChunksWide / 2))
|
||||
currentBuffer = nearBuffer;
|
||||
else
|
||||
currentBuffer = farBuffer;
|
||||
@@ -193,6 +197,22 @@ public class BuildBufferThread implements Callable<NearFarBuffer>
|
||||
{
|
||||
buffer.pos(x, y, z).color(red, green, blue, alpha).endVertex();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Find the coordinates that are in the center half of the given
|
||||
* 2D matrix, starting at (0,0) and going to (2 * lodRadius, 2 * lodRadius).
|
||||
*/
|
||||
private static boolean isCoordinateInNearFogArea(int chunkX, int chunkZ, int lodRadius)
|
||||
{
|
||||
int halfRadius = lodRadius / 2;
|
||||
|
||||
return (chunkX >= lodRadius - halfRadius
|
||||
&& chunkX <= lodRadius + halfRadius)
|
||||
&&
|
||||
(chunkZ >= lodRadius - halfRadius
|
||||
&& chunkZ <= lodRadius + halfRadius);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -3,7 +3,7 @@ package com.backsun.lod.builders;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
import com.backsun.lod.handlers.LodFileHandler;
|
||||
import com.backsun.lod.handlers.LodDimensionFileHandler;
|
||||
import com.backsun.lod.objects.LodChunk;
|
||||
import com.backsun.lod.objects.LodDimension;
|
||||
import com.backsun.lod.objects.LodWorld;
|
||||
@@ -20,12 +20,12 @@ import net.minecraft.world.chunk.storage.ExtendedBlockStorage;
|
||||
* (specifically: Lod World, Dimension, Region, and Chunk objects)
|
||||
*
|
||||
* @author James Seibel
|
||||
* @version 2-21-2021
|
||||
* @version 2-22-2021
|
||||
*/
|
||||
public class LodBuilder
|
||||
{
|
||||
private ExecutorService lodGenThreadPool = Executors.newFixedThreadPool(1);
|
||||
public LodWorld lodWorld;
|
||||
private ExecutorService lodGenThreadPool = Executors.newSingleThreadExecutor();
|
||||
public volatile LodWorld lodWorld;
|
||||
|
||||
/** Default size of any LOD regions we use */
|
||||
public int regionWidth = 5;
|
||||
@@ -41,7 +41,7 @@ public class LodBuilder
|
||||
* Returns LodWorld so that it can be passed
|
||||
* to the LodRenderer.
|
||||
*/
|
||||
public LodWorld generateLodChunk(Chunk chunk)
|
||||
public LodWorld generateLodChunkAsync(Chunk chunk)
|
||||
{
|
||||
Minecraft mc = Minecraft.getMinecraft();
|
||||
|
||||
@@ -68,13 +68,13 @@ public class LodBuilder
|
||||
|
||||
if (lodWorld == null)
|
||||
{
|
||||
lodWorld = new LodWorld(LodFileHandler.getWorldName());
|
||||
lodWorld = new LodWorld(LodDimensionFileHandler.getWorldName());
|
||||
}
|
||||
else
|
||||
{
|
||||
// if we have a lodWorld make sure
|
||||
// it is for this minecraft world
|
||||
if (!lodWorld.worldName.equals(LodFileHandler.getWorldName()))
|
||||
if (!lodWorld.worldName.equals(LodDimensionFileHandler.getWorldName()))
|
||||
{
|
||||
// this lodWorld isn't for this minecraft world
|
||||
// delete it so we can get a new one
|
||||
@@ -106,7 +106,6 @@ public class LodBuilder
|
||||
// they will throw errors as they try to access things that no longer
|
||||
// exist.
|
||||
}
|
||||
|
||||
});
|
||||
lodGenThreadPool.execute(thread);
|
||||
|
||||
@@ -119,9 +118,9 @@ public class LodBuilder
|
||||
*/
|
||||
public boolean isValidChunk(Chunk chunk)
|
||||
{
|
||||
ExtendedBlockStorage[] data = chunk.getBlockStorageArray();
|
||||
ExtendedBlockStorage[] blockStorage = chunk.getBlockStorageArray();
|
||||
|
||||
for(ExtendedBlockStorage e : data)
|
||||
for(ExtendedBlockStorage e : blockStorage)
|
||||
{
|
||||
if(e != null && !e.isEmpty())
|
||||
{
|
||||
|
||||
+26
-57
@@ -23,9 +23,9 @@ import net.minecraft.world.storage.ISaveHandler;
|
||||
* @author James Seibel
|
||||
* @version 01-30-2021
|
||||
*/
|
||||
public class LodFileHandler
|
||||
public class LodDimensionFileHandler
|
||||
{
|
||||
private LodDimension loadedRegion = null;
|
||||
private LodDimension loadedDimension = null;
|
||||
public long regionLastWriteTime[][];
|
||||
|
||||
// String s = Minecraft.getMinecraftDir().getCanonicalPath() + "/saves/" + world.getSaveHandler().getSaveDirectoryName() + "/data/AA/World" + world.provider.dimensionId + ".dat";
|
||||
@@ -36,19 +36,17 @@ public class LodFileHandler
|
||||
private final String FILE_EXTENSION = ".txt";
|
||||
|
||||
private ExecutorService fileWritingThreadPool = Executors.newFixedThreadPool(1);
|
||||
/** Is true if the readyToReadAndWrite is false */
|
||||
private boolean waitingToSaveRegions = false;
|
||||
|
||||
|
||||
public LodFileHandler(ISaveHandler newSaveHandler, LodDimension newLoadedRegion)
|
||||
public LodDimensionFileHandler(ISaveHandler newSaveHandler, LodDimension newLoadedDimension)
|
||||
{
|
||||
saveHandler = newSaveHandler;
|
||||
|
||||
loadedRegion = newLoadedRegion;
|
||||
loadedDimension = newLoadedDimension;
|
||||
// these two variable are used in sync with the LodDimension
|
||||
regionLastWriteTime = new long[loadedRegion.getWidth()][loadedRegion.getWidth()];
|
||||
for(int i = 0; i < loadedRegion.getWidth(); i++)
|
||||
for(int j = 0; j < loadedRegion.getWidth(); j++)
|
||||
regionLastWriteTime = new long[loadedDimension.getWidth()][loadedDimension.getWidth()];
|
||||
for(int i = 0; i < loadedDimension.getWidth(); i++)
|
||||
for(int j = 0; j < loadedDimension.getWidth(); j++)
|
||||
regionLastWriteTime[i][j] = -1;
|
||||
|
||||
if (saveHandler != null && saveHandler.getWorldDirectory() != null)
|
||||
@@ -141,8 +139,10 @@ public class LodFileHandler
|
||||
// Save to File //
|
||||
//==============//
|
||||
|
||||
|
||||
public synchronized void saveDirtyRegionsToFile()
|
||||
/**
|
||||
* Save all dirty regions in this LodDimension to file.
|
||||
*/
|
||||
public synchronized void saveDirtyRegionsToFileAsync()
|
||||
{
|
||||
// we don't currently support reading or writing
|
||||
// files when connected to a server
|
||||
@@ -150,64 +150,31 @@ public class LodFileHandler
|
||||
return;
|
||||
|
||||
if (!readyToReadAndWrite())
|
||||
{
|
||||
// we aren't ready to read and write yet
|
||||
if(!waitingToSaveRegions)
|
||||
{
|
||||
waitingToSaveRegions = true;
|
||||
|
||||
// retry until we are able to read and write
|
||||
// then wake up the fileWritingThreadPool
|
||||
Thread retryReady = new Thread(() ->
|
||||
{
|
||||
try
|
||||
{
|
||||
// check once every so often so see
|
||||
// if anything has changed so we can
|
||||
// start reading and writing files
|
||||
while(!readyToReadAndWrite())
|
||||
{
|
||||
this.wait(1000);
|
||||
// get the save handler again, if for some
|
||||
// reason the original handler was null
|
||||
saveHandler = Minecraft.getMinecraft().getIntegratedServer().getWorld(0).getSaveHandler();
|
||||
save_dir = getWorldSaveDirectory();
|
||||
}
|
||||
|
||||
// we can start writing files now
|
||||
fileWritingThreadPool.execute(saveDirtyRegionsThread);
|
||||
waitingToSaveRegions = false;
|
||||
}
|
||||
catch (InterruptedException e)
|
||||
{ /* should never be called */}
|
||||
});
|
||||
|
||||
retryReady.run();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
fileWritingThreadPool.execute(saveDirtyRegionsThread);
|
||||
}
|
||||
private Thread saveDirtyRegionsThread = new Thread(() ->
|
||||
{
|
||||
for(int i = 0; i < loadedRegion.getWidth(); i++)
|
||||
for(int i = 0; i < loadedDimension.getWidth(); i++)
|
||||
{
|
||||
for(int j = 0; j < loadedRegion.getWidth(); j++)
|
||||
for(int j = 0; j < loadedDimension.getWidth(); j++)
|
||||
{
|
||||
if(loadedRegion.isRegionDirty[i][j])
|
||||
if(loadedDimension.isRegionDirty[i][j])
|
||||
{
|
||||
saveRegionToDisk(loadedRegion.regions[i][j]);
|
||||
loadedRegion.isRegionDirty[i][j] = false;
|
||||
saveRegionToDisk(loadedDimension.regions[i][j]);
|
||||
loadedDimension.isRegionDirty[i][j] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
waitingToSaveRegions = false;
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* Save a specific region to disk.<br>
|
||||
* Note: it will save to the LodDimension that this
|
||||
* handler is associated with.
|
||||
*/
|
||||
private void saveRegionToDisk(LodRegion region)
|
||||
{
|
||||
if (!readyToReadAndWrite() || region == null)
|
||||
@@ -258,15 +225,13 @@ public class LodFileHandler
|
||||
* Return the name of the file that should contain the
|
||||
* region at the given x and z. <br>
|
||||
* Returns null if this object isn't ready to read and write.
|
||||
* @param regionX
|
||||
* @param regionZ
|
||||
*/
|
||||
private String getFileNameForRegion(int regionX, int regionZ)
|
||||
{
|
||||
if (!readyToReadAndWrite())
|
||||
return null;
|
||||
|
||||
return save_dir + "\\lod_data\\DIM" + loadedRegion.dimension.getId() + "\\" +
|
||||
return save_dir + "\\lod_data\\DIM" + loadedDimension.dimension.getId() + "\\" +
|
||||
FILE_NAME_PREFIX + "." + regionX + "." + regionZ + FILE_EXTENSION;
|
||||
}
|
||||
|
||||
@@ -274,6 +239,8 @@ public class LodFileHandler
|
||||
/**
|
||||
* Returns if this FileHandler is ready to read
|
||||
* and write files.
|
||||
* <br>
|
||||
* This returns true when the world save directory is known.
|
||||
*/
|
||||
public boolean readyToReadAndWrite()
|
||||
{
|
||||
@@ -306,6 +273,8 @@ public class LodFileHandler
|
||||
|
||||
|
||||
/**
|
||||
* Gets the canonical path to the world save folder.
|
||||
* <br>
|
||||
* Returns null if there was an IO Exception
|
||||
*/
|
||||
private String getWorldSaveDirectory()
|
||||
@@ -11,7 +11,8 @@ import net.minecraft.client.Minecraft;
|
||||
|
||||
/**
|
||||
* This object is used to get variables from methods
|
||||
* where they are private.
|
||||
* where they are private. Specifically the fog setting
|
||||
* in Optifine.
|
||||
*
|
||||
* @author James Seibel
|
||||
* @version 09-21-2020
|
||||
|
||||
@@ -3,7 +3,7 @@ package com.backsun.lod.objects;
|
||||
import java.awt.Color;
|
||||
|
||||
import com.backsun.lod.util.enums.ColorDirection;
|
||||
import com.backsun.lod.util.enums.LodLocation;
|
||||
import com.backsun.lod.util.enums.LodCorner;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.client.Minecraft;
|
||||
@@ -73,7 +73,7 @@ public class LodChunk
|
||||
//==============//
|
||||
|
||||
/**
|
||||
* Create an empty LodChunk
|
||||
* Create an empty invisible LodChunk at (0,0)
|
||||
*/
|
||||
public LodChunk()
|
||||
{
|
||||
@@ -145,7 +145,7 @@ public class LodChunk
|
||||
|
||||
// top
|
||||
top = new short[4];
|
||||
for(LodLocation loc : LodLocation.values())
|
||||
for(LodCorner loc : LodCorner.values())
|
||||
{
|
||||
lastIndex = index;
|
||||
index = data.indexOf(DATA_DELIMITER, lastIndex + 1);
|
||||
@@ -156,7 +156,7 @@ public class LodChunk
|
||||
|
||||
// bottom
|
||||
bottom = new short[4];
|
||||
for(LodLocation loc : LodLocation.values())
|
||||
for(LodCorner loc : LodCorner.values())
|
||||
{
|
||||
lastIndex = index;
|
||||
index = data.indexOf(DATA_DELIMITER, lastIndex + 1);
|
||||
@@ -202,11 +202,11 @@ public class LodChunk
|
||||
}
|
||||
|
||||
/**
|
||||
* Illegal argument is thrown if either the
|
||||
* chunk or world is null. The reason the world
|
||||
* can't be null is because it's required to determine
|
||||
* a block's color.
|
||||
* @throws IllegalArgumentException
|
||||
* Creates a LodChunk for a chunk in the given world. <br>
|
||||
* Note: The world is required to determine each block's color
|
||||
*
|
||||
* @throws IllegalArgumentException
|
||||
* thrown if either the chunk or world is null.
|
||||
*/
|
||||
public LodChunk(Chunk chunk, World world) throws IllegalArgumentException
|
||||
{
|
||||
@@ -228,16 +228,16 @@ public class LodChunk
|
||||
colors = new Color[6];
|
||||
|
||||
// generate the top and bottom points of this LOD
|
||||
for(LodLocation loc : LodLocation.values())
|
||||
for(LodCorner loc : LodCorner.values())
|
||||
{
|
||||
top[loc.value] = generateLodSection(chunk, true, loc);
|
||||
bottom[loc.value] = generateLodSection(chunk, false, loc);
|
||||
top[loc.value] = generateLodCorner(chunk, SectionGenerationMode.GENERATE_TOP, loc);
|
||||
bottom[loc.value] = generateLodCorner(chunk, SectionGenerationMode.GENERATE_BOTTOM, loc);
|
||||
}
|
||||
|
||||
// determine the average color for each direction
|
||||
for(ColorDirection dir : ColorDirection.values())
|
||||
{
|
||||
colors[dir.value] = generateLodColorSection(chunk, world, dir);
|
||||
colors[dir.value] = generateLodColor(chunk, world, dir);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -253,15 +253,17 @@ public class LodChunk
|
||||
|
||||
|
||||
/**
|
||||
* Generate the height for the given LodLocation, either the top or bottom.
|
||||
* <br><br>
|
||||
* If invalid/null/empty chunks are given
|
||||
* crashes may occur.
|
||||
*/
|
||||
public short generateLodSection(Chunk chunk, boolean getTopSection, LodLocation lodLoc)
|
||||
private short generateLodCorner(Chunk chunk, SectionGenerationMode generationMode, LodCorner lodLoc)
|
||||
{
|
||||
// should have a length of 16
|
||||
// (each storage is 16x16x16 and the
|
||||
// world height is 256)
|
||||
ExtendedBlockStorage[] data = chunk.getBlockStorageArray();
|
||||
ExtendedBlockStorage[] blockStorage = chunk.getBlockStorageArray();
|
||||
|
||||
|
||||
|
||||
@@ -313,21 +315,29 @@ public class LodChunk
|
||||
}
|
||||
|
||||
|
||||
if(getTopSection)
|
||||
return determineTopPoint(data, startX, endX, startZ, endZ);
|
||||
if(generationMode == SectionGenerationMode.GENERATE_TOP)
|
||||
return determineTopPoint(blockStorage, startX, endX, startZ, endZ);
|
||||
else
|
||||
return determineBottomPoint(data, startX, endX, startZ, endZ);
|
||||
return determineBottomPoint(blockStorage, startX, endX, startZ, endZ);
|
||||
}
|
||||
/** GENERATE_TOP, GENERATE_BOTTOM */
|
||||
private enum SectionGenerationMode
|
||||
{
|
||||
GENERATE_TOP,
|
||||
GENERATE_BOTTOM;
|
||||
}
|
||||
|
||||
private short determineBottomPoint(ExtendedBlockStorage[] data, int startX, int endX, int startZ, int endZ)
|
||||
/**
|
||||
* Find the lowest valid point from the bottom.
|
||||
*/
|
||||
private short determineBottomPoint(ExtendedBlockStorage[] blockStorage, int startX, int endX, int startZ, int endZ)
|
||||
{
|
||||
// search from the bottom up
|
||||
for(int i = 0; i < data.length; i++)
|
||||
for(int i = 0; i < blockStorage.length; i++)
|
||||
{
|
||||
for(int y = 0; y < CHUNK_DATA_HEIGHT; y++)
|
||||
{
|
||||
|
||||
if(isLayerValidLodPoint(data, startX, endX, startZ, endZ, i, y))
|
||||
if(isLayerValidLodPoint(blockStorage, startX, endX, startZ, endZ, i, y))
|
||||
{
|
||||
// we found
|
||||
// enough blocks in this
|
||||
@@ -335,23 +345,24 @@ public class LodChunk
|
||||
// LOD point
|
||||
return (short) (y + (i * CHUNK_DATA_HEIGHT));
|
||||
}
|
||||
|
||||
} // y
|
||||
} // data
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// we never found a valid LOD point
|
||||
return -1;
|
||||
}
|
||||
|
||||
private short determineTopPoint(ExtendedBlockStorage[] data, int startX, int endX, int startZ, int endZ)
|
||||
/**
|
||||
* Find the highest valid point from the Top
|
||||
*/
|
||||
private short determineTopPoint(ExtendedBlockStorage[] blockStorage, int startX, int endX, int startZ, int endZ)
|
||||
{
|
||||
// search from the top down
|
||||
for(int i = data.length - 1; i >= 0; i--)
|
||||
for(int i = blockStorage.length - 1; i >= 0; i--)
|
||||
{
|
||||
for(int y = CHUNK_DATA_WIDTH - 1; y >= 0; y--)
|
||||
{
|
||||
if(isLayerValidLodPoint(data, startX, endX, startZ, endZ, i, y))
|
||||
if(isLayerValidLodPoint(blockStorage, startX, endX, startZ, endZ, i, y))
|
||||
{
|
||||
// we found
|
||||
// enough blocks in this
|
||||
@@ -359,10 +370,8 @@ public class LodChunk
|
||||
// LOD point
|
||||
return (short) (y + (i * CHUNK_DATA_HEIGHT));
|
||||
}
|
||||
} // y
|
||||
} // data
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// we never found a valid LOD point
|
||||
return -1;
|
||||
@@ -373,7 +382,7 @@ public class LodChunk
|
||||
* values a valid LOD point?
|
||||
*/
|
||||
private boolean isLayerValidLodPoint(
|
||||
ExtendedBlockStorage[] data,
|
||||
ExtendedBlockStorage[] blockStorage,
|
||||
int startX, int endX,
|
||||
int startZ, int endZ,
|
||||
int dataIndex, int y)
|
||||
@@ -385,7 +394,7 @@ public class LodChunk
|
||||
{
|
||||
for(int z = startZ; z < endZ; z++)
|
||||
{
|
||||
if(data[dataIndex] == null)
|
||||
if(blockStorage[dataIndex] == null)
|
||||
{
|
||||
// this section doesn't have any blocks,
|
||||
// it is not a valid section
|
||||
@@ -393,7 +402,7 @@ public class LodChunk
|
||||
}
|
||||
else
|
||||
{
|
||||
if(data[dataIndex].get(x, y, z) != null && Block.getIdFromBlock(data[dataIndex].get(x, y, z).getBlock()) != airBlockId)
|
||||
if(blockStorage[dataIndex].get(x, y, z) != null && Block.getIdFromBlock(blockStorage[dataIndex].get(x, y, z).getBlock()) != airBlockId)
|
||||
{
|
||||
// we found a valid block in
|
||||
// in this layer
|
||||
@@ -412,9 +421,11 @@ public class LodChunk
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private Color generateLodColorSection(Chunk chunk, World world, ColorDirection colorDir)
|
||||
/**
|
||||
* Generate the color of the given ColorDirection at the given chunk
|
||||
* in the given world.
|
||||
*/
|
||||
private Color generateLodColor(Chunk chunk, World world, ColorDirection colorDir)
|
||||
{
|
||||
Minecraft mc = Minecraft.getMinecraft();
|
||||
BlockColors bc = mc.getBlockColors();
|
||||
@@ -441,11 +452,18 @@ public class LodChunk
|
||||
}
|
||||
|
||||
/**
|
||||
* Only accepts TOP and BOTTOM as ColorPositions
|
||||
* Generates the color of the top or bottom of a given chunk in the given world.
|
||||
*
|
||||
* @throws IllegalArgumentException if given a ColorDirection other than TOP or BOTTOM
|
||||
*/
|
||||
private Color generateLodColorVertical(Chunk chunk, ColorDirection colorDir, World world, BlockColors bc)
|
||||
{
|
||||
ExtendedBlockStorage[] data = chunk.getBlockStorageArray();
|
||||
if(colorDir != ColorDirection.TOP && colorDir != ColorDirection.BOTTOM)
|
||||
{
|
||||
throw new IllegalArgumentException("generateLodColorVertical only accepts the ColorDirection TOP or BOTTOM");
|
||||
}
|
||||
|
||||
ExtendedBlockStorage[] blockStorage = chunk.getBlockStorageArray();
|
||||
|
||||
int numbOfBlocks = 0;
|
||||
int red = 0;
|
||||
@@ -456,8 +474,8 @@ public class LodChunk
|
||||
|
||||
|
||||
// either go top down or bottom up
|
||||
int dataStart = goTopDown? data.length - 1 : 0;
|
||||
int dataMax = data.length;
|
||||
int dataStart = goTopDown? blockStorage.length - 1 : 0;
|
||||
int dataMax = blockStorage.length;
|
||||
int dataMin = 0;
|
||||
int dataIncrement = goTopDown? -1 : 1;
|
||||
|
||||
@@ -474,16 +492,16 @@ public class LodChunk
|
||||
|
||||
for(int di = dataStart; !foundBlock && di >= dataMin && di < dataMax; di += dataIncrement)
|
||||
{
|
||||
if(!foundBlock && data[di] != null)
|
||||
if(!foundBlock && blockStorage[di] != null)
|
||||
{
|
||||
for(int y = topStart; !foundBlock && y >= topMin && y < topMax; y += topIncrement)
|
||||
{
|
||||
int ci;
|
||||
if(Block.getIdFromBlock(data[di].get(x, y, z).getBlock()) == waterBlockId)
|
||||
if(Block.getIdFromBlock(blockStorage[di].get(x, y, z).getBlock()) == waterBlockId)
|
||||
// this is a special case since getColor on water generally returns white
|
||||
ci = waterColor;
|
||||
else
|
||||
ci = bc.getColor(data[di].get(x, y, z), world, new BlockPos(x,y,z));
|
||||
ci = bc.getColor(blockStorage[di].get(x, y, z), world, new BlockPos(x,y,z));
|
||||
|
||||
if(ci == 0)
|
||||
{
|
||||
@@ -519,10 +537,20 @@ public class LodChunk
|
||||
|
||||
return new Color(red, green, blue);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generates the color of the side of a given chunk in the given world for the given ColorDirection.
|
||||
*
|
||||
* @throws IllegalArgumentException if given a ColorDirection other than N, S, W, E (North, South, East, West)
|
||||
*/
|
||||
private Color generateLodColorHorizontal(Chunk chunk, ColorDirection colorDir, World world, BlockColors bc)
|
||||
{
|
||||
ExtendedBlockStorage[] data = chunk.getBlockStorageArray();
|
||||
if(colorDir != ColorDirection.N && colorDir != ColorDirection.S && colorDir != ColorDirection.E && colorDir != ColorDirection.W)
|
||||
{
|
||||
throw new IllegalArgumentException("generateLodColorHorizontal only accepts the ColorDirection N (North), S (South), E (East), or W (West)");
|
||||
}
|
||||
|
||||
ExtendedBlockStorage[] blockStorage = chunk.getBlockStorageArray();
|
||||
|
||||
int numbOfBlocks = 0;
|
||||
int red = 0;
|
||||
@@ -563,9 +591,9 @@ public class LodChunk
|
||||
}
|
||||
|
||||
|
||||
for (int di = 0; di < data.length; di++)
|
||||
for (int di = 0; di < blockStorage.length; di++)
|
||||
{
|
||||
if (data[di] != null)
|
||||
if (blockStorage[di] != null)
|
||||
{
|
||||
for (int y = 0; y < CHUNK_DATA_HEIGHT; y++)
|
||||
{
|
||||
@@ -607,11 +635,11 @@ public class LodChunk
|
||||
}
|
||||
|
||||
int ci;
|
||||
if(Block.getIdFromBlock(data[di].get(x, y, z).getBlock()) == waterBlockId)
|
||||
if(Block.getIdFromBlock(blockStorage[di].get(x, y, z).getBlock()) == waterBlockId)
|
||||
// this is a special case since getColor on water generally returns white
|
||||
ci = waterColor;
|
||||
else
|
||||
ci = bc.getColor(data[di].get(x, y, z), world, new BlockPos(x,y,z));
|
||||
ci = bc.getColor(blockStorage[di].get(x, y, z), world, new BlockPos(x,y,z));
|
||||
|
||||
if (ci == 0) {
|
||||
// skip air or invisible blocks
|
||||
@@ -671,6 +699,30 @@ public class LodChunk
|
||||
|
||||
|
||||
|
||||
//================//
|
||||
// misc functions //
|
||||
//================//
|
||||
|
||||
/**
|
||||
* If this LOD is either invisible from every
|
||||
* direction or doesn't have a valid height
|
||||
* it is empty.
|
||||
*/
|
||||
public boolean isLodEmpty()
|
||||
{
|
||||
for(LodCorner corner : LodCorner.values())
|
||||
if(top[corner.value] != -1 || bottom[corner.value] != -1)
|
||||
// at least one corner is valid
|
||||
return false;
|
||||
|
||||
Color invisible = new Color(0,0,0,0);
|
||||
for(ColorDirection dir : ColorDirection.values())
|
||||
if(!colors[dir.value].equals(invisible))
|
||||
// at least one direction has a non-invisible color
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -681,7 +733,6 @@ public class LodChunk
|
||||
//========//
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Outputs all data in csv format
|
||||
* with the given delimiter.
|
||||
@@ -727,27 +778,6 @@ public class LodChunk
|
||||
|
||||
s += "x: " + x + " z: " + z + "\t";
|
||||
|
||||
// s += "top: ";
|
||||
// for(int i = 0; i < top.length; i++)
|
||||
// {
|
||||
// s += top[i] + " ";
|
||||
// }
|
||||
// s += "\t";
|
||||
|
||||
// s += "bottom: ";
|
||||
// for(int i = 0; i < bottom.length; i++)
|
||||
// {
|
||||
// s += bottom[i] + " ";
|
||||
// }
|
||||
// s += "\t";
|
||||
|
||||
// s += "colors ";
|
||||
// for(int i = 0; i < colors.length; i++)
|
||||
// {
|
||||
// if(colors[i] != null)
|
||||
// s += "(" + colors[i].getRed() + ", " + colors[i].getGreen() + ", " + colors[i].getBlue() + "), ";
|
||||
// }
|
||||
|
||||
s += "(" + colors[ColorDirection.TOP.value].getRed() + ", " + colors[ColorDirection.TOP.value].getGreen() + ", " + colors[ColorDirection.TOP.value].getBlue() + "), ";
|
||||
|
||||
return s;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.backsun.lod.objects;
|
||||
|
||||
import com.backsun.lod.handlers.LodFileHandler;
|
||||
import com.backsun.lod.handlers.LodDimensionFileHandler;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.world.DimensionType;
|
||||
@@ -10,13 +10,13 @@ import net.minecraft.world.DimensionType;
|
||||
* for a given dimension.
|
||||
*
|
||||
* @author James Seibel
|
||||
* @version 01-31-2021
|
||||
* @version 02-23-2021
|
||||
*/
|
||||
public class LodDimension
|
||||
{
|
||||
public final DimensionType dimension;
|
||||
|
||||
private volatile int width; // if this ever changes make sure to update the halfWidth too
|
||||
private volatile int width;
|
||||
private volatile int halfWidth;
|
||||
|
||||
public LodRegion regions[][];
|
||||
@@ -25,7 +25,8 @@ public class LodDimension
|
||||
private int centerX;
|
||||
private int centerZ;
|
||||
|
||||
private LodFileHandler rfHandler;
|
||||
private LodDimensionFileHandler fileHandler;
|
||||
|
||||
|
||||
public LodDimension(DimensionType newDimension, int newMaxWidth)
|
||||
{
|
||||
@@ -33,7 +34,7 @@ public class LodDimension
|
||||
width = newMaxWidth;
|
||||
|
||||
// dimension 0 works here since we are just looking for the save handler anyway
|
||||
rfHandler = new LodFileHandler(Minecraft.getMinecraft().getIntegratedServer().getWorld(0).getSaveHandler(), this);
|
||||
fileHandler = new LodDimensionFileHandler(Minecraft.getMinecraft().getIntegratedServer().getWorld(0).getSaveHandler(), this);
|
||||
|
||||
regions = new LodRegion[width][width];
|
||||
isRegionDirty = new boolean[width][width];
|
||||
@@ -50,7 +51,10 @@ public class LodDimension
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Move the center of this LodDimension and move all owned
|
||||
* regions over by the given x and z offset.
|
||||
*/
|
||||
public void move(int xOffset, int zOffset)
|
||||
{
|
||||
// if the x or z offset is equal to or greater than
|
||||
@@ -144,22 +148,16 @@ public class LodDimension
|
||||
}
|
||||
|
||||
|
||||
public int getCenterX()
|
||||
{
|
||||
return centerX;
|
||||
}
|
||||
|
||||
public int getCenterZ()
|
||||
{
|
||||
return centerZ;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Gets the region at the given X and Z
|
||||
* <br>
|
||||
* Returns null if the region doesn't exist
|
||||
* or is outside the loaded area.
|
||||
*/
|
||||
public LodRegion getRegion(int regionX, int regionZ)
|
||||
{
|
||||
int xIndex = (regionX - centerX) + halfWidth;
|
||||
@@ -201,7 +199,11 @@ public class LodDimension
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Add the given LOD to this dimension at the coordinate
|
||||
* stored in the LOD. If an LOD already exists at the given
|
||||
* coordinates it will be overwritten.
|
||||
*/
|
||||
public void addLod(LodChunk lod)
|
||||
{
|
||||
int regionX = (lod.x + centerX) / LodRegion.SIZE;
|
||||
@@ -236,14 +238,15 @@ public class LodDimension
|
||||
int xIndex = (regionX - centerX) + halfWidth;
|
||||
int zIndex = (regionZ - centerZ) + halfWidth;
|
||||
isRegionDirty[xIndex][zIndex] = true;
|
||||
|
||||
|
||||
|
||||
rfHandler.saveDirtyRegionsToFile();
|
||||
fileHandler.saveDirtyRegionsToFileAsync();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns null if the LodChunk isn't loaded
|
||||
* Get the LodChunk at the given X and Z coordinates
|
||||
* in this dimension.
|
||||
* <br>
|
||||
* Returns null if the LodChunk doesn't exist or
|
||||
* is outside the loaded area.
|
||||
*/
|
||||
public LodChunk getLodFromCoordinates(int chunkX, int chunkZ)
|
||||
{
|
||||
@@ -271,11 +274,13 @@ public class LodDimension
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get the region at the given X and Z coordinates from the
|
||||
* RegionFileHandler.
|
||||
*/
|
||||
public LodRegion getRegionFromFile(int regionX, int regionZ)
|
||||
{
|
||||
return rfHandler.loadRegionFromFile(regionX, regionZ);
|
||||
return fileHandler.loadRegionFromFile(regionX, regionZ);
|
||||
}
|
||||
|
||||
|
||||
@@ -293,6 +298,22 @@ public class LodDimension
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public int getCenterX()
|
||||
{
|
||||
return centerX;
|
||||
}
|
||||
|
||||
public int getCenterZ()
|
||||
{
|
||||
return centerZ;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public int getWidth()
|
||||
{
|
||||
return width;
|
||||
@@ -311,6 +332,18 @@ public class LodDimension
|
||||
for(int j = 0; j < width; j++)
|
||||
isRegionDirty[i][j] = false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
String s = "";
|
||||
|
||||
s += "dim: " + dimension.getName() + "\t";
|
||||
s += "(" + centerX + "," + centerZ + ")";
|
||||
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ package com.backsun.lod.objects;
|
||||
* one file in the file system.
|
||||
*
|
||||
* @author James Seibel
|
||||
* @version 1-20-2021
|
||||
* @version 1-22-2021
|
||||
*/
|
||||
public class LodRegion
|
||||
{
|
||||
@@ -31,6 +31,11 @@ public class LodRegion
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add the given LOD to this region at the coordinate
|
||||
* stored in the LOD. If an LOD already exists at the given
|
||||
* coordinates it will be overwritten.
|
||||
*/
|
||||
public void addLod(LodChunk lod)
|
||||
{
|
||||
// we use ABS since LODs can be negative, but if they are
|
||||
@@ -43,6 +48,13 @@ public class LodRegion
|
||||
chunks[xIndex][zIndex] = lod;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the LodChunk at the given X and Z coordinates
|
||||
* in this region.
|
||||
* <br>
|
||||
* Returns null if the LodChunk doesn't exist or
|
||||
* is outside the loaded area.
|
||||
*/
|
||||
public LodChunk getLod(int chunkX, int chunkZ)
|
||||
{
|
||||
// since we add LOD's with ABS, we get them the same way
|
||||
@@ -52,11 +64,16 @@ public class LodRegion
|
||||
if(arrayX >= SIZE || arrayZ >= SIZE)
|
||||
return null;
|
||||
|
||||
// TODO fix some LOD strips showing up in the wrong location
|
||||
// issue #2
|
||||
// maybe this has to do with ABS being used incorrectly?
|
||||
return chunks[arrayX][arrayZ];
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns all LodChunks in this region
|
||||
*/
|
||||
public LodChunk[][] getAllLods()
|
||||
{
|
||||
return chunks;
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
package com.backsun.lod.objects;
|
||||
|
||||
import java.util.Dictionary;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* This stores all LODs for a given world.
|
||||
*
|
||||
* @author James Seibel
|
||||
* @version 01-31-2021
|
||||
* @version 02-22-2021
|
||||
*/
|
||||
public class LodWorld
|
||||
{
|
||||
@@ -17,7 +16,7 @@ public class LodWorld
|
||||
/**
|
||||
* Key = Dimension id (as an int)
|
||||
*/
|
||||
private Dictionary<Integer, LodDimension> lodDimensions;
|
||||
private Map<Integer, LodDimension> lodDimensions;
|
||||
|
||||
|
||||
public LodWorld(String newWorldName)
|
||||
@@ -38,12 +37,27 @@ public class LodWorld
|
||||
return lodDimensions.get(dimensionId);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Resizes the max width in regions that each LodDimension
|
||||
* should use.
|
||||
*/
|
||||
public void resizeDimensionRegionWidth(int newWidth)
|
||||
{
|
||||
Enumeration<Integer> keys = lodDimensions.keys();
|
||||
for(Integer key : lodDimensions.keySet())
|
||||
lodDimensions.get(key).setRegionWidth(newWidth);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
String s = "";
|
||||
|
||||
while(keys.hasMoreElements())
|
||||
lodDimensions.get(keys.nextElement()).setRegionWidth(newWidth);
|
||||
s += worldName + "\t - dimensions: ";
|
||||
for(Integer key : lodDimensions.keySet())
|
||||
s += lodDimensions.get(key).dimension.getName() + ", ";
|
||||
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,10 +22,11 @@ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||
// Minecraft.getMinecraft().getIntegratedServer()
|
||||
|
||||
/**
|
||||
* This is used by the client.
|
||||
* This handles all events sent to the client,
|
||||
* and is the starting point for most of this program.
|
||||
*
|
||||
* @author James_Seibel
|
||||
* @version 02-21-2021
|
||||
* @version 02-23-2021
|
||||
*/
|
||||
public class ClientProxy extends CommonProxy
|
||||
{
|
||||
@@ -57,6 +58,10 @@ public class ClientProxy extends CommonProxy
|
||||
GL11.glDisable(GL11.GL_STENCIL_TEST);
|
||||
}
|
||||
|
||||
/**
|
||||
* Do any setup that is required to draw LODs
|
||||
* and then tell the LodRenderer to draw.
|
||||
*/
|
||||
public void renderLods(float partialTicks)
|
||||
{
|
||||
int newWidth = Math.max(4, (Minecraft.getMinecraft().gameSettings.renderDistanceChunks * LodChunk.WIDTH * 2) / LodRegion.SIZE);
|
||||
@@ -116,7 +121,7 @@ public class ClientProxy extends CommonProxy
|
||||
@SubscribeEvent
|
||||
public void chunkLoadEvent(ChunkEvent event)
|
||||
{
|
||||
lodWorld = lodBuilder.generateLodChunk(event.getChunk());
|
||||
lodWorld = lodBuilder.generateLodChunkAsync(event.getChunk());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -132,7 +137,7 @@ public class ClientProxy extends CommonProxy
|
||||
|
||||
if(world != null)
|
||||
{
|
||||
lodWorld = lodBuilder.generateLodChunk(world.getChunkFromChunkCoords(event.getChunkX(), event.getChunkZ()));
|
||||
lodWorld = lodBuilder.generateLodChunkAsync(world.getChunkFromChunkCoords(event.getChunkX(), event.getChunkZ()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.backsun.lod.proxy;
|
||||
|
||||
/**
|
||||
* This is used by the server.
|
||||
* This handles any events sent to the server.
|
||||
*
|
||||
* @author James_Seibel
|
||||
* @version 08-31-2020
|
||||
|
||||
@@ -24,7 +24,7 @@ import com.backsun.lod.util.LodConfig;
|
||||
import com.backsun.lod.util.enums.ColorDirection;
|
||||
import com.backsun.lod.util.enums.FogDistance;
|
||||
import com.backsun.lod.util.enums.FogQuality;
|
||||
import com.backsun.lod.util.enums.LodLocation;
|
||||
import com.backsun.lod.util.enums.LodCorner;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.BufferBuilder;
|
||||
@@ -41,6 +41,10 @@ import net.minecraft.util.math.MathHelper;
|
||||
*/
|
||||
public class LodRenderer
|
||||
{
|
||||
/** this is the light used when rendering the LODs,
|
||||
* it should be something different than what is used by Minecraft */
|
||||
private static final int LOD_GL_LIGHT_NUMBER = GL11.GL_LIGHT2;
|
||||
|
||||
/** If true the LODs colors will be replaced with
|
||||
* a checkerboard, this can be used for debugging. */
|
||||
public boolean debugging = false;
|
||||
@@ -98,23 +102,22 @@ public class LodRenderer
|
||||
mc = Minecraft.getMinecraft();
|
||||
|
||||
// for some reason "Tessellator.getInstance()" won't work here, we have to create a new one
|
||||
tessellator = new Tessellator(2097152);
|
||||
tessellator = new Tessellator(2097152); // the number here is what is used by the default Tessellator
|
||||
bufferBuilder = tessellator.getBuffer();
|
||||
|
||||
reflectionHandler = new ReflectionHandler();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Besides drawing the LODs this method also starts
|
||||
* the async process of generating the Buffers that hold those LODs.
|
||||
*
|
||||
* @param newDimension The dimension to draw, if null doesn't replace the current dimension.
|
||||
* @param partialTicks how far into the current tick this method was called.
|
||||
*/
|
||||
public void drawLODs(LodDimension newDimension, float partialTicks)
|
||||
{
|
||||
if (reflectionHandler.fovMethod == null)
|
||||
{
|
||||
// don't continue if we can't get the
|
||||
// user's FOV
|
||||
return;
|
||||
}
|
||||
|
||||
if (reflectionHandler.fovMethod == null)
|
||||
{
|
||||
// we aren't able to get the user's
|
||||
@@ -131,6 +134,19 @@ public class LodRenderer
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//===============//
|
||||
// initial setup //
|
||||
//===============//
|
||||
|
||||
|
||||
// used for debugging and viewing how long different processes take
|
||||
mc.mcProfiler.endSection();
|
||||
mc.mcProfiler.startSection("LOD");
|
||||
mc.mcProfiler.startSection("LOD setup");
|
||||
|
||||
|
||||
// should LODs be regenerated?
|
||||
if ((int)Minecraft.getMinecraft().player.posX / LodChunk.WIDTH != prevChunkX ||
|
||||
(int)Minecraft.getMinecraft().player.posZ / LodChunk.WIDTH != prevChunkZ ||
|
||||
@@ -138,6 +154,7 @@ public class LodRenderer
|
||||
prevFogDistance != LodConfig.fogDistance ||
|
||||
lodDimension != newDimension)
|
||||
{
|
||||
// yes
|
||||
regen = true;
|
||||
|
||||
prevChunkX = (int)Minecraft.getMinecraft().player.posX / LodChunk.WIDTH;
|
||||
@@ -152,17 +169,9 @@ public class LodRenderer
|
||||
regen = false;
|
||||
}
|
||||
|
||||
lodDimension = newDimension;
|
||||
if (newDimension != null)
|
||||
lodDimension = newDimension;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// used for debugging and viewing how long different processes take
|
||||
mc.mcProfiler.endSection();
|
||||
mc.mcProfiler.startSection("LOD");
|
||||
mc.mcProfiler.startSection("LOD setup");
|
||||
if (LodConfig.drawCheckerBoard)
|
||||
{
|
||||
if (debugging != LodConfig.drawCheckerBoard)
|
||||
@@ -183,9 +192,6 @@ public class LodRenderer
|
||||
double cameraX = player.lastTickPosX + (player.posX - player.lastTickPosX) * partialTicks;
|
||||
double cameraY = player.lastTickPosY + (player.posY - player.lastTickPosY) * partialTicks;
|
||||
double cameraZ = player.lastTickPosZ + (player.posZ - player.lastTickPosZ) * partialTicks;
|
||||
|
||||
|
||||
|
||||
|
||||
// determine how far the game's render distance is currently set
|
||||
int renderDistWidth = mc.gameSettings.renderDistanceChunks;
|
||||
@@ -204,29 +210,32 @@ public class LodRenderer
|
||||
// create the LODs //
|
||||
//=================//
|
||||
|
||||
// only regenerate LODs if:
|
||||
// only regenerate the LODs if:
|
||||
// 1. we want to regenerate LODs
|
||||
// 2. we aren't already regenerating LODs
|
||||
// 2. we aren't already regenerating the LODs
|
||||
// 3. we aren't waiting for the build and draw buffers to swap
|
||||
// (this is to prevent thread conflicts)
|
||||
if (regen && !regenerating && !switchBuffers)
|
||||
{
|
||||
mc.mcProfiler.endStartSection("LOD generation");
|
||||
regenerating = true;
|
||||
|
||||
|
||||
// this will only be called once, unless the numbBufferThreads changes
|
||||
if (numbBufferThreads != bufferThreads.size())
|
||||
setupBufferThreads();
|
||||
|
||||
// this will mainly happen when the view distance is changed
|
||||
if (drawableNearBuffers == null || drawableFarBuffers == null ||
|
||||
previousChunkRenderDistance != mc.gameSettings.renderDistanceChunks)
|
||||
setupBuffers(numbChunksWide);
|
||||
|
||||
|
||||
// generate the LODs on a separate thread to prevent stuttering or freezing
|
||||
genThread.execute(createLodBufferGenerationThread(cameraX, cameraZ, numbChunksWide));
|
||||
}
|
||||
|
||||
// replace the buffers used to draw and build,
|
||||
// this is done to keep everything thread safe
|
||||
// this is only done when the createLodBufferGenerationThread
|
||||
// has finished executing on a parallel thread.
|
||||
if (switchBuffers)
|
||||
{
|
||||
swapBuffers();
|
||||
@@ -242,13 +251,13 @@ public class LodRenderer
|
||||
//===========================//
|
||||
|
||||
// set the required open GL settings
|
||||
GL11.glPolygonMode(GL11.GL_FRONT_AND_BACK, GL11.GL_FILL);
|
||||
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
|
||||
GL11.glLineWidth(2.0f);
|
||||
GL11.glDisable(GL11.GL_TEXTURE_2D);
|
||||
GL11.glEnable(GL11.GL_CULL_FACE);
|
||||
|
||||
GL11.glPolygonMode(GL11.GL_FRONT_AND_BACK, GL11.GL_FILL);
|
||||
|
||||
// move the LODs so they are in the correct place relative to the camera
|
||||
GlStateManager.translate(-cameraX, -cameraY, -cameraZ);
|
||||
|
||||
setProjectionMatrix(partialTicks);
|
||||
@@ -266,21 +275,26 @@ public class LodRenderer
|
||||
switch(LodConfig.fogDistance)
|
||||
{
|
||||
case NEAR_AND_FAR:
|
||||
mc.mcProfiler.endStartSection("LOD draw setup");
|
||||
// when drawing NEAR_AND_FAR fog we need 2 draw
|
||||
// calls since fog can only go in one direction at a time
|
||||
|
||||
mc.mcProfiler.endStartSection("LOD draw");
|
||||
setupFog(FogDistance.NEAR, reflectionHandler.getFogQuality());
|
||||
sendLodsToGpuAndDraw(drawableNearBuffers);
|
||||
|
||||
mc.mcProfiler.endStartSection("LOD draw setup");
|
||||
mc.mcProfiler.endStartSection("LOD draw");
|
||||
setupFog(FogDistance.FAR, reflectionHandler.getFogQuality());
|
||||
sendLodsToGpuAndDraw(drawableFarBuffers);
|
||||
break;
|
||||
|
||||
case NEAR:
|
||||
mc.mcProfiler.endStartSection("LOD draw setup");
|
||||
mc.mcProfiler.endStartSection("LOD draw");
|
||||
setupFog(FogDistance.NEAR, reflectionHandler.getFogQuality());
|
||||
sendLodsToGpuAndDraw(drawableNearBuffers);
|
||||
break;
|
||||
|
||||
case FAR:
|
||||
mc.mcProfiler.endStartSection("LOD draw setup");
|
||||
mc.mcProfiler.endStartSection("LOD draw");
|
||||
setupFog(FogDistance.FAR, reflectionHandler.getFogQuality());
|
||||
sendLodsToGpuAndDraw(drawableFarBuffers);
|
||||
break;
|
||||
@@ -302,7 +316,7 @@ public class LodRenderer
|
||||
|
||||
GL11.glPolygonMode(GL11.GL_FRONT_AND_BACK, GL11.GL_FILL);
|
||||
GL11.glEnable(GL11.GL_TEXTURE_2D);
|
||||
GL11.glDisable(GL11.GL_LIGHT2);
|
||||
GL11.glDisable(LOD_GL_LIGHT_NUMBER);
|
||||
GL11.glDisable(GL11.GL_COLOR_MATERIAL);
|
||||
|
||||
// change the perspective matrix back to prevent incompatibilities
|
||||
@@ -319,49 +333,11 @@ public class LodRenderer
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* draw an array of cubes (or squares) with the given colors.
|
||||
* @param lods bounding boxes to draw
|
||||
* @param colors color of each box to draw
|
||||
* This is where the actual drawing happens.
|
||||
*
|
||||
* @param buffers the buffers sent to the GPU to draw
|
||||
*/
|
||||
private void generateLodBuffers(AxisAlignedBB[][] lods, Color[][] colors, FogDistance fogDistance)
|
||||
{
|
||||
List<Future<NearFarBuffer>> bufferFutures = new ArrayList<>();
|
||||
|
||||
for(int i = 0; i < numbBufferThreads; i++)
|
||||
{
|
||||
bufferThreads.get(i).setNewData(buildableNearBuffers[i], buildableFarBuffers[i], fogDistance, lods, colors, i, numbBufferThreads);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
bufferFutures = bufferThreadPool.invokeAll(bufferThreads);
|
||||
}
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
// this should never happen, but just in case
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
for(int i = 0; i < numbBufferThreads; i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
buildableNearBuffers[i] = bufferFutures.get(i).get().nearBuffer;
|
||||
buildableFarBuffers[i] = bufferFutures.get(i).get().farBuffer;
|
||||
}
|
||||
catch(CancellationException | ExecutionException| InterruptedException e)
|
||||
{
|
||||
// this should never happen, but just in case
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void sendLodsToGpuAndDraw(BufferBuilder[] buffers)
|
||||
{
|
||||
for(int i = 0; i < numbBufferThreads; i++)
|
||||
@@ -371,11 +347,10 @@ public class LodRenderer
|
||||
|
||||
bufferBuilder.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_COLOR);
|
||||
bufferBuilder.getByteBuffer().clear();
|
||||
// replace the data in bufferBuilder with the data from the given buffer
|
||||
bufferBuilder.putBulkData(buffers[i].getByteBuffer());
|
||||
|
||||
mc.mcProfiler.endStartSection("LOD draw");
|
||||
tessellator.draw();
|
||||
mc.mcProfiler.endStartSection("LOD draw setup");
|
||||
|
||||
bufferBuilder.getByteBuffer().clear(); // this is required otherwise nothing is drawn
|
||||
}
|
||||
@@ -451,7 +426,6 @@ public class LodRenderer
|
||||
/**
|
||||
* create a new projection matrix and send it over to the GPU
|
||||
* @param partialTicks how many ticks into the frame we are
|
||||
* @return true if the matrix was successfully created and sent to the GPU, false otherwise
|
||||
*/
|
||||
private void setProjectionMatrix(float partialTicks)
|
||||
{
|
||||
@@ -483,16 +457,18 @@ public class LodRenderer
|
||||
float gammaMultiplyer = (mc.gameSettings.gammaSetting * 0.5f + 0.5f);
|
||||
float lightStrength = sunBrightness * skyHasLight * gammaMultiplyer;
|
||||
float lightAmbient[] = {lightStrength, lightStrength, lightStrength, 1.0f};
|
||||
|
||||
|
||||
ByteBuffer temp = ByteBuffer.allocateDirect(16);
|
||||
temp.order(ByteOrder.nativeOrder());
|
||||
GL11.glLight(GL11.GL_LIGHT2, GL11.GL_AMBIENT, (FloatBuffer) temp.asFloatBuffer().put(lightAmbient).flip());
|
||||
GL11.glEnable(GL11.GL_LIGHT2); // Enable the above lighting
|
||||
GL11.glLight(LOD_GL_LIGHT_NUMBER, GL11.GL_AMBIENT, (FloatBuffer) temp.asFloatBuffer().put(lightAmbient).flip());
|
||||
GL11.glEnable(LOD_GL_LIGHT_NUMBER); // Enable the above lighting
|
||||
|
||||
GlStateManager.enableLighting();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* create the BuildBufferThreads
|
||||
*/
|
||||
private void setupBufferThreads()
|
||||
{
|
||||
bufferThreads.clear();
|
||||
@@ -501,7 +477,7 @@ public class LodRenderer
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Create all buffers that will be used.
|
||||
*/
|
||||
private void setupBuffers(int numbChunksWide)
|
||||
{
|
||||
@@ -540,17 +516,17 @@ public class LodRenderer
|
||||
|
||||
|
||||
/**
|
||||
* Returns -1 if there are no valid points
|
||||
* @Returns -1 if there are no valid points
|
||||
*/
|
||||
private int getHighestPointInLod(short[] heightPoints)
|
||||
private int getValidHeightPoint(short[] heightPoints)
|
||||
{
|
||||
if (heightPoints[LodLocation.NE.value] != -1)
|
||||
return heightPoints[LodLocation.NE.value];
|
||||
if (heightPoints[LodLocation.NW.value] != -1)
|
||||
return heightPoints[LodLocation.NW.value];
|
||||
if (heightPoints[LodLocation.SE.value] != -1)
|
||||
return heightPoints[LodLocation.NE.value];
|
||||
return heightPoints[LodLocation.NE.value];
|
||||
if (heightPoints[LodCorner.NE.value] != -1)
|
||||
return heightPoints[LodCorner.NE.value];
|
||||
if (heightPoints[LodCorner.NW.value] != -1)
|
||||
return heightPoints[LodCorner.NW.value];
|
||||
if (heightPoints[LodCorner.SE.value] != -1)
|
||||
return heightPoints[LodCorner.NE.value];
|
||||
return heightPoints[LodCorner.NE.value];
|
||||
}
|
||||
|
||||
|
||||
@@ -603,7 +579,7 @@ public class LodRenderer
|
||||
// this is just how chunk loading/unloading works. This can hopefully
|
||||
// be hidden with careful use of fog)
|
||||
int middle = (numbChunksWide / 2);
|
||||
if (RenderUtil.isCoordinateInLoadedArea(i, j, middle))
|
||||
if (isCoordInCenterArea(i, j, middle))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -660,8 +636,8 @@ public class LodRenderer
|
||||
|
||||
|
||||
// add the new box to the array
|
||||
int topPoint = getHighestPointInLod(lod.top);
|
||||
int bottomPoint = getHighestPointInLod(lod.bottom);
|
||||
int topPoint = getValidHeightPoint(lod.top);
|
||||
int bottomPoint = getValidHeightPoint(lod.bottom);
|
||||
|
||||
// don't draw an LOD if it is empty
|
||||
if (topPoint == -1 && bottomPoint == -1)
|
||||
@@ -679,6 +655,54 @@ public class LodRenderer
|
||||
return t;
|
||||
}
|
||||
|
||||
/**
|
||||
* draw an array of boxes with the given colors.
|
||||
* <br><br>
|
||||
* Currently only one color per box is supported.
|
||||
*
|
||||
* @param lods bounding boxes to draw
|
||||
* @param colors color of each box to draw
|
||||
*/
|
||||
private void generateLodBuffers(AxisAlignedBB[][] lods, Color[][] colors, FogDistance fogDistance)
|
||||
{
|
||||
List<Future<NearFarBuffer>> bufferFutures = new ArrayList<>();
|
||||
|
||||
// update the information that the bufferThreads are using
|
||||
for(int i = 0; i < numbBufferThreads; i++)
|
||||
{
|
||||
bufferThreads.get(i).setNewData(buildableNearBuffers[i], buildableFarBuffers[i], fogDistance, lods, colors, i, numbBufferThreads);
|
||||
}
|
||||
|
||||
// run all the bufferThreads and get their results
|
||||
try
|
||||
{
|
||||
bufferFutures = bufferThreadPool.invokeAll(bufferThreads);
|
||||
}
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
// this should never happen, but just in case
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
// update our buildable buffers
|
||||
for(int i = 0; i < numbBufferThreads; i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
buildableNearBuffers[i] = bufferFutures.get(i).get().nearBuffer;
|
||||
buildableFarBuffers[i] = bufferFutures.get(i).get().farBuffer;
|
||||
}
|
||||
catch(CancellationException | ExecutionException| InterruptedException e)
|
||||
{
|
||||
// this should never happen, but just in case
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Swap buildable and drawable buffers.
|
||||
*/
|
||||
@@ -705,4 +729,16 @@ public class LodRenderer
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns if the given coordinate is in the loaded area of the world.
|
||||
* @param centerCoordinate the center of the loaded world
|
||||
*/
|
||||
private boolean isCoordInCenterArea(int i, int j, int centerCoordinate)
|
||||
{
|
||||
return (i >= centerCoordinate - mc.gameSettings.renderDistanceChunks
|
||||
&& i <= centerCoordinate + mc.gameSettings.renderDistanceChunks)
|
||||
&&
|
||||
(j >= centerCoordinate - mc.gameSettings.renderDistanceChunks
|
||||
&& j <= centerCoordinate + mc.gameSettings.renderDistanceChunks);
|
||||
}
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
package com.backsun.lod.renderer;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
|
||||
/**
|
||||
* This holds miscellaneous helper code
|
||||
* to be used in the rendering process.
|
||||
*
|
||||
* @author James Seibel
|
||||
* @version 2-13-2021
|
||||
*/
|
||||
public class RenderUtil
|
||||
{
|
||||
/**
|
||||
* Returns if the given coordinate is in the loaded area of the world.
|
||||
* @param centerCoordinate the center of the loaded world
|
||||
*/
|
||||
public static boolean isCoordinateInLoadedArea(int i, int j, int centerCoordinate)
|
||||
{
|
||||
Minecraft mc = Minecraft.getMinecraft();
|
||||
|
||||
return (i >= centerCoordinate - mc.gameSettings.renderDistanceChunks
|
||||
&& i <= centerCoordinate + mc.gameSettings.renderDistanceChunks)
|
||||
&&
|
||||
(j >= centerCoordinate - mc.gameSettings.renderDistanceChunks
|
||||
&& j <= centerCoordinate + mc.gameSettings.renderDistanceChunks);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Find the coordinates that are in the center half of the given
|
||||
* 2D matrix, starting at (0,0) and going to (2 * lodRadius, 2 * lodRadius).
|
||||
*/
|
||||
public static boolean isCoordinateInNearFogArea(int i, int j, int lodRadius)
|
||||
{
|
||||
int halfRadius = lodRadius / 2;
|
||||
|
||||
return (i >= lodRadius - halfRadius
|
||||
&& i <= lodRadius + halfRadius)
|
||||
&&
|
||||
(j >= lodRadius - halfRadius
|
||||
&& j <= lodRadius + halfRadius);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -9,6 +9,7 @@ import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||
|
||||
/**
|
||||
* This is linked to Forge's mod config GUI.
|
||||
*
|
||||
* @author James Seibel
|
||||
* @version 02-14-2021
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.backsun.lod.util;
|
||||
|
||||
/**
|
||||
* This holds meta information about the mod.
|
||||
*
|
||||
* @author James Seibel
|
||||
* @version 04-16-2020
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package com.backsun.lod.util.enums;
|
||||
|
||||
/**
|
||||
* TOP, N, S, E, W, BOTTOM
|
||||
*
|
||||
* @author James Seibel
|
||||
* @version 10-17-2020
|
||||
*
|
||||
* TOP, N, S, E, W, BOTTOM
|
||||
*/
|
||||
public enum ColorDirection
|
||||
{
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
package com.backsun.lod.util.enums;
|
||||
|
||||
/**
|
||||
* @author James Seibel
|
||||
* @version 1-23-2021
|
||||
*/
|
||||
public enum DrawMode
|
||||
{
|
||||
/** Draw the LOD objects in groups.
|
||||
* <br>
|
||||
* <br>
|
||||
* Fancy fog: render the center and outside LOD
|
||||
* objects in 2 different groups.
|
||||
* <br>
|
||||
* Fast fog: render all LOD objects at one time.
|
||||
*/
|
||||
BATCH(0),
|
||||
|
||||
/** Draw each LOD objects separately.
|
||||
* <br>
|
||||
* <br>
|
||||
* Not suggested normally since draw calls are GPU expensive.
|
||||
*/
|
||||
INDIVIDUAL(5);
|
||||
|
||||
public final int value;
|
||||
|
||||
private DrawMode(int newValue)
|
||||
{
|
||||
value = newValue;
|
||||
}
|
||||
}
|
||||
@@ -8,9 +8,9 @@ package com.backsun.lod.util.enums;
|
||||
*/
|
||||
public enum FogDistance
|
||||
{
|
||||
/** valid for both fast and fancy fog qualities. */
|
||||
/** good for fast or fancy fog qualities. */
|
||||
NEAR,
|
||||
/** valid for both fast and fancy fog qualities. */
|
||||
/** good for fast or fancy fog qualities. */
|
||||
FAR,
|
||||
/** only looks good if the fog quality is set to Fancy. */
|
||||
NEAR_AND_FAR;
|
||||
|
||||
+3
-4
@@ -1,13 +1,12 @@
|
||||
package com.backsun.lod.util.enums;
|
||||
|
||||
/**
|
||||
* NE, SE, SW, NW
|
||||
*
|
||||
* @author James Seibel
|
||||
* @version 1-20-2020
|
||||
*
|
||||
* NE, SE, SW, NW
|
||||
*/
|
||||
public enum LodLocation
|
||||
public enum LodCorner
|
||||
{
|
||||
// used for position
|
||||
|
||||
@@ -22,7 +21,7 @@ public enum LodLocation
|
||||
|
||||
public final int value;
|
||||
|
||||
private LodLocation(int newValue)
|
||||
private LodCorner(int newValue)
|
||||
{
|
||||
value = newValue;
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
"modid": "lod",
|
||||
"name": "Level Of Details",
|
||||
"description": "Generates and renders simplified chunks beyond the normal view distance, at a low performance cost.",
|
||||
"version": "0.1",
|
||||
"version": "1.0",
|
||||
"mcversion": "1.12.2",
|
||||
"url": "",
|
||||
"updateUrl": "",
|
||||
|
||||
Reference in New Issue
Block a user