I'm using SDL, I have OpenGL rendering setup, I want to draw some text to the screen.
I found this question: Using SDL_ttf with OpenGL which seems to address the same concern, but I think my GL-fu isn't good enough to understand what to do next.
Ie, I have the texture from that other post, which, if I understand everything correctly, is an integer ID representing a GL texture that contains the rendered text. How do I actually render this texture onto my screen (everything's 2D here so I just want to render it as flat text on the screen, not onto some fancy surface in a 3D scene or anything).
Alternatively, is there any easier way of getting this working? (ie, rendering some text via SDL while also being able to render GL shapes)
edit: Or, even more generally, is there an easier way of being able to render both text and shapes onto the screen via SDL?
Use SDL_ttf to turn your string into a bitmap; this is just a single function call.
Use the code in the link you posted to turn it into a texture.
Draw a rectangle using said texture. That is, glBindTexture, glBegin, (glTexCoord, glVertex) x4, glEnd. If you have doubts about this step, you better go through some basic OpenGL tutorials (covering texture mapping, of course) first.
Try this snippet, it renders a SDL true type font extension library font starting from the bottom left side of the screen.
Note the arrangment of the texcords to the shape on the screen. The pixels from the text texture start 0,0 at the top left of the image. So I need to flip that around to make it show properly on a screen with x,y at the bottom left.
void RenderText(std::string message, SDL_Color color, int x, int y,
TTF_Font* font)
{
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
gluOrtho2D(0, gWindow->getWidth(),0,gWindow->getHeight());
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glDisable(GL_DEPTH_TEST);
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
SDL_Surface * sFont = TTF_RenderText_Blended(font, message.c_str(), color);
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_RGBA, sFont->w, sFont->h, 0, GL_BGRA,
GL_UNSIGNED_BYTE, sFont->pixels);
glBegin(GL_QUADS);
{
glTexCoord2f(0,1); glVertex2f(x, y);
glTexCoord2f(1,1); glVertex2f(x + sFont->w, y);
glTexCoord2f(1,0); glVertex2f(x + sFont->w, y + sFont->h);
glTexCoord2f(0,0); glVertex2f(x, y + sFont->h);
}
glEnd();
glDisable(GL_BLEND);
glDisable(GL_TEXTURE_2D);
glEnable(GL_DEPTH_TEST);
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glDeleteTextures(1, &texture);
SDL_FreeSurface(sFont);
}
Related
I'm trying to display a 128x128 array of floats (0.0 -> 1.0) as a texture of green on black within a legacy FLTK application. The rest of the application uses immediate mode for all it's drawing, so I don't want to change the way it works. From reading tutorials, I've come up with the following calls that should be sufficient to load the texture into graphics memory, and draw it to the current context (managed by FLTK). However, all I can get it to do is draw a black square where the texture should be, drawing over anything else that has been drawn there (GL_LINES).
Is there anything basic that I'm missing here? some initialization step that I've neglected? Thanks in advance. Here the code that I'm trying to get running:
// Part of class init
glGenTextures(1, &tex);
// As far as I can tell, this is optional with FLTK having already
// set these parameters. Omitting them does not change output.
glPushMatrix();
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMatrixMode(GL_MODEL);
glLoadIdentity();
// This is the meat of the problem. reports no GL errors.
glEnable(GL_TEXTURE_2D);
glShadeModel(GL_FLAT);
glBindTexture(GL_TEXTURE_2D, tex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 128, 128, 0, GL_GREEN, GL_FLOAT, &image);
glBegin(GL_QUADS);
glTexCoord2d(0,0); glVertex2f(-0.9,-0.9);
glTexCoord2d(0,1); glVertex2f(-0.9, 0.9);
glTexCoord2d(1,0); glVertex2f( 0.9,-0.9);
glTexCoord2d(1,1); glVertex2f( 0.9, 0.9);
glEnd();
glDisable(GL_TEXTURE_2D);
// Again, busywork.
glPopMatrix();
I'm trying to write an OpenGL/GLSL app that will use GLSL for image processing. I've done some research and come to the conclusion that the right approach is to render to a framebuffer object and then retrieve the image from the gpu. Unfortunately I can't figure out how to set up the frustum and render the quadrilateral so that it fills it properly. Does anyone know how to do this?
You need to render with an orthogonal projection matrix.
glPushMatrix(GL_WORLDVIEW);
glLoadIdentity();
glPushMatrix(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, width, height, 0, 0, 1);
glBegin(GL_QUADS);
glVertex2i(0, 0);
glVertex2i(width, 0);
glVertex2i(width, height);
glVertex2i(0, height);
glEnd();
glPopMatrix();
glMatrixMode(GL_WORLDVIEW);
glPopMatrix();
Width and height are the dimensions of your FBO. Of course they could be both one if you don't need to address special parts of your FBO by drawing quads at pixel positions.
I'm trying to use FBO's for performance improvements and for the gained knowledge by trying out something new, but I have run in following problem:
When I render some texture to the back buffer it works perfect (just a bit slow because of multiple layers of textures on top of each other)
But when I try to first draw the textures onto another texture using an FBO the new texture always keeps white.
Now to the Code
This is my FBOsetup function (called at the beginning (after creating the Opengl context)):
int FBOId;
int FBOTexId;
void setupFBO(){
IntBuffer buffer = ByteBuffer.allocateDirect(1 * 4).order(ByteOrder.nativeOrder()).asIntBuffer();
glGenFramebuffersEXT(buffer);
FBOId= buffer.get();
FBOTexId=glGenTextures();
glBindTexture(GL_TEXTURE_2D, FBOTexId);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, tileSize, tileSize, 0, GL_RGB, GL_UNSIGNED_BYTE, ByteBuffer.allocateDirect(4*tileSize*tileSize));
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, FBOId);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, FBOTexId, 0);
}
Now the render function:
void redraw(){
glPushMatrix();
glPushAttrib(GL_VIEWPORT_BIT | GL_COLOR_BUFFER_BIT);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, FBOId);
glLoadIdentity();
glOrtho(0, tileSize, tileSize, 0, -1, 1);
glMatrixMode(GL_MODELVIEW);
glEnable(GL_TEXTURE_2D);
Main.drawTexture(0, 0, tileSize, tileSize, textureRotation, textureId);
glBindFramebufferEXT( EXTFramebufferObject.GL_FRAMEBUFFER_EXT, 0);
glPopAttrib();
glPopMatrix();
}
And the final draw function:
void draw(){
Main.drawTexture(x*tileSize, y*tileSize, tileSize, tileSize, FBOTexId);
}
And for all who want it my drawTexture function:
public static void drawTexture(float x, float y, float xSize, float ySize, float rot, int textureId){
GL11.glBindTexture(GL11.GL_TEXTURE_2D, textureId);
GL11.glMatrixMode(GL11.GL_TEXTURE);
GL11.glLoadIdentity();
GL11.glTranslatef(0.5f,0.5f,0.0f);
GL11.glRotatef(rot,0.0f,0.0f,1.0f);
GL11.glTranslatef(-0.5f,-0.5f,0.0f);
GL11.glMatrixMode(GL11.GL_MODELVIEW);
GL11.glBegin(GL11.GL_QUADS);
GL11.glTexCoord2f(0,0);
GL11.glVertex2f(x,y);
GL11.glTexCoord2f(1,0);
GL11.glVertex2f(x+xSize,y);
GL11.glTexCoord2f(1,1);
GL11.glVertex2f(x+xSize,y+ySize);
GL11.glTexCoord2f(0,1);
GL11.glVertex2f(x,y+ySize);
GL11.glEnd();
GL11.glMatrixMode(GL11.GL_MODELVIEW);
}
If I replace the Main.draw line in the draw() function with this Main.drawTexture(x*tileSize, y*tileSize, tileSize, tileSize, textureRotation, textureId); it directly draws the texture to the correct position on the screen, but the problem is that I would always have to redraw all layers of textures and with the FBO's I draw all the layers everytime something changes and then only draw the texture from the FBO.
Well first thanks for all the comments. I havent realy found the error nor do I understand why this is necessary but this is how it works:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
By adding these two lines of code after the glBindTexture(GL_TEXTURE_2D, FBOTextId) in the setupFBO() function everything works fine.
If u replace the GL_NEAREST in above lines with GL_LINEAR works too, but it has some strange artifacts when scaling the image.
By the way just a short question which has nothing to do with this thread:
Does someone know a way of making parts of a texture (by drawing to it with an fbo) transparant by evaluating the colors from another texture?
My question is to draw a polygon or some other OpenGL primitives above or over a background image. Summarizing like paint in different layers, but in OpenGL i think there is no layers.
Now i'm doing some test trying to draw a triangle and a line over the background image.
To draw the background i use a square with OpenGL window size and then apply the png image in this square as a texture.
After that I try to paint the triangle and the line with different colors but I don't see anything except the background image.
I play with the alpha channel but i don't see anything.
Code:
void init()
{
// glClearColor(0.0, 0.0, 0.0, 0.0);
glEnable(GL_DEPTH_TEST);
// The following two lines enable semi transparent
glEnable(GL_BLEND);
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
int width, height;
bool hasAlpha;
char filename[] = "prueba-luz.png";
bool success = loadPngImage(filename, width, height, hasAlpha, &textureImage);
if (!success)
{
cout << "Unable to load png file" << endl;
return;
}
cout << "Image loaded " << width << " " << height << " alpha " << hasAlpha << endl;
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexImage2D(GL_TEXTURE_2D, 0, hasAlpha ? 4 : 3, width,
height, 0, hasAlpha ? GL_RGBA : GL_RGB, GL_UNSIGNED_BYTE,
textureImage);
// glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
// glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
// glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
}
void display(void)
{
glEnable(GL_TEXTURE_2D);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); // Igual que GL_REPLACE pero se le puede aplicar transparencias a la textura
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glPushMatrix();
glColor4f(1, 1, 1, 1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBegin(GL_QUADS);
glTexCoord2i(0,0); glVertex2i(10, -10);
glTexCoord2i(1,0); glVertex2i(-10, -10);
glTexCoord2i(1,1); glVertex2i(-10, 10);
glTexCoord2i(0,1); glVertex2i(10, 10);
glEnd();
glPopMatrix();
glDisable(GL_TEXTURE_2D);
glBegin(GL_POLYGON);
glColor4f(1.0, 1.0, 1.0, 0.8);
glVertex3f(-1.0f, -3.0f, 0.0f); // A
glVertex3f( 1.0f, -3.5f, 0.0f); // B
glVertex3f( 0.0f, 0.5f, 0.0f); // C
glEnd();
glBegin(GL_LINES);
glColor4f( 1.0, 0.0, 0.0, 0.8 );
glVertex2f(-8.0, 6.0);
glVertex2f (5.0, -3.0);
glEnd();
glutSwapBuffers();
}
How can i draw one image over the background image ???
Some things spotted :
Try to disable depth test. You are drawing everything at Z=0 and your application is definitely writing to the depth buffer. I'm not sure why you enable depth testing here since everything you draw is on Z=0.
By default all fragments written to the same or higher Z value will be discarded when depth testing is enabled. This can be changed with glDepthFunc (Default value GL_LESS). This is probably why your geometry is discarded in this example.
Drawing 2D geometry do not mean that the depth buffer will not be affected. OpenGL will draw this geometry with Z=0 and write that to your depth buffer.
Currently there is no reason for your application to use depth testing unless you draw your geometry on different z positions. You can use depth testing in 2D drawing to make "layers" by assigning different z values to each object.
A good practice for 2D drawing with z-culling is to draw the closes layer first, then draw the layers further in. This makes sure your write fewer fragments.
For example :
Z = 0 : Draw non-transparent overlays
Z = -1 : Draw stuff hidden behind the overlays
Z = -2 : Draw background
However, transparent objects need special rules.
You need to get control over your depth buffer. There are options :
glEnable/Disable(GL_DEPTH_TEST) : Enable or disable z-culling
glDepthMask(GL_TRUE/GL_FALSE) : Enable or disable writing to the the depth buffer
(glDepthFunc can be used to define how fragments are discarded)
Note here that the two first functions give you way more options than you might think
Depth culling and depth write when drawing objects
Depth culling, but your object do not affect the depth buffer
No depth culling, but your object will write to the depth buffer
No depth culling and no depth write
If you want to draw all your transparent objects in a last pass you can for example enable depth testing so the objects are not drawn on top your your overlays, but you disable depth writes because you want to be able to draw several overlapping objects in that layer.
Use your creativity and learn to love the depth buffer :D
i'm using OpenGL for showing grabbed frames from video camera with texture mapping. There is no problem at all but i have to select some region of the grabbed frame then i have to zoom it, first of all i can't draw a Rubber rectangle it must be transparent when i select the some region of grabbed frame i have to see textured frame transparently could you gimme some piece of code or clue, btw i'm showing grabbed frames like that any suggestion will be good for me...
void GLWidget::initializeGL()
{
glShadeModel(GL_SMOOTH);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClearDepth(1.0f);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
glEnable(GL_TEXTURE_2D);
glGenTextures(1, &m_pTextureId);
glBindTexture(GL_TEXTURE_2D, m_pTextureId);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
}
void GLWidget::resizeGL(int w, int h)
{
glViewport(0,0,w,h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-1,1,-1,1,-1,1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void GLWidget::setTextureData(BYTE *data, int width, int height)
{
makeCurrent();
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
if (m_isTextured)
glTexSubImage2D(GL_TEXTURE_2D,0,0,0,width,height,GL_BGRA_EXT,GL_UNSIGNED_BYTE,data);
else
glTexImage2D(GL_TEXTURE_2D,0,3,width,height,0,GL_BGRA_EXT,GL_UNSIGNED_BYTE,0);
glBindTexture(GL_TEXTURE_2D,m_pTextureId);
glBegin(GL_QUADS);
glTexCoord2f(0.0,0.0);glVertex2f(-1.0,-1.0);
glTexCoord2f(0.0,1.0);glVertex2f(-1.0,1.0);
glTexCoord2f(1.0,1.0);glVertex2f(1.0,1.0);
glTexCoord2f(1.0,0.0);glVertex2f(1.0,-1.0);
glEnd();
swapBuffers();
}
I'm passing captured frame data to setTextureData it's working but i dunno does it good way ...
Thanks for reply #genpfault,
i used x1=0, y1=0, x2=1, y2=1 but it's drawing rectangle to all texture area. and draws 1 more rectangle to coordinates x1,y1... . How can i fix it. Btw how can i remove that rectangle ?, There is one more issue if i draw a rectangle then texture again rectangle going invisible ...
Just draw a translucent (alpha < 1.0) rectangle:
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glColor4ub(255, 255, 255, 128);
glRectf(x1, y1, x2, y2);
glDisable(GL_BLEND);