I've been trying to write a game engine in lwjgl and I've come across an issue with rendering and I'd like a bit of help. Basically, I've followed some steps in the lwjgl-basics (mattdesl on GitHub) and produced a Texture class and a section in my renderer that work except that they don't render a texture. Here's the code...
public void drawTexturedRectangle(float x1, float y1, float w, float h, Texture t){
t.bind();
GL11.glColor4f(1.0f, 0, 1.0f, 1.0f);
GL11.glBegin(GL11.GL_QUADS);
GL11.glTexCoord2f(0, 0);
GL11.glVertex2f(x1, y1);
GL11.glTexCoord2f(1.0f, 0);
GL11.glVertex2f(x1 + w, y1);
GL11.glTexCoord2f(1.0f, 1.0f);
GL11.glVertex2f(x1 + w, y1 + h);
GL11.glTexCoord2f(0, 1.0f);
GL11.glVertex2f(x1, y1 + h);
GL11.glEnd();
}
That's where it renders. Here's the Texture class:
package com.nightfall.morningside;
import java.io.*;
import java.net.URL;
import java.nio.ByteBuffer;
import de.matthiasmann.twl.utils.*;
import org.lwjgl.opengl.*;
import org.lwjgl.opengl.GL12.*;
import org.lwjgl.BufferUtils;
public class Texture {
public int width;
public int height;
public int id;
public Texture(URL pathToTexture){
try {
InputStream pngstream = pathToTexture.openStream();
PNGDecoder pngdecoder = new PNGDecoder(pngstream);
width = pngdecoder.getWidth();
height = pngdecoder.getHeight();
int bpp = 4;
ByteBuffer buffer = BufferUtils.createByteBuffer(bpp * width * height);
pngdecoder.decode(buffer, width * bpp, PNGDecoder.Format.RGBA);
buffer.flip();
id = GL11.glGenTextures();
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.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL12.GL_CLAMP_TO_EDGE);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL12.GL_CLAMP_TO_EDGE);
GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA, width, height, 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, buffer);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void bind(){
GL11.glBindTexture(GL11.GL_TEXTURE_2D, id);
}
}
The TexturedRectangle class:
package com.nightfall.morningside.geometry;
import com.nightfall.morningside.Texture;
import com.nightfall.morningside.Textured;
public class TexturedRectangle extends Rectangle implements Textured{
public Texture texture;
public TexturedRectangle(float xone, float yone, float w, float h, Texture t) {
super(xone, yone, w, h);
texture = t;
}
public Texture getTexture() {
return texture;
}
}
The Rectangle class:
package com.nightfall.morningside.geometry;
public class Rectangle {
private float x1;
private float y1;
private float width;
private float height;
public Rectangle(float xone, float yone, float w, float h){
x1 = xone;
y1 = yone;
width = w;
height = h;
}
public float getX1(){
return x1;
}
public float getY1(){
return y1;
}
public float getHeight(){
return height;
}
public float getWidth(){
return width;
}
public Point getLocation(){
return new Point(x1, y1);
}
}
And the Textured interface:
package com.nightfall.morningside;
public interface Textured {
public Texture getTexture();
}
And the Point class:
package com.nightfall.morningside.geometry;
public class Point {
private float x1;
private float y1;
public Point(float x, float y){
x1 = x;
y1 = y;
}
public float getX(){
return x1;
}
public float getY(){
return y1;
}
}
I hope this is everything. I believe it's an issue in the way I'm rendering but maybe there's an issue in where I load textures.
If you need anything else, I'll put it up for you.
Thanks.
Texture are disable by default. When you want to render a textured primitive (a textured quad for instance), you must activate texturing with
glEnable(GL_TEXTURE2D);
glBindTexture(GL_TEXTURE_2D, textureId);
The first line tells openGL to use texturing, the second specify which texture you want to use.
To stop using the texture, you can:
Bind zero to GL_TEXTURE_2D : glBindTexture(GL_TEXTURE_2D, 0); or
Disable GL_TEXTURE_2D : glDisable(GL_TEXTURE_2D);
edit, I forgot all the GLxx. prefixes (static import in my codes)
Related
So I am creating a sprite and drawing it to the screen using a different class.
I now want to scale it to be the same aspect ratio/size on each screen.
I have tried doing that by using this code:
public Player(Vector2 position, float width, float height, float rotation, float speed)
{
super(speed, rotation, width, height, position);
}
public void update()
{
width = Gdx.graphics.getWidth() / 10;
height = Gdx.graphics.getHeight() / 10;
}
But this doesn't work, it does nothing.
I have also tried setting the width and height to a static value for example 100 by 100. But this does not work either.
Thank you for any help! :)
Edit: adding base and derived classes:
Here's the code for the Entity class:
public abstract class Entity {
public void setPosition(Vector2 position) {
this.position = position;
}
public float getWidth() {
return width;
}
public void setWidth(float width) {
this.width = width;
}
public float getHeight() {
return height;
}
public void setHeight(float height) {
this.height = height;
}
public Rectangle getBounds() {
return bounds;
}
public void setBounds(Rectangle bounds) {
this.bounds = bounds;
}
}
Here's the code for the MoveEntity class:
public MoveEntity(float speed, float rotation,
float width, float height,
Vector2 position) {
super(position, width, height);
this.speed = speed;
this.rotation = rotation;
vel = new Vector2(0, 0);
}
public Vector2 getVel() {
return vel;
}
public void setVel(Vector2 target) {
this.vel = target;
}
public float getRotation() {
return rotation;
}
public void setRotation(float r) {
..............///
maybe it do not speak English, but you talk about a sprite and I do not see him any site, anyway.
assuming this is the sprite to which you refer -> spr_player
You can do this in several ways but basing on this line of code that you publish
Variable class. (for test):
float width = Gdx.graphics.getWidth() / 10;
float height = Gdx.graphics.getHeight() / 10;
Try to use this:
sb.draw(spr_player, p.getPosition().x, p.getPosition().y
width, height);
this is the funtion in the Class SpriteBatch:
public void draw (Texture texture, float x, float y,
float width, float height)
also you could use, setSize in the Sprite class, somewhere before render.
spr_player.setSize(width, height);
this is the funtion in the Class Sprite:
public void setSize (float width, float height)
if the size will not change during the game maybe, you can call the setSize, in method created or show, or in the constructor call this way, if the result you want:
Sprite spr_player = new Sprite (your_texture, width, height);
this is the funtion in the Class Sprite:
public Sprite (Texture texture, int srcWidth, int srcHeight)
I'm currently trying to make a game(Java, lwjgl, OpenGL) so that I can get a basic understanding of the how a top down RPG game works(i.e. in learning process). Recently, I tried to implement a healthbar that would hover over the player's sprite, but when I tried to draw it through my Draw class, the display goes haywire and almost everything except the player turn black, while the player sprite itself gets tinted the color passed(in R, G, B) to the Draw method.
The Source Code:
Player Class
package GameObjects;
import Graphics.ImageLoader;
import java.awt.Rectangle;
import java.util.ArrayList;
import static org.lwjgl.opengl.GL11.glPopMatrix;
import static org.lwjgl.opengl.GL11.glPushMatrix;
import org.newdawn.slick.opengl.Texture;
import rpgmain.*;
/**
*
* #author Samsung
*/
public class Player extends GameObject{
private float velX, velY;
private int curHealth, maxHealth;
private Texture tex;
public Player(float x, float y, ObjectId id) {
super(x, y, id);
velX = velY = 0;
curHealth = maxHealth = 100;
tex = ImageLoader.loadTexture("Player", "png");
}
protected void update(ArrayList<GameObject> objects) {
x += velX;
y += velY;
Collisions(objects);
}
protected void render() {
Draw.rect(x, y, 32, 32, tex);
dispHealth();
}
public void Collisions(ArrayList<GameObject> objects) {
for(GameObject obj : objects) {
if(obj.getId() == ObjectId.WaterTile) {
if(Collision.checkCollision(getBoundsTop(), obj.getBounds())) {
velX = velY = 0;
y = obj.getY() - 32;
}
if(Collision.checkCollision(getBoundsBottom(), obj.getBounds())) {
velX = velY = 0;
y = obj.getY() + 32;
}
if(Collision.checkCollision(getBoundsLeft(), obj.getBounds())) {
velX = velY = 0;
x = obj.getX() + 32;
}
if(Collision.checkCollision(getBoundsRight(), obj.getBounds())) {
velX = velY = 0;
x = obj.getX() - 32;
}
}
}
}
public void dispHealth() {
Draw.rect(x, y + 34, 10, 5, 1F, 0F, 0F); //THIS CODE TINTS THE PLAYER RED
}
public void setVelX(float velX) {
this.velX = velX;
}
public void setVelY(float velY) {
this.velY = velY;
}
public Rectangle getBounds() {
return new Rectangle((int)x, (int) y, 32, 32);
}
public Rectangle getBoundsTop() {
return new Rectangle((int)x + 7, (int) y + 26, 16, 6);
}
public Rectangle getBoundsBottom() {
return new Rectangle((int)x + 7, (int) y, 16, 6);
}
public Rectangle getBoundsLeft() {
return new Rectangle((int)x + 4, (int) y, 1, 32);
}
public Rectangle getBoundsRight() {
return new Rectangle((int)x + 31, (int) y, 1, 32);
}
public Rectangle getBoundsCentre() {
return new Rectangle((int)x + 20, (int) y, 4, 32);
}
}
Draw Class
package rpgmain;
import static org.lwjgl.opengl.GL11.*;
import org.newdawn.slick.opengl.*;
/**
*
* #author Samsung
*/
public class Draw {
public static void rect(float x, float y, float width, float height, Texture tex) {
glTranslatef(x, y, 0);
//glColor3f(1F, 1F, 1F);
glClearColor(0.7f, 0.7f, 0.7f, 1.0f);
tex.bind();
glBegin(GL_QUADS); //Specifies to the program where the drawing code begins. just to keep stuff neat. GL_QUADS specifies the type of shape you're going to be drawing.
{
//PNG format for images
glTexCoord2f(0,1); glVertex2f(0, 0); //Specify the vertices. 0, 0 is on BOTTOM LEFT CORNER OF SCREEN.
glTexCoord2f(0,0); glVertex2f(0, height); //2f specifies the number of args we're taking(2) and the type (float)
glTexCoord2f(1,0); glVertex2f(width, height);
glTexCoord2f(1,1); glVertex2f(width, 0);
}
glEnd();
}
public static void rect(float x, float y, float width, float height, Texture tex, float r, float g, float b) {
glTranslatef(x, y, 0);
glColor3f(r, g, b);
tex.bind();
glBegin(GL_QUADS); //Specifies to the program where the drawing code begins. just to keep stuff neat. GL_QUADS specifies the type of shape you're going to be drawing.
{
glTexCoord2f(0,0); glVertex2f(0, 0); //Specify the vertices. 0, 0 is on BOTTOM LEFT CORNER OF SCREEN.
glTexCoord2f(0,1); glVertex2f(0, height); //2f specifies the number of args we're taking(2) and the type (float)
glTexCoord2f(1,1); glVertex2f(width, height);
glTexCoord2f(1,0); glVertex2f(width, 0);
}
glEnd();
}
public static void rect(float x, float y, float width, float height, float r, float g, float b) {
glTranslatef(x, y, 0);
glColor3f(r, g, b); //Problem seems to be here
glBegin(GL_QUADS); //Specifies to the program where the drawing code begins. just to keep stuff neat. GL_QUADS specifies the type of shape you're going to be drawing.
{
glVertex2f(0, 0); //Specify the vertices. 0, 0 is on BOTTOM LEFT CORNER OF SCREEN.
glVertex2f(0, height); //2f specifies the number of args we're taking(2) and the type (float)
glVertex2f(width, height);
glVertex2f(width, 0);
}
glEnd();
}
}
I don't know whether to include other classes as well,but I guess I'll include the GameObject class as well.
GameObject Class
package rpgmain;
import java.awt.Rectangle;
import java.util.ArrayList;
/**
*
* #author Samsung
*/
public abstract class GameObject {
protected float x, y;
ObjectId id;
public GameObject(float x, float y, ObjectId id) {
this.x = x;
this.y = y;
this.id = id;
}
protected abstract void update(ArrayList<GameObject> objects);
protected abstract void render();
public abstract Rectangle getBounds();
public float getX() {
return x;
}
public void setX(float x) {
this.x = x;
}
public float getY() {
return y;
}
public void setY(float y) {
this.y = y;
}
public ObjectId getId() {
return id;
}
}
I figured it out. There where two main problems with my code, ll in the Draw class.
GL_TEXTURE_2D
I disabled this using glDisable(GL_Texture_2D) every time I started drawing a a normal non textured rectangle, and enabled it after I was done, and did the reverse in the texture drawing method (i.e. enable before start drawing, disable after finish). This resulted in the health bar actually showing up.
glColor3f(r, g, b);
This is the actual problem of the question. The rectangle ended up tinting every texture on the display because I did not know that glColor3f affects every Vertex you draw. So to tackle this, before drawing a textured QUAD, I set it's color to white first(using glColor4f(1f, 1f, 1f, 1f);) and everything rendered perfectly.
The changes:
public static void rect(float x, float y, float width, float height, Texture tex) {
glEnable(GL_TEXTURE_2D);
glTranslatef(x, y, 0);
glColor4f(1f, 1f, 1f, 1f); //NEEDS to be white before drawing, else stuff will tint.
tex.bind();
glBegin(GL_QUADS); //Specifies to the program where the drawing code begins. just to keep stuff neat. GL_QUADS specifies the type of shape you're going to be drawing.
{
//PNG format for images
glTexCoord2f(0,1); glVertex2f(0, 0); //Specify the vertices. 0, 0 is on BOTTOM LEFT CORNER OF SCREEN.
glTexCoord2f(0,0); glVertex2f(0, height); //2f specifies the number of args we're taking(2) and the type (float)
glTexCoord2f(1,0); glVertex2f(width, height);
glTexCoord2f(1,1); glVertex2f(width, 0);
}
glEnd();
glDisable(GL_TEXTURE_2D);
}
This is an update to a question I recently asked, but with new problems after I tried some stuff. What I want is to draw multiple circles on the screen. I created a class for the circle object. In my renderer class, I created an array list of these circles each with a different position. When called to draw, it only draws one of them. I logged what was going on and each object is being called to get drawn, but it seems only one appears on the screen. It's not just my circles. It appears throughout personal testing OpenGL ES 2.0 will only draw one object on the screen. I have no idea how to fix this. Is there something special I have to do in OpenGL ES 2.0? Here is my code. Ignore the incredibly sloppy and inefficient code right now. I am aware of it and will fix it later. Here is my circle object class:
GLCircle:
package com.background.gl.objects;
import static android.opengl.GLES20.GL_TRIANGLE_FAN;
import static android.opengl.GLES20.glDrawArrays;
import static android.opengl.Matrix.multiplyMM;
import static android.opengl.Matrix.setIdentityM;
import static android.opengl.Matrix.translateM;
import static com.background.gl.glcirclebackgroundanimation.Constants.BYTES_PER_FLOAT;
import java.util.Random;
import android.opengl.Matrix;
import android.util.Log;
import com.background.gl.data.VertexArray;
import com.background.gl.helper.TextureShaderProgram;
public class GLCircle {
private static final int POSITION_COMPONENT_COUNT = 2;
private static final int TEXTURE_COORDINATES_COMPONENT_COUNT = 2;
private static final int STRIDE = (POSITION_COMPONENT_COUNT
+ TEXTURE_COORDINATES_COMPONENT_COUNT) * BYTES_PER_FLOAT;
public float x;
public float y;
protected float[] wallBounds;
protected boolean positiveX, positiveY;
public boolean nullify;
protected float xCounter = 0f;
protected float yCounter = 0f;
public float[] bounds;
protected Random ran;
private float[] VERTEX_DATA = {
// Order of coordinates: X, Y, S, T
// Triangle Fan
0f, 0f, 0.5f, 0.5f,
-0.25f, -0.25f, 0f, 0.9f,
0.25f, -0.25f, 1f, 0.9f,
0.25f, 0.25f, 1f, 0.1f,
-0.25f, 0.25f, 0f, 0.1f,
-0.25f, -0.25f, 0f, 0.9f };
private final VertexArray vertexArray;
public GLCircle(float x, float y) {
vertexArray = new VertexArray(VERTEX_DATA);
ran = new Random();
wallBounds = new float[4];
nullify = false;
this.x = x;
this.y = y;
}
public void bindData(TextureShaderProgram textureProgram) {
//Bind the position data to the shader attribute
vertexArray.setVertexAttribPointer(
0,
textureProgram.getPositionAttributeLocation(),
POSITION_COMPONENT_COUNT,
STRIDE);
//Bind the texture coordinate data to the shader attribute
vertexArray.setVertexAttribPointer(
POSITION_COMPONENT_COUNT,
textureProgram.getTextureCoordinatesAttributeLocation(),
TEXTURE_COORDINATES_COMPONENT_COUNT,
STRIDE);
}
public void drawCircle() {
glDrawArrays(GL_TRIANGLE_FAN, 0, 6);
}
public float getX() {
return this.x;
}
public float getY() {
return this.y;
}
public boolean isPositiveX() {
return positiveX;
}
public boolean isPositiveY() {
return positiveY;
}
public float[] getBounds(float ranX, float ranY) {
if(!positiveX) {
/*if(ranX >= 0f) {
wallBounds[0] = 1.05f + ranX;
} else {*/
this.wallBounds[0] = 1.05f + ranX;
//}
} else {
/*
if(ranX >= 0f) {
wallBounds[0] = 1.05f - ranX;
} else {*/
this.wallBounds[1] = 1.05f - ranX;
//}
}
if(!positiveY) {
this.wallBounds[2] = 1.75f + ranY;
} else {
this.wallBounds[3] = 1.75f - ranY;
}
return this.wallBounds;
}
public void setPos(float[] modelMatrix,
float[] projectionMatrix, TextureShaderProgram textureProgram,
int texture, float x, float y, String log) {
setIdentityM(modelMatrix, 0);
translateM(modelMatrix, 0, 0f, 0.01f, 0f);
final float[] temp = new float[16];
multiplyMM(temp, 0, projectionMatrix, 0, modelMatrix, 0);
System.arraycopy(temp, 0, projectionMatrix, 0, temp.length);
textureProgram.useProgram();
textureProgram.setUniforms(projectionMatrix, texture);
bindData(textureProgram);
drawCircle();
Log.d("Drawing", "Drawing " + log);
}
public void scaleCircle(float[] modelMatrix, float x, float y, float z) {
Matrix.scaleM(modelMatrix, 0, x, y, z);
}
public void storeResults(float[] results) {
this.x = results[0];
this.y = results[1];
}
public void translateCircle(float x, float[] modelMatrix, float[] projectionMatrix) {
setIdentityM(modelMatrix, 0);
translateM(modelMatrix, 0, /*-0.001f*/ x, -3f, -2f);
final float[] temp = new float[16];
multiplyMM(temp, 0, projectionMatrix, 0, modelMatrix, 0);
System.arraycopy(temp, 0, projectionMatrix, 0, temp.length);
}
}
Again, I'm aware of most things I'm doing incorrectly, but currently I just need to figure out why I can't draw multiple objects on the screen. Here is my renderer code:
package com.background.gl.glcirclebackgroundanimation;
import static android.opengl.GLES20.GL_COLOR_BUFFER_BIT;
import static android.opengl.GLES20.glClear;
import static android.opengl.GLES20.glClearColor;
import static android.opengl.GLES20.glViewport;
import static android.opengl.Matrix.multiplyMM;
import static android.opengl.Matrix.setIdentityM;
import static android.opengl.Matrix.translateM;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import android.content.Context;
import android.opengl.GLSurfaceView.Renderer;
import android.util.Log;
import com.background.gl.helper.TextureShaderProgram;
import com.background.gl.objects.GLCircle;
import com.background.gl.objects.Mallet;
import com.background.gl.objects.Table;
import com.background.gl.util.MatrixHelper;
import com.background.gl.util.TextureHelper;
public class CircleDynamicBackgroundRenderer implements Renderer {
private final Context context;
private final float[] projectionMatrix = new float[16];
private final float[] modelMatrix = new float[16];
protected static float ranX,
ranY, ranSignX, ranSignY, ranSignVeloX, ranSignVeloY;
public boolean logNums;
private Table table;
private Mallet mallet;
private List<GLCircle> circles;
private GLCircle circle2;
float xPos, yPos;
int x = 1;
float[] bounds;
Random ran;
private TextureShaderProgram textureProgram;
private int texture;
public CircleDynamicBackgroundRenderer(Context context) {
this.context = context;
circles = new ArrayList<GLCircle>();
xPos = 0.1f;
ran = new Random();
logNums = true;
}
#Override
public void onSurfaceChanged(GL10 glUnused, int width, int height) {
glViewport(0, 0, width, height);
Log.w("Width and height", Integer.toString(width) + ", " + Integer.toString(height));
MatrixHelper.perspectiveM(projectionMatrix, 90, (float) width
/ (float) height, 1f, 10f);
for(int i = 0; i < circles.size(); i++) {
circles.get(i).translateCircle(circles.get(i).x, modelMatrix, projectionMatrix);
}
// /circle2.translateCircle(circle2.x, modelMatrix);
/*final float[] temp = new float[16];
multiplyMM(temp, 0, projectionMatrix, 0, modelMatrix, 0);
System.arraycopy(temp, 0, projectionMatrix, 0, temp.length);*/
}
#Override
public void onSurfaceCreated(GL10 glUnused, EGLConfig config) {
glClearColor(0.0f, 0.0f, 1.0f, 0.0f);
table = new Table();
mallet = new Mallet();
textureProgram = new TextureShaderProgram(context);
texture = TextureHelper.loadTexture(context, R.drawable.air_hockey_surface);
//texture2 = TextureHelper.loadTexture(context, R.drawable.air_hockey_surface_2);
for(int i = 0; i < 3; i++) {
GLCircle circle = new GLCircle(generateRanFloats()[0], generateRanFloats()[1]);
circles.add(circle);
/*circle[i].x = circle[i].getX();
circle[i].y = circle[i].getY();
circle[i].bounds = circle[i].getBounds();*/
}
//circle2 = new GLCircle(generateRanFloats()[0], generateRanFloats()[1]);
Log.d("Circles size", Integer.toString(circles.size()));
Log.d("circles", Float.toString(circles.get(1).getX()) + " " + Float.toString(circles.get(2).getX()));
}
#Override
public void onDrawFrame(GL10 glUnused) {
//Clear the rendering surface
glClear(GL_COLOR_BUFFER_BIT);
for(int i = 0; i < circles.size(); i++) {
circles.get(i).setPos(modelMatrix, projectionMatrix, textureProgram, texture, circles.get(i).x, circles.get(i).y, "1"); if(logNums) {
Log.d("Circle1, c2", Float.toString(circles.get(i).x) + ", " + Float.toString(circles.get(i).x));
logNums = false;
}
//Log.d("Circles", Float.toString(circles.get(i).x));
}
}
public float[] generateRanFloats() {
ranSignX = ran.nextFloat();
ranSignY = ran.nextFloat();
ranSignX = ranSignX > 0.5f? -1:1;
ranSignY = ranSignY > 0.5f? -1:1;
ranSignVeloX = ran.nextFloat();
ranSignVeloY = ran.nextFloat();
ranX = ran.nextFloat() * 1.05f;
ranY = ran.nextFloat() * 1.75f;
ranX = ranSignX > 0.5? -ranX:ranX;
ranY = ranSignY > 0.5? -ranY:ranY;
Log.d("Generated", Float.toString(ranX));
return new float[] {ranX, ranY};
}
}
It's been two days now and I cannot for the live of me figure out what is wrong and how to fix this. I really need to figure out a way to fix this. Any assistance will be greatly appreciated. If you need to see more code, let me know.
Per the last discussion - did you work on the perspective matrix ? I would recommend first starting with the ortho projection, get your code working, then move to working with perspective projection. You can use the below as a starting point for ortho projection.
mat4.ortho(-1.0, 1.0, -1, 1.0, -10.0, 100.0, projectionMatrix);
Also remove all the z translations in your code, make your code work on xy, then add z translations.
PS: Isnt it better to continue in the same thread as (OpenGL ES 2.0 only draws the object once) ?
I have a problem with what seems to be binding the textures to a shape. When I do so, I get a white shape of the correct dimensions, the color given to it by Color.white.bind().
GraphicsManager.java
package com.jackwilsdon.spectrun;
import java.io.IOException;
import org.lwjgl.LWJGLException;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.GL11;
import org.lwjgl.util.vector.Vector2f;
import org.newdawn.slick.Color;
import org.newdawn.slick.opengl.Texture;
import org.newdawn.slick.opengl.TextureLoader;
import org.newdawn.slick.util.ResourceLoader;
public class GraphicsManager {
final static int WIDTH = 800;
final static int HEIGHT = 600;
private static Texture cloudTexture = null;
public static void initDisplay() throws LWJGLException
{
Display.setDisplayMode(new DisplayMode(WIDTH, HEIGHT));
Display.create();
}
public static void initOpenGL()
{
GL11.glMatrixMode(GL11.GL_PROJECTION);
GL11.glLoadIdentity();
GL11.glOrtho(0, WIDTH, 0, HEIGHT, 1, -1);
GL11.glMatrixMode(GL11.GL_MODELVIEW);
}
public static void loadTextures()
{
Texture currentObject = null;
try {
currentObject = TextureLoader.getTexture("PNG", ResourceLoader.getResourceAsStream("./resources/cloud.png"));
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("Texture loaded: "+currentObject);
System.out.println(">> Image width: "+currentObject.getImageWidth());
System.out.println(">> Image height: "+currentObject.getImageHeight());
System.out.println(">> Texture width: "+currentObject.getTextureWidth());
System.out.println(">> Texture height: "+currentObject.getTextureHeight());
System.out.println(">> Texture ID: "+currentObject.getTextureID());
cloudTexture = currentObject;
}
public static void DrawRectangle(int x, int y, int width, int height)
{
GL11.glBegin(GL11.GL_QUADS);
GL11.glVertex2f(x,y);
GL11.glVertex2f(x+width,y);
GL11.glVertex2f(x+width,y+height);
GL11.glVertex2f(x,y+height);
GL11.glEnd();
}
public static void DrawRectangle(int x, int y, int width, int height, int red, int green, int blue)
{
GL11.glColor3ub((byte)red, (byte)green, (byte)blue);
DrawRectangle(x, y, width, height);
}
public static Vector2f DrawCloud(int x, int y)
{
cloudTexture.bind();
int width = cloudTexture.getImageWidth();
int height = cloudTexture.getImageHeight();
GL11.glBegin(GL11.GL_QUADS);
GL11.glVertex2f(x,y);
GL11.glVertex2f(x+width,y);
GL11.glVertex2f(x+width,y+height);
GL11.glVertex2f(x,y+height);
GL11.glEnd();
return new Vector2f(cloudTexture.getImageWidth(), cloudTexture.getImageHeight());
}
}
I suspect it has something to do with my initOpenGL() method, as in an example I have looked at (http://ninjacave.com/slickutil1), theirs is very different. Just copying theirs into mine gives unexpected results (black screen). Is something missing from my initOpenGL() method?
EDIT: The loadTextures() method outputs the correct image dimensions, but the texture's dimensions are different, what does this mean?
EDIT 2: The PNG is not the problem, I've tried 2 others to find the same result.
A new problem has arisen after fixing my code, by setting the texture coordinates.
I now get a weird effect, like this; i.imgur.com/5lr79.png. The image is no longer full size, and has a black box to the bottom left of it.
GraphicsManager.java
package com.jackwilsdon.spectrun;
import java.io.IOException;
import org.lwjgl.LWJGLException;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.GL11;
import org.lwjgl.util.vector.Vector2f;
import org.newdawn.slick.Color;
import org.newdawn.slick.opengl.Texture;
import org.newdawn.slick.opengl.TextureLoader;
import org.newdawn.slick.util.ResourceLoader;
public class GraphicsManager {
final static int WIDTH = 800;
final static int HEIGHT = 600;
private static Texture cloudTexture = null;
public static void initDisplay() throws LWJGLException
{
Display.setDisplayMode(new DisplayMode(WIDTH, HEIGHT));
Display.create();
}
public static void initOpenGL()
{
GL11.glEnable(GL11.GL_TEXTURE);
GL11.glMatrixMode(GL11.GL_PROJECTION);
GL11.glLoadIdentity();
GL11.glOrtho(0, WIDTH, 0, HEIGHT, 1, -1);
GL11.glMatrixMode(GL11.GL_MODELVIEW);
}
public static void loadTextures()
{
Texture currentObject = null;
try {
currentObject = TextureLoader.getTexture("PNG", ResourceLoader.getResourceAsStream("./resources/cloud.png"));
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("Texture loaded: "+currentObject);
System.out.println(">> Image width: "+currentObject.getImageWidth());
System.out.println(">> Image height: "+currentObject.getImageHeight());
System.out.println(">> Texture width: "+currentObject.getTextureWidth());
System.out.println(">> Texture height: "+currentObject.getTextureHeight());
System.out.println(">> Texture ID: "+currentObject.getTextureID());
cloudTexture = currentObject;
}
public static void DrawRectangle(int x, int y, int width, int height)
{
GL11.glBegin(GL11.GL_QUADS);
GL11.glVertex2f(x,y);
GL11.glVertex2f(x+width,y);
GL11.glVertex2f(x+width,y+height);
GL11.glVertex2f(x,y+height);
GL11.glEnd();
}
public static void DrawRectangle(int x, int y, int width, int height, int red, int green, int blue)
{
GL11.glColor3ub((byte)red, (byte)green, (byte)blue);
DrawRectangle(x, y, width, height);
}
public static Vector2f DrawCloud(int x, int y)
{
cloudTexture.bind();
int width = cloudTexture.getImageWidth();
int height = cloudTexture.getImageHeight();
GL11.glBegin(GL11.GL_QUADS);
GL11.glTexCoord2f(1,1);
GL11.glVertex2f(x,y);
GL11.glTexCoord2f(0,1);
GL11.glVertex2f(x+width,y);
GL11.glTexCoord2f(0,0);
GL11.glVertex2f(x+width,y+height);
GL11.glTexCoord2f(1,0);
GL11.glVertex2f(x,y+height);
GL11.glEnd();
return new Vector2f(cloudTexture.getImageWidth(), cloudTexture.getImageHeight());
}
}
It doesn't help that you aren't calling GL11.glEnable( GL11.GL_TEXTURE ) and you also aren't setting any texture coordinates.
Both of these will rather mess up your ability to see a texture on the quad ...
I do believe the call to bind() needs to be between your glBegin() and glEnd() call to make it stick. The dimension problem is somewhat more odd - perhaps your texture dimensions are not a power of 2 and it is being translated by the driver?
You didnt enable gl_TEXTURE_2D first of all. Second, you need to call .bind() inside glBegin() and your glEnd(). Third, you need texture coordinates. So, for the top left edge it would be 'glTexCoord(0, 0)', the next would be '(1, 0)' and then '(1, 1)' and lastly '(0, 1)'
Don't forget to call TextureImpl.unbind when needed.
I'm following the tutorial set found at insanitydesign.com, which is an Android port of the NeHe tutorials on OpenGL. I'm having a lot of problems understanding why the tutorial version appears to render correctly at all times while my modified version randomly renders completely incorrectly. Occasionally, the problem is evident immediately when the program loads, but sometimes I have to rotate the screen before it appears. You can download a zip file containing screengrabs where I've rotated the screen 12 times from filedropper. As you can see, the triangle usually renders but on occasion appears completely distorted and smudged. Here is a link to my entire Eclipse project if you're curious.
I suspect the problem is in my Shape.draw() method, but I can't know for sure.
This is, I believe, the relevant code:
GLRenderer.java
private Shape shape;
public GLRenderer(){
Log.i(this.toString(),"ctor");
shape = Shape.makeTriangle();
}
#Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
speedPerSecond = SystemClock.uptimeMillis();
Log.d(this.toString(), ".onSurfaceCreated");
gl.glShadeModel(GL10.GL_SMOOTH);
gl.glClearColor(1.0f, 0.0f, 0.0f, 0.5f);
gl.glClearDepthf(1.0f); //Depth Buffer Setup
gl.glEnable(GL10.GL_DEPTH_TEST); //Enables Depth Testing
gl.glDepthFunc(GL10.GL_LEQUAL); //The Type Of Depth Testing To Do
//Really Nice Perspective Calculations
gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST);
}
#Override
public void onDrawFrame(GL10 gl) {
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
gl.glLoadIdentity();
shape.setX(0.0f);
shape.setY(0.0f);
shape.setZ(-6.0f);
shape.draw(gl);
}
#Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
if(height == 0){
height = 1;
}
gl.glViewport(0, 0, width, height);
gl.glMatrixMode(GL10.GL_PROJECTION);
gl.glLoadIdentity();
GLU.gluPerspective(gl, 45.0f, (float)width / (float)height, 0.1f, 50.0f);
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadIdentity();
}
Shape.java
package com.smashing.test;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import javax.microedition.khronos.opengles.GL10;
import android.util.Log;
public class Shape implements IGLShape {
public float getX(){
return x;
}
public float getY(){
return y;
}
public float getZ(){
return z;
}
public void setX(float pX){
x = pX;
}
public void setY(float pY){
y = pY;
}
public void setZ(float pZ){
z = pZ;
}
public static Shape makeTriangle(){
Shape s = new Shape();
/*
* Is this correct? I want to create a right triangle on screen like this
* |\
* | \
* | \
* | \
* |____\ though with a 90/45/45 degree spread rather than this poor representation.
*/
float v[] = {
0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f,
1.0f, 0.0f, 0.0f
};
s.setVertices(v);
return s;
}
public static Shape makeShapeFromVertices(float pVerts[]){
Shape s = new Shape();
s.setVertices(pVerts);
return s;
}
private float x = 0.0f;
private float y = 0.0f;
private float z = 0.0f;
private float[] mVertices;
private FloatBuffer mVertexBuffer;
public void setVertices(float pVerts[]){
mVertices = pVerts;
ByteBuffer bb = ByteBuffer.allocateDirect(mVertices.length * 4);
bb.order(ByteOrder.nativeOrder());
mVertexBuffer = bb.asFloatBuffer();
mVertexBuffer.put(mVertices);
mVertexBuffer.position(0);
}
public float[] getVertices(){
return mVertices;
}
private Shape(){
}
#Override
public void draw(GL10 gl) {
/*
* I believe the problem is here... but I don't understand how or why?
*/
gl.glTranslatef(x, y, z);
gl.glFrontFace(GL10.GL_CW);
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mVertexBuffer);
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, mVertices.length);
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
gl.glTranslatef(-x, -y, -z);
}
}
EDIT: I am aware that the tutorial is a little different than my version. I'm attempting to extrapolate from it and experiment... I'm just completely surprised and astounded at the differences and would like to know why they exist, and how I can avoid such an unpleasant outcome as I've found with my rendering scheme.
you should replace
glDrawArrays(GL10.GL_TRIANGLE_STRIP, ...)
with
glDrawArrays(GL10.GL_TRIANGLES, ...)
I think that as you're drawing a simple triangle and not a quad, that is the cause of the trouble.
Regards