Button help

Is there a way to accurately compare glVertex3f coordinates and mouse coordinates (from something like glutMouseFunc)? I ask because I created a program that has a button (I still need to work on displaying the button to where it looks better) and I need a way to know if the mouse is within the coordinates of the button. The program already does this perfectly but I had to manually find the mouse coord equivalents of the displayed button to get it to work, so I'm hoping to find an easier way to do that. My code for the program is:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
#include <GlutText.h>
#include <iostream>

//Include OpenGL header files, so that we can use OpenGL
#ifdef __APPLE__
#include <OpenGL/OpenGL.h>
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#endif

using namespace std;

typedef void (*ButtonCallback)(); //defines ButtonCallback as a point to a void function
                                 //void is the type
                                //*ButtonCallback means that it points to the function with that name
                               //() is the varible(s)

void Hello_World();
void ButtonPressed(int button, int state, int x, int y);
void MouseMoved(int x,int y);

struct Button
{
    float X; //The top left corner of
    float Y; //the button is (X,Y)
    float Length;
    float Height;
    char* Text;
    ButtonCallback ButtonFunction;
    int use; //in the button still used by the program or has it been pressed?
};

Button MyButton = { -4 , 0.75f , 8 , 1.5f , "Hello World" , Hello_World , 1};

struct Color
{
    float red;
    float green;
    float blue;
};

Color OuterButton = {1,1,1};
Color ButtonText = {1,0,0};

//Called when a key is pressed
void handleKeypress(unsigned char key, //The key that was pressed
					int x, int y) {    //The current mouse coordinates
	switch (key) {
		case 27: //Escape key
			exit(0); //Exit the program
	}
}

//Initializes 3D rendering
void initRendering() {
	//Makes 3D drawing work when something is in front of something else
	glEnable(GL_DEPTH_TEST);
	glEnable(GL_COLOR_MATERIAL); //enables colors
	glClearColor(0, 0, 0, 1.0f); //sets background color. First three are RBG and last should ALWAYS be 1
}

//Called when the window is resized
void handleResize(int w, int h) { //This should be about a 5x5 screen.
	//Tell OpenGL how to convert from coordinates to pixel values
	glViewport(0, 0, w, h);

	glMatrixMode(GL_PROJECTION); //Switch to setting the camera perspective

	//Set the camera perspective
	glLoadIdentity(); //Reset the camera
	gluPerspective(450.0,                  //The camera angle (Y-COORD)
				   w / h,                  //The width-to-height ratio (X-COORD)
				   1.0,                   //The near z clipping coordinate
				   200.0);                //The far z clipping coordinate
    MyButton.use = 1;

}

//Draws the 3D scene
void drawScene() {

	//Clear information from last draw
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	glMatrixMode(GL_MODELVIEW); //Switch to the drawing perspective
	glLoadIdentity(); //Reset the drawing perspective
	glTranslatef(0.0f,0.0f,-5.0f); //move 5 units forward

    glColor3f(OuterButton.red,OuterButton.green,OuterButton.blue);
	glBegin(GL_TRIANGLES);

    glVertex3f(MyButton.X,MyButton.Y,0);
    glVertex3f(MyButton.X + MyButton.Length,MyButton.Y,0);
    glVertex3f(MyButton.X,MyButton.Y - MyButton.Height,0);

    glVertex3f(MyButton.X + MyButton.Length,MyButton.Y - MyButton.Height,0);
    glVertex3f(MyButton.X + MyButton.Length,MyButton.Y,0);
    glVertex3f(MyButton.X,MyButton.Y - MyButton.Height,0);

    glEnd();

    glPushMatrix();
    glColor3f(ButtonText.red,ButtonText.green,ButtonText.blue);
    glTranslatef(MyButton.X/2,-0.1f,2.0f);
    drawStrokeText(MyButton.Text,0.0045);
    glPopMatrix();

	glutSwapBuffers(); //Send the 3D scene to the screen
}

int main(int argc, char** argv) {
	//Initialize GLUT
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
	glutInitWindowSize(400, 400);

	//Create the window
	glutCreateWindow("Button");
	initRendering();

	//Set handler functions
	glutDisplayFunc(drawScene);
	glutKeyboardFunc(handleKeypress);
	glutReshapeFunc(handleResize);
	glutPassiveMotionFunc(MouseMoved); //called when mouse is moved without a button being pressed
	glutMouseFunc(ButtonPressed); //called when mouse button is pressed or released

	glutMainLoop();
	return 0;
}

void ButtonPressed(int button,   //GLUT_LEFT_BUTTON ot GLUT_RIGHT_BUTTON
                   int state,    //GLUT_UP or GLUT_DOWN
                   int x, int y) //Mouse position when button was pressed
{
    if (MyButton.use != 0){
    //cout<<x<<endl<<y<<endl<<endl;
    if ( /*x >= MyButton.X and x <= MyButton.X + MyButton.Length &&
         y <= MyButton.Y and y >= MyButton.Y - MyButton.Height &&*/
         x >= 39 and x <= 360 &&
         y >= 169 and y <= 228 &&
         state == GLUT_DOWN &&
         button == GLUT_LEFT_BUTTON )
         {
             MyButton.use = 0;
             MyButton.ButtonFunction();
         }
    }
}

