Just wondering if someone can help me track down my issue with the following code where the text color is not being set correctly (its just rendering whatever color is in the background)
void RenderText(int x, int y, const char *string)
{
int i, len;
glUseProgram(0);
glLoadIdentity();
glColor3f(1.0f, 1.0f, 1.0f);
glTranslatef(0.0f, 0.0f, -5.0f);
glRasterPos2i(x, y);
glDisable(GL_TEXTURE_2D);
for (i = 0, len = strlen(string); i < len; i++)
{
glutBitmapCharacter(GLUT_BITMAP_8_BY_13, (int)string[i]);
}
glEnable(GL_TEXTURE_2D);
}
I've checked all the usual things (I think), disabling texturing, setting color before rasterPos'ing, etc Ive disabled shaders but Im still having issues
Looks like you've forgotten to glDisable(GL_LIGHTING) before drawing your string.
No color is stored with any OpenGL bitmap (which is what glutBitmapCharacter created. The bitmap is monochrome and stores only shape.
When the bitmap is drawn (e.g. glBitmap or maybe glDrawLists), the current raster color is used. The raster color is not always the same as the active color, see http://www.opengl.org/wiki/Coloring_a_bitmap.
Color is usually controlled with the glColor3f function, thus if the text is white and shouldn't be then the following change should help:
glLoadIdentity();
glColor3f(0.5f, 0.5f, 0.5f); //<-- this line controls the color (now text is gray)
glTranslatef(0.0f, 0.0f, -5.0f);
glRasterPos2i(x, y);
Also, calling glDisable(GL_TEXTURE_2D) and glEnable(GL_TEXTURE_2D) is unnecessary. Instead you can just call glBindTexture(GL_TEXTURE_2D,0) to disable textures and then use the same function to set the active texture. Just make sure to call glEnable(GL_TEXTURE_2D) in your initialization function.
Related
When I render my text using TTF_RenderUTF8_Blended I obtain a solid rectangle on the screen. The color depends on the one I choose, in my case the rectangle is red.
My question
What am I missing? It seems like I'm not getting the proper Alpha values from the surface generated with SDL_DisplayFormatAlpha(TTF_RenderUTF8_Blended( ... )), or am I? Does anyone recognize or know the problem?
Additionnal informations
If I use TTF_RenderUTF8_Solid or TTF_RenderUTF8_Shaded the text is drawn properly, but not blended of course.
I am also drawing other textures on the screen, so I draw the text last to ensure the blending will take into account the current surface.
Edit:SDL_Color g_textColor = {255, 0, 0, 0}; <-- I tried with and without the alpha value, but I get the same result.
I have tried to summarize the code without removing too much details. Variables prefixed with "g_" are global.
Init() function
// This function creates the required texture.
bool Init()
{
// ...
g_pFont = TTF_OpenFont("../arial.ttf", 12);
if(g_pFont == NULL)
return false;
// Write text to surface
g_pText = SDL_DisplayFormatAlpha(TTF_RenderUTF8_Blended(g_pFont, "My first Text!", g_textColor)); //< Doesn't work
// Note that Solid and Shaded Does work properly if I uncomment them.
//g_pText = SDL_DisplayFormatAlpha(TTF_RenderUTF8_Solid(g_pFont, "My first Text!", g_textColor));
//g_pText = SDL_DisplayFormatAlpha(TTF_RenderUTF8_Shaded(g_pFont, "My first Text!", g_textColor, g_bgColor));
if(g_pText == NULL)
return false;
// Prepare the texture for the font
GLenum textFormat;
if(g_pText->format->BytesPerPixel == 4)
{
// alpha
if(g_pText->format->Rmask == 0x000000ff)
textFormat = GL_RGBA;
else
textFormat = GL_BGRA_EXT;
}
// Create the font's texture
glGenTextures(1, &g_FontTextureId);
glBindTexture(GL_TEXTURE_2D, g_FontTextureId);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, g_pText->format->BytesPerPixel, g_pText->w, g_pText->h, 0, textFormat, GL_UNSIGNED_BYTE, g_pText->pixels);
// ...
}
DrawText() function
// this function is called each frame
void DrawText()
{
SDL_Rect sourceRect;
sourceRect.x = 0;
sourceRect.y = 0;
sourceRect.h = 10;
sourceRect.w = 173;
// DestRect is null so the rect is drawn at 0,0
SDL_BlitSurface(g_pText, &sourceRect, g_pSurfaceDisplay, NULL);
glBindTexture(GL_TEXTURE_2D, g_FontTextureId);
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glBegin( GL_QUADS );
glTexCoord2f(0.0f, 0.0f);
glVertex2f(0.0f, 0.0f);
glTexCoord2f(0.0f, 1.0f);
glVertex2f(0.0f, 10.0f);
glTexCoord2f(1.0f, 1.0f);
glVertex2f(173.0f, 10.0f);
glTexCoord2f(1.0f, 0.0f);
glVertex2f(173.0f, 0.0f);
glEnd();
glDisable(GL_BLEND);
glDisable(GL_TEXTURE_2D);
}
You've made a fairly common mistake. It's on the OpenGL end of things.
When you render the textured quad in DrawText(), you enable OpenGL's blending capability, but you never specify the blending function (i.e. how it should be blended)!
You need this code to enable regular alpha-blending in OpenGL:
glEnable( GL_BLEND );
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
This info used to be on the OpenGL website, but I can't find it now.
That should stop it from coming out solid red. The reasons the others worked is because they're not alpha-blended, they're actually just red-on-black images with no alpha, so the blending function doesn't matter. But the blended one only contains red color, with an alpha channel to make it less-red.
I notice a few other small problems in your program though.
In the DrawText() function, you are blitting the surface using SDL and rendering with OpenGL. You should not use regular SDL blitting when using OpenGL; it doesn't work. So this line should not be there:
SDL_BlitSurface(g_pText, &sourceRect, g_pSurfaceDisplay, NULL);
Also, this line leaks memory:
g_pText = SDL_DisplayFormatAlpha( TTF_RenderUTF8_Blended(...) );
TTF_RenderUTF8_Blended() returns a pointer to SDL_Surface, which must be freed with SDL_FreeSurface(). Since you're passing it into SDL_DisplayFormatAlpha(), you lose track of it, and it never gets freed (hence the memory leak).
The good news is that you don't need SDL_DisplayFormatAlpha here because TTF_RenderUTF8_Blended returns a 32-bit surface with an alpha-channel anyway! So you can rewrite this line as:
g_pText = TTF_RenderUTF8_Blended(g_pFont, "My first Text!", g_textColor);
I'm new to directx and finally I managed to load an image which I want to display as background image/texture
Defining image
void setBGImage(std::string path)
{
D3DXCreateTextureFromFileA(m_Device, path.c_str(), &m_BGImage);
m_BGImageCenter = D3DXVECTOR3(450.0f, 250.0f, 0.0f); // Image is 900x500
}
Drawing image
void DrawBackground()
{
m_Sprite->Begin(D3DXSPRITE_OBJECTSPACE|D3DXSPRITE_DONOTMODIFY_RENDERSTATE);
// Texture tiling
/*
D3DXMATRIX texScaling;
D3DXMatrixScaling(&texScaling, 1.0f, 1.0f, 0.0f);
m_Device->SetTransform(D3DTS_TEXTURE0, &texScaling);*/
//D3DXMATRIX T, S, R;
//D3DXMatrixTranslation(&T, 0.0f, 0.0f, 0.0f);
//D3DXMatrixScaling(&S, 1.0f, 1.0f, 0.0f);
//D3DXMatrixRotationZ(&R, 0.45f);
//m_Sprite->SetTransform(&(S*T));
m_Sprite->Draw(m_BGImage, 0, &m_BGImageCenter, 0, D3DCOLOR_XRGB(255, 255, 255));
m_Sprite->Flush();
m_Sprite->End();
}
onResetDevice (is getting called at startup)
void onResetDevice()
{
m_Sprite->OnResetDevice();
// Sets up the camera 640 units back looking at the origin.
D3DXMATRIX V;
D3DXVECTOR3 pos(0.0f, 0.0f, -640.0f); // This distance is just a test value to get only the image and no white background/border as soon as I have it centered I will adjust it.
D3DXVECTOR3 up(0.0f, 1.0f, 0.0f);
D3DXVECTOR3 target(0.0f, 0.0f, 0.0f);
D3DXMatrixLookAtLH(&V, &pos, &target, &up);
m_Device->SetTransform(D3DTS_VIEW, &V);
// The following code defines the volume of space the camera sees.
D3DXMATRIX P;
RECT R;
GetClientRect(m_hWnd, &R);
float width = (float)R.right;
float height = (float)R.bottom;
D3DXMatrixPerspectiveFovLH(&P, D3DX_PI*0.25f, width/height, 0.0f, 1.0f);
m_Device->SetTransform(D3DTS_PROJECTION, &P);
// This code sets texture filters, which helps to smooth out disortions when you scale a texture.
m_Device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
m_Device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
m_Device->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR);
// This line of code disables Direct3D lighting.
m_Device->SetRenderState(D3DRS_LIGHTING, false);
// The following code specifies an alpha test and reference value.
m_Device->SetRenderState(D3DRS_ALPHAREF, 10);
m_Device->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATER);
// The following code is used to setup alpha blending.
m_Device->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
m_Device->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
m_Device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
m_Device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
// Indicates that we are using 2D texture coordinates.
m_Device->SetTextureStageState(0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_COUNT2);
}
When I use these methods to render my background image it get's displayed upside down, not centered (little bit to the right) and I've got the feeling the height width ratio isn't correct (image is kinda blurry and it feels like the image is not as high as it's supposed to be).
What did I try?
I tried to adjust various coordinates in order to look at the image from the other side and then rotate it but whatever I tried it turned into a white/non-existing background.
Centering the image is not such a big deal I can just move the camera position but I'm confused since the m_BGImageCenter was supposed to do that for me in the Draw method and it seems to not work 100% correct.
My Questions (I guess it's ok to ask multiple questions in this context):
How can I get the image not upside down (I know how you would do it in theory but I somehow don't get it right, so please give me the coordinates).
Why is the image not centered?
Is it possible that D3DXMatrixPerspectiveFovLH is wrapping my image since it looks a little bit blurry.
I am creating a 3D game. I have objects in my game. When an enemy hits my position I want my screen to go red for a short time. I have chosen to do this by trying to render a full screen red square at my camera position. This is my attempt which is in my render method.
RenderQuadTerrain();
//Draw the skybox
CreateSkyBox(vNewPos.x, vNewPos.y, vNewPos.z,3500,3000,3500);
DrawCoins();
CollisionTest(g_Camera.Position().x, g_Camera.Position().y, g_Camera.Position().z);
DrawEnemy();
DrawEnemy1();
//Draw SecondaryObjects models
DrawSecondaryObjects();
//Apply lighting effects
LightingEffects();
escapeAttempt();
if(hitbyenemy==true){
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE); // additive blending
float blendFactor = 1.0;
glColor3f(blendFactor ,0,0); // when blendFactor = 0, the quad won't be visible. When blendFactor=1, the scene will be bathed in redness
glBegin(GL_QUADS); // Draw A Quad
glVertex3f(-1.0f, 1.0f, 0.0f); // Top Left
glVertex3f( 1.0f, 1.0f, 0.0f); // Top Right
glVertex3f( 1.0f,-1.0f, 0.0f); // Bottom Right
glVertex3f(-1.0f,-1.0f, 0.0f); // Bottom Left
glEnd();
}
All this does, however, is turn all of the objects in my game a transparent colour, and I can't see the square anywhere. I don't even know how to position the quad. I'm very new to openGL.
How my game looks without an attempt to render a quad:
How my game looks after my attempt:
With Kevin's code and glDisable(GL_DEPTH_TEST);
EDIT: I have changed the code to the below paste..still looks like image 1.
http://pastebin.com/eiVFcQqM
There are several possible contributions to the problem:
You probably want regular blending, not additive blending; additive blending will not turn white, yellow, or purple objects red. Change the blend func to glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); and use a color of glColor4f(1, 0, 0, blendFactor);
You should glDisable(GL_DEPTH_TEST); while drawing the overlay, to prevent it from being hidden by other geometry, and reenable it afterward (or use glPush/PopAttrib(GL_ENABLE_BIT)).
The projection and modelview matrixes should be the identity, to ensure a quad with those coordinates covers the entire screen. (However, you may have that implicitly already, since you say it is affecting the full screen, just not in the right way.)
If these suggestions do not fix it, please edit your question showing screenshots of your game with and without the red flash so we can understand the problem better.
There's something wrong in my code somewhere but for any number of primitives that I draw, despite calling glClearColor and then picking a color with glColor3f, the colors that appear are completely random...
So in my Rendering class I cycle through all the objects and call their drawing methods, for primitives they would look like:
inline void PrimitiveDrawer::drawWireframePrism(Vector3 pos, float radius, Vector3 col){
glClearColor( 1.0f, 1.0f, 1.0f, 1.0f );
glColor3f(col.x, col.y, col.z);
glLineWidth(3);
glBegin (GL_LINE_LOOP);
...
glEnd()
But no matter what color i select I always get different ones... The interesting think is that all primitive lines I draw with this method assume the color of the models that they bound (they are meant to be bounding volumes for meshes)... Could it have to do with the model loaders I am using?
This is affecting every shape (outside the ones around the models), where every GL_LINE assumes the same colour (green for some reason), including the glutBitMapCharacter that I am trying to draw... That's the main think that bothers me as I'd like to pick the colour for the text drawing, currently I am doing:
void renderBitmapString(float x, float y, void *font,char *string)
{
char *c;
glRasterPos2f(x, y);
for (c=string; *c != '\0'; c++) {
glutBitmapCharacter(font, *c);
}
}
void drawText(char text[20], float x, float y){
glPushMatrix();
setOrthographicProjection();
glLoadIdentity();
glClearColor( 0, 0, 0, 0 );
glColor4f(0, 0, 1, 1);
renderBitmapString(x, y,(void *)font, text);
resetPerspectiveProjection();
glPopMatrix();
}
But the text comes up green instead of blue?
glClearColor has nothing to do with glColor. glClearColor sets the color used with a call of glClear(GL_COLOR_BUFFER_BIT) to clear the framebuffer with.
Colors from other objects drawn sounds to me, that you forget to disable texturing. Add a glDiable(GL_TEXTURE_2D); after you're done drawing textured stuff.
After loading an image, I have the individual bytes for each channel loaded into an array of unsigned characters. It's passed to a function that projects it as a texture onto a quad. Everything seems to work properly other than the alpha channel, which shows up as the background color. I'm using OpenGL to draw the image. Would I benefit by adding a layering mechanism? Also, how can I achieve the transparent effect that I want?
Note: This is the code that I have a feeling needs changed:
void SetUpView()
{
// Set color and depth clear value
glClearDepth(1.f);
glClearColor(1.f, 0.f, 0.f, 0.f);
// Enable Z-buffer read and write
glEnable(GL_DEPTH_TEST);
glEnable(GL_TEXTURE_2D);
glDepthMask(GL_TRUE);
glEnable (GL_BLEND);
glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
// Setup a perspective projection
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(90.f, 1.f, 1.f, 500.f);
};
Also, here's the code to render the quad.
void DrawTexturedRect(RectBounds *Verts, Image *Texture)
{
glBindTexture(GL_TEXTURE_2D, GetTextureID(Texture));
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glPixelZoom(1, -1);
glBegin(GL_QUADS);
glTexCoord2f(0.0, 1.0);
glVertex3f(Verts->corners[0].x, Verts->corners[0].y, Verts->corners[0].z);
glTexCoord2f(1.0, 1.0);
glVertex3f(Verts->corners[1].x, Verts->corners[1].y, Verts->corners[1].z);
glTexCoord2f(1.0, 0.0);
glVertex3f(Verts->corners[2].x, Verts->corners[2].y, Verts->corners[2].z);
glTexCoord2f(0.0, 0.0);
glVertex3f(Verts->corners[3].x, Verts->corners[3].y, Verts->corners[3].z);
glEnd();
};
The Image class holds an array of unsigned chars, obtained using OpenIL.
Relevant code:
loaded = ilLoadImage(filename.c_str());
ilConvertImage(IL_RGBA, IL_UNSIGNED_BYTE);
unsigned char *bytes = ilGetData();
//NewImage is an instance of an Image. This is returned and passed to the above function.
NewImage->data = bytes;
Before drawing anything transparent you should call:
glDepthMask(false);
And then afterwards:
glDepthMask(true);
Also, all transparent objects must be drawn after all opaque ones.
glClearColor(1.f, 0.f, 0.f, 0.f);
I'd assume that's at the RGBA default, and you're setting red to 1.0.
How about a better explanation of what you're trying to accomplish?
Try:
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
Edit: I know what that looks like. It looks like you are drawing the blue square (Which has a Z-order position placing it behind the cursor) AFTER the cursor. You have to draw things in the correct, back-to-front Z-Order when alpha blending or you see errors like you are seeing.