#include #include #include #include #include #include #include #include "tmalloc.h" #include "xgalaxy.h" #include "trackball.h" typedef struct { Vector v; Vector V; GdkColor color; char name[2]; } Axis3D; static Axis3D axises[]={ { { 1.0, 0.0, 0.0 }, { 0.0, 0.0, 0.0 }, { 0, 8480, 57570, 22360 }, "X" }, { { 0.0, 1.0, 0.0 }, { 0.0, 0.0, 0.0 }, { 0, 8480, 47300, 57570 }, "Y" }, { { 0.0, 0.0, 1.0 }, { 0.0, 0.0, 0.0 }, { 0, 57570, 8480, 8480 }, "Z" } }; static int cmpAxis3D(const void *a, const void *b) { return ( ((Axis3D*)a)->V.z > ((Axis3D*)b)->V.z ) ? 1 : -1; } void drawAxis() { double minsize = fmin( XGalaxy.drawing_area->allocation.width, XGalaxy.drawing_area->allocation.height ); double Length = 0.4*minsize; GdkGC *gc = gdk_gc_new(XGalaxy.drawing_area->window); PangoLayout *pl = gtk_widget_create_pango_layout(XGalaxy.drawing_area, NULL); int i; for(i=0;i<3;i++) { rotate( &(axises[i].V), &(axises[i].v), &(XGalaxy.angle) ); vector_mul( &(axises[i].V), &(axises[i].V), Length ); } qsort(axises, 3, sizeof(Axis3D), cmpAxis3D); for(i=0;i<3;i++) { antialiasedLine( gc, XGalaxy.drawing_area->allocation.width/2, XGalaxy.drawing_area->allocation.height/2, XGalaxy.drawing_area->allocation.width/2 + axises[i].V.x, XGalaxy.drawing_area->allocation.height/2 - axises[i].V.y, &(axises[i].color) ); gdk_gc_set_rgb_fg_color(gc, &(axises[i].color)); pango_layout_set_text(pl, axises[i].name, -1); gdk_draw_layout( XGalaxy.pixmap, gc, XGalaxy.drawing_area->allocation.width/2 + axises[i].V.x, XGalaxy.drawing_area->allocation.height/2 - axises[i].V.y, pl ); } g_object_unref(G_OBJECT(pl)); g_object_unref(G_OBJECT(gc)); } void fitGalaxy() { double max=-1.0; int i; for(i=0;i max ) max = fabs(XGalaxy.entry[i].a.x); if ( fabs(XGalaxy.entry[i].a.y) > max ) max = fabs(XGalaxy.entry[i].a.y); if ( fabs(XGalaxy.entry[i].a.z) > max ) max = fabs(XGalaxy.entry[i].a.z); } XGalaxy.Scale = 1.0/(3.0*max); } static int cmpStar(const void *a, const void *b) { return ( ((Star*)a)->a.z > ((Star*)b)->a.z ) ? 1 : -1; } #define MIN_BRIGHT (0.4) void drawStars() { int i; double minsize = fmin( XGalaxy.drawing_area->allocation.width, XGalaxy.drawing_area->allocation.height ); double r, brightness; GdkGC *gc = gdk_gc_new(XGalaxy.drawing_area->window); if ( !XGalaxy.trace ) { gdk_draw_rectangle (XGalaxy.pixmap, XGalaxy.drawing_area->style->white_gc, TRUE, 0, 0, XGalaxy.drawing_area->allocation.width, XGalaxy.drawing_area->allocation.height ); if ( XGalaxy.drawaxis) drawAxis(); } if ( XGalaxy.runing ) { pthread_mutex_lock(&(XGalaxy.mutex)); memcpy( XGalaxy.tmpentry, XGalaxy.galaxy.stars, sizeof(Star)*XGalaxy.galaxy.nstars ); pthread_mutex_unlock(&(XGalaxy.mutex)); for(i=0;i 1.0 ) brightness = 1.0; DrawDisk( gc, ((double)XGalaxy.drawing_area->allocation.width)/2.0 + (minsize*XGalaxy.Scale*XGalaxy.tmpentry[i].a.x), ((double)XGalaxy.drawing_area->allocation.height)/2.0 - (minsize*XGalaxy.Scale*XGalaxy.tmpentry[i].a.y), r, 1.0, brightness ); } } g_object_unref(G_OBJECT(gc)); } void drawGalaxy() { GdkRectangle update_rect; if (!XGalaxy.pixmap) return; update_rect.x=0; update_rect.y=0; update_rect.width = XGalaxy.drawing_area->allocation.width; update_rect.height = XGalaxy.drawing_area->allocation.height; gdk_window_invalidate_rect (XGalaxy.drawing_area->window, &update_rect, FALSE); } void angle_changed(GtkRange *range, gpointer user_data) { double angle = gtk_range_get_value(range)*M_PI/180.0; Quaternion old, newquaternion; if (XGalaxy.locksignal) return; if (XGalaxy.trace) { XGalaxy.locksignal=1; switch((int)user_data) { case 'X': gtk_range_set_value(range, XGalaxy.Xangle*180.0/M_PI); break; case 'Y': gtk_range_set_value(range, XGalaxy.Yangle*180.0/M_PI); break; case 'Z': gtk_range_set_value(range, XGalaxy.Zangle*180.0/M_PI); break; default: break; } XGalaxy.locksignal=0; return; } memcpy(&old, &(XGalaxy.angle), sizeof(old)); memset(&newquaternion, 0 , sizeof(newquaternion)); switch( (int)user_data ) { case 'X': newquaternion.d.x = sin( (angle-XGalaxy.Xangle)/2.0 ); newquaternion.w = cos( (angle-XGalaxy.Xangle)/2.0 ); XGalaxy.Xangle=angle; break; case 'Y': newquaternion.d.y = sin( (angle-XGalaxy.Yangle)/2.0 ); newquaternion.w = cos( (angle-XGalaxy.Yangle)/2.0 ); XGalaxy.Yangle=angle; break; case 'Z': newquaternion.d.z = sin( (angle-XGalaxy.Zangle)/2.0 ); newquaternion.w = cos( (angle-XGalaxy.Zangle)/2.0 ); XGalaxy.Zangle=angle; break; default: g_print("Unknown axis: %c\n", (char)(int)user_data); } //quater_vmul( &(XGalaxy.angle), &old, &newquaternion ); quater_vmul( &(XGalaxy.angle), &newquaternion, &old ); drawGalaxy(); } void clearDraw() { if ( !XGalaxy.pixmap ) return; gdk_draw_rectangle (XGalaxy.pixmap, XGalaxy.drawing_area->style->white_gc, TRUE, 0, 0, XGalaxy.drawing_area->allocation.width, XGalaxy.drawing_area->allocation.height); if ( XGalaxy.drawaxis ) drawAxis(); } gint expose_event( GtkWidget *widget, GdkEventExpose *event ) { /* draw only last expose */ if ( event->count > 0) return TRUE; drawStars(); gdk_draw_pixmap(widget->window, widget->style->fg_gc[GTK_WIDGET_STATE (widget)], XGalaxy.pixmap, event->area.x, event->area.y, event->area.x, event->area.y, event->area.width, event->area.height); return FALSE; } gint configure_event( GtkWidget *widget, GdkEventConfigure *event ) { if (XGalaxy.pixmap) g_object_unref(XGalaxy.pixmap); XGalaxy.pixmap = gdk_pixmap_new(widget->window, widget->allocation.width, widget->allocation.height, -1); clearDraw(); return TRUE; } gboolean mouse_motion_notify(GtkWidget *widget, GdkEventMotion *event) { int x = 0; int y = 0; GdkModifierType state = 0; if (XGalaxy.locksignal || XGalaxy.trace ) return TRUE; if (event->is_hint) gdk_window_get_pointer(event->window, &x, &y, &state); else { x = event->x; y = event->y; state = event->state; } if (state & GDK_BUTTON1_MASK) { double width, height; Quaternion old; Vector angles; width = widget->allocation.width; height = widget->allocation.height; trackball( &(XGalaxy.motion), (2.0*XGalaxy.beginx - width) / width, ( height - 2.0*XGalaxy.beginy) / height, ( 2.0*x - width) / width, ( height - 2.0*y) / height ); memcpy(&old, &(XGalaxy.angle), sizeof(old)); //quater_vmul( &(XGalaxy.angle), &old, &(XGalaxy.motion) ); quater_vmul( &(XGalaxy.angle), &(XGalaxy.motion), &old ); XGalaxy.locksignal=1; quater_to_angles( &(XGalaxy.angle), &angles); XGalaxy.Xangle = angles.x; gtk_range_set_value(GTK_RANGE(XGalaxy.XSlider), angles.x*180.0/M_PI); XGalaxy.Yangle = angles.y; gtk_range_set_value(GTK_RANGE(XGalaxy.YSlider), angles.y*180.0/M_PI); XGalaxy.Zangle = angles.z; gtk_range_set_value(GTK_RANGE(XGalaxy.ZSlider), angles.z*180.0/M_PI); XGalaxy.locksignal=0; XGalaxy.beginx = x; XGalaxy.beginy = y; drawGalaxy(); } return TRUE; }