#include /* rand() */ #include #include #include #include #include #include "SierpinskiDA.h" #include "Vector.h" using namespace std; SierpinskiDA::SierpinskiDA(const Glib::RefPtr & config, Gtk::Entry & n_points_entry) : Gtk::GL::DrawingArea(config), m_n_points_entry(n_points_entry) { set_gl_capability(config); set_events(Gdk::POINTER_MOTION_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK | Gdk::SCROLL_MASK); m_dragging = false; } void SierpinskiDA::regenerate_clicked() { regenerate(atoi(m_n_points_entry.get_text().c_str())); queue_draw(); } void SierpinskiDA::regenerate(int npts) { #define deg2rad(x) ((x)/180.0*M_PI) const static float pts[][3] = { {0, 0, sqrt(1 + sin(deg2rad(60))*sin(deg2rad(60))+1.5*1.5)}, {0, 1, 0}, {sin(deg2rad(60)), -cos(deg2rad(60)), 0}, {-sin(deg2rad(60)), -cos(deg2rad(60)), 0} }; gl_begin(); glNewList(m_dl, GL_COMPILE); glBegin(GL_POINTS); double pt[3]; double r = rand() / (double) RAND_MAX; for (int i = 0; i < 3; i++) { pt[i] = pts[0][i] + r * pts[1][i] - pts[0][i]; } for (int i = 0; i < npts; i++) { glVertex3dv(pt); int pt_idx = rand() & 0x3; for (int j = 0; j < 3; j++) { pt[j] = (pt[j] + pts[pt_idx][j]) / 2.0; } } glEnd(); glEndList(); gl_end(); } bool SierpinskiDA::gl_begin() { Glib::RefPtr glwindow = get_gl_window(); return glwindow->gl_begin(get_gl_context()); } void SierpinskiDA::gl_end() { Glib::RefPtr glwindow = get_gl_window(); glwindow->gl_end(); } bool SierpinskiDA::draw() { if (!gl_begin()) return false; glClearColor(0.0, 0.0, 0.0, 1.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glPushMatrix(); glMultMatrixf(m_drag_matrix); glCallList(m_dl); glPopMatrix(); if (get_gl_window()->is_double_buffered()) get_gl_window()->swap_buffers(); else glFlush(); gl_end(); return true; } bool SierpinskiDA::on_motion_notify_event(GdkEventMotion * event) { if (m_dragging) { Vector v = ptrToDragVector(); Vector cross = m_dragBegin * v; if (cross.mag2() > 0.5) { gl_begin(); glPushMatrix(); glLoadIdentity(); glRotated(180.0 * acos(m_dragBegin % v) / M_PI, cross[0], cross[1], cross[2]); glGetFloatv(GL_MODELVIEW_MATRIX, &m_drag_matrix[0]); glPopMatrix(); gl_end(); } queue_draw(); } return true; } bool SierpinskiDA::on_button_press_event(GdkEventButton * event) { if (event->button == 1) { m_dragging = true; m_dragBegin = ptrToDragVector(); } return false; } bool SierpinskiDA::on_button_release_event(GdkEventButton * event) { if (event->button == 1) { m_dragging = false; gl_begin(); glPushMatrix(); glLoadIdentity(); glGetFloatv(GL_MODELVIEW_MATRIX, &m_drag_matrix[0]); glPopMatrix(); gl_end(); } return false; } bool SierpinskiDA::on_scroll_event(GdkEventScroll * event) { return false; } void SierpinskiDA::on_realize() { Gtk::GL::DrawingArea::on_realize(); if (!gl_begin()) return; glViewport(0, 0, get_width(), get_height()); m_dl = glGenLists(1); glEnable(GL_DEPTH_TEST); #if 0 glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); float color[] = {1, 1, 1, 1}; glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, color); #endif glColor3f(1, 1, 1); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(60, get_width()/(double)get_height(), 0.01, 1000.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glGetFloatv(GL_MODELVIEW_MATRIX, &m_drag_matrix[0]); gluLookAt(0, -3, 1.5, 0, 0, 1, 0, 0, 1); gl_end(); regenerate(10000); } /* * called on widget resizes */ bool SierpinskiDA::on_configure_event(GdkEventConfigure * event) { if (!gl_begin()) return false; glViewport(0, 0, get_width(), get_height()); gl_end(); return true; } bool SierpinskiDA::on_expose_event(GdkEventExpose * event) { return draw(); } Vector SierpinskiDA::ptrToDragVector() { int x, y; get_pointer(x, y); int w = get_width(); int h = get_height(); double r = min(w, h) / 2.0; double xd = (x - w/2.0) / r; double yd = (h/2.0 - y) / r; double d2 = xd*xd + yd*yd; double z = d2 >= 1.0 ? 0.0 : sqrt(1 - d2); return Vector(xd, yd, z).normalize(); }