Adding text

Hello, I hope you guys can help me with this;
The application I am doing you will be able to right click; menu pops up and you can choose add text. Once selected you can type text.

I have the menu working but am stuck with the adding text. It will add alright but not in the correct position (0,0) as opposed to where the mouse is.

so, so far I have this:

 
if(id==8) //Add text
{
     printf("About to add text
");
     glutKeyboardFunc(keyboard);
     glFlush();
} 

That (id==8) is the menu item.
keyboard function is as follows

  
void keyboard(unsigned char key, int x, int y)
{
     glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, key);
     glFlush();
}

So by doing that the text prints out properly but only at position (0,0). I hope someone can help me out. I’ve been stuck a good while now. Thanks.

I think you missed;
glRasterPos2i(x, y);

hello Song,
thanks for the quick reply; I gather that I missed glRasterPos2i(x, y);
That would have to be called before it goes into the keyboard function, but I can’t get the current mouse position. The menu pops open at the right click but there is no way to get those x,y co-ordinates… well there probably is a way but I’m stumped.

If it helps I’ll outline what my simple program does:

in - int main(int argc, char** argv)
I set up window and call addmenu();

in - void addmenu()
I set up menu and sub menu’s then add a menu id
menu_id = glutCreateMenu(myRightClickMenu);
then
glutAttachMenu(GLUT_RIGHT_BUTTON);

in - void myRightClickMenu(int id)
on “add text” I call, glutKeyboardFunc(keyboard);

then finally:

 
void keyboard(unsigned char key, int x, int y)
{
	glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, key);
	glFlush();
}  

I’m stuck again but I found the answer with the glut function for getting the position

before the keyboard function is called I set the raster points by calling: glutPassiveMotionFunc(passive);

in that function I get the real x and real y position by doing the following:

 
void passive(int x, int y)  //find the current position of the mouse
{
	GLint viewport[4];
	GLdouble mvmatrix[16], projmatrix[16];
	GLint realy; /* OpenGL y coordinate position */

	glGetIntegerv (GL_VIEWPORT, viewport);
	glGetDoublev (GL_MODELVIEW_MATRIX, mvmatrix);
	glGetDoublev (GL_PROJECTION_MATRIX, projmatrix);
	realy = viewport[3] - (GLint) y - 1;
	glRasterPos2f(x, realy);
} 

Sniipe,
Your keyboard callback function has already got current cursor position.
void keyboard(unsigned char key, int x, int y)

Once a key is pressed, glut sends the current (x,y) coords of the cursor to your function.

I believe you also have mouse button callback function, glutMouseFunc().

Your callback might look like this;
void mouse(int button, int state, int x, int y);

It is more sense to me to get the current cursor position when mouse button is clicked.
==song==

Song, thanks again for your quick reply. Here is my code so far. if I have glRasterPos2i(x, y) in the keyboard function the characters will print out on top of each other. I need to get the position before that hence the passive function. If I use the mouse function it will miss the first character I print.

  
#include <GL/glut.h>
#include <stdio.h>

/* globals */
GLsizei wh = 500, ww = 500; /* initial window size */ 
GLfloat size = 3.0;   /* half side length of square */
static int submenu_shape;
static int submenu_fill;
static int menu_id;

void keyboard(unsigned char key, int x, int y)
{
	glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, key);
	glFlush();
}

void passive(int x, int y)  //find the current position of the mouse
{
	GLint viewport[4];
	GLdouble mvmatrix[16], projmatrix[16];
	GLint realy; /* OpenGL y coordinate position */

	glGetIntegerv (GL_VIEWPORT, viewport);
	glGetDoublev (GL_MODELVIEW_MATRIX, mvmatrix);
	glGetDoublev (GL_PROJECTION_MATRIX, projmatrix);
	realy = viewport[3] - (GLint) y - 1;
	glRasterPos2f(x, realy);
}

/* Right mouse button click - its menu system*/
void myRightClickMenu(int id)
{	
	//Right click menu options
	if(id==0) //Exit has been clicked
	{
		exit(0);
	}
	if(id==1) //clear screen has been clicked
	{
		glClear(GL_COLOR_BUFFER_BIT);
		glFlush();
	}
	if(id==2) //shape->square
	{
		//not working yet
	}
	if(id==3) //shape->circle
	{
		//not working yet
	}
	if(id==4) //shape->triangle
	{
		//not working yet
	}
	if(id==5) //shape->bezier curve
	{
		//not working yet
	}
	if(id==6) //Fill->On
	{
		//not working yet
	}
	if(id==7) //Fill->Off
	{
		//not working yet
	}
	if(id==8) //Add text; with this -> where ever your mouse is is where u start typing.
	{
		glutPassiveMotionFunc(passive);	
		glutKeyboardFunc(keyboard);
	}

}


