Inverted text when rendering text in Cairo - c++

I am writing a program using Cairo where I need to change the coordinates from screen to Cartesian using the following code:
cairo_translate( cr, x, height );
cairo_scale( cr, 1.0, -1.0 ); // FLIP the Y axis
But when I try to render text (cairo_show_text), the text is inverted also and, hence, unreadable.
The same happens when using a scaled font (cairo_scaled_font_t):
cairo_font_options_t *font_options;
cairo_matrix_t ctm, font_matrix;
cairo_scaled_font_t *scaled_font;
font_options = cairo_font_options_create();
cairo_get_matrix( cr, &ctm );
cairo_get_font_matrix( cr, &font_matrix );
font_matrix.xx = font_matrix.yy = 20.0; // font size
// font_face initialized elsewhere and is valid
scaled_font = cairo_scaled_font_create( font_face, &font_matrix, &ctm, font_options );
cairo_set_scaled_font( cr, scaled_font );
cairo_move_to( cr, 1, 50 );
cairo_show_text( cr, "some text" );
...
I think the matrix needs some adjustments, but I don't know how. Any help is appreciated. Thanks in advance.
EDIT:
The text is upside down. For example, 'L' looks like a Gamma, and 'W' looks like an 'M'.

Theres two ways to do this that I know:
cairo_matrix_t ms, mt, m;
cairo_matrix_init_scale(&ms, 1.0f, -1.0f);
cairo_matrix_init_translate(&mt, 0.0f, -m_height);
cairo_matrix_multiply(&m, &mt, &ms);
cairo_set_matrix(cr, &m);
or:
cairo_scale(cr, 1.0f, -1.0f);
cairo_translate(cr, 0.0f, -m_height);
Both solved the problem for me. Scale the cr by the -1 on y, but that means the text is off the surface, so translate by the -height of the surface and it should sit right.

Since you flip the coordinate system upside down, text is also shown upside down. The solution to this problem is to manually flip back text, by setting a font matrix with a negative entry for the vertical scale. You can do this, by modifying your code for setting the font size like this:
double font_size = 20.0;
font_matrix.xx = font_size;
font_matrix.yy = -font_size; // negative size to vertically flip text

Well, you are flipping the Y-axis, thus the text gets flipped, too. Try this:
cairo_save(cr);
cairo_reset_clip(cr);
cairo_show_text(cr, "Some Text");
cairo_restore(cr);
The above replaces the cairo_show_text() call in your example.

Related

D3DXMatrixRotationAxis rotate the wrong axis

I'm writing simple 3d application, with directX. Im a newbie, but i think i understand how D3DX Rotation works.
when creating a colision detection functionality i notice that ball bounce in wrong direction. the code should change the direction of axis given in "direction" vector. Instead it change the 2 others:
speed = D3DXVECTOR3(1.0f, 2.0f, 3.0f);
direction = D3DXVECTOR3(1.0f, 0.0f, 0.0f);
D3DXMATRIX temp;
D3DXMatrixRotationAxis(&temp, &direction, 3.14f);
D3DXVec3TransformCoord(&speed, &speed, &temp);
from breakpoint i know that speed changed from 1 , 2 , 3 to:
_D3DVECTOR {x=0.999999762 y=-2.00477481 z=-2.99681091 } _D3DVECTOR
What am i doing wrong here? The idea is to invert the axis specified in direction vector.
You have created a rotation transformation of 180 around the X axis.
Operating that on (1,2,3) resulted with (1,-2,-3) which is what you specified.
"Bouncing" your "speed" S vector with a plane that has Normal N:
angle = acos(S*N); // provided that * is an operator for D3DXVec3Dot
axis = S^N; // provided that ^ is an operator for D3DXVec3Cross
D3DXMatrixRotationAxis(&temp, &axis , angle*2); // angle is *2
D3DXVec3TransformCoord(&S, &S, &temp);
S=-S; // negate direction

Orient object along surface normal

