#include <GL/glut.h>
#include <stdio.h>
#include <math.h>
#define SELECT_BUFF 64
#define FEEDBACK_BUFF 512
#define cube 1
struct Rect
{
float left;
float right;
float bottom;
float top;
float near;
float far;
} typedef Rect;
int selectedObject = 0;
Rect box;
void unproject(float x, float y, float z, GLdouble *dest)
{
GLint viewport[4];
GLdouble modelview[16];
GLdouble projection[16];
GLfloat wx = x, wy, wz = z;
glGetIntegerv(GL_VIEWPORT,viewport);
glGetDoublev(GL_MODELVIEW_MATRIX,modelview);
glGetDoublev(GL_PROJECTION_MATRIX,projection);
wy = y = viewport[3]-y;
gluUnProject(wx, wy, wz, modelview, projection, viewport, &dest[0], &dest[1], &dest[2]);
}
void kocka (int color)
{
glColor3f(0.5, 0.5, 0.5);
if(color == 1)
{
glColor3f(1,1,1);
}
glBegin(GL_QUADS);
// Front face
glVertex3f(-1.0, -1.0, 1.0);
glVertex3f( 1.0, -1.0, 1.0);
glVertex3f( 1.0, 1.0, 1.0);
glVertex3f(-1.0, 1.0, 1.0);
// Back face
glVertex3f(-1.0, -1.0, -1.0);
glVertex3f(-1.0, 1.0, -1.0);
glVertex3f(1.0, 1.0, -1.0);
glVertex3f( 1.0, -1.0, -1.0);
// Top face
glVertex3f(-1.0, 1.0, -1.0);
glVertex3f(-1.0, 1.0, 1.0);
glVertex3f( 1.0, 1.0, 1.0);
glVertex3f(1.0, 1.0, -1.0);
// Bottom face
glVertex3f(-1.0, -1.0, -1.0);
glVertex3f( 1.0, -1.0, -1.0);
glVertex3f( 1.0, -1.0, 1.0);
glVertex3f(-1.0, -1.0, 1.0);
// Right face
glVertex3f(1.0, -1.0, -1.0);
glVertex3f(1.0, 1.0, -1.0);
glVertex3f(1.0, 1.0, 1.0);
glVertex3f(1.0, -1.0, 1.0);
// Left face
glVertex3f(-1.0, -1.0, -1.0);
glVertex3f(-1.0, -1.0, 1.0);
glVertex3f(-1.0, 1.0, 1.0);
glVertex3f(-1.0, 1.0, -1.0);
glEnd();
}
void drawScene(GLenum mode)
{
if(mode == GL_RENDER || mode == GL_FEEDBACK)
{
glMatrixMode (GL_PROJECTION);
glLoadIdentity ();
gluPerspective(65, 800/600, 1, 100);
}
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
gluLookAt(2, 5, 4, 0, 0, 0, 0, 1, 0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
if(mode == GL_SELECT) glLoadName(cube);
if(mode == GL_FEEDBACK) glPassThrough((GLfloat)cube);
glPushMatrix();
glTranslatef(-2, 1, 1);
kocka(selectedObject);
glPopMatrix();
}
void makeSelection(int object)
{
static GLfloat feedbackBuffer[FEEDBACK_BUFF];
int size, i, j, count;
glFeedbackBuffer(FEEDBACK_BUFF, GL_3D, feedbackBuffer);
glRenderMode(GL_FEEDBACK);
drawScene(GL_FEEDBACK);
size = glRenderMode(GL_RENDER);
i = 0;
while(i < size)
{
if(feedbackBuffer[i] == GL_PASS_THROUGH_TOKEN)
{
if(feedbackBuffer[i+1] == (GLfloat)object)
{
i += 2;
while(i < size && feedbackBuffer[i] != GL_PASS_THROUGH_TOKEN)
{
if(feedbackBuffer[i] == GL_POLYGON_TOKEN)
{
count = (int)feedbackBuffer[++i];
i++;
for(j = 0; j < count; j++)
{
//min x , max x
if(feedbackBuffer[i] < box.left) box.left = feedbackBuffer[i];
if(feedbackBuffer[i] > box.right) box.right = feedbackBuffer[i++];
//min y, max y
if(feedbackBuffer[i] < box.bottom) box.bottom = feedbackBuffer[i];
if(feedbackBuffer[i] > box.top) box.top = feedbackBuffer[i++];
//min z, max z (depth)
if(feedbackBuffer[i] < box.near) box.near = feedbackBuffer[i];
if(feedbackBuffer[i] > box.far) box.far = feedbackBuffer[i++];
}
}
else
{
i++;
}
}
break;
}
}
i++;
}
glutPostRedisplay();
}
void processSelection(float x, float y)
{
static GLuint selectBuffer[SELECT_BUFF];
GLint hits, viewport[4];
glSelectBuffer(SELECT_BUFF, selectBuffer);
glGetIntegerv(GL_VIEWPORT, viewport);
glRenderMode(GL_SELECT);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
gluPickMatrix((GLdouble)x, viewport[3] - (GLdouble)y, 0.5, 0.5, viewport);
gluPerspective(65, 800/600, 1, 100);
glInitNames();
glPushName(0);
drawScene(GL_SELECT);
glPopName();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
hits = glRenderMode(GL_RENDER);
if(hits > 0)
{
makeSelection(selectBuffer[3]);
if(selectedObject == 0) selectedObject = 1;
else selectedObject = 0;
}
}
void display()
{
drawScene(GL_RENDER);
if(selectedObject != 0)
{
GLdouble vk1[3], vk2[3];
unproject(box.left, box.bottom, box.near, vk1);
unproject(box.right, box.top, box.far, vk2);
printf("********************\n");
printf("x: %f, y: %f, z: %f\n", vk1[0], vk1[1], vk1[2]);
printf("x: %f, y: %f, z: %f\n", vk2[0], vk2[1], vk2[2]);
printf("********************\n");
glPushMatrix();
glTranslatef(vk1[0], vk1[1], vk1[2]);
glScalef(0.5, 0.5, 0.5);
kocka(selectedObject);
glPopMatrix();
}
glFlush();
glutSwapBuffers();
}
void init(void)
{
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glEnable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_SMOOTH);
box.left = 9999;
box.right = -9999;
box.bottom = 9999;
box.top = -9999;
box.near = 9999;
box.far = -9999;
}
void mouseCallback(int button, int state, int x, int y)
{
if(button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
{
processSelection((float)x, (float)y);
}
}
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
glutInitWindowSize (800, 600);
glutInitWindowPosition (100, 100);
glutCreateWindow ("Test");
init();
glutDisplayFunc(display);
glutMouseFunc(mouseCallback);
glutMainLoop();
return 0;
}