package kenkron.antiqueatlasoverlay;
import hunternif.mc.atlas.AntiqueAtlasMod;
import hunternif.mc.atlas.client.*;
import hunternif.mc.atlas.client.gui.GuiAtlas;
import hunternif.mc.atlas.core.DimensionData;
import hunternif.mc.atlas.marker.DimensionMarkersData;
import hunternif.mc.atlas.marker.Marker;
import hunternif.mc.atlas.marker.MarkersData;
import hunternif.mc.atlas.registry.MarkerRenderInfo;
import hunternif.mc.atlas.util.AtlasRenderHelper;
import hunternif.mc.atlas.util.Rect;
import net.minecraft.client.Minecraft;
import net.minecraft.client.entity.EntityPlayerSP;
import net.minecraft.client.gui.ScaledResolution;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.util.math.Vec3d;
import net.minecraftforge.client.event.RenderGameOverlayEvent;
import net.minecraftforge.fml.common.eventhandler.EventPriority;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import org.lwjgl.opengl.GL11;
import java.util.List;
class AAORenderEventReceiver {
/**
* Number of blocks per chunk in minecraft. This is certianly stored
* somewhere else, but I couldn't be bothered to find it.
*/
private static final int CHUNK_SIZE = 16;
/**
* I know public variables can be messed with, but that's a risk I'm willing
* to take. Fraction of image devoted to each border.
*/
float BORDER_X = 0.0f, BORDER_Y = 0.0f;
int TILE_SIZE = 8;
/**
* Position of the minimap relative to it's corner.
*/
int X = 2, Y = 2;
/**
* Dimensions of the minimap
*/
int WIDTH = GuiAtlas.WIDTH / 2, HEIGHT = GuiAtlas.HEIGHT / 2;
/**
* Determines which corner to align to
*/
boolean ALIGN_RIGHT = true, ALIGN_BOTTOM = false;
/**
* If true, the minimap will render only while the atlas is held, instead of
* rendering whenever it's in the hotbar.
*/
boolean REQUIRES_HOLD = true;
/**
* If true, the minimap will show
* If false, it will not
*/
boolean ENABLED = true;
/**
* Size of markers on the minimap
*/
int MARKER_SIZE = GuiAtlas.MARKER_SIZE / 2;
int PLAYER_ICON_WIDTH = 7;
int PLAYER_ICON_HEIGHT = 8;
/**
* new ScaledResolution(mc).getScaleFactor();
*/
private int screenScale = 1;
private ScaledResolution res;
/**
* Convenience method that returns the first atlas ID for all atlas items
* the player is currently carrying in the hotbar/offhand. Returns null if
* there are none. Offhand gets priority.
**/
private static Integer getPlayerAtlas(EntityPlayer player) {
if (!AntiqueAtlasMod.settings.itemNeeded) {
return player.getUniqueID().hashCode();
}
ItemStack stack = player.getHeldItemOffhand();
if (!stack.isEmpty() && stack.getItem() == AntiqueAtlasMod.itemAtlas) {
return stack.getItemDamage();
}
for (int i = 0; i < 9; i++) {
stack = player.inventory.getStackInSlot(i);
if (!stack.isEmpty() && stack.getItem() == AntiqueAtlasMod.itemAtlas) {
return stack.getItemDamage();
}
}
return null;
}
@SubscribeEvent(priority = EventPriority.NORMAL)
@SideOnly(Side.CLIENT)
public void eventHandler(RenderGameOverlayEvent.Post event) {
if (event.getType() != RenderGameOverlayEvent.ElementType.ALL) {
return;
}
if (!ENABLED) {
return;
}
// Overlay must close if Atlas GUI is opened
if (Minecraft.getMinecraft().currentScreen instanceof GuiAtlas) {
return;
}
EntityPlayerSP player = Minecraft.getMinecraft().player;
Integer atlas = null;
if (REQUIRES_HOLD) {
ItemStack stack = player.getHeldItemMainhand();
ItemStack stack2 = player.getHeldItemOffhand();
if (stack != null && stack.getItem() == AntiqueAtlasMod.itemAtlas) {
atlas = stack.getItemDamage();
} else if (stack2 != null && stack2.getItem() == AntiqueAtlasMod.itemAtlas) {
atlas = stack2.getItemDamage();
}
} else {
atlas = getPlayerAtlas(player);
}
if (atlas != null) {
int gameWidth = event.getResolution().getScaledWidth();
int gameHeight = event.getResolution().getScaledHeight();
// remember, y=0 is at the top
Rect bounds = new Rect().setOrigin(X, Y);
if (ALIGN_RIGHT) {
bounds.minX = gameWidth - (WIDTH + X);
}
if (ALIGN_BOTTOM) {
bounds.minY = gameHeight - (HEIGHT + Y);
}
bounds.setSize(WIDTH, HEIGHT);
res = event.getResolution();
drawMinimap(bounds, atlas, player.getPositionVector(), player.getRotationYawHead(), player.dimension);
}
}
@SideOnly(Side.CLIENT)
private void drawMinimap(Rect shape, int atlasID, Vec3d position, float rotation,
int dimension) {
screenScale = new ScaledResolution(Minecraft.getMinecraft()).getScaleFactor();
GlStateManager.color(1, 1, 1, 1);
GlStateManager.enableBlend();
GlStateManager.alphaFunc(GL11.GL_GREATER, 0); // So light detail on tiles is
// visible
AtlasRenderHelper.drawFullTexture(Textures.BOOK, shape.minX,
shape.minY, shape.getWidth(), shape.getHeight());
Rect innerShape = new Rect(
// stop it eclipse
shape.minX + Math.round(BORDER_X * shape.getWidth()),
shape.minY + Math.round(BORDER_Y * shape.getHeight()),
shape.maxX - Math.round(BORDER_X * shape.getWidth()),
shape.maxY - Math.round(BORDER_Y * shape.getHeight()));
drawTiles(innerShape, atlasID, position, dimension);
if (MARKER_SIZE > 0) {
drawMarkers(innerShape, atlasID, position, dimension);
int shapeMiddleX = (shape.minX + shape.maxX) / 2;
int shapeMiddleY = (shape.minY + shape.maxY) / 2;
drawPlayer(shapeMiddleX, shapeMiddleY, rotation);
}
// Overlay the frame so that edges of the map are smooth:
GlStateManager.color(1, 1, 1, 1);
AtlasRenderHelper.drawFullTexture(Textures.BOOK_FRAME, shape.minX,
shape.minY, shape.getWidth(), shape.getHeight());
GlStateManager.disableBlend();
}
@SideOnly(Side.CLIENT)
private void drawTiles(Rect shape, int atlasID, Vec3d position,
int dimension) {
GL11.glEnable(GL11.GL_SCISSOR_TEST);
// glScissor uses the default window coordinates,
// the display window does not. We need to fix this
glScissorGUI(shape);
GlStateManager.enableBlend();
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
DimensionData biomeData = AntiqueAtlasMod.atlasData.getAtlasData(
atlasID, Minecraft.getMinecraft().world).getDimensionData(dimension);
TileRenderIterator iter = new TileRenderIterator(biomeData);
Rect iteratorScope = getChunkCoverage(position, shape);
iter.setScope(iteratorScope);
iter.setStep(1);
Vec3d chunkPosition = new Vec3d(
position.xCoord / CHUNK_SIZE,
position.yCoord / CHUNK_SIZE,
position.zCoord / CHUNK_SIZE);
int shapeMiddleX = (shape.minX + shape.maxX) / 2;
int shapeMiddleY = (shape.minY + shape.maxY) / 2;
SetTileRenderer renderer = new SetTileRenderer(TILE_SIZE / 2);
while (iter.hasNext()) {
SubTileQuartet subtiles = iter.next();
for (SubTile subtile : subtiles) {
if (subtile == null || subtile.tile == null)
continue;
// Position of this subtile (measured in chunks) relative to the
// player
float relativeChunkPositionX = (float) (subtile.x / 2.0
+ iteratorScope.minX - chunkPosition.xCoord);
float relativeChunkPositionY = (float) (subtile.y / 2.0
+ iteratorScope.minY - chunkPosition.zCoord);
renderer.addTileCorner(
BiomeTextureMap.instance().getTexture(subtile.tile),
shapeMiddleX
+ (int) Math.floor(relativeChunkPositionX
* TILE_SIZE),
shapeMiddleY
+ (int) Math.floor(relativeChunkPositionY
* TILE_SIZE), subtile.getTextureU(),
subtile.getTextureV());
}
}
renderer.draw();
// get GL back to normal
GL11.glDisable(GL11.GL_SCISSOR_TEST);
GlStateManager.color(1, 1, 1, 1);
}
@SideOnly(Side.CLIENT)
private void drawMarkers(Rect shape, int atlasID, Vec3d position,
int dimension) {
GL11.glEnable(GL11.GL_SCISSOR_TEST);
// glScissor uses the default window coordinates,
// the display window does not. We need to fix this
glScissorGUI(shape);
// biomeData needed to prevent undiscovered markers from appearing
DimensionData biomeData = AntiqueAtlasMod.atlasData.getAtlasData(
atlasID, Minecraft.getMinecraft().world).getDimensionData(
dimension);
DimensionMarkersData globalMarkersData = AntiqueAtlasMod.globalMarkersData
.getData().getMarkersDataInDimension(dimension);
// Draw global markers:
drawMarkersData(globalMarkersData, shape, biomeData, position);
MarkersData markersData = AntiqueAtlasMod.markersData.getMarkersData(
atlasID, Minecraft.getMinecraft().world);
DimensionMarkersData localMarkersData = null;
if (markersData != null) {
localMarkersData = markersData.getMarkersDataInDimension(dimension);
}
// Draw local markers:
drawMarkersData(localMarkersData, shape, biomeData, position);
// get GL back to normal
GL11.glDisable(GL11.GL_SCISSOR_TEST);
GlStateManager.color(1, 1, 1, 1);
}
@SideOnly(Side.CLIENT)
private void drawPlayer(float x, float y, float rotation) {
// Draw player icon:
GlStateManager.pushMatrix();
GlStateManager.translate(x, y, 0);
GlStateManager.rotate(180 + rotation, 0, 0, 1);
GlStateManager.translate(-PLAYER_ICON_WIDTH / 2, -PLAYER_ICON_HEIGHT / 2, 0);
AtlasRenderHelper.drawFullTexture(Textures.PLAYER, 0, 0, PLAYER_ICON_WIDTH, PLAYER_ICON_HEIGHT);
GlStateManager.popMatrix();
GlStateManager.color(1, 1, 1, 1);
}
@SideOnly(Side.CLIENT)
private void drawMarkersData(DimensionMarkersData markersData,
Rect shape, DimensionData biomeData, Vec3d position) {
//this will be large enough to include markers that are larger than tiles
Rect markerShape = new Rect(shape.minX - MARKER_SIZE / 2, shape.minY - MARKER_SIZE / 2,
shape.maxX + MARKER_SIZE / 2, shape.maxY + MARKER_SIZE / 2);
Rect mcchunks = getChunkCoverage(position, markerShape);
Rect chunks = new Rect((int) Math.floor(mcchunks.minX / MarkersData.CHUNK_STEP),
(int) Math.floor(mcchunks.minY / MarkersData.CHUNK_STEP),
(int) Math.ceil(mcchunks.maxX / MarkersData.CHUNK_STEP),
(int) Math.ceil(mcchunks.maxY / MarkersData.CHUNK_STEP));
int shapeMiddleX = (shape.minX + shape.maxX) / 2;
int shapeMiddleY = (shape.minY + shape.maxY) / 2;
for (int x = chunks.minX; x <= chunks.maxX; x++) {
for (int z = chunks.minY; z <= chunks.maxY; z++) {
//A marker chunk is greater than a Minecraft chunk
List<Marker> markers = markersData.getMarkersAtChunk(
Math.round(x),
Math.round(z));
if (markers == null)
continue;
for (Marker marker : markers) {
// Position of this marker relative to the player
// Rounded to the nearest even number
int relativeChunkPositionX = TILE_SIZE * (2 * (marker.getX() / 2) - 2 * (int) Math.floor(position.xCoord / 2))
/ CHUNK_SIZE;
int relativeChunkPositionY = TILE_SIZE * (2 * (marker.getZ() / 2) - 2 * (int) Math.floor(position.zCoord / 2))
/ CHUNK_SIZE;
int guiX = (int) Math.floor(shapeMiddleX - MARKER_SIZE / 2 + relativeChunkPositionX);
int guiY = (int) Math.floor(shapeMiddleY - MARKER_SIZE / 2 + relativeChunkPositionY);
renderMarker(marker, guiX, guiY, biomeData);
}
}
}
}
@SideOnly(Side.CLIENT)
private void renderMarker(Marker marker, int x, int y,
DimensionData biomeData) {
if (!marker.isVisibleAhead()
&& !biomeData.hasTileAt(marker.getChunkX(), marker.getChunkZ())) {
return;
}
GlStateManager.color(1, 1, 1, 1);
MarkerRenderInfo info = marker.getType().getRenderInfo(1, TILE_SIZE, screenScale);
AtlasRenderHelper.drawFullTexture(info.tex, x, y, MARKER_SIZE, MARKER_SIZE);
}
private Rect getChunkCoverage(Vec3d position, Rect windowShape) {
int minChunkX = (int) Math.floor(position.xCoord / CHUNK_SIZE
- windowShape.getWidth() / (2f * TILE_SIZE));
minChunkX -= 1;// IDK
int minChunkY = (int) Math.floor(position.zCoord / CHUNK_SIZE
- windowShape.getHeight() / (2f * TILE_SIZE));
minChunkY -= 1;// IDK
int maxChunkX = (int) Math.ceil(position.xCoord / CHUNK_SIZE
+ windowShape.getWidth() / (2f * TILE_SIZE));
maxChunkX += 1;
int maxChunkY = (int) Math.ceil(position.zCoord / CHUNK_SIZE
+ windowShape.getHeight() / (2f * TILE_SIZE));
maxChunkY += 1;
return new Rect(minChunkX, minChunkY, maxChunkX, maxChunkY);
}
/**
* Calls GL11.glScissor, but uses GUI coordinates
*/
@SideOnly(Side.CLIENT)
private void glScissorGUI(Rect shape) {
// glScissor uses the default window coordinates,
// the display window does not. We need to fix this
int mcHeight = Minecraft.getMinecraft().displayHeight;
float scissorScaleX = Minecraft.getMinecraft().displayWidth * 1.0f
/ res.getScaledWidth();
float scissorScaleY = mcHeight * 1.0f / res.getScaledHeight();
GL11.glScissor((int) (shape.minX * scissorScaleX),
(int) (mcHeight - shape.maxY * scissorScaleY),
(int) (shape.getWidth() * scissorScaleX),
(int) (shape.getHeight() * scissorScaleY));
}
}