/* reshaping routine called whenever window is resized or moved */
void myReshape(GLsizei w, GLsizei h) 
{
	/* adjust clipping box */
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(0.0, (GLdouble)w, 0.0, (GLdouble)h, -1.0, 1.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

	/* adjust viewport and clear */
    glViewport(0,0,w,h);
    glClear(GL_COLOR_BUFFER_BIT);
    glFlush();

	/* set global size for use by drawing routine */
    ww = w;
    wh = h;
}
/* myinit function */
void myinit() 
{

    glClearColor (0.0, 0.0, 0.0, 1.0);
    glViewport(0,0,ww,wh);
	/* Pick 2D clipping window to match
	size of screen window. This choice avoids having to scale object
	coordinates each time window is resized. */

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(0.0, (GLdouble) ww , 0.0, (GLdouble) wh , -1.0, 1.0);

	/* set clear color to black and clear window */
    glClearColor (0.0, 0.0, 0.0, 1.0);
    glClear(GL_COLOR_BUFFER_BIT);
    glFlush();
}

/* display callback required by GLUT */
void display() 
{}

/* Add menu function called from Main*/
void addmenu()
{
	submenu_shape = glutCreateMenu(menu_id);
	glutAddMenuEntry("Square",2);
	glutAddMenuEntry("Circle",3);
	glutAddMenuEntry("Triangle",4);
	glutAddMenuEntry("Bezier Curve",5);
	
	submenu_fill = glutCreateMenu(menu_id);
	glutAddMenuEntry("On",6);
	glutAddMenuEntry("Off",7);

	menu_id = glutCreateMenu(myRightClickMenu);

	glutAddMenuEntry("Clear Screen", 1);
	glutAddSubMenu("Shape",submenu_shape);
	glutAddSubMenu("Fill",submenu_fill);
	glutAddMenuEntry("Add Text",8);
	glutAddMenuEntry("Exit", 0);
	
	//menu attached to right mouse button
	glutAttachMenu(GLUT_RIGHT_BUTTON);
}

/* Main */


int main(int argc, char** argv) 
{
    glutInit(&argc,argv);
    glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);
    glutCreateWindow("Assignment 1: Rory Carroll - D04102698");
    myinit ();
    glutReshapeFunc (myReshape);
    glutDisplayFunc(display);
    addmenu();  /* call function to add menu to right mouse button */
    glutMainLoop();
}

Sniipe,
I ran your application and understood what you meant.

I suggest 2 things;

  • Call glRasterPos*() only once when first key entered.
  • Get the cursor coords from keyboard callback.

In order to do that, you may need flag variables in global scope. The code snippet looks like this;

// global vars
bool addTextSelected = false;
bool needCursorPos = true;
...

void myRightClickMenu(int id)
{
    // init flags
    addTextSelected = false;

    ...	
    if(id==8) //<-- better with SWITCH statement instead of IF
    {
        addTextSelected = true;
        needCursorPos = true;
    }
}
...

// keyboard CALLBACK
void keyboard(unsigned char key, int x, int y)
{
    if(addTextSelected)
    {
        // set raster position when the first key entered
        if(needCursorPos)
        {
            glRasterPos2i(x,wh-y); // invert vertical direction
            needCursorPos = false;
        }

        // write text
        glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, key);
        glFlush();
    }
}

Notice that glutKeyboardFunc() is removed from myRightClickMenu(), since registering a callback function is required only once.

I noticed clearing screen problem due to drawing a character one at a time. Other option might be storing text into a buffer. So you can clear screen and rewrite a string in the buffer every frame.
==song==

Tried to add your code but ran into difficulty:

c:\Documents and Settings\Rory Carroll\My Documents\Graphics\Assignment1\rorycarroll.c(10) : error C2061: syntax error : identifier ‘addTextSelected’
c:\Documents and Settings\Rory Carroll\My Documents\Graphics\Assignment1\rorycarroll.c(10) : error C2059: syntax error : ‘;’
c:\Documents and Settings\Rory Carroll\My Documents\Graphics\Assignment1\rorycarroll.c(10) : error C2513: '/global/ ’ : no variable declared before ‘=’
c:\Documents and Settings\Rory Carroll\My Documents\Graphics\Assignment1\rorycarroll.c(10) : error C2065: ‘false’ : undeclared identifier
c:\Documents and Settings\Rory Carroll\My Documents\Graphics\Assignment1\rorycarroll.c(11) : error C2061: syntax error : identifier ‘needCursorPos’
c:\Documents and Settings\Rory Carroll\My Documents\Graphics\Assignment1\rorycarroll.c(11) : error C2059: syntax error : ‘;’
c:\Documents and Settings\Rory Carroll\My Documents\Graphics\Assignment1\rorycarroll.c(11) : error C2513: '/global/ ’ : no variable declared before ‘=’
c:\Documents and Settings\Rory Carroll\My Documents\Graphics\Assignment1\rorycarroll.c(11) : error C2065: ‘true’ : undeclared identifier

I reckon I haven’t included the right file for it. All I have is:
#include <GL/glut.h>
#include <stdio.h>

I got it to work when I used int’s instead and when I eventually remembered to glutKeyboardFunc(keyboard). Thanks SongHo, ur a legend!

I guess you are using C compiler.
“bool” is a C++ specific data type, so change “bool” to “int”, “true” to 1 and “false” to “0”.

hmm, using visual studio… Surely that has everything… no worries I’m happy that I got it working. cheers again.