Trying to draw text in OpenGL, but texture is offset slightly - opengl

I am trying to draw text in OpenGL. I used a small C# program to draw all characters from 0x21 to 0x7E into a bitmap. I load that as a texture and try to use that to draw my text. It appears to work, but I seem to get some weird problems. http://i54.tinypic.com/mmd7k8.png Notice the extra pixel next to 'a' and the fact that 'c' is cut off slightly. It appears the whole thing is shifted slightly. Does anybody know why I get this problem? I don't want to use a library such as gltext because I don't want to depend on libfreetype as I am only drawing a few strings. Here is the code that I am using:
static void textDrawChar(char c, int x, int y)
{
GLfloat vert[8];
GLfloat texcoord[8];
vert[0] = x; vert[1] = y;
vert[2] = x; vert[3] = y + TEXT_HEIGHT;
vert[4] = x + font_char_width[c-0x21]; vert[5] = y + TEXT_HEIGHT;
vert[6] = x + font_char_width[c-0x21]; vert[7] = y;
texcoord[0] = (float)(font_char_pos[c-0x21])/TOTAL_WIDTH;
texcoord[1] = 1.0f;
texcoord[2] = (float)(font_char_pos[c-0x21])/TOTAL_WIDTH;
texcoord[3] = 0.0f;
texcoord[4] = (float)(font_char_pos[c-0x21] + font_char_width[c-0x21])/TOTAL_WIDTH;
texcoord[5] = 0.0f;
texcoord[6] = (float)(font_char_pos[c-0x21] + font_char_width[c-0x21])/TOTAL_WIDTH;
texcoord[7] = 1.0f;
glBindTexture(GL_TEXTURE_2D, texture);
glVertexPointer(2, GL_FLOAT, 0, vert);
glTexCoordPointer(2, GL_FLOAT, 0, texcoord);
glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, indices);
}
void textDraw(void)
{
textDrawChar('a', 300, 300);
textDrawChar('b', 300+font_char_width['a'-0x21], 300);
textDrawChar('c', 300+font_char_width['a'-0x21]+font_char_width['b'-0x21], 300);
}
EDIT I added 4 to the texture coordinate (0,2,4,6) and that seems to have fixed the problem. However, now I need to know whether that will continue to work or may break for unknown reasons. Here is the bitmap creation code, in case the problem might be in there.
using System;
using System.Drawing;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Collections;
namespace font_to_bmp
{
class Program
{
static void Main(string[] args)
{
Bitmap b = new Bitmap(1715, 36);
Graphics g = Graphics.FromImage(b);
g.FillRectangle(new SolidBrush(Color.Transparent), 0, 0, 1715, 36);
Font f = new Font("Liberation Sans", 24, GraphicsUnit.Point);
g.PageUnit = GraphicsUnit.Pixel;
int curx = 0;
StreamWriter w = new StreamWriter(new FileStream("font_width.h", FileMode.Create, FileAccess.Write, FileShare.Read));
w.WriteLine("static const int font_char_width[] = {");
ArrayList hax = new ArrayList();
for (int i = 0x21; i <= 0x7E; i++)
{
char c = (char)i;
string s = c.ToString();
SizeF sz = g.MeasureString(s, f);
StringFormat sf = new StringFormat();
sf.SetMeasurableCharacterRanges(new CharacterRange[] {new CharacterRange(0,1)});
Region r = g.MeasureCharacterRanges(s, f, new RectangleF(0, 0, 1000, 1000), sf)[0];
RectangleF r2 = r.GetBounds(g);
Console.WriteLine("{0} is {1}x{2}", s, r2.Width, r2.Height);
int w_int = (int)(Math.Ceiling(r2.Width));
g.DrawString(s, f, new SolidBrush(Color.Black), curx, 0);
hax.Add(curx);
curx += w_int;
w.WriteLine("\t{0},", w_int);
}
Console.WriteLine("Total width {0}", curx);
w.WriteLine("};");
w.WriteLine();
w.WriteLine("static const int font_char_pos[] = {");
foreach(int z in hax)
{
w.WriteLine("\t{0},", z);
}
w.WriteLine("};");
w.Close();
b.Save("font.png");
}
}
}

