So I'm trying to change the texture using FBOs, When I run it, The whole game gets drawn in the new FBO that I created then deleted, Here's the function
public void ChangeTextureBuffer(int width, int height, ByteBuffer newBuffer) {
int frameID = glGenFramebuffers();
glBindFramebuffer(GL_FRAMEBUFFER, frameID);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, ID, 0);
glViewport(0, 0, width, height);
Texture texture = new Texture(width, height, newBuffer);
glBindTexture(GL_TEXTURE_2D, texture.ID);
glBegin(GL_QUADS);
glTexCoord2f(0, 0);
glVertex2f(-1, -1);
glTexCoord2f(1, 0);
glVertex2f(1, -1);
glTexCoord2f(1, 1);
glVertex2f(1, 1);
glTexCoord2f(0, 1);
glVertex2f(-1, 1);
glEnd();
texture.Delete();
glDeleteFramebuffers(frameID);
glBindTexture(GL_TEXTURE_2D, 0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
And here's what I'm getting
https://i.stack.imgur.com/fanSD.png
It's getting drawn where I want it to be with the size that I want, I just don't want everything to be drawn there.
Here's how its supposed to look, Everything getting drawn in its place, I just want to change the text on the bottom left side to show the FPS
https://i.stack.imgur.com/Mc2JT.png
Also when I delete a texture or framebuffer, OpenGL isn't reusing the id, I don't know if that's a feature or a bug.
Related
I use this to initiate openGL:
GL11.glMatrixMode(GL11.GL_PROJECTION);
GL11.glLoadIdentity();
GL11.glOrtho(0, width, height, 0, -1, 1);
GL11.glViewport(0, 0, width, height);
GL11.glMatrixMode(GL11.GL_MODELVIEW);
I create a True Type Font like this:
Font awtFont = new Font(font, i, size);
return new TrueTypeFont(awtFont, false);
However binding/ unbinding a texture messes up the font, forcing me to re-crate the font every time i want to draw some text. I can not afford to do this as it causes a major lag spike.
This is the method i use to draw textures:
public static void drawImage(image i, int x, int y) {
i.bind();
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glBegin(7);
{
glTexCoord2f(0, 0);
glVertex2f(x, y);
glTexCoord2f(0, 1);
glVertex2f(x, y + i.height);
glTexCoord2f(1, 1);
glVertex2f(x + i.width, y + i.height);
glTexCoord2f(1, 0);
glVertex2f(x + i.width, y);
}
glEnd();
i.unBind();
}
When i removed i.bind() and i.unbind() the text drawing started working perfectly, but then i did not have my texture draw. So how can i have my texture and my text drawn?
PS:
I have enabled alpha blending:
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
and do not disable it because the texture i want to render requires it.
Inserting TextureImpl.bindNone() before every call to render text seamed to fix the problem. I am still not sure where the problem came from because i have used the slick util text render before without using TextureImpl.bindNone() without problems.
I am making a platformer which I started developing with default java functions, but now am switching to OpenGL for everything. I have done everything like I always do with OpenGL, and what I did works fine in my other OpenGL projects. Now my problem is that LWJGL/OpenGL is scaling my textures in a very strange way.
It seems to be related to my screen's aspect ratio. (8:5)
I already had to flip the screen to make it the right way round, but as you can see the text is working fine, it's just the textured rect, and it isn't even straight on the bottom.
Here are the most important snippets from the two classes which actually use OpenGL:
Metamorph.java (main class)
public static void initGL()
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, Display.getWidth(), 0, Display.getHeight(), 1, -1);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glMatrixMode(GL_MODELVIEW);
glClearColor(0, 0, 0, 1);
glDisable(GL_DEPTH_TEST);
}
public void render()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glScalef(1.0f, -1.0f, 1.0f);
glTranslatef(0f, -720f, 0f);
//glScalef(1280f/800, 720f/500, 1f);
renderer.render();
Display.update();
Display.sync(60);
}
Renderer.java (rendering stuff)
private void renderMainMenuWithGL()
{
//System.out.println("Main Menu!");
glColor4f(1, 1, 1, 1);
try
{
Texture bg = loadTexture("mockery");
bg.bind();
} catch (Exception e)
{
e.printStackTrace();
}
//drawQuad(0, 0, 1280, 720, 0, 0, 1280, 720);
glPushMatrix();
{
glBegin(GL_QUADS);
glTexCoord2f(0, 0);glVertex2f(0, 0);
glTexCoord2f(0, 1);glVertex2f(0, 720);
glTexCoord2f(1, 1);glVertex2f(1280, 720);
glTexCoord2f(1, 0);glVertex2f(1280, 0);
glEnd();
}
glPopMatrix();
TrueTypeFont f = loadFont(MAINFONT, Font.PLAIN, 50);
TrueTypeFont fb = loadFont(MAINFONT, Font.PLAIN, 48);
int sel = -1;
if(Mouse.getX() > 1000 && Mouse.getX() < 1240 && Mouse.getY() > 282.5F && Mouse.getY()< 737.5F)
sel = Math.round((Mouse.getY() - 337.5F)/75F);
if(sel == 0)
drawStringRight(fb, 1240, 350, "Story", new Color(0xff516b6b));
else
drawStringRight(f, 1240, 350, "Story", new Color(0xff516b6b));
}
private void drawStringRight(TrueTypeFont f, int x, int y, String s, Color c)
{
glPushMatrix();
f.drawString(x-f.getWidth(s), y, s, c);
glPopMatrix();
}
I am also open to advice on file structure/what I did wrong elsewhere, but keep in mind this is heavily WIP
The only possible problem I can see from what you have posted is the scaling and translating you are doing prior to rendering. You should not need to do this with your projection matrix setup the way it is. Other possibilities are that either the dimensions are not really 1280x720 as you think or you have modified one of the matrices further in the code you have not posted. I would try setting both the modelview and projection matrices to the identity matrix and then use glOrtho as you have above immediatly before drawing your quad, and use Display.getWidth and Display.getHeight instead of 1280/720 for the vertex coords.
This works fine for me:
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, Display.getWidth(), 0, Display.getHeight(), 1, -1);
glBegin(GL_QUADS);
glTexCoord2f(0,0);
glVertex2i(0, 0);
glTexCoord2f(1,0);
glVertex2i(Display.getWidth(), 0);
glTexCoord2f(1,1);
glVertex2i(Display.getWidth(), Display.getHeight());
glTexCoord2f(0,1);
glVertex2i(0, Display.getHeight());
glEnd();
If this still doesnt work, make sure that the viewport is also set to the entire display: glViewport(0,0,Display.getWidth(),Display.getHeight()).
Aswell, I notice that you are using glPushMatrix() and glPopMatrix before and after drawing, which does nothing and is not needed. Push and pop are used to save the current projection or modelview matrix and then reload it later, so that you can apply transformations inbetween and undo them when needed.
You're setting the projection matrix such that the coordinates of the corners of the window are (0,0) through (1680, 1050), and those are mapped into an area that covers 1280x800 pixels. Then you're drawing a 1280x720 image into it, so the screen coordinates of the image come out to span only 800x500 pixels. If you use 1280x720 in your glOrtho() call, I believe it will fix the issue. That is, you want the size of the window, not the size of the display in that call.
I can't figure out why this:
glPushMatrix();
GL11.glBindTexture(this.target, this.textureID);
glColor3f(1, 1, 1);
glTranslated(posX, posY, 0);
glBegin(GL_QUADS);
{
glTexCoord2d(posXLeft, posYTop);
glVertex2d(0, 0);
glTexCoord2d(posXLeft, posYBottom);
glVertex2d(0, verH);
glTexCoord2d(posXRight, posYBottom);
glVertex2d(verW, verH);
glTexCoord2d(posXRight, posYTop);
glVertex2d(verW, 0);
}
glEnd();
glPopMatrix();
is working perfectly, where posX and posY are obviously the position in pixels, posXLeft etc is the ratio of the texture to show.
But this:
glPushMatrix();
GL11.glBindTexture(this.target, this.textureID);
glColor3f(1, 1, 1);
glTranslated(posX, posY, 0);
glBegin(GL_LINES);
{
glVertex2d(10, 10);
glVertex2d(800, 600);
}
glEnd();
glPopMatrix();
isn't. And it should be even easier to draw lines instead of a piece of a texture.
What I want to reach is to add some zig-zag lines on a texture to simulate cracks as it is damaged or broken, but I can't even draw a single line, so I am stuck here.
Any advice?
You still got texturing enabled in your line drawing code. But you don't specify texture coordinates, so you'll draw your line with a solid color as defined by texture at the currently set texture coordinate.
My suggestion: Disable texturing for drawing that line.
As said by datenwolf you have to disable the texturing, thes thing is that than you have to re-enable it, although you will have problems the next cycle of drawing if that property is not set correctly.
the solution is:
glPushMatrix();
GL11.glBindTexture(this.target, this.textureID);
glColor3f(1, 1, 1);
glDisable(GL_TEXTURE_2D);
glTranslated(posX, posY, 0);
glBegin(GL_LINES);
{
glVertex2d(10, 10);
glVertex2d(800, 600);
}
glEnd();
glEnable(GL_TEXTURE_2D);
glPopMatrix();
and that should solve your problem.
I have a textured skydome. It renders white when an image is attached, but it does renders right when a color is given. I have reasons to assume the texture is overwritten, thus some tips on this would be great. It used to work fine, displaying the texture appropriately.
EDIT: If I print the texture directly to the fbo, it does show the texture. However when I map it to the sphere it shows up white. Give the sphere a color, and it shows correctly with the color. Also for the record, white is not the clear color. And I use an image that's quite large (3000x1000~).
ADD: No errors are given anywhere.
Changing:
glActiveTextureARB(GL_TEXTURE6_ARB);
glCallList(SkySphere.getDisplayList());
To:
glActiveTextureARB(GL_TEXTURE0_ARB);
glCallList(SkySphere.getDisplayList());
displays the proper image once, first cycle, then, white again.
glBindTexture(GL_TEXTURE_2D, 0);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fboId);
glViewport(0,0,screenWidth,screenHeight);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(90.0f, ((float)screenWidth/(float)screenHeight),0.1f,100.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glShadeModel(GL_SMOOTH);
glHint(GL_PERSPECTIVE_CORRECTION_HINT,
GL_NICEST);
glDisable(GL_DEPTH_TEST);
glClearColor(1.0f,1.0f,0.0f,1.0f);
glClear (GL_COLOR_BUFFER_BIT);
glLoadIdentity ();
camera.look();
glEnable(GL_TEXTURE_2D);
glDisable(GL_LIGHTING);
glActiveTextureARB(GL_TEXTURE6_ARB);
glCallList(SkySphere.getDisplayList());
glDisable(GL_TEXTURE_2D);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
This is the skysphere code:
public static int loadTexture(String filename) {
ByteBuffer buf = null;
int tWidth = 0;
int tHeight = 0;
.. load png into buffer..
// Create a new texture object in memory and bind it
textureId = GL11.glGenTextures();
GL11.glBindTexture(GL11.GL_TEXTURE_2D, textureId);
// All RGB bytes are aligned to each other and each component is 1 byte
GL11.glPixelStorei(GL11.GL_UNPACK_ALIGNMENT, 1);
// Upload the texture data and generate mip maps (for scaling)
GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGB, tWidth, tHeight, 0,
GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, buf);
// Setup what to do when the texture has to be scaled
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER,
GL11.GL_NEAREST);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER,
GL11.GL_LINEAR);
return textureId;
}
public static int getDisplayList() {
return displayList;
}
public static int makeSphere() {
Sphere s = new Sphere(); // an LWJGL class for drawing sphere
s.setOrientation(GLU.GLU_INSIDE); // normals point inwards
s.setTextureFlag(true); // generate texture coords
displayList = GL11.glGenLists(1);
GL11.glNewList(displayList, GL11.GL_COMPILE);
{
GL11.glPushMatrix();
{
GL11.glBindTexture(GL11.GL_TEXTURE_2D, getTextureId());
//GL11.glTranslatef(0,0,0);
GL11.glRotatef(90f, 1,0,0); // rotate the sphere to align the axis vertically
s.draw(1, 48, 48); // run GL commands to draw sphere
}
GL11.glPopMatrix();
}
GL11.glEndList();
return displayList;
}
In initGL:
SkySphere.createShader();
SkySphere.loadTexture("textures/panorama2.png");
SkySphere.makeSphere();
Also I'm doing most of my work in framebuffers:
glBindTexture(GL_TEXTURE_2D, 0);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, modelsFboId);
And in one occasion copy the depth to a texture:
glActiveTextureARB(GL_TEXTURE3_ARB);
glBindTexture(GL_TEXTURE_2D, modelsDepthTextureId);
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, screenWidth, screenHeight);
glBindTexture(GL_TEXTURE_2D, 0);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
I used
glPushAttrib(GL_ALL_ATTRIB_BITS);
at the beginning and
glPopAttrib();
at the end to reset the OpenGL states each frame.
I have a Java OpenGL (JOGL) app, and I'm trying to create a texture mapped quad that covers the entire screen. In draw some pixels to a buffer and then I want to read those pixels into a texture and redraw them on screen (with a fragment shader applied). My code for mapping the texture to the viewport is:
gl.glMatrixMode(GL.GL_PROJECTION);
gl.glPushMatrix();
gl.glLoadIdentity();
gl.glOrtho( 0, width, height, 0, -1, 1 );
gl.glMatrixMode(GL.GL_MODELVIEW);
gl.glPushMatrix();
gl.glLoadIdentity();
IntBuffer ib = IntBuffer.allocate(1);
gl.glEnable(GL.GL_TEXTURE_2D);
gl.glGenTextures(1, ib);
gl.glPixelStorei(GL.GL_PACK_ALIGNMENT, 1);
//buff contains pixels read from glReadPixels
gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, GL.GL_RGBA, width, height, 0, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE, buff);
gl.glBindTexture(GL.GL_TEXTURE_2D, ib.get(0));
gl.glBegin(GL.GL_QUADS);
gl.glTexCoord2f(0,1);
gl.glVertex2f(0,0);
gl.glTexCoord2f(0,0);
gl.glVertex2f(0,height);
gl.glTexCoord2f(1,0);
gl.glVertex2f(width,height);
gl.glTexCoord2f(1,1);
gl.glVertex2f(width,0);
gl.glEnd();
gl.glBindTexture(GL.GL_TEXTURE_2D, 0);
gl.glPopMatrix();
gl.glPopMatrix();
The end result is a quad that is not covering the whole viewport (it's partially on) and that does not contain the pixels from the buffer. What am I doing incorrectly here?
thanks,
Jeff
First, you should only create the texture in your initialization code. You should not be calling glTexImage2D every frame. Only call glTexImage2D again if the size of the texture changes; glTexSubImage2D can be used to upload data to the texture. Think of glTexImage2D as "new", while glTexSubImage2D as a memory copy.
Do this once, after initializing OpenGL.
IntBuffer ib = IntBuffer.allocate(1); //Store this in your object
gl.glGenTextures(1, ib);
gl.glPixelStorei(GL.GL_PACK_ALIGNMENT, 1);
//buff contains pixels read from glReadPixels
gl.glBindTexture(GL.GL_TEXTURE_2D, ib.get(0));
gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, GL.GL_RGBA, width, height, 0, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE, 0);
gl.glBindTexture(GL.GL_TEXTURE_2D, 0);
Then, each frame, do this:
gl.glMatrixMode(GL.GL_PROJECTION);
gl.glPushMatrix();
gl.glLoadIdentity();
gl.glMatrixMode(GL.GL_MODELVIEW);
gl.glPushMatrix();
gl.glLoadIdentity();
gl.glBindTexture(GL.GL_TEXTURE_2D, ib.get(0)); //Retrieved from your object
gl.glEnable(GL.GL_TEXTURE_2D);
gl.glTexSubImage2D(GL.GL_TEXTURE_2D, 0, 0, 0, width, height, 0, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE, buff);
gl.glBegin(GL.GL_QUADS);
gl.glTexCoord2f(0,1);
gl.glVertex2f(-1, -1);
gl.glTexCoord2f(0, 0);
gl.glVertex2f(-1, 1);
gl.glTexCoord2f(1, 0);
gl.glVertex2f(1, 1);
gl.glTexCoord2f(1, 1);
gl.glVertex2f(1, -1);
gl.glEnd();
gl.glMatrixMode(GL.GL_MODELVIEW);
gl.glPopMatrix();
gl.glMatrixMode(GL.GL_PROJECTION);
gl.glPopMatrix();
gl.glMatrixMode(GL.GL_MODELVIEW);
By using identity for projection and modelview, we are able to supply vertex coordinates directly in clip-space. The [-1, 1] range in clip-space maps to [0, width/height] in window space. So we don't have to know or care about how big the window is; as long as the glViewport was set up correctly, this should work.
It may not be the problem, but it won't be helping: You are popping the modelview matrix twice for a single push. You are not popping the projection matrix at all.
I would recommend setting the projection matrix once at startup, without doing any pushes or pops. You don't really need to push and pop the modelview matrix either. (You could do your texture setup once at startup, too.)
I would start with checking glError with code like the below. Note I used the GL2 object because there were some issues with older versions of JOGL and the GL object, silly things like GL_QUADS not being there.
If you have a shader enabled with the above code, you need to do the texturing by reading the sampler. If so, please attach the shader code you are using with this rendering code.
private static void checkForGLErrors(GL2 gl) {
int errno = gl.glGetError();
switch (errno) {
case GL2.GL_INVALID_ENUM:
System.err.println("OpenGL Error: Invalid ENUM");
break;
case GL2.GL_INVALID_VALUE:
System.err.println("OpenGL Error: Invalid Value");
break;
case GL2.GL_INVALID_OPERATION:
System.err.println("OpenGL Error: Invalid Operation");
break;
case GL2.GL_STACK_OVERFLOW:
System.err.println("OpenGL Error: Stack Overflow");
break;
case GL2.GL_STACK_UNDERFLOW:
System.err.println("OpenGL Error: Stack Underflow");
break;
case GL2.GL_OUT_OF_MEMORY:
System.err.println("OpenGL Error: Out of Memory");
break;
default:
return;
}
}
I would also try to avoid generating the texture every frame if it is something that doesn't change. You can save the textureId and bind it later.