]> git.cworth.org Git - akamaru/commitdiff
Add fps counter, add comment about sqrt() approximation.
authorKristian Høgsberg <krh@redhat.com>
Sat, 20 May 2006 21:30:28 +0000 (17:30 -0400)
committerKristian Høgsberg <krh@dinky.bitplanet.net>
Sat, 20 May 2006 21:30:28 +0000 (17:30 -0400)
akamaru.c

index fe14d2009e4e7e9c3da3f9630a067ac10ae71250..14d06015b67c1d257d35bbee4aa44ef9c578529d 100644 (file)
--- a/akamaru.c
+++ b/akamaru.c
@@ -20,6 +20,7 @@
 #include <cairo-xlib.h>
 #include <gdk/gdkx.h>
 #include <stdlib.h>
+#include <sys/time.h>
 #include <math.h>
 
 const double ground_friction = 0.1, ground_level = 400;
@@ -206,13 +207,13 @@ model_init_curtain (Model *model)
 static void
 model_init_grid (Model *model)
 {
-  const int num_ropes = 4;
-  const int num_rope_objects = 4;
+  const int num_ropes = 10;
+  const int num_rope_objects = 10;
   const int num_objects = num_ropes * num_rope_objects;
   const int num_strings = num_ropes * (num_rope_objects - 1) +
     (num_ropes - 1) * num_rope_objects;
-  const int string_length = 30;
-  const int rope_offset = 30;
+  const int string_length = 10;
+  const int rope_offset = 10;
   double x, y;
   int i, j, index, string_index;
 
@@ -312,6 +313,29 @@ model_integrate (Model *model, double step)
   }
 }
 
+/* The square root in the distance computation for the string and
+ * stick constraints can be aproximated using Newton:
+ *
+ *    distance = 
+ *      (model->sticks[i].length +
+ *       (dx * dx + dy * dy) / model->sticks[i].length) / 2;
+ *
+ * This works really well, since the constraints aren't typically
+ * violated much.  Thus, the distance is really close to the stick
+ * length, which then makes a good initial guess.  However, the
+ * approximation seems to be slower that just calling sqrt()...
+ */
+
+static inline double
+estimate_distance (double dx, double dy, double r)
+{
+#ifdef APPROXIMATE_SQUARE_ROOTS
+  return (r + (dx * dx + dy * dy) / r) / 2;
+#else
+  return sqrt (dx * dx + dy * dy);
+#endif
+}
+
 static void
 model_constrain (Model *model, double step)
 {
@@ -376,7 +400,7 @@ model_constrain (Model *model, double step)
     y = model->strings[i].a->position.y;
     dx = model->strings[i].b->position.x - x;
     dy = model->strings[i].b->position.y - y;
-    distance = sqrt (dx * dx + dy * dy);
+    distance = estimate_distance (dx, dy, model->strings[i].length);
     if (distance < model->strings[i].length)
       continue;
     fraction = (distance - model->strings[i].length) / distance / 2;
@@ -386,36 +410,19 @@ model_constrain (Model *model, double step)
     model->strings[i].b->position.y = y + dy * (1 - fraction);
   }
 
-#if 1
   /* Stick constraints. */
   for (i = 0; i < model->num_sticks; i++) {
     x = model->sticks[i].a->position.x;
     y = model->sticks[i].a->position.y;
     dx = model->sticks[i].b->position.x - x;
     dy = model->sticks[i].b->position.y - y;
-    distance = sqrt (dx * dx + dy * dy);
+    distance = estimate_distance (dx, dy, model->sticks[i].length);
     fraction = (distance - model->sticks[i].length) / distance / 2;
     model->sticks[i].a->position.x = x + dx * fraction;
     model->sticks[i].a->position.y = y + dy * fraction;
     model->sticks[i].b->position.x = x + dx * (1 - fraction);
     model->sticks[i].b->position.y = y + dy * (1 - fraction);
   }
-#else
-  /* Stick constraints, without square roots. */
-  squared = stick_length * stick_length;
-  for (i = 0; i < model->num_objects - 1; i++) {
-    j = i + 1;
-    x = model->objects[i].position.x;
-    y = model->objects[i].position.y;
-    dx = model->objects[j].position.x - x;
-    dy = model->objects[j].position.y - y;
-    fraction = squared / (dx * dx + dy * dy + squared) - 0.5;
-    model->objects[i].position.x = x + dx * fraction;
-    model->objects[i].position.y = y + dy * fraction;
-    model->objects[j].position.x = x + dx * (1 - fraction);
-    model->objects[j].position.y = y + dy * (1 - fraction);
-  }
-#endif
 }
 
 static void
@@ -426,7 +433,7 @@ model_step (Model *model, double delta_t)
   model_accumulate_forces (model);
   model_integrate (model, delta_t);
 
-  for (i = 0; i < 35; i++)
+  for (i = 0; i < 100; i++)
     model_constrain (model, delta_t);
 
   model->theta += delta_t;
