Lwjgl render only one texture - java

I'm tryng to create a Minecraft clone, but my code render only one texture, i'm a opengl beginner, some help please?
(I'm italian so excuse me for my bad english)
Here my Texture class
private String location;
private int id;
private boolean loaded = false;
public Texture(String location) {
this.location = location;
}
public void loadTexture() {
if (!this.loaded) {
this.loaded = true;
try {
InputStream stream = new FileInputStream("Textures/" + this.location);
PNGDecoder decoder = new PNGDecoder(stream);
ByteBuffer buffer = ByteBuffer.allocateDirect(4 * decoder.getWidth() * decoder.getHeight());
decoder.decode(buffer, decoder.getWidth() * 4);
buffer.flip();
this.id = GL11.glGenTextures();
GL11.glBindTexture(GL11.GL_TEXTURE_2D, this.id);
GL11.glPixelStorei(GL11.GL_UNPACK_ALIGNMENT, 1);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST);
GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA, decoder.getWidth(), decoder.getHeight(), 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, buffer);
GL30.glGenerateMipmap(GL11.GL_TEXTURE_2D);
} catch (Exception e) {
e.printStackTrace();
}
}
}
public int getId() {
return this.id;
}
my chunk data class that renderize
public class ChunkData {
private final Vector3i chunkPos;
private final Block[][][] blocks;
public ChunkData(Vector3i pos) {
this.chunkPos = new Vector3i(pos);
this.blocks = new Block[16][16][16];
}
public static boolean inChunk(int x, int y, int z) {
return x >= 0 && y >= 0 && z >= 0 && x < 16 && y < 16 && z < 16;
}
public void setBlockAt(int x, int y, int z, Block block) {
if (inChunk(x, y, z)) {
this.blocks[x][y][z] = block;
}
}
public Block getBlockAt(int x, int y, int z) {
if (inChunk(x, y, z)) {
return this.blocks[x][y][z];
}
return null;
}
public Vector3i getChunkPos() {
return this.chunkPos;
}
public void render() {
blocks[1][1][2].getTexture().loadTexture();
blocks[2][2][1].getTexture().loadTexture();
}
}
there are 2 blocks, one contains this texture
#Override
public Texture getTexture() {
return new Texture("Dirt.png");
}
and another is this
#Override
public Texture getTexture() {
return new Texture("Stone.png");
}
the blocks[1][1][2] contains a Stone texture and the [2][2][2] a Dirt texture but when i run the program it displays both as a stone texture.

Related

LWJGL2, OpenGL framebuffer only rendering a partial flat-shaded section of the scene

I am trying to simply render the scene to a framebuffer object and then back to the screen. The issue is that the framebuffer ends up rendering out what looks to be the lower left quadrant of the scene with only flat shading. When I render normally without the FBO all the shading is normal and the whole scene is rendered. I don't understand why this isn't what the FBO gets.
I am rendering to a quad that fits the screen and glViewport is always set to the display width.
Something to note is that it looks suspiciously like it's rendering from the position of the first entity.
No FBO:
With FBO:
FBO class:
public class FrameBufferObject
{
private int frameBuffer;
private int colourBuffer;
private int depthBuffer;
private int colourTexture;
private int depthTexture;
private int colourWidth;
private int colourHeight;
private int depthWidth;
private int depthHeight;
private int depthType;
public static final int NONE = 0;
public static final int DEPTH_TEXTURE = 1;
public static final int DEPTH_RENDER_BUFFER = 2;
public FrameBufferObject(int textureWidth, int textureHeight, int depthWidth, int depthHeight, int depthBufferType)
{
this.colourWidth = textureWidth;
this.colourHeight = textureHeight;
this.depthWidth = depthWidth;
this.depthHeight = depthHeight;
this.depthType = depthBufferType;
initialiseFrameBuffer(depthBufferType);
}
public FrameBufferObject(int width, int height, int depthBufferType)
{
this.colourWidth = width;
this.colourHeight = height;
this.depthWidth = width;
this.depthHeight = height;
this.depthType = depthBufferType;
initialiseFrameBuffer(depthBufferType);
}
private void initialiseFrameBuffer(int type)
{
frameBuffer = glGenFramebuffers();
glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
glDrawBuffer(GL_COLOR_ATTACHMENT0);
colourTexture = glGenTextures();
glBindTexture(GL_TEXTURE_2D, colourTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, colourWidth, colourHeight,
0, GL_RGB, GL_UNSIGNED_BYTE, (ByteBuffer) null);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
colourTexture, 0);
if (type == DEPTH_RENDER_BUFFER) {
depthBuffer = glGenRenderbuffers();
glBindRenderbuffer(GL_RENDERBUFFER, depthBuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, depthWidth, depthHeight);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthBuffer);
}
else if (type == DEPTH_TEXTURE)
{
depthTexture = glGenTextures();
glBindTexture(GL_TEXTURE_2D, depthTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32, depthWidth, depthHeight,
0, GL_DEPTH_COMPONENT, GL_FLOAT, (ByteBuffer) null);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
depthTexture, 0);
}
unbindFrameBuffer();
}
public void bindFrameBuffer()
{
glBindTexture(GL_TEXTURE_2D, 0);
glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
glViewport(0, 0, colourWidth, colourHeight);
}
public void unbindFrameBuffer()
{
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glViewport(0, 0, Display.getWidth(), Display.getHeight());
}
public void cleanUp()
{
glDeleteFramebuffers(frameBuffer);
glDeleteTextures(colourTexture);
glDeleteTextures(depthTexture);
glDeleteRenderbuffers(depthBuffer);
glDeleteRenderbuffers(colourBuffer);
}
public int getColourTexture() {
return colourTexture;
}
public int getDepthBuffer() {
return depthBuffer;
}
}
Renderer:
public EntityRenderer(StaticShader staticShader)
{
this.staticShader = staticShader;
glEnable(GL_CULL_FACE);
glEnable(GL_BACK);
projectionMatrix = MatrixUtils.projectionMatrix();
this.staticShader.start();
this.staticShader.loadProjectionMatrix(projectionMatrix);
this.staticShader.stop();
}
public void prepare() {
glEnable(GL_DEPTH_TEST);
glClearColor(1, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
}
private void prepareRenderInstance(Transform transform) {
Matrix4f matrix = MatrixUtils.transformationMatrix(transform);
staticShader.loadTransformationMatrix(matrix);
}
private void unbindMesh() {
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glDisableVertexAttribArray(2);
glBindVertexArray(0);
}
private Map<StaticMesh, List<RawModel>> getMeshes()
{
return null;
}
#Override
public void render()
{
Collection<Entity> entities = World.getEntities().values();
for (Entity entity : entities)
{
StaticMesh mesh =
(entity.getComponent(StaticMeshComponent.class)).getMesh();
prepareMesh(mesh);
prepareRenderInstance(entity.getTransform());
glDrawElements(GL_TRIANGLES, mesh.getModel().getVertexCount(),
GL_UNSIGNED_INT, 0);
unbindMesh();
}
private void prepareMesh(StaticMesh mesh)
{
RawModel rawModel = mesh.getModel();
Material material = mesh.getMaterials().get(0);
glBindVertexArray(rawModel.getVaoID());
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
staticShader.loadSpecular(10f, 1f);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, material.getTexture().getId());
glDrawElements(GL_TRIANGLES, rawModel.getVertexCount(), GL_UNSIGNED_INT, 0);
}
#Override
public void cleanUp()
{
staticShader.cleanUp();
}
}
Main render method where I bind the framebuffer:
public void render()
{
gameBuffer.bindFrameBuffer();
List<Light> lights = World.getLights();
entityRenderer.prepare();
staticShader.start();
staticShader.loadViewMatrix(camera);
staticShader.loadLights(lights);
entityRenderer.render();
staticShader.stop();
gameBuffer.unbindFrameBuffer();
WidgetManager.swap(gameBuffer.getColourTexture());
widgetRenderer.render();
}
Shader program base class:
public abstract class GenericShader
{
private static int programID;
private static int vertexShaderID;
private static int fragmentShaderID;
private static FloatBuffer matrixBuffer = BufferUtils.createFloatBuffer(16);
public GenericShader(String vertexFile, String fragmentFile)
{
this.vertexShaderID = loadShader(vertexFile, 35633);
this.fragmentShaderID = loadShader(fragmentFile, 35632);
this.programID = glCreateProgram();
glAttachShader(programID, vertexShaderID);
glAttachShader(programID, fragmentShaderID);
bindAttributes();
glLinkProgram(programID);
glValidateProgram(programID);
getAllUniformLocations();
}
public void start() {
glUseProgram(programID);
}
public void stop() {
glUseProgram(0);
}
public void cleanUp() {
stop();
glDetachShader(programID, vertexShaderID);
glDetachShader(programID, fragmentShaderID);
glDeleteShader(vertexShaderID);
glDeleteShader(fragmentShaderID);
glDeleteProgram(programID);
}
protected abstract void getAllUniformLocations();
protected int getUniformLocation(String uniformName) {
return glGetUniformLocation(programID, uniformName);
}
protected void loadBoolean(int location, boolean value) {
glUniform1f(location, value ? 1 : 0);
}
protected void loadFloat(int location, float value) {
glUniform1f(location, value);
}
protected void loadVector3D(int location, Vector3f vec) {
glUniform3f(location, vec.x, vec.y, vec.z);
}
protected void loadMatrix(int location, Matrix4f matrix)
{
matrix.store(matrixBuffer);
matrixBuffer.flip();
glUniformMatrix4(location, false, matrixBuffer);
}
protected abstract void bindAttributes();
protected void bindAttribute(int attribute, String variableName) {
glBindAttribLocation(programID, attribute, variableName);
}
private static int loadShader(String file, int type) {
StringBuilder shaderSource = new StringBuilder();
try {
BufferedReader reader = new BufferedReader(new FileReader(file));
String line;
while((line = reader.readLine()) != null) {
shaderSource.append(line).append("\n");
}
reader.close();
} catch (IOException var5) {
var5.printStackTrace();
System.out.println("Could not read shader.");
System.exit(-1);
}
int shaderID = glCreateShader(type);
glShaderSource(shaderID, shaderSource);
glCompileShader(shaderID);
if (glGetShaderi(shaderID, 35713) == 0) {
System.out.println(glGetShaderInfoLog(shaderID, 500));
System.err.println("Could not compile shader!");
System.exit(-1);
}
return shaderID;
}
}
Static shader:
public StaticShader()
{
super(VERTEX_FILE, FRAGMENT_FILE);
}
#Override
protected void bindAttributes()
{
super.bindAttribute(0, "position");
super.bindAttribute(1, "textureCoordinates");
super.bindAttribute(2, "normals");
}
#Override
protected void getAllUniformLocations()
{
location_transformationMatrix = super.getUniformLocation("transformationMatrix");
location_projectionMatrix = super.getUniformLocation("projectionMatrix");
location_viewMatrix = super.getUniformLocation("viewMatrix");
location_shineDamper = super.getUniformLocation("shineDamper");
location_reflectivity = super.getUniformLocation("reflectivity");
location_useFakeLighting = super.getUniformLocation("useFakeLighting");
location_skyColour = super.getUniformLocation("skyColour");
location_density = super.getUniformLocation("density");
location_gradient = super.getUniformLocation("gradient");
location_atlasRows = super.getUniformLocation("atlasRows");
location_offset = super.getUniformLocation("offset");
//location_lightPositions = new int[MAX_LIGHTS];
//location_lightColours = new int[MAX_LIGHTS];
//location_attenuations = new int[MAX_LIGHTS];
//for (int i = 0; i < MAX_LIGHTS; i++)
//{
location_lightPosition = super.getUniformLocation("lightPosition");//s[" + i + "]");
location_lightColour = super.getUniformLocation("lightColour");//s[" + i + "]");
//location_attenuation = super.getUniformLocation("attenuations[" + i + "]");
//}
}
public void loadLights(List<Light> lights)
{
super.loadVector3D(location_lightPosition, lights.get(0).getTransform().position);
super.loadVector3D(location_lightColour, lights.get(0).getColour());
}
public void loadSpecular(float shineDamper, float reflectivity) {
super.loadFloat(location_shineDamper, shineDamper);
super.loadFloat(location_reflectivity, reflectivity);
}
public void loadTransformationMatrix(Matrix4f matrix)
{
super.loadMatrix(location_transformationMatrix, matrix);
}
public void loadProjectionMatrix(Matrix4f matrix)
{
super.loadMatrix(location_projectionMatrix, matrix);
}
public void loadViewMatrix(Camera camera)
{
Matrix4f viewMatrix = MatrixUtils.createViewMatrix(camera);
super.loadMatrix(location_viewMatrix, viewMatrix);
}