Addressing the pixels exactly in a texture is a bit tricky. See my answer given in OpenGL Texture Coordinates in Pixel Space
This has been asked a few times, but I don't have the links at hand, so a quick and rough explanation. Let's say the texture is 8 pixels wide:
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
^ ^ ^ ^ ^ ^ ^ ^ ^
0.0 | | | | | | | 1.0
| | | | | | | | |
0/8 1/8 2/8 3/8 4/8 5/8 6/8 7/8 8/8
The digits denote the texture's pixels, the bars the edges of the texture and in case of nearest filtering the border between pixels. You however want to hit the pixels' centers. So you're interested in the texture coordinates
(0/8 + 1/8)/2 = 1 / (2 * 8)
(1/8 + 2/8)/2 = 3 / (2 * 8)
...
(7/8 + 8/8)/2 = 15 / (2 * 8)
Or more generally for pixel i in a N wide texture the proper texture coordinate is
(2i - 1)/(2N)
However if you want to perfectly align your texture with the screen pixels, remember that what you specify as coordinates are not a quad's pixels, but edges, which, depending on projection may align with screen pixel edges, not centers, thus may require other texture coordinates.

Related

Convert Pixels Buffer type from 1555 to 5551 (C++, OpenGL ES)

I'm having a problem while converting OpenGL video plugin to support GLES 3.0
So far everything went well, except glTexSubImage2D the original code uses GL_UNSIGNED_SHORT_1_5_5_5_REV as pixels type which is not supported in GLES 3.0
the type that worked is GL_UNSIGNED_SHORT_5_5_5_1 but colors and pixels are broken,
so I thought converting the pixels buffer would be fine..
but due to my limited understanding in GL and C++ I didn't succeed to do that.
Pixels process:
the pixels will be converted internally to 16 bit ABGR as in the Shader comments:
// Take a normalized color and convert it into a 16bit 1555 ABGR
// integer in the format used internally by the Playstation GPU.
uint rebuild_psx_color(vec4 color) {
uint a = uint(floor(color.a + 0.5));
uint r = uint(floor(color.r * 31. + 0.5));
uint g = uint(floor(color.g * 31. + 0.5));
uint b = uint(floor(color.b * 31. + 0.5));
return (a << 15) | (b << 10) | (g << 5) | r;
}
it will be received by this method after processing by vGPU:
static void Texture_set_sub_image_window(struct Texture *tex, uint16_t top_left[2], uint16_t resolution[2], size_t row_len, uint16_t* data)
{
uint16_t x = top_left[0];
uint16_t y = top_left[1];
/* TODO - Am I indexing data out of bounds? */
size_t index = ((size_t) y) * row_len + ((size_t) x);
uint16_t* sub_data = &( data[index] );
glPixelStorei(GL_UNPACK_ROW_LENGTH, (GLint) row_len);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glBindTexture(GL_TEXTURE_2D, tex->id);
glTexSubImage2D(GL_TEXTURE_2D, 0,
(GLint) top_left[0], (GLint) top_left[1],
(GLsizei) resolution[0], (GLsizei) resolution[1],
GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV /* Not supported in GLES */,
(void*)sub_data);
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
}
as for row_len it's get the value from #define VRAM_WIDTH_PIXELS 1024
What I tried to do:
1st I replaced the type with another one:
glTexSubImage2D(GL_TEXTURE_2D, 0,
(GLint) top_left[0], (GLint) top_left[1],
(GLsizei) resolution[0], (GLsizei) resolution[1],
GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1 /* <- Here new type */,
(void*)sub_data);
2nd converted sub_data using this method:
uint16_t* ABGRConversion(const uint16_t* pixels, int row_len, int x, int y, int width, int height) {
uint16_t *frameBuffer = (uint16_t*)malloc(width * row_len * height);
signed i, j;
for (j=0; j < height; j++)
{
for (i=0; i < width; i++)
{
int offset = j * row_len + i;
uint16_t pixel = pixels[offset];
frameBuffer[offset] = Convert1555To5551(pixel); //<- stuck here
}
}
return frameBuffer;
}
I have no idea what Convert1555To5551 should look like?
Note: Sorry if some descriptions is wrong, I don't really have full understanding for the whole process.
Performance is not major problem.. just need to know how to deal with the current pixel buffer.
Side note: I had to replace glFramebufferTexture with glFramebufferTexture2D so I hope it's not involved in the issue.
Thanks.
This should be what you're looking for.
uint16_t Convert1555To5551(uint16_t pixel)
{
// extract rgba from 1555 (1 bit alpha, 5 bits blue, 5 bits green, 5 bits red)
uint16_t a = pixel >> 15;
uint16_t b = (pixel >> 10) & 0x1f; // mask lowest five bits
uint16_t g = (pixel >> 5) & 0x1f;
uint16_t r = pixel & 0x1f;
// compress rgba into 5551 (5 bits red, 5 bits green, 5 bits blue, 1 bit alpha)
return (r << 11) | (g << 6) | (b << 1) | a;
}