When the user clicks on a surface I would like place an object at this position and orient it perpendicular to the surface normal.
After the user performs a click, I read the depth of three neighboring pixels from the buffer, unproject the pixels from screen coordinates to object space and then compute the surface normal from these points in object space:
glReadPixels(mouseX, mouseY, ..., &depthCenter);
pointCenter = gluUnProject(mouseX, mouseY, depthCenter, ...);
glReadPixels(mouseX, mouseY - 1, ..., &depthUp);
pointUp = gluUnProject(mouseX, mouseY - 1, depthUp, ...);
glReadPixels(mouseX - 1, mouseY, ..., &depthLeft);
pointLeft = gluUnProject(mouseX - 1, mouseY, depthLeft, ...);
centerUpVec = norm( pointCenter - pointUp );
centerLeftVec = norm( pointCenter - pointLeft );
normalVec = norm( centerUpVec.cross(centerLeftVec) );
I know that computing the normal just from three pixels is problematic (e.g. at edges or if the three points have vastly different depth), but for my initial test on a flat surface this must suffice.
Finally, in order to orient the object along the computed normal vector I create a rotation matrix from the normal and the up vector:
upVec = vec(0.0f, 1.0f, 0.0f);
xAxis = norm( upVec.cross(normalVec) );
yAxis = norm( normalVec.cross(xAxis) );
// set orientation of model matrix
modelMat(0,0) = xAxis(0);
modelMat(1,0) = yAxis(0);
modelMat(2,0) = normalVec(0);
modelMat(0,1) = xAxis(1);
modelMat(1,1) = yAxis(1);
modelMat(2,1) = normalVec(1);
modelMat(0,2) = xAxis(2);
modelMat(1,2) = yAxis(2);
modelMat(2,2) = normalVec(2);
// set position of model matrix by using the previously computed center-point
modelMat(0,3) = pointCenter(0);
modelMat(1,3) = pointCenter(1);
modelMat(2,3) = pointCenter(2);
For testing purposes I'm placing an objects on a flat surface after each click. This works well in most cases when my camera is facing downwards the up vector.
However, once I rotate my camera the placed objects are oriented arbitrarily and I can't figure out why!
Ok, I just found a small, stupid bug in my code that was unrelated to the actual problem. Therefore, the approach stated in the question above is working correctly.
In order to avoid some pitfalls, one could of course just use a math library, such as Eigen, in order to compute the rotation between the up vector and the surface normal:
upVec = Eigen::Vector3f(0.0f, 1.0f, 0.0f);
Eigen::Quaternion<float> rotationQuat;
rotationQuat.setFromTwoVectors(upVec, normalVec);

Render FreeType text with flipped ortho, difference between top and baseline of glyph

