Java tutorial
/** * Wrath Engine * Copyright (C) 2015 Trent Spears * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package wrath.client; import java.awt.Desktop; import java.awt.image.BufferedImage; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.net.URI; import java.nio.ByteBuffer; import javax.imageio.ImageIO; import javax.swing.JOptionPane; import org.lwjgl.BufferUtils; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL12; import org.lwjgl.util.vector.Matrix4f; import org.lwjgl.util.vector.Vector3f; import wrath.client.enums.PopupMessageType; import wrath.client.enums.RenderMode; import wrath.client.graphics.Camera; import wrath.util.Logger; /** * General static utilities library. * Contains assorted methods for the Client to use. * @author Trent Spears */ public class ClientUtils { /** * Static libraries, no constructor necessary. */ private ClientUtils() { } /** * Creates a Creates a {@link org.lwjgl.util.vector.Matrix4f} representing the depth of the screen. * @param fov The angle of the camera's view. * @return Returns a {@link org.lwjgl.util.vector.Matrix4f} representing the depth of the screen. */ public static Matrix4f createProjectionMatrix(float fov) { if (Game.getCurrentInstance().getRenderMode() == RenderMode.Mode2D) return (Matrix4f) (new Matrix4f().setIdentity()); float aspectRatio = (float) Game.getCurrentInstance().getWindowManager().getWidth() / (float) Game.getCurrentInstance().getWindowManager().getHeight(); float yscale = (float) (1f / Math.tan(Math.toRadians(fov / 2f))) * aspectRatio; float xscale = yscale / aspectRatio; float field_len = Game.RenderManager.FAR_PLANE - Game.RenderManager.NEAR_PLANE; Matrix4f ret = new Matrix4f(); ret.m00 = xscale; ret.m11 = yscale; ret.m22 = -((Game.RenderManager.FAR_PLANE + Game.RenderManager.NEAR_PLANE) / field_len); ret.m23 = -1; ret.m32 = -((2 * Game.RenderManager.FAR_PLANE * Game.RenderManager.NEAR_PLANE) / field_len); ret.m33 = 0f; return ret; } /** * Creates a {@link org.lwjgl.util.vector.Matrix4f} representing the screen position of an object. * This is all done automatically. * @param translation The {@link org.lwjgl.util.vector.Vector3f} representing the movement on the x-y-z plane. * @param rotateX The degrees (in radians) that X should be rotated. * @param rotateY The degrees (in radians) that Y should be rotated. * @param rotateZ The degrees (in radians) that Z should be rotated. * @param scale The scale (multiplier) of the model. * @return Returns a fully-loaded {@link org.lwjgl.util.vector.Matrix4f} object ready to be loaded onto the shader. */ public static Matrix4f createTransformationMatrix(Vector3f translation, float rotateX, float rotateY, float rotateZ, float scale) { Matrix4f ret = new Matrix4f(); ret.setIdentity(); Matrix4f.translate(translation, ret, ret); Matrix4f.rotate((float) Math.toRadians(rotateX), new Vector3f(1, 0, 0), ret, ret); Matrix4f.rotate((float) Math.toRadians(rotateY), new Vector3f(0, 1, 0), ret, ret); Matrix4f.rotate((float) Math.toRadians(rotateZ), new Vector3f(0, 0, 1), ret, ret); Matrix4f.scale(new Vector3f(scale, scale, scale), ret, ret); return ret; } /** * Creates a {@link org.lwjgl.util.vector.Matrix4f} representing the screen position of the Player {@link wrath.client.graphics.Camera}. * @param camera The Player's {@link wrath.client.graphics.Camera}. * @return Returns a fully-loaded {@link org.lwjgl.util.vector.Matrix4f} object ready to be loaded onto the shader. */ public static Matrix4f createViewMatrix(Camera camera) { Matrix4f ret = new Matrix4f(); ret.setIdentity(); Matrix4f.rotate((float) Math.toRadians(camera.getOrientation().x), new Vector3f(1, 0, 0), ret, ret); Matrix4f.rotate((float) Math.toRadians(camera.getOrientation().y), new Vector3f(0, 1, 0), ret, ret); Matrix4f.rotate((float) Math.toRadians(camera.getOrientation().z), new Vector3f(0, 0, 1), ret, ret); Vector3f negCam = new Vector3f(-camera.getPosition().x, -camera.getPosition().y, -camera.getPosition().z); Matrix4f.translate(negCam, ret, ret); return ret; } /** * Displays a pop-up message. * @param popupTitle The title of the pop-up message. * @param message The message displayed on the pop-up. * @param type The type of message to display. Changes the icon. */ public static void displayPopupMessage(String popupTitle, String message, PopupMessageType type) { int opt = JOptionPane.INFORMATION_MESSAGE; if (type == null) opt = JOptionPane.PLAIN_MESSAGE; else if (type == PopupMessageType.ERROR) opt = JOptionPane.ERROR_MESSAGE; else if (type == PopupMessageType.INFO) opt = JOptionPane.INFORMATION_MESSAGE; else if (type == PopupMessageType.PLAIN) opt = JOptionPane.PLAIN_MESSAGE; else if (type == PopupMessageType.QUESTION) opt = JOptionPane.QUESTION_MESSAGE; else if (type == PopupMessageType.WARNING) opt = JOptionPane.WARNING_MESSAGE; JOptionPane.showMessageDialog(null, message, popupTitle, opt); } /** * Converts a ByteBuffer (Used in OpenGL) to a BufferedImage. * @param buffer The ByteBuffer that contains the image data. * @param width The Width (in pixels) of the image. * @param height The Height (in pixels) of the image. * @return Returns the BufferedImage that contains the data from the ByteBuffer. */ public static BufferedImage getByteBufferToImage(ByteBuffer buffer, int width, int height) { BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); for (int x = 0; x < width; x++) for (int y = 0; y < height; y++) { int i = (x + (width * y)) * 4; int r = buffer.get(i) & 0xFF; int g = buffer.get(i + 1) & 0xFF; int b = buffer.get(i + 2) & 0xFF; img.setRGB(x, height - (y + 1), (0xFF << 24) | (r << 16) | (g << 8) | b); } return img; } /** * Loads a ByteBuffer (Used in OpenGL) from most images. * @param image Image to convert. * @return Returns the ByteBuffer converting from the original image. */ public static ByteBuffer getImageToByteBuffer(BufferedImage image) { try { byte[] imageBuffer = new byte[image.getWidth() * image.getHeight() * 4]; int counter = 0; for (int i = 0; i < image.getWidth(); i++) { for (int j = 0; j < image.getHeight(); j++) { int colorSpace = image.getRGB(j, i); imageBuffer[counter + 0] = (byte) ((colorSpace << 8) >> 24); imageBuffer[counter + 1] = (byte) ((colorSpace << 16) >> 24); imageBuffer[counter + 2] = (byte) ((colorSpace << 24) >> 24); imageBuffer[counter + 3] = (byte) (colorSpace >> 24); counter += 4; } } return ByteBuffer.wrap(imageBuffer); } catch (NullPointerException e) { System.err.println("Could not convert Image to ByteBuffer! Operations Error has occured!"); } return ByteBuffer.allocate(0); } /** * Converts a primitive Java boolean to the LWJGL version of the boolean. * Mostly a convenience method. * @param bool The primitive Java boolean value. * @return Returns the LWJGL version of the boolean. */ public static int getOpenGLBoolean(boolean bool) { if (bool) return GL11.GL_TRUE; else return GL11.GL_FALSE; } /** * Loads a LWJGL Texture from an image. * @param image The {@link java.awt.image.BufferedImage} version of the Texture. * @return Returns the LWJGL texture id. */ public static int getTexture(BufferedImage image) { if (image == null) return 0; int[] pixels = new int[image.getWidth() * image.getHeight()]; image.getRGB(0, 0, image.getWidth(), image.getHeight(), pixels, 0, image.getWidth()); ByteBuffer buffer = BufferUtils.createByteBuffer(image.getWidth() * image.getHeight() * 4); for (int y = 0; y < image.getHeight(); y++) { for (int x = 0; x < image.getWidth(); x++) { int pixel = pixels[y * image.getWidth() + x]; buffer.put((byte) ((pixel >> 16) & 0xFF)); buffer.put((byte) ((pixel >> 8) & 0xFF)); buffer.put((byte) (pixel & 0xFF)); buffer.put((byte) ((pixel >> 24) & 0xFF)); } } buffer.flip(); int id = GL11.glGenTextures(); GL11.glEnable(GL11.GL_TEXTURE_2D); GL11.glBindTexture(GL11.GL_TEXTURE_2D, id); GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL12.GL_CLAMP_TO_EDGE); GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL12.GL_CLAMP_TO_EDGE); GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA, image.getWidth(), image.getHeight(), 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, buffer); GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0); return id; } /** * Loads a {@link java.awt.image.BufferedImage} from a {@link java.io.File}. * @param file The {@link java.io.File} to load the {@link java.awt.image.BufferedImage} from. * @return Returns the {@link java.awt.image.BufferedImage} located in the {@link java.io.File}. */ public static BufferedImage loadImageFromFile(File file) { if (file == null) return null; BufferedImage ret = null; try { ret = ImageIO.read(file); } catch (IOException e) { System.err.println("Could not load image from file! I/O Error!"); } return ret; } /** * Reads the specified shader file and retrieves it's source in {@link java.lang.String} format. * It is recommended that shaders be stored in the 'assets/shaders' directory (which is not present by default). * @param shaderFile The {@link java.io.File} to read the shader from. * @return Returns the String source of the shader. */ public static String loadShaderSource(File shaderFile) { if (!shaderFile.exists()) { System.err.println( "Could not load shader from file '" + shaderFile.getAbsolutePath() + "'! File not found!"); return null; } String src = ""; try { String inp; try (BufferedReader read = new BufferedReader(new FileReader(shaderFile))) { while ((inp = read.readLine()) != null) src = src + inp + '\n'; } } catch (IOException e) { System.err .println("Could not load shader from file '" + shaderFile.getAbsolutePath() + "'! I/O Error!"); return null; } return src; } /** * Opens the URL in the System's default web browser. * @param url The URL in the form of a String. */ public static void openUrlInBrowser(String url) { if (Desktop.isDesktopSupported()) { if (Desktop.getDesktop().isSupported(Desktop.Action.BROWSE)) { try { Desktop.getDesktop().browse(URI.create(url)); } catch (IOException e) { System.err.println("Could not open URL '" + url + "' in browser! URL may not be valid!"); } } else { System.err.println("Could not open URL '" + url + "' in browser! Action not supported!"); } } } /** * Displays an error message in modal form, and closes the program if fatal. * @param message The message to display to the user. * @param fatal Determines whether or not the error is fatal, if fatal the program will close. */ public static void throwInternalError(String message, boolean fatal) { JOptionPane.showMessageDialog(null, message, "!! INTERNAL ERROR !!", JOptionPane.ERROR_MESSAGE); if (fatal) System.exit(0); } }