Implement LOD generation, temporary storage, and rendering
This commit is contained in:
@@ -7,13 +7,14 @@ import net.minecraft.world.DimensionType;
|
||||
* currently needed by the LodRenderer.
|
||||
*
|
||||
* @author James Seibel
|
||||
* @version 10-25-2020
|
||||
* @version 1-20-2021
|
||||
*/
|
||||
public class LoadedRegions
|
||||
{
|
||||
public final DimensionType dimension;
|
||||
|
||||
private int maxWidth;
|
||||
private int width; // if this ever changes make sure to update the halfWidth too
|
||||
private int halfWidth;
|
||||
|
||||
public LodRegion regions[][];
|
||||
|
||||
@@ -23,28 +24,33 @@ public class LoadedRegions
|
||||
public LoadedRegions(DimensionType newDimension, int newMaxWidth)
|
||||
{
|
||||
dimension = newDimension;
|
||||
maxWidth = newMaxWidth;
|
||||
width = newMaxWidth;
|
||||
|
||||
regions = new LodRegion[width][width];
|
||||
|
||||
centerX = 0;
|
||||
centerZ = 0;
|
||||
|
||||
halfWidth = (int)Math.floor(width / 2);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Move over all data currently stored and update the centerX and Z
|
||||
*/
|
||||
public void move(int xOffset, int zOffset)
|
||||
{
|
||||
// if the x or z offset is equal to or greater than
|
||||
// the total size, just delete the current data
|
||||
// and update the centerX and/or centerZ
|
||||
if (Math.abs(xOffset) >= maxWidth || Math.abs(zOffset) >= maxWidth)
|
||||
if (Math.abs(xOffset) >= width || Math.abs(zOffset) >= width)
|
||||
{
|
||||
for(int x = 0; x < maxWidth; x++)
|
||||
for(int x = 0; x < width; x++)
|
||||
{
|
||||
for(int z = 0; z < maxWidth; z++)
|
||||
for(int z = 0; z < width; z++)
|
||||
{
|
||||
regions[x][z] = null;
|
||||
}
|
||||
}
|
||||
|
||||
// update the new center
|
||||
centerX += xOffset;
|
||||
centerZ += zOffset;
|
||||
@@ -54,56 +60,181 @@ public class LoadedRegions
|
||||
|
||||
|
||||
// X
|
||||
|
||||
// if xOffset is positive cut off the left side
|
||||
// (move the center to the right)
|
||||
int start = (xOffset > 0)? 0 : maxWidth - 1;
|
||||
int min = (xOffset > 0)? 0 : maxWidth - Math.abs(xOffset) + centerX;
|
||||
int max = (xOffset > 0)? xOffset : maxWidth - 1 - xOffset;
|
||||
int increment = (xOffset > 0)? 1 : -1;
|
||||
|
||||
for(int x = start; x >= min && x < max; x += increment)
|
||||
if(xOffset > 0)
|
||||
{
|
||||
for(int z = 0; z < maxWidth; z++)
|
||||
// move everything over to the left (as the center moves to the right)
|
||||
for(int x = 0; x < width; x++)
|
||||
{
|
||||
regions[Math.abs((x + centerX) % maxWidth)][Math.abs((z + centerZ) % maxWidth)] = null;
|
||||
for(int z = 0; z < width; z++)
|
||||
{
|
||||
if(x + xOffset < width)
|
||||
regions[x][z] = regions[x + xOffset][z];
|
||||
else
|
||||
regions[x][z] = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// move everything over to the right (as the center moves to the left)
|
||||
for(int x = width - 1; x >= 0; x--)
|
||||
{
|
||||
for(int z = 0; z < width; z++)
|
||||
{
|
||||
if(x + xOffset >= 0)
|
||||
regions[x][z] = regions[x + xOffset][z];
|
||||
else
|
||||
regions[x][z] = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Z
|
||||
start = (zOffset > 0)? 0 : maxWidth - 1;
|
||||
min = (zOffset > 0)? 0 : maxWidth - Math.abs(zOffset) + centerZ;
|
||||
max = (zOffset > 0)? zOffset : maxWidth - 1 - zOffset;
|
||||
increment = (zOffset > 0)? 1 : -1;
|
||||
|
||||
for(int x = 0; x < maxWidth; x++)
|
||||
if(zOffset > 0)
|
||||
{
|
||||
for(int z = start; z >= min && z < max; z += increment)
|
||||
// move everything up (as the center moves down)
|
||||
for(int x = 0; x < width; x++)
|
||||
{
|
||||
regions[Math.abs((x + centerX) % maxWidth)][Math.abs((z + centerZ) % maxWidth)] = null;
|
||||
for(int z = 0; z < width; z++)
|
||||
{
|
||||
if(z + zOffset < width)
|
||||
regions[x][z] = regions[x][z + zOffset];
|
||||
else
|
||||
regions[x][z] = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// move everything down (as the center moves up)
|
||||
for(int x = 0; x < width; x++)
|
||||
{
|
||||
for(int z = width - 1; z >= 0; z--)
|
||||
{
|
||||
if(z + zOffset >= 0)
|
||||
regions[x][z] = regions[x][z + zOffset];
|
||||
else
|
||||
regions[x][z] = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// update the new center
|
||||
centerX += xOffset;
|
||||
centerZ += zOffset;
|
||||
}
|
||||
|
||||
|
||||
public int getCenterX()
|
||||
{
|
||||
return centerX;
|
||||
}
|
||||
|
||||
public int getCenterZ()
|
||||
{
|
||||
return centerZ;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public LodRegion getRegion(int regionX, int regionZ)
|
||||
{
|
||||
int xIndex = (regionX - centerX) + halfWidth;
|
||||
int zIndex = (centerZ - regionZ) + halfWidth;
|
||||
|
||||
if (xIndex < 0 || xIndex >= width || zIndex < 0 || zIndex >= width)
|
||||
// out of range
|
||||
return null;
|
||||
|
||||
return regions[xIndex][zIndex];
|
||||
}
|
||||
|
||||
/**
|
||||
* Overwrite the LodRegion at the location of newRegion with newRegion.
|
||||
*/
|
||||
public void setRegion(LodRegion newRegion)
|
||||
{
|
||||
int xIndex = (newRegion.x - centerX) + halfWidth;
|
||||
int zIndex = (centerZ - newRegion.z) + halfWidth;
|
||||
|
||||
if (xIndex < 0 || xIndex >= width || zIndex < 0 || zIndex >= width)
|
||||
// out of range
|
||||
return;
|
||||
|
||||
regions[xIndex][zIndex] = newRegion;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public void addLod(LodChunk lod)
|
||||
{
|
||||
int x = lod.x / 16;
|
||||
int z = lod.z / 16;
|
||||
|
||||
// prevent issues if X/Z is negative and less than 16
|
||||
if (lod.x < 0)
|
||||
{
|
||||
x = (Math.abs(x) * -1) - 1;
|
||||
}
|
||||
if (lod.z < 0)
|
||||
{
|
||||
z = (Math.abs(z) * -1) - 1;
|
||||
}
|
||||
|
||||
LodRegion region = getRegion(x, z);
|
||||
|
||||
if (region == null)
|
||||
{
|
||||
// if no region exists, create it
|
||||
region = new LodRegion(x, z);
|
||||
setRegion(region);
|
||||
}
|
||||
|
||||
// TODO check what should be happening here
|
||||
region.addLod(lod);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns null if the LodChunk isn't loaded
|
||||
*/
|
||||
public LodChunk getChunkFromCoordinates(int chunkX, int chunkZ)
|
||||
{
|
||||
int xIndex = (chunkX + centerX) % maxWidth;
|
||||
int zIndex = (chunkZ + centerZ) % maxWidth;
|
||||
// (chunkX + centerX) % width
|
||||
int xIndex = (chunkX + centerX) / LodRegion.SIZE;
|
||||
int zIndex = (chunkZ + centerZ) / LodRegion.SIZE;
|
||||
|
||||
LodRegion region = regions[xIndex / maxWidth][zIndex / maxWidth];
|
||||
// prevent issues if chunkX/Z is negative and less than width
|
||||
if (chunkX < 0)
|
||||
{
|
||||
xIndex = (Math.abs(xIndex) * -1) - 1;
|
||||
}
|
||||
if (chunkZ < 0)
|
||||
{
|
||||
zIndex = (Math.abs(zIndex) * -1) - 1;
|
||||
}
|
||||
|
||||
LodRegion region = getRegion(xIndex, zIndex);
|
||||
|
||||
// TODO should abs be used here?
|
||||
//if(chunkX < 0 || chunkZ < 0)
|
||||
// return null;
|
||||
|
||||
if(region == null)
|
||||
return null;
|
||||
|
||||
return region.chunks[xIndex % LodRegion.SIZE][xIndex % LodRegion.SIZE];
|
||||
return region.getLod(chunkX, chunkZ);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ import net.minecraft.world.chunk.storage.ExtendedBlockStorage;
|
||||
* and color data for an LOD object.
|
||||
*
|
||||
* @author James Seibel
|
||||
* @version 10-17-2020
|
||||
* @version 1-20-2021
|
||||
*/
|
||||
public class LodChunk
|
||||
{
|
||||
@@ -26,8 +26,10 @@ public class LodChunk
|
||||
/** This is what separates each piece of data in the toData method */
|
||||
public static final char DATA_DELIMITER = ',';
|
||||
|
||||
private final int CHUNK_DATA_WIDTH = 16;
|
||||
private final int CHUNK_DATA_HEIGHT = 16;
|
||||
public static final int WIDTH = 16;
|
||||
|
||||
private final int CHUNK_DATA_WIDTH = WIDTH;
|
||||
private final int CHUNK_DATA_HEIGHT = WIDTH;
|
||||
|
||||
/**
|
||||
* This is how many blocks are
|
||||
@@ -39,7 +41,6 @@ public class LodChunk
|
||||
// since each layer is 1/4 the chunk
|
||||
|
||||
|
||||
|
||||
/** The x coordinate of the chunk. */
|
||||
public int x;
|
||||
/** The z coordinate of the chunk. */
|
||||
@@ -142,7 +143,7 @@ public class LodChunk
|
||||
lastIndex = index;
|
||||
index = data.indexOf(DATA_DELIMITER, lastIndex);
|
||||
|
||||
top[loc.index] = Short.parseShort(data.substring(lastIndex,index - 1));
|
||||
top[loc.value] = Short.parseShort(data.substring(lastIndex,index - 1));
|
||||
}
|
||||
|
||||
|
||||
@@ -152,7 +153,7 @@ public class LodChunk
|
||||
lastIndex = index;
|
||||
index = data.indexOf(DATA_DELIMITER, lastIndex);
|
||||
|
||||
bottom[loc.index] = Short.parseShort(data.substring(lastIndex,index - 1));
|
||||
bottom[loc.value] = Short.parseShort(data.substring(lastIndex,index - 1));
|
||||
}
|
||||
|
||||
|
||||
@@ -214,8 +215,8 @@ public class LodChunk
|
||||
// generate the top and bottom points of this LOD
|
||||
for(LodLocation loc : LodLocation.values())
|
||||
{
|
||||
top[loc.index] = generateLodSection(chunk, true, loc);
|
||||
bottom[loc.index] = generateLodSection(chunk, false, loc);
|
||||
top[loc.value] = generateLodSection(chunk, true, loc);
|
||||
bottom[loc.value] = generateLodSection(chunk, false, loc);
|
||||
}
|
||||
|
||||
// determine the average color for each direction
|
||||
|
||||
@@ -7,10 +7,11 @@ package backsun.lod.objects;
|
||||
* one file in the file system.
|
||||
*
|
||||
* @author James Seibel
|
||||
* @version 10-22-2020
|
||||
* @version 1-20-2021
|
||||
*/
|
||||
public class LodRegion
|
||||
{
|
||||
/** number of chunks wide */
|
||||
public static final int SIZE = 32;
|
||||
|
||||
/** X coordinate of this region */
|
||||
@@ -18,7 +19,7 @@ public class LodRegion
|
||||
/** Z coordinate of this region */
|
||||
public final int z;
|
||||
|
||||
public LodChunk chunks[][];
|
||||
private LodChunk chunks[][];
|
||||
|
||||
|
||||
public LodRegion(int regionX, int regionZ)
|
||||
@@ -28,4 +29,31 @@ public class LodRegion
|
||||
|
||||
chunks = new LodChunk[SIZE][SIZE];
|
||||
}
|
||||
|
||||
|
||||
public void addLod(LodChunk lod)
|
||||
{
|
||||
// we use ABS since LODs can be negative, but if they are
|
||||
// the region will negative first, therefore we don't have to
|
||||
// store the LOD chunks at negative indexes since we search
|
||||
// LOD the region first
|
||||
int xIndex = Math.abs(lod.x % LodChunk.WIDTH);
|
||||
int zIndex = Math.abs(lod.z % LodChunk.WIDTH);
|
||||
|
||||
chunks[xIndex][zIndex] = lod;
|
||||
}
|
||||
|
||||
|
||||
public LodChunk getLod(int x, int z)
|
||||
{
|
||||
// since we add LOD's with ABS, we get them the same way
|
||||
x = Math.abs(x);
|
||||
z = Math.abs(z);
|
||||
|
||||
if(x >= SIZE || z >= SIZE)
|
||||
return null;
|
||||
|
||||
return chunks[x][z];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package backsun.lod.proxy;
|
||||
|
||||
import backsun.lod.objects.LoadedRegions;
|
||||
import backsun.lod.objects.LodChunk;
|
||||
import backsun.lod.objects.LodRegion;
|
||||
import backsun.lod.renderer.LodRenderer;
|
||||
@@ -16,21 +17,19 @@ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||
* This is used by the client.
|
||||
*
|
||||
* @author James_Seibel
|
||||
* @version 10-22-2020
|
||||
* @version 1-20-2021
|
||||
*/
|
||||
public class ClientProxy extends CommonProxy
|
||||
{
|
||||
private LodRenderer renderer;
|
||||
private LodRegionFileHandler rfHandler;
|
||||
//TODO have the ability to store multiple regions based on how large the user's view distance is
|
||||
private LodRegion region;
|
||||
private LoadedRegions regions;
|
||||
|
||||
private int regionWidth = 5;
|
||||
|
||||
public ClientProxy()
|
||||
{
|
||||
rfHandler = new LodRegionFileHandler();
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -43,6 +42,20 @@ public class ClientProxy extends CommonProxy
|
||||
@SubscribeEvent
|
||||
public void renderWorldLastEvent(RenderWorldLastEvent event)
|
||||
{
|
||||
double playerX = Minecraft.getMinecraft().player.posX;
|
||||
double playerZ = Minecraft.getMinecraft().player.posZ;
|
||||
|
||||
// TODO make sure moving between regions works correctly
|
||||
// move the regions based on the player's movement //TODO deal with -0 - -15
|
||||
int xOffset = ((int)playerX / (LodChunk.WIDTH * LodRegion.SIZE)) - regions.getCenterX();
|
||||
int zOffset = ((int)playerZ / (LodChunk.WIDTH * LodRegion.SIZE)) - regions.getCenterZ();
|
||||
|
||||
if (xOffset != 0 || zOffset != 0)
|
||||
{
|
||||
regions.move(xOffset, zOffset);
|
||||
}
|
||||
|
||||
|
||||
// we wait to create the renderer until the first frame
|
||||
// to make sure that the EntityRenderer has
|
||||
// been created, that way we can get the fovModifer
|
||||
@@ -63,7 +76,7 @@ public class ClientProxy extends CommonProxy
|
||||
//===============//
|
||||
|
||||
// TODO determine if a old region should be unloaded
|
||||
// use the chunkUnloadedEvent
|
||||
// use the chunkUnloadedEvent, or player moved?
|
||||
|
||||
@SubscribeEvent
|
||||
public void chunkLoadEvent(ChunkEvent event)
|
||||
@@ -87,6 +100,8 @@ public class ClientProxy extends CommonProxy
|
||||
*
|
||||
Use this for generating chunks and maybe determining if they are loaded at all?
|
||||
|
||||
Could I create my own chunk generator and multithread it? It wouldn't save to the world, but could I save it for LODs?
|
||||
|
||||
chunk = Minecraft.getMinecraft().getIntegratedServer().getWorld(0).getChunkProvider().chunkGenerator.generateChunk(chunk.x, chunk.z);
|
||||
|
||||
System.out.println(chunk.x + " " + chunk.z + "\tloaded: " + chunk.isLoaded() + "\tpop: " + chunk.isPopulated() + "\tter pop: " + chunk.isTerrainPopulated());
|
||||
@@ -102,24 +117,23 @@ public class ClientProxy extends CommonProxy
|
||||
// or null chunks in this method)
|
||||
if (chunk != null && isValidChunk(chunk) && Minecraft.getMinecraft().world != null)
|
||||
{
|
||||
LodChunk c = new LodChunk(chunk, Minecraft.getMinecraft().world);
|
||||
LodChunk lod = new LodChunk(chunk, Minecraft.getMinecraft().world);
|
||||
|
||||
// TODO does this work with negative chunks?
|
||||
// TODO set up dynamic/multiple regions
|
||||
if (region == null || (region.x != (c.x / 32) && region.z != (c.z / 32)))
|
||||
|
||||
if (regions == null)
|
||||
{
|
||||
region = new LodRegion(c.x / 32, c.z / 32);
|
||||
regions = new LoadedRegions(null, regionWidth);
|
||||
}
|
||||
|
||||
region.data[Math.abs(c.x % 32)][Math.abs(c.z % 32)] = c;
|
||||
regions.addLod(lod);
|
||||
|
||||
if (renderer != null)
|
||||
{
|
||||
//TODO send data to renderer
|
||||
renderer.renderRegions = region;
|
||||
renderer.regions = regions;
|
||||
}
|
||||
|
||||
rfHandler.saveRegionToDisk(region);
|
||||
// TODO
|
||||
//rfHandler.saveRegionToDisk(regions);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import backsun.lod.objects.LoadedRegions;
|
||||
import backsun.lod.objects.LodChunk;
|
||||
import backsun.lod.util.OfConfig;
|
||||
import backsun.lod.util.enums.ColorDirection;
|
||||
import backsun.lod.util.enums.LodLocation;
|
||||
import backsun.lod.util.fog.FogMode;
|
||||
import backsun.lod.util.fog.FogType;
|
||||
import net.minecraft.client.Minecraft;
|
||||
@@ -21,11 +22,11 @@ import net.minecraft.util.math.AxisAlignedBB;
|
||||
|
||||
/**
|
||||
* @author James Seibel
|
||||
* @version 10-25-2020
|
||||
* @version 1-20-2021
|
||||
*/
|
||||
public class LodRenderer
|
||||
{
|
||||
public boolean debugging = false;
|
||||
public boolean debugging = true;
|
||||
|
||||
private Minecraft mc;
|
||||
private float farPlaneDistance;
|
||||
@@ -34,12 +35,14 @@ public class LodRenderer
|
||||
public static final int LOD_WIDTH = 16;
|
||||
public static final int MINECRAFT_CHUNK_WIDTH = 16;
|
||||
|
||||
public int defaultLodHeight = 0;
|
||||
|
||||
private Tessellator tessellator;
|
||||
private BufferBuilder bufferBuilder;
|
||||
|
||||
private OfConfig ofConfig;
|
||||
|
||||
public LoadedRegions regions;
|
||||
public LoadedRegions regions = null;
|
||||
|
||||
|
||||
|
||||
@@ -112,8 +115,6 @@ public class LodRenderer
|
||||
int totalLength = (int) farPlaneDistance * VIEW_DISTANCE_MULTIPLIER;
|
||||
int numbOfBoxesWide = (totalLength / LOD_WIDTH);
|
||||
|
||||
int lodHeight = 0;
|
||||
|
||||
// this where we will start drawing squares
|
||||
// (exactly half the total width)
|
||||
int startX = (-LOD_WIDTH * (numbOfBoxesWide / 2)) + playerXChunkOffset;
|
||||
@@ -126,13 +127,6 @@ public class LodRenderer
|
||||
Color colorArray[] = new Color[numbOfBoxesWide * numbOfBoxesWide];
|
||||
|
||||
|
||||
// used for debugging
|
||||
// and drawing a checkerboard
|
||||
boolean alternateColor = false;
|
||||
boolean evenWidth = false;
|
||||
if (debugging && numbOfBoxesWide % 2 == 0)
|
||||
evenWidth = true;
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -142,13 +136,10 @@ public class LodRenderer
|
||||
|
||||
mc.world.profiler.endStartSection("LOD generation");
|
||||
|
||||
|
||||
// x axis
|
||||
for (int i = 0; i < numbOfBoxesWide; i++)
|
||||
{
|
||||
// this is so that the debug pattern will be a checkerboard instead of stripes
|
||||
if (debugging && evenWidth)
|
||||
alternateColor = !alternateColor;
|
||||
|
||||
// z axis
|
||||
for (int j = 0; j < numbOfBoxesWide; j++)
|
||||
{
|
||||
@@ -158,28 +149,27 @@ public class LodRenderer
|
||||
startX; // offset so the center LOD block is centered underneath the player
|
||||
double zOffset = -cameraZ + (LOD_WIDTH * j) + startZ;
|
||||
|
||||
int chunkX = ((LOD_WIDTH * j) + startX) / MINECRAFT_CHUNK_WIDTH;
|
||||
int chunkZ = ((LOD_WIDTH * i) + startZ) / MINECRAFT_CHUNK_WIDTH;
|
||||
|
||||
int chunkX = ((LOD_WIDTH * i) + startX) / MINECRAFT_CHUNK_WIDTH;
|
||||
int chunkZ = ((LOD_WIDTH * j) + startZ) / MINECRAFT_CHUNK_WIDTH;
|
||||
|
||||
LodChunk lod = regions.getChunkFromCoordinates(chunkX, chunkZ);
|
||||
|
||||
if (lod == null)
|
||||
{
|
||||
colorArray[i + (j * numbOfBoxesWide)] = new Color(0,0,0,0);
|
||||
lodArray[i + (j * numbOfBoxesWide)] = new AxisAlignedBB(0, lodHeight, 0, LOD_WIDTH, lodHeight, LOD_WIDTH);
|
||||
lodArray[i + (j * numbOfBoxesWide)] = new AxisAlignedBB(0, defaultLodHeight, 0, LOD_WIDTH, defaultLodHeight, LOD_WIDTH);
|
||||
continue;
|
||||
}
|
||||
|
||||
Color c = lod.colors[ColorDirection.TOP.index];
|
||||
|
||||
double yOffset = -cameraY + lod.top[0];
|
||||
double yOffset = -cameraY;
|
||||
|
||||
|
||||
// if debugging draw the squares as a black and white checker board
|
||||
if (debugging)
|
||||
{
|
||||
if (alternateColor)
|
||||
if ((i + j) % 2 == 0)
|
||||
c = white;
|
||||
else
|
||||
c = black;
|
||||
@@ -188,8 +178,6 @@ public class LodRenderer
|
||||
c = red;
|
||||
|
||||
colorArray[i + (j * numbOfBoxesWide)] = c;
|
||||
|
||||
alternateColor = !alternateColor;
|
||||
}
|
||||
|
||||
|
||||
@@ -211,7 +199,7 @@ public class LodRenderer
|
||||
colorArray[i + (j * numbOfBoxesWide)] = c;
|
||||
|
||||
// add the new box to the array
|
||||
lodArray[i + (j * numbOfBoxesWide)] = new AxisAlignedBB(0, lodHeight, 0, LOD_WIDTH, lodHeight, LOD_WIDTH).offset(xOffset, yOffset, zOffset);
|
||||
lodArray[i + (j * numbOfBoxesWide)] = new AxisAlignedBB(0, lod.bottom[LodLocation.NE.value], 0, LOD_WIDTH, lod.bottom[LodLocation.NE.value], LOD_WIDTH).offset(xOffset, yOffset, zOffset);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user