-
-typedef struct _Color Color;
-struct _Color {
- double red, green, blue;
-};
-
-static void
-draw_sticks (cairo_t *cr,
- Model *model,
- Color *color)
-{
- int i;
-
- cairo_set_source_rgba (cr, color->red, color->green, color->blue, 1);
- cairo_new_path (cr);
- cairo_set_line_width (cr, 2);
- cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND);
- cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
-
- for (i = 0; i < model->num_sticks; i++) {
- cairo_move_to (cr,
- model->sticks[i].a->position.x,
- model->sticks[i].a->position.y);
- cairo_line_to (cr,
- model->sticks[i].b->position.x,
- model->sticks[i].b->position.y);
- }
-
- cairo_stroke (cr);
-}
-
-static void
-draw_strings (cairo_t *cr,
- Model *model,
- Color *color)
-{
- int i;
-
- cairo_set_source_rgba (cr, color->red, color->green, color->blue, 1);
- cairo_new_path (cr);
- cairo_set_line_width (cr, 1);
- cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND);
- cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
-
- for (i = 0; i < model->num_strings; i++) {
- cairo_move_to (cr,
- model->strings[i].a->position.x,
- model->strings[i].a->position.y);
- cairo_line_to (cr,
- model->strings[i].b->position.x,
- model->strings[i].b->position.y);
- }
-
- cairo_stroke (cr);
-}
-
-static void
-draw_offsets (cairo_t *cr,
- Model *model,
- Color *color)
-{
- int i;
-
- cairo_set_source_rgba (cr, color->red, color->green, color->blue, 0.5);
- cairo_new_path (cr);
- cairo_set_line_width (cr, 4);
- cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND);
- cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
-
- for (i = 0; i < model->num_offsets; i++) {
- cairo_move_to (cr,
- model->offsets[i].a->position.x,
- model->offsets[i].a->position.y);
- cairo_line_to (cr,
- model->offsets[i].b->position.x,
- model->offsets[i].b->position.y);
- }
-
- cairo_stroke (cr);
-}
-
-static void
-draw_constraints (cairo_t *cr,
- Model *model,
- Color *color)
-{
- cairo_set_source_rgba (cr, color->red, color->green, color->blue, 0.5);
-
- cairo_move_to (cr, 0, ground_level);
- cairo_line_to (cr, 1500, ground_level);
- cairo_line_to (cr, 1500, ground_level + 10);
- cairo_line_to (cr, 0, ground_level + 10);
- cairo_close_path (cr);
-
- cairo_move_to (cr, 0, box_top);
- cairo_line_to (cr, box_left, box_top);
- cairo_line_to (cr, box_left, box_bottom);
- cairo_line_to (cr, 0, box_bottom);
- cairo_close_path (cr);
-
- cairo_fill (cr);
-}
-
-static void
-draw_objects (cairo_t *cr, Model *model, Color *color)
-{
- int i;
-
- for (i = 0; i < model->num_objects; i++) {
- }
-}
-
-static Color blue = { 0, 0, 1 };
-static Color green = { 0, 1, 0 };
-static Color red = { 1, 0, 0 };
-static Color black = { 0, 0, 0 };
-static Color white = { 1, 1, 1 };
-
-typedef struct _Closure Closure;
-struct _Closure {
- GtkWidget *drawing_area;
- GtkWidget *fps_label;
- Model *model;
- int frame_count;
- int i;
- struct timeval start;
-};
-
-static gboolean
-expose_event (GtkWidget *widget,
- GdkEventExpose *event,
- gpointer data)
-{
- Closure *closure = data;
- cairo_t *cr;
-
- cr = gdk_cairo_create (widget->window);
-
- cairo_set_source_rgb (cr, 1, 1, 1);
- cairo_paint (cr);
-
- draw_constraints (cr, closure->model, &red);
- draw_sticks (cr, closure->model, &black);
- draw_strings (cr, closure->model, &green);
- draw_offsets (cr, closure->model, &blue);
- draw_objects (cr, closure->model, &white);
-
- cairo_destroy (cr);
-
- return TRUE;
-}
-
-static gboolean
-button_press_event (GtkWidget *widget,
- GdkEventButton *event,
- gpointer data)
-{
- Closure *closure = data;
-
- if (event->button != 1)
- return TRUE;
-
- closure->model->anchor_position.x = event->x;
- closure->model->anchor_position.y = event->y;
- closure->model->anchor_object = model_find_nearest (closure->model,
- event->x, event->y);
-
- return TRUE;
-}
-
-static gboolean
-button_release_event (GtkWidget *widget,
- GdkEventButton *event,
- gpointer data)
-{
- Closure *closure = data;
-
- if ((event->state & GDK_BUTTON1_MASK) == 0)
- return TRUE;
-
- closure->model->anchor_object = NULL;
-
- return TRUE;
-}
-
-static gboolean
-motion_notify_event (GtkWidget *widget,
- GdkEventMotion *event,
- gpointer data)
-{
- Closure *closure = data;
- int x, y;
- GdkModifierType state;
-
- gdk_window_get_pointer (event->window, &x, &y, &state);
-
- closure->model->anchor_position.x = x + 0.5;
- closure->model->anchor_position.y = y + 0.5;
-
- return TRUE;
-}
-
-typedef void (*ModelInitFunc) (Model *model);
-
-static void
-model_changed (GtkComboBox *combo, gpointer user_data)
-{
- Closure *closure = user_data;
- GtkTreeIter iter;
- GtkTreeModel *tree_model;
- ModelInitFunc init;
- char *name;
-
- tree_model = gtk_combo_box_get_model (combo);
- if (!gtk_combo_box_get_active_iter (combo, &iter))
- return;
-
- gtk_tree_model_get (tree_model, &iter, 0, &name, 1, &init, -1);
-
- model_fini (closure->model);
- (*init) (closure->model);
-}
-
-static GtkTreeModel *
-create_model_store (void)
-{
- static struct {
- const char *name;
- ModelInitFunc init;
- } models[] = {
- { "Rope", model_init_rope },
- { "Snake", model_init_snake },
- { "Curtain", model_init_curtain },
- { "Grid", model_init_grid }
- };
-
- GtkTreeIter iter;
- GtkTreeStore *store;
- gint i;
-
- store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_POINTER);
-
- for (i = 0; i < G_N_ELEMENTS(models); i++) {
- gtk_tree_store_append (store, &iter, NULL);
- gtk_tree_store_set (store, &iter,
- 0, models[i].name, 1, models[i].init, -1);
- }
-
- return GTK_TREE_MODEL (store);
-
-}
-
-static GtkWidget *
-create_model_combo (Closure *closure)
-{
- GtkWidget *hbox;
- GtkWidget *combo, *label;
- GtkTreeModel *store;
- GtkCellRenderer *renderer;
-
- hbox = gtk_hbox_new (FALSE, 8);
-
- label = gtk_label_new_with_mnemonic ("_Model:");
- gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
-
- store = create_model_store ();
- combo = gtk_combo_box_new_with_model (store);
- gtk_combo_box_set_active (GTK_COMBO_BOX (combo), 0);
- g_object_unref (store);
-
- renderer = gtk_cell_renderer_text_new ();
- gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), renderer, TRUE);
- gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo), renderer,
- "text", 0,
- NULL);
-
- gtk_label_set_mnemonic_widget (GTK_LABEL (label), combo);
- gtk_box_pack_start (GTK_BOX (hbox), combo, FALSE, FALSE, 0);
- g_signal_connect (combo, "changed",
- G_CALLBACK (model_changed), closure);
-
- label = gtk_label_new ("Frames per second: 0");
- gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
-
- closure->fps_label = label;
-
- return hbox;
-}
-
-static void
-create_window (Closure *closure)
-{
- GtkWidget *window;
- GtkWidget *frame;
- GtkWidget *vbox;
- GtkWidget *da;
- GtkWidget *model_combo;
-
- window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
- gtk_window_set_title (GTK_WINDOW (window), "Akamaru");
-
- g_signal_connect (window, "destroy",
- G_CALLBACK (gtk_main_quit), &window);
-
- gtk_container_set_border_width (GTK_CONTAINER (window), 8);
-
- vbox = gtk_vbox_new (FALSE, 8);
- gtk_container_set_border_width (GTK_CONTAINER (vbox), 8);
- gtk_container_add (GTK_CONTAINER (window), vbox);
-
- /*
- * Create the drawing area
- */
-
- frame = gtk_frame_new (NULL);
- gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
- gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, TRUE, 0);
-
- da = gtk_drawing_area_new ();
- /* set a minimum size */
- gtk_widget_set_size_request (da, 600, 500);
-
- gtk_container_add (GTK_CONTAINER (frame), da);
-
- /* Signals used to handle backing pixmap */
-
- g_signal_connect (da, "expose_event",
- G_CALLBACK (expose_event), closure);
-
- /* Event signals */
-
- g_signal_connect (da, "motion_notify_event",
- G_CALLBACK (motion_notify_event), closure);
- g_signal_connect (da, "button_press_event",
- G_CALLBACK (button_press_event), closure);
- g_signal_connect (da, "button_release_event",
- G_CALLBACK (button_release_event), closure);
-
- /* Ask to receive events the drawing area doesn't normally
- * subscribe to
- */
- gtk_widget_set_events (da, gtk_widget_get_events (da)
- | GDK_LEAVE_NOTIFY_MASK
- | GDK_BUTTON_PRESS_MASK
- | GDK_BUTTON_RELEASE_MASK
- | GDK_POINTER_MOTION_MASK
- | GDK_POINTER_MOTION_HINT_MASK);
-
- model_combo = create_model_combo (closure);
- gtk_box_pack_start (GTK_BOX (vbox), model_combo, FALSE, FALSE, 0);
-
- closure->drawing_area = da;
-}
-
-static gint
-timeout_callback (gpointer data)
-{
- Closure *closure = data;
- int i;
-
- model_step (closure->model, 1);
-
- closure->i++;
- if (closure->i == 1) {
- gtk_widget_queue_draw (closure->drawing_area);
- closure->i = 0;
- closure->frame_count++;
- }
-
- if (closure->frame_count == 200) {
- struct timeval end, elapsed;
- double total;
- char text[50];
-
- closure->frame_count = 0;
- gettimeofday (&end, NULL);
- if (closure->start.tv_usec > end.tv_usec) {
- end.tv_usec += 1000000;
- end.tv_sec--;
- }
-
- elapsed.tv_usec = end.tv_usec - closure->start.tv_usec;
- elapsed.tv_sec = end.tv_sec - closure->start.tv_sec;
-
- total = elapsed.tv_sec + ((double) elapsed.tv_usec / 1e6);
- if (total < 0) {
- total = 0;
- }
- closure->start = end;
- snprintf (text, sizeof text, "Frames per second: %.2f", 200 / total);
- gtk_label_set_text (GTK_LABEL (closure->fps_label), text);
- }
-
- return TRUE;
-}
-
-int
-main (int argc, char *argv[])
-{
- Closure closure;
- Model model;
-
- gtk_init (&argc, &argv);
- model_init_rope (&model);
- create_window (&closure);
- closure.i = 0;
- gtk_widget_show_all (gtk_widget_get_toplevel (closure.drawing_area));
- closure.model = &model;
- closure.frame_count = 0;
- gettimeofday (&closure.start, NULL);
- g_timeout_add (40, timeout_callback, &closure);
- gtk_main ();
-
- return 0;
-}