#include "main.h" #include #include #include #include #include #include #include #include #include #include #include "listhash.h" #include "misc.h" /* * Macro Defines */ #define FOV 60.0 #define DEPTH 192.0 #define HOST_LIST_SIZE 20 #define BUFSIZE 512 /* This is a Predeclaration */ void SetFullscreen(int on); void FindOurWindow(void); /* * Global Constants */ enum { X = 0, Y = 1, Z = 2 }; /* * Global Variables * -quite a few are used, mostly to maintain render state */ /* Pipes */ int pktpipe; int pointpipe; /* frames per second */ struct counter_t fps; /* packets per second */ struct counter_t pps; /* Number of uSeconds to sleep if there is no Work */ unsigned int idle_sleep = 100; /* Packet List */ struct list_t packets; /* Point List */ struct list_t points; /* Point Hash */ struct hash_table pointhash; /* Host List - More of a Queue */ struct { char line[HOST_LIST_SIZE][LABELSIZE]; int head; } hostlist; /* Mouse State */ struct { int x; int y; int depressed; } mouse_state; /* View Point */ int spin = 0; int view_in_motion = 0; GLfloat angle[2] = { 0.0, 0.0 }; GLfloat speed[2] = { 0.0, 0.6 }; GLfloat zoom = -(DEPTH/2.0); GLfloat viewcords[3] = { 0.0, 0.0, 0.0 }; GLfloat destcords[3] = { 0.0, 0.0, 0.0 }; GLenum current_mode = 0; /* Window Data */ int winIdMain; Window winMain; int viewport[2] = { 800, 600 }; /********************************************************** * Functions * **********************************************************/ /********************************************************** * Local List and Hash Interfaces * **********************************************************/ void add_packet(struct packet_t *p) { struct list_head *lh; struct packet_t *pkt; if(DEBUG) {fprintf(stderr,"add_packet: %p\n",p);} lh = list_add(&packets, p, sizeof(struct packet_t)); pkt = lh->data; if(pkt == NULL) { fprintf(stderr,"add_packet: pkt == NULL\n"); } pkt->rmap = lh; } void del_packet(struct packet_t *p) { if(DEBUG) {fprintf(stderr,"del_packet: %p\n",p);} if(p->rmap == NULL) { fprintf(stderr,"del_packet: p->rmap == NULL\n"); } list_del(&packets, p->rmap); } void add_point(struct point_t *p) { struct list_head *lh; struct point_t *pkt; if(DEBUG) {fprintf(stderr,"add_point: %p\n",p);} lh = list_add(&points,p,sizeof(struct point_t)); pkt = lh->data; pkt->rmap = lh; /* Use NCP(No Copy) so that we are refering to the same data */ hash_add_ncp(&pointhash,p->ip,pkt); } void del_point(struct point_t *p) { if(DEBUG) {fprintf(stderr,"del_point: %p\n",p);} /* Use the NF(No Free) version * so that the data is around to be freed by hash_del */ list_del_nf(&points, p->rmap); hash_del(&pointhash,p->hash,p->ip); } struct point_t *find_point(hash_t ha, unique_t uni) { return hash_find(&pointhash,ha,uni); } /********************************************************* * Packet and Point Altering Functions * *********************************************************/ void dim_packet(struct packet_t *p) { p->src.col.r *= 0.95; p->src.col.g *= 0.95; p->src.col.b *= 0.95; p->dst.col.r *= 0.95; p->dst.col.g *= 0.95; p->dst.col.b *= 0.95; } void dim_point(struct point_t *p) { p->vertex.col.r *= 0.975; p->vertex.col.g *= 0.975; p->vertex.col.b *= 0.975; } void boost_point(struct point_t *p) { if(p != NULL) { p->life += 100; p->vertex.col.r = 1.0; p->vertex.col.g = 1.0; p->vertex.col.b = 1.0; } } void AgePacket(struct packet_t *p) { --(p->life); if(p->life == 0) { del_packet(p); } else if(p->life < 20) { dim_packet(p); } } void AgePoint(struct point_t *p) { --(p->life); if(p->life == 0 || p->vertex.col.r < 0.1) { del_point(p); } else if(p->life < 100) { dim_point(p); } } /*********************************************************** * Drawing Functions * ***********************************************************/ void drawString (char *s) { unsigned int i; for (i = 0; i < strlen(s); i++) { glutBitmapCharacter(GLUT_BITMAP_HELVETICA_10, s[i]); } } /* Draw Line Based on a Packet Structure */ void DrawLineP(struct packet_t *p) { glPushMatrix(); glBegin(GL_LINES); glColor3f((GLfloat)p->src.col.r,(GLfloat)p->src.col.g,(GLfloat)p->src.col.b); glVertex3f((GLfloat)p->src.x,(GLfloat)p->src.y,(GLfloat)p->src.z); glColor3f((GLfloat)p->dst.col.r,(GLfloat)p->dst.col.g,(GLfloat)p->dst.col.b); glVertex3f((GLfloat)p->dst.x,(GLfloat)p->dst.y,(GLfloat)p->dst.z); glEnd(); glPopMatrix(); } /* Draw Point from a Vertex Structure */ void DrawPoint(struct vert_t *c) { glPushMatrix(); glBegin(GL_POINTS); glPointSize(10.0); glColor3f((GLfloat)c->col.r,(GLfloat)c->col.g,(GLfloat)c->col.b); glVertex3f((GLfloat)c->x,(GLfloat)c->y,(GLfloat)c->z); glPointSize(1.0); glEnd(); glPopMatrix(); } /* Adds Label Text to a Point from a Point Structure */ void DrawLabel(struct point_t *p) { /* Text */ //glPushMatrix(); glColor4f(p->vertex.col.r, p->vertex.col.g, p->vertex.col.b, 0.75); glRasterPos3f(p->vertex.x - 0.2, p->vertex.y + 0.3, p->vertex.z); drawString(p->label); //glPopMatrix(); } void DrawBackingQuad(GLfloat x, GLfloat y, GLfloat w, GLfloat h) { glPushMatrix(); glBegin(GL_QUADS); glColor4f(1.0,1.0,1.0,0.25); glVertex3f(x,y,0.0); glVertex3f(x+w,y,0.0); glVertex3f(x+w,y-h,0.0); glVertex3f(x,y-h,0.0); glEnd(); glPopMatrix(); } void DrawInfo(void) { char buffer[512]; GLfloat yd = (26.0/viewport[Y]); GLfloat xd = (26.0/viewport[X]); /* Some Magic Numer based on my prototypes */ DrawBackingQuad(-1.0,1.0,(420.0/viewport[X]),(160.0/viewport[Y])); glColor4f(1.0,1.0,1.0,0.75); sprintf(buffer,"Location x:%.2f, y:%.2f, z:%.2f",viewcords[X],viewcords[Y],viewcords[Z]); glRasterPos3f(-1.0+xd,1.0-yd,1.0); drawString(buffer); sprintf(buffer,"Destination x:%.2f, y:%.2f, z:%.2f",destcords[X],destcords[Y],destcords[Z]); glRasterPos3f(-1.0+xd,1.0-(yd*2),1.0); drawString(buffer); sprintf(buffer,"Angle X: %.1f, Angle Y: %.1f",angle[X],angle[Y]); glRasterPos3f(-1.0+xd,1.0-(yd*3),1.0); drawString(buffer); sprintf(buffer,"Speed X: %.2f, Speed Y: %.2f",speed[X],speed[Y]); glRasterPos3f(-1.0+xd,1.0-(yd*4),1.0); drawString(buffer); sprintf(buffer,"PPS: %d, FPS: %d",pps.value,fps.value); glRasterPos3f(-1.0+xd,1.0-(yd*5),1.0); drawString(buffer); } void DrawHostList(void) { GLfloat w = (256.0/viewport[X]); GLfloat yd = (26.0/viewport[Y]); GLfloat h = yd*(HOST_LIST_SIZE + 1); GLfloat x = (1.0 - w); GLfloat y = (2.0 - h)/2.0; int i; DrawBackingQuad(x, y, w, h); x += (10.0/viewport[X]); y -= yd; glPushMatrix(); glColor4f(1.0,1.0,1.0,0.75); for(i = hostlist.head; i < HOST_LIST_SIZE; ++i) { glRasterPos3f(x,y,1.0); drawString(hostlist.line[i]); y -= yd; } for(i = 0; i < hostlist.head; ++i) { glRasterPos3f(x,y,1.0); drawString(hostlist.line[i]); y -= yd; } glPopMatrix(); } void DrawAxis(int type) { GLfloat cords[3] = {0.0, 0.0, 0.0}; cords[type] = (DEPTH/2.0); glPushMatrix(); glBegin(GL_LINES); glColor4f(1.0,1.0,1.0,0.8); glVertex3f(-cords[X],-cords[Y],-cords[Z]); glVertex3f(cords[X],cords[Y],cords[Z]); glEnd(); glPopMatrix(); } void DrawPacket(void *data) { struct packet_t *p = data; //fprintf(stderr,"DrawPacket: data:%p\n",data); DrawLineP(p); AgePacket(p); } void DrawPointFunc(void *data) { struct point_t *p = data; if(current_mode == GL_SELECT) { glLoadName(p->ip); } DrawPoint(&(p->vertex)); if(p->type & LABEL) { DrawLabel(p); } if(current_mode != GL_SELECT) { AgePoint(p); } } /**************************************************** * Display Functions * * - These Call Draw Functions * ****************************************************/ void DrawPackets(void) { list_do(&packets,DrawPacket); } void DrawPoints(void) { glPushMatrix(); list_do(&points,DrawPointFunc); glPopMatrix(); } void Draw2D(void) { /* Reprogram to 2D Mode */ glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(-1.0,1.0,-1.0,1.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); DrawInfo(); DrawHostList(); } void Draw3D(void) { /* Axis */ DrawAxis(X); DrawAxis(Y); DrawAxis(Z); /* Packets */ DrawPackets(); /* Points */ DrawPoints(); } void TranslateViewPort(void) { glNormal3f(0.0,0.0,0.0); gluPerspective(FOV,((GLfloat)viewport[X]/(GLfloat)viewport[Y]),1.0,DEPTH); glTranslatef(0.0,0.0,zoom); glRotatef(angle[Y],0.0,1.0,0.0); glRotatef(angle[X],1.0,0.0,0.0); glTranslatef(-viewcords[X],-viewcords[Y],-viewcords[Z]); } /********************************************************* * Main Display Function * *********************************************************/ void display(void) { count(&fps,1); glutSetWindow(winIdMain); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); /* View Port */ glMatrixMode(GL_PROJECTION); glLoadIdentity(); TranslateViewPort(); /* Models */ glMatrixMode(GL_MODELVIEW); glLoadIdentity(); Draw3D(); Draw2D(); glFlush(); glutSwapBuffers(); } /*********************************************************** * Idle Loop and Major Supporting Functions * ***********************************************************/ void MoveViewTowardDest(void) { int d; int moves = 0; GLfloat diff; for(d = 0; d < 3; ++d) { if(viewcords[d] != destcords[d]) { diff = destcords[d] - viewcords[d]; if(diff <= 0.5 && diff >= -0.5) { viewcords[d] = destcords[d]; } else if(viewcords[d] < destcords[d]) { viewcords[d] += 0.5; } else { viewcords[d] -= 0.5; } ++moves; } } if(moves == 0) { view_in_motion = 0; } } void RotateViewAngle(void) { int i; for(i = 0; i < 2; ++i) { if(angle[i] < 360.0 && angle[i] > -360.0) { angle[i] += speed[i]; } else if(angle[i] > 360.0) { angle[i] = (angle[i] - 360) + speed[i]; } else { angle[i] = (360 + angle[i]) + speed[i]; } } } int read_pktpipe(void) { struct packet_t packet; if(read(pktpipe,&packet,sizeof(struct packet_t)) == sizeof(struct packet_t)) { add_packet(&packet); return 1; } else { return 0; } } int read_pointpipe(void) { struct point_t *p = NULL; struct point_t point; if(read(pointpipe,&point,sizeof(struct point_t)) == sizeof(struct point_t)) { if(DEBUG) {fprintf(stderr,"read_pointpipe: Got Point\n");} if(point.type & POINT) { if(DEBUG) {fprintf(stderr,"read_pointpipe: Its a Point\n");} p = find_point(point.hash,point.ip); if(p == NULL) { add_point(&point); } else { boost_point(&point); } return 1; } else if(point.type & TEXT) { if(DEBUG) {fprintf(stderr,"read_pointpipe: Its Text\n");} strncpy(hostlist.line[hostlist.head],point.label,LABELSIZE); ++hostlist.head; if(hostlist.head == HOST_LIST_SIZE) { hostlist.head = 0; } boost_point(find_point(point.hash,point.ip)); } if(DEBUG) {fprintf(stderr,"read_pointpipe: Left Safely\n");} } return 0; } void Idle_Loop(void) { static unsigned int redraws = 0; int worked = 0; while(read_pktpipe() && worked < idle_sleep) { ++worked; } count(&pps,worked); while(read_pointpipe() && worked < idle_sleep+5) { ++worked; } if(spin && (speed[X] != 0.0 || speed[Y] != 0.0)) { RotateViewAngle(); worked = 1; } if(view_in_motion) { MoveViewTowardDest(); worked = 1; } /* XXX: Thoughts on a variable idle_sleep? if(worked && idle_sleep > 100) { --idle_sleep; } else if(!worked && idle_sleep < 5000) { ++idle_sleep; } */ if(worked || redraws == 0) { glutPostRedisplay(); ++redraws; } else { usleep(idle_sleep); redraws = 0; } } /************************************************* * GLUT Event Functions * *************************************************/ void reshape(int w, int h) { glViewport(0,0,w,h); viewport[X] = w; viewport[Y] = h; glutPostRedisplay(); } void keyboard(unsigned char key, int x, int y) { key = tolower(key); switch (key) { case 'a': if(spin) { speed[Y] += 0.2; } else { angle[Y] += 1.0; } break; case 'd': if(spin) { speed[Y] -= 0.2; } else { angle[Y] -= 1.0; } break; case 'w': if(spin) { speed[X] += 0.2; } else { angle[X] += 1.0; } break; case 's': if(spin) { speed[X] -= 0.2; } else { angle[X] -= 1.0; } break; case '-': zoom -= 1.0; break; case '+': zoom += 1.0; break; case 'i': spin = ~spin; break; case 'o': destcords[X] = 0.0; destcords[Y] = 0.0; destcords[Z] = 0.0; view_in_motion = 1; break; case 'q': SetFullscreen(0); glutDestroyWindow(winIdMain); exit(0); break; default : break; } glutPostRedisplay(); } void pick_host(int x, int y) { struct point_t *p = NULL; GLint viewPort[4]; GLuint select_buffer[BUFSIZE]; GLint hits,curhits; GLuint bestz = 0xffffffff; unique_t picked = 0; int i,j; glGetIntegerv(GL_VIEWPORT, viewPort); glSelectBuffer(BUFSIZE, select_buffer); glRenderMode(GL_SELECT); current_mode = GL_SELECT; glInitNames(); glPushName(0); /* View Port */ glMatrixMode(GL_PROJECTION); glLoadIdentity(); /* Due to the Small Size of the Targets I set the Zone Large e.g. 20.0,20.0 */ gluPickMatrix((GLdouble)x,(GLdouble)(viewPort[3] - y), 20.0, 20.0, viewPort); TranslateViewPort(); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); DrawPoints(); glFlush(); hits = glRenderMode(GL_RENDER); if(DEBUG) {fprintf(stderr,"pick_host; hits:%d\n",hits);} if(hits > 0) { j = 0; for(i = 0; i < hits; ++i) { curhits = select_buffer[j]; ++j; if(select_buffer[j] < bestz) { bestz = select_buffer[j]; j += 2; picked = select_buffer[j]; } j += curhits; } p = hash_findu(&pointhash,picked); if(p != NULL) { if(DEBUG) {fprintf(stderr,"pick_host; picked:%s\n",p->label);} destcords[X] = p->vertex.x; destcords[Y] = p->vertex.y; destcords[Z] = p->vertex.z; view_in_motion = 1; glutPostRedisplay(); } } /* Leaving */ current_mode = 0; } void mouse(int button, int state, int x, int y) { if(button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) { mouse_state.depressed = 1; pick_host(x,y); } else if(button == GLUT_LEFT_BUTTON && state == GLUT_UP) { mouse_state.depressed = 0; } else if(button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN) { mouse_state.depressed = 2; mouse_state.x = x; mouse_state.y = y; } else if(button == GLUT_RIGHT_BUTTON && state == GLUT_UP) { mouse_state.depressed = 0; } } void motion(int x, int y) { if(mouse_state.depressed == 2) { if(spin == 0) { angle[X] += ((double)( y - mouse_state.y ))/3.0; angle[Y] += ((double)( x - mouse_state.x ))/3.0; } else { speed[X] -= (((double)( y - mouse_state.y ))/((double)viewport[Y])); speed[Y] += (((double)( x - mouse_state.x ))/((double)viewport[X])); if(speed[X] < 0.005 && speed[X] > -0.005) { speed[X] = 0.0; } if(speed[Y] < 0.005 && speed[Y] > -0.005) { speed[Y] = 0.0; } } mouse_state.x = x; mouse_state.y = y; glutPostRedisplay(); } } /************************************************************* * Fullscreen Mode Functions * *************************************************************/ void ConfineMouse(Display *display, Window window, int on) { int numTries, grabResult; if (on) { /* The sync is required so the window is available */ XSync(display, False); /* Grab the input focus so that the cursor is moved to the window */ XSetInputFocus(display, window, RevertToNone, CurrentTime); for (numTries = 0; numTries < 10; numTries++) { grabResult = XGrabPointer(display, window, True, ButtonPressMask|ButtonReleaseMask|ButtonMotionMask |PointerMotionMask, GrabModeAsync, GrabModeAsync, window, None, CurrentTime); if (grabResult != AlreadyGrabbed) { if(DEBUG) {fprintf(stderr,"Mouse Grabbed\n");} break; } usleep(100000); } grabResult = XGrabKeyboard(display, window, False, GrabModeAsync, GrabModeAsync, CurrentTime); if (grabResult != 0) { XUngrabPointer(display, CurrentTime); } } else { XUngrabPointer(display, CurrentTime); XUngrabKeyboard(display, CurrentTime); } } void SetFullscreen(int on) { static int x = 0; static int y = 0; XWindowAttributes attribs; XF86VidModeModeLine curmode; XF86VidModeModeInfo **modes; int dot,nmodes,i; Display *display = glXGetCurrentDisplay(); int screen = DefaultScreen(display); XF86VidModeGetAllModeLines(display,screen,&nmodes,&modes); XGetWindowAttributes(display,winMain,&attribs); if(on) { XF86VidModeGetModeLine(display,screen,&dot,&curmode); x = curmode.hdisplay; y = curmode.vdisplay; for (i = 0; i < nmodes; ++i) { if((viewport[X] == modes[i]->hdisplay) && (viewport[Y] == modes[i]->vdisplay)) { XF86VidModeSwitchToMode(display,screen,modes[i]); XF86VidModeSetViewPort(display,screen,attribs.x,attribs.y); ConfineMouse(display,winMain,1); } } } else { for(i = 0; i < nmodes; ++i) { if((modes[i]->hdisplay == x) && (modes[i]->vdisplay == y)) { XF86VidModeSwitchToMode(display,screen,modes[i]); ConfineMouse(display,winMain,0); } } } } int ScanWindows(Display *display, Window *w) { XWindowAttributes attribs; Window root,parent; Window *children; unsigned int nchildren; int i; XQueryTree(display,*w,&root,&parent,&children,&nchildren); for(i = 0; i < nchildren; ++i) { *w = children[i]; XGetWindowAttributes(display,*w,&attribs); if(DEBUG) { fprintf(stderr,"\nWindow %d\n",*w); fprintf(stderr,"x:%d, y:%d, border:%d\n",attribs.x,attribs.y,attribs.border_width); fprintf(stderr,"width:%d, height:%d\n",attribs.width,attribs.height); } if((attribs.width == viewport[X] && attribs.height == viewport[Y])) { return 1; } else { if(ScanWindows(display,w)) { return 1; } } } if(children != NULL) { XFree(children); } return 0; } void FindOurWindow(void) { Window w; Display *display = glXGetCurrentDisplay(); w = RootWindow(display,DefaultScreen(display)); if(ScanWindows(display,&w) != 0) { winMain = w; if(DEBUG) {fprintf(stderr,"Our window : %d\n",winMain);} } else { fprintf(stderr,"Couldn't find our window :/\n"); exit(1); } } /* We go to Fullscreen on First Idle Call */ void Fake_Idle_Loop(void) { FindOurWindow(); SetFullscreen(1); glutIdleFunc(Idle_Loop); glutPostRedisplay(); } /************************************************************* * Initialisation * *************************************************************/ void local_glinit(void) { glClearColor(0.0, 0.0, 0.0, 0.0); /* Shading + Depth */ glShadeModel(GL_SMOOTH); glEnable(GL_DEPTH_TEST); glEnable(GL_POINT_SMOOTH); glEnable(GL_LINE_SMOOTH); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } int graphics_handling_child(int pkp, int pop, int argc, char **argv) { /* Set Packet Pipe & Make it Non-Blocking */ pktpipe = pkp; fcntl(pktpipe, F_SETFL, O_NONBLOCK); /* Set Point Pipe & Make it Non-Blocking */ pointpipe = pop; fcntl(pointpipe, F_SETFL, O_NONBLOCK); /* Init Counters */ counter_init(&fps,1); counter_init(&pps,1); /* Init Lists */ list_init(&packets); list_init(&points); /* Init hash */ hash_table_init(&pointhash); /* Init Glut Main Window*/ glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH); glutInitWindowSize(viewport[X],viewport[Y]); glutInitWindowPosition(0,0); winIdMain = glutCreateWindow(VERSION); /* Init Mouse State */ mouse_state.x = 0; mouse_state.y = 0; mouse_state.depressed = 0; /* Setup GL and Glut */ local_glinit(); glutKeyboardFunc(keyboard); glutMouseFunc(mouse); glutDisplayFunc(display); glutMotionFunc(motion); glutReshapeFunc(reshape); glutIdleFunc(Fake_Idle_Loop); //glutFullScreen(); /* Enter Main Loop */ glutMainLoop(); exit(0); }