LWJGL Cannot create uniform even though I could create other uniforms

I've been following a tutorial by LWJGLGameDev on LWJGL found at https://lwjglgamedev.gitbooks.io/3d-game-development-with-lwjgl/content/. I'm using its source code and have my project set up the same way as theirs. Everything seemed fine until I tried to run the code from the tutorial in chapter 8 when the Renderer tries to create the modelViewMatrix uniform and it throws an exception that it could not find the uniform modelViewMatrix. I'm a newbie at LWJGL and openGL so I don't fully understand what is happening. Thank you in advance. Here is the relevant code:
public class Renderer {
/**
* Field of View in Radians
*/
private static final float FOV = (float) Math.toRadians(60.0f);
private static final float Z_NEAR = 0.01f;
private static final float Z_FAR = 1000.f;
private final Transformation transformation;
private ShaderProgram shaderProgram;
public Renderer() {
transformation = new Transformation();
}
public void init(Window window) throws Exception {
// Create shader
shaderProgram = new ShaderProgram();
shaderProgram.createVertexShader(Utils.loadResource("/shaders/vertex.vs"));
shaderProgram.createFragmentShader(Utils.loadResource("/shaders/fragment.fs"));
shaderProgram.link();
// Create uniforms for modelView and projection matrices and texture
shaderProgram.createUniform("projectionMatrix");
shaderProgram.createUniform("texture_sampler");
shaderProgram.createUniform("modelViewMatrix");
}
public void clear() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
public void render(Window window, Camera camera, GameItem[] gameItems) {
clear();
if ( window.isResized() ) {
glViewport(0, 0, window.getWidth(), window.getHeight());
window.setResized(false);
}
shaderProgram.bind();
// Update projection Matrix
Matrix4f projectionMatrix = transformation.getProjectionMatrix(FOV, window.getWidth(), window.getHeight(), Z_NEAR, Z_FAR);
shaderProgram.setUniform("projectionMatrix", projectionMatrix);
// Update view Matrix
Matrix4f viewMatrix = transformation.getViewMatrix(camera);
shaderProgram.setUniform("texture_sampler", 0);
// Render each gameItem
for(GameItem gameItem : gameItems) {
// Set model view matrix for this item
Matrix4f modelViewMatrix = transformation.getModelViewMatrix(gameItem, viewMatrix);
shaderProgram.setUniform("modelViewMatrix", modelViewMatrix);
// Render the mes for this game item
gameItem.getMesh().render();
}
shaderProgram.unbind();
}
public void cleanup() {
if (shaderProgram != null) {
shaderProgram.cleanup();
}
}
}
ShaderProgram:
public class ShaderProgram {
private final int programId;
private int vertexShaderId;
private int fragmentShaderId;
private final Map<String, Integer> uniforms;
public ShaderProgram() throws Exception {
programId = glCreateProgram();
if (programId == 0) {
throw new Exception("Could not create Shader");
}
uniforms = new HashMap<>();
}
public void createUniform(String uniformName) throws Exception {
int uniformLocation = glGetUniformLocation(programId, uniformName);
if (uniformLocation < 0) {
throw new Exception("Could not find uniform:" + uniformName);
}
uniforms.put(uniformName, uniformLocation);
}
public void setUniform(String uniformName, Matrix4f value) {
try (MemoryStack stack = MemoryStack.stackPush()) {
// Dump the matrix into a float buffer
FloatBuffer fb = stack.mallocFloat(16);
value.get(fb);
glUniformMatrix4fv(uniforms.get(uniformName), false, fb);
}
}
public void setUniform(String uniformName, int value) {
glUniform1i(uniforms.get(uniformName), value);
}
public void createVertexShader(String shaderCode) throws Exception {
vertexShaderId = createShader(shaderCode, GL_VERTEX_SHADER);
}
public void createFragmentShader(String shaderCode) throws Exception {
fragmentShaderId = createShader(shaderCode, GL_FRAGMENT_SHADER);
}
protected int createShader(String shaderCode, int shaderType) throws Exception {
int shaderId = glCreateShader(shaderType);
if (shaderId == 0) {
throw new Exception("Error creating shader. Type: " + shaderType);
}
glShaderSource(shaderId, shaderCode);
glCompileShader(shaderId);
if (glGetShaderi(shaderId, GL_COMPILE_STATUS) == 0) {
throw new Exception("Error compiling Shader code: " + glGetShaderInfoLog(shaderId, 1024));
}
glAttachShader(programId, shaderId);
return shaderId;
}
public void link() throws Exception {
glLinkProgram(programId);
if (glGetProgrami(programId, GL_LINK_STATUS) == 0) {
throw new Exception("Error linking Shader code: " + glGetProgramInfoLog(programId, 1024));
}
if (vertexShaderId != 0) {
glDetachShader(programId, vertexShaderId);
}
if (fragmentShaderId != 0) {
glDetachShader(programId, fragmentShaderId);
}
glValidateProgram(programId);
if (glGetProgrami(programId, GL_VALIDATE_STATUS) == 0) {
System.err.println("Warning validating Shader code: " + glGetProgramInfoLog(programId, 1024));
}
}
public void bind() {
glUseProgram(programId);
}
public void unbind() {
glUseProgram(0);
}
public void cleanup() {
unbind();
if (programId != 0) {
glDeleteProgram(programId);
}
}
}
Transformation:
public class Transformation {
private final Matrix4f projectionMatrix;
private final Matrix4f modelViewMatrix;
private final Matrix4f viewMatrix;
public Transformation() {
projectionMatrix = new Matrix4f();
modelViewMatrix = new Matrix4f();
viewMatrix = new Matrix4f();
}
public final Matrix4f getProjectionMatrix(float fov, float width, float height, float zNear, float zFar) {
float aspectRatio = width / height;
projectionMatrix.identity();
projectionMatrix.perspective(fov, aspectRatio, zNear, zFar);
return projectionMatrix;
}
public Matrix4f getViewMatrix(Camera camera) {
Vector3f cameraPos = camera.getPosition();
Vector3f rotation = camera.getRotation();
viewMatrix.identity();
// First do the rotation so camera rotates over its position
viewMatrix.rotate((float)Math.toRadians(rotation.x), new Vector3f(1, 0, 0))
.rotate((float)Math.toRadians(rotation.y), new Vector3f(0, 1, 0));
// Then do the translation
viewMatrix.translate(-cameraPos.x, -cameraPos.y, -cameraPos.z);
return viewMatrix;
}
public Matrix4f getModelViewMatrix(GameItem gameItem, Matrix4f viewMatrix) {
Vector3f rotation = gameItem.getRotation();
modelViewMatrix.identity().translate(gameItem.getPosition()).
rotateX((float)Math.toRadians(-rotation.x)).
rotateY((float)Math.toRadians(-rotation.y)).
rotateZ((float)Math.toRadians(-rotation.z)).
scale(gameItem.getScale());
Matrix4f viewCurr = new Matrix4f(viewMatrix);
return viewCurr.mul(modelViewMatrix);
}
}
Utils:
public class Utils {
public static String loadResource(String fileName) throws Exception {
String result;
try (InputStream in = Utils.class.getClass().getResourceAsStream(fileName);
Scanner scanner = new Scanner(in, "UTF-8")) {
result = scanner.useDelimiter("\\A").next();
}
return result;
}
}
GameItem:
public class GameItem
{
private final Mesh mesh;
private final Vector3f position;
private float scale;
private final Vector3f rotation;
public GameItem(Mesh mesh)
{
this.mesh=mesh;
position=new Vector3f(0,0,0);
scale=1;
rotation=new Vector3f(0,0,0);
}
public Vector3f getPosition()
{
return position;
}
public void setPosition(float x, float y, float z)
{
this.position.x=x;
this.position.y=y;
this.position.z=z;
}
public float getScale()
{
return scale;
}
public void setScale(float scale)
{
this.scale=scale;
}
public Vector3f getRotation()
{
return rotation;
}
public void setRotation(float x, float y, float z) {
this.rotation.x = x;
this.rotation.y = y;
this.rotation.z = z;
}
public Mesh getMesh() {
return mesh;
}
}
Mesh:
public class Mesh {
private final int vaoId;
private final List<Integer> vboIdList;
private final int vertexCount;
private final Texture texture;
public Mesh(float[] positions, float[] textCoords, int[] indices, Texture texture) {
FloatBuffer posBuffer = null;
FloatBuffer textCoordsBuffer = null;
IntBuffer indicesBuffer = null;
try {
this.texture = texture;
vertexCount = indices.length;
vboIdList = new ArrayList();
vaoId = glGenVertexArrays();
glBindVertexArray(vaoId);
// Position VBO
int vboId = glGenBuffers();
vboIdList.add(vboId);
posBuffer = MemoryUtil.memAllocFloat(positions.length);
posBuffer.put(positions).flip();
glBindBuffer(GL_ARRAY_BUFFER, vboId);
glBufferData(GL_ARRAY_BUFFER, posBuffer, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);
// Texture coordinates VBO
vboId = glGenBuffers();
vboIdList.add(vboId);
textCoordsBuffer = MemoryUtil.memAllocFloat(textCoords.length);
textCoordsBuffer.put(textCoords).flip();
glBindBuffer(GL_ARRAY_BUFFER, vboId);
glBufferData(GL_ARRAY_BUFFER, textCoordsBuffer, GL_STATIC_DRAW);
glVertexAttribPointer(1, 2, GL_FLOAT, false, 0, 0);
// Index VBO
vboId = glGenBuffers();
vboIdList.add(vboId);
indicesBuffer = MemoryUtil.memAllocInt(indices.length);
indicesBuffer.put(indices).flip();
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboId);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indicesBuffer, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
} finally {
if (posBuffer != null) {
MemoryUtil.memFree(posBuffer);
}
if (textCoordsBuffer != null) {
MemoryUtil.memFree(textCoordsBuffer);
}
if (indicesBuffer != null) {
MemoryUtil.memFree(indicesBuffer);
}
}
}
public int getVaoId() {
return vaoId;
}
public int getVertexCount() {
return vertexCount;
}
public void render() {
// Activate firs texture bank
glActiveTexture(GL_TEXTURE0);
// Bind the texture
glBindTexture(GL_TEXTURE_2D, texture.getId());
// Draw the mesh
glBindVertexArray(getVaoId());
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glDrawElements(GL_TRIANGLES, getVertexCount(), GL_UNSIGNED_INT, 0);
// Restore state
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glBindVertexArray(0);
}
public void cleanUp() {
glDisableVertexAttribArray(0);
// Delete the VBOs
glBindBuffer(GL_ARRAY_BUFFER, 0);
for (int vboId : vboIdList) {
glDeleteBuffers(vboId);
}
// Delete the texture
texture.cleanup();
// Delete the VAO
glBindVertexArray(0);
glDeleteVertexArrays(vaoId);
}
}
Window:
public class Window {
private final String title;
private int width;
private int height;
private long windowHandle;
private boolean resized;
private boolean vSync;
public Window(String title, int width, int height, boolean vSync) {
this.title = title;
this.width = width;
this.height = height;
this.vSync = vSync;
this.resized = false;
}
public void init() {
// Setup an error callback. The default implementation
// will print the error message in System.err.
GLFWErrorCallback.createPrint(System.err).set();
// Initialize GLFW. Most GLFW functions will not work before doing this.
if (!glfwInit()) {
throw new IllegalStateException("Unable to initialize GLFW");
}
glfwDefaultWindowHints(); // optional, the current window hints are already the default
glfwWindowHint(GLFW_VISIBLE, GL_FALSE); // the window will stay hidden after creation
glfwWindowHint(GLFW_RESIZABLE, GL_TRUE); // the window will be resizable
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
// Create the window
windowHandle = glfwCreateWindow(width, height, title, NULL, NULL);
if (windowHandle == NULL) {
throw new RuntimeException("Failed to create the GLFW window");
}
// Setup resize callback
glfwSetFramebufferSizeCallback(windowHandle, (window, width, height) -> {
this.width = width;
this.height = height;
this.setResized(true);
});
// Setup a key callback. It will be called every time a key is pressed, repeated or released.
glfwSetKeyCallback(windowHandle, (window, key, scancode, action, mods) -> {
if (key == GLFW_KEY_ESCAPE && action == GLFW_RELEASE) {
glfwSetWindowShouldClose(window, true); // We will detect this in the rendering loop
}
});
// Get the resolution of the primary monitor
GLFWVidMode vidmode = glfwGetVideoMode(glfwGetPrimaryMonitor());
// Center our window
glfwSetWindowPos(
windowHandle,
(vidmode.width() - width) / 2,
(vidmode.height() - height) / 2
);
// Make the OpenGL context current
glfwMakeContextCurrent(windowHandle);
if (isvSync()) {
// Enable v-sync
glfwSwapInterval(1);
}
// Make the window visible
glfwShowWindow(windowHandle);
GL.createCapabilities();
// Set the clear color
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glEnable(GL_DEPTH_TEST);
}
public long getWindowHandle() {
return windowHandle;
}
public void setClearColor(float r, float g, float b, float alpha) {
glClearColor(r, g, b, alpha);
}
public boolean isKeyPressed(int keyCode) {
return glfwGetKey(windowHandle, keyCode) == GLFW_PRESS;
}
public boolean windowShouldClose() {
return glfwWindowShouldClose(windowHandle);
}
public String getTitle() {
return title;
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
public boolean isResized() {
return resized;
}
public void setResized(boolean resized) {
this.resized = resized;
}
public boolean isvSync() {
return vSync;
}
public void setvSync(boolean vSync) {
this.vSync = vSync;
}
public void update() {
glfwSwapBuffers(windowHandle);
glfwPollEvents();
}
}
Never mind, the problem was that the vertex.vs file had to specify the uniform:
#version 330
layout (location=0) in vec3 position;
layout (location=1) in vec2 texCoord;
out vec2 outTexCoord;
uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;
void main()
{
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
outTexCoord = texCoord;
}

Android bytedeco javacpp ffmpeg decode h264 bytes to yuv and render with openGL ES 2.0. Wrong colors

there! I try to display a video stream, which comes from server as byte array.
Data in this array is h264 encoded image and i decode it with bytedeco javacpp-presets library in this way:
public class DMDecoder {
private static final String LOG_TAG = "DMDecoder";
private AVCodec avCodec;
private AVCodecContext avCodecContext;
private AVFrame avFrame;
private AVPacket avPacket;
private boolean wasIFrame;
private long IFrameTimeStampMs;
private int maxFps;
private int codecId;
private DMDecoderCallback callback;
public DMDecoder(DMDecoderCallback cb) {
this.callback = cb;
this.codecId = AV_CODEC_ID_H264;
avcodec_register_all();
restart();
}
public void restart() {
stop();
start();
}
public void stop() {
frames = 0;
if (avCodecContext != null) {
avcodec_close(avCodecContext);
avcodec_free_context(avCodecContext);
avCodecContext = null;
}
if (avCodec != null) {
av_free(avCodec);
avCodec = null;
}
if (avFrame != null) {
av_frame_free(avFrame);
avFrame = null;
}
if (avPacket != null) {
av_free_packet(avPacket);
avPacket = null;
}
}
public void start() {
avCodec = avcodec_find_decoder(codecId);
avCodecContext = avcodec_alloc_context3(avCodec);
AVDictionary opts = new AVDictionary();
avcodec_open2(avCodecContext, avCodec, opts);
avFrame = av_frame_alloc();
avPacket = new AVPacket();
av_init_packet(avPacket);
}
public VideoFrame decode(byte[] data, int dataOffset, int dataSize) {
avPacket.pts(AV_NOPTS_VALUE);
avPacket.dts(AV_NOPTS_VALUE);
avPacket.data(new BytePointer(data).position(dataOffset));
avPacket.size(dataSize);
avPacket.pos(-1);
IntBuffer gotPicture = IntBuffer.allocate(1);
int processedBytes = avcodec_decode_video2(
avCodecContext, avFrame, gotPicture, avPacket);
if (avFrame.width() == 0 || avFrame.height() == 0) return null;
VideoFrame frame = new VideoFrame();
frame.colorPlane0 = new byte[avFrame.width() * avFrame.height()];
frame.colorPlane1 = new byte[avFrame.width() / 2 * avFrame.height() / 2];
frame.colorPlane2 = new byte[avFrame.width() / 2 * avFrame.height() / 2];
if (avFrame.data(0) != null) avFrame.data(0).get(frame.colorPlane0);
if (avFrame.data(1) != null) avFrame.data(1).get(frame.colorPlane1);
if (avFrame.data(2) != null) avFrame.data(2).get(frame.colorPlane2);
frame.lineSize0 = avFrame.width();
frame.lineSize1 = avFrame.width() / 2;
frame.lineSize2 = avFrame.width() / 2;
frame.width = avFrame.width();
frame.height = avFrame.height();
return frame;
}
}
VideoFrame class is just simple POJO:
public class VideoFrame {
public byte[] colorPlane0;
public byte[] colorPlane1;
public byte[] colorPlane2;
public int lineSize0;
public int lineSize1;
public int lineSize2;
public int width;
public int height;
public long presentationTime;
}
After decoding i send this frame to my GLRenderer class
public class GLRenderer implements GLSurfaceView.Renderer {
private static final String LOG_TAG = "GLRenderer";
private TexturePlane plane;
private ConcurrentLinkedQueue<VideoFrame> frames;
private int maxFps = 30;
private VideoFrame currentFrame;
private long startTime, endTime;
private int viewWidth, viewHeight;
private boolean isFirstFrameProcessed;
public GLRenderer(int viewWidth, int viewHeight) {
frames = new ConcurrentLinkedQueue<>();
this.viewWidth = viewWidth;
this.viewHeight = viewHeight;
}
// mMVPMatrix is an abbreviation for "Model View Projection Matrix"
private final float[] mMVPMatrix = new float[16];
private final float[] mProjectionMatrix = new float[16];
private final float[] mViewMatrix = new float[16];
#Override
public void onSurfaceCreated(GL10 unused, EGLConfig config) {
// Set the background frame color
GLES20.glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
plane = new TexturePlane();
}
public void setMaxFps(int maxFps) {
this.maxFps = maxFps;
}
#Override
public void onDrawFrame(GL10 unused) {
// Draw background color
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
// Set the camera position (View matrix)
Matrix.setLookAtM(mViewMatrix, 0, 0, 0, -3, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
// Calculate the projection and view transformation
Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0);
if (!isFirstFrameProcessed) checkViewPort(viewWidth, viewHeight);
if (maxFps > 0 && startTime > 0) {
endTime = System.currentTimeMillis();
long time = endTime - startTime;
//
long wantedTime = 1000 / maxFps;
//
long wait;
if (time < wantedTime) {
wait = wantedTime - time;
//
try {
Thread.sleep(wait);
} catch (InterruptedException e) {
Log.e(LOG_TAG, "thread interrupted exception");
}
}
}
startTime = System.currentTimeMillis();
tick();
plane.draw(mMVPMatrix);
}
private void updateFrame(VideoFrame frame) {
plane.updateTexture(frame.colorPlane0, frame.width, frame.height, 0);
plane.updateTexture(frame.colorPlane1, frame.width / 2, frame.height / 2, 1);
plane.updateTexture(frame.colorPlane2, frame.width / 2, frame.height / 2, 2);
plane.setTextureWidth(frame.width);
plane.setTextureHeight(frame.height);
}
private void tick() {
if (frames.isEmpty()) return;
VideoFrame frame = frames.peek();
if (frame == null) return;
long tms = System.currentTimeMillis();
if (frame.presentationTime <= tms) {
updateFrame(frame);
currentFrame = frame;
frames.remove(frame);
}
}
#Override
public void onSurfaceChanged(GL10 unused, int width, int height) {
checkViewPort(width, height);
viewWidth = width;
viewHeight = height;
plane.setTextureWidth(width);
plane.setTextureHeight(height);
}
private void checkViewPort(int width, int height) {
float viewRatio = (float) width / height;
if (currentFrame != null) {
float targetRatio = (float) currentFrame.width / currentFrame.height;
int x, y, newWidth, newHeight;
if (targetRatio > viewRatio) {
newWidth = width;
newHeight = (int) (width / targetRatio);
x = 0;
y = (height - newHeight) / 2;
} else {
newHeight = height;
newWidth = (int) (height * targetRatio);
y = 0;
x = (width - newWidth) / 2;
}
GLES20.glViewport(x, y, newWidth, newHeight);
} else {
GLES20.glViewport(0, 0, width, height);
}
Matrix.frustumM(mProjectionMatrix, 0, 1, -1, -1, 1, 3, 4);
}
public void addFrame(VideoFrame frame) {
if (frame != null) {
frames.add(frame);
}
}
}
GLRenderer works with simple openGL polygon, on which i draw all textures
public class TexturePlane {
private static final String LOG_TAG = "TexturePlane";
private final String vertexShaderCode = "" +
"uniform mat4 uMVPMatrix;" +
"attribute vec4 vPosition;" +
"attribute vec2 a_TexCoordinate;" +
"varying vec2 v_TexCoordinate;" +
"void main() {" +
" gl_Position = uMVPMatrix * vPosition;" +
" v_TexCoordinate = a_TexCoordinate;" +
"}";
private final String fragmentShaderCode = "" +
"precision mediump float;" +
"varying vec2 v_TexCoordinate;" +
"uniform sampler2D s_texture_y;" +
"uniform sampler2D s_texture_u;" +
"uniform sampler2D s_texture_v;" +
"void main() {" +
" float y = texture2D(s_texture_y, v_TexCoordinate).r;" +
" float u = texture2D(s_texture_u, v_TexCoordinate).r - 0.5;" +
" float v = texture2D(s_texture_v, v_TexCoordinate).r - 0.5;" +
" float r = y + 1.13983 * v;" +
" float g = y - 0.39465 * u - 0.58060 * v;" +
" float b = y + 2.03211 * u;" +
" gl_FragColor = vec4(r, g, b, 1.0);" +
"}";
private final FloatBuffer vertexBuffer;
private final FloatBuffer textureBuffer;
private final ShortBuffer drawListBuffer;
private final int mProgram;
private int mPositionHandle;
private int mMVPMatrixHandle;
// number of coordinates per vertex in this array
private static final int COORDS_PER_VERTEX = 3;
private static final int COORDS_PER_TEXTURE = 2;
private static float squareCoords[] = {
-1f, 1f, 0.0f,
-1f, -1f, 0.0f,
1f, -1f, 0.0f,
1f, 1f, 0.0f
};
private static float uvs[] = {
0.0f, 0.0f,
0.0f, 1.0f,
1.0f, 1.0f,
1.0f, 0.0f
};
private final short drawOrder[] = {0, 1, 2, 0, 2, 3}; // order to draw vertices
private final int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertex
private int textureWidth = 640;
private int textureHeight = 480;
private int yTextureUniformHandle;
private int uTextureUniformHandle;
private int vTextureUniformHandle;
private int yTextureHandle;
private int uTextureHandle;
private int vTextureHandle;
private int mTextureCoordinateHandle;
public void setTextureWidth(int textureWidth) {
this.textureWidth = textureWidth;
}
public int getTextureWidth() {
return textureWidth;
}
public void setTextureHeight(int textureHeight) {
this.textureHeight = textureHeight;
}
public int getTextureHeight() {
return textureHeight;
}
/**
* Sets up the drawing object data for use in an OpenGL ES context.
*/
public TexturePlane() {
// initialize vertex byte buffer for shape coordinates
ByteBuffer bb = ByteBuffer.allocateDirect(squareCoords.length * 4);
bb.order(ByteOrder.nativeOrder());
vertexBuffer = bb.asFloatBuffer();
vertexBuffer.put(squareCoords);
vertexBuffer.position(0);
// initialize byte buffer for the draw list
ByteBuffer dlb = ByteBuffer.allocateDirect(drawOrder.length * 2);
dlb.order(ByteOrder.nativeOrder());
drawListBuffer = dlb.asShortBuffer();
drawListBuffer.put(drawOrder);
drawListBuffer.position(0);
// initialize byte buffer for the draw list
ByteBuffer tbb = ByteBuffer.allocateDirect(uvs.length * 4);
tbb.order(ByteOrder.nativeOrder());
textureBuffer = tbb.asFloatBuffer();
textureBuffer.put(uvs);
textureBuffer.position(0);
mProgram = GLES20.glCreateProgram(); // create empty OpenGL Program
compileShaders();
setupTextures();
}
public void setupTextures() {
yTextureHandle = setupTexture(null, textureWidth, textureHeight, 0);
uTextureHandle = setupTexture(null, textureWidth, textureHeight, 1);
vTextureHandle = setupTexture(null, textureWidth, textureHeight, 2);
}
public int setupTexture(ByteBuffer data, int width, int height, int index) {
final int[] textureHandle = new int[1];
GLES20.glGenTextures(1, textureHandle, 0);
if (textureHandle[0] != 0) {
// Bind to the texture in OpenGL
GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + index);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandle[0]);
updateTexture(data, width, height, index);
// Set filtering
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
// Set wrapping mode
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_REPEAT);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_REPEAT);
}
if (textureHandle[0] == 0) {
Log.e(LOG_TAG, "Error loading texture.");
}
return textureHandle[0];
}
public void updateTexture(byte[] data, int width, int height, int index) {
if (data == null) {
if (width == 0 || height == 0) {
width = textureWidth;
height = textureHeight;
}
data = new byte[width * height];
if (index == 0) {
Arrays.fill(data, y);
} else if (index == 1) {
Arrays.fill(data, u);
} else {
Arrays.fill(data, v);
}
}
byteBuffer.wrap(data);
byteBuffer.position(0);
GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + index);
GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_LUMINANCE,
width, height, 0, GLES20.GL_LUMINANCE, GLES20.GL_UNSIGNED_BYTE, byteBuffer);
}
private void compileShaders() {
// prepare shaders and OpenGL program
int vertexShader = loadShader(
GLES20.GL_VERTEX_SHADER,
vertexShaderCode);
int fragmentShader = loadShader(
GLES20.GL_FRAGMENT_SHADER,
fragmentShaderCode);
GLES20.glAttachShader(mProgram, vertexShader); // add the vertex shader to program
GLES20.glAttachShader(mProgram, fragmentShader); // add the fragment shader to program
GLES20.glLinkProgram(mProgram); // create OpenGL program executables
checkGlError("glLinkProgram");
// Add program to OpenGL environment
GLES20.glUseProgram(mProgram);
mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
mTextureCoordinateHandle = GLES20.glGetAttribLocation(mProgram, "a_TexCoordinate");
GLES20.glEnableVertexAttribArray(mPositionHandle);
GLES20.glEnableVertexAttribArray(mTextureCoordinateHandle);
yTextureUniformHandle = GLES20.glGetUniformLocation(mProgram, "s_texture_y");
uTextureUniformHandle = GLES20.glGetUniformLocation(mProgram, "s_Texture_u");
vTextureUniformHandle = GLES20.glGetUniformLocation(mProgram, "s_Texture_v");
mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
checkGlError("glGetUniformLocation");
}
/**
* Utility method for compiling a OpenGL shader.
* <p/>
* <p><strong>Note:</strong> When developing shaders, use the checkGlError()
* method to debug shader coding errors.</p>
*
* #param type - Vertex or fragment shader type.
* #param shaderCode - String containing the shader code.
* #return - Returns an id for the shader.
*/
public int loadShader(int type, String shaderCode) {
// create a vertex shader type (GLES20.GL_VERTEX_SHADER)
// or a fragment shader type (GLES20.GL_FRAGMENT_SHADER)
int shader = GLES20.glCreateShader(type);
// add the source code to the shader and compile it
GLES20.glShaderSource(shader, shaderCode);
GLES20.glCompileShader(shader);
return shader;
}
/**
* Utility method for debugging OpenGL calls. Provide the name of the call
* just after making it:
* <p/>
* <pre>
* mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");
* MyGLRenderer.checkGlError("glGetUniformLocation");</pre>
*
* If the operation is not successful, the check throws an error.
*
* #param glOperation - Name of the OpenGL call to check.
*/
public void checkGlError(String glOperation) {
int error;
String errorString;
while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
errorString = GLU.gluErrorString(error);
String message = glOperation + ": glError " + error + ": " + errorString;
Log.e(LOG_TAG, message);
throw new RuntimeException(message);
}
}
public void draw(float[] mvpMatrix) {
// Prepare the triangle coordinate data
GLES20.glVertexAttribPointer(
mPositionHandle, COORDS_PER_VERTEX,
GLES20.GL_FLOAT, false,
vertexStride, vertexBuffer);
GLES20.glVertexAttribPointer(
mTextureCoordinateHandle, COORDS_PER_TEXTURE,
GLES20.GL_FLOAT, false,
0, textureBuffer);
GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);
checkGlError("glUniformMatrix4fv");
GLES20.glUniform1i(yTextureUniformHandle, 0);
GLES20.glUniform1i(uTextureUniformHandle, 1);
GLES20.glUniform1i(vTextureUniformHandle, 2);
// Draw the square
GLES20.glDrawElements(
GLES20.GL_TRIANGLES, drawOrder.length,
GLES20.GL_UNSIGNED_SHORT, drawListBuffer);
}
}
But i have a problem there. My GL surface display image with wrong colors. image
What i'm doing wrong?
UPDATE:
As Ronald S. Bultje say, i added glBindTexture(...) function in my code. And now updateTexture(...) method looks like this:
public void updateTexture(byte[] data, int width, int height, int index) {
if (data == null) {
if (width == 0 || height == 0) {
width = textureWidth;
height = textureHeight;
}
data = new byte[width * height];
if (index == 0) {
Arrays.fill(data, y);
} else if (index == 1) {
Arrays.fill(data, u);
} else {
Arrays.fill(data, v);
}
}
byteBuffer.wrap(data);
byteBuffer.position(0);
GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + index);
int textureHandle = index == 0 ? yTextureHandle : index == 1 ? uTextureHandle : vTextureHandle;
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandle);
GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_LUMINANCE,
width, height, 0, GLES20.GL_LUMINANCE, GLES20.GL_UNSIGNED_BYTE, byteBuffer);
}
Your updateTexture() function doesn't call GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandle[index]); after calling GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + index);
[edit] actually given your code, it would be index==0?yTextureHandle:index==1?uTextureHandle?vTextureHandle, I'm sure you can figure out how to refactor your code to make this easier.

