私の質問はこれです:私はopenGL(LWJGL)でテクスチャとして画像をロードしました.drawメソッドを呼び出すたびに、表示したいタイルセットの位置を選択できます(私の場合は特定のフレームですスプライトのアニメーション)、タイルセット全体を読み取って単一のスプライトのみの小さなタイルセットに分割するのが最善か、それとも画像全体を処理するのと同じかを知りたいです。
実際には、各タイルのテクスチャに画像全体をロードし、描画されるたびに、各タイルはタイルセット全体で GL_QUADS と連携します。
タイルセットには、多数のタイルと多数のアニメーション タイルを含めることができます。
以前は、大きな画像を読み取って tileset オブジェクトに入れてから、各タイルを分離し、画像を切り取り、切り取った部分をタイルに配置して、画像を処理していました。
テクスチャと同じかどうかはわかりません。
その場合、既存の質問のカットである新しいテクスチャの開始を作成する方法は何ですか?
私がやりたいことはこれです:
MAP は TILESET を読み込みます TILESET は IMAGE 全体を読み込みます イメージを多くの小さなイメージ (テクスチャ) に分割します TILE は小さなテクスチャのみを持ち、大きなテクスチャの一部になります。
が描画されるたびに、各タイルは小さいタイルのみを処理します。タイルセット全体を各タイルに渡して、ユーザーに表示する部分だけを伝えても、それは正しいですか、それとも同じですか?
これは私の TileSet クラスです:
package mh.map;
import java.awt.Color;
import java.awt.Image;
import java.awt.Rectangle;
import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import java.util.Vector;
import mh.GameWindow;
import tiled.util.TileCutter;
public class TileSet implements Iterable<Tile> {
private String base;
final private Vector<Tile> tiles = new Vector<Tile>();
private long tilebmpFileLastModified;
private TileCutter tileCutter;
private Rectangle tileDimensions;
private int tileSpacing;
private int tileMargin;
private int tilesPerRow;
private String externalSource;
private File tilebmpFile;
private String name;
private Color transparentColor;
private Image tileSetImage;
private Texture texture;
public TileSet() {
this.tileDimensions = new Rectangle();
}
public void importTileTexture(String ref, int width, int height, int spacing, int margin) {
try {
this.texture = GameWindow.getTextureLoader().getTexture(ref);
int texWidth = this.texture.getImageWidth();
int texHeight = this.texture.getImageHeight();
int tilePerRow = texWidth / width;
int rows = texHeight / height;
for (int i = 0; i < rows; i++) {
for (int j = 0; j < tilePerRow; j++) {
Tile t = new Tile(this, j, i);
this.addNewTile(t);
}
}
} catch (IOException e) {
System.err.println("Unable to load texture: " + ref);
e.printStackTrace();
}
}
public int addTile(Tile t) {
if (t.getId() < 0) {
t.setId(this.tiles.size());
}
if (this.tileDimensions.width < t.getWidth()) {
this.tileDimensions.width = t.getWidth();
}
if (this.tileDimensions.height < t.getHeight()) {
this.tileDimensions.height = t.getHeight();
}
this.tiles.add(t);
t.setTileSet(this);
return t.getId();
}
public void addNewTile(Tile t) {
t.setId(-1);
this.addTile(t);
}
public void removeTile(int i) {
this.tiles.set(i, null);
}
public int size() {
return this.tiles.size();
}
public int getMaxTileId() {
return this.tiles.size() - 1;
}
public Tile getTile(int i) {
try {
return this.tiles.get(i);
} catch (ArrayIndexOutOfBoundsException a) {
}
return null;
}
public Tile getFirstTile() {
Tile ret = null;
int i = 0;
while ((ret == null) && (i <= this.getMaxTileId())) {
ret = this.getTile(i);
i++;
}
return ret;
}
public Texture getTexture() {
return this.texture;
}
}
これはTile.javaです
package mh.map;
import java.io.IOException;
import java.util.Properties;
import mh.GameWindow;
import mh.interfaces.IImage;
import org.lwjgl.opengl.GL11;
public class Tile implements IImage {
/**
* The texture that stores the image for this sprite (not just one frame)
* @deprecated Use instead {@link TileSet#getTexture()}
*/
private Texture texture;
private int id;
private TileSet set;
private Properties prop;
private int offsetX;
private int offsetY;
/**
* Creates a new Tile with a reference to the <code>TileSet</code> and a specified position in that specific set.
*
* @param ts
* The TileSet
* @param texX
* The x position of the tile in the tileset (in tile unit)
* @param texY
* The y position of the tile in the tileset (in tile unit)
*/
public Tile(TileSet ts, int texX, int texY) {
this.set = ts;
this.offsetX = texX;
this.offsetY = texY;
this.texture = ts.getTexture();
}
@Override
public int getWidth() {
return this.texture.getImageWidth();
}
@Override
public int getHeight() {
return this.texture.getImageHeight();
}
public void draw(double x, double y) {
GL11.glPushMatrix();
this.texture.bind();
GL11.glTranslated(x, y, 0);
GL11.glColor3f(1, 1, 1);
GL11.glBegin(GL11.GL_QUADS);
{
// TODO, USE OFFSETS TO DRAW THE CORRECT PIECE OF THE TEXTURE
GL11.glTexCoord2f(0, 0);
GL11.glVertex2f(0, 0);
GL11.glTexCoord2f(0, this.texture.getHeight());
GL11.glVertex2f(0, 32);
GL11.glTexCoord2f(this.texture.getWidth(), this.texture.getHeight());
GL11.glVertex2f(32, 32);
GL11.glTexCoord2f(this.texture.getWidth(), 0);
GL11.glVertex2f(32, 0);
}
GL11.glEnd();
// restore the model view matrix to prevent contamination
GL11.glPopMatrix();
}
public void setId(int i) {
if (i >= 0) {
this.id = i;
}
}
public int getId() {
return this.id;
}
public Properties getProperties() {
return this.prop;
}
public void setProperties(Properties p) {
this.prop = p;
}
public void setTileSet(TileSet ts) {
this.set = ts;
}
}
これがテクスチャローダーです。
package mh.map;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Transparency;
import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.ComponentColorModel;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferByte;
import java.awt.image.Raster;
import java.awt.image.WritableRaster;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.net.URL;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.IntBuffer;
import java.util.HashMap;
import java.util.Hashtable;
import javax.imageio.ImageIO;
import org.lwjgl.opengl.GL11;
/**
* @author Kevin Glass
* @author Brian Matzon
* @author Gianmarco Laggia
*/
public class TextureLoader {
/** The table of textures that have been loaded in this loader */
private final HashMap<String, Texture> table = new HashMap<String, Texture>();
/** The colour model including alpha for the GL image */
private final ColorModel glAlphaColorModel;
/** The colour model for the GL image */
private final ColorModel glColorModel;
/**
* Create a new texture loader based on the game panel
*/
public TextureLoader() {
this.glAlphaColorModel = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), new int[] { 8, 8, 8, 8 }, true, false,
Transparency.TRANSLUCENT, DataBuffer.TYPE_BYTE);
this.glColorModel = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), new int[] { 8, 8, 8, 0 }, false, false, Transparency.OPAQUE,
DataBuffer.TYPE_BYTE);
}
/**
* Create a new texture ID
*
* @return A new texture ID
*/
private int createTextureID() {
IntBuffer tmp = this.createIntBuffer(1);
GL11.glGenTextures(tmp);
return tmp.get(0);
}
/**
* Load a texture
*
* @param resourceName
* The location of the resource to load
* @return The loaded texture
* @throws IOException
* Indicates a failure to access the resource
*/
public Texture getTexture(String resourceName) throws IOException {
Texture tex = this.table.get(resourceName);
if (tex != null) {
return tex;
}
tex = this.getTexture(resourceName, GL11.GL_TEXTURE_2D, // target
GL11.GL_RGBA, // dst pixel format
GL11.GL_LINEAR, // min filter (unused)
GL11.GL_LINEAR);
this.table.put(resourceName, tex);
return tex;
}
/**
* Load a texture into OpenGL from a image reference on disk.
*
* @param resourceName
* The location of the resource to load
* @param target
* The GL target to load the texture against
* @param dstPixelFormat
* The pixel format of the screen
* @param minFilter
* The minimising filter
* @param magFilter
* The magnification filter
* @return The loaded texture
* @throws IOException
* Indicates a failure to access the resource
*/
public Texture getTexture(String resourceName, int target, int dstPixelFormat, int minFilter, int magFilter) throws IOException {
int srcPixelFormat = 0;
// create the texture ID for this texture
int textureID = this.createTextureID();
Texture texture = new Texture(target, textureID);
// bind this texture
GL11.glBindTexture(target, textureID);
BufferedImage bufferedImage = this.loadImage(resourceName);
texture.setWidth(bufferedImage.getWidth());
texture.setHeight(bufferedImage.getHeight());
if (bufferedImage.getColorModel().hasAlpha()) {
srcPixelFormat = GL11.GL_RGBA;
} else {
srcPixelFormat = GL11.GL_RGB;
}
// convert that image into a byte buffer of texture data
ByteBuffer textureBuffer = this.convertImageData(bufferedImage, texture);
if (target == GL11.GL_TEXTURE_2D) {
GL11.glTexParameteri(target, GL11.GL_TEXTURE_MIN_FILTER, minFilter);
GL11.glTexParameteri(target, GL11.GL_TEXTURE_MAG_FILTER, magFilter);
}
// produce a texture from the byte buffer
GL11.glTexImage2D(target, 0, dstPixelFormat, this.get2Fold(bufferedImage.getWidth()), this.get2Fold(bufferedImage.getHeight()), 0, srcPixelFormat,
GL11.GL_UNSIGNED_BYTE, textureBuffer);
return texture;
}
/**
* Get the closest greater power of 2 to the fold number
*
* @param fold
* The target number
* @return The power of 2
*/
private int get2Fold(int fold) {
int ret = 2;
while (ret < fold) {
ret *= 2;
}
return ret;
}
/**
* Convert the buffered image to a texture
*
* @param bufferedImage
* The image to convert to a texture
* @param texture
* The texture to store the data into
* @return A buffer containing the data
*/
private ByteBuffer convertImageData(BufferedImage bufferedImage, Texture texture) {
ByteBuffer imageBuffer = null;
WritableRaster raster;
BufferedImage texImage;
int texWidth = 2;
int texHeight = 2;
// find the closest power of 2 for the width and height
// of the produced texture
while (texWidth < bufferedImage.getWidth()) {
texWidth *= 2;
}
while (texHeight < bufferedImage.getHeight()) {
texHeight *= 2;
}
texture.setTextureHeight(texHeight);
texture.setTextureWidth(texWidth);
// create a raster that can be used by OpenGL as a source
// for a texture
if (bufferedImage.getColorModel().hasAlpha()) {
raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, texWidth, texHeight, 4, null);
texImage = new BufferedImage(this.glAlphaColorModel, raster, false, new Hashtable<String, Texture>());
} else {
raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, texWidth, texHeight, 3, null);
texImage = new BufferedImage(this.glColorModel, raster, false, new Hashtable<String, Texture>());
}
// copy the source image into the produced image
Graphics g = texImage.getGraphics();
g.setColor(new Color(0f, 0f, 0f, 0f));
g.fillRect(0, 0, texWidth, texHeight);
g.drawImage(bufferedImage, 0, 0, null);
// build a byte buffer from the temporary image
// that be used by OpenGL to produce a texture.
byte[] data = ((DataBufferByte) texImage.getRaster().getDataBuffer()).getData();
imageBuffer = ByteBuffer.allocateDirect(data.length);
imageBuffer.order(ByteOrder.nativeOrder());
imageBuffer.put(data, 0, data.length);
imageBuffer.flip();
return imageBuffer;
}
/**
* Load a given resource as a buffered image
*
* @param ref
* The location of the resource to load
* @return The loaded buffered image
* @throws IOException
* Indicates a failure to find a resource
*/
private BufferedImage loadImage(String ref) throws IOException {
URL url = TextureLoader.class.getClassLoader().getResource(ref);
if (url == null) {
url = new URL("file:"+ref);
// throw new IOException("Cannot find: " + ref);
}
System.out.println("URL:" + url);
BufferedImage bufferedImage = ImageIO.read(new BufferedInputStream(url.openStream()));//this.getClass().getClassLoader().getResourceAsStream(ref)));
return bufferedImage;
}
/**
* Creates an integer buffer to hold specified ints - strictly a utility method
*
* @param size
* how many int to contain
* @return created IntBuffer
*/
protected IntBuffer createIntBuffer(int size) {
ByteBuffer temp = ByteBuffer.allocateDirect(4 * size);
temp.order(ByteOrder.nativeOrder());
return temp.asIntBuffer();
}
}