224 lines
4.7 KiB
C++
224 lines
4.7 KiB
C++
|
|
#include <stdlib.h> /* rand() */
|
|
#include <GL/gl.h>
|
|
#include <GL/glu.h>
|
|
|
|
#include <iostream>
|
|
|
|
#include <gtkmm/entry.h>
|
|
#include <gdkmm/cursor.h>
|
|
|
|
#include "SierpinskiDA.h"
|
|
#include "Vector.h"
|
|
|
|
using namespace std;
|
|
|
|
SierpinskiDA::SierpinskiDA(const Glib::RefPtr<const Gdk::GL::Config> & 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<Gdk::GL::Window> glwindow = get_gl_window();
|
|
return glwindow->gl_begin(get_gl_context());
|
|
}
|
|
|
|
void SierpinskiDA::gl_end()
|
|
{
|
|
Glib::RefPtr<Gdk::GL::Window> 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();
|
|
}
|