void MouseMoved(int x,int y ) //Mouse position
{
    if (MyButton.use != 0){
    if ( /*x >= MyButton.X and x <= MyButton.X + MyButton.Length &&
         y <= MyButton.Y and y >= MyButton.Y - MyButton.Height &&*/
         x >= 39 and x <= 360 &&
         y >= 169 and y <= 228)
         {
             ButtonText = {1,1,1};
             OuterButton = {1,0,0};
         }
    else
    {
        ButtonText = {1,0,0};
        OuterButton = {1,1,1};
    }
    glutPostRedisplay();
    }
}

void Hello_World()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	glMatrixMode(GL_MODELVIEW); //Switch to the drawing perspective
	glLoadIdentity(); //Reset the drawing perspective
	glTranslatef(-5.1f,0.0f,-5.0f); //move 5 units forward

	drawStrokeText("Hello World", Big_Text - 0.0001);

	glutSwapBuffers(); //Send the 3D scene to the screen

}

... in GlutText.h

#define Normal_Text 0.001f
#define Big_Text 0.015f
#define Large_Text 0.020f

void drawStrokeText(char* string, float scale)
{
	  char *c;

      glScalef(scale,scale,scale);
	  for (c=string; *c != '\0'; c++)
	  {
    		glutStrokeCharacter(GLUT_STROKE_ROMAN , *c);
	  }
}
bump
Paint every button with a different colour. When the user clicks, just check over which color it is, and that's your button.
I read somewhere that OpenGL has a "where in the 3d world is this mouse click on the screen" function. I do believe that you are "supposed" to change transformations to become a 2d enviornment when trying to do the menu thing.
@ne555 that doesn't help at all. The problem is that I can't do something like that since I have no way of comparing the buttons location and the mouse location.

@LowestOne what do you mean by the menu thing?
You don't compare the location, but the colour.
By "menu thing" I mean a time when you want selections from a menu, rather than a place in the physical world. There are a couple OpenGL manuals around the web. I would recommend reading them rather than a tutorial you might find online. I know that I did a few online tutorials, but nothing sank in until I built up a base of OpenGL. I got stuck on the lighting section, because I didn't want to use Glut's primitives with their pre calculated normals. Still trying to find the time to make a xml parser to get the normal data from a .DAE.)

Anyway, you're trouble is that your perspective is being set in the resize function, where it is made to be 3d. If you're trying to make a menu with buttons, you want to be in a 2d world.

This code might help you, as out of context as it is:
1
2
3
4
5
6
7
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);
}


With it's explaination:
The internals of GLUT will pass this function two arguments: the width and height, in pixels, of the new, moved, or resized window. glViewport()
adjusts the pixel rectangle for drawing to be the entire new window. The next three routines adjust the coordinate system for drawing so that the
lower-left corner is (0, 0), and the upper-right corner is (w, h)


At that point, you should be able to make rectangles and have them appear in a place relative to the position in the window, rather than relative to a position in the "game world".
Last edited on
Thanks. Your reshape function for making it 2D works perfectly. Now the coordinates for the mouse and the coordinates for drawing the button are exactly the same. I have the program almost perfect now (I just have to code the in the resizing of the button when the screen sized is changed).
I just have to code the in the resizing of the button when the screen sized is changed

Never seen a program do that before.

I saved myself the headache and just decided to make resize not possible (something GLUT can not do, I believe).

All of my knowledge is spent explaining this next part. Basically you draw your 3d world (cubes models ect) in a 3d projection, and then switch to the orthogonal projection to display buttons (all in the same frame).
Last edited on
I thought it would be a cool thing to have the program do. It also wasn't that hard (just took a few variables). All I did was have a variable store the current screen size so whenever the window was resized, it finds the ratio of the new window size:the old window size and multiplies that by variables that represent the size of the button and the scale of the text:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void handleResize(int w, int h) {
glViewport (0, 0, (GLsizei) w, (GLsizei) h);
glMatrixMode (GL_PROJECTION);
glLoadIdentity ();
gluOrtho2D (0.0, (GLdouble) w, 0.0, (GLdouble) h);
//MyButton.use = 1;
    TempData BeforeToAfter = {w/Initial_Screen.X , h/Initial_Screen.Y};
    MyButton.X *= BeforeToAfter.X;
    MyButton.Y *= BeforeToAfter.Y;
    MyButton.Length *= BeforeToAfter.X;
    MyButton.Height *= BeforeToAfter.Y;
    scale.X *= BeforeToAfter.X;
    scale.Y *= BeforeToAfter.Y;
    Initial_Screen = {w,h};
    glutPostRedisplay();
}


TempData is just a struct with members X and Y. I couldn't think of a name so I just called it that. Initial_Screen is a variable of type TempData as well as scale. Initial_Screen is the size of the screen and scale is how much the text in the button is scaled (using glScale3f)
Topic archived. No new replies allowed.