diff options
author | Kristian Høgsberg <krh@redhat.com> | 2006-07-05 03:19:32 -0400 |
---|---|---|
committer | Kristian Høgsberg <krh@redhat.com> | 2006-07-05 03:19:32 -0400 |
commit | 9ad6f0b348f59520b427fa383aa85f42a430a11b (patch) | |
tree | 83b567794f85f719c98645a9f1fb42e45b99a6d3 | |
parent | 395c1747a3e3133808b565942f15570c731c54d6 (diff) |
First steps towards making the akamaru model dynamic.
-rw-r--r-- | akamaru.c | 291 | ||||
-rw-r--r-- | akamaru.h | 33 | ||||
-rw-r--r-- | dock.c | 117 |
3 files changed, 309 insertions, 132 deletions
@@ -21,6 +21,54 @@ #include "akamaru.h" +static void +link_init (Link *link) +{ + link->prev = link; + link->next = link; +} + +static void +link_insert_before (Link *link, Link *anchor) +{ + link->prev = anchor->prev; + link->next = anchor; + link->prev->next = link; + link->next->prev = link; +} + +static void +link_remove (Link *link) +{ + link->prev->next = link->next; + link->next->prev = link->prev; +} + +static void +list_init (List *list, size_t offset) +{ + link_init (&list->head); + list->offset = offset; +} + +static void +list_for_each (List *list, ListFunc func, void *data) +{ + Link *l; + + for (l = list->head.next; l != &list->head; l = l->next) + func ((char *) l - list->offset, data); +} + +static void +list_append (List *list, void *element) +{ + Link *link; + + link = (Link *) ((char *) element + list->offset); + link_insert_before (link, &list->head); +} + void object_init (Object *object, double x, double y, double mass) { @@ -39,6 +87,20 @@ spring_init (Spring *spring, Object *a, Object *b, double length) spring->length = length; } +Spring * +model_add_spring (Model *model, Object *a, Object *b, double length) +{ + Spring *spring; + + spring = g_new (Spring, 1); + spring->a = a; + spring->b = b; + spring->length = length; + list_append (&model->spring_list, spring); + + return spring; +} + void stick_init (Stick *stick, Object *a, Object *b, double length) { @@ -73,6 +135,20 @@ spacer_init (Spacer *spacer, Object *a, Object *b, double length) spacer->length = length; } +Spacer * +model_add_spacer (Model *model, Object *a, Object *b, double length) +{ + Spacer *spacer; + + spacer = g_new (Spacer, 1); + spacer->a = a; + spacer->b = b; + spacer->length = length; + list_append (&model->spacer_list, spacer); + + return spacer; +} + void anchor_init (Anchor *anchor, Object *object, double x, double y) { @@ -141,6 +217,38 @@ polygon_init_enclosing_rectangle (Polygon *polygon, double x0, double y0, } void +model_init (Model *model) +{ + memset (model, 0, sizeof *model); + list_init (&model->object_list, G_STRUCT_OFFSET (Object, link)); + list_init (&model->spacer_list, G_STRUCT_OFFSET (Spacer, link)); + list_init (&model->spring_list, G_STRUCT_OFFSET (Spring, link)); +} + +Object * +model_add_object (Model *model, double x, double y, double mass, void *data) +{ + Object *object; + + object = g_new (Object, 1); + object->position.x = x; + object->position.y = y; + object->previous_position.x = x; + object->previous_position.y = y; + object->mass = mass; + list_append (&model->object_list, object); + object->data = data; + + return object; +} + +void +model_for_each_object (Model *model, ObjectFunc func, void *data) +{ + list_for_each (&model->object_list, (ListFunc) func, data); +} + +void model_fini (Model *model) { int i; @@ -161,46 +269,61 @@ model_fini (Model *model) } static void +object_accumulate_forces (Object *object, void *data) +{ + Model *model = data; + Vector v; + + /* Gravity */ + object->force.x = 0; + object->force.y = model->gravity * object->mass; + + /* Friction */ + v.x = object->position.x - object->previous_position.x; + v.y = object->position.y - object->previous_position.y; + object->force.x -= v.x * model->friction; + object->force.y -= v.y * model->friction; +} + +static void +spring_accumulate_forces (void *element, void *data) +{ + Spring *spring = element; + Model *model = data; + double x, y, dx, dy, distance, displacement; + Vector u; + + x = spring->a->position.x; + y = spring->a->position.y; + dx = spring->b->position.x - x; + dy = spring->b->position.y - y; + distance = sqrt (dx * dx + dy * dy); + u.x = dx / distance; + u.y = dy / distance; + displacement = distance - spring->length; + spring->a->force.x += u.x * model->k * displacement; + spring->a->force.y += u.y * model->k * displacement; + spring->b->force.x -= u.x * model->k * displacement; + spring->b->force.y -= u.y * model->k * displacement; +} + +static void model_accumulate_forces (Model *model) { int i; - double x, y, dx, dy, distance, displacement; + double x, y, dx, dy; Point middle; - Vector u, v; - for (i = 0; i < model->num_objects; i++) { - /* Gravity */ - model->objects[i].force.x = 0; - model->objects[i].force.y = model->gravity * model->objects[i].mass; - - /* Friction */ - v.x = model->objects[i].position.x - model->objects[i].previous_position.x; - v.y = model->objects[i].position.y - model->objects[i].previous_position.y; - model->objects[i].force.x -= v.x * model->friction; - model->objects[i].force.y -= v.y * model->friction; - } + model_for_each_object (model, object_accumulate_forces, model); - for (i = 0; i < model->num_springs; i++) { - x = model->springs[i].a->position.x; - y = model->springs[i].a->position.y; - dx = model->springs[i].b->position.x - x; - dy = model->springs[i].b->position.y - y; - distance = sqrt (dx * dx + dy * dy); - u.x = dx / distance; - u.y = dy / distance; - displacement = distance - model->springs[i].length; - model->springs[i].a->force.x += u.x * model->k * displacement; - model->springs[i].a->force.y += u.y * model->k * displacement; - model->springs[i].b->force.x -= u.x * model->k * displacement; - model->springs[i].b->force.y -= u.y * model->k * displacement; - } + list_for_each (&model->spring_list, spring_accumulate_forces, model); for (i = 0; i < model->num_offset_springs; i++) { - middle.x = - (model->offset_springs[i].a->position.x + + middle.x = + (model->offset_springs[i].a->position.x + model->offset_springs[i].b->position.x) / 2; - middle.y = - (model->offset_springs[i].a->position.y + + middle.y = + (model->offset_springs[i].a->position.y + model->offset_springs[i].b->position.y) / 2; x = middle.x - model->offset_springs[i].dx / 2; @@ -214,37 +337,24 @@ model_accumulate_forces (Model *model) model->offset_springs[i].b->force.x -= dx * model->k; model->offset_springs[i].b->force.y -= dy * model->k; } - - for (i = 0; i < model->num_objects; i++) { - double f = - model->objects[i].force.x * model->objects[i].force.x + - model->objects[i].force.y * model->objects[i].force.y; - - if (f > 100000000) - abort(); - } } static void -model_integrate (Model *model, double step) +object_integrate (Object *object, void *data) { - double x, y; - Object *o; - int i; + double x, y, step; - for (i = 0; i < model->num_objects; i++) { - o = &model->objects[i]; - x = o->position.x; - y = o->position.y; - - o->position.x = - x + (x - o->previous_position.x) + o->force.x * step * step; - o->position.y = - y + (y - o->previous_position.y) + o->force.y * step * step; - - o->previous_position.x = x; - o->previous_position.y = y; - } + step = * (double *) data; + x = object->position.x; + y = object->position.y; + + object->position.x = + x + (x - object->previous_position.x) + object->force.x * step * step; + object->position.y = + y + (y - object->previous_position.y) + object->force.y * step * step; + + object->previous_position.x = x; + object->previous_position.y = y; } /* The square root in the distance computation for the string and @@ -317,15 +427,30 @@ polygon_reflect_object (Polygon *polygon, Object *object, double elasticity) object->previous_position.y -= (1 + elasticity) * distance * n->y; } +typedef struct _ObjectConstrainPolygonClosure { + Model *model; + Polygon *polygon; +} ObjectConstrainPolygonClosure; + +static void +object_constrain_polygon (Object *object, void *data) +{ + ObjectConstrainPolygonClosure *closure = data; + + if (polygon_contains_point (closure->polygon, &object->position)) + polygon_reflect_object (closure->polygon, object, + closure->model->elasticity); +} + static void model_constrain_polygon (Model *model, Polygon *polygon) { - int i; + ObjectConstrainPolygonClosure closure; - for (i = 0; i < model->num_objects; i++) { - if (polygon_contains_point (polygon, &model->objects[i].position)) - polygon_reflect_object (polygon, &model->objects[i], model->elasticity); - } + closure.model = model; + closure.polygon = polygon; + + model_for_each_object (model, object_constrain_polygon, &closure); } static void @@ -352,7 +477,7 @@ model_constrain_offset (Model *model, Offset *offset) x = x / offset->num_objects - offset->dx * (offset->num_objects - 1) / 2; y = y / offset->num_objects - offset->dy * (offset->num_objects - 1) / 2; - + for (i = 0; i < offset->num_objects; i++) { offset->objects[i]->position.x = x + offset->dx * i; offset->objects[i]->position.y = y + offset->dy * i; @@ -360,6 +485,29 @@ model_constrain_offset (Model *model, Offset *offset) } static void +model_constrain_spacer (void *element, void *data) +{ + Spacer *spacer = element; + double x, y, dx, dy, distance, fraction; + + x = spacer->a->position.x; + y = spacer->a->position.y; + dx = spacer->b->position.x - x; + dy = spacer->b->position.y - y; + + distance = estimate_distance (dx, dy, spacer->length); + if (distance > spacer->length) + return; + + fraction = (distance - spacer->length) / distance / 2; + spacer->a->position.x = x + dx * fraction; + spacer->a->position.y = y + dy * fraction; + spacer->b->position.x = x + dx * (1 - fraction); + spacer->b->position.y = y + dy * (1 - fraction); +} + + +static void model_constrain (Model *model) { double dx, dy, x, y, distance, fraction; @@ -387,20 +535,7 @@ model_constrain (Model *model) } /* Spacer constraints. */ - for (i = 0; i < model->num_spacers; i++) { - x = model->spacers[i].a->position.x; - y = model->spacers[i].a->position.y; - dx = model->spacers[i].b->position.x - x; - dy = model->spacers[i].b->position.y - y; - distance = estimate_distance (dx, dy, model->spacers[i].length); - if (distance > model->spacers[i].length) - continue; - fraction = (distance - model->spacers[i].length) / distance / 2; - model->spacers[i].a->position.x = x + dx * fraction; - model->spacers[i].a->position.y = y + dy * fraction; - model->spacers[i].b->position.x = x + dx * (1 - fraction); - model->spacers[i].b->position.y = y + dy * (1 - fraction); - } + list_for_each (&model->spacer_list, model_constrain_spacer, model); /* Stick constraints. */ for (i = 0; i < model->num_sticks; i++) { @@ -431,7 +566,7 @@ model_step (Model *model, double delta_t) int i; model_accumulate_forces (model); - model_integrate (model, delta_t); + model_for_each_object (model, object_integrate, &delta_t); for (i = 0; i < model->constrain_iterations; i++) model_constrain (model); @@ -1,6 +1,20 @@ #ifndef __AKAMARU_H__ #define __AKAMARU_H__ +typedef struct _Link Link; +typedef struct _List List; +struct _Link { + Link *prev; + Link *next; +}; + +struct _List { + Link head; + size_t offset; +}; + +typedef void (*ListFunc) (void *element, void *data); + typedef struct _xy_pair Point; typedef struct _xy_pair Vector; struct _xy_pair { @@ -27,6 +41,10 @@ struct _Object { double mass; double theta; + + Link link; + + void *data; }; struct _Stick { @@ -48,6 +66,7 @@ struct _Offset { struct _Spring { Object *a, *b; int length; + Link link; }; struct _OffsetSpring { @@ -58,6 +77,7 @@ struct _OffsetSpring { struct _Spacer { Object *a, *b; int length; + Link link; }; struct _Anchor { @@ -73,6 +93,10 @@ struct _Polygon { }; struct _Model { + List object_list; + List spacer_list; + List spring_list; + int num_objects; Object *objects; int num_sticks; @@ -103,6 +127,8 @@ struct _Model { double theta; }; +typedef void (*ObjectFunc) (Object *element, void *data); + void object_init (Object *object, double x, double y, double mass); void offset_spring_init (OffsetSpring *spring, Object *a, Object *b, double dx, double dy); @@ -119,8 +145,15 @@ void polygon_init_rectangle (Polygon *polygon, double x0, double y0, void polygon_init_enclosing_rectangle (Polygon *polygon, double x0, double y0, double x1, double y1); +void model_init (Model *model); void model_fini (Model *model); +Object *model_add_object (Model *model, double x, double y, double mass, void *data); +void model_for_each_object (Model *model, ObjectFunc func, void *data); + +Spacer *model_add_spacer (Model *model, Object *a, Object *b, double length); +Spring *model_add_spring (Model *model, Object *a, Object *b, double length); + void model_step (Model *model, double delta_t); Object *model_find_nearest (Model *model, double x, double y); @@ -52,6 +52,8 @@ struct _KibaDock KibaLauncher *dragging_launcher; GConfClient *gconf_client; + + Object *object; }; struct _KibaDockClass @@ -109,6 +111,10 @@ static void kiba_dock_init_model (Model *model, static KibaLauncher *kiba_launcher_new (KibaDock *dock, Object *object, const char *gconf_path); +static void kiba_launcher_create_window (KibaLauncher *launcher); +static void kiba_dock_add_launcher (KibaDock *dock, KibaLauncher *launcher, + int x, int y); + static gint timeout_callback (gpointer data); G_DEFINE_TYPE (KibaDock, kiba_dock, GTK_TYPE_WIDGET) @@ -178,7 +184,10 @@ kiba_dock_init (KibaDock *dock) launcher = kiba_launcher_new (dock, &dock->model.objects[i + 1], path); if (launcher == NULL) continue; - dock->launchers = g_list_prepend (dock->launchers, launcher); + + kiba_dock_add_launcher (dock, launcher, + g_random_int_range (0, width), + g_random_int_range (0, height)); } gtk_drag_dest_set(GTK_WIDGET (dock), @@ -296,6 +305,7 @@ kiba_dock_realize (GtkWidget *widget) GdkScreen *screen; GdkWindowAttr attributes; gint attributes_mask; + GList *l; g_return_if_fail (KIBA_IS_DOCK (widget)); @@ -317,6 +327,12 @@ kiba_dock_realize (GtkWidget *widget) widget->window = gdk_window_new (gdk_screen_get_root_window (screen), &attributes, attributes_mask); gdk_window_set_user_data (widget->window, dock); + + for (l = dock->launchers; l != NULL; l = l->next) + { + KibaLauncher *launcher = l->data; + kiba_launcher_create_window (launcher); + } } static void @@ -361,10 +377,11 @@ kiba_dock_map (GtkWidget *widget) GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED); gdk_window_show (widget->window); - for (l = dock->launchers; l != NULL; l = l->next) { - KibaLauncher *launcher = l->data; - gdk_window_show (launcher->window); - } + for (l = dock->launchers; l != NULL; l = l->next) + { + KibaLauncher *launcher = l->data; + gdk_window_show (launcher->window); + } } static gint @@ -374,12 +391,13 @@ timeout_callback (gpointer data) GList *l; int i; - for (l = dock->launchers; l != NULL; l = l->next) { - KibaLauncher *launcher = l->data; - gdk_window_move (launcher->window, - launcher->object->position.x + 0.5, - launcher->object->position.y + 0.5); - } + for (l = dock->launchers; l != NULL; l = l->next) + { + KibaLauncher *launcher = l->data; + gdk_window_move (launcher->window, + launcher->object->position.x + 0.5, + launcher->object->position.y + 0.5); + } for (i = 0; i < 6; i++) model_step (&dock->model, 0.01); @@ -388,28 +406,39 @@ timeout_callback (gpointer data) } static void +add_spacer (Object *object, void *data) +{ + KibaDock *dock = data; + + /* Skip the anchor object. */ + if (object->data == NULL && object != dock->object) + model_add_spacer (&dock->model, dock->object, object, dock->spacing); +} + +static void +kiba_dock_add_launcher (KibaDock *dock, KibaLauncher *launcher, int x, int y) +{ + Object *object; + + object = model_add_object (&dock->model, x, y, 12, NULL); + model_add_spring (&dock->model, dock->model.anchors[0].object, object, 0); + dock->object = object; + model_for_each_object (&dock->model, add_spacer, dock); + dock->launchers = g_list_prepend (dock->launchers, launcher); + + launcher->object = object; + launcher->dock = dock; +} + +static void kiba_dock_init_model (Model *model, int num_items, int width, int height, int spacing) { - const int num_objects = num_items + 1; - const int num_spacers = (num_objects - 1) * (num_objects - 2) / 2; - const int num_springs = num_objects - 1; - const int spread = spacing + 20; - int i, j, left_edge; - Object *object; - Spring *spring; - Spacer *spacer; - - memset (model, 0, sizeof *model); - model->objects = g_new (Object, num_objects); - model->num_objects = num_objects; - model->springs = g_new (Spring, num_springs); - model->num_springs = num_springs; - model->spacers = g_new (Spacer, num_spacers); - model->num_spacers = num_spacers; + int left_edge; + + model_init (model); model->anchors = g_new (Anchor, 1); model->num_anchors = 1; - model->k = 0.1; model->elasticity = 0.9; model->friction = 150; @@ -430,24 +459,10 @@ kiba_dock_init_model (Model *model, int num_items, model->anchors[0].x = width / 2; model->anchors[0].y = height - 50; - model->anchors[0].object = &model->objects[0]; - - object_init (&model->objects[0], - model->anchors[0].x, model->anchors[0].y, 0); - - object = &model->objects[1]; - spring = model->springs; - spacer = model->spacers; - left_edge = (width - (num_items - 1) * spread) / 2; - - for (i = 1; i < num_objects; i++, object++) { - object_init (&model->objects[i], - left_edge + (i - 1) * spread, height - 100, 12); - spring_init (spring++, &model->objects[0], object, 0); - for (j = 1; j < num_objects - i; j++) { - spacer_init (spacer++, object, object + j, spacing); - } - } + /* Set object data to something non-NULL so we can recognize the anchor. */ + model->anchors[0].object = model_add_object (model, + width / 2, height - 50, 0, + model); } static gboolean @@ -651,15 +666,12 @@ load_icon (KibaLauncher *launcher, GError **error) } static void -kiba_launcher_create_window (KibaLauncher *launcher, GError **error) +kiba_launcher_create_window (KibaLauncher *launcher) { GdkWindowAttr attributes; gint attributes_mask; GdkScreen *screen = gdk_screen_get_default (); - if (!load_icon (launcher, error)) - return; - attributes.wclass = GDK_INPUT_OUTPUT; attributes.visual = gdk_screen_get_rgba_visual (screen); attributes.colormap = gdk_screen_get_rgba_colormap (screen); @@ -716,10 +728,7 @@ kiba_launcher_new (KibaDock *dock, Object *object, const char *gconf_path) return NULL; } - launcher->object = object; - launcher->dock = dock; - - kiba_launcher_create_window (launcher, &error); + load_icon (launcher, &error); if (error != NULL) { printf ("error creating launcher window: %s\n", error->message); g_error_free (error); |