PDA

View Full Version : Problems Drawing Letters With GL_LINE_STRIP



Ganheddo
04-27-2008, 12:13 AM
Hi everyone,

I've started working with C++ and OpenGL/GLUT a few weeks ago and I'm having a few probs with GL_LINE_STRIP.

Here's my code:

#include <stdlib.h>
#include <string.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glut.h>

// size per char = 1..6 x 1..12, 0 = end of stroke, -1 = end of data
GLfloat AData[] = {1,3, 1,10, 0, 2,11, 4,11, 0, 5,10, 5,3, 0, 2,7,
4,7, -1};
GLfloat BData[] = {4,3, 1,3, 1,11, 4,11, 0, 1,7, 4,7, 0, 5,4, 5,6,
0, 5,8, 5,10, -1};
GLfloat CData[] = {2,3, 5,3, 0, 1,4, 1,10, 0, 2,11, 5,11, -1};
/*
GLbyte DData[] = {};
GLbyte EData[] = {};
GLbyte FData[] = {};
*/

/* drawLetter() interprets the instructions from the array
* for that letter and renders the letter with line segments.
*/
static void drawLetter(GLfloat *charData)
{
glBegin(GL_LINE_STRIP);
for (int ii = 0; charData[ii] != -1;)
{
if (charData[ii] != 0)
{
glVertex2f(charData[ii], charData[ii + 1]);
ii++;ii++;
}
else
{
glEnd();
glBegin(GL_LINE_STRIP);
ii++;
}
}
glEnd();
glTranslatef(8.0, 0.0, 0.0);
}

/* Create a display list for each character */
static void init (void)
{
GLuint base;

glShadeModel (GL_FLAT);

base = glGenLists (128);
glListBase(base);
glNewList(base+'A', GL_COMPILE); drawLetter(AData);
glEndList();
glNewList(base+'B', GL_COMPILE); drawLetter(BData);
glEndList();
glNewList(base+'C', GL_COMPILE); drawLetter(CData);
glEndList();
/*
glNewList(base+'D', GL_COMPILE); drawLetter(DData);
glEndList();
glNewList(base+'E', GL_COMPILE); drawLetter(EData);
glEndList();
glNewList(base+'F', GL_COMPILE); drawLetter(FData);
glEndList();
*/
glNewList(base+' ', GL_COMPILE);
glTranslatef(8.0, 0.0, 0.0); glEndList();
}

char *test1 = "ABC";
char *test2 = "C B A";

static void printStrokedString(char *s)
{
GLsizei len = strlen(s);
glCallLists(len, GL_BYTE, (GLbyte *)s);
}

void display(void)
{
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1.0, 1.0, 1.0);
glPushMatrix();
//glScalef(2.0, 2.0, 2.0);
glTranslatef(10.0, 220.0, 0.0);
printStrokedString(test1);
glPopMatrix();
glPushMatrix();
//glScalef(2.0, 2.0, 2.0);
glTranslatef(10.0, 204.0, 0.0);
printStrokedString(test2);
glPopMatrix();
glFlush();
}

void reshape(int w, int h)
{
glViewport(0, 0, (GLsizei) w, (GLsizei) h);
glMatrixMode (GL_PROJECTION);
glLoadIdentity ();
gluOrtho2D (0.0, (GLdouble) w, 0.0, (GLdouble) h);
}

void keyboard(unsigned char key, int x, int y)
{
switch (key) {
case ' ':
glutPostRedisplay();
break;
case 27:
exit(0);
}
}

int main(int argc, char** argv)
{
glutInit(&amp;argc, argv);
glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize (640, 480);
glutCreateWindow (argv[0]);
init ();
glutReshapeFunc(reshape);
glutKeyboardFunc(keyboard);
glutDisplayFunc(display);
glutMainLoop();
return 0;
}


The problem is that seperate line strips are disconnected. There seems to be some imprecision (the specified pixel coordinates in the arrays should be okay?) but I can't figure out where this comes from.
If I you edit out the code tags before the scaling commands, then it becomes even more apparant.
I tried it with GL_LINES instead of GL_LINE_SRTIP but it got even worse. So I guess my specified coordinates aren't mapped accurately to the window's pixels? Is there a way to solve this?

Inquisitor
04-27-2008, 06:04 AM
Just a guess (I didn't try it out):
You shouldn't compare floats against exact values.
Perhaps changing

charData[ii]!=0
into
charData[ii]>0.001f

and
charData[ii]!=-1
into
charData[ii]>-0.5f

solves your problem.

Ganheddo
04-27-2008, 07:51 AM
Nope that's not solving the problem, the -1 and 0 comparisons work (tested it).

I'm not really comparing any pixel coordinates there either.
A "-1" just indicates the end of the data in the array and a "0" indicates that a new line strip should start.

thx anyway

ZbuffeR
04-27-2008, 03:34 PM
Several things here :
- your coordinates are disjoint, so it *will* show holes, especially when zoomed.
- you should try to draw everything continuously, ie. as if you never raise the pencil. Not always possible, but you should at least try.
Here is my solution :


GLfloat AData[] = {1,3, 1,10, 2,11, 4,11, 5,10, 5,3, 0, 1,7, 5,7, -1};
GLfloat BData[] = {1,7, 1,11, 4,11, 5,10, 5,8, 4,7, 1,7,
1,3, 4,3, 5,4, 5,6, 4,7, -1};
GLfloat CData[] = {5,3, 2,3, 1,4, 1,10, 2,11, 5,11, -1};


Then add this during right after the GL init, to better see what is going on :
glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_LINE_SMOOTH);
You see the lines with exact coordinates are in fact between each pixel row or column. Then add this to your reshape function :


glMatrixMode (GL_MODELVIEW);
glLoadIdentity ();
glTranslatef(+0.5, +0.5, 0.0);

There you are. And it works with the zoom too :-)


You should read the part of OpenGL specification which talks about the "diamond exit rule".

Ganheddo
04-28-2008, 11:41 PM
- your coordinates are disjoint, so it *will* show holes, especially when zoomed.
No, if the lines would've been drawn precisely, then there wouldn't be any "holes" / disjoint lines.
It should look like on the left side (but it does look more like the characters on the right):
http://img246.imageshack.us/img246/5964/imprecisebi1.jpg

Thx for your example, it works well.
I guessed that I might antialiase or smooth it, but I'd rather not use such a "brute force" approach.
Instead I'd really like to know why it isn't possible for me to draw lines with pixel-precision?


You see the lines with exact coordinates are in fact between each pixel row or column
Why is that? Shouldn't the lines be mapped to the exact pixel coordinates of the window?


You should read the part of OpenGL specification which talks about the "diamond exit rule".
That sounds interesting, I'll dig through it ^_-

-NiCo-
04-29-2008, 02:30 AM
Maybe this (http://www.opengl.org/discussion_boards/ubbthreads.php?ubb=showflat&Number=235566#Post235566) post can help you understand the problem.

Ganheddo
04-29-2008, 09:04 AM
Thx for the tip NiCo, but I guess at the end the problem was just a false assumption of mine, due to not really knowing how GL_LINE_STRIP works.

I assumed that with e.g. glVertex(1,3) a line of three pixels would be drawn. But oh well, silly me didn't notice that this only draws a line of two pixels.

So after changing the coordinates in my arrays accordingly, the characters were drawn as expected. The only thing left bugging me, was that the characters got messy when they were scaled.

After a quick glance over the thread you linked, I figured why not use Quads instead of lines? Now everything works perfect and the characters scale just fine.

So thx everyone, I got it ^_-