I am working on a project where I implement a FreeType rendering object to draw text of which the rendering environment is specified with an orthographic projection matrix:
glm::ortho(0, Width, Height, 0);
This makes sure the coordinates are similar to standard GUI systems with (0,0) being the top-left part of the window instead of the bottom-left.
However when rendering using FreeType, things get difficult, because FreeType operates with their origin at the bottom-left of a glyph (minus the descender). My issue is similar to https://stackoverflow.com/questions/25353472/render-freetype-gl-text-with-flipped-projection but no answer was yet provided and his solution was not to my liking (the used library is also slightly different, I assume he is using a wrapper).
So I render my text as follows:
renderText("Testing 123 if text performs sufficiently", 0.0f, 0.0f, 1.0f, 1.0f);
Of which renderText function contains:
renderText(const GLchar *text, GLfloat x, GLfloat y, GLfloat sx, GLfloat sy)
{
[...]
GLfloat xpos = x + glyph->bitmap_left * sx;
GLfloat ypos = y - glyph->bitmap_top * sy;
GLfloat w = glyph->bitmap.width * sx;
GLfloat h = glyph->bitmap.rows * sy;
// Update VBO
GLfloat vertices[4][4] = {
{ xpos, ypos, 0, 0 },
{ xpos + w, ypos, 1, 0 },
{ xpos, ypos + h, 0, 1 },
{ xpos + w, ypos + h, 1, 1 }
};
[...]
}
If I render it like this, it will render the text below the y coordinate of 0 so it won't be visible unless I add an offset to the y coordinate. So looking at FreeType's glyph metrics:
I want to offset the y position by a positive amount equal to the difference between the origin and the top of the glyph image so it always neatly renders the text at my given position. Looking at the image I believe this to be the yMax value so I added the following statement to the code before updating the VBO:
ypos += (glyph->face->bbox.yMax >> 6) * sy;
Which seemed to fix the issue when I loaded the FreeType glyphs with font size 24, but as soon as I tried to use different font sizes it failed to work as this image shows:
As you can see, it clearly doesn't work as I thought it would. I've been thouroughly searching through FreeType's documentation if I was missing something, but I could not find it. Am I using the wrong metrics (using Ascender didn't work as well)?
I want to offset the y position by a positive amount equal to the difference between the origin and the top of the glyph image so it always neatly renders the text at my given position. Looking at the image I believe this to be the yMax value so I added the following statement to the code before updating the VBO:
ypos += (glyph->face->bbox.yMax >> 6) * sy;
In actuality, yMax is not what you are interested in. You could use yMax - yMin to find the height of your glyph, but that is really all it is good for.
From the FreeType 2 API documentation, FT_GlyphSlotRec::bitmap_top is:
The bitmap's top bearing expressed in integer pixels. Remember that this is the distance from the baseline to the top-most glyph scanline, upwards y coordinates being positive.
Look at the image you included in your question again, that is effectively bearingY. Your problem is that you are subtracting this value from your ypos when you should not be. You do need the value as I will explain below, but you definitely do not want to subtract it.
If you eliminate bitmap_top from your calculation of ypos you get the following:
Which is obviously incorrect because it ignores differences in ascent between each character in your string.
Now, take a close look at the following correctly aligned diagram:
In the diagram above, I have illustrated your string's top-most line in red, bottom-most in green and the baseline for all of your glyphs in grey.
As you can see, the capital letter 'T' has the greatest ascent and this generalization holds true for most fonts. Directly below the red line, I have illustrated the difference in ascent between capital 'T' and the current letter as the yellow area. This is the important quantity that you must calculate to properly align your string.
The yellow region in the correctly aligned figure above can be calculated thus:
Chars['T'].bitmap_top - glyph->bitmap_top
If you stop subtracting glyph->bitmap_top from ypos and add the value above, you should get the same results as the correctly aligned diagram.
For bonus points, if you want to align your text to the bottom of the screen, the concept is very similar only you are interested in the difference between the character with the greatest descent (often lowercase 'g') and the current character. That is the distance between the grey baseline and the green line and can be expressed as height - bearingY in your glyph metrics figure.
You should be able to compute descent using this:
(glyph->metrics.height >> 6) - glyph->bitmap_top // bitmap_top is in integer coords

C++ OpenGL / FreeType scrolling font

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.

Draw stroke characters with outlines in openGL

I am using openGL to draw fonts. My fonts need to be rotatable and I cannot use glut, so I created a static class that has vertex lists for every needed character. I then render these using GL_LINE_STRIP.
Recently I've been asked to allow my characters to have outlines, sort of like they would if you went into word, created a bold character and then under Font, gave it an outline.
Not sure how to put a picture of that in stack overflow.
I was wondering if there was a way to do that given my current method of drawing characters using lines. Is it possible to have a line border, or is that inherently nonsense?
Two passes:
const float OUTLINE_WIDTH = 3.0f;
const float INNER_WIDTH = 1.0f;
glLineWidth( OUTLINE_WIDTH );
glColor3ub( outline.r, outline.g, outline.b );
DrawText();
glLineWidth( INNER_WIDTH );
glColor3ub( inner.r, inner.g, inner.b );
DrawText();