package openmods.gui.component;
import java.util.EnumSet;
import java.util.Set;
import net.minecraft.block.Block;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.RenderBlocks;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.texture.TextureManager;
import net.minecraft.client.renderer.texture.TextureMap;
import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher;
import net.minecraft.init.Blocks;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.MathHelper;
import net.minecraftforge.common.util.ForgeDirection;
import openmods.api.IValueReceiver;
import openmods.gui.listener.IListenerBase;
import openmods.gui.misc.SidePicker;
import openmods.gui.misc.SidePicker.HitCoord;
import openmods.gui.misc.SidePicker.Side;
import openmods.gui.misc.Trackball.TrackballWrapper;
import openmods.utils.MathUtils;
import openmods.utils.bitmap.IReadableBitMap;
import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.GL11;
public class GuiComponentSideSelector extends BaseComponent implements IValueReceiver<Set<ForgeDirection>> {
private static final double SQRT_3 = Math.sqrt(3);
public static interface ISideSelectedListener extends IListenerBase {
public void onSideToggled(ForgeDirection side, boolean currentState);
}
private final RenderBlocks blockRender = new RenderBlocks();
private final TrackballWrapper trackball = new TrackballWrapper(1, 40);
private final int diameter;
private final double scale;
private ForgeDirection lastSideHovered;
private final Set<ForgeDirection> selectedSides = EnumSet.noneOf(ForgeDirection.class);
private boolean highlightSelectedSides = true;
private boolean isInInitialPosition;
private ISideSelectedListener sideSelectedListener;
private Block block;
private int meta;
private TileEntity te;
public GuiComponentSideSelector(int x, int y, double scale, Block block, int meta, TileEntity te, boolean highlightSelectedSides) {
super(x, y);
this.scale = scale;
this.diameter = MathHelper.ceiling_double_int(scale * SQRT_3);
this.block = block;
this.meta = meta;
this.te = te;
this.highlightSelectedSides = highlightSelectedSides;
}
@Override
public void render(Minecraft minecraft, int offsetX, int offsetY, int mouseX, int mouseY) {
if (isInInitialPosition == false || Mouse.isButtonDown(2)) {
trackball.setTransform(MathUtils.createEntityRotateMatrix(minecraft.renderViewEntity));
isInInitialPosition = true;
}
final int width = getWidth();
final int height = getWidth();
// assumption: block is rendered in (0,0,0) - (1,1,1) coordinates
GL11.glPushMatrix();
Tessellator tessellator = Tessellator.instance;
GL11.glTranslatef(offsetX + x + width / 2, offsetY + y + height / 2, diameter);
GL11.glScaled(scale, -scale, scale);
trackball.update(mouseX - width, -(mouseY - height));
if (te != null) TileEntityRendererDispatcher.instance.renderTileEntityAt(te, -0.5, -0.5, -0.5, 0.0F);
if (block != null) drawBlock(minecraft.renderEngine, tessellator);
SidePicker picker = new SidePicker(0.5);
HitCoord coord = picker.getNearestHit();
if (coord != null) drawHighlight(tessellator, coord.side, 0x444444);
if (highlightSelectedSides) {
for (ForgeDirection dir : selectedSides) {
drawHighlight(tessellator, Side.fromForgeDirection(dir), 0xCC0000);
}
}
lastSideHovered = coord == null? ForgeDirection.UNKNOWN : coord.side.toForgeDirection();
GL11.glPopMatrix();
}
@Override
public void renderOverlay(Minecraft minecraft, int offsetX, int offsetY, int mouseX, int mouseY) {}
private static void drawHighlight(Tessellator t, SidePicker.Side side, int color) {
GL11.glDisable(GL11.GL_LIGHTING);
GL11.glEnable(GL11.GL_BLEND);
GL11.glDisable(GL11.GL_DEPTH_TEST);
GL11.glDisable(GL11.GL_TEXTURE_2D);
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
t.startDrawingQuads();
t.setColorRGBA_I(color, 64);
switch (side) {
case XPos:
t.addVertex(0.5, -0.5, -0.5);
t.addVertex(0.5, 0.5, -0.5);
t.addVertex(0.5, 0.5, 0.5);
t.addVertex(0.5, -0.5, 0.5);
break;
case YPos:
t.addVertex(-0.5, 0.5, -0.5);
t.addVertex(-0.5, 0.5, 0.5);
t.addVertex(0.5, 0.5, 0.5);
t.addVertex(0.5, 0.5, -0.5);
break;
case ZPos:
t.addVertex(-0.5, -0.5, 0.5);
t.addVertex(0.5, -0.5, 0.5);
t.addVertex(0.5, 0.5, 0.5);
t.addVertex(-0.5, 0.5, 0.5);
break;
case XNeg:
t.addVertex(-0.5, -0.5, -0.5);
t.addVertex(-0.5, -0.5, 0.5);
t.addVertex(-0.5, 0.5, 0.5);
t.addVertex(-0.5, 0.5, -0.5);
break;
case YNeg:
t.addVertex(-0.5, -0.5, -0.5);
t.addVertex(0.5, -0.5, -0.5);
t.addVertex(0.5, -0.5, 0.5);
t.addVertex(-0.5, -0.5, 0.5);
break;
case ZNeg:
t.addVertex(-0.5, -0.5, -0.5);
t.addVertex(-0.5, 0.5, -0.5);
t.addVertex(0.5, 0.5, -0.5);
t.addVertex(0.5, -0.5, -0.5);
break;
default:
break;
}
t.draw();
GL11.glEnable(GL11.GL_DEPTH_TEST);
GL11.glEnable(GL11.GL_TEXTURE_2D);
GL11.glDisable(GL11.GL_BLEND);
}
private void drawBlock(TextureManager manager, Tessellator t) {
GL11.glColor4f(1, 1, 1, 1);
manager.bindTexture(TextureMap.locationBlocksTexture);
blockRender.setRenderBoundsFromBlock(block);
t.startDrawingQuads();
blockRender.renderFaceXNeg(Blocks.stone, -0.5, -0.5, -0.5, block.getIcon(4, meta));
blockRender.renderFaceXPos(Blocks.stone, -0.5, -0.5, -0.5, block.getIcon(5, meta));
blockRender.renderFaceYPos(Blocks.stone, -0.5, -0.5, -0.5, block.getIcon(1, meta));
blockRender.renderFaceYNeg(Blocks.stone, -0.5, -0.5, -0.5, block.getIcon(0, meta));
blockRender.renderFaceZNeg(Blocks.stone, -0.5, -0.5, -0.5, block.getIcon(2, meta));
blockRender.renderFaceZPos(Blocks.stone, -0.5, -0.5, -0.5, block.getIcon(3, meta));
t.draw();
}
private void toggleSide(ForgeDirection side) {
boolean wasntPresent = !selectedSides.remove(side);
if (wasntPresent) selectedSides.add(side);
notifyListeners(side, wasntPresent);
}
private void notifyListeners(final ForgeDirection side, final boolean wasntPresent) {
if (sideSelectedListener != null) sideSelectedListener.onSideToggled(side, wasntPresent);
}
@Override
public void mouseUp(int mouseX, int mouseY, int button) {
super.mouseDown(mouseX, mouseY, button);
if (button == 0 && lastSideHovered != null && lastSideHovered != ForgeDirection.UNKNOWN) {
toggleSide(lastSideHovered);
}
}
@Override
public void mouseDown(int mouseX, int mouseY, int button) {
super.mouseDown(mouseX, mouseY, button);
lastSideHovered = null;
}
@Override
public int getWidth() {
return diameter;
}
@Override
public int getHeight() {
return diameter;
}
@Override
public void setValue(Set<ForgeDirection> dirs) {
selectedSides.clear();
selectedSides.addAll(dirs);
}
public void setValue(IReadableBitMap<ForgeDirection> dirs) {
selectedSides.clear();
for (ForgeDirection dir : ForgeDirection.VALID_DIRECTIONS)
if (dirs.get(dir)) selectedSides.add(dir);
}
public void setListener(ISideSelectedListener sideSelectedListener) {
this.sideSelectedListener = sideSelectedListener;
}
}