I'm trying to load a simple background texture for the menu of a game I'm creating, but the texture isn't displayed properly.
For example, if I use this texture: http://s15.postimage.org/mqvuhq463/Super_Mario_Galazy_Background.png the entire background is blue and if I use this texture: http://www.highresolutiontextures.com/wp-content/uploads/2010/11/food-textures-01-bowtie-pasta-texture.jpg the entire background is a shade of orange.
This is the code I've written:
public class Menu extends Painter
{
public Menu(GLCanvas canvas, Animator animator, GameWindow window)
{
super(canvas, animator, window);
}
#Override
public void display(GLAutoDrawable drawable)
{
GL gl = drawable.getGL();
drawBackground(gl);
gl.glFlush();
}
private void drawBackground(GL gl)
{
Texture background = textureLoader.getTexture("background");
background.enable();
background.bind();
gl.glBegin(GL.GL_QUADS);
gl.glVertex2f(0f, 0f);
gl.glVertex2f(0f, window.getHeight());
gl.glVertex2f(window.getWidth(), window.getHeight());
gl.glVertex2f(window.getWidth(), 0);
gl.glEnd();
background.disable();
}
#Override
public void init(GLAutoDrawable drawable)
{
GL gl = drawable.getGL();
textureLoader = new TextureLoader("menu textures/", gl);
gl.glMatrixMode(GL.GL_PROJECTION);
gl.glLoadIdentity();
// set ortho to the size of the background
gl.glOrtho(0, 800, 800, 0, -1, 1);
gl.glMatrixMode(GL.GL_MODELVIEW_MATRIX);
gl.glClearColor(0f, 0f, 0f, 0f);
gl.glClear(GL.GL_COLOR_BUFFER_BIT);
}
}
I haven't got the slightest clue how this is even possible, so any help would be greatly appreciated.
You don't supply texture coordinates. Without texture coordinates all vertices receive the default texture coordinate, which is (0,0,0,0), which is the bottom left corner. If you look at your texture images the colors you see, are the colors of the bottom left pixel of each picture.
Solution: Supply texture coordinates. Texture coordinates are in the range [0; 1].
Related
I want to render a cube with three faces visible, each of those faces should have a different texture applied to it, which should be easily interchangable. I managed to get this basic code running, that only works with colors.
import com.jogamp.opengl.*;
import com.jogamp.opengl.awt.GLJPanel;
import javax.swing.*;
import java.awt.*;
import static com.jogamp.opengl.GL.GL_MULTISAMPLE;
public class CubeRenderer extends GLJPanel implements GLEventListener {
public static void main(String[] args) {
JFrame window = new JFrame("JOGL Scene");
GLCapabilities caps = new GLCapabilities(null);
CubeRenderer panel = new CubeRenderer(caps);
window.setContentPane(panel);
window.pack();
window.setLocation(50,50);
window.setResizable(false);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setVisible(true);
panel.requestFocusInWindow();
}
private final float rotateX;
private final float rotateY;
private final float rotateZ; // rotation amounts about axes
private int texture;
// Correct orientation -45.0, 150.0, 90.0
public CubeRenderer(GLCapabilities capabilities) {
super(capabilities);
setPreferredSize( new Dimension(500,500) );
addGLEventListener(this);
rotateX = -45.0f;
rotateY = 150.0f;
rotateZ = 90.0f;
}
private void square(GL2 gl, float r, float g, float b) {
gl.glColor3f(r,g,b); // The color for the square.
gl.glTranslatef(0,0,0.5f); // Move square 0.5 units forward.
gl.glNormal3f(0,0,1); // Normal vector to square (this is actually the default).
gl.glBegin(GL2.GL_TRIANGLE_FAN);
gl.glVertex2f(-0.5f,-0.5f); // Draw the square (before the
gl.glVertex2f(0.5f,-0.5f); // the translation is applied)
gl.glVertex2f(0.5f,0.5f); // on the xy-plane, with its
gl.glVertex2f(-0.5f,0.5f); // at (0,0,0).
gl.glEnd();
}
private void cube(GL2 gl) {
gl.glPushMatrix();
gl.glRotatef(180,0,1,0); // rotate square to back face
square(gl,0,1,1); // back face is cyan
gl.glPopMatrix();
gl.glPushMatrix();
gl.glRotatef(-90,0,1,0); // rotate square to left face
square(gl,0,1,0); // left face is green
gl.glPopMatrix();
gl.glPushMatrix();
gl.glRotatef(-90,1,0,0); // rotate square to top face
square(gl,0,0,1); // top face is blue
gl.glPopMatrix();
}
public void display(GLAutoDrawable drawable) {
// called when the panel needs to be drawn
GL2 gl = drawable.getGL().getGL2();
gl.glClearColor(0,0,0,0);
gl.glClear( GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT );
gl.glMatrixMode(GL2.GL_PROJECTION); // Set up the projection.
gl.glLoadIdentity();
gl.glOrtho(-1,1,-1,1,-2,2);
gl.glMatrixMode(GL2.GL_MODELVIEW);
gl.glLoadIdentity(); // Set up modelview transform.
gl.glRotatef(rotateZ,0,0,1);
gl.glRotatef(rotateY,0,1,0);
gl.glRotatef(rotateX,1,0,0);
cube(gl);
}
public void init(GLAutoDrawable drawable) {
// called when the panel is created
GL2 gl = drawable.getGL().getGL2();
gl.glClearColor(0.8F, 0.8F, 0.8F, 1.0F);
gl.glEnable(GL.GL_DEPTH_TEST);
gl.glEnable(GL2.GL_LIGHTING);
gl.glEnable(GL2.GL_LIGHT0);
gl.glEnable(GL2.GL_COLOR_MATERIAL);
gl.glEnable(GL_MULTISAMPLE);
}
public void dispose(GLAutoDrawable drawable) {
// called when the panel is being disposed
}
public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
// called when user resizes the window
}
}
I however could not figure out how to apply texture instead of colors and how to then render the whole cube into a png, as I could not get any of these tutorials to run, as most of them were quite old.
Either merge the 3 images into a single image, create a single texture, bind it, enable texture target and use your texture as a texture atlas by using appropriate texture coordinates (see glTexCoords) or create 3 textures for your 3 images and perform enable/bind/draw/disable for each texture.
Have a look at TextureIO, AWTTextureIO, glBindTexture, glEnable, glDisable and glTexCoord2f.
Please note that my answer assumes that you use the fixed pipeline but using the programmable pipeline would be preferable on the long term. You should use the retained mode (VAOs, VBOs, ...) even though you use the fixed pipeline instead of the immediate mode (glBegin, glEnd, glVertex, ...) in my humble opinion.
I want to write an app which displays text for exactly 1/60 seconds (framerate = 60 Hz) on a device.
What is the best way to manage this task ?
I first tried it without OpenGL by using an ImageView, but the time management isn't easy that way, because I haven't access on the renderer. Or is there a way how to have access on the renderer ?
My following code doesn't display "T E S T I N G" with OpenGL and I don't know why.
public class MainActivity extends AppCompatActivity implements GLSurfaceView.Renderer {
// The texture pointer
private int[] textures = new int[1];
private Bitmap bitmap;
private Canvas canvas;
private Drawable background;
private Paint textPaint;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
GLSurfaceView glSurfaceView = new GLSurfaceView(this);
// OpenGL Version 2
glSurfaceView.setEGLContextClientVersion(2);
// bits for the channels of output image (red, green, blue, alpha, depth, stencil)
glSurfaceView.setEGLConfigChooser(8, 8, 8, 8, 16, 0);
// Activity acts as the Renderer
glSurfaceView.setRenderer(this);
// update on demand
glSurfaceView.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
// our bitmap
bitmap = Bitmap.createBitmap(256, 256, Bitmap.Config.ARGB_4444);
// get a canvas to paint over the bitmap
canvas = new Canvas(bitmap);
bitmap.eraseColor(0);
// get a background image from resources
// note the image format must match the bitmap format
background = this.getApplicationContext().getResources().getDrawable(R.drawable.background);
background.setBounds(0, 0, 256, 256);
// draw the background to our bitmap
background.draw(canvas);
// draw the text
textPaint = new Paint();
textPaint.setTextSize(32);
textPaint.setAntiAlias(true);
textPaint.setARGB(0xff, 0x00, 0x00, 0x00);
// draw the text centered
canvas.drawText("T E S T I N G", 16, 112, textPaint);
}
// when OpenGL starts up
#Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
// default state to background color light grey state
GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
}
// called as often as possible => high frame rate
#Override
public void onDrawFrame(GL10 gl) {
// clear the color buffer (bitmaps)
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
// generate one texture pointer...
gl.glGenTextures(1, textures, 0);
//...and bind it to our array
gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);
// create Nearest Filtered Texture
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
// different possible texture parameters, e.g. GL10.GL_CLAMP_TO_EDGE
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_REPEAT);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_REPEAT);
// use the Android GLUtils to specify a two-dimensional texture image from our bitmap
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);
// clean up
bitmap.recycle();
}
// for resizing purposes
#Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
// when size of the GLSurfaceView changes we also want to change the size of the rendering view port to be the same
GLES20.glViewport(0, 0, width, height);
}}
You will find a good place to start with a GLSurfaceView here:
https://developer.android.com/training/graphics/opengl/environment.html
However, for text, simply draw text to a texture and render the texture. See this answer for how to do just that: https://stackoverflow.com/a/4336679/2979092
To ensure the use of GLES 2.0 add this to your manifest
<uses-feature android:glEsVersion="0x00020000" android:required="true" />
Extend the GLSurfaceView
class MyGLSurfaceView extends GLSurfaceView {
private final MyGLRenderer mRenderer;
public MyGLSurfaceView(Context context){
super(context);
setEGLContextClientVersion(2);
mRenderer = new MyGLRenderer(); // extended GLSurfaceView.Renderer
setRenderer(mRenderer);
}
}
Your renderer skeleton
public class MyGLRenderer implements GLSurfaceView.Renderer {
public void onSurfaceCreated(GL10 unused, EGLConfig config) {
GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
}
public void onDrawFrame(GL10 unused) {
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
}
public void onSurfaceChanged(GL10 unused, int width, int height) {
GLES20.glViewport(0, 0, width, height);
}
}
To update on demand set
setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
Render text to a texture using a Bitmap (copied from linked answer)
Bitmap bitmap = Bitmap.createBitmap(256, 256, Bitmap.Config.ARGB_4444);
// get a canvas to paint over the bitmap
Canvas canvas = new Canvas(bitmap);
bitmap.eraseColor(0);
// get a background image from resources
// note the image format must match the bitmap format
Drawable background = context.getResources().getDrawable(R.drawable.background);
background.setBounds(0, 0, 256, 256);
background.draw(canvas); // draw the background to our bitmap
// Draw the text
Paint textPaint = new Paint();
textPaint.setTextSize(32);
textPaint.setAntiAlias(true);
textPaint.setARGB(0xff, 0x00, 0x00, 0x00);
// draw the text centered
canvas.drawText("Hello World", 16,112, textPaint);
//Generate one texture pointer...
gl.glGenTextures(1, textures, 0);
//...and bind it to our array
gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);
//Create Nearest Filtered Texture
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
//Different possible texture parameters, e.g. GL10.GL_CLAMP_TO_EDGE
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_REPEAT);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_REPEAT);
//Use the Android GLUtils to specify a two-dimensional texture image from our bitmap
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);
//Clean up
bitmap.recycle();
You will also need to bind a shader program before rendering if you're using GLES 2.0.
When I tried draw a Texture using SpriteBatch it was result flip like this:
Here what I do:
I create MyRect object which draw bounding rectangle and an image.
Here MyRect class preview:
public class MyRect {
private Vector2 position;
private int width;
private float height;
private Texture img;
private Sprite sprite;
public MyRect(int x, int y, int width, int height){
img = new Texture("badlogic.jpg");
sprite = new Sprite(img);
position = new Vector2(x,y);
this.width = width;
this.height = height;
}
public void draw(ShapeRenderer shapeRenderer, SpriteBatch batch){
// Gdx.gl.glClearColor(0, 0, 0, 1);
// Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
shapeRenderer.begin(ShapeType.Line);
// Draw Background color
shapeRenderer.setColor(55 / 255.0f, 80 / 255.0f, 100 / 255.0f, 1);
shapeRenderer.rect(position.x, position.y, width, height);
shapeRenderer.end();
batch.begin();
// batch.disableBlending();
batch.draw(img, position.x, position.y,
width, height);
batch.end();
}
}
Parameters ShapeRenderer and SpriteBatch pass by GameScreen class.
GameScreen preview:
public class GameScreen implements Screen{
private MyRect myRect;
private ShapeRenderer shapeRenderer;
private SpriteBatch batch;
private OrthographicCamera cam;
public GameScreen(){
myRect = new MyRect(10,10,50,50);
int gameHeight=100;
cam = new OrthographicCamera();
cam.setToOrtho(true, 136, gameHeight);
batch = new SpriteBatch();
batch.setProjectionMatrix(cam.combined);
shapeRenderer = new ShapeRenderer();
shapeRenderer.setProjectionMatrix(cam.combined);
}
#Override
public void render(float delta) {
// TODO Auto-generated method stub
myRect.draw(shapeRenderer, batch);
}
}
Why is this happen? Am I doing it wrong?
Your camera is upside down because you called setToOrtho(true, ...) on it instead of setToOrtho(false, ...)
It is valid to use an upside-down camera (which might be more comfortable if you've used Flash or some other Y-down system before), but then you need to flip all your TextureRegions (aka Sprites): sprite.flip(false, true). Alternatively, you can create a TextureAtlas using TexturePacker (look it up in libgdx documentation) and set the flipY option, so it flips them ahead of time for you. Eventually, for performance you will need to use a TextureAtlas anyway.
By the way, when you start drawing multiple instances of MyRect, you are going to need to move the spriteBatch.begin() and end() and shapeRenderer.begin() and end() out of the individual MyRect's draw method or you will run into a performance problem. And as such, there will need to be two draw methods (one for sprite batch and one for shape renderer).
apparently, the only thing I see different than how I would do, is try to change:
this meybe if it works"for test"
cam.setToOrtho(false, 136, gameHeight);
this is how I use the camera.
I do not know whether to use true, you have to do some different way, to draw the batch, in anyway. if the camera false, it looks good, I think it has to flip the image before to draw uv
I'm trying to write a java opengl (JOGL) method that writes to an offscreen drawable and then writes that to an image. I have verified this works when using an onscreen drawable as well as GLP buffers, but the output image in its current state is just solid black. The code is below.
GLProfile glp = GLProfile.getDefault();
GLCapabilities caps = new GLCapabilities(glp);
caps.setOnscreen(false);
// create the offscreen drawable
GLDrawableFactory factory = GLDrawableFactory.getFactory(glp);
GLOffscreenAutoDrawable drawable = factory.createOffscreenAutoDrawable(null,caps,null,width,height);
drawable.display();
drawable.getContext().makeCurrent();
// a series of x/y coordinates
FloatBuffer buffer = generateData();
GL2 gl = drawable.getGL().getGL2();
// use pixel coordinates
gl.glMatrixMode(GLMatrixFunc.GL_PROJECTION);
gl.glLoadIdentity();
gl.glOrtho(0d, width, height, 0d, -1d, 1d);
// draw some points to the drawable
gl.glPointSize(4f);
gl.glColor3f(1f,0f,0f);
gl.glEnableClientState(GL2.GL_VERTEX_ARRAY);
gl.glVertexPointer(2, GL2.GL_FLOAT, 0, buffer);
gl.glDrawArrays(GL2.GL_POINTS, 0, numPoints);
BufferedImage im = new AWTGLReadBufferUtil(drawable.getGLProfile(), false).readPixelsToBufferedImage(drawable.getGL(), 0, 0, width, height, true /* awtOrientation */);
ImageIO.write(im,"png",new File("im.png"));
This is a bit old, but I found a solution to the problem that seems to work for me. I just added an ordinary GLEventListener object right before calling .display() on the drawable, as such:
//...
drawable.addGLEventListener(new OffscreenJOGL());
drawable.display();
//Move drawing code to OffscreenJOGL
BufferedImage im = new AWTGLReadBufferUtil(drawable.getGLProfile(), false).readPixelsToBufferedImage(drawable.getGL(), 0, 0, width, height, true /* awtOrientation */);
ImageIO.write(im,"png",new File("im.png"));
The code to draw now should be in your custom OffscreenJOGL class, under the init(...), reshape(...) and display(...) methods. Note that setting the current context must be in the init(...) method of OffscreenJOGL. I get an exception thrown otherwise.
class OffscreenJOGL implements GLEventListener {
public void init(GLAutoDrawable drawable) {
drawable.getContext().makeCurrent();
//Other init code here
}
public void display(GLAutodrawable drawable) {
//Code for drawing here
}
public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
//Called at least once after init(...) and before display(...)
}
public void dispose(GLAutoDrawable drawable) {
//Dispose code here
}
}
Most likely you might have found the required answer for your query.
If not, I suggest to add a line, for example:
gl.glClearColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha)
I have tested it, and it works.
I want to rotate my cube and add 4 buttons to speed up speed down move up and move down. Could you help me? The color is yellow. 4 buttons under cube.cube should rotate about y axis.
public class MyGLRenderer implements Renderer {
Context context;
Cube cube;
public MyGLRenderer(Context context) {
this.context = context;
cube = new Cube();
}
// Call back when the surface is first created or re-created
#Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
// clear-value for color and depth, enabling depth-test, etc.
gl.glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // Set color's clear-value to black
}
// Call back after onSurfaceCreated() or whenever the window's size changes
#Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
if (height == 0)
height = 1;
float aspect = (float) width / height;
// Set the viewport (display area) to cover the entire window
gl.glViewport(0, 0, width, height);
// Select projection matrix: projection matrix or model-view matrix
gl.glMatrixMode(GL10.GL_PROJECTION);
// Reset projection matrix
gl.glLoadIdentity();
GLU.gluPerspective(gl, 45, aspect, 0.1f, 100.f);
// Select model-view matrix
gl.glMatrixMode(GL10.GL_MODELVIEW);
// Reset
gl.glLoadIdentity();
}
// Call back to draw the current frame.
#Override
public void onDrawFrame(GL10 gl) {
// Clear color and depth buffers using clear-value set earlier
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
// Reset model-view matrix
gl.glLoadIdentity();
// Translate into the screen
gl.glTranslatef(0.0f, 0.0f, -5.0f);
// Draw cube
cube.draw(gl);
}
}
this is what you are looking for: https://www.opengl.org/sdk/docs/man2/xhtml/glRotate.xml and you have to place it in front of glTranslatef