Wrong coordinates for different objects

In short:
I create Polygon object with a help of this method:
public static float[][] getPolygonArrays(float cx, float cy, float R, int sides) {
float[] x = new float[sides];
float[] y = new float[sides];
double thetaInc = 2 * Math.PI / sides;
double theta = (sides % 2 == 0) ? thetaInc : -Math.PI / 2;
for (int j = 0; j < sides; j++) {
x[j] = (float) (cx + R * Math.cos(theta));
y[j] = (float) (cy + R * Math.sin(theta));
theta += thetaInc;
}
return new float[][]{x, y};
}
and merge it to one dimension array with:
public static float[] mergeCoordinates(float[][] vertices) throws Exception {
if (vertices.length != 2 || vertices[0].length != vertices[1].length) throw new Exception("No valid data");
ArrayList<Float> mergedArrayList = new ArrayList<Float>();
float[] mergedArray = new float[vertices[0].length * 2];
for(int i = 0; i < vertices[0].length; i++) {
mergedArrayList.add(vertices[0][i]);
mergedArrayList.add(vertices[1][i]);
}
int i = 0;
for (Float f : mergedArrayList) {
mergedArray[i++] = (f != null ? f : Float.NaN);
}
return mergedArray;
}
I use 0 as value for X and Y for all newly created Polygons (named in code as Platform). And result of method mergeCoordinates i pass to method setVertices of Polygon object.
After this step i do setPosition with x = Gdx.graphics.getWidth()/2 and y = Gdx.graphics.getHeight()/2. Polygons are positioned good, right on the game screen center.
Than i create a new one Polygon, which must use origin coordinates from first Polygon object, this new polygon i named Figure. To set origin coordinates i use method setOrigin of Polygon class, and use X and Y of Platform Polygon object.
When i run method rotate of Platform Polygon object i also rotate Figure Polygon object, and Figure must rotate around origin point, center of Platform. But it does not.
Figure do rotation around bottom right corner.
For example:
my screen size is 640 x 480. Center point will be 320 x 240. This is X and Y of Platform Polygon object, i checked it with getX and getY of Polygon. I create Figure at 0,0, do setPosition(320, 200) (this is preferred orbit distance for figure to platform). And Figure positioned also good.
I run setOrigin(320, 240) for Figure Polygon Object.
I run rotate for Figure object. And it somehow think that right bottom corner have coordinates x = 320 and y = 240 and do rotation around this point.
Any could help me to solve this problem?
More details on problem you can find below(details, images, gifs, schemes and also sources).
More detailed part starts here
i'm trying to understand how coordinate system in libgdx work, cause i have a problem with positioning objects in game world.
I created simple application, with one big Red Polygon object(Platform in code),
10 White Triangle Polygons(Sector in code) which are included into big polygon object and inherits it's behavior(such like rotate, moveTo and etc).
Than i added inside each Sector one Green Polyline(Direction in code) from first vertice of Sector Polygon to midle point of the opposite side to first point.
This is technical line and i will use it's vertices(coordinates of two points) to move small Red Polygon Object(Figure in code), from center to oposite side to center point of Sector.
When i click on Stage and click coordinates are inside Platform i rotate it to the left or to the right(depends on where click was made). On rotate all Sectors and technical lines are rotated correctly.
http://i.imgur.com/s5xaI8j.gif
(670Kb)
As you can see on gif, figures rotates around theire's center point. I found that Polygon class has method setOrigin(float x, float y) and in annotation to this method said next:
/** Sets the origin point to which all of the polygon's local vertices
are relative to. */
So i tried to use this method, set origin X of Figure as center X of Platform and origin Y as center Y of Platform, and tried to rotate Platform.
http://i.imgur.com/pXpTuQi.gif
(1.06Mb)
As you can see, Figure polygon think that his origin coordinates are at right bottom corner. And Figure do rotation around right bottom corner.
I changed origin to next values: x = 50 and y = 50, here is a result:
http://i.imgur.com/Iajb9sN.gif
(640Kb)
I cannot get why it behave like that. What should i change in my logic?
I have not much classes in my project. I removed all imports and getters/setter to reduce amount of lines.
If it is necessary i could provide entire project.
GameScreen code:
public class GameScreen extends DefaultScreen {
private final GameWorld world;
private final GameRenderer renderer;
public GameScreen() {
world = new GameWorld();
renderer = new GameRenderer(world);
}
#Override
public void render(float delta) {
world.update(delta);
renderer.render();
}
#Override
public void resize(int width, int height) {
world.resize(width, height);
}
}
GameWorld code:
public class GameWorld {
private ArrayList < Platform > platforms = new ArrayList < Platform > ();
private OrthographicCamera camera;
private Stage stage;
private Array < Figure > activeFigures;
private Pool < Figure > figuresPool;
private long lastFigureTime = TimeUtils.nanoTime();
public GameWorld() {
setCamera(new OrthographicCamera());
getCamera().setToOrtho(true, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
setStage(new Stage());
getStage().setViewport(new ScreenViewport(getCamera()));
initializePools();
createPlatforms();
getStage().addListener(new InputListener() {
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
float degrees = Config.PLATFORM_ROTATE_DEGREES;
if (x <= Gdx.graphics.getWidth() / 2) {
degrees *= -1;
}
int i = getPlatforms().size();
while (i-- > 0) {
Platform platform = getPlatforms().get(i);
if (!platform.isLocked() && platform.isRotatable() && platform.getShape().getPolygon().contains(x, y)) {
platform.addAction(Actions.rotateBy(degrees, 1, Interpolation.bounceOut));
break;
}
}
return true;
}
});
Gdx.input.setInputProcessor(getStage());
}
private void initializePools() {
setActiveFigures(new Array < Figure > ());
setFiguresPool(new Pool < Figure > () {#Override
protected Figure newObject() {
return new Figure();
}
});
}
private void createPlatforms() {
float max = Gdx.graphics.getHeight() / (Gdx.graphics.getWidth() / (Gdx.graphics.getWidth() / 2));
float x = Gdx.graphics.getWidth() / 2;
float y = Gdx.graphics.getHeight() / 2;
float sides = 10f;
Color color = Color.RED;
createPlatform(x, y, max * Config.THIRD_PLATFORM_RADIUS_MULTIPLIER, sides, color, true, false, false, null);
}
private Platform createPlatform(float x, float y, float radius, float sides, Color color, boolean rotatable, boolean locked, boolean isEmpty, Platform relatedTo) {
Platform platform = new Platform(0, 0, radius, sides, color, isEmpty, this);
platform.moveTo(x, y);
platform.setRotatable(rotatable);
platform.setLocked(locked);
getPlatforms().add(platform);
getStage().addActor(platform);
if (relatedTo != null) {
relatedTo.addRelation(platform);
}
return platform;
}
private Figure createFigure(float x, float y) {
Figure figure = getFiguresPool().obtain();
figure.init(this, 0, 0, 10f, 4f, Color.DARK_GRAY);
figure.moveTo(x, y);
getActiveFigures().add(figure);
getStage().addActor(figure);
return figure;
}
public void spawnFigure() {
if (getActiveFigures().size >= 10) return;
if (TimeUtils.nanoTime() - getLastFigureTime() <= 2000000000) return;
Platform platform = null;
for (Platform p: getPlatforms()) {
if (!p.isEmpty()) {
platform = p;
break;
}
}
if (platform == null) {
setLastFigureTime(TimeUtils.nanoTime());
return;
}
Sector sector = platform.getSectors().get(MathUtils.random(platform.getSectors().size() - 1));
float x = platform.getX();
float y = platform.getY();
Figure figure = createFigure(x, y);
figure.origin(x, y);
x = sector.getDirection().getTransformedVertices()[2];
y = sector.getDirection().getTransformedVertices()[3];
figure.addAction(Actions.moveTo(x, y, 1));
setLastFigureTime(TimeUtils.nanoTime());
}
public void update(float delta) {
updatePlatforms(delta);
updateFigures(delta);
spawnFigure();
}
private void updatePlatforms(float delta) {
for (Platform platform: getPlatforms()) {
platform.update(delta);
}
}
private void updateFigures(float delta) {
Figure figure;
int figures = getActiveFigures().size;
for (int i = figures; --i >= 0;) {
figure = getActiveFigures().get(i);
if (figure.isAlive() == false) {
getActiveFigures().removeIndex(i);
getFiguresPool().free(figure);
} else {
figure.update(delta);
}
}
}
public void resize(int width, int height) {
getCamera().setToOrtho(true, width, height);
getStage().getViewport().update(width, height, true);
for (Platform platform: getPlatforms()) {
platform.resize(true, width, height);
}
for (Figure figure: getActiveFigures()) {
figure.resize(true, width, height);
}
}
}
GameRenderer code:
public class GameRenderer {
private ShapeRenderer shapeRenderer;
private GameWorld world;
private SpriteBatch spriteBatch;
public GameRenderer(GameWorld world) {
setWorld(world);
setShapeRenderer(new ShapeRenderer());
getShapeRenderer().setProjectionMatrix(getWorld().getCamera().combined);
setSpriteBatch(new SpriteBatch());
getSpriteBatch().setProjectionMatrix(getWorld().getCamera().combined);
}
public void render() {
Gdx.gl.glClearColor(0f, 0.2f, 0.4f, 1f);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
getWorld().getCamera().update();
getSpriteBatch().setProjectionMatrix(getWorld().getCamera().combined);
getShapeRenderer().setProjectionMatrix(getWorld().getCamera().combined);
getWorld().getStage().act(Gdx.graphics.getDeltaTime());
getWorld().getStage().draw();
renderGameObjects();
}
private void renderGameObjects() {
renderPlatforms();
renderFigures();
}
private void renderFigures() {
getShapeRenderer().begin(ShapeRenderer.ShapeType.Line);
for (Figure figure: getWorld().getActiveFigures()) {
figure.render(getSpriteBatch(), getShapeRenderer());
}
getShapeRenderer().end();
}
private void renderPlatforms() {
getShapeRenderer().begin(ShapeRenderer.ShapeType.Line);
for (Platform platform: world.getPlatforms()) {
platform.render(getSpriteBatch(), getShapeRenderer());
}
getShapeRenderer().end();
}
}
Platform code:
public class Platform extends GameObject {
private ArrayList < Sector > sectors = new ArrayList < Sector > ();
private ArrayList < Platform > relations = new ArrayList < Platform > ();
private boolean rotatable = true;
private boolean locked = false;
private void initialize(float cx, float cy, float radius, float sides, Color color) {
setPosition(cx, cy);
setRadius(radius);
setShape(ShapeType.POLYGON.getInstance(new float[] {
cx, cy, radius, sides
}, color));
}
public Platform(float cx, float cy, float radius, float sides, Color color, boolean isEmpty, GameWorld gameWorld) {
setGameWorld(gameWorld);
initialize(cx, cy, radius, sides, color);
setEmpty(isEmpty);
if (!isEmpty()) {
generateSectors();
}
}
private void generateSectors() {
float[] vertices = getShape().getVertices();
for (int i = 0; i < vertices.length; i += 2) {
try {
Color color = Color.WHITE;
if (i + 3 > vertices.length) {
getSectors().add(new Sector(new float[] {
getX(), getY(), vertices[i], vertices[i + 1], vertices[0], vertices[1]
}, color, this, i / 2));
} else {
getSectors().add(new Sector(new float[] {
getX(), getY(), vertices[i], vertices[i + 1], vertices[i + 2], vertices[i + 3]
}, color, this, i / 2));
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
public void rotateBy(float degrees) {
setRotation(degrees);
getShape().rotate(degrees);
for (Sector sector: getSectors()) {
sector.rotate(degrees);
}
for (Platform platform: getRelations()) {
platform.rotateBy(degrees);
}
for (Figure figure: getGameWorld().getActiveFigures()) {
figure.rotate(degrees);
}
}
#Override
public void moveTo(float x, float y) {
super.moveTo(x, y);
getShape().moveTo(x, y);
for (Sector sector: getSectors()) {
sector.moveTo(x, y);
}
for (Platform platform: getRelations()) {
platform.moveTo(x, y);
}
}
public void addRelation(Platform platform) {
if (platform.equals(this)) return;
getRelations().add(platform);
}
#Override
public void update(float delta) {
for (Sector sector: getSectors()) {
sector.update(delta);
}
}
#Override
public void dispose() {
for (Sector sector: getSectors()) {
sector.dispose();
}
}
#Override
public void render(SpriteBatch spriteBatch, ShapeRenderer shapeRenderer) {
render(spriteBatch);
if (Config.DEBUG_LAYOUTS) render(shapeRenderer);
for (Sector sector: getSectors()) {
sector.render(spriteBatch, shapeRenderer);
}
}
private void render(ShapeRenderer shapeRenderer) {
shapeRenderer.setColor(getShape().getColor());
shapeRenderer.polygon(getShape().getVertices());
}
public void resize(boolean reposition, int width, int height) {
if (reposition) {
moveTo(width / 2, height / 2);
}
}
}
Sector code:
public class Sector extends GameObject {
private Polyline direction;
private float[] vertices;
private Platform platform;
private int sectorId;
public Sector(float[] vertices, Color color, Platform platform, int sectorId) throws Exception {
setSectorId(sectorId);
setVertices(vertices);
initialize(vertices, color, platform);
}
private void createDirection() {
float[] vertices = getShape().getPolygon().getVertices();
float x1 = vertices[0];
float y1 = vertices[1];
float x2 = (vertices[2]+vertices[4])/2;
float y2 = (vertices[3]+vertices[5])/2;
setDirection(new Polyline(new float[]{ x1, y1, x2, y2 }));
}
public Sector(float[] vertices, Color color, boolean isEmpty) throws Exception {
initialize(vertices, color);
setEmpty(isEmpty);
}
private void initialize(float[] vertices, Color color) throws Exception {
if (vertices.length != 6) {
throw new Exception("Sector constructor expects 6 vertices");
}
setShape(ShapeType.TRIANGLE.getInstance(vertices, color));
createDirection();
}
private void initialize(float[] vertices, Color color, Platform platform) throws Exception {
if (vertices.length != 6) {
throw new IllegalArgumentException("Sector constructor expects 6 vertices");
}
setShape(ShapeType.TRIANGLE.getInstance(vertices, color));
setPlatform(platform);
createDirection();
}
public void rotate(float degrees) {
getShape().rotate(degrees);
getDirection().rotate(degrees);
}
#Override
public void moveTo(float x, float y) {
super.moveTo(x, y);
getShape().moveTo(x, y);
getDirection().setPosition(x, y);
}
#Override
public void render(SpriteBatch spriteBatch, ShapeRenderer shapeRenderer) {
render(spriteBatch);
if (Config.DEBUG_LAYOUTS) render(shapeRenderer);
}
private void render(ShapeRenderer shapeRenderer) {
shapeRenderer.setColor(getShape().getColor());
shapeRenderer.polygon(getShape().getVertices());
shapeRenderer.setColor(Color.GREEN);
shapeRenderer.line(getDirection().getTransformedVertices()[0], getDirection().getTransformedVertices()[1], getDirection().getTransformedVertices()[2], getDirection().getTransformedVertices()[3]);
}
}
Figure code:
public class Figure extends GameObject {
private GameWorld world;
public void init(GameWorld world, float cx, float cy, float radius, float sides, Color color) {
super.init();
setWorld(world);
initialize(cx, cy, radius, sides, color);
}
private void initialize(float cx, float cy, float radius, float sides, Color color) {
super.moveTo(cx, cy);
setRadius(radius);
setShape(ShapeType.POLYGON.getInstance(new float[] {
cx, cy, radius, sides
}, color));
}
#Override
public void moveTo(float x, float y) {
super.moveTo(x, y);
getShape().moveTo(x, y);
}
#Override
public void setPosition(float x, float y) {
if (!isAllowedToFlyFuther()) {
clearActions();
return;
}
moveTo(x, y);
}
private boolean isAllowedToFlyFuther() {
for (Figure figure: getWorld().getActiveFigures()) {
if (!figure.equals(this) && Intersector.overlapConvexPolygons(figure.getShape().getPolygon(), getShape().getPolygon())) {
return false;
}
}
return true;
}
#Override
public void reset() {
super.reset();
remove();
}
#Override
public void update(float delta) {}
private void render(SpriteBatch spriteBatch) {}
#Override
public void dispose() {}
#Override
public void render(SpriteBatch spriteBatch, ShapeRenderer shapeRenderer) {
render(spriteBatch);
if (Config.DEBUG_LAYOUTS) render(shapeRenderer);
}
private void render(ShapeRenderer shapeRenderer) {
shapeRenderer.setColor(getShape().getColor());
shapeRenderer.polygon(getShape().getVertices());
}
public void rotate(float degrees) {
setRotation(degrees);
getShape().rotate(degrees);
}
public void origin(float originX, float originY) {
setOrigin(originX, originY);
getShape().setOrigin(originX, originY);
}
public void resize(boolean reposition, int width, int height) {
if (reposition) {
//TODO: implement reposition for figures
}
}
}
GameObject code:
public abstract class GameObject extends Actor implements Poolable {
private int speed = 200;
private int baseSpeed = 200;
private boolean alive;
private float radius;
private GameWorld gameWorld;
private Shape shape;
private boolean empty = false;
public GameObject() {
setAlive(false);
}
public void init() {
setAlive(true);
}
public void reset() {
setAlive(false);
}
public abstract void update(float delta);
public abstract void render(SpriteBatch spriteBatch, ShapeRenderer shapeRenderer);
public abstract void dispose();
public void moveTo(float x, float y) {
super.setPosition(x, y);
}
}
Shape code:
public class Shape {
private Color color = new Color(Color.RED);
private float[] vertices;
private int sides;
private float radius;
private Polygon polygon = new Polygon();
public void rotate(float degrees) {
getPolygon().rotate(degrees);
setVertices(getPolygon().getTransformedVertices());
}
public void moveTo(float x, float y) {
getPolygon().setPosition(x, y);
setVertices(getPolygon().getTransformedVertices());
}
public void setOrigin(float originX, float originY) {
getPolygon().setOrigin(originX, originY);
setVertices(getPolygon().getTransformedVertices());
}
public void scale(float ratio) {
getPolygon().setScale(ratio, ratio);
setVertices(getPolygon().getTransformedVertices());
}
}
ShapeType code:
public enum ShapeType {
POLYGON {#Override
public Shape getInstance(float[] settings, Color color) {
try {
return new PolygonShape(settings, color);
} catch (Exception e) {
e.printStackTrace();
}
return new BaseShape();
}
},
TRIANGLE {#Override
public Shape getInstance(float[] settings, Color color) {
try {
return new TriangleShape(settings, color);
} catch (Exception e) {
e.printStackTrace();
}
return new BaseShape();
}
};
public abstract Shape getInstance(float[] settings, Color color);
}
PolygonShape code:
public class PolygonShape extends Shape {
public PolygonShape(float[] settings, Color color) throws Exception {
if (settings.length < 4) {
throw new IllegalArgumentException("Polygon shape constructor expects minimum 4 items in settings");
}
setSides((int) settings[3]);
setRadius(settings[2]);
setVertices(Utils.mergeCoordinates(Utils.getPolygonArrays(settings[0], settings[1], settings[2], (int) settings[3])));
getPolygon().setVertices(getVertices());
}
}
TriangleShape code:
public class TriangleShape extends Shape {
public TriangleShape(float[] settings, Color color) throws Exception {
if (settings.length < 6) {
throw new IllegalArgumentException("Triangle shape constructor expects minimum 6 items in settings");
}
setVertices(settings);
setColor(color);
getPolygon().setVertices(getVertices());
}
}
Utils code:
public class Utils {
public static float[] mergeCoordinates(float[][] vertices) throws Exception {
if (vertices.length != 2 || vertices[0].length != vertices[1].length) throw new Exception("No valid data");
ArrayList < Float > mergedArrayList = new ArrayList < Float > ();
float[] mergedArray = new float[vertices[0].length * 2];
for (int i = 0; i < vertices[0].length; i++) {
mergedArrayList.add(vertices[0][i]);
mergedArrayList.add(vertices[1][i]);
}
int i = 0;
for (Float f: mergedArrayList) {
mergedArray[i++] = (f != null ? f : Float.NaN);
}
return mergedArray;
}
public static float[][] getPolygonArrays(float cx, float cy, float R, int sides) {
float[] x = new float[sides];
float[] y = new float[sides];
double thetaInc = 2 * Math.PI / sides;
double theta = (sides % 2 == 0) ? thetaInc : -Math.PI / 2;
for (int j = 0; j < sides; j++) {
x[j] = (float)(cx + R * Math.cos(theta));
y[j] = (float)(cy + R * Math.sin(theta));
theta += thetaInc;
}
return new float[][] {
x, y
};
}
}
Config code:
public class Config {
public static final String LOG = TheGame.class.getSimpleName();
public static final boolean DEBUG_LAYOUTS = true;
public static final boolean SHOW_LOG = false;
public static final float PLATFORM_ROTATE_DEGREES = 36;
}
DesktopLauncher code:
public class DesktopLauncher {
public static void main(String[] arg) {
LwjglApplicationConfiguration config = new LwjglApplicationConfiguration();
config.title = "The Game!";
config.width = 1920 / 3;
config.height = 1080 / 3;
new LwjglApplication(new TheGame(), config);
}
}
Project structure:
Platform object structure and dependencies:
Render objects workflow

How to select a region of an image during drawing in LWGJL?

I am trying to select a specific region of a texture in LWJGL during the drawing process, but my efforts have been fruitless. How (if possible) can I select only a region of a whole texture during drawing.
Please note that I am nowhere new to Java, I am an experienced programmer, but not when it comes to LWGJL, as I'm still getting the full grasps with it.
Below is my code.
Sprite.java
public class Sprite
{
private Icon icon;
private int width;
private int height;
private int offcutX; // all below and this for selecting the region of the image.
private int offcutY;
private int imageX;
private int imageY;
public Sprite(TextureRegistry registry, String ref)
{
this(registry, ref, 0, 0, 0, 0);
}
public Sprite (TextureRegistry registry, String ref, int offcutX, int offcutY, int imageX, int imageY)
{
try
{
icon = registry.getIcon("net/blockbuster/resources/" + ref); // loads the icon and converts it to opengl-readable format.
width = icon.getIconWidth();
height = icon.getIconHeight();
this.offcutX = offcutX;
this.offcutY = offcutY;
this.imageX = imageX;
this.imageY = imageY;
}
catch (IOException e)
{
e.printStackTrace();
System.exit(-1);
}
}
public int getWidth()
{
return icon.getIconWidth();
}
public int getHeight()
{
return icon.getIconHeight();
}
public void draw(int x, int y) // drawing method, called on every loop.
{
glPushMatrix();
icon.bind();
glTranslatef(x, y, 0);
glBegin(GL_QUADS);
{ // I would like to be able to do this within this block.
glTexCoord2f(0, 0);
glVertex2f(0, 0);
glTexCoord2f(0, 1);
glVertex2f(0, height);
glTexCoord2f(1, 1);
glVertex2f(width, height);
glTexCoord2f(1, 0);
glVertex2f(width, 0);
}
glEnd();
glPopMatrix();
}
}
TextureRegistry.java
public class TextureRegistry
{
private HashMap<String, Icon> table = new HashMap<String, Icon>(); // map to hold all loaded textures
public Icon getIcon(String resourceName) throws IOException
{
Icon tex = table.get(resourceName);
if (tex != null)
{
return tex;
}
tex = getIcon(resourceName, GL_TEXTURE_2D, GL_RGBA8, GL_LINEAR, GL_LINEAR);
table.put(resourceName, tex);
return tex;
}
public Icon getIcon(String resourceName, int target, int dstPixelFormat, int minFilter, int magFilter) throws IOException
{
BufferedImage image = loadImage(resourceName);
int textureID = loadTexture(image);
Icon icon = new Icon(target, textureID);
icon.setWidth(image.getWidth());
icon.setHeight(image.getHeight());
return icon;
}
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() * 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)); // r
buffer.put((byte)((pixel >> 8) & 0xFF)); // g
buffer.put((byte)(pixel * 0xFF)); // b
buffer.put((byte)((pixel >> 24) & 0xFF)); // a
}
}
buffer.flip();
int textureID = glGenTextures();
glBindTexture(GL_TEXTURE_2D, textureID);
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);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, image.getWidth(), image.getHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
return textureID;
}
public static BufferedImage loadImage(String ref) throws IOException
{
URL url = TextureRegistry.class.getClassLoader().getResource(ref);
if (url == null)
{
throw new IOException("Cannot find: " + ref);
}
Image img = new ImageIcon(url).getImage();
BufferedImage bufferedImage = new BufferedImage(img.getWidth(null), img.getHeight(null), BufferedImage.TYPE_INT_ARGB);
Graphics g = bufferedImage.getGraphics();
g.drawImage(img, 0, 0, null);
g.dispose();
return bufferedImage;
}
}
Icon.java
public class Icon
{
private int target;
private int iconID;
private int width;
private int height;
private int iconWidth;
private int iconHeight;
private float widthRatio;
private float heightRatio;
public Icon(int target, int iconID)
{
this.target = target;
this.iconID = iconID;
}
public void bind()
{
glBindTexture(target, iconID); // binds the texture
}
public void setHeight(int newHeight)
{
this.height = newHeight;
setHeight();
}
public void setWidth(int newWidth)
{
this.width = newWidth;
setWidth();
}
public int getIconHeight()
{
return height;
}
public int getIconWidth()
{
return width;
}
public float getHeight()
{
return heightRatio;
}
public float getWidth()
{
return widthRatio;
}
public void setIconHeight(int iconHeight)
{
this.iconHeight = iconHeight;
setHeight();
}
public void setIconWidth(int iconWidth)
{
this.iconWidth = iconWidth;
setWidth();
}
private void setHeight()
{
if (iconHeight != 0)
{
heightRatio = ((float)height) / iconHeight;
}
}
private void setWidth()
{
if (iconWidth != 0)
{
widthRatio = ((float)width) / iconWidth;
}
}
}
To specify a region of a texture to be drawn all you need to do is modify your texCoords. Currently you are using your entire texture, if for example you wanted only the quarter of it closest to the origin you would use this in your draw method:
glTexCoord2f(0, 0);
glVertex2f(0, 0);
glTexCoord2f(0, 1/2f);
glVertex2f(0, height);
glTexCoord2f(1/2f, 1/2f);
glVertex2f(width, height);
glTexCoord2f(1/2f, 0);
glVertex2f(width, 0);
which would result in an image the same size as before although using only the bottom left quarter of the texture.

Categories

Resources