@@ -578,12 +585,22 @@ 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)
 {
-  Model *model = data;
+  Closure *closure = data;
   cairo_t *cr;
 
   cr = gdk_cairo_create (widget->window);
@@ -591,11 +608,11 @@ expose_event (GtkWidget      *widget,
   cairo_set_source_rgb (cr, 1, 1, 1);
   cairo_paint (cr);
 
-  draw_constraints (cr, model, &red);
-  draw_sticks (cr, model, &black);
-  draw_strings (cr, model, &green);
-  draw_offsets (cr, model, &blue);
-  draw_objects (cr, model, &white);
+  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);
 
@@ -607,14 +624,15 @@ button_press_event (GtkWidget        *widget,
                    GdkEventButton *event,
                    gpointer        data)
 {
-  Model *model = data;
+  Closure *closure = data;
 
   if (event->button != 1)
     return TRUE;
 
-  model->anchor_position.x = event->x;
-  model->anchor_position.y = event->y;
-  model->anchor_object = model_find_nearest (model, event->x, event->y);
+  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;
 }
@@ -624,12 +642,12 @@ button_release_event (GtkWidget        *widget,
                      GdkEventButton *event,
                      gpointer        data)
 {
-  Model *model = data;
+  Closure *closure = data;
 
   if ((event->state & GDK_BUTTON1_MASK) == 0)
     return TRUE;
 
-  model->anchor_object = NULL;
+  closure->model->anchor_object = NULL;
 
   return TRUE;
 }
@@ -639,14 +657,14 @@ motion_notify_event (GtkWidget        *widget,
                     GdkEventMotion *event,
                     gpointer        data)
 {
-  Model *model = data;
+  Closure *closure = data;
   int x, y;
   GdkModifierType state;
 
   gdk_window_get_pointer (event->window, &x, &y, &state);
 
-  model->anchor_position.x = x + 0.5;
-  model->anchor_position.y = y + 0.5;
+  closure->model->anchor_position.x = x + 0.5;
+  closure->model->anchor_position.y = y + 0.5;
 
   return TRUE;
 }
@@ -656,7 +674,7 @@ typedef void (*ModelInitFunc) (Model *model);
 static void
 model_changed (GtkComboBox *combo, gpointer user_data)
 {
-  Model *model = user_data;
+  Closure *closure = user_data;
   GtkTreeIter iter;
   GtkTreeModel *tree_model;
   ModelInitFunc init;
@@ -668,8 +686,8 @@ model_changed (GtkComboBox *combo, gpointer user_data)
 
   gtk_tree_model_get (tree_model, &iter, 0, &name, 1, &init, -1);
 
-  model_fini (model);
-  (*init) (model);
+  model_fini (closure->model);
+  (*init) (closure->model);
 }
 
 static GtkTreeModel *
@@ -702,7 +720,7 @@ create_model_store (void)
 }
 
 static GtkWidget *
-create_model_combo (Model *model)
+create_model_combo (Closure *closure)
 {
   GtkWidget *hbox;
   GtkWidget *combo, *label;
@@ -728,13 +746,18 @@ create_model_combo (Model *model)
   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), model);
+                   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 GtkWidget *
-create_window (Model *model)
+static void
+create_window (Closure *closure)
 {
   GtkWidget *window;
   GtkWidget *frame;
@@ -743,7 +766,7 @@ create_window (Model *model)
   GtkWidget *model_combo;
 
   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
-  gtk_window_set_title (GTK_WINDOW (window), "Drawing Area");
+  gtk_window_set_title (GTK_WINDOW (window), "Akamaru");
 
   g_signal_connect (window, "destroy",
                    G_CALLBACK (gtk_main_quit), &window);
@@ -771,16 +794,16 @@ create_window (Model *model)
   /* Signals used to handle backing pixmap */
       
   g_signal_connect (da, "expose_event",
-                   G_CALLBACK (expose_event), model);
+                   G_CALLBACK (expose_event), closure);
       
   /* Event signals */
       
   g_signal_connect (da, "motion_notify_event",
-                   G_CALLBACK (motion_notify_event), model);
+                   G_CALLBACK (motion_notify_event), closure);
   g_signal_connect (da, "button_press_event",
-                   G_CALLBACK (button_press_event), model);
+                   G_CALLBACK (button_press_event), closure);
   g_signal_connect (da, "button_release_event",
-                   G_CALLBACK (button_release_event), model);
+                   G_CALLBACK (button_release_event), closure);
 
   /* Ask to receive events the drawing area doesn't normally
    * subscribe to
@@ -792,32 +815,49 @@ create_window (Model *model)
                         | GDK_POINTER_MOTION_MASK
                         | GDK_POINTER_MOTION_HINT_MASK);
 
-  model_combo = create_model_combo (model);
+  model_combo = create_model_combo (closure);
   gtk_box_pack_start (GTK_BOX (vbox), model_combo, FALSE, FALSE, 0);
 
-  return da;
+  closure->drawing_area = da;
 }
 
-typedef struct _Closure Closure;
-struct _Closure {
-  GtkWidget *drawing_area;
-  Model *model;
-  int i;
-};
-
 static gint
 timeout_callback (gpointer data)
 {
   Closure *closure = data;
   int i;
 
-  for (i = 0; i < 3; i++)
-    model_step (closure->model, 0.5);
+  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;
@@ -831,11 +871,13 @@ main (int argc, char *argv[])
 
   gtk_init (&argc, &argv);
   model_init_rope (&model);
-  closure.drawing_area = create_window (&model);
+  create_window (&closure);
   closure.i = 0;
   gtk_widget_show_all (gtk_widget_get_toplevel (closure.drawing_area));
   closure.model = &model;
-  g_timeout_add (100, timeout_callback, &closure);
+  closure.frame_count = 0;
+  gettimeofday (&closure.start, NULL);
+  g_timeout_add (40, timeout_callback, &closure);
   gtk_main ();
 
   return 0;