package speedytools.clientside.selections;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.renderer.WorldRenderer;
import net.minecraft.client.renderer.texture.TextureManager;
import net.minecraft.util.EnumFacing;
import net.minecraftforge.fml.common.FMLLog;
import net.minecraft.block.Block;
import net.minecraft.client.renderer.GLAllocation;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.init.Blocks;
import net.minecraft.util.BlockPos;
import net.minecraft.util.Vec3;
import net.minecraft.world.World;
import net.minecraft.world.chunk.Chunk;
import org.lwjgl.opengl.GL11;
import speedytools.common.blocks.BlockWithMetadata;
import speedytools.common.blocks.RegistryForBlocks;
import speedytools.common.selections.VoxelSelection;
import speedytools.common.selections.VoxelSelectionWithOrigin;
import speedytools.common.utilities.Colour;
import speedytools.common.utilities.Pair;
import speedytools.common.utilities.QuadOrientation;
import speedytools.common.utilities.UsefulConstants;
import javax.xml.soap.Text;
import java.util.BitSet;
import java.util.LinkedList;
/**
* Created by TheGreyGhost on 10/07/14.
* Used to render the selection.
* Typical usage:
* 1) create new
* 2) createFromSelection() to set up
* 3) render(x, y, z, renderdistance)
* 4) IMPORTANT! before discarding the instance, call release() to release the OpenGL resources
* Internally - stores a renderlist for each chunk, aligned to the world origin chunks
*/
public class BlockVoxelMultiSelectorRenderer
{
public BlockVoxelMultiSelectorRenderer(TextureManager textureManager)
{
selectionBlockTextures = new SelectionBlockTextures(textureManager);
selectionBlockTextures.setAutoAllocateIcon(true);
}
/**
* releases the GL11 render lists associated with this instance
*
*/
public void release()
{
for (Pair<Integer, Integer> allocation : displayListAllocations) {
GL11.glDeleteLists(allocation.getFirst(), allocation.getSecond());
}
displayListAllocations.clear();
displayListWireFrameXY = 0;
displayListWireFrameYZ = 0;
displayListWireFrameXZ = 0;
mode = OperationInProgress.INVALID;
displayListMapping = null;
}
/**
* Releases all GL11 resources for good
* this must not be used after calling releaseFinal().
*/
public void releaseFinal()
{
release();
selectionBlockTextures.release();
selectionBlockTextures = null;
}
/**
* gets the origin for the renderer in world coordinates
*
* @return the origin for the selection in world coordinates
*/
public BlockPos getWorldOrigin() {
return new BlockPos(sourceWXorigin, sourceWYorigin, sourceWZorigin);
}
private int displayListWireFrameXY = 0;
private int displayListWireFrameYZ = 0;
private int displayListWireFrameXZ = 0;
private final int DISPLAY_LIST_XSIZE = 16; // to align with world chunks
private final int DISPLAY_LIST_YSIZE = 16;
private final int DISPLAY_LIST_ZSIZE = 16;
// display list for the blocks in the selection: each displaylist renders DISPLAY_LIST_XSIZE * YSIZE * ZSIZE blocks
// private int displayListCubesBase = 0;
// private int displayListCubesCount = 0;
private int chunkCountX, chunkCountY, chunkCountZ;
private int xSize, ySize, zSize;
private int xOffset, yOffset, zOffset;
private int sourceWXorigin, sourceWYorigin, sourceWZorigin;
private IBlockState overrideTextureBlock;
private BitSet unloadedChunks = new BitSet(); // unloadedChunks[cx + cz * chunkCountX] = 1 if this chunk was unloaded when trying to get textures -> don't know what the block is
private int [] displayListMapping; // mapping of the cx, cy, cz to displayListIndex used by OpenGL.
// holds the allocated display lists: <start index, count>
private LinkedList<Pair<Integer, Integer>> displayListAllocations = new LinkedList<Pair<Integer, Integer>>();
private SelectionBlockTextures selectionBlockTextures;
// get the display list for the given chunk
private int getDisplayListIndex(int cx, int cy, int cz) {
return displayListMapping[cx + cy * chunkCountX + cz * chunkCountX * chunkCountY];
// return displayListCubesBase + cx + cy * chunkCountX + cz * chunkCountX * chunkCountY;
}
/** resizes the renderer to a new position and size. Retains (repositions) the existing render lists, doesn't update
* any new chunks
* @param newWXorigin the new world origin
* @param newWYorigin
* @param newWZorigin
* @param newXsize the
* @param newYsize
* @param newZsize
*/
public void resize(int newWXorigin, int newWYorigin, int newWZorigin, int newXsize, int newYsize, int newZsize)
{
int startChunkX = newWXorigin >> 4;
int endChunkX = (newWXorigin + newXsize - 1) >> 4;
int startChunkY = newWYorigin >> 4;
int endChunkY = (newWYorigin + newYsize - 1) >> 4;
int startChunkZ = newWZorigin >> 4;
int endChunkZ = (newWZorigin + newZsize - 1) >> 4;
int newChunkCountX = endChunkX - startChunkX + 1;
int newChunkCountY = endChunkY - startChunkY + 1;
int newchunkCountZ = endChunkZ - startChunkZ + 1;
int newDisplayListCount = resizeDisplayList(0, false, startChunkX - (sourceWXorigin >> 4), startChunkY - (sourceWYorigin >> 4), startChunkZ - (sourceWZorigin >> 4),
newChunkCountX, newChunkCountY, newchunkCountZ);
int displayListCubesBase = 0;
if (newDisplayListCount > 0) {
displayListCubesBase = GLAllocation.generateDisplayLists(newDisplayListCount);
if (displayListCubesBase == 0) {
release();
FMLLog.warning("Unable to create a displayList in BlockVoxelMultiSelectorRenderer::resize");
return;
}
displayListAllocations.add(new Pair<Integer, Integer>(displayListCubesBase, newDisplayListCount));
}
resizeDisplayList(displayListCubesBase, true, startChunkX - (sourceWXorigin >> 4), startChunkY - (sourceWYorigin >> 4), startChunkZ - (sourceWZorigin >> 4),
newChunkCountX, newChunkCountY, newchunkCountZ);
xSize = newXsize;
ySize = newYsize;
zSize = newZsize;
chunkCountX = newChunkCountX;
chunkCountY = newChunkCountY;
chunkCountZ = newchunkCountZ;
xOffset = newWXorigin & 0x0f;
yOffset = newWYorigin & 0x0f;
zOffset = newWZorigin & 0x0f;
sourceWXorigin = newWXorigin;
sourceWYorigin = newWYorigin;
sourceWZorigin = newWZorigin;
unloadedChunks.set(0, chunkCountX * chunkCountZ);
createMeshRenderLists(newXsize, newYsize, newZsize);
}
/**
* resizes the render displayList; keeps the original displayLists but moves them to their new position relative to the new origin
* fills newly created chunk slots with the indicated displaylist numbers
* @param nextListIndexStart the index of the first displaylist to use for new chunks; n empty chunks will use indices nextListIndexStart to nextListIndexStart + n-1 inclusive
* @param overwrite if true, create the new display list and move the old entries. If false, just count the number of new displaylistindices required.
* @param newCX0 the origin of the render relative to the old origin (eg newCX0 == -2 means that the new display starts 2 chunks to the left of the old)
* @param newCY0
* @param newCZ0
* @param newCXsize the number of x chunks in the new render
* @param newCYsize
* @param newCZsize
* @return the number of new displaylists added/required
*/
private int resizeDisplayList(int nextListIndexStart, boolean overwrite,
int newCX0, int newCY0, int newCZ0, int newCXsize, int newCYsize, int newCZsize)
{
assert (newCXsize > 0);
assert (newCYsize > 0);
assert (newCZsize > 0);
int [] newDisplayListMapping = new int[0];
if (overwrite) {
newDisplayListMapping = new int[newCXsize * newCYsize * newCZsize];
}
int newChunkCount = 0;
for (int cx = 0; cx < newCXsize; ++cx) {
for (int cy = 0; cy < newCYsize; ++cy) {
for (int cz = 0; cz < newCZsize; ++cz) {
boolean isExistingChunk = (cx + newCX0 >= 0 && cx + newCX0 < chunkCountX)
&& (cy + newCY0 >= 0 && cy + newCY0 < chunkCountY)
&& (cz + newCZ0 >= 0 && cz + newCZ0 < chunkCountZ);
if (!isExistingChunk) {
++newChunkCount;
}
if (overwrite) {
int newChunkIndex = cx + cy * newCXsize + cz * newCXsize * newCYsize;
if (isExistingChunk) {
newDisplayListMapping[newChunkIndex] = getDisplayListIndex(cx + newCX0, cy + newCY0, cz + newCZ0);
} else {
newDisplayListMapping[newChunkIndex] = nextListIndexStart++;
}
}
}
}
}
if (overwrite) {
displayListMapping = newDisplayListMapping;
}
return newChunkCount;
}
/**
* Refresh the renderlist for this renderer based on new information
*/
public void refreshRenderListStart()
{
cxCurrent = 0;
cyCurrent = 0;
czCurrent = 0;
mode = OperationInProgress.IN_PROGRESS;
}
/**
* Refresh the renderlist for this renderer based on new information
* @param world
* @param unknownVoxels
* @param maxTimeInNS the maximum amount of time to spend before returning, in ns
* @return the estimated fraction complete [0 .. 1]; or -1 if complete
*/
public float refreshRenderListContinue(World world, VoxelSelectionWithOrigin selectedVoxels, VoxelSelectionWithOrigin unknownVoxels, long maxTimeInNS)
{
if (mode == OperationInProgress.COMPLETE) return -1;
if (mode != OperationInProgress.IN_PROGRESS) {
FMLLog.severe("Mode should be IN_PROGRESS in BlockVoxelMultiSelectorRenderer::refreshRenderListContinue, but was actually " + mode);
return -1;
}
long startTime = System.nanoTime();
for (; cxCurrent < chunkCountX; ++cxCurrent, cyCurrent = 0) {
for (; cyCurrent < chunkCountY; ++cyCurrent, czCurrent = 0) {
for (; czCurrent < chunkCountZ; ++czCurrent) {
if (System.nanoTime() - startTime >= maxTimeInNS) return (cxCurrent / (float)chunkCountX);
renderThisChunk(world, overrideTextureBlock, selectedVoxels, unknownVoxels, sourceWXorigin, sourceWYorigin, sourceWZorigin, cxCurrent, cyCurrent, czCurrent);
Chunk chunk = world.getChunkFromChunkCoords((sourceWXorigin + cxCurrent * DISPLAY_LIST_XSIZE) >> 4,
(sourceWZorigin + czCurrent * DISPLAY_LIST_ZSIZE) >> 4);
if (!chunk.isEmpty()) {
unloadedChunks.clear(cxCurrent + czCurrent * chunkCountX);
// System.out.println("refresh clear [" + cxCurrent + ", " + czCurrent + "]");
}
}
}
}
selectionBlockTextures.updateTextures();
mode = OperationInProgress.COMPLETE;
return -1;
}
/**
* create the render list for this chunk
* @param world
* @param textureOverride if non null, uses this block texture instead of the world blocks textures
* @param selectedVoxels
* @param unknownVoxels
* @param wxOrigin
* @param wyOrigin
* @param wzOrigin
* @param cx
* @param cy
* @param cz
*/
private void renderThisChunk(World world, IBlockState textureOverride, VoxelSelection selectedVoxels, VoxelSelection unknownVoxels,
int wxOrigin, int wyOrigin, int wzOrigin,
int cx, int cy, int cz)
{
final double NUDGE_DISTANCE = 0.01;
final double FRAME_NUDGE_DISTANCE = NUDGE_DISTANCE + 0.002;
GL11.glNewList(getDisplayListIndex(cx, cy, cz), GL11.GL_COMPILE);
GL11.glPushAttrib(GL11.GL_ENABLE_BIT);
GL11.glDisable(GL11.GL_CULL_FACE);
GL11.glDisable(GL11.GL_LIGHTING);
GL11.glEnable(GL11.GL_TEXTURE_2D);
Tessellator tessellator = Tessellator.getInstance();
tessellateSurfaceWithTexture(world, textureOverride, selectedVoxels, unknownVoxels, wxOrigin, wyOrigin, wzOrigin,
cx * DISPLAY_LIST_XSIZE - xOffset, cy * DISPLAY_LIST_YSIZE - yOffset, cz * DISPLAY_LIST_ZSIZE - zOffset,
tessellator, WhatToDraw.FACES, NUDGE_DISTANCE);
GL11.glEnable(GL11.GL_BLEND);
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
GL11.glColor4f(Colour.BLACK_40.R, Colour.BLACK_40.G, Colour.BLACK_40.B, Colour.BLACK_40.A);
GL11.glLineWidth(2.0F);
GL11.glDisable(GL11.GL_TEXTURE_2D);
GL11.glDepthMask(false);
tessellateSurface(selectedVoxels, unknownVoxels,
cx * DISPLAY_LIST_XSIZE - xOffset, cy * DISPLAY_LIST_YSIZE - yOffset, cz * DISPLAY_LIST_ZSIZE - zOffset,
tessellator, WhatToDraw.WIREFRAME, FRAME_NUDGE_DISTANCE);
GL11.glDepthMask(true);
GL11.glPopAttrib();
GL11.glEndList();
}
private enum OperationInProgress {
INVALID, IN_PROGRESS, COMPLETE
}
private OperationInProgress mode = OperationInProgress.INVALID;
int cxCurrent, cyCurrent, czCurrent;
/**
* Look for any chunks which have missing textures and check to see if they have been loaded; if so, update the render list
* @param world
* @param unknownVoxels
* @param maxTimeInNS the maximum amount of time to spend before returning, in ns
* @return true if there are no more unknown block textures
*/
public boolean updateWithLoadedChunks(World world, VoxelSelectionWithOrigin selectedVoxels, VoxelSelectionWithOrigin unknownVoxels, long maxTimeInNS)
{
if (unloadedChunks.isEmpty()) return true;
long startTime = System.nanoTime();
for (int cx = 0; cx < chunkCountX; ++cx) {
for (int cz = 0; cz < chunkCountZ; ++cz) {
if (System.nanoTime() - startTime >= maxTimeInNS) return false;
if (unloadedChunks.get(cx + cz * chunkCountX)) {
Chunk chunk = world.getChunkFromChunkCoords((sourceWXorigin + cx * DISPLAY_LIST_XSIZE) >> 4,
(sourceWZorigin + cz * DISPLAY_LIST_ZSIZE) >> 4);
if (!chunk.isEmpty()) {
for (int cy = 0; cy < chunkCountY; ++cy) {
renderThisChunk(world, overrideTextureBlock, selectedVoxels, unknownVoxels, sourceWXorigin, sourceWYorigin, sourceWZorigin, cx, cy, cz);
}
unloadedChunks.clear(cx + cz * chunkCountX);
// System.out.println("update clear [" + cx + ", " + cz + "]");
}
}
}
}
return unloadedChunks.isEmpty();
}
/**
* create a render list for the current selection.
* Renders all voxels in selectedVoxels with the corresponding block texture, and also renders all voxels in unknownVoxels with an "unknown" texture
* Quads, with lines to outline them
* Aligns to world chunk boundaries
* @param world
* @param textureOverride if not null, draw the render list with the texture of the given block
* @param selectedVoxels the current selection
* @param unknownVoxels any unknown voxels in the current selection (voxels that might be selected - not known). Must be the same size [x,y,z] as selectedVoxels
*/
public void createRenderListStart(World world, IBlockState textureOverride, int wxOrigin, int wyOrigin, int wzOrigin, VoxelSelection selectedVoxels, VoxelSelection unknownVoxels)
{
release();
displayListWireFrameXY = GLAllocation.generateDisplayLists(1);
displayListWireFrameXZ = GLAllocation.generateDisplayLists(1);
displayListWireFrameYZ = GLAllocation.generateDisplayLists(1);
displayListAllocations.add(new Pair<Integer, Integer>(displayListWireFrameXY, 1));
displayListAllocations.add(new Pair<Integer, Integer>(displayListWireFrameXZ, 1));
displayListAllocations.add(new Pair<Integer, Integer>(displayListWireFrameYZ, 1));
int displayListCount = 1;
xSize = selectedVoxels.getxSize();
ySize = selectedVoxels.getySize();
zSize = selectedVoxels.getzSize();
assert (xSize == unknownVoxels.getxSize());
assert (ySize == unknownVoxels.getySize());
assert (zSize == unknownVoxels.getzSize());
int startChunkX = wxOrigin >> 4;
int endChunkX = (wxOrigin + xSize - 1) >> 4;
int startChunkY = wyOrigin >> 4;
int endChunkY = (wyOrigin + ySize - 1) >> 4;
int startChunkZ = wzOrigin >> 4;
int endChunkZ = (wzOrigin + zSize - 1) >> 4;
chunkCountX = endChunkX - startChunkX + 1;
chunkCountY = endChunkY - startChunkY + 1;
chunkCountZ = endChunkZ - startChunkZ + 1;
xOffset = wxOrigin & 0x0f;
yOffset = wyOrigin & 0x0f;
zOffset = wzOrigin & 0x0f;
sourceWXorigin = wxOrigin;
sourceWYorigin = wyOrigin;
sourceWZorigin = wzOrigin;
unloadedChunks.set(0, chunkCountX * chunkCountZ);
if (selectedVoxels.getxSize() > 0 && selectedVoxels.getySize() > 0 && selectedVoxels.getzSize() > 0) {
displayListCount = chunkCountX * chunkCountY * chunkCountZ;
}
int displayListCubesBase = GLAllocation.generateDisplayLists(displayListCount);
if (displayListCubesBase == 0 || displayListWireFrameXY == 0 || displayListWireFrameXZ == 0 || displayListWireFrameYZ == 0) {
release();
FMLLog.warning("Unable to create a displayList in BlockVoxelMultiSelectorRenderer::createRenderList");
return;
}
displayListAllocations.add(new Pair<Integer, Integer>(displayListCubesBase, displayListCount));
displayListMapping = new int [chunkCountX * chunkCountY * chunkCountZ];
for (int cx = 0; cx < chunkCountX; ++cx) {
for (int cy = 0; cy < chunkCountY; ++cy) {
for (int cz = 0; cz < chunkCountZ; ++cz) {
displayListMapping[cx + cy * chunkCountX + cz * chunkCountX * chunkCountY] = displayListCubesBase + cx + cy * chunkCountX + cz * chunkCountX * chunkCountY;
}
}
}
createMeshRenderLists(selectedVoxels.getxSize(), selectedVoxels.getySize(), selectedVoxels.getzSize());
cxCurrent = 0;
cyCurrent = 0;
czCurrent = 0;
overrideTextureBlock = textureOverride;
mode = OperationInProgress.IN_PROGRESS;
}
/**
* create a render list for the current selection.
* Quads, with lines to outline them
* @param world
* @param unknownVoxels
* @return the estimated fraction complete [0 .. 1]; or -1 if complete
*/
public float createRenderListContinue(World world, int wxOrigin, int wyOrigin, int wzOrigin, VoxelSelection selectedVoxels, VoxelSelection unknownVoxels, long maxTimeInNS)
{
if (mode != OperationInProgress.IN_PROGRESS) {
FMLLog.severe("Mode should be IN_PROGRESS in BlockVoxelMultiSelectorRenderer::createRenderListContinue, but was actually " + mode);
return -1;
}
long startTime = System.nanoTime();
// final double NUDGE_DISTANCE = 0.01;
// final double FRAME_NUDGE_DISTANCE = NUDGE_DISTANCE + 0.002;
for (; cxCurrent < chunkCountX; ++cxCurrent, cyCurrent = 0) {
for (; cyCurrent < chunkCountY; ++cyCurrent, czCurrent = 0) {
for (; czCurrent < chunkCountZ; ++czCurrent) {
if (System.nanoTime() - startTime >= maxTimeInNS) return (cxCurrent / (float)chunkCountX);
renderThisChunk(world, overrideTextureBlock, selectedVoxels, unknownVoxels, wxOrigin, wyOrigin, wzOrigin, cxCurrent, cyCurrent, czCurrent);
Chunk chunk = world.getChunkFromChunkCoords((wxOrigin + cxCurrent * DISPLAY_LIST_XSIZE) >> 4,
(wzOrigin + DISPLAY_LIST_ZSIZE) >> 4);
if (!chunk.isEmpty()) {
unloadedChunks.clear(cxCurrent + czCurrent * chunkCountX);
}
//
// GL11.glNewList(getDisplayListIndex(cxCurrent, cyCurrent, czCurrent), GL11.GL_COMPILE);
// GL11.glPushAttrib(GL11.GL_ENABLE_BIT);
// GL11.glDisable(GL11.GL_CULL_FACE);
// GL11.glDisable(GL11.GL_LIGHTING);
// GL11.glEnable(GL11.GL_TEXTURE_2D);
// Tessellator tessellator = Tessellator.getInstance(); WorldRenderer worldRenderer = tessellator.getWorldRenderer();
// tessellateSurfaceWithTexture(world, selectedVoxels, unknownVoxels, wxOrigin, wyOrigin, wzOrigin,
// cxCurrent * DISPLAY_LIST_XSIZE - xOffset, cyCurrent * DISPLAY_LIST_YSIZE - yOffset, czCurrent * DISPLAY_LIST_ZSIZE - zOffset,
// tessellator, WhatToDraw.FACES, NUDGE_DISTANCE);
//
// GL11.glEnable(GL11.GL_BLEND);
// GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
// GL11.glColor4f(Colour.BLACK_40.R, Colour.BLACK_40.G, Colour.BLACK_40.B, Colour.BLACK_40.A);
// GL11.glLineWidth(2.0F);
// GL11.glDisable(GL11.GL_TEXTURE_2D);
// GL11.glDepthMask(false);
// tessellateSurface(selectedVoxels, unknownVoxels,
// cxCurrent * DISPLAY_LIST_XSIZE - xOffset, cyCurrent * DISPLAY_LIST_YSIZE - yOffset, czCurrent * DISPLAY_LIST_ZSIZE - zOffset,
// tessellator, WhatToDraw.WIREFRAME, FRAME_NUDGE_DISTANCE);
//
// GL11.glDepthMask(true);
// GL11.glPopAttrib();
// GL11.glEndList();
}
}
}
selectionBlockTextures.updateTextures();
mode = OperationInProgress.COMPLETE;
return -1;
}
int debugCount = 0;
/**
* render the current selection (must have called createRenderList previously). Caller should set gLTranslatef so that the player's eyes are at [0,0,0]
* playerRelativePos is position of the player relative to the minimum [x,y,z] corner of the VoxelSelection
*/
public void renderSelection(Vec3 playerRelativePos, int blockRenderDistance, QuadOrientation quadOrientation, Colour colour)
{
if (displayListMapping == null) {
return;
}
double relativeXpos = playerRelativePos.xCoord + xOffset; // align to chunk boundary
double relativeYpos = playerRelativePos.yCoord + yOffset;
double relativeZpos = playerRelativePos.zCoord + zOffset;
try {
GL11.glPushMatrix();
GL11.glPushAttrib(GL11.GL_ENABLE_BIT);
GL11.glTranslated(-relativeXpos, -relativeYpos, -relativeZpos);
// transform the player world [x,z] into the coordinates of the selection
int playerRelativePositionX = quadOrientation.calcXfromWXZ((int)(relativeXpos), (int)(relativeZpos));
int playerRelativePositionZ = quadOrientation.calcZfromWXZ((int)(relativeXpos), (int)(relativeZpos));
final int CX_MIN = Math.max(0, (int)((playerRelativePositionX - blockRenderDistance)/ DISPLAY_LIST_XSIZE));
final int CY_MIN = Math.max(0, (int)((relativeYpos - blockRenderDistance)/ DISPLAY_LIST_YSIZE));
final int CZ_MIN = Math.max(0, (int)((playerRelativePositionZ - blockRenderDistance)/ DISPLAY_LIST_ZSIZE));
final int CX_MAX = Math.min(chunkCountX - 1, (int)((playerRelativePositionX + blockRenderDistance)/ DISPLAY_LIST_XSIZE));
final int CY_MAX = Math.min(chunkCountY - 1, (int)((relativeYpos + blockRenderDistance)/ DISPLAY_LIST_YSIZE));
final int CZ_MAX = Math.min(chunkCountZ - 1, (int)((playerRelativePositionZ + blockRenderDistance)/ DISPLAY_LIST_ZSIZE));
Pair<Float, Float> renderNudge = quadOrientation.getWXZNudge();
GL11.glTranslatef(renderNudge.getFirst(), 0.0F, renderNudge.getSecond());
if (quadOrientation.getClockwiseRotationCount() > 0) { // rotate around the midpoint
GL11.glTranslatef(xSize / 2.0F + xOffset, 0, zSize / 2.0F + zOffset);
GL11.glRotatef(quadOrientation.getClockwiseRotationCount() * -90, 0, 1, 0);
GL11.glTranslatef(-xSize / 2.0F - xOffset, 0, -zSize / 2.0F - zOffset);
}
if (quadOrientation.isFlippedX()) { // flip around the midpoint
GL11.glTranslatef(xSize / 2.0F + xOffset, 0, 0);
GL11.glScaled(-1, 1, 1);
GL11.glTranslatef(-xSize / 2.0F - xOffset, 0, 0);
}
try {
GL11.glPushMatrix();
GL11.glPushAttrib(GL11.GL_ENABLE_BIT);
selectionBlockTextures.bindTexture();
for (int cy = CY_MIN; cy <= CY_MAX; ++cy) {
for (int cx = CX_MIN; cx <= CX_MAX; ++cx) {
for (int cz = CZ_MIN; cz <= CZ_MAX; ++cz) {
GL11.glTranslated(cx*16, cy*16, cz*16);
GL11.glColor4f(colour.R, colour.G, colour.B, colour.A);
GL11.glCallList(getDisplayListIndex(cx, cy, cz));
GL11.glTranslated(-cx*16, -cy*16, -cz*16);
}
}
}
} finally {
GL11.glPopAttrib();
GL11.glPopMatrix();
}
GL11.glTranslated(xOffset, yOffset, zOffset); // the grid doesn't need to be offset for the chunk alignment
// cull the back faces of the grid:
// only draw a face if you can see the front of it
// eg for xpos face - if player is to the right, for xneg - if player is to the left. if between don't draw either one.
// exception: if inside the cube, render all faces. Yneg is always drawn.
double playerRelativePositionVx = quadOrientation.calcXfromWXZ(playerRelativePos.xCoord, playerRelativePos.zCoord);
double playerRelativePositionVz = quadOrientation.calcZfromWXZ(playerRelativePos.xCoord, playerRelativePos.zCoord);
boolean inside = (playerRelativePositionVx >= 0 && playerRelativePositionVx <= xSize)
&& ( playerRelativePos.yCoord <= ySize)
&& (playerRelativePositionVz >= 0 && playerRelativePositionVz <= zSize);
final Colour WALL_GRID_COLOUR = Colour.BLACK_40;
final Colour FLOOR_GRID_COLOUR = Colour.WHITE_40;
GL11.glColor4f(WALL_GRID_COLOUR.R, WALL_GRID_COLOUR.G, WALL_GRID_COLOUR.B, WALL_GRID_COLOUR.A);
if (inside || playerRelativePositionVx < 0) {
GL11.glPushMatrix();
GL11.glTranslated(0, ySize, 0);
GL11.glCallList(displayListWireFrameYZ);
GL11.glPopMatrix();
}
if (inside || playerRelativePositionVx > xSize) {
GL11.glPushMatrix();
GL11.glTranslated(xSize, ySize, 0);
GL11.glCallList(displayListWireFrameYZ);
GL11.glPopMatrix();
}
GL11.glColor4f(FLOOR_GRID_COLOUR.R, FLOOR_GRID_COLOUR.G, FLOOR_GRID_COLOUR.B, FLOOR_GRID_COLOUR.A);
if (true) {
GL11.glPushMatrix();
GL11.glTranslated(0, 0, 0);
GL11.glCallList(displayListWireFrameXZ);
GL11.glPopMatrix();
}
GL11.glColor4f(WALL_GRID_COLOUR.R, WALL_GRID_COLOUR.G, WALL_GRID_COLOUR.B, WALL_GRID_COLOUR.A);
if (inside || playerRelativePos.yCoord > ySize) {
GL11.glPushMatrix();
GL11.glTranslated(0, ySize, 0);
GL11.glCallList(displayListWireFrameXZ);
GL11.glPopMatrix();
}
if (inside || playerRelativePositionVz < 0) {
GL11.glPushMatrix();
GL11.glTranslated(0, ySize, 0);
GL11.glCallList(displayListWireFrameXY);
GL11.glPopMatrix();
}
if (inside || playerRelativePositionVz > zSize) {
GL11.glPushMatrix();
GL11.glTranslated(0, ySize, zSize);
GL11.glCallList(displayListWireFrameXY);
GL11.glPopMatrix();
}
} finally {
GL11.glPopAttrib();
GL11.glPopMatrix();
}
}
enum WhatToDraw {FACES, WIREFRAME}
private void tessellateSurface(VoxelSelection selection, VoxelSelection unknownVoxels, int sx0, int sy0, int sz0,
Tessellator tessellator, WhatToDraw whatToDraw, double nudgeDistance)
{
int xNegNudge, xPosNudge, yNegNudge, yPosNudge, zNegNudge, zPosNudge;
WorldRenderer worldRenderer = tessellator.getWorldRenderer();
if (whatToDraw == WhatToDraw.FACES) {
worldRenderer.startDrawingQuads();
}
// goes outside the VoxelSelection size, which always returns zero when out of bounds
// "nudges" the quad boundaries to make solid blocks slightly larger, avoids annoying visual artifacts when overlapping with world blocks
// three cases of nudge for each edge: internal (concave) edges = nudge inwards (-1), flat = no nudge (0), outer (convex) = nudge outwards (+1)
for (int y = 0; y < DISPLAY_LIST_YSIZE; ++y) {
for (int z = 0; z < DISPLAY_LIST_ZSIZE; ++z) {
for (int x = 0; x < DISPLAY_LIST_XSIZE; ++x) {
int sx = x + sx0;
int sy = y + sy0;
int sz = z + sz0;
if (selection.getVoxel(sx, sy, sz) || unknownVoxels.getVoxel(sx, sy, sz)) {
// xneg face
if (!selection.getVoxel(sx - 1, sy, sz) && !unknownVoxels.getVoxel(sx - 1, sy, sz)) {
yNegNudge = (selection.getVoxel(sx-1, sy-1, sz+0) ? -1 : (selection.getVoxel(sx+0, sy-1, sz+0) ? 0 : 1) );
yPosNudge = (selection.getVoxel(sx-1, sy+1, sz+0) ? -1 : (selection.getVoxel(sx+0, sy+1, sz+0) ? 0 : 1) );
zNegNudge = (selection.getVoxel(sx-1, sy+0, sz-1) ? -1 : (selection.getVoxel(sx+0, sy+0, sz-1) ? 0 : 1) );
zPosNudge = (selection.getVoxel(sx-1, sy+0, sz+1) ? -1 : (selection.getVoxel(sx+0, sy+0, sz+1) ? 0 : 1) );
if (whatToDraw == WhatToDraw.WIREFRAME) worldRenderer.startDrawing(GL11.GL_LINE_LOOP);
worldRenderer.addVertex(x - nudgeDistance, y - yNegNudge * nudgeDistance, z - zNegNudge * nudgeDistance);
worldRenderer.addVertex(x - nudgeDistance, y + 1 + yPosNudge * nudgeDistance, z - zNegNudge * nudgeDistance);
worldRenderer.addVertex(x - nudgeDistance, y + 1 + yPosNudge * nudgeDistance, z + 1 + zPosNudge * nudgeDistance);
worldRenderer.addVertex(x - nudgeDistance, y - yNegNudge * nudgeDistance, z + 1 + zPosNudge * nudgeDistance);
if (whatToDraw == WhatToDraw.WIREFRAME) tessellator.draw();
}
// xpos face
if (!selection.getVoxel(sx + 1, sy, sz) && !unknownVoxels.getVoxel(sx + 1, sy, sz)) {
yNegNudge = (selection.getVoxel(sx+1, sy-1, sz+0) ? -1 : (selection.getVoxel(sx+0, sy-1, sz+0) ? 0 : 1) );
yPosNudge = (selection.getVoxel(sx+1, sy+1, sz+0) ? -1 : (selection.getVoxel(sx+0, sy+1, sz+0) ? 0 : 1) );
zNegNudge = (selection.getVoxel(sx+1, sy+0, sz-1) ? -1 : (selection.getVoxel(sx+0, sy+0, sz-1) ? 0 : 1) );
zPosNudge = (selection.getVoxel(sx+1, sy+0, sz+1) ? -1 : (selection.getVoxel(sx+0, sy+0, sz+1) ? 0 : 1) );
if (whatToDraw == WhatToDraw.WIREFRAME) worldRenderer.startDrawing(GL11.GL_LINE_LOOP);
worldRenderer.addVertex(x + 1 + nudgeDistance, y - yNegNudge * nudgeDistance, z - zNegNudge * nudgeDistance);
worldRenderer.addVertex(x + 1 + nudgeDistance, y + 1 + yPosNudge * nudgeDistance, z - zNegNudge * nudgeDistance);
worldRenderer.addVertex(x + 1 + nudgeDistance, y + 1 + yPosNudge * nudgeDistance, z + 1 + zPosNudge * nudgeDistance);
worldRenderer.addVertex(x + 1 + nudgeDistance, y - yNegNudge * nudgeDistance, z + 1 + zPosNudge * nudgeDistance);
if (whatToDraw == WhatToDraw.WIREFRAME) tessellator.draw();
}
// yneg face
if (!selection.getVoxel(sx, sy-1, sz) && !unknownVoxels.getVoxel(sx, sy-1, sz)) {
xNegNudge = (selection.getVoxel(sx-1, sy-1, sz+0) ? -1 : (selection.getVoxel(sx-1, sy+0, sz+0) ? 0 : 1) );
xPosNudge = (selection.getVoxel(sx+1, sy-1, sz+0) ? -1 : (selection.getVoxel(sx+1, sy+0, sz+0) ? 0 : 1) );
zNegNudge = (selection.getVoxel(sx+0, sy-1, sz-1) ? -1 : (selection.getVoxel(sx+0, sy+0, sz-1) ? 0 : 1) );
zPosNudge = (selection.getVoxel(sx+0, sy-1, sz+1) ? -1 : (selection.getVoxel(sx+0, sy+0, sz+1) ? 0 : 1) );
if (whatToDraw == WhatToDraw.WIREFRAME) worldRenderer.startDrawing(GL11.GL_LINE_LOOP);
worldRenderer.addVertex(x - xNegNudge * nudgeDistance, y - nudgeDistance, z - zNegNudge * nudgeDistance);
worldRenderer.addVertex(x + 1 + xPosNudge * nudgeDistance, y - nudgeDistance, z - zNegNudge * nudgeDistance);
worldRenderer.addVertex(x + 1 + xPosNudge * nudgeDistance, y - nudgeDistance, z + 1 + zPosNudge * nudgeDistance);
worldRenderer.addVertex(x - xNegNudge * nudgeDistance, y - nudgeDistance, z + 1 + zPosNudge * nudgeDistance);
if (whatToDraw == WhatToDraw.WIREFRAME) tessellator.draw();
}
// ypos face
if (!selection.getVoxel(sx, sy+1, sz) && !unknownVoxels.getVoxel(sx, sy+1, sz)) {
xNegNudge = (selection.getVoxel(sx-1, sy+1, sz+0) ? -1 : (selection.getVoxel(sx-1, sy+0, sz+0) ? 0 : 1) );
xPosNudge = (selection.getVoxel(sx+1, sy+1, sz+0) ? -1 : (selection.getVoxel(sx+1, sy+0, sz+0) ? 0 : 1) );
zNegNudge = (selection.getVoxel(sx+0, sy+1, sz-1) ? -1 : (selection.getVoxel(sx+0, sy+0, sz-1) ? 0 : 1) );
zPosNudge = (selection.getVoxel(sx+0, sy+1, sz+1) ? -1 : (selection.getVoxel(sx+0, sy+0, sz+1) ? 0 : 1) );
if (whatToDraw == WhatToDraw.WIREFRAME) worldRenderer.startDrawing(GL11.GL_LINE_LOOP);
worldRenderer.addVertex(x - xNegNudge * nudgeDistance, y + 1 + nudgeDistance, z - zNegNudge * nudgeDistance);
worldRenderer.addVertex(x + 1 + xPosNudge * nudgeDistance, y + 1 + nudgeDistance, z - zNegNudge * nudgeDistance);
worldRenderer.addVertex(x + 1 + xPosNudge * nudgeDistance, y + 1 + nudgeDistance, z + 1 + zPosNudge * nudgeDistance);
worldRenderer.addVertex(x - xNegNudge * nudgeDistance, y + 1 + nudgeDistance, z + 1 + zPosNudge * nudgeDistance);
if (whatToDraw == WhatToDraw.WIREFRAME) tessellator.draw();
}
// zneg face
if (!selection.getVoxel(sx, sy, sz-1) && !unknownVoxels.getVoxel(sx, sy, sz-1)) {
xNegNudge = (selection.getVoxel(sx-1, sy+0, sz-1) ? -1 : (selection.getVoxel(sx-1, sy+0, sz+0) ? 0 : 1) );
xPosNudge = (selection.getVoxel(sx+1, sy+0, sz-1) ? -1 : (selection.getVoxel(sx+1, sy+0, sz+0) ? 0 : 1) );
yNegNudge = (selection.getVoxel(sx+0, sy-1, sz-1) ? -1 : (selection.getVoxel(sx+0, sy-1, sz+0) ? 0 : 1) );
yPosNudge = (selection.getVoxel(sx+0, sy+1, sz-1) ? -1 : (selection.getVoxel(sx+0, sy+1, sz+0) ? 0 : 1) );
if (whatToDraw == WhatToDraw.WIREFRAME) worldRenderer.startDrawing(GL11.GL_LINE_LOOP);
worldRenderer.addVertex(x - xNegNudge * nudgeDistance, y - yNegNudge * nudgeDistance, z - nudgeDistance);
worldRenderer.addVertex(x + 1 + xPosNudge * nudgeDistance, y - yNegNudge * nudgeDistance, z - nudgeDistance);
worldRenderer.addVertex(x + 1 + xPosNudge * nudgeDistance, y + 1 + yPosNudge * nudgeDistance, z - nudgeDistance);
worldRenderer.addVertex(x - xNegNudge * nudgeDistance, y + 1 + yPosNudge * nudgeDistance, z - nudgeDistance);
if (whatToDraw == WhatToDraw.WIREFRAME) tessellator.draw();
}
// zpos face
if (!selection.getVoxel(sx, sy, sz+1) && !unknownVoxels.getVoxel(sx, sy, sz+1)) {
xNegNudge = (selection.getVoxel(sx-1, sy+0, sz+1) ? -1 : (selection.getVoxel(sx-1, sy+0, sz+0) ? 0 : 1) );
xPosNudge = (selection.getVoxel(sx+1, sy+0, sz+1) ? -1 : (selection.getVoxel(sx+1, sy+0, sz+0) ? 0 : 1) );
yNegNudge = (selection.getVoxel(sx+0, sy-1, sz+1) ? -1 : (selection.getVoxel(sx+0, sy-1, sz+0) ? 0 : 1) );
yPosNudge = (selection.getVoxel(sx+0, sy+1, sz+1) ? -1 : (selection.getVoxel(sx+0, sy+1, sz+0) ? 0 : 1) );
if (whatToDraw == WhatToDraw.WIREFRAME) worldRenderer.startDrawing(GL11.GL_LINE_LOOP);
worldRenderer.addVertex(x - xNegNudge * nudgeDistance, y - yNegNudge * nudgeDistance, z + 1 + nudgeDistance);
worldRenderer.addVertex(x + 1 + xPosNudge * nudgeDistance, y - yNegNudge * nudgeDistance, z + 1 + nudgeDistance);
worldRenderer.addVertex(x + 1 + xPosNudge * nudgeDistance, y + 1 + yPosNudge * nudgeDistance, z + 1 + nudgeDistance);
worldRenderer.addVertex(x - xNegNudge * nudgeDistance, y + 1 + yPosNudge * nudgeDistance, z + 1 + nudgeDistance);
if (whatToDraw == WhatToDraw.WIREFRAME) tessellator.draw();
}
}
}
}
}
if (whatToDraw == WhatToDraw.FACES) {
tessellator.draw();
}
}
/**
* draw the textured surface of this chunk starting from the [x0,y0,z0] index into the selection
* @param world
* @param overrideTexture if not null, use the texture from this block
* @param unknownVoxels
* @param wxOrigin world x of the selection
* @param wyOrigin world y of the selection
* @param wzOrigin world z of the selection
* @param sx0 start x coordinate in the selection
* @param sy0 start y coordinate in the selection
* @param sz0 start z coordinated in the selection
* @param tessellator
* @param whatToDraw
* @param nudgeDistance how far to nudge the face (to prevent overlap)
*/
private void tessellateSurfaceWithTexture(World world, IBlockState overrideTexture,
VoxelSelection selection, VoxelSelection unknownVoxels, int wxOrigin, int wyOrigin, int wzOrigin,
int sx0, int sy0, int sz0,
Tessellator tessellator, WhatToDraw whatToDraw, double nudgeDistance)
{
int xNegNudge, xPosNudge, yNegNudge, yPosNudge, zNegNudge, zPosNudge;
WorldRenderer worldRenderer = tessellator.getWorldRenderer();
if (whatToDraw == WhatToDraw.FACES) {
worldRenderer.startDrawingQuads();
}
// goes outside the VoxelSelection size, which always returns zero when out of bounds
// "nudges" the quad boundaries to make solid blocks slightly larger, avoids annoying visual artifacts when overlapping with world blocks
// three cases of nudge for each edge: internal (concave) edges = nudge inwards (-1), flat = no nudge (0), outer (convex) = nudge outwards (+1)
for (int y = 0; y < DISPLAY_LIST_YSIZE; ++y) {
for (int z = 0; z < DISPLAY_LIST_ZSIZE; ++z) {
for (int x = 0; x < DISPLAY_LIST_XSIZE; ++x) {
int sx = x + sx0;
int sy = y + sy0;
int sz = z + sz0;
boolean selected = selection.getVoxel(sx, sy, sz);
if (selected || unknownVoxels.getVoxel(sx, sy, sz)) {
int wx = sx + wxOrigin;
int wy = sy + wyOrigin;
int wz = sz + wzOrigin;
// unknown blocks get SelectionFog
// selected blocks which are air (either because the block is air, or because the chunk is not loaded), get SelectionSolidFog
IBlockState iBlockState = RegistryForBlocks.blockSelectionFog.getDefaultState();
if (selected) {
if (overrideTexture != null) {
iBlockState = overrideTexture;
} else {
iBlockState = world.getBlockState(new BlockPos(wx, wy, wz));
}
if (iBlockState == Blocks.air) {
iBlockState = RegistryForBlocks.blockSelectionSolidFog.getDefaultState();
}
}
// xneg face
if (!selection.getVoxel(sx - 1, sy, sz) && !unknownVoxels.getVoxel(sx - 1, sy, sz)) {
yNegNudge = (selection.getVoxel(sx-1, sy-1, sz+0) ? -1 : (selection.getVoxel(sx+0, sy-1, sz+0) ? 0 : 1) );
yPosNudge = (selection.getVoxel(sx-1, sy+1, sz+0) ? -1 : (selection.getVoxel(sx+0, sy+1, sz+0) ? 0 : 1) );
zNegNudge = (selection.getVoxel(sx-1, sy+0, sz-1) ? -1 : (selection.getVoxel(sx+0, sy+0, sz-1) ? 0 : 1) );
zPosNudge = (selection.getVoxel(sx-1, sy+0, sz+1) ? -1 : (selection.getVoxel(sx+0, sy+0, sz+1) ? 0 : 1) );
SelectionBlockTextures.SBTIcon icon = selectionBlockTextures.getSBTIcon(iBlockState, EnumFacing.WEST);
if (whatToDraw == WhatToDraw.WIREFRAME) worldRenderer.startDrawing(GL11.GL_LINE_LOOP);
worldRenderer.addVertexWithUV(x - nudgeDistance, y - yNegNudge * nudgeDistance, z - zNegNudge * nudgeDistance, icon.getMinU(), icon.getMaxV());
worldRenderer.addVertexWithUV(x - nudgeDistance, y + 1 + yPosNudge * nudgeDistance, z - zNegNudge * nudgeDistance, icon.getMinU(), icon.getMinV());
worldRenderer.addVertexWithUV(x - nudgeDistance, y + 1 + yPosNudge * nudgeDistance, z + 1 + zPosNudge * nudgeDistance, icon.getMaxU(), icon.getMinV());
worldRenderer.addVertexWithUV(x - nudgeDistance, y - yNegNudge * nudgeDistance, z + 1 + zPosNudge * nudgeDistance, icon.getMaxU(), icon.getMaxV());
if (whatToDraw == WhatToDraw.WIREFRAME) tessellator.draw();
}
// xpos face
if (!selection.getVoxel(sx + 1, sy, sz) && !unknownVoxels.getVoxel(sx + 1, sy, sz)) {
yNegNudge = (selection.getVoxel(sx+1, sy-1, sz+0) ? -1 : (selection.getVoxel(sx+0, sy-1, sz+0) ? 0 : 1) );
yPosNudge = (selection.getVoxel(sx+1, sy+1, sz+0) ? -1 : (selection.getVoxel(sx+0, sy+1, sz+0) ? 0 : 1) );
zNegNudge = (selection.getVoxel(sx+1, sy+0, sz-1) ? -1 : (selection.getVoxel(sx+0, sy+0, sz-1) ? 0 : 1) );
zPosNudge = (selection.getVoxel(sx+1, sy+0, sz+1) ? -1 : (selection.getVoxel(sx+0, sy+0, sz+1) ? 0 : 1) );
SelectionBlockTextures.SBTIcon icon = selectionBlockTextures.getSBTIcon(iBlockState, EnumFacing.EAST);
if (whatToDraw == WhatToDraw.WIREFRAME) worldRenderer.startDrawing(GL11.GL_LINE_LOOP);
worldRenderer.addVertexWithUV(x + 1 + nudgeDistance, y - yNegNudge * nudgeDistance, z - zNegNudge * nudgeDistance, icon.getMinU(), icon.getMaxV());
worldRenderer.addVertexWithUV(x + 1 + nudgeDistance, y + 1 + yPosNudge * nudgeDistance, z - zNegNudge * nudgeDistance, icon.getMinU(), icon.getMinV());
worldRenderer.addVertexWithUV(x + 1 + nudgeDistance, y + 1 + yPosNudge * nudgeDistance, z + 1 + zPosNudge * nudgeDistance, icon.getMaxU(), icon.getMinV());
worldRenderer.addVertexWithUV(x + 1 + nudgeDistance, y - yNegNudge * nudgeDistance, z + 1 + zPosNudge * nudgeDistance, icon.getMaxU(), icon.getMaxV());
if (whatToDraw == WhatToDraw.WIREFRAME) tessellator.draw();
}
// yneg face
if (!selection.getVoxel(sx, sy-1, sz) && !unknownVoxels.getVoxel(sx, sy-1, sz)) {
xNegNudge = (selection.getVoxel(sx-1, sy-1, sz+0) ? -1 : (selection.getVoxel(sx-1, sy+0, sz+0) ? 0 : 1) );
xPosNudge = (selection.getVoxel(sx+1, sy-1, sz+0) ? -1 : (selection.getVoxel(sx+1, sy+0, sz+0) ? 0 : 1) );
zNegNudge = (selection.getVoxel(sx+0, sy-1, sz-1) ? -1 : (selection.getVoxel(sx+0, sy+0, sz-1) ? 0 : 1) );
zPosNudge = (selection.getVoxel(sx+0, sy-1, sz+1) ? -1 : (selection.getVoxel(sx+0, sy+0, sz+1) ? 0 : 1) );
SelectionBlockTextures.SBTIcon icon = selectionBlockTextures.getSBTIcon(iBlockState, EnumFacing.DOWN);
// NB yneg face is flipped left-right in vanilla
if (whatToDraw == WhatToDraw.WIREFRAME) worldRenderer.startDrawing(GL11.GL_LINE_LOOP);
worldRenderer.addVertexWithUV(x - xNegNudge * nudgeDistance, y - nudgeDistance, z - zNegNudge * nudgeDistance, icon.getMaxU(), icon.getMaxV());
worldRenderer.addVertexWithUV(x + 1 + xPosNudge * nudgeDistance, y - nudgeDistance, z - zNegNudge * nudgeDistance, icon.getMinU(), icon.getMaxV());
worldRenderer.addVertexWithUV(x + 1 + xPosNudge * nudgeDistance, y - nudgeDistance, z + 1 + zPosNudge * nudgeDistance, icon.getMinU(), icon.getMinV());
worldRenderer.addVertexWithUV(x - xNegNudge * nudgeDistance, y - nudgeDistance, z + 1 + zPosNudge * nudgeDistance, icon.getMaxU(), icon.getMinV());
if (whatToDraw == WhatToDraw.WIREFRAME) tessellator.draw();
}
// ypos face
if (!selection.getVoxel(sx, sy+1, sz) && !unknownVoxels.getVoxel(sx, sy+1, sz)) {
xNegNudge = (selection.getVoxel(sx-1, sy+1, sz+0) ? -1 : (selection.getVoxel(sx-1, sy+0, sz+0) ? 0 : 1) );
xPosNudge = (selection.getVoxel(sx+1, sy+1, sz+0) ? -1 : (selection.getVoxel(sx+1, sy+0, sz+0) ? 0 : 1) );
zNegNudge = (selection.getVoxel(sx+0, sy+1, sz-1) ? -1 : (selection.getVoxel(sx+0, sy+0, sz-1) ? 0 : 1) );
zPosNudge = (selection.getVoxel(sx+0, sy+1, sz+1) ? -1 : (selection.getVoxel(sx+0, sy+0, sz+1) ? 0 : 1) );
SelectionBlockTextures.SBTIcon icon = selectionBlockTextures.getSBTIcon(iBlockState, EnumFacing.UP);
if (whatToDraw == WhatToDraw.WIREFRAME) worldRenderer.startDrawing(GL11.GL_LINE_LOOP);
worldRenderer.addVertexWithUV(x - xNegNudge * nudgeDistance, y + 1 + nudgeDistance, z - zNegNudge * nudgeDistance, icon.getMinU(), icon.getMaxV());
worldRenderer.addVertexWithUV(x + 1 + xPosNudge * nudgeDistance, y + 1 + nudgeDistance, z - zNegNudge * nudgeDistance, icon.getMaxU(), icon.getMaxV());
worldRenderer.addVertexWithUV(x + 1 + xPosNudge * nudgeDistance, y + 1 + nudgeDistance, z + 1 + zPosNudge * nudgeDistance, icon.getMaxU(), icon.getMinV());
worldRenderer.addVertexWithUV(x - xNegNudge * nudgeDistance, y + 1 + nudgeDistance, z + 1 + zPosNudge * nudgeDistance, icon.getMinU(), icon.getMinV());
if (whatToDraw == WhatToDraw.WIREFRAME) tessellator.draw();
}
// zneg face
if (!selection.getVoxel(sx, sy, sz-1) && !unknownVoxels.getVoxel(sx, sy, sz-1)) {
xNegNudge = (selection.getVoxel(sx-1, sy+0, sz-1) ? -1 : (selection.getVoxel(sx-1, sy+0, sz+0) ? 0 : 1) );
xPosNudge = (selection.getVoxel(sx+1, sy+0, sz-1) ? -1 : (selection.getVoxel(sx+1, sy+0, sz+0) ? 0 : 1) );
yNegNudge = (selection.getVoxel(sx+0, sy-1, sz-1) ? -1 : (selection.getVoxel(sx+0, sy-1, sz+0) ? 0 : 1) );
yPosNudge = (selection.getVoxel(sx+0, sy+1, sz-1) ? -1 : (selection.getVoxel(sx+0, sy+1, sz+0) ? 0 : 1) );
SelectionBlockTextures.SBTIcon icon = selectionBlockTextures.getSBTIcon(iBlockState, EnumFacing.NORTH);
if (whatToDraw == WhatToDraw.WIREFRAME) worldRenderer.startDrawing(GL11.GL_LINE_LOOP);
worldRenderer.addVertexWithUV(x - xNegNudge * nudgeDistance, y - yNegNudge * nudgeDistance, z - nudgeDistance, icon.getMaxU(), icon.getMaxV());
worldRenderer.addVertexWithUV(x + 1 + xPosNudge * nudgeDistance, y - yNegNudge * nudgeDistance, z - nudgeDistance, icon.getMinU(), icon.getMaxV());
worldRenderer.addVertexWithUV(x + 1 + xPosNudge * nudgeDistance, y + 1 + yPosNudge * nudgeDistance, z - nudgeDistance, icon.getMinU(), icon.getMinV());
worldRenderer.addVertexWithUV(x - xNegNudge * nudgeDistance, y + 1 + yPosNudge * nudgeDistance, z - nudgeDistance, icon.getMaxU(), icon.getMinV());
if (whatToDraw == WhatToDraw.WIREFRAME) tessellator.draw();
}
// zpos face
if (!selection.getVoxel(sx, sy, sz+1) && !unknownVoxels.getVoxel(sx, sy, sz+1)) {
xNegNudge = (selection.getVoxel(sx-1, sy+0, sz+1) ? -1 : (selection.getVoxel(sx-1, sy+0, sz+0) ? 0 : 1) );
xPosNudge = (selection.getVoxel(sx+1, sy+0, sz+1) ? -1 : (selection.getVoxel(sx+1, sy+0, sz+0) ? 0 : 1) );
yNegNudge = (selection.getVoxel(sx+0, sy-1, sz+1) ? -1 : (selection.getVoxel(sx+0, sy-1, sz+0) ? 0 : 1) );
yPosNudge = (selection.getVoxel(sx+0, sy+1, sz+1) ? -1 : (selection.getVoxel(sx+0, sy+1, sz+0) ? 0 : 1) );
SelectionBlockTextures.SBTIcon icon = selectionBlockTextures.getSBTIcon(iBlockState, EnumFacing.SOUTH);
if (whatToDraw == WhatToDraw.WIREFRAME) worldRenderer.startDrawing(GL11.GL_LINE_LOOP);
worldRenderer.addVertexWithUV(x - xNegNudge * nudgeDistance, y - yNegNudge * nudgeDistance, z + 1 + nudgeDistance, icon.getMinU(), icon.getMaxV());
worldRenderer.addVertexWithUV(x + 1 + xPosNudge * nudgeDistance, y - yNegNudge * nudgeDistance, z + 1 + nudgeDistance, icon.getMaxU(), icon.getMaxV());
worldRenderer.addVertexWithUV(x + 1 + xPosNudge * nudgeDistance, y + 1 + yPosNudge * nudgeDistance, z + 1 + nudgeDistance, icon.getMaxU(), icon.getMinV());
worldRenderer.addVertexWithUV(x - xNegNudge * nudgeDistance, y + 1 + yPosNudge * nudgeDistance, z + 1 + nudgeDistance, icon.getMinU(), icon.getMinV());
if (whatToDraw == WhatToDraw.WIREFRAME) tessellator.draw();
}
}
}
}
}
if (whatToDraw == WhatToDraw.FACES) {
tessellator.draw();
}
}
/**
* create the "cage" wireframes for the selection
* @param meshXSize
* @param ySize
* @param meshZSize
*/
private void createMeshRenderLists(int meshXSize, int ySize, int meshZSize)
{
final int MESH_HEIGHT = 256;
generateWireFrame2DMesh(displayListWireFrameXY, meshXSize, MESH_HEIGHT, 0);
generateWireFrame2DMesh(displayListWireFrameXZ, meshXSize, 0, meshZSize);
generateWireFrame2DMesh(displayListWireFrameYZ, 0, MESH_HEIGHT, meshZSize);
}
/**
* a vertical wireframe mesh made up of 1x1 squares, in the xy, yz, or xz plane
* origin is the top (ymax) corner, i.e. the topmost square is [0,0,0], the bottommost square is +xcount, -ycount, zcount
* one of the three must be 0 to specify which plane the mesh is in.
*/
private void generateWireFrame2DMesh(int displayListNumber, int xcount, int ycount, int zcount)
{
if (displayListNumber == 0) return;
assert (xcount >= 0 && ycount >= 0 && zcount >= 0);
assert (xcount == 0 || ycount == 0 || zcount == 0);
Tessellator tessellator = Tessellator.getInstance(); WorldRenderer worldRenderer = tessellator.getWorldRenderer();
GL11.glNewList(displayListNumber, GL11.GL_COMPILE);
GL11.glPushAttrib(GL11.GL_ENABLE_BIT);
GL11.glEnable(GL11.GL_BLEND);
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
GL11.glLineWidth(2.0F);
GL11.glDisable(GL11.GL_TEXTURE_2D);
GL11.glDepthMask(false);
worldRenderer.startDrawing(GL11.GL_LINE_LOOP);
worldRenderer.addVertex(0.0, 0.0, 0.0);
if (xcount == 0) {
worldRenderer.addVertex( 0.0, -ycount, 0.0);
worldRenderer.addVertex( 0.0, -ycount, zcount);
worldRenderer.addVertex( 0.0, 0, zcount);
} else {
worldRenderer.addVertex(xcount, 0.0, 0.0);
worldRenderer.addVertex(xcount, -ycount, zcount);
worldRenderer.addVertex( 0.0, -ycount, zcount);
}
tessellator.draw();
for (int x = 1; x < xcount; ++x) {
worldRenderer.startDrawing(GL11.GL_LINES);
worldRenderer.addVertex(x, 0.0, 0.0);
worldRenderer.addVertex(x, -ycount, zcount);
tessellator.draw();
}
for (int y = 1; y < ycount; ++y) {
worldRenderer.startDrawing(GL11.GL_LINES);
worldRenderer.addVertex( 0.0, -y, 0.0);
worldRenderer.addVertex(xcount, -y, zcount);
tessellator.draw();
}
for (int z = 1; z < zcount; ++z) {
worldRenderer.startDrawing(GL11.GL_LINES);
worldRenderer.addVertex( 0.0, 0.0, z);
worldRenderer.addVertex(xcount, -ycount, z);
tessellator.draw();
}
GL11.glDepthMask(true);
GL11.glPopAttrib();
GL11.glEndList();
}
}