Fastest Method to compute Linear interpolation between 2 points in QT using OpenGL

I'm trying to interpolate a triangle with the help of vertex coordinates.
a
|\
| \
| \
| \
b|_ _ _ \c
I'm interpolating the vertices in this order (b,a),(a,c)and (c,b).
Here the a,b and c are the 3 dimensional coordinates with a color value.
a = (x1,y1,z1,c1);
b = (x2,y2,z2,c2);
c = (x3,y3,z3,c3);
Structure used to compute the calculation:
struct pointsInterpolateStruct{
QList<double> x,y,z;
QList<double> r, g, b, clr;
void clear() {
x.clear();
y.clear();
z.clear();
r.clear();
g.clear();
b.clear();
clr.clear();
}
};
Interpolation Code:
QList<double> x,y,z,clrs;
This above mentioned lists has been used to read the values from a file which contains the coordinates of a,b and c.
/**
void interpolate();
#param1 ipts is an object for the point interpolation struct which holds the x,y,z and color
#param2 idx1 is the point A
#param 3idx2 is the point B
#return returns the interpolated values after filling the struct pointsInterpolateStruct
*/
void GLThread::interpolate(pointsInterpolateStruct *ipts,int idx1, int idx2) {
int ipStep = 0;
double delX, imX,iX,delY,imY,iY,delZ,imZ,iZ,delClr,imC,iC;
ipStep = 5; // number of points needed between the 2 points
delX = imX = iX = delY = imY = iY = delZ = imZ = iZ = delClr = imC = iC = 0;
delX = (x.at(idx2) - x.at(idx1));
imX = x.at(idx1);
iX = (delX / (ipStep + 1));
delY = (y.at(idx2) - y.at(idx1));
imY = aParam->y.at(idx1);
iY = (delY / (ipStep + 1));
delZ = (z.at(idx2) - z.at(idx1));
imZ = z.at(idx1);
iZ = (delZ / (ipStep + 1));
delClr = (clrs.at(idx2) - clrs.at(idx1));
imC = clrs.at(idx1);
iC = (delClr / (ipStep + 1));
ipts->clear();
int i = 0;
while(i<= ipStep) {
ipts->x.append((imX+ iX * i));
ipts->y.append((imY+ iY * i));
ipts->z.append((imZ+ iZ * i));
ipts->clr.append((imC + iC * i));
i++;
}
}*
Visualization of this interpolated points using OpenGL :
All the points are filled to vertices and color buffers and I'm drawing it using the below format. Visualization is very fast even for larger points.
void GLWidget::drawInterpolatedTriangle(void) {
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_VERTEX_ARRAY);
glColorPointer(3, GL_FLOAT, 0, clr);
glVertexPointer(3, GL_FLOAT, 0, vrt);
glPushMatrix();
glDrawArrays(GL_POLYGON, 0, vrtCnt);
glPopMatrix();
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
}
}
}
Now everything working fine. I'm getting the desired output. But the problem is when I'm trying to do the same for 'n' number of triangles (say n = 40,000), the application gets crashed even if I called this function in a QThread and I found that this method is not an efficient method as it takes lot of time for computation.
Please suggest an optimistic way to do this process so that I can achieve better results at good performance.
Output image :
Interpolated Triangle (point view)
Mesh View
Polygon View
After examining the memory used by the application, I found that there's large number of unwanted data has been stored in the list and arrays in my program (i.e., clearing the list x,y,z,r,g,b and clrs in pointsInterpolateStruct). I have cleared all the unwanted / unused data instantly and tried to run the application with larger triangles. Now I can achieve better performance. I didn't changed anything in visualization process.

SFML leaves part of texture blank, if I create it from PixelPtr

