Java tutorial
/* * Copyright 2016 Clment "w67clement" Wagner * * This file is part of OpenW67Render. * * OpenW67Render is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * OpenW67Render 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with OpenW67Render. If not, see <http://www.gnu.org/licenses/>. */ package com.w67clement.openw67render.utils; import com.w67clement.openw67render.registry.TextureRegistry; import java.awt.image.BufferedImage; import java.nio.ByteBuffer; import java.nio.IntBuffer; import org.lwjgl.BufferUtils; import org.lwjgl.opengl.GL13; import static org.lwjgl.opengl.GL11.*; import static org.lwjgl.stb.STBImage.*; /** * <h1>Texture</h1> * <p> * Representation of a texture. * </p> */ public class Texture { /** * Width of the texture. */ protected final int width; /** * Height of the texture. */ protected final int height; protected final ByteBuffer data; private final TextureWrapMode textureWrapMode; private final TextureFilterMode textureFilterMode; /** * Stores the handle of the texture. */ protected int id; /** * Creates a texture with specified width, height, data and modes. * * @param width Width of the texture * @param height Height of the texture * @param data Picture Data in RGBA format */ public Texture(int width, int height, ByteBuffer data, TextureWrapMode textureWrapMode, TextureFilterMode textureFilterMode) { this.width = width; this.height = height; this.data = data; this.textureWrapMode = textureWrapMode; this.textureFilterMode = textureFilterMode; init(); } /** * Loads texture from AWT image. * * @param image AWT image to load. * * @return Texture from specified AWT image. */ public static Texture loadTexture(ByteBuffer image, int width, int height) { return loadTexture(image, width, height, TextureWrapMode.CLAMP_TO_EDGE, TextureFilterMode.NEAREST); } /** * Loads texture from AWT image. * * @param image AWT image to load. * @param textureWrapMode Wrap mode of the texture. * @param textureFilterMode Filter mode of texture. * * @return Texture from specified AWT image. */ public static Texture loadTexture(ByteBuffer image, int width, int height, TextureWrapMode textureWrapMode, TextureFilterMode textureFilterMode) { Texture texture = new Texture(width, height, image, textureWrapMode, textureFilterMode); TextureRegistry.getInstance().add(texture); return texture; } /** * Loads texture from file. * * @param path File path of the texture. * * @return Texture from specified file */ public static Texture loadTexture(String path) { return loadTexture(path, TextureWrapMode.CLAMP_TO_EDGE, TextureFilterMode.NEAREST); } /** * Loads texture from file. * * @param path File path of the texture. * @param textureWrapMode Wrap mode of the texture. * * @return Texture from specified file */ public static Texture loadTexture(String path, TextureWrapMode textureWrapMode) { return loadTexture(path, textureWrapMode, TextureFilterMode.NEAREST); } /** * Loads texture from file. * * @param path File path of the texture. * @param textureWrapMode Wrap mode of the texture. * @param textureFilterMode Filter mode of texture. * * @return Texture from specified file */ public static Texture loadTexture(String path, TextureWrapMode textureWrapMode, TextureFilterMode textureFilterMode) { /* Prepare image buffers */ IntBuffer w = BufferUtils.createIntBuffer(1); IntBuffer h = BufferUtils.createIntBuffer(1); IntBuffer comp = BufferUtils.createIntBuffer(1); /* Load image */ stbi_set_flip_vertically_on_load(1); ByteBuffer image = stbi_load(path, w, h, comp, 4); if (image == null) { throw new RuntimeException( "Failed to load a texture file!" + System.lineSeparator() + stbi_failure_reason()); } /* Get width and height of image */ int width = w.get(); int height = h.get(); // Original: //return new Texture(width, height, image); // Modified: Texture texture = new Texture(width, height, image, textureWrapMode, textureFilterMode); TextureRegistry.getInstance().add(texture); return texture; } /** * Loads texture from AWT image. * * @param image AWT image to load. * * @return Texture from specified AWT image. */ public static Texture loadTexture(BufferedImage image) { return loadTexture(image, TextureWrapMode.CLAMP_TO_EDGE, TextureFilterMode.NEAREST); } /** * Loads texture from AWT image. * * @param image AWT image to load. * @param textureWrapMode Wrap mode of the texture. * @param textureFilterMode Filter mode of texture. * * @return Texture from specified AWT image. */ public static Texture loadTexture(BufferedImage image, TextureWrapMode textureWrapMode, TextureFilterMode textureFilterMode) { 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); //4 for RGBA, 3 for RGB for (int y = image.getHeight() - 1; y > 0; y--) { for (int x = 0; x < image.getWidth(); x++) { int pixel = pixels[y * image.getWidth() + x]; buffer.put((byte) ((pixel >> 16) & 0xFF)); // Red component buffer.put((byte) ((pixel >> 8) & 0xFF)); // Green component buffer.put((byte) (pixel & 0xFF)); // Blue component buffer.put((byte) ((pixel >> 24) & 0xFF)); // Alpha component. Only for RGBA } } buffer.flip(); return loadTexture(buffer, image.getWidth(), image.getHeight(), textureWrapMode, textureFilterMode); } protected void init() { id = glGenTextures(); glBindTexture(GL_TEXTURE_2D, id); if (textureWrapMode != null) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, textureWrapMode.getPointer()); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, textureWrapMode.getPointer()); } if (textureFilterMode != null) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, textureFilterMode.getPointer()); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, textureFilterMode.getPointer()); } glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); } /** * Binds the texture. */ public void bind() { GL13.glActiveTexture(id); glBindTexture(GL_TEXTURE_2D, id); } public void unbind() { glBindTexture(GL_TEXTURE_2D, 0); } /** * Deletes the texture. */ public void delete() { glDeleteTextures(id); } /** * Gets the texture width. * * @return Texture width */ public int getWidth() { return width; } /** * Gets the texture height. * * @return Texture height */ public int getHeight() { return height; } /** * Gets the texture id. * * @return Texture id. */ public final int getId() { return id; } /** * Gets the texture wrap mode. * * @return Texture wrap mode. */ public TextureWrapMode getTextureWrapMode() { return textureWrapMode; } /** * Gets the texture filter mode. * * @return Texture filter mode. */ public TextureFilterMode getTextureFilterMode() { return textureFilterMode; } /** * Reloads the texture. */ public void reload() { delete(); init(); } @Override public String toString() { return "Texture{" + "width=" + width + ", height=" + height + ", textureWrapMode=" + textureWrapMode + ", textureFilterMode=" + textureFilterMode + ", id=" + id + '}'; } public enum TextureWrapMode { CLAMP(0x2900), CLAMP_TO_EDGE(0x812D), REPEAT(GL_REPEAT); private int pointer; TextureWrapMode(int pointer) { this.pointer = pointer; } /** * Gets the pointer of the Texture Wrap Mode. * * @return Texture wrap mode's pointer. */ public int getPointer() { return pointer; } } public enum TextureFilterMode { LINEAR(GL_LINEAR), NEAREST(GL_NEAREST); private int pointer; TextureFilterMode(int pointer) { this.pointer = pointer; } /** * Gets the pointer of the Texture Wrap Mode. * * @return Texture wrap mode's pointer. */ public int getPointer() { return pointer; } } }