2012-05-29 129 views
13

是否可以加載PNG紋理並在LWJGL中繪製字符串而不使用Slick Framework?LWJGL紋理和字符串

每次我谷歌「如何在LWJGL加載PNG圖像」我得到的答案是這樣 - >「嘿,只是用從光滑的框架textureloader」
同爲「如何繪製字符串LWJGL」 - >「只是使用TTFFont類從光滑的框架」

但我不希望使用此中途-crossframework設計。因爲我不認爲這是最好的方式。

是否有LWJGL的任何庫或擴展只針對紋理或字符串?

回答

22

基本上,你把一個BufferedImage,使用getRBG()獲得每個像素的RGB,採取的數據,並把它變成一個ByteBuffer(用於輸入圖像數據到OpenGL的數據類型),設置一些紋理數據,並創建GL_TEXTURE_2D

此代碼由Krythic做的:

import java.awt.image.BufferedImage; 
import java.io.IOException; 
import java.nio.ByteBuffer; 

import javax.imageio.ImageIO; 

import org.lwjgl.BufferUtils; 
import org.lwjgl.opengl.GL12; 

import static org.lwjgl.opengl.GL11.*; 

public class TextureLoader { 
    private static final int BYTES_PER_PIXEL = 4;//3 for RGB, 4 for RGBA 
     public static int loadTexture(BufferedImage image){ 

      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() * BYTES_PER_PIXEL); //4 for RGBA, 3 for RGB 

      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));  // 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(); //FOR THE LOVE OF GOD DO NOT FORGET THIS 

      // You now have a ByteBuffer filled with the color data of each pixel. 
      // Now just create a texture ID and bind it. Then you can load it using 
      // whatever OpenGL method you want, for example: 

      int textureID = glGenTextures(); //Generate texture ID 
      glBindTexture(GL_TEXTURE_2D, textureID); //Bind texture ID 

      //Setup wrap mode 
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL12.GL_CLAMP_TO_EDGE); 
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL12.GL_CLAMP_TO_EDGE); 

      //Setup texture scaling filtering 
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 

      //Send texel data to OpenGL 
      glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, image.getWidth(), image.getHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer); 

      //Return the texture ID so we can bind it later again 
      return textureID; 
     } 

     public static BufferedImage loadImage(String loc) 
     { 
      try { 
       return ImageIO.read(MainClass.class.getResource(loc)); 
      } catch (IOException e) { 
       //Error Handling Here 
      } 
      return null; 
     } 
} 

若要使用此代碼,做這樣的事情:

BufferedImage image = TextureLoader.loadImage("/res/test.png");//The path is inside the jar file 
int textureID = TextureLoader.loadTexture(image); 

您可以保存textureID爲final變量(如果紋理從來沒有更改)或在每次渲染後卸載紋理使用GL11.glDeleteTextures(textureID);

要做文本,只需創建一個BufferedImage手動,並使用createGraphics()獲取圖像的graphics2D()實例。然後,使用drawString()繪製到BufferedImage,將其加載到TextureLoader中,在屏幕上渲染它,然後使用上述方法卸載紋理。

+4

上面的代碼是我的,我寫它前一段時間。想象一下,我驚喜的發現它隨機堆棧溢出!讓我感到所有溫暖和模糊,知道它一直在互聯網上的方式! = P – Krythic

+0

你的代碼真棒。我每次都使用它。 –

+1

還應該注意的是,我給Dinnerbone這個相同的片段,以幫助他在Minecraft中創建茶色玻璃。 – Krythic

0

LWJGL現在包含STB綁定,這是加載圖像和字體的首選方式,無需使用Slick甚至AWT。

要加載PNG:

import static org.lwjgl.opengl.GL11.GL_REPEAT; 
import static org.lwjgl.opengl.GL11.GL_LINEAR; 
import static org.lwjgl.opengl.GL11.GL_RGBA; 
import static org.lwjgl.opengl.GL11.GL_TEXTURE_2D; 
import static org.lwjgl.opengl.GL11.GL_TEXTURE_MAG_FILTER; 
import static org.lwjgl.opengl.GL11.GL_TEXTURE_MIN_FILTER; 
import static org.lwjgl.opengl.GL11.GL_TEXTURE_WRAP_S; 
import static org.lwjgl.opengl.GL11.GL_TEXTURE_WRAP_T; 
import static org.lwjgl.opengl.GL11.GL_UNPACK_ALIGNMENT; 
import static org.lwjgl.opengl.GL11.GL_UNSIGNED_BYTE; 
import static org.lwjgl.opengl.GL11.glBindTexture; 
import static org.lwjgl.opengl.GL11.glGenTextures; 
import static org.lwjgl.opengl.GL11.glPixelStorei; 
import static org.lwjgl.opengl.GL11.glTexImage2D; 
import static org.lwjgl.opengl.GL11.glTexParameteri; 
import static org.lwjgl.opengl.GL30.glGenerateMipmap; 
import static org.lwjgl.stb.STBImage.stbi_load_from_memory; 
import static org.lwjgl.system.MemoryStack.stackPush; 
import static org.lwjgl.demo.util.IOUtils.ioResourceToByteBuffer; 

import java.nio.ByteBuffer; 
import java.nio.IntBuffer; 

import org.lwjgl.system.MemoryStack; 

public class Texture{ 
    private int width; 
    private int height; 
    private int id; 

    public Texture(String imagePath) { 
     ByteBuffer imageData = ioResourceToByteBuffer(imagePath, 1024); 

     try (MemoryStack stack = stackPush()) { 
      IntBuffer w = stack.mallocInt(1); 
      IntBuffer h = stack.mallocInt(1); 
      IntBuffer components = stack.mallocInt(1); 

      // Decode texture image into a byte buffer 
      ByteBuffer decodedImage = stbi_load_from_memory(imageData, w, h, components, 4); 

      this.width = w.get(); 
      this.height = h.get(); 

      // Create a new OpenGL texture 
      this.id = glGenTextures(); 

      // Bind the texture 
      glBindTexture(GL_TEXTURE_2D, this.id); 

      // Tell OpenGL how to unpack the RGBA bytes. Each component is 1 byte size 
      glPixelStorei(GL_UNPACK_ALIGNMENT, 1); 
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); 
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); 

      // Upload the texture data 
      glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, this.width, this.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, decodedImage); 

      // Generate Mip Map 
      glGenerateMipmap(GL_TEXTURE_2D); 
     } 
    } 
} 

用於圖像加載更完整的示例,並且文本印刷可以在LWJGL源代碼中找到:

org.lwjgl.demo.stb