C++ OpenGL / FreeType scrolling font - c++

Looking for opinions on the best way to scroll text, Im using the freetype lib with OpenGL/c++ on Slackware.
I am basically using the nehe example for the freetype setup/print methods.
http://nehe.gamedev.net/tutorial/freetype_fonts_in_opengl/24001/
So say for example, i wanted some text to slowly erode from the bottom up,pixel by pixel, any ideas?
Although i have not fully examined their code, would it be best to alter the TexCoord/Vertex data?
glBegin(GL_QUADS);
glTexCoord2d(0,0); glVertex2f(0,bitmap.rows);
glTexCoord2d(0,y); glVertex2f(0,0);
glTexCoord2d(x,y); glVertex2f(bitmap.width,0);
glTexCoord2d(x,0); glVertex2f(bitmap.width,bitmap.rows);
glEnd();
glPopMatrix();
glTranslatef(face->glyph->advance.x >> 6 ,0,0);
Any advise at all would be helpful

You could use clip planes for that. They will determine the area where the text will be rendered. You can move the clip planes each frame so that clipped/visible area is changes and your text will slowly erode from the bottom up, pixel by pixel.
This code clips the text from right and left:
procedure TRenderUI.SetupClipX(X1,X2:smallint);
var cp:array[0..3]of real; //Function uses 8byte floats //ClipPlane X+Y+Z=-D
begin
glEnable(GL_CLIP_PLANE0);
glEnable(GL_CLIP_PLANE1);
FillChar(cp, SizeOf(cp), 0);
cp[0] := 1; cp[3] := -X1; //Upper edge
glClipPlane(GL_CLIP_PLANE0, #cp);
cp[0] := -1; cp[3] := X2; //Lower edge
glClipPlane(GL_CLIP_PLANE1, #cp);
end;
//Release all clipping planes
procedure TRenderUI.ReleaseClip;
begin
glDisable(GL_CLIP_PLANE0);
glDisable(GL_CLIP_PLANE1);
end;
You can use up to 4 clipping planes simultaneously.

Related

OpenGL: How to fix missing corner pixel in rect (lines or line loop) [duplicate]

This question already has answers here:
OpenGL GL_LINES endpoints not joining
(5 answers)
Closed 1 year ago.
Take a look at the bottom-left corner of the green rectangles in the middle:
They're missing one pixel at the bottom left.
I drew those like this:
class Rect: public StaticModel {
public:
Rect() {
constexpr glm::vec2 vertices[] {
{-0.5,0.5}, // top left
{0.5,0.5}, // top right
{0.5,-0.5}, // bottom right
{-0.5,-0.5}, // bottom left
};
_buf.bufferData<glm::vec2>(vertices,BufferUsage::StaticDraw);
_idxBuf.bufferData<GLuint>({0,1,3,2,0,3,1,2},BufferUsage::StaticDraw);
}
void bind() const override {
_buf.bindVertex();
_idxBuf.bind();
}
void draw() const override {
gl::drawElements(8,DrawMode::Lines);
}
private:
VertexBuffer _buf{sizeof(glm::vec2)};
ElementArrayBuffer _idxBuf{};
};
That code is using a bunch of my helper methods/classes but you should be able to tell what it does. I tried drawing the rect using a simple GL_LINE_LOOP but that had the same problem, so now I'm trying GL_LINES and drawing all the lines in the same direction: top to bottom and left to right, but even still I'm missing a pixel.
These coordinates are going through orthographic projection:
gl_Position = projection * model * vec4(inPos, 0.0, 1.0);
So the shader is scaling those 0.5 coords up to pixel coords, but I don't think it's a rounding error.
Anything else I can try to get that corner to align?
OpenGL gives a lot of leeway for how implementations rasterize lines. It requires some desirable properties, but those do not prevent gaps when mixing x-major ('horizontal') and y-major ('vertical') lines.
First thing, the "spirit of the spec" is to rasterize half-open lines; i.e. include the first vertex and exclude the final one. For that reason you should ensure that each vertex appears exactly once as a source and once as destination:
_idxBuf.bufferData<GLuint>({0,1,1,2,2,3,3,0},BufferUsage::StaticDraw);
This is contrary to your attempt of drawing "top to bottom and left to right".
GL_LINE_LOOP already does that though, and you say that it doesn't solve the problem. That is indeed not guaranteed to solve the problem because you mix x-major and y-major lines here, but you still should follow the rule in order for the next point to work.
Next, I bet, some of your vertices fall right between the pixels; i.e. the window coordinates fractional part is exactly zero. When rasterizing such primitives the differences between different implementations (or in our case between x-major and y-major lines on the same implementation) become prominent.
To solve that you can snap your vertices to the pixel grid:
// xy - vertex in window coordinates, i.e. same as gl_FragCoord
xy = floor(xy) + 0.5
You can do this either in C++, or in the vertex shader. In either case you'll need to apply the projection and viewport transformations, and then undo them so that OpenGL can re-apply them afterwards. It's ugly, I know.
The only bullet-proof way to rasterize pixel-perfect lines, however, is to render triangles to cover the shape (either each line individually or the entire rectangle) and compute the coverage analytically from gl_FragCoord.xy in the fragment shader.

Not updating coordinate positions?

I have managed to rotate a rectangle in OpenGL (C++) just fine. I am making a program that tests two rectangles for collision using the "separated axis theorem". To use the theorem, I need the x and y coordinates of each corner of the rectangle, but my problem is that, although I call glRotatef(...), the coordinates of the corners of the rectangle are not changed to the values that they are rotated too, but the rectangle rotates as it should. How can I update the coordinates of my rectangle after glRotatef is called?
Code:
// float r1.x[4] and r1.y[4] hold the x and y position of each of the 4 corners, starting with the upper left (r1.x[0], r1.y[0])
glLoadIdentity();
glTranslatef((r1.x[0] + r1.x[2]) / 2, (r1.y[1] + r1.y[3]) / 2, 0); // Translates matrix to center of rectangle
glRotatef(r1.angle, 0, 0, 1);
glTranslatef(-((r1.x[0] + r1.x[2]) / 2), -((r1.y[1] + r1.y[3]) / 2), 0); // Translates back
r1.angle++;
glBegin(GL_QUADS);
glVertex2f(r1.x[0], r1.y[0]);
glVertex2f(r1.x[1], r1.y[1]);
glVertex2f(r1.x[2], r1.y[2]);
glVertex2f(r1.x[3], r1.y[3]);
glEnd();
Transformation calls in OpenGL (like glTranslatef and glRotatef) update an internal transformation matrix that get multiplied by the points you provide before getting drawn on the screen. OpenGL does not at all touch your data.
In general, that is what you want. You have a model that is constant in time, but it gets transformed around.
If however, you do need to update your data, you need to create your own transformation matrix, manually multiply it and then draw with a clean transformation matrix (with glLoadIdentity)
You could get a little help from OpenGL though, as you can get the transformation matrix from OpenGL, but I don't recommend this. The math is not that hard and you'd appreciate learning how to do it.

2D tile based game, shows gaps between the tile sprites when I zoom in with the camera?

I am using the D3DXSPRITE method to draw my map tiles to the screen, i just added a zoom function which zooms in when you hold the up arrow, but noticed you can now see gaps between the tiles, here's some screen shots
normal size (32x32) per tile
zoomed in (you can see white gaps between the tiles)
zoomed out (even worst!)
Here's the code snipplet which I translate and scale the world with.
D3DXMATRIX matScale, matPos;
D3DXMatrixScaling(&matScale, zoom_, zoom_, 0.0f);
D3DXMatrixTranslation(&matPos, xpos_, ypos_, 0.0f);
device_->SetTransform(D3DTS_WORLD, &(matPos * matScale));
And this is my drawing of the map, (tiles are in a vector of a vector of tiles.. and I haven't done culling yet)
LayerInfo *p_linfo = NULL;
RECT rect = {0};
D3DXVECTOR3 pos;
pos.x = 0.0f;
pos.y = 0.0f;
pos.z = 0.0f;
for (short y = 0;
y < BottomTile(); ++y)
{
for (short x = 0;
x < RightTile(); ++x)
{
for (int i = 0; i < TILE_LAYER_COUNT; ++i)
{
p_linfo = tile_grid_[y][x].Layer(i);
if (p_linfo->Visible())
{
p_linfo->GetTextureRect(&rect);
sprite_batch->Draw(
p_engine_->GetTexture(p_linfo->texture_id),
&rect, NULL, &pos, 0xFFFFFFFF);
}
}
pos.x += p_engine_->TileWidth();
}
pos.x = 0;
pos.y += p_engine_->TileHeight();
}
Your texture indices are wrong. 0,0,32,32 is not the correct value- it should be 0,0,31,31. A zero-based index into your texture atlas of 256 pixels would yield values of 0 to 255, not 0 to 256, and a 32x32 texture should yield 0,0,31,31. In this case, the colour of the incorrect pixels depends on the colour of the next texture along the right and the bottom.
That's the problem of magnification and minification. Your textures should have invisible border populated with part of adjacent texture. Then magnification and minification filters will use that border to calculate color of edge pixels rather than default (white) color.
I think so.
I also had a similar problem with texture mapping. What worked for me was changing the texture address mode in the sampler state description; texture address mode is used to control what direct3d does with texture coordinates outside of the ([0.0f, 1.0f]) range: i changed the ADDRESS_U, ADDRESS_V, ADDRESS_W members to D3D11_TEXTURE_ADDRESS_CLAMP which basically clamps all out-of-range values for the texture coordinates into the [0.0f, 1.0f] range.
After a long time searching and testing people solutions I found this rules are the most complete rules that I've ever read.
pixel-perfect-2d from Official Unity WebSite
plus with my own experience i found out that if sprite PPI is 72(for example), you should try to use more PPI for that Image(96 maybe or more).It actually make sprite more dense and make no space for white gaps to show up.
Welcome to the world of floating-point. Those gaps exist due to imperfections using floating-point numbers.
You might be able to improve the situation by being really careful when doing your floating-point math but those seams will be there unless you make one whole mesh out of your terrain.
It's the rasterizer that given the view and projection matrix as well as the vertex positions is slightly off. You maybe able to improve on that but I don't know how successful you'll be.
Instead of drawing different quads you can index only the visible vertexes that make up your terrain and instead use texture tiling techniques to paint different stuff on there. I believe that won't get you the ugly seam because in that case, there technically isn't one.

DirectX problems

I have a couple of queries regarding programming in DirectX using C++.
The first problem that I am having is that I have a texture that doesn't display on screen properly. The window is set to 800x600 when it is created and the texture is also 800x600 but when the program is loaded, only part of the texture is displayed. The code is shown below for the texture loading and drawing.
//This sets the image
helpFileTexture = new Texture(d3dDevice, L"../Resources/Help Guide.png");
//This is the draw function
helpFileTexture->Draw(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
//Which calls this
void Texture::Draw(long xPos, long yPos, long width, long height)
{
sprite->Begin(NULL);
RECT imageRectangle;
imageRectangle.left = xPos;
imageRectangle.top = yPos;
imageRectangle.right = imageRectangle.left + width;
imageRectangle.bottom = imageRectangle.top + height;
sprite->Draw(texture, &imageRectangle, &D3DXVECTOR3(1.0f, 1.0f, 0.0f), &D3DXVECTOR3((float)xPos, (float)yPos, 0.0f), D3DCOLOR_XRGB(255, 255, 255));
sprite->End();
}
As I said the SCREEN_WIDTH is set to 800 and the SCREEN_HEIGHT is set to 600 (which are also the same dimensions as the image). It draws from the top left as it should do but will only show part of the image. The window size was set to about 1100x1100 when the entire image could be seen. Have I done something wrong in the coding to set the image size.
The next thing is that I am having a problem hiding the cursor. I want to hide the cursor when I click the left mouse button and then have it reappear when I let go. But the cursor does not disappear. The coding for this is below.
if(input->mouseButtons.rgbButtons[0])
{
d3dDevice->ShowCursor(FALSE);
GetCursorPos(&input->mousePosition);
SetCursorPos(SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2);
input->mousePosition.x -= SCREEN_WIDTH / 2;
mainCamera->UpdateYaw(input->mousePosition.x * rotationSpeed);
indexYaw += mainCamera->GetYaw();
D3DXMatrixRotationY(&viewMatrix, indexYaw);
d3dDevice->SetTransform(D3DTS_VIEW, &viewMatrix);
}
else
{
d3dDevice->ShowCursor(TRUE);
}
As you can see the cursor is suppose to disappear when the left mouse button is click for the camera control but it still shows.
The last couple of things is what is the best way to implement collision detection between objects and terrain following or can you link me to where a good place to find these would be.
I know this is a lot I have asked but any help would be great
The fix you implemented is not correct (the scaling one). The reason for the sizing issue is that when the texture is loaded using the D3DXLoadTextureFromFile method, DirectX changes the size of the image to the nearest power of 2 higher than the actual size. Hence the reason for it appearing larger than the screen.
So, in order to prevent it from doing this, you should use the D3DXLoadTextureFromFileEx method, and specify D3DX_DEFAULT_NONPOW2 for parameters 3 and 4. This will stop DirectX from scaling up the size of the texture. For more information on the method, refer to the MSDN page: http://msdn.microsoft.com/en-us/library/bb172802(v=vs.85).aspx
Note: Be sure to use D3DPOOL_MANAGED as the D3DPOOL option, otherwise if you use D3DPOOL_DEFAULT your models will become see through! (as I found out).

World-Coordinate Issues with gluUnProject()

I'm currently calling Trace (method below) from a game loop. Right now all I'm trying to do is get the world coordinates from the screen mouse so I can move objects around in the world space. The values I'm getting from gluUnProject are however; puzzling me.
I was using glReadPixel(...) to get the Z value but that produced little to no movement in the object I was drawing and the resulting vector ended up being the same as my cameras location (except for the tiny decimal changes due to mouse movement), so I decided to get rid of the call and replace the Z value with 1.
My question is: Does the following code look right to you? Every example I've seen thusfar is either identical or -very- similar but I can't seem to produce correct results, even if I lock down the Y axis. If the code is correct, then I'm guessing that I'm just not using the resulting vector properly. Should I not be able to draw an object or point directly with the resulting vector or do I have to do something else with it, like normalize?
The current render mode is GL_RENDER and I am using glFrustum with a NearZ value of 1 and FarZ value of 2048, to create a perspective. There is also a series of viewports created along with scissors, with a size and width of 512x768 and positioned in each corner of a 1024x768 window. Trace(...) is called in between rendering of the upper left viewport and is the only perspective projection, while the other viewports are orthographic. FOV is set to 45.
void VideoWindow::Trace(int cursorX, int cursorY)
{
double objX, objY, objZ;//holder for world coordinates
GLint view[4];//viewport dimensions+pos
GLdouble p[16];//projection matrix
GLdouble m[16];//modelview matrix
GLdouble z;//Z-Buffer Value?
glGetDoublev (GL_MODELVIEW_MATRIX, m);
glGetDoublev (GL_PROJECTION_MATRIX,p);
glGetIntegerv( GL_VIEWPORT, view );
//view[3]-cursorY = conversion from upper left (0,0) to lower left (0,0)
//Unproject 2D Screen coordinates into wonderful world coordinates
gluUnProject(cursorX, view[3]-cursorY, 1, m, p, view, &objX, &objY, &objZ);
//Do something useful here???
}
Any ideas?
Edit: I've changed the winZ value to 0.5 instead of 1 which gives a vector thats more reasonable but drawing a point still wasn't matching the mouse. I found out that the value of view[3] was 384 which is correct for the viewport I'm using but I replaced it with 768 (the actual window size) and the point followed the mouse 100%. Further experimentation reveals that I can't use the coordinates to move around a 3D object in the perspective world space using this these coordinates however moving around 3D object in Orthographic space works fine.
The winz argument to gluUnproject specifies the depth from the camera at which you're "picking" your points. As you've stated this coordinate should be in the [0, 1] range.
Some tutorials like NeHes read out the z coordinate from the depth buffer so that you "pick" at the right depth, of course for this to work you'll have to do the gluUnproject after you've rendered everything else.
Regardless, if you set winz to 0.5 or something (not 0 or 1 or the point will end up on the near or far clip plane, and maybe culled) and do the following:
gluUnProject(cursorX, view[3]-cursorY, 0.5, m, p, view, &objX, &objY, &objZ);
//Do something useful here???
glPointSize(10);
glBegin(GL_POINTS);
glColor3f(1, 0, 0);
glVertex3f(objX, objY, objZ);
glEnd();
You should end up with a red blob at the mouse pointer (provided nothing else overdraws it afterwards and you don't have any funny render states which renders the point invisible).
just a thought, but if the third argument to gluUnProject is the z distance to the camera, wouldn't any point you draw at that location be on the near clipping plane of your frustum?
Better make that z value a bit higher.