nuclear@0: #include nuclear@0: #include nuclear@0: #include nuclear@0: #include nuclear@0: #include nuclear@0: #include nuclear@0: #include nuclear@0: nuclear@0: #ifndef __APPLE__ nuclear@0: #include nuclear@0: #else nuclear@0: #include nuclear@0: #endif nuclear@0: #include nuclear@0: #include nuclear@0: nuclear@0: #define FONTSZ 18 nuclear@0: nuclear@0: void init_gl(int argc, char **argv); nuclear@0: float rbvis_width(struct rbnode *tree); nuclear@0: void rbvis_draw(struct rbnode *tree, float x, float y); nuclear@0: nuclear@0: void draw_roundbox(float xsz, float ysz, float rad, int segm, const float *col, float border, const float *bcol); nuclear@0: void draw_fillet(float rad, int segm); nuclear@0: nuclear@0: struct rbtree *tree; nuclear@0: int num_nodes; nuclear@0: struct dtx_font *font; nuclear@0: char input_buffer[64]; nuclear@0: int win_xsz, win_ysz; nuclear@0: nuclear@0: int main(int argc, char **argv) nuclear@0: { nuclear@0: int i; nuclear@0: nuclear@0: if(argv[1]) { nuclear@0: if(!isdigit(argv[1][0])) { nuclear@0: fprintf(stderr, "pass a fucking number, not: %s\n", argv[1]); nuclear@0: return 1; nuclear@0: } nuclear@0: num_nodes = atoi(argv[1]); nuclear@0: } nuclear@0: nuclear@0: if(!(font = dtx_open_font("linux-libertine.ttf", FONTSZ))) { nuclear@0: fprintf(stderr, "failed to open font\n"); nuclear@0: return 1; nuclear@0: } nuclear@0: nuclear@0: if(!(tree = rb_create(RB_KEY_INT))) { nuclear@0: return 1; nuclear@0: } nuclear@0: nuclear@0: for(i=0; idata) nuclear@0: nuclear@0: void disp(void); nuclear@0: void reshape(int x, int y); nuclear@0: void keyb(unsigned char key, int x, int y); nuclear@0: void draw_rect(float x, float y, float width, float height, const char *text, int red); nuclear@0: void draw_link(float x0, float y0, float x1, float y1, int red); nuclear@0: nuclear@0: void init_gl(int argc, char **argv) nuclear@0: { nuclear@0: glutInitWindowSize(1280, 720); nuclear@0: glutInit(&argc, argv); nuclear@0: glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_MULTISAMPLE); nuclear@0: nuclear@0: glutCreateWindow("foo"); nuclear@0: nuclear@0: dtx_use_font(font, FONTSZ); nuclear@0: nuclear@0: glutDisplayFunc(disp); nuclear@0: glutReshapeFunc(reshape); nuclear@0: glutKeyboardFunc(keyb); nuclear@0: nuclear@0: glEnable(GL_DEPTH_TEST); nuclear@0: glEnable(GL_MULTISAMPLE); nuclear@0: nuclear@0: glutMainLoop(); nuclear@0: } nuclear@0: nuclear@0: void disp(void) nuclear@0: { nuclear@0: struct rbnode *root = rb_root(tree); nuclear@0: nuclear@0: glClearColor(0.57, 0.64, 0.59, 1.0); nuclear@0: glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); nuclear@0: nuclear@0: glMatrixMode(GL_MODELVIEW); nuclear@0: glLoadIdentity(); nuclear@0: nuclear@0: if(input_buffer[0]) { nuclear@0: char *prompt = "select node to delete: "; nuclear@0: char *buf = alloca(strlen(prompt) + strlen(input_buffer)); nuclear@0: nuclear@0: glPushMatrix(); nuclear@0: glTranslatef(10, 10, -0.9); nuclear@0: glColor3f(0, 0, 0); nuclear@0: sprintf(buf, "%s%s", prompt, input_buffer); nuclear@0: dtx_string(buf); nuclear@0: glPopMatrix(); nuclear@0: } nuclear@0: nuclear@0: if(root) { nuclear@0: rbvis_draw(root, rbvis_width(root->left) + NWIDTH, 550); nuclear@0: } nuclear@0: nuclear@0: glutSwapBuffers(); nuclear@0: assert(glGetError() == GL_NO_ERROR); nuclear@0: } nuclear@0: nuclear@0: nuclear@0: float rbvis_width(struct rbnode *tree) nuclear@0: { nuclear@0: if(!tree) nuclear@0: return NWIDTH; nuclear@0: nuclear@0: return NWIDTH + rbvis_width(tree->left) + rbvis_width(tree->right) + PADDING * 3.0; nuclear@0: } nuclear@0: nuclear@0: void rbvis_draw(struct rbnode *tree, float x, float y) nuclear@0: { nuclear@0: float leftx, rightx, nexty; nuclear@0: static const float hxsz = NWIDTH / 2.0; nuclear@0: static const float hysz = NHEIGHT / 2.0; nuclear@0: char text[16]; nuclear@0: nuclear@0: if(!tree) nuclear@0: return; nuclear@0: nuclear@0: leftx = x - (tree->left ? rbvis_width(tree->left->right) + NWIDTH : rbvis_width(tree->left) / 2.0); nuclear@0: rightx = x + (tree->right ? rbvis_width(tree->right->left) + NWIDTH : rbvis_width(tree->right) / 2.0); nuclear@0: nuclear@0: nexty = y - DY; nuclear@0: nuclear@0: sprintf(text, "%d", rb_node_keyi(tree)); nuclear@0: draw_rect(x - hxsz, y - hysz, NWIDTH, NHEIGHT, text, tree->red); nuclear@0: nuclear@0: rbvis_draw(tree->left, leftx, nexty); nuclear@0: rbvis_draw(tree->right, rightx, nexty); nuclear@0: nuclear@0: if(tree->left) nuclear@0: draw_link(x, y, leftx, nexty, tree->left->red); nuclear@0: if(tree->right) nuclear@0: draw_link(x, y, rightx, nexty, tree->right->red); nuclear@0: } nuclear@0: nuclear@0: void draw_rect(float x, float y, float width, float height, const char *text, int red) nuclear@0: { nuclear@0: float node_col[] = {0.63, 0.71, 0.82, 1.0}; nuclear@0: float bord_col[] = {0, 0, 0, 1}; nuclear@0: nuclear@0: if(red) { nuclear@0: bord_col[0] = 1.0; nuclear@0: } nuclear@0: nuclear@0: glMatrixMode(GL_MODELVIEW); nuclear@0: glPushMatrix(); nuclear@0: glTranslatef(x + width / 2.0, y + height / 2.0, 0.0); nuclear@0: nuclear@0: draw_roundbox(width, height, 8, 6, node_col, 1.2, bord_col); nuclear@0: nuclear@0: glColor3f(0.15, 0.15, 0.15); nuclear@0: glTranslatef(-dtx_string_width(text) / 2.0, -dtx_string_height(text) / 2.0, 0.1); nuclear@0: dtx_string(text); nuclear@0: glMatrixMode(GL_MODELVIEW); nuclear@0: glPopMatrix(); nuclear@0: } nuclear@0: nuclear@0: void draw_link(float x0, float y0, float x1, float y1, int red) nuclear@0: { nuclear@0: glPushAttrib(GL_LINE_BIT); nuclear@0: if(red) { nuclear@0: glLineWidth(3); nuclear@0: } else { nuclear@0: glLineWidth(2); nuclear@0: } nuclear@0: nuclear@0: glBegin(GL_LINES); nuclear@0: if(red) { nuclear@0: glColor3f(0.8, 0.36, 0.3); nuclear@0: } else { nuclear@0: glColor3f(0, 0, 0); nuclear@0: } nuclear@0: glVertex3f(x0, y0, -0.8); nuclear@0: glVertex3f(x1, y1, -0.8); nuclear@0: glEnd(); nuclear@0: nuclear@0: glPopAttrib(); nuclear@0: } nuclear@0: nuclear@0: void draw_roundbox(float xsz, float ysz, float rad, int segm, const float *col, float border, const float *bcol) nuclear@0: { nuclear@0: float hin_xsz, hin_ysz; nuclear@0: nuclear@0: if(border > 0.0f) { nuclear@0: glPushMatrix(); nuclear@0: glTranslatef(0, 0, -0.001); nuclear@0: draw_roundbox(xsz + 2 * border, ysz + 2 * border, rad + border, segm, bcol, 0.0, bcol); nuclear@0: glPopMatrix(); nuclear@0: } nuclear@0: nuclear@0: /* half inner size */ nuclear@0: hin_xsz = (xsz - 2.0 * rad) / 2.0; nuclear@0: hin_ysz = (ysz - 2.0 * rad) / 2.0; nuclear@0: nuclear@0: glColor4fv(col); nuclear@0: nuclear@0: glBegin(GL_QUADS); nuclear@0: /* center */ nuclear@0: glVertex2f(-hin_xsz, -hin_ysz); nuclear@0: glVertex2f(hin_xsz, -hin_ysz); nuclear@0: glVertex2f(hin_xsz, hin_ysz); nuclear@0: glVertex2f(-hin_xsz, hin_ysz); nuclear@0: /* right */ nuclear@0: glVertex2f(hin_xsz, -hin_ysz); nuclear@0: glVertex2f(hin_xsz + rad, -hin_ysz); nuclear@0: glVertex2f(hin_xsz + rad, hin_ysz); nuclear@0: glVertex2f(hin_xsz, hin_ysz); nuclear@0: /* top */ nuclear@0: glVertex2f(-hin_xsz, hin_ysz); nuclear@0: glVertex2f(hin_xsz, hin_ysz); nuclear@0: glVertex2f(hin_xsz, hin_ysz + rad); nuclear@0: glVertex2f(-hin_xsz, hin_ysz + rad); nuclear@0: /* left */ nuclear@0: glVertex2f(-hin_xsz - rad, -hin_ysz); nuclear@0: glVertex2f(-hin_xsz, -hin_ysz); nuclear@0: glVertex2f(-hin_xsz, hin_ysz); nuclear@0: glVertex2f(-hin_xsz - rad, hin_ysz); nuclear@0: /* bottom */ nuclear@0: glVertex2f(-hin_xsz, -hin_ysz - rad); nuclear@0: glVertex2f(hin_xsz, -hin_ysz - rad); nuclear@0: glVertex2f(hin_xsz, -hin_ysz); nuclear@0: glVertex2f(-hin_xsz, -hin_ysz); nuclear@0: glEnd(); nuclear@0: nuclear@0: glMatrixMode(GL_MODELVIEW); nuclear@0: nuclear@0: glPushMatrix(); nuclear@0: glTranslatef(hin_xsz, hin_ysz, 0); nuclear@0: draw_fillet(rad, segm); nuclear@0: glPopMatrix(); nuclear@0: nuclear@0: glPushMatrix(); nuclear@0: glTranslatef(-hin_xsz, hin_ysz, 0); nuclear@0: glRotatef(90, 0, 0, 1); nuclear@0: draw_fillet(rad, segm); nuclear@0: glPopMatrix(); nuclear@0: nuclear@0: glPushMatrix(); nuclear@0: glTranslatef(-hin_xsz, -hin_ysz, 0); nuclear@0: glRotatef(180, 0, 0, 1); nuclear@0: draw_fillet(rad, segm); nuclear@0: glPopMatrix(); nuclear@0: nuclear@0: glPushMatrix(); nuclear@0: glTranslatef(hin_xsz, -hin_ysz, 0); nuclear@0: glRotatef(270, 0, 0, 1); nuclear@0: draw_fillet(rad, segm); nuclear@0: glPopMatrix(); nuclear@0: } nuclear@0: nuclear@0: void draw_fillet(float rad, int segm) nuclear@0: { nuclear@0: int i; nuclear@0: nuclear@0: glBegin(GL_TRIANGLE_FAN); nuclear@0: glVertex2f(0, 0); nuclear@0: for(i=0; i= 0) { nuclear@0: glutPositionWindow(wposx, wposy); nuclear@0: wposx = -1; nuclear@0: } else { nuclear@0: wposx = glutGet(GLUT_WINDOW_X); nuclear@0: wposy = glutGet(GLUT_WINDOW_Y); nuclear@0: glutFullScreen(); nuclear@0: } nuclear@0: break; nuclear@0: nuclear@0: case 'a': nuclear@0: rb_inserti(tree, num_nodes++, 0); nuclear@0: glutPostRedisplay(); nuclear@0: break; nuclear@0: nuclear@0: case 'r': nuclear@0: { nuclear@0: int x; nuclear@0: do { nuclear@0: x = rand() % 1024; nuclear@0: } while(rb_findi(tree, x)); nuclear@0: nuclear@0: rb_inserti(tree, x, 0); nuclear@0: } nuclear@0: glutPostRedisplay(); nuclear@0: break; nuclear@0: nuclear@0: case 'd': nuclear@0: inp_next = input_buffer; nuclear@0: *inp_next++ = ' '; nuclear@0: *inp_next = 0; nuclear@0: glutPostRedisplay(); nuclear@0: break; nuclear@0: nuclear@0: case '0': nuclear@0: case '1': nuclear@0: case '2': nuclear@0: case '3': nuclear@0: case '4': nuclear@0: case '5': nuclear@0: case '6': nuclear@0: case '7': nuclear@0: case '8': nuclear@0: case '9': nuclear@0: if(inp_next) { nuclear@0: *inp_next++ = key; nuclear@0: *inp_next = 0; nuclear@0: glutPostRedisplay(); nuclear@0: } nuclear@0: break; nuclear@0: nuclear@0: case '\b': nuclear@0: if(inp_next > input_buffer) { nuclear@0: *--inp_next = 0; nuclear@0: glutPostRedisplay(); nuclear@0: } nuclear@0: break; nuclear@0: nuclear@0: case '\n': nuclear@0: case '\r': nuclear@0: if(inp_next) { nuclear@0: int x; nuclear@0: char *endp; nuclear@0: nuclear@0: *inp_next = 0; nuclear@0: inp_next = 0; nuclear@0: nuclear@0: if((x = strtol(input_buffer, &endp, 10)), endp == input_buffer) { nuclear@0: fprintf(stderr, "invalid input: %s\n", input_buffer); nuclear@0: } else if(!rb_findi(tree, x)) { nuclear@0: fprintf(stderr, "%d not found in the tree\n", x); nuclear@0: } else { nuclear@0: printf("deleting: %d\n", x); nuclear@0: rb_deletei(tree, x); nuclear@0: } nuclear@0: input_buffer[0] = 0; nuclear@0: glutPostRedisplay(); nuclear@0: } nuclear@0: break; nuclear@0: } nuclear@0: } nuclear@0: