/* * This file is part of PlotLTR * * (c) 2002 Matthias Transier, Praktische Informatik IV, University of Mannheim * * PlotLTR is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * PlotLTR is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Foobar; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include typedef enum{LOAD, PACKETS, DROPS} displaymode; static GLfloat spin[3], dist; static float max; static int timeslot, slots, fieldsize, render, duration, animation, writePPMs, useZ, drawNodes; static displaymode mode = LOAD; static GSList *tFrames = NULL; void output(char *string) { int len, i; glRasterPos2f(0, 0); len = (int) strlen(string); for (i = 0; i < len; i++) glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_24, string[i]); } void writePPM(int frame) { int i, j, w, h; FILE *OUT; GLubyte *pixeldata; char filename[] = "frameXXXX.ppm"; w = glutGet(GLUT_WINDOW_WIDTH); h = glutGet(GLUT_WINDOW_HEIGHT); pixeldata = (GLubyte*) calloc(w * h * 3, sizeof(GLubyte)); glReadPixels(0, 0, w, h, GL_RGB, GL_UNSIGNED_BYTE, pixeldata); sprintf(filename, "frame%04d.ppm", frame); OUT = fopen(filename, "w"); fprintf(OUT, "P6\n%d %d\n255\n", w, h); for (j = h - 1; j >= 0; j--) for (i = 0; i < w; i++) fprintf(OUT, "%c%c%c", pixeldata[3 * (w * j + i)], pixeldata[3 * (w * j + i) + 1], pixeldata[3 * (w * j + i) + 2]); fclose(OUT); free(pixeldata); } void animate(int value) { if (value && timeslot + 1 < slots) { timeslot++; glutPostRedisplay(); glutTimerFunc((double)duration / slots * 1000, animate, animation); if (writePPMs) glutTimerFunc(0, writePPM, timeslot); } else animation = 0; } void surface2strips(GPtrArray *vertices) { int i; GSList *list = NULL; GtsTriangle *t; GtsSurface *surface; GtsVertex *v1, *v2, *v3; /* create triangle enclosing all the vertices (needed for delaunay) */ for (i = 0; i < vertices->len; i++) list = g_slist_prepend(list, g_ptr_array_index(vertices, i)); t = gts_triangle_enclosing(gts_triangle_class(), list, 1); g_slist_free(list); surface = gts_surface_new(gts_surface_class(), gts_face_class(), gts_edge_class(), gts_vertex_class()); gts_surface_add_face(surface, gts_face_new(gts_face_class(), t->e1, t->e2, t->e3)); /* add all vertices to the surface */ for (i = 0; i < vertices->len; i++) { v1 = g_ptr_array_index(vertices, i); if (gts_delaunay_add_vertex(surface, v1, NULL) != NULL) printf("error adding node %d!\n", i); } g_ptr_array_free(vertices, TRUE); /* remove enclosing triangle */ gts_triangle_vertices(t, &v1, &v2, &v3); gts_allow_floating_vertices = TRUE; gts_object_destroy(GTS_OBJECT(v1)); gts_object_destroy(GTS_OBJECT(v2)); gts_object_destroy(GTS_OBJECT(v3)); gts_allow_floating_vertices = FALSE; if (gts_delaunay_check(surface) != NULL) printf("error: triangulation not delaunay-conform!\n"); tFrames = g_slist_append(tFrames, gts_surface_strip(surface)); } int init(char* filename) { int i, xmax, ymax, pmax, dmax, p, d; GLfloat x, y, z; float t, slottime; FILE *DATA; GPtrArray *vertices, *packets, *drops; GSList *frames = NULL; dist = 100; timeslot = 0; render = GL_LINE_STRIP; animation = 0; writePPMs = 0; useZ = 1; drawNodes = 0; glClearColor(0.0, 0.0, 0.0, 0.0); glShadeModel(GL_SMOOTH); glEnable(GL_DEPTH_TEST); glPointSize(2); glEnable(GL_POINT_SMOOTH); DATA = fopen(filename, "r"); if (fscanf(DATA, "# x=%d, y=%d, n=%d, stop=%d\n", &xmax, &ymax, &fieldsize, &duration) < 4) { printf("Error reading input file!\n"); return 1; } max = 0; slottime = -1; do { fscanf(DATA, "%*s %f _%d_ (%f/%f) %f\n", &t, &i, &x, &y, &z); if (t != slottime) { vertices = g_ptr_array_new(); g_ptr_array_set_size(vertices, fieldsize); frames = g_slist_append(frames, vertices); slottime = t; } g_ptr_array_index(vertices, i) = gts_vertex_new(gts_vertex_class(), x * 100. / xmax, 100. - y * 100. / ymax, z * 10.); if (GTS_POINT(g_ptr_array_index(vertices, i))->z > max) max = GTS_POINT(g_ptr_array_index(vertices, i))->z; } while (getc(DATA) != EOF); fclose(DATA); /* read node data (node pos_x/pos_y packets drops) */ strcpy(rindex(filename, '.') + 1, "nod"); if ((DATA = fopen(filename, "r")) > 0) { fscanf(DATA, "# pmax = %d, dmax = %d\n", &pmax, &dmax); if (dmax == 0) dmax = 1; /* append one frame for packets and one for drops */ packets = g_ptr_array_new(); g_ptr_array_set_size(packets, fieldsize); frames = g_slist_append(frames, packets); drops = g_ptr_array_new(); g_ptr_array_set_size(drops, fieldsize); frames = g_slist_append(frames, drops); while (fscanf(DATA, "%d %d %d\n", &i, &p, &d) == 3) { g_ptr_array_index(packets, i) = gts_vertex_new(gts_vertex_class(), GTS_POINT(g_ptr_array_index(vertices, i))->x, GTS_POINT(g_ptr_array_index(vertices, i))->y, log(1 + (exp(1) - 1) * p / pmax) * max); g_ptr_array_index(drops, i) = gts_vertex_new(gts_vertex_class(), GTS_POINT(g_ptr_array_index(vertices, i))->x, GTS_POINT(g_ptr_array_index(vertices, i))->y, log(1 + (exp(1) - 1) * d / dmax) * max); } fclose(DATA); } slots = g_slist_length(frames); /* convert surface of each frame to triangle strips */ for (i = 0; i < slots; i++) { vertices = g_slist_nth_data(frames, i); surface2strips(vertices); printf("Processing frames: %d/%d (%d%%) done.\r", g_slist_length(tFrames), slots, (int)(100. * g_slist_length(tFrames) / slots + .5)); fflush(stdout); } g_slist_free(frames); /* prevent packets and drops from being animated */ slots -= 2; return 0; } void displayFrame(int frame) { int i, j; GSList *tStripList, *tStrip; GtsTriangle *t; GtsVertex *v1, *v2, *v3; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity(); glPushMatrix(); glTranslatef(0, 0, -dist); glRotatef(spin[0], 1.0, 0.0, 0.0); glRotatef(spin[1], 0.0, 1.0, 0.0); glRotatef(spin[2], 0.0, 0.0, 1.0); glTranslatef(-100 / 2, -100 / 2, -(max / 2)); tStripList = g_slist_nth_data(tFrames, frame); for (i = 0; i < g_slist_length(tStripList); i++) { tStrip = g_slist_nth_data(tStripList, i); for (j = 0; j < g_slist_length(tStrip); j++) { glBegin(render); t = g_slist_nth_data(tStrip, j); gts_triangle_vertices(t, &v1, &v2, &v3); if (GTS_POINT(v1)->z / max > 0.25) glColor3f(1, 1 - (GTS_POINT(v1)->z / max - 0.25) * 4 / 3, 0); else glColor3f(GTS_POINT(v1)->z / max * 4, 1, 0); glVertex3f(GTS_POINT(v1)->x, GTS_POINT(v1)->y, useZ ? GTS_POINT(v1)->z : 0); if (GTS_POINT(v2)->z / max > 0.25) glColor3f(1, 1 - (GTS_POINT(v2)->z / max - 0.25) * 4 / 3, 0); else glColor3f(GTS_POINT(v2)->z / max * 4, 1, 0); glVertex3f(GTS_POINT(v2)->x, GTS_POINT(v2)->y, useZ ? GTS_POINT(v2)->z : 0); if (GTS_POINT(v3)->z / max > 0.25) glColor3f(1, 1 - (GTS_POINT(v3)->z / max - 0.25) * 4 / 3, 0); else glColor3f(GTS_POINT(v3)->z / max * 4, 1, 0); glVertex3f(GTS_POINT(v3)->x, GTS_POINT(v3)->y, useZ ? GTS_POINT(v3)->z : 0); if (render == GL_LINE_STRIP) { if (GTS_POINT(v1)->z / max > 0.25) glColor3f(1, 1 - (GTS_POINT(v1)->z / max - 0.25) * 4 / 3, 0); else glColor3f(GTS_POINT(v1)->z / max * 4, 1, 0); glVertex3f(GTS_POINT(v1)->x, GTS_POINT(v1)->y, useZ ? GTS_POINT(v1)->z : 0); } glEnd(); if (drawNodes) { glBegin(GL_LINES); glColor3f(1, 1, 1); glVertex3f(GTS_POINT(v1)->x, GTS_POINT(v1)->y, useZ ? GTS_POINT(v1)->z : 0); glVertex3f(GTS_POINT(v1)->x, GTS_POINT(v1)->y, (useZ ? GTS_POINT(v1)->z : 0) + 1); glVertex3f(GTS_POINT(v2)->x, GTS_POINT(v2)->y, useZ ? GTS_POINT(v2)->z : 0); glVertex3f(GTS_POINT(v2)->x, GTS_POINT(v2)->y, (useZ ? GTS_POINT(v2)->z : 0) + 1); glVertex3f(GTS_POINT(v3)->x, GTS_POINT(v3)->y, useZ ? GTS_POINT(v3)->z : 0); glVertex3f(GTS_POINT(v3)->x, GTS_POINT(v3)->y, (useZ ? GTS_POINT(v3)->z : 0) + 1); glEnd(); } } } glPopMatrix(); glTranslatef(-0.04, -0.04, -0.1); glColor3f(0, 0, 1); } void display(void) { char message[10]; switch (mode) { case LOAD: displayFrame(timeslot); sprintf(message, "%.1f s", (timeslot + 1.) * duration / slots); break; case PACKETS: displayFrame(slots); sprintf(message, "Packets"); break; case DROPS: displayFrame(slots + 1); sprintf(message, "Drops"); break; } output(message); glutSwapBuffers(); } void reshape(int w, int h) { glViewport(0, 0, (GLsizei) w, (GLsizei) h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(50, (GLfloat) w / (GLfloat) h, 0.1, 200); glMatrixMode(GL_MODELVIEW); } void keyboard(unsigned char key, int x, int y) { switch (key) { case 'x': case 'y': case 'z': spin[key - 'x'] = (GLfloat) (((int)spin[key - 'x'] + 2) % 360); glutPostRedisplay(); break; case 'X': case 'Y': case 'Z': spin[key - 'X'] = (GLfloat) (((int)spin[key - 'X'] - 2) % 360); glutPostRedisplay(); break; case '+': if (timeslot + 1 < slots) timeslot++; glutPostRedisplay(); break; case '-': if (timeslot > 0) timeslot--; glutPostRedisplay(); break; case '1': timeslot = 0; glutPostRedisplay(); break; case 's': writePPM(timeslot); break; case 'a': animation = 1 - animation; if (writePPMs) writePPM(timeslot); glutTimerFunc((double)duration / slots * 1000, animate, animation); break; case 'w': writePPMs = 1 - writePPMs; break; case 'p': render = GL_POINTS; glutPostRedisplay(); break; case 'f': render = GL_LINE_STRIP; glutPostRedisplay(); break; case 't': render = GL_TRIANGLES; glutPostRedisplay(); break; case '2': useZ = 0; glutPostRedisplay(); break; case '3': useZ = 1; glutPostRedisplay(); break; case 'n': drawNodes = 1 - drawNodes; glutPostRedisplay(); break; case 27: case 'q': exit(0); } } void mouse(int button, int state, int x, int y) { switch(button) { case GLUT_LEFT_BUTTON: if (state == GLUT_DOWN) { dist--; glutPostRedisplay(); } break; case GLUT_RIGHT_BUTTON: dist++; glutPostRedisplay(); break; } } void menu(int item) { switch (item) { case 0: exit(0); break; case 1: mode = LOAD; glutPostRedisplay(); break; case 2: mode = PACKETS; glutPostRedisplay(); break; case 3: mode = DROPS; glutPostRedisplay(); break; } } int main(int argc, char** argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); glutInitWindowSize(500, 500); glutInitWindowPosition(100, 100); glutCreateWindow("Load on MAC layer"); if (init(argv[1]) == 0) { glutDisplayFunc(display); glutReshapeFunc(reshape); glutKeyboardFunc(keyboard); glutMouseFunc(mouse); glutCreateMenu(menu); glutAddMenuEntry("Display load", 1); glutAddMenuEntry("Display packets", 2); glutAddMenuEntry("Display drops", 3); glutAddMenuEntry("Exit", 0); glutAttachMenu(GLUT_MIDDLE_BUTTON); glutMainLoop(); return 0; } else { return 1; } }