| package com.plusminus.craft; | |
| import java.awt.BasicStroke; | |
| import java.awt.Color; | |
| import java.awt.Font; | |
| import java.awt.Graphics2D; | |
| import java.awt.Image; | |
| import java.awt.image.BufferedImage; | |
| import java.awt.image.DataBufferByte; | |
| import java.io.File; | |
| import java.io.IOException; | |
| import java.nio.ByteBuffer; | |
| import java.nio.FloatBuffer; | |
| import java.util.ArrayList; | |
| import java.util.Stack; | |
| import java.util.TreeSet; | |
| import javax.imageio.ImageIO; | |
| import javax.swing.JOptionPane; | |
| import org.lwjgl.Sys; | |
| import org.lwjgl.opengl.Display; | |
| import org.lwjgl.opengl.DisplayMode; | |
| import org.lwjgl.opengl.GL11; | |
| import org.lwjgl.util.glu.*; | |
| import org.lwjgl.input.Keyboard; | |
| import org.lwjgl.input.Mouse; | |
| import com.plusminus.craft.dtf.ByteArrayTag; | |
| import com.plusminus.craft.dtf.CompoundTag; | |
| import com.plusminus.craft.dtf.DTFReader; | |
| import com.plusminus.craft.dtf.IntTag; | |
| import com.plusminus.craft.dtf.Tag; | |
| import static com.plusminus.craft.MineCraftConstants.*; | |
| public class XRay { | |
| // for the sprite sheet | |
| // number of chunks around the camera which are visible (Square) | |
| private int visible_chunk_range = 5; | |
| private int mapchange_redraw_range = 3; | |
| private static final int[] CHUNK_RANGES_KEYS = new int[] { | |
| Keyboard.KEY_NUMPAD1, | |
| Keyboard.KEY_NUMPAD2, | |
| Keyboard.KEY_NUMPAD3, | |
| Keyboard.KEY_NUMPAD4, | |
| Keyboard.KEY_NUMPAD5, | |
| Keyboard.KEY_NUMPAD6 | |
| }; | |
| private static final int[] CHUNK_RANGES = new int[] {3,4,5,6,7,8}; | |
| private int currentChunkRange = 2; | |
| // highlight distance | |
| private static final int[] HIGHLIGHT_RANGES_KEYS = new int[] { | |
| Keyboard.KEY_1, | |
| Keyboard.KEY_2, | |
| Keyboard.KEY_3, | |
| Keyboard.KEY_4, | |
| Keyboard.KEY_5, | |
| Keyboard.KEY_6, | |
| Keyboard.KEY_7 | |
| }; | |
| private static final int[] HIGHLIGHT_RANGES = new int[] {2, 3, 4, 5, 6, 7, 8}; | |
| private int currentHighlightDistance = 1; | |
| // set to true when the program is finished | |
| private boolean done = false; | |
| // are we full screen | |
| private boolean fullscreen = false; | |
| // window title | |
| private final String app_version = "2.7 Maintenance Branch 4"; | |
| private final String app_name = "Minecraft X-Ray"; | |
| private final String windowTitle = app_name + " " + app_version; | |
| // current display mode | |
| private DisplayMode displayMode; | |
| // last system time in the main loop (to calculate delta for camera movement) | |
| private long lastTime; | |
| // our camera | |
| private FirstPersonCameraController camera; | |
| // the current mouseX and mouseY on the screen | |
| private int mouseX; | |
| private int mouseY; | |
| // the sprite sheet for all textures | |
| public Texture minecraftTexture; | |
| // the textures used by the minimap | |
| private Texture minimapTexture; | |
| private Texture minimapArrowTexture; | |
| // Whether or not we're showing bedrock | |
| private boolean render_bedrock = false; | |
| // the minecraft level we are exploring | |
| private MinecraftLevel level; | |
| // the current block (universal coordinate) where the camera is hovering on | |
| private int levelBlockX, levelBlockZ; | |
| // the current and previous chunk coordinates where the camera is hovering on | |
| private int currentLevelX, currentLevelZ; | |
| private int oldLevelX, oldLevelZ; | |
| // wheter we are loading a level | |
| private boolean loading = false; | |
| private long loadingStart = 0; | |
| private float loadingProgress = 0; | |
| // synchronization object, a bit redundant now ... but potentially the loader could cause a conflict with the drawing operation | |
| private Object lock = new Object(); | |
| // we render to a display list and use that later for quick drawing, this is the index | |
| private int worldDisplayListNum; | |
| private int visibleOresListNum; | |
| // wheter we need to recreate the display list using the updated level data | |
| private boolean needToRedrawWorld = false; | |
| // wheter we need to reload the world | |
| private boolean needToReloadWorld = false; | |
| // the width and height of the current screen resolution | |
| private int screenWidth, screenHeight; | |
| // the current camera position | |
| private int currentCameraPosX; | |
| private int currentCameraPosZ; | |
| // wheter we show the big map or the mini map | |
| private boolean mapBig = false; | |
| // wheter we are done with loading the map data (just for the mini map really) | |
| private boolean mapLoaded = false; | |
| // wheter we have selected a world number already | |
| private boolean worldSelected = false; | |
| // the available world numbers | |
| private ArrayList<Integer> availableWorlds; | |
| private ArrayList<Integer> availableNetherWorlds; | |
| // the world chunks we still need to load | |
| private Stack<Block> mapChunksToLoad; | |
| // the total chunks in this world | |
| private int totalMapChunks = 0; | |
| // the current (selected) world number | |
| private int worldNum =1; | |
| // the currently pressed key | |
| private int keyPressed = -1; | |
| // the index to the available worlds array | |
| private int worldSelectIndex = 0; | |
| // simple list of textures containing the text we present the user on the world selection screen | |
| private ArrayList<Texture> worldSelectionTextures; | |
| // the current fps we are 'doing' | |
| private int fps; | |
| // the laste time fps was updated | |
| private long lastFpsTime = -1; | |
| // the number of frames since the last fps update | |
| private int framesSinceLastFps; | |
| // the fps display texture | |
| private Texture fpsTexture; | |
| // far too many fps calculation variables (copied this from another project) | |
| public long previousTime; | |
| public long timeDelta; | |
| private boolean updateFPSText; | |
| private long time; | |
| private boolean[] mineralToggle; | |
| private Texture[] mineralToggleTextures; | |
| // lighting on or of (its actually fog, but hey...) | |
| private boolean lightMode = false; | |
| // highlight the ores by making them blink | |
| private boolean highlightOres = true; | |
| // level info texture | |
| private boolean levelInfoToggle; | |
| private Texture levelInfoTexture; | |
| // light level | |
| private int[] lightLevelEnd = new int[]{30,50,70,100,130}; | |
| private int[] lightLevelStart = new int[]{0,20,30,40,60}; | |
| private int currentLightLevel = 2; | |
| // lets start with the program | |
| public static void main(String args[]) { | |
| new XRay().run(); | |
| } | |
| // go | |
| public void run() { | |
| try { | |
| // check whether we can access minecraft | |
| // and if we have worlds to load | |
| checkMinecraftFiles(); | |
| // prompt for the resolution and initialize the window | |
| createWindow(); | |
| // basic opengl initialization | |
| initGL(); | |
| // init our program | |
| initialize(); | |
| // main loop | |
| while (!done) | |
| { | |
| long time = Sys.getTime(); | |
| float timeDelta = (time - lastTime)/1000.0f; | |
| lastTime = time; | |
| // handle input given the timedelta (for mouse control) | |
| handleInput(timeDelta); | |
| // render whatever we need to render | |
| render(timeDelta); | |
| // Push to screen | |
| Display.update(); | |
| } | |
| // cleanup | |
| cleanup(); | |
| } | |
| catch (Exception e) { | |
| // bah some error happened | |
| e.printStackTrace(); | |
| System.exit(0); | |
| } | |
| } | |
| public void incLightLevel() { | |
| this.currentLightLevel++; | |
| if(this.currentLightLevel >= this.lightLevelStart.length) { | |
| this.currentLightLevel = this.lightLevelStart.length-1; | |
| } | |
| } | |
| public void decLightLevel() { | |
| this.currentLightLevel--; | |
| if(this.currentLightLevel <= 0) { | |
| this.currentLightLevel = 0; | |
| } | |
| } | |
| public void setLightLevel() { | |
| this.setLightLevel(0); | |
| } | |
| public void setLightLevel(int diff) { | |
| int min = this.lightLevelStart[this.currentLightLevel]; | |
| int max = this.lightLevelEnd[this.currentLightLevel]; | |
| min = min + diff; | |
| max = max + diff; | |
| if(min <= 0) { | |
| min = 0; | |
| } | |
| if(max <= 0) { | |
| max = 0; | |
| } | |
| GL11.glFogf(GL11.GL_FOG_START, min); | |
| GL11.glFogf(GL11.GL_FOG_END, max); | |
| } | |
| /*** | |
| * Initialize the basic openGL environment | |
| */ | |
| private void initGL() { | |
| GL11.glEnable(GL11.GL_TEXTURE_2D); // Enable Texture Mapping | |
| GL11.glShadeModel(GL11.GL_FLAT); // Disable Smooth Shading | |
| GL11.glClearColor(0.0f, 0.3f, 1.0f, 0.3f); // Blue Background | |
| GL11.glClearDepth(1.0); // Depth Buffer Setup | |
| GL11.glEnable(GL11.GL_DEPTH_TEST); // Enables Depth Testing | |
| GL11.glDepthFunc(GL11.GL_LEQUAL); // The Type Of Depth Testing To Do | |
| //GL11.glDepthFunc(GL11.GL_ALWAYS); | |
| GL11.glEnable(GL11.GL_BLEND); | |
| GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); | |
| // GL11.glBlendFunc(GL11.GL_ONE, GL11.GL_ONE); | |
| GL11.glMatrixMode(GL11.GL_PROJECTION); // Select The Projection Matrix | |
| GL11.glLoadIdentity(); // Reset The Projection Matrix | |
| // Calculate The Aspect Ratio Of The Window | |
| GLU.gluPerspective( | |
| 90.0f, | |
| (float) displayMode.getWidth() / (float) displayMode.getHeight(), | |
| 0.1f, | |
| 400.0f); | |
| GL11.glMatrixMode(GL11.GL_MODELVIEW); // Select The Modelview Matrix | |
| // Really Nice Perspective Calculations | |
| GL11.glHint(GL11.GL_PERSPECTIVE_CORRECTION_HINT, GL11.GL_NICEST); | |
| GL11.glDisable (GL11.GL_FOG); | |
| GL11.glFogi (GL11.GL_FOG_MODE, GL11.GL_LINEAR); | |
| float[] color = new float[] {0.0f, 0.3f, 1.0f, 0.3f}; | |
| ByteBuffer colorBytes = ByteBuffer.allocateDirect(64); | |
| FloatBuffer colorBuffer = colorBytes.asFloatBuffer(); | |
| colorBuffer.rewind(); | |
| colorBuffer.put(color); | |
| colorBuffer.rewind(); | |
| GL11.glFog (GL11.GL_FOG_COLOR, colorBytes.asFloatBuffer()); | |
| GL11.glFogf (GL11.GL_FOG_DENSITY, 0.3f); | |
| GL11.glHint (GL11.GL_FOG_HINT, GL11.GL_NICEST); | |
| setLightLevel(); | |
| } | |
| /*** | |
| * Load textures | |
| * init precalc tables | |
| * determine available worlds | |
| * init misc variables | |
| */ | |
| private void initialize() { | |
| // init the precalc tables | |
| mineralToggle = new boolean[HIGHLIGHT_ORES.length]; | |
| mineralToggleTextures = new Texture[HIGHLIGHT_ORES.length]; | |
| // world display list | |
| worldDisplayListNum = GL11.glGenLists(1); | |
| visibleOresListNum = GL11.glGenLists(1); | |
| // camera | |
| camera = new FirstPersonCameraController(0, 0, 0); | |
| // textures | |
| try { | |
| // ui textures | |
| minimapTexture = TextureTool.allocateTexture(2048,2048); | |
| minimapArrowTexture = TextureTool.allocateTexture(32,32); | |
| fpsTexture = TextureTool.allocateTexture(128, 32); | |
| levelInfoTexture = TextureTool.allocateTexture(128,128); | |
| drawMinimapArrowImage(); | |
| // minecraft textures | |
| BufferedImage minecraftTextureImage = MineCraftEnvironment.getMinecraftTexture(); | |
| minecraftTexture = TextureTool.allocateTexture(minecraftTextureImage, GL11.GL_NEAREST); | |
| minecraftTexture.update(); | |
| // world selection screen textures, nothing fancy | |
| worldSelectionTextures = new ArrayList<Texture>(); | |
| for(int i : availableWorlds) { | |
| Texture worldTexture = TextureTool.allocateTexture(512,32); | |
| Graphics2D g = worldTexture.getImage().createGraphics(); | |
| g.setFont(ARIALFONT); | |
| g.setColor(Color.white); | |
| g.drawString("World " + i, 10, 16); | |
| worldTexture.update(); | |
| worldSelectionTextures.add(worldTexture); | |
| } | |
| for(int i : availableNetherWorlds) { | |
| Texture worldTexture = TextureTool.allocateTexture(512,32); | |
| Graphics2D g = worldTexture.getImage().createGraphics(); | |
| g.setFont(ARIALFONT); | |
| g.setColor(Color.white); | |
| g.drawString("World " + i + " Nether", 10, 16); | |
| worldTexture.update(); | |
| worldSelectionTextures.add(worldTexture); | |
| } | |
| // mineral textures | |
| for(int i=0;i<HIGHLIGHT_ORES.length;i++) { | |
| mineralToggleTextures[i] = TextureTool.allocateTexture(128,32); | |
| Graphics2D g = mineralToggleTextures[i].getImage().createGraphics(); | |
| g.setFont(ARIALFONT); | |
| g.setColor(Color.white); | |
| g.drawString("[F" + (i+1) + "] " + ORES_DESCRIPTION[i], 10, 16); | |
| mineralToggleTextures[i].update(); | |
| } | |
| } catch (IOException e1) { | |
| // TODO Auto-generated catch block | |
| e1.printStackTrace(); | |
| } | |
| // level data | |
| levelBlockX = Integer.MIN_VALUE; | |
| levelBlockZ = Integer.MIN_VALUE; | |
| oldLevelX = 2000; // no meaning to 2000, just 'far away' from 0,0 | |
| oldLevelZ = 2000; | |
| // set mouse grabbed so we can get x/y coordinates | |
| Mouse.setGrabbed(true); | |
| } | |
| private BufferedImage resizeImage(Image baseImage, int newWidth, int newHeight) { | |
| BufferedImage newImage = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_4BYTE_ABGR); | |
| Graphics2D g = newImage.createGraphics(); | |
| g.drawImage(baseImage, 0,0, newWidth, newHeight, null); | |
| return newImage; | |
| } | |
| private byte[] convertIcon(byte[] icon) { | |
| byte[] newIcon = new byte[icon.length]; | |
| for(int i=0;i<newIcon.length;i += 4) { | |
| newIcon[i+3] = icon[i+0]; | |
| newIcon[i+2] = icon[i+1]; | |
| newIcon[i+1] = icon[i+2]; | |
| newIcon[i+0] = icon[i+3]; | |
| } | |
| return newIcon; | |
| } | |
| /*** | |
| * Creates the window and initializes the lwjgl display object | |
| * @throws Exception | |
| */ | |
| private void createWindow() throws Exception { | |
| // set icon buffers | |
| // stupid conversions needed | |
| File iconFile = new File("xray_icon.png"); | |
| ByteBuffer[] icons = null; | |
| if(iconFile.exists() || iconFile.canRead()) { | |
| BufferedImage iconTexture128 = ImageIO.read(iconFile); | |
| iconTexture128 = resizeImage(iconTexture128, 128, 128); // just to be sure all icons are the same imagetype | |
| BufferedImage iconTexture64 = resizeImage(iconTexture128, 64, 64); | |
| BufferedImage iconTexture32 = resizeImage(iconTexture128, 32, 32); | |
| BufferedImage iconTexture16 = resizeImage(iconTexture128, 16, 16); | |
| byte[] iconBuffer128d = ((DataBufferByte) iconTexture128.getRaster().getDataBuffer()).getData(); | |
| byte[] iconBuffer64d = ((DataBufferByte) iconTexture64.getRaster().getDataBuffer()).getData(); | |
| byte[] iconBuffer32d = ((DataBufferByte) iconTexture32.getRaster().getDataBuffer()).getData(); | |
| byte[] iconBuffer16d = ((DataBufferByte) iconTexture16.getRaster().getDataBuffer()).getData(); | |
| iconBuffer128d = convertIcon(iconBuffer128d); // LWJGL (opengl?) needs RGBA ... imagetype available is ABGR | |
| iconBuffer64d = convertIcon(iconBuffer64d); | |
| iconBuffer32d = convertIcon(iconBuffer32d); | |
| iconBuffer16d = convertIcon(iconBuffer16d); | |
| ByteBuffer iconBuffer128 = ByteBuffer.wrap(iconBuffer128d); | |
| ByteBuffer iconBuffer64 = ByteBuffer.wrap(iconBuffer64d); | |
| ByteBuffer iconBuffer32 = ByteBuffer.wrap(iconBuffer32d); | |
| ByteBuffer iconBuffer16 = ByteBuffer.wrap(iconBuffer16d); | |
| iconBuffer128.rewind(); | |
| iconBuffer64.rewind(); | |
| iconBuffer32.rewind(); | |
| iconBuffer16.rewind(); | |
| icons = new ByteBuffer[] { | |
| iconBuffer128, iconBuffer64, iconBuffer32, iconBuffer16 | |
| }; | |
| ResolutionDialog.iconImage = iconTexture128; | |
| } | |
| // System.out.println(new File(".").getAbsolutePath()); | |
| // ask the user for the resolution | |
| if(ResolutionDialog.presentDialog("Mincraft XRAY") == ResolutionDialog.DIALOG_BUTTON_EXIT) { | |
| // want to quit? fine. | |
| System.exit(0); | |
| } | |
| // set fullscreen from the dialog | |
| fullscreen = ResolutionDialog.selectedFullScreenValue; | |
| if(icons != null) | |
| Display.setIcon(icons); | |
| //Display.setIcon(); | |
| Display.setFullscreen(fullscreen); | |
| displayMode = ResolutionDialog.selectedDisplayMode; | |
| Display.setDisplayMode(displayMode); | |
| Display.setTitle(windowTitle); | |
| Display.setVSyncEnabled(true); | |
| Display.create(); | |
| screenWidth = displayMode.getWidth(); | |
| screenHeight = displayMode.getHeight(); | |
| } | |
| /*** | |
| * Checks for sanity of the minecraft environment | |
| */ | |
| private void checkMinecraftFiles() { | |
| if(MineCraftEnvironment.getMinecraftDirectory() == null) { | |
| JOptionPane.showMessageDialog(null, "OS not supported (" + System.getProperty( "os.name" ) + "), please report.", "Minecraft XRAY error" , JOptionPane.ERROR_MESSAGE); | |
| System.exit(0); | |
| } | |
| if(!MineCraftEnvironment.getMinecraftDirectory().exists()) { | |
| JOptionPane.showMessageDialog(null, "Minecraft directory not found: " + MineCraftEnvironment.getMinecraftDirectory().getAbsolutePath(), "Minecraft XRAY error" , JOptionPane.ERROR_MESSAGE); | |
| System.exit(0); | |
| } | |
| if(!MineCraftEnvironment.getMinecraftDirectory().canRead()) { | |
| JOptionPane.showMessageDialog(null, "Minecraft directory not readable: " + MineCraftEnvironment.getMinecraftDirectory().getAbsolutePath(), "Minecraft XRAY error", JOptionPane.ERROR_MESSAGE); | |
| System.exit(0); | |
| } | |
| availableWorlds = MineCraftEnvironment.getAvailableWorlds(); | |
| availableNetherWorlds = MineCraftEnvironment.getAvailableWorlds(true); | |
| if(availableWorlds.size() == 0 && availableNetherWorlds.size() == 0) { | |
| JOptionPane.showMessageDialog(null, "Minecraft directory found, but no minecraft levels available.", "Minecraft XRAY error", JOptionPane.ERROR_MESSAGE); | |
| System.exit(0); | |
| } | |
| } | |
| private void setChunkRange(int n) { | |
| if(n >= CHUNK_RANGES.length) n = CHUNK_RANGES.length-1; | |
| if(n <= 0) n = 0; | |
| if(n == currentChunkRange) { | |
| return; | |
| } | |
| this.currentChunkRange = n; | |
| this.visible_chunk_range = CHUNK_RANGES[n]; | |
| this.mapchange_redraw_range = this.visible_chunk_range-2; | |
| this.needToReloadWorld = true; | |
| } | |
| private void setHighlightRange(int n) { | |
| if(n >= HIGHLIGHT_RANGES.length) n = HIGHLIGHT_RANGES.length-1; | |
| if(n <= 0) n = 0; | |
| if(n == currentHighlightDistance) { | |
| return; | |
| } | |
| this.currentHighlightDistance = n; | |
| } | |
| /*** | |
| * Sets the world number we want to view | |
| * @param worldNum | |
| */ | |
| private void setMinecraftWorld(int worldNum) { | |
| this.setMinecraftWorld(worldNum, false); | |
| } | |
| /*** | |
| * Sets the world number we want to view | |
| * @param worldNum | |
| * @param nether | |
| */ | |
| private void setMinecraftWorld(int worldNum, boolean nether) { | |
| this.worldNum = worldNum; | |
| this.level = new MinecraftLevel(worldNum, nether); | |
| // determine which chunks are available in this world | |
| mapChunksToLoad = new Stack<Block>(); | |
| totalMapChunks = 0; | |
| for(int x=-63;x<63;x++) { | |
| for(int z=-63;z<63;z++) { | |
| if(MineCraftEnvironment.getChunkFile(worldNum, x, z).exists()) { | |
| mapChunksToLoad.add(new Block(x,0,z)); | |
| totalMapChunks++; | |
| } | |
| if(z < -47 && x > 5 && x < 10 && z > -50) { | |
| File f = MineCraftEnvironment.getChunkFile(worldNum, x, z); | |
| //System.out.println("(" + x + ", " + z + ") " + f.getAbsolutePath() + " : " + f.exists()); | |
| } | |
| } | |
| } | |
| moveCameraToPlayerPos(); | |
| } | |
| private void moveCameraToSpawnPoint() { | |
| Block spawnPoint = level.getSpawnPoint(); | |
| this.camera.getPosition().set(spawnPoint.x, spawnPoint.y-1, spawnPoint.z); | |
| this.camera.setYawAndPitch(0,0); | |
| } | |
| private void moveCameraToPlayerPos() { | |
| Block playerPos = level.getPlayerPosition(); | |
| this.camera.getPosition().set(playerPos.x, playerPos.y, playerPos.z); | |
| this.camera.setYawAndPitch(180+level.getPlayerYaw(),level.getPlayerPitch()); | |
| } | |
| /*** | |
| * handles all input on all screens | |
| * @param timeDelta | |
| */ | |
| private void handleInput(float timeDelta) { | |
| //distance in mouse movement from the last getDX() call. | |
| mouseX = Mouse.getDX(); | |
| //distance in mouse movement from the last getDY() call. | |
| mouseY = Mouse.getDY(); | |
| if(worldSelected) { | |
| // we are on the main world screen or the level loading screen | |
| // update the camera (but only if the mouse is grabbed) | |
| if (Mouse.isGrabbed()) | |
| { | |
| camera.incYaw(mouseX * MOUSE_SENSITIVITY); | |
| camera.incPitch(-mouseY * MOUSE_SENSITIVITY); | |
| } | |
| if (Mouse.isButtonDown(0)) { | |
| MOVEMENT_SPEED = 30.0f; | |
| } else if (Mouse.isButtonDown(1)) { | |
| MOVEMENT_SPEED = 3.0f; | |
| } else { | |
| MOVEMENT_SPEED = 10.0f; | |
| } | |
| // check for various keys | |
| if (Keyboard.isKeyDown(Keyboard.KEY_W))//move forward | |
| { | |
| camera.walkForward(MOVEMENT_SPEED*timeDelta); | |
| } | |
| if (Keyboard.isKeyDown(Keyboard.KEY_S))//move backwards | |
| { | |
| camera.walkBackwards(MOVEMENT_SPEED*timeDelta); | |
| } | |
| if (Keyboard.isKeyDown(Keyboard.KEY_A))//strafe left | |
| { | |
| camera.strafeLeft(MOVEMENT_SPEED*timeDelta); | |
| } | |
| if (Keyboard.isKeyDown(Keyboard.KEY_D))//strafe right | |
| { | |
| camera.strafeRight(MOVEMENT_SPEED*timeDelta); | |
| } | |
| if (Keyboard.isKeyDown(Keyboard.KEY_SPACE))//strafe right | |
| { | |
| camera.moveUp(MOVEMENT_SPEED*timeDelta); | |
| } | |
| if (Keyboard.isKeyDown(Keyboard.KEY_LCONTROL))//strafe right | |
| { | |
| camera.moveUp(-MOVEMENT_SPEED*timeDelta); | |
| } | |
| if(Keyboard.isKeyDown(Keyboard.KEY_TAB) && keyPressed != Keyboard.KEY_TAB) { | |
| mapBig = !mapBig; | |
| keyPressed = Keyboard.KEY_TAB; | |
| } | |
| } else { | |
| // world selection screen | |
| if(Keyboard.isKeyDown(Keyboard.KEY_RETURN) || Keyboard.isKeyDown(Keyboard.KEY_SPACE)) { | |
| worldSelected = true; | |
| if (worldSelectIndex > availableWorlds.size()-1) | |
| { | |
| this.setMinecraftWorld(availableNetherWorlds.get(worldSelectIndex - availableWorlds.size()), true); | |
| } | |
| else | |
| { | |
| this.setMinecraftWorld(availableWorlds.get(worldSelectIndex)); | |
| } | |
| } | |
| if (Keyboard.isKeyDown(Keyboard.KEY_W) && keyPressed != Keyboard.KEY_W)//move forward | |
| { | |
| keyPressed = Keyboard.KEY_W; | |
| if(worldSelectIndex > 0) worldSelectIndex--; | |
| } | |
| if (Keyboard.isKeyDown(Keyboard.KEY_S) && keyPressed != Keyboard.KEY_S)//move backwards | |
| { | |
| keyPressed = Keyboard.KEY_S; | |
| if(worldSelectIndex < availableWorlds.size()-1) worldSelectIndex++; | |
| } | |
| if (Keyboard.isKeyDown(Keyboard.KEY_UP) && keyPressed != Keyboard.KEY_UP)//move forward | |
| { | |
| keyPressed = Keyboard.KEY_UP; | |
| if(worldSelectIndex > 0) worldSelectIndex--; | |
| } | |
| if (Keyboard.isKeyDown(Keyboard.KEY_DOWN) && keyPressed != Keyboard.KEY_DOWN)//move backwards | |
| { | |
| keyPressed = Keyboard.KEY_DOWN; | |
| if(worldSelectIndex < availableWorlds.size()+availableNetherWorlds.size()-1) worldSelectIndex++; | |
| } | |
| } | |
| if(!loading) { | |
| needToReloadWorld = false; | |
| for(int i=0;i<mineralToggle.length;i++) { | |
| if(Keyboard.isKeyDown(Keyboard.KEY_F1 + i) && keyPressed != Keyboard.KEY_F1 + i) { | |
| keyPressed = Keyboard.KEY_F1 + i; | |
| mineralToggle[i] = !mineralToggle[i]; | |
| needToReloadWorld = true; | |
| } | |
| } | |
| if(needToReloadWorld) { | |
| invalidateSelectedChunks(); | |
| } | |
| } | |
| if(Keyboard.isKeyDown(Keyboard.KEY_F10) && keyPressed != Keyboard.KEY_F10) { // Is F10 Being Pressed? | |
| keyPressed = Keyboard.KEY_F10; | |
| switchFullScreenMode(); // Toggle Fullscreen / Windowed Mode | |
| } | |
| if(Keyboard.isKeyDown(Keyboard.KEY_F) && keyPressed != Keyboard.KEY_F) { // Is F9 Being Pressed? | |
| keyPressed = Keyboard.KEY_F; | |
| setLightMode(!lightMode); // toggle torch | |
| } | |
| if(Keyboard.isKeyDown(Keyboard.KEY_H) && keyPressed != Keyboard.KEY_H) { // Is F8 Being Pressed? | |
| keyPressed = Keyboard.KEY_H; | |
| highlightOres = !highlightOres; // Toggle torch | |
| } | |
| if(Keyboard.isKeyDown(Keyboard.KEY_HOME) && keyPressed != Keyboard.KEY_HOME) { // Is HOME Being Pressed? | |
| keyPressed = Keyboard.KEY_HOME; | |
| moveCameraToSpawnPoint(); //Move to spawnpoint | |
| } | |
| if(Keyboard.isKeyDown(Keyboard.KEY_END) && keyPressed != Keyboard.KEY_END) { // Is HOME Being Pressed? | |
| keyPressed = Keyboard.KEY_END; | |
| moveCameraToPlayerPos(); //Move to spawnpoint | |
| } | |
| if(Keyboard.isKeyDown(Keyboard.KEY_ADD) && keyPressed != Keyboard.KEY_ADD) { // Is PLUS Being Pressed? | |
| keyPressed = Keyboard.KEY_ADD; | |
| incLightLevel(); // Increase Light Level | |
| } | |
| if(Keyboard.isKeyDown(Keyboard.KEY_EQUALS) && keyPressed != Keyboard.KEY_EQUALS) { // Is PLUS Being Pressed? | |
| keyPressed = Keyboard.KEY_EQUALS; | |
| incLightLevel(); // Increase Light Level | |
| } | |
| if(Keyboard.isKeyDown(Keyboard.KEY_MINUS) && keyPressed != Keyboard.KEY_MINUS) { // Is PLUS Being Pressed? | |
| keyPressed = Keyboard.KEY_MINUS; | |
| decLightLevel(); // Increase Light Level | |
| } | |
| if(Keyboard.isKeyDown(Keyboard.KEY_SUBTRACT) && keyPressed != Keyboard.KEY_SUBTRACT) { // Is PLUS Being Pressed? | |
| keyPressed = Keyboard.KEY_SUBTRACT; | |
| decLightLevel(); // Increase Light Level | |
| } | |
| if(Keyboard.isKeyDown(Keyboard.KEY_GRAVE) && keyPressed != Keyboard.KEY_GRAVE) { // toggle level info | |
| keyPressed = Keyboard.KEY_GRAVE; | |
| levelInfoToggle = !levelInfoToggle; // toggle level info | |
| } | |
| if (Keyboard.isKeyDown(Keyboard.KEY_B) && keyPressed != Keyboard.KEY_B) { // Toggle bedrock rendering | |
| keyPressed = Keyboard.KEY_B; | |
| render_bedrock = !render_bedrock; | |
| invalidateSelectedChunks(true); | |
| } | |
| // handle chunk ranges | |
| for(int i = 0; i<CHUNK_RANGES.length;i++) { | |
| if(Keyboard.isKeyDown(CHUNK_RANGES_KEYS[i]) && keyPressed != CHUNK_RANGES_KEYS[i]) { // Is PLUS Being Pressed? | |
| keyPressed = CHUNK_RANGES_KEYS[i]; | |
| setChunkRange(i); // Increase Light Level | |
| } | |
| } | |
| // handle highlight distances | |
| for(int i = 0; i<HIGHLIGHT_RANGES.length;i++) { | |
| if(Keyboard.isKeyDown(HIGHLIGHT_RANGES_KEYS[i]) && keyPressed != HIGHLIGHT_RANGES_KEYS[i]) { | |
| keyPressed = HIGHLIGHT_RANGES_KEYS[i]; | |
| setHighlightRange(i); | |
| } | |
| } | |
| if(Keyboard.isKeyDown(Keyboard.KEY_ESCAPE)) { // Release the mouse on Escape | |
| Mouse.setGrabbed(false); | |
| } | |
| if (Mouse.isButtonDown(0)) { | |
| Mouse.setGrabbed(true); // Grab the mouse if we're clicked | |
| } | |
| if (Keyboard.isKeyDown(Keyboard.KEY_Q) && Keyboard.isKeyDown(Keyboard.KEY_LCONTROL)) { // Exit if "Ctrl-Q" is pressed | |
| done = true; | |
| } | |
| if(Display.isCloseRequested()) { // Exit if window is closed | |
| done = true; | |
| } | |
| if(keyPressed != -1) { | |
| if(!Keyboard.isKeyDown(keyPressed)) { | |
| keyPressed = -1; | |
| } | |
| } | |
| } | |
| private void invalidateSelectedChunks() { | |
| level.invalidateSelected(false); | |
| } | |
| private void invalidateSelectedChunks(boolean main_dirty) { | |
| level.invalidateSelected(main_dirty); | |
| } | |
| private void setLightMode(boolean lightMode) { | |
| this.lightMode = lightMode; | |
| if(lightMode) { | |
| GL11.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // Black Background | |
| GL11.glEnable (GL11.GL_FOG); | |
| } else { | |
| GL11.glClearColor(0.0f, 0.3f, 1.0f, 0.3f); // Blue Background | |
| GL11.glDisable (GL11.GL_FOG); | |
| } | |
| } | |
| /*** | |
| * Switches full screen mode | |
| */ | |
| private void switchFullScreenMode() { | |
| fullscreen = !fullscreen; | |
| try { | |
| Display.setFullscreen(fullscreen); | |
| } | |
| catch(Exception e) { | |
| e.printStackTrace(); | |
| } | |
| } | |
| /*** | |
| * Load a map chunk and draw the progress to the screen. Note that we don't actually | |
| * run the mainloop while doing this, which is a bit Off, but lets us read in the map | |
| * as quickly as possible, rather than having it slaved to the mainloop time. Specifically, | |
| * we want to avoid calling the Display.update() function if we don't have to. | |
| */ | |
| private void loadMapPart() { | |
| long curtime = Sys.getTime(); | |
| long interval = Sys.getTimerResolution() / 30; // Update the status bar 30 times a second | |
| while (!mapChunksToLoad.isEmpty()) { | |
| Block b = mapChunksToLoad.pop(); | |
| drawMapChunkToMap(b.x, b.z); | |
| if ((Sys.getTime()-curtime) > interval) | |
| { | |
| handleInput(0); | |
| if (done) | |
| { | |
| return; | |
| } | |
| curtime = Sys.getTime(); | |
| float progress= 1.0f - ((float) mapChunksToLoad.size() / (float) totalMapChunks); | |
| float bx = 100; | |
| float ex = screenWidth-100; | |
| float by = (screenHeight/2.0f)-50; | |
| float ey = (screenHeight/2.0f)+50; | |
| float px = ((ex-bx)*progress) + bx; | |
| setOrthoOn(); | |
| GL11.glDisable(GL11.GL_BLEND); | |
| GL11.glDisable(GL11.GL_TEXTURE_2D); | |
| GL11.glColor4f(1.0f, 1.0f, 1.0f, 1.0f); | |
| GL11.glLineWidth(20); | |
| // progress bar outer box | |
| GL11.glBegin(GL11.GL_LINE_LOOP); | |
| GL11.glVertex2f(bx, by); | |
| GL11.glVertex2f(ex, by); | |
| GL11.glVertex2f(ex, ey); | |
| GL11.glVertex2f(bx, ey); | |
| GL11.glEnd(); | |
| // progress bar 'progress' | |
| GL11.glBegin(GL11.GL_TRIANGLE_STRIP); | |
| GL11.glVertex2f(bx, by); | |
| GL11.glVertex2f(px, by); | |
| GL11.glVertex2f(bx, ey); | |
| GL11.glVertex2f(px, ey); | |
| GL11.glEnd(); | |
| GL11.glEnable(GL11.GL_BLEND); | |
| GL11.glEnable(GL11.GL_TEXTURE_2D); | |
| setOrthoOff(); | |
| Display.update(); | |
| } | |
| } | |
| mapLoaded = true; | |
| drawMapMarkersToMinimap(); | |
| minimapTexture.update(); | |
| setLightMode(true); // basically enable fog etc | |
| } | |
| /*** | |
| * Draw the current and spawn position to the minimap | |
| */ | |
| private void drawMapMarkersToMinimap() { | |
| Graphics2D g = minimapTexture.getImage().createGraphics(); | |
| Block spawn = level.getSpawnPoint(); | |
| Block player = level.getPlayerPosition(); | |
| int px = 1024-player.x; | |
| int py = 1024-player.z; | |
| int sx = 1024-spawn.x; | |
| int sy = 1024-spawn.z; | |
| g.setColor(Color.red.brighter()); | |
| g.setStroke(new BasicStroke(2)); | |
| g.drawOval(sx-6, sy-6, 11, 11); | |
| g.drawLine(sx-8, sy, sx+8, sy); | |
| g.drawLine(sx, sy-8, sx, sy+8); | |
| g.setColor(Color.yellow.brighter()); | |
| g.drawOval(px-6, py-6, 11, 11); | |
| g.drawLine(px-8, py, px+8, py); | |
| g.drawLine(px, py-8, px, py+8); | |
| minimapTexture.update(); | |
| } | |
| /*** | |
| * Renders the world selection screen | |
| */ | |
| private void renderWorldSelection() { | |
| setOrthoOn(); | |
| float y = 0; | |
| float yy = screenHeight / (worldSelectionTextures.size()+1); | |
| float x = (screenWidth / 2.0f)-256; | |
| GL11.glColor4f(1.0f, 1.0f, 1.0f, 1.0f); | |
| // draw available worlds | |
| for(Texture t : worldSelectionTextures) { | |
| y += yy; | |
| SpriteTool.drawSpriteAbsoluteXY(t, x, y); | |
| } | |
| float bx = x; | |
| float by = (worldSelectIndex+1) * yy; | |
| float ex = x+512; | |
| float ey = by+32; | |
| by -=5; | |
| ey -=5; | |
| // draw the current selection box (just a red rectangle) | |
| GL11.glDisable(GL11.GL_BLEND); | |
| GL11.glDisable(GL11.GL_TEXTURE_2D); | |
| GL11.glColor4f(1.0f, 0.0f, 0.0f, 1.0f); | |
| GL11.glLineWidth(4); | |
| GL11.glBegin(GL11.GL_LINE_LOOP); | |
| GL11.glVertex2f(bx, by); | |
| GL11.glVertex2f(ex, by); | |
| GL11.glVertex2f(ex, ey); | |
| GL11.glVertex2f(bx, ey); | |
| GL11.glEnd(); | |
| GL11.glEnable(GL11.GL_BLEND); | |
| GL11.glEnable(GL11.GL_TEXTURE_2D); | |
| setOrthoOff(); | |
| } | |
| /*** | |
| * Main render loop | |
| * @param timeDelta | |
| * @return | |
| */ | |
| private boolean render(float timeDelta) { | |
| //GL11.glLoadIdentity(); | |
| GL11.glLoadIdentity(); | |
| GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT); // Clear The Screen And The Depth Buffer | |
| // are we at the world selection screen? | |
| if(!worldSelected) { | |
| renderWorldSelection(); | |
| return true; | |
| } | |
| // are we still loading the map? | |
| if(!mapLoaded) { | |
| loadMapPart(); | |
| return true; | |
| } | |
| // we are viewing a world | |
| GL11.glPushMatrix(); | |
| // change the camera to point a the right direction | |
| camera.applyCameraTransformation(); | |
| currentCameraPosX = (int) -camera.getPosition().x; | |
| currentCameraPosZ = (int) -camera.getPosition().z; | |
| // determine if we need to load new map chunks | |
| if(!loading && (currentCameraPosX != levelBlockX || currentCameraPosZ != levelBlockZ || needToReloadWorld)) { | |
| levelBlockX = currentCameraPosX; | |
| levelBlockZ = currentCameraPosZ; | |
| currentLevelX = level.getChunkX(levelBlockX); | |
| currentLevelZ = level.getChunkZ(levelBlockZ); | |
| } | |
| // draw the visible world | |
| int chunk_range = visible_chunk_range; | |
| if (HIGHLIGHT_RANGES[currentHighlightDistance] < chunk_range) | |
| { | |
| chunk_range = HIGHLIGHT_RANGES[currentHighlightDistance]; | |
| } | |
| GL11.glEnable(GL11.GL_TEXTURE_2D); | |
| GL11.glColor3f(1.0f,1.0f,1.0f); | |
| minecraftTexture.bind(); | |
| for(int lx=currentLevelX-visible_chunk_range;lx<currentLevelX+visible_chunk_range;lx++) { | |
| for(int lz=currentLevelZ-visible_chunk_range;lz<currentLevelZ+visible_chunk_range;lz++) { | |
| Chunk k = level.getChunk(lx, lz); | |
| if(k != null) | |
| { | |
| k.renderSolid(render_bedrock); | |
| k.renderSelected(this.mineralToggle); | |
| } | |
| } | |
| } | |
| for(int lx=currentLevelX-visible_chunk_range;lx<currentLevelX+visible_chunk_range;lx++) { | |
| for(int lz=currentLevelZ-visible_chunk_range;lz<currentLevelZ+visible_chunk_range;lz++) { | |
| Chunk k = level.getChunk(lx, lz); | |
| if(k != null) k.renderTransparency(); | |
| } | |
| } | |
| if(highlightOres) { | |
| GL11.glDisable(GL11.GL_DEPTH_TEST); | |
| long time = System.currentTimeMillis(); | |
| float alpha = (time % 1000) / 1000.0f; | |
| if(time % 2000 > 1000) alpha = 1.0f - alpha; | |
| alpha = 0.1f + (alpha*0.8f); | |
| GL11.glColor4f(alpha, alpha, alpha, alpha); | |
| setLightLevel(20); | |
| GL11.glBlendFunc(GL11.GL_ONE, GL11.GL_ONE); | |
| for(int lx=currentLevelX-chunk_range;lx<currentLevelX+chunk_range;lx++) { | |
| for(int lz=currentLevelZ-chunk_range;lz<currentLevelZ+chunk_range;lz++) { | |
| Chunk k = level.getChunk(lx, lz); | |
| if(k != null) | |
| k.renderSelected(this.mineralToggle); | |
| } | |
| } | |
| GL11.glEnable(GL11.GL_DEPTH_TEST); | |
| GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); | |
| setLightLevel(); | |
| } | |
| GL11.glPopMatrix(); | |
| // draw the user interface (fps and map) | |
| drawUI(); | |
| return true; | |
| } | |
| /*** | |
| * Draw the ui | |
| */ | |
| private void drawUI() { | |
| framesSinceLastFps++; | |
| setOrthoOn(); // 2d mode | |
| drawMinimap(); | |
| drawFPSCounter(); | |
| drawMineralToggle(); | |
| drawLoadingBar(); | |
| drawLevelInfo(); | |
| setOrthoOff(); // back to 3d mode | |
| } | |
| private void updateLevelInfo() { | |
| Graphics2D g = levelInfoTexture.getImage().createGraphics(); | |
| g.setBackground(Color.BLUE); | |
| g.clearRect(0, 0, 128, 128); | |
| g.setColor(Color.WHITE); | |
| g.fillRect(2, 2, 124, 124); | |
| g.setFont(ARIALFONT); | |
| int chunkX = level.getChunkX(levelBlockX); | |
| int chunkZ = level.getChunkZ(levelBlockZ); | |
| g.setColor(Color.BLACK); | |
| g.drawString("Chunk X:", 5, 22); | |
| g.setColor(Color.RED.darker()); | |
| g.drawString(Integer.toString(chunkX), 90, 22); | |
| g.setColor(Color.BLACK); | |
| g.drawString("Chunk Z:", 5, 22+16); | |
| g.setColor(Color.RED.darker()); | |
| g.drawString(Integer.toString(chunkZ), 90, 22+16); | |
| g.setColor(Color.BLACK); | |
| g.drawString("World X:", 5, 22+32); | |
| g.setColor(Color.RED.darker()); | |
| g.drawString(Integer.toString(levelBlockX), 90, 22+32); | |
| g.setColor(Color.BLACK); | |
| g.drawString("World Z:", 5, 22+16+32); | |
| g.setColor(Color.RED.darker()); | |
| g.drawString(Integer.toString(levelBlockZ), 90, 22+16+32); | |
| long heapSize = Runtime.getRuntime().totalMemory(); | |
| g.setColor(Color.BLACK); | |
| g.drawString("Memory Used", 5, 22+16+32+25); | |
| g.setColor(Color.RED.darker()); | |
| g.drawString(Integer.toString((int) (heapSize/1024/1024)) + " MB", 20, 22+16+32+25+20); | |
| levelInfoTexture.update(); | |
| } | |
| /*** | |
| * | |
| */ | |
| private void drawLevelInfo() { | |
| if(levelInfoToggle) { | |
| GL11.glColor4f(1.0f, 1.0f, 1.0f, 1.0f); | |
| SpriteTool.drawSpriteAbsoluteXY( | |
| levelInfoTexture, | |
| 0, | |
| 48 | |
| ); | |
| } | |
| } | |
| /*** | |
| * draw the loading bar | |
| */ | |
| private void drawLoadingBar() { | |
| if(loading) { | |
| /* long time = System.currentTimeMillis() - loadingStart; | |
| float alpha = (time % 1000) / 1000.0f; | |
| if(time % 2000 > 1000) alpha = 1.0f - alpha;*/ | |
| float bx = screenWidth/2.0f - 200.0f; | |
| float ex = bx+400.0f; | |
| float by = 20; | |
| float ey = 50; | |
| float px = ((ex-bx)*loadingProgress) + bx; | |
| float alpha = 1.0f; | |
| if(loadingProgress < 0.1f) { | |
| alpha = loadingProgress * 10.0f; | |
| } | |
| if(loadingProgress > 0.9f) { | |
| alpha = 1.0f - ((loadingProgress-0.9f) * 10.0f); | |
| } | |
| GL11.glDisable(GL11.GL_TEXTURE_2D); | |
| GL11.glColor4f(1.0f, 1.0f, 1.0f, alpha); | |
| GL11.glLineWidth(2); | |
| // progress bar outer box | |
| GL11.glBegin(GL11.GL_LINE_LOOP); | |
| GL11.glVertex2f(bx, by); | |
| GL11.glVertex2f(ex, by); | |
| GL11.glVertex2f(ex, ey); | |
| GL11.glVertex2f(bx, ey); | |
| GL11.glEnd(); | |
| // progress bar 'progress' | |
| GL11.glBegin(GL11.GL_TRIANGLE_STRIP); | |
| GL11.glVertex2f(bx, by); | |
| GL11.glVertex2f(px, by); | |
| GL11.glVertex2f(bx, ey); | |
| GL11.glVertex2f(px, ey); | |
| GL11.glEnd(); | |
| GL11.glEnable(GL11.GL_TEXTURE_2D); | |
| } | |
| } | |
| /*** | |
| * Draw the mineral toggles | |
| */ | |
| private void drawMineralToggle() { | |
| int barWidth = 128+10+32; | |
| int barHeight = 42; | |
| int maxCols = 5; | |
| float mineralTogglebarLength = (mineralToggleTextures.length % maxCols) * barWidth; | |
| float curX = (screenWidth / 2.0f) - (mineralTogglebarLength/2.0f); | |
| float curY = screenHeight - barHeight; | |
| if (mineralToggleTextures.length > maxCols) | |
| { | |
| curY -= barHeight; | |
| } | |
| for(int i=0;i<mineralToggleTextures.length;i++) { | |
| if (i == mineralToggleTextures.length - maxCols) | |
| { | |
| mineralTogglebarLength = maxCols * barWidth; | |
| curY += barHeight; | |
| curX = (screenWidth / 2.0f) - (mineralTogglebarLength/2.0f); | |
| } | |
| if(mineralToggle[i]) { | |
| GL11.glColor4f(1.0f, 1.0f, 1.0f, 1.0f); | |
| GL11.glDisable(GL11.GL_TEXTURE_2D); | |
| SpriteTool.drawCurrentSprite( | |
| curX - 2, curY -2, | |
| 36, 36, | |
| MineCraftConstants.precalcSpriteSheetToTextureX[blockDataToSpriteSheet[HIGHLIGHT_ORES[i]]], | |
| MineCraftConstants.precalcSpriteSheetToTextureY[blockDataToSpriteSheet[HIGHLIGHT_ORES[i]]], | |
| MineCraftConstants.precalcSpriteSheetToTextureX[blockDataToSpriteSheet[HIGHLIGHT_ORES[i]]]+TEX16, | |
| MineCraftConstants.precalcSpriteSheetToTextureY[blockDataToSpriteSheet[HIGHLIGHT_ORES[i]]]+TEX16 | |
| ); | |
| GL11.glEnable(GL11.GL_TEXTURE_2D); | |
| } else { | |
| GL11.glColor4f(0.5f, 0.5f, 0.5f, 1.0f); | |
| } | |
| minecraftTexture.bind(); | |
| SpriteTool.drawCurrentSprite( | |
| curX, curY, | |
| 32, 32, | |
| MineCraftConstants.precalcSpriteSheetToTextureX[blockDataToSpriteSheet[HIGHLIGHT_ORES[i]]], | |
| MineCraftConstants.precalcSpriteSheetToTextureY[blockDataToSpriteSheet[HIGHLIGHT_ORES[i]]], | |
| MineCraftConstants.precalcSpriteSheetToTextureX[blockDataToSpriteSheet[HIGHLIGHT_ORES[i]]]+TEX16, | |
| MineCraftConstants.precalcSpriteSheetToTextureY[blockDataToSpriteSheet[HIGHLIGHT_ORES[i]]]+TEX16 | |
| ); | |
| SpriteTool.drawSpriteAbsoluteXY(mineralToggleTextures[i], curX + 32 + 10, curY+7); | |
| curX += barWidth; | |
| } | |
| } | |
| /*** | |
| * Draws a simple fps counter on the top-left of the screen | |
| */ | |
| private void drawFPSCounter() { | |
| previousTime = time; | |
| time = System.nanoTime(); | |
| timeDelta = time - previousTime; | |
| if (time - lastFpsTime > NANOSPERSECOND) { | |
| fps = framesSinceLastFps; | |
| framesSinceLastFps = 0; | |
| lastFpsTime = time; | |
| updateFPSText = true; | |
| } | |
| if (updateFPSText) { | |
| if(levelInfoToggle) | |
| updateLevelInfo(); | |
| Graphics2D g = fpsTexture.getImage().createGraphics(); | |
| g.setBackground(Color.BLUE); | |
| g.clearRect(0, 0, 128, 32); | |
| g.setColor(Color.WHITE); | |
| g.fillRect(2, 2, 124, 28); | |
| g.setColor(Color.BLACK); | |
| g.setFont(ARIALFONT); | |
| g.drawString("FPS:", 10, 22); | |
| g.setColor(Color.RED.darker()); | |
| g.drawString(Integer.toString(fps), 60, 22); | |
| fpsTexture.update(); | |
| updateFPSText = false; | |
| } | |
| fpsTexture.bind(); | |
| GL11.glColor4f(1.0f, 1.0f, 1.0f, 0.7f); | |
| SpriteTool.drawSpriteAbsoluteXY(fpsTexture, 0, 0); | |
| GL11.glColor4f(1.0f, 1.0f, 1.0f, 1f); | |
| } | |
| /*** | |
| * Sets ortho (2d) mode | |
| */ | |
| public void setOrthoOn() | |
| { | |
| // prepare projection matrix to render in 2D | |
| GL11.glMatrixMode(GL11.GL_PROJECTION); | |
| GL11.glPushMatrix(); // preserve perspective view | |
| GL11.glLoadIdentity(); // clear the perspective matrix | |
| GL11.glOrtho( // turn on 2D mode | |
| ////viewportX,viewportX+viewportW, // left, right | |
| ////viewportY,viewportY+viewportH, // bottom, top !!! | |
| 0,screenWidth, // left, right | |
| screenHeight,0, // bottom, top | |
| -500,500); // Zfar, Znear | |
| // clear the modelview matrix | |
| GL11.glMatrixMode(GL11.GL_MODELVIEW); | |
| GL11.glPushMatrix(); // Preserve the Modelview Matrix | |
| GL11.glLoadIdentity(); // clear the Modelview Matrix | |
| // disable depth test so further drawing will go over the current scene | |
| GL11.glDisable(GL11.GL_DEPTH_TEST); | |
| } | |
| /** | |
| * Restore the previous mode | |
| */ | |
| public static void setOrthoOff() | |
| { | |
| // restore the original positions and views | |
| GL11.glMatrixMode(GL11.GL_PROJECTION); | |
| GL11.glPopMatrix(); | |
| GL11.glMatrixMode(GL11.GL_MODELVIEW); | |
| GL11.glPopMatrix(); | |
| // turn Depth Testing back on | |
| GL11.glEnable(GL11.GL_DEPTH_TEST); | |
| } | |
| /*** | |
| * draws the minimap or the big map | |
| */ | |
| private void drawMinimap() { | |
| if(mapBig) { | |
| // the big map | |
| // just draws the texture, but move the texture so the middle of the screen is where we currently are | |
| float halfMapWidth = 2048/2.0f; // 840 | |
| minimapTexture.bind(); | |
| GL11.glColor4f(1.0f, 1.0f, 1.0f, 0.7f); | |
| GL11.glPushMatrix(); | |
| GL11.glTranslatef((screenWidth/2.0f)-currentCameraPosX, (screenHeight/2.0f)-currentCameraPosZ, 0.0f); | |
| GL11.glBegin(GL11.GL_TRIANGLE_STRIP); | |
| GL11.glTexCoord2f(0, 0); | |
| GL11.glVertex2f(-halfMapWidth, -halfMapWidth); | |
| GL11.glTexCoord2f(1, 0); | |
| GL11.glVertex2f(+halfMapWidth, -halfMapWidth); | |
| GL11.glTexCoord2f(0, 1); | |
| GL11.glVertex2f(-halfMapWidth, +halfMapWidth); | |
| GL11.glTexCoord2f(1, 1); | |
| GL11.glVertex2f(+halfMapWidth, +halfMapWidth); | |
| GL11.glEnd(); | |
| GL11.glPopMatrix(); | |
| GL11.glColor4f(1.0f, 1.0f, 1.0f, 1f); | |
| SpriteTool.drawSpriteAndRotateAndScale(minimapArrowTexture, screenWidth/2.0f, screenHeight/2.0f, camera.getYaw(),0.5f); | |
| } else { | |
| // the minimap | |
| // a bit more interesting | |
| // I set the minimap to 200 wide and tall | |
| float vSizeFactor = 200.0f/2048.0f; | |
| float vTexX = 0.5f + (1.0f/2048.0f) * currentCameraPosX; | |
| float vTexY = 0.5f + (1.0f/2048.0f) * currentCameraPosZ; | |
| float vTexZ = vSizeFactor; | |
| minimapTexture.bind(); | |
| GL11.glColor4f(1.0f, 1.0f, 1.0f, 0.7f); | |
| GL11.glPushMatrix(); | |
| GL11.glTranslatef(screenWidth-100, 100, 0.0f); | |
| GL11.glBegin(GL11.GL_TRIANGLE_STRIP); | |
| GL11.glTexCoord2f(vTexX-vTexZ, vTexY-vTexZ); | |
| GL11.glVertex2f(-100, -100); | |
| GL11.glTexCoord2f(vTexX+vTexZ, vTexY-vTexZ); | |
| GL11.glVertex2f(+100, -100); | |
| GL11.glTexCoord2f(vTexX-vTexZ, vTexY+vTexZ); | |
| GL11.glVertex2f(-100, +100); | |
| GL11.glTexCoord2f(vTexX+vTexZ, vTexY+vTexZ); | |
| GL11.glVertex2f(+100, +100); | |
| GL11.glEnd(); | |
| GL11.glPopMatrix(); | |
| GL11.glColor4f(1.0f, 1.0f, 1.0f, 1f); | |
| SpriteTool.drawSpriteAndRotateAndScale(minimapArrowTexture, screenWidth-100, 100, camera.getYaw(),0.5f); | |
| } | |
| } | |
| /*** | |
| * draws a chunk to the (mini) map | |
| * @param x | |
| * @param z | |
| */ | |
| public void drawMapChunkToMap(int x, int z) { | |
| level.loadChunk(x, z); | |
| byte[] chunkData = level.getChunkData(x,z); | |
| Graphics2D g = minimapTexture.getImage().createGraphics(); | |
| for(int zz = 0; zz<16; zz++) { | |
| for(int xx =0; xx<16; xx++) { | |
| int highestY = 0; | |
| // determine the top most visible block | |
| for(int yy =1; yy<128; yy++) { | |
| int blockOffset = yy + (zz * 128) + (xx * 128 * 16); | |
| byte blockData = chunkData[blockOffset]; | |
| if(MineCraftConstants.blockDataToSpriteSheet[blockData] > -1) { | |
| if(yy > highestY) { | |
| highestY = yy; | |
| } | |
| } | |
| } | |
| // draw it if we can do something with it | |
| int blockOffset = highestY + (zz * 128) + (xx * 128 * 16); | |
| byte blockData = chunkData[blockOffset]; | |
| if (blockData > -1) { | |
| Color blockColor = MineCraftConstants.blockColors[blockData]; | |
| if(blockColor != null) { | |
| g.setColor(blockColor); | |
| int px = 1024+(x*16)+xx; | |
| int py = 1024+(z*16)+zz; | |
| g.drawLine(px, py, px, py); // yes, this can be optimized (draw to texture instead of image), but meh... | |
| } | |
| } | |
| } | |
| } | |
| } | |
| /*** | |
| * Draws the minimap arrow image (to the texture) | |
| */ | |
| private void drawMinimapArrowImage() { | |
| Graphics2D g = minimapArrowTexture.getImage().createGraphics(); | |
| //g.clearRect(0, 0, 32, 32); | |
| g.setColor(Color.red); | |
| g.setStroke(new BasicStroke(5)); | |
| g.drawLine(3,16, 30,24); | |
| g.drawLine(30,24,30,8); | |
| g.drawLine(30,8, 3,16); | |
| minimapArrowTexture.update(); | |
| } | |
| /*** | |
| * cleanup | |
| */ | |
| private void cleanup() { | |
| Display.destroy(); | |
| } | |
| } | |
| /* | |
| // top | |
| GL11.glVertex3f(wx, 128, wz); | |
| GL11.glVertex3f(wx+16, 128, wz); | |
| GL11.glVertex3f(wx+16, 128, wz); | |
| GL11.glVertex3f(wx+16, 128, wz+16); | |
| GL11.glVertex3f(wx+16, 128, wz+16); | |
| GL11.glVertex3f(wx+16, 128, wz+16); | |
| GL11.glVertex3f(wx, 128, wz+16); | |
| GL11.glVertex3f(wx, 128, wz+16); | |
| // sides | |
| GL11.glVertex3f(wx, 128, wz); | |
| GL11.glVertex3f(wx, 0, wz); | |
| GL11.glVertex3f(wx+16, 128, wz); | |
| GL11.glVertex3f(wx+16, 0, wz); | |
| GL11.glVertex3f(wx+16, 128, wz+16); | |
| GL11.glVertex3f(wx+16, 0, wz+16); | |
| GL11.glVertex3f(wx, 128, wz+16); | |
| GL11.glVertex3f(wx, 0, wz+16); | |
| // bottom | |
| GL11.glVertex3f(wx, 0, wz); | |
| GL11.glVertex3f(wx+16, 0, wz); | |
| GL11.glVertex3f(wx+16, 0, wz); | |
| GL11.glVertex3f(wx+16, 0, wz+16); | |
| GL11.glVertex3f(wx+16, 0, wz+16); | |
| GL11.glVertex3f(wx+16, 0, wz+16); | |
| GL11.glVertex3f(wx, 0, wz+16); | |
| GL11.glVertex3f(wx, 0, wz+16); | |
| */ |