I have a code, which converts plain BGR data to sf::Texture. "ifs" is opened ifstream to file which contains byte triplets of BGR colors (header of source file is omitted). And Width & Height 100% valid. In my example image is 800x600.
struct h3pcx_color_bgr { uint8_t b, uint8_t g, uint8_t r };
sf::Uint8* pixels = new sf::Uint8[width * height * 4];
h3pcx_color_bgr* fileData = new h3pcx_color_bgr[width*height];
ifs.read((char*)fileData, width * height * sizeof(h3pcx_color_bgr));
for (uint32_t i = 0; i < width*height; ++i) {
pixels[i * 4] = fileData[i].r;
pixels[i * 4 + 1] = fileData[i].g;
pixels[i * 4 + 2] = fileData[i].b;
pixels[i * 4 + 3] = 255;
}
This code works good, problem comes after. Once I draw my texture:
m_tex.update(pixels); //sf::Texture
m_sprite.setTexture(m_tex); //sf::Sprite
m_window->draw(m_sprite); // m_window is sf::RenderWindow
I have this annoying grey line in image below:
What I did:
Verified, that pixels contains valid value
Code snippet below (700 * 595 is inside "grey area") shows, that both pixels and fileData contains valid data (not grey color, which is appears just uninitialized memory).
auto f = fileData[700 * 595]; // 32, 31, 38
auto r = pixels[700 * 595 * 4]; // 38
auto g = pixels[700 * 595 * 4 + 1]; // 31
auto b = pixels[700 * 595 * 4 + 2]; // 32
"Grey" color is 204, 204, 204.
Tried to use sf::Image
If we do something like this:
img.create(width, height, pixels); // img is sf::Image
img.setPixel(700, 595, sf::Color::Blue);
And then convert it to sf::Texture, and draw. Result will be same image with grey area, but pixel 700, 585 will be blue!
If I get color value from "grey area":
auto clr = img.getPixel(700,600); //sf::Color(204,204,204)
So, it looks like, there are some hard-limit(???) on quantity of pixels (but I doubt it, since I've looked on actual SFML code, and did not found anything suspicious) or my stupid mistake. I would be very grateful, if someone can point out - why this grey line appears.
In the code:
auto f = fileData[700 * 595];
You are accessing pixel 500, 520. To access the pixel 700, 595 you have to use:
auto f = fileData[700 + 595 * 800]; // x + y * width
I would write this as a comment, but I lack the necessary reputation.
If any1 is wondering - It's just file is wrong, with this exact grey color in the end. Code is correct.

openGL drawElements - one extra triangle, using index array?

I'm generating a terrain from a .bmp file, as a very early precursor for a strategy game. In my code I load the BMP file as an openGL texture, then using a double loop to generate coordinates (x, y redChannel). Then I create indices by again double looping and generating the triangles for a square between (x,y) to (x+1, y+1). However, when I run the code, I end up with an extra triangle going from the end of one line to the beginning of the next line, and which I cannot seem to solve. This only happens when I use varied heights and a sufficiently large map, or at least it is not visible otherwise.
This is the code:
void Map::setupVertices(GLsizei* &sizeP, GLint * &vertexArray, GLubyte* &colorArray){
//textureNum is the identifier generated by glGenTextures
GLuint textureNum = loadMap("heightmap.bmp");
//Bind the texture again, and extract the needed data
glBindTexture(GL_TEXTURE_2D, textureNum);
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width);
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &height);
GLint i = height*width;
GLubyte * imageData = new GLubyte[i+1];
glGetTexImage(GL_TEXTURE_2D,0,GL_RED, GL_UNSIGNED_BYTE, &imageData[0]);
//Setup varibles: counter (used for counting vertices)
//VertexArray: pointer to address for storing the vertices. Size: 3 ints per point, width*height points total
//ColorArray: pointer to address for storing the color data. 3 bytes per point.
int counter = 0;
vertexArray = new GLint[height*width*3];
colorArray = new GLubyte[height*width*3];
srand(time(NULL));
//Loop through rows
for (int y = 0; y < height; y++){
//Loop along the line
for (int x=0; x < width; x++){
//Add vertices: x, y, redChannel
//Add colordata: the common-color.
colorArray[counter] = imageData[x+y*width];
vertexArray[counter++] = x;
colorArray[counter] = imageData[x+y*width];
vertexArray[counter++] = y;
colorArray[counter] = imageData[x+y*width];//(float) (rand() % 255);
vertexArray[counter++] = (float)imageData[x+y*width] /255 * maxHeight;
}
}
//"Return" total vertice amount
sizeP = new GLsizei(counter);
}
void Map::setupIndices(GLsizei* &sizeP, GLuint* &indexArray){
//Pointer to location for storing indices. Size: 2 triangles per square, 3 points per triangle, width*height triangles
indexArray = new GLuint[width*height*2*3];
int counter = 0;
//Loop through rows, don't go to top row (because those triangles are to the row below)
for (int y = 0; y < height-1; y++){
//Loop along the line, don't go to last point (those are connected to second last point)
for (int x=0; x < width-1; x++){
//
// TL___TR
// | / |
// LL___LR
int lowerLeft = x + width*y;
int lowerRight = lowerLeft+1;
int topLeft = lowerLeft + width+1;
int topRight = topLeft + 1;
indexArray[counter++] = lowerLeft;
indexArray[counter++] = lowerRight;
indexArray[counter++] = topLeft;
indexArray[counter++] = topLeft;
indexArray[counter++] = lowerRight;
indexArray[counter++] = topRight;
}
}
//"Return" the amount of indices
sizeP = new GLsizei(counter);
}
I eventually draw this with this code:
void drawGL(){
glPushMatrix();
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3,GL_INT,0,mapHeight);
glEnableClientState(GL_COLOR_ARRAY);
glColorPointer(3,GL_UNSIGNED_BYTE,0,mapcolor);
if (totalIndices != 0x00000000){
glDrawElements(GL_TRIANGLES, *totalIndices, GL_UNSIGNED_INT, indices);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
glPopMatrix();
}
Here's a picture of the result:
http://s22.postimg.org/k2qoru3kx/open_GLtriangles.gif
And with only blue lines and black background.
http://s21.postimg.org/5yw8sz5mv/triangle_Error_Blue_Line.gif
There also appears to be one of these going in the other direction as well, at the very edge right, but I'm supposing for now that it may be related to the same issue.
I'd simplify this part:
int lowerLeft = x + width * y;
int lowerRight = (x + 1) + width * y;
int topLeft = x + width * (y + 1);
int topRight = (x + 1) + width * (y + 1);
The problem looks like topLeft has an extra + 1 when it should only have the + width.
This causes the "top" vertices to both be shifted along by one column. You might not notice the offsets within the grid and, as you pointed out, they're not visible until the height changes.
Also, returning new GLsizei(counter) seems a bit round about. Why not just pass in GLsizei& counter.
These might be worth a look too. You can save a fair bit of data using strip primitives for many procedural objects:
Generate a plane with triangle strips
triangle-strip-for-grids-a-construction

OgreBullet incorrect HeightmapCollisionShape shape scale?

I am trying to load a HeightmapTerrainShape in OgreBullet by (mostly) using the demo code, but my terrain mesh is offset from the HeightmapTerrainShape. I have no clue why this is happening. This is my code:
void TerrainLoader::setTerrainPhysics(Ogre::Image *imgPtr)
{
unsigned page_size = terrainGroup->getTerrainSize();
Ogre::Vector3 terrainScale(4096 / (page_size-1), 600, 4096 / (page_size-1));
float *heights = new float[page_size*page_size];
for(unsigned y = 0; y < page_size; ++y)
{
for(unsigned x = 0; x < page_size; ++x)
{
Ogre::ColourValue color = imgPtr->getColourAt(x, y, 0);
heights[x + y * page_size] = color.r;
}
}
OgreBulletCollisions::HeightmapCollisionShape *terrainShape = new OgreBulletCollisions::HeightmapCollisionShape(
page_size,
page_size,
terrainScale,
heights,
true
);
OgreBulletDynamics::RigidBody *terrainBody = new OgreBulletDynamics::RigidBody(
"Terrain",
OgreInit::level->physicsManager->getWorld()
);
imgPtr = NULL;
Ogre::Vector3 terrainShiftPos(terrainScale.x/(page_size-1), 0, terrainScale.z/(page_size-1));
terrainShiftPos.y = terrainScale.y / 2 * terrainScale.y;
Ogre::SceneNode *pTerrainNode = OgreInit::sceneManager->getRootSceneNode()->createChildSceneNode();
terrainBody->setStaticShape(pTerrainNode, terrainShape, 0.0f, 0.8f, terrainShiftPos);
//terrainBody->setPosition(terrainBody->getWorldPosition()-Ogre::Vector3(0.005, 0, 0.005));
OgreInit::level->physicsManager->addBody(terrainBody);
OgreInit::level->physicsManager->addShape(terrainShape);
}
This is what it looks like with the debug drawer turned on:
My world is 4096*600*4096 in size, and each chunk is 64*600*64
heights[x + y * page_size] = color.r;
This Line gives you negative values. If you combine negative terrain height values with ogre bullet terrain, you get a wrong bounding box conversation.
You need to use the intervall 0-1 for height values.
Had the same problem with perlin noise filter that gives you values from -1 to 1.