/* pdnmesh - a 2D finite element solver * Copyright (C) 2001-2005 Sarod Yatawatta This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA $Id: surfmesh.c,v 1.4 2005/03/11 21:58:11 sarod Exp $ */ /**********************************************************************/ /* mesh grid routines */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #ifndef WIN32 #include #include #include #include /* for gdk_gl_glPoly* */ #endif/*WIN32*/ #ifdef WIN32 #include #endif/*!WIN32*/ #include #include #include "types.h" /* a mesh grid will be drawn on a new window */ #ifndef WIN32 #define MAXGRID 5 static int beginX, beginY; static float sphi=90.0; static float stheta=45.0; static float sdepth=5.0/4.0 * (MAXGRID/2); static float zNear=(MAXGRID/2)/10.0; static float zFar=(MAXGRID/2)*3.0; static float aspect=4.1/4.0; /* to keep track of mesh grid window */ GtkWidget *global_surf_mesh_window=NULL; static gboolean motion_notify_event_meshgrid(GtkWidget *widget, GdkEventMotion *event, gpointer data) { gboolean redraw=FALSE; if ( event->state & GDK_BUTTON1_MASK) { sphi+=(float)(event->x-beginX)/4.0; stheta+=(float)(beginY-event->y)/4.0; redraw=TRUE; } if (event->state & GDK_BUTTON2_MASK ) { sdepth-=((event->y-beginY)/(widget->allocation.height))*(MAXGRID/2); redraw=TRUE; } beginX=event->x; beginY=event->y; if (redraw) gtk_widget_queue_draw(widget); return(TRUE); } static gboolean button_press_event_meshgrid(GtkWidget *widget, GdkEventButton *event, gpointer data) { if (event->button==1) { beginX=event->x; beginY=event->y; return(TRUE); } if (event->button==2) { beginX=event->x; beginY=event->y; return(FALSE); } return(FALSE); } static gboolean button_press_event_popup_menu_meshgrid(GtkWidget *widget, GdkEventButton *event, gpointer data) { if (event->button==3){ gtk_menu_popup(GTK_MENU(widget), NULL,NULL,NULL,NULL, event->button,event->time); return(TRUE); } return(FALSE); } /* calculate unit normal vector to given triangle */ /*static void triangle_normal(double x1, double y1, double z1, double x2, double y2, double z2, double x3, double y3, double z3) { double v1,v2,v3,u1,u2,u3,n1,n2,n3; extern int errno; u1=x2-x1;u2=y2-y1;u3=z2-z1; v1=x3-x1;v2=y3-y1;v3=z3-z1; n1=v2*u3-u2*v3;n2=u1*v3-v1*u3;n3=v1*u2-u1*v2; errno=0; v1=sqrt(ABS(n1*n1+n2*n2+n3*n3)); #ifdef DEBUG if ( !errno ) printf("error\n"); printf("normal> %lf %lf %lf :%lf\n",n1,n2,n3,v1); #endif if(v1 != 0.0) { n1/=v1;n2/=v1;n3/=v1; glNormal3f(-(GLfloat)n1,-(GLfloat)n2,-(GLfloat)n3); #ifdef DEBUG printf("normal>> %lf %lf %lf\n",n1,n2,n3); #endif } } */ static void draw_mesh_grid(void) { triangle *rec; int i; GLfloat r,g,b; double elevation; if ( ABS(g_maxpot)status==LIVE) { glBegin(GL_TRIANGLES); i=(int)((Mzz(rec->p0,current_plotting_contour,M)-g_minpot)/(g_maxpot-g_minpot)*contour_levels); get_colour(&r,&g,&b,i, contour_levels); /* set the colour */ glColor3f((GLfloat)r, (GLfloat)g, (GLfloat)b); glVertex3f( (GLfloat)Mx(rec->p0,M), (GLfloat) My(rec->p0,M),(GLfloat)Mzz(rec->p0,current_plotting_contour,M)/elevation); i=(int)((Mzz(rec->p1,current_plotting_contour,M)-g_minpot)/(g_maxpot-g_minpot)*contour_levels); get_colour(&r,&g,&b,i, contour_levels); /* set the colour */ glColor3f((GLfloat)r, (GLfloat)g, (GLfloat)b); glVertex3f( (GLfloat)Mx(rec->p1,M), (GLfloat) My(rec->p1,M),(GLfloat)Mzz(rec->p1,current_plotting_contour,M)/elevation); i=(int)((Mzz(rec->p2,current_plotting_contour,M)-g_minpot)/(g_maxpot-g_minpot)*contour_levels); get_colour(&r,&g,&b,i, contour_levels); /* set the colour */ glColor3f((GLfloat)r, (GLfloat)g, (GLfloat)b); glVertex3f( (GLfloat)Mx(rec->p2,M), (GLfloat) My(rec->p2,M),(GLfloat)Mzz(rec->p2,current_plotting_contour,M)/elevation); /* normal vector */ /* triangle_normal(Mx(rec->p0),My(rec->p0),Mzz(rec->p0,current_plotting_contour)/elevation,Mx(rec->p1),My(rec->p1),Mzz(rec->p1,current_plotting_contour)/elevation,Mx(rec->p2),My(rec->p2),Mzz(rec->p2,current_plotting_contour)/elevation); */ glEnd(); } /*rt.print_record(rec); */ rec=DAG_traverse_prune_list(&dt); } plot_contour_all_in_3d(M); glLineWidth(2.0); /* plot boundaries */ glBegin(GL_LINES); for (i=0; i 1 */ static void switch_to_next_eigenmode(GtkWidget *widget, gpointer data) { GtkWidget *w=GTK_WIDGET(data); /* main window drawing area */ /* switch to next eigenmode */ if (solve_equation== POISSON || solve_equation == POISSON_SPARSE ) { current_plotting_contour=0; } else if (solve_equation == HELMHOLTZ ) { current_plotting_contour++; if ( current_plotting_contour >=degree_of_freedom ) current_plotting_contour=0; } else if ((solve_equation == HELMHOLTZ_INHOMO) || (solve_equation == HELMHOLTZ_FREQ) || (solve_equation == HELMHOLTZ_BETA)) { current_plotting_contour++; if ( current_plotting_contour >=3*degree_of_freedom ) current_plotting_contour=0; } #ifdef DEBUG g_print("%s: parent %s\" %d th eigenmode\"\n",gtk_widget_get_name(widget), gtk_widget_get_name(w), current_plotting_contour); #endif gdk_window_invalidate_rect(widget->window, &widget->allocation ,FALSE); /* send redraw to main drawing area as well */ gdk_window_invalidate_rect(w->window, &w->allocation,TRUE); } static GtkWidget * create_popup_menu_meshgrid(GtkWidget *drawing_area,GtkWidget *window, GtkWidget *main_drawing_area) { GtkWidget *menu; GtkWidget *menu_item; menu=gtk_menu_new(); /* only for Helmholtz equation */ menu_item=gtk_menu_item_new_with_label("Next Eigenmode"); gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item); g_signal_connect(G_OBJECT(menu_item),"activate", G_CALLBACK(switch_to_next_eigenmode),(gpointer)main_drawing_area); gtk_widget_show(menu_item); /* Close Window */ menu_item=gtk_menu_item_new_with_label("Close Window"); gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item); g_signal_connect(G_OBJECT(menu_item), "activate", G_CALLBACK(close_window_meshgrid), window); gtk_widget_show(menu_item); return(menu); } static void realize_meshgrid (GtkWidget *widget, gpointer data) { /* material properties */ GLfloat mat_specular[]={0.4,0.4,0.4,1.0}; GLfloat mat_shininess[]={40.0}; GLfloat lightPosition[4]={0.0,0.0,1.0,1.0}; GdkGLContext *glcontext=gtk_widget_get_gl_context(widget); GdkGLDrawable *gldrawable=gtk_widget_get_gl_drawable(widget); GdkGLProc proc=NULL; if (!gdk_gl_drawable_gl_begin(gldrawable,glcontext)) return; /* glPolygonOffsetEXT */ proc=gdk_gl_get_glPolygonOffsetEXT(); if (proc==NULL) { proc=gdk_gl_get_proc_address("glPolygonOffset"); if (proc==NULL) { g_print("Sorry, glPolygonOffset() is not supported by this renderer.\n"); exit(1); } } glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LEQUAL); glClearColor(0.0,0.0,0.0,0.0); gdk_gl_glPolygonOffsetEXT(proc, 1.0, 1.0); glHint(GL_LINE_SMOOTH_HINT,GL_NICEST); glHint(GL_POLYGON_SMOOTH_HINT,GL_NICEST); glHint(GL_PERSPECTIVE_CORRECTION_HINT,GL_NICEST); glShadeModel(GL_SMOOTH); glMaterialfv(GL_FRONT,GL_SPECULAR,mat_specular); glMaterialfv(GL_FRONT,GL_SHININESS,mat_shininess); glLightfv(GL_LIGHT0,GL_POSITION,lightPosition); glColorMaterial(GL_FRONT,GL_DIFFUSE); glEnable(GL_CULL_FACE); glEnable(GL_LIGHT0); glEnable(GL_COLOR_MATERIAL); glEnable(GL_LIGHTING); /* intialize mesh */ /* intial mesh ? */ gdk_gl_drawable_gl_end(gldrawable); return; } static gboolean configure_event_meshgrid(GtkWidget *widget, GdkEventConfigure *event, gpointer data) { GdkGLContext *glcontext=gtk_widget_get_gl_context(widget); GdkGLDrawable *gldrawable=gtk_widget_get_gl_drawable(widget); GLfloat w=widget->allocation.width; GLfloat h=widget->allocation.height; if(!gdk_gl_drawable_gl_begin(gldrawable,glcontext)) return(FALSE); aspect=(float)w/(float)h; glViewport(0,0,w,h); gdk_gl_drawable_gl_end(gldrawable); return(TRUE); } static gboolean expose_event_meshgrid(GtkWidget *widget, GdkEventExpose *event, gpointer data) { GdkGLContext *glcontext=gtk_widget_get_gl_context(widget); GdkGLDrawable *gldrawable=gtk_widget_get_gl_drawable(widget); if (!gdk_gl_drawable_gl_begin(gldrawable,glcontext)) return(FALSE); glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(64.0,aspect,zNear,zFar); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslatef(0.0,0.0,-sdepth); glRotatef(-stheta,1.0,0.0,0.0); glRotatef(sphi,0.0,0.0,1.0); draw_mesh_grid(); if ( gdk_gl_drawable_is_double_buffered(gldrawable)) gdk_gl_drawable_swap_buffers(gldrawable); else glFlush(); glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); gdk_gl_drawable_gl_end(gldrawable); return(TRUE); } static GtkWidget * create_mesh_grid_window(GdkGLConfig *glconfig, GtkWidget *main_area) { GtkWidget *window; GtkWidget *vbox; GtkWidget *drawing_area; GtkWidget *menu; window=gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_title(GTK_WINDOW(window),"Surf Mesh"); gtk_container_set_reallocate_redraws(GTK_CONTAINER(window),FALSE); /* default signal handler */ g_signal_connect_swapped(GTK_OBJECT(window),"delete_event", G_CALLBACK(close_window),NULL); vbox=gtk_vbox_new(FALSE,0); gtk_container_add(GTK_CONTAINER(window),vbox); gtk_widget_show(vbox); drawing_area=gtk_drawing_area_new(); gtk_widget_set_size_request(drawing_area,DEFAULT_WIDTH,DEFAULT_HEIGHT); gtk_widget_set_gl_capability(drawing_area, glconfig, NULL, TRUE, GDK_GL_RGBA_TYPE); gtk_widget_add_events(drawing_area, GDK_BUTTON1_MOTION_MASK | GDK_BUTTON2_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_VISIBILITY_NOTIFY_MASK); g_signal_connect_after(G_OBJECT(drawing_area), "realize", G_CALLBACK(realize_meshgrid),NULL); g_signal_connect(G_OBJECT(drawing_area), "configure_event", G_CALLBACK(configure_event_meshgrid), NULL); g_signal_connect(G_OBJECT(drawing_area), "expose_event", G_CALLBACK(expose_event_meshgrid), NULL); g_signal_connect(G_OBJECT(drawing_area),"motion_notify_event", G_CALLBACK(motion_notify_event_meshgrid), NULL); g_signal_connect(G_OBJECT(drawing_area),"button_press_event", G_CALLBACK(button_press_event_meshgrid), NULL); /* more events */ gtk_box_pack_start(GTK_BOX(vbox), drawing_area, TRUE,TRUE,0); gtk_widget_show(drawing_area); /* menu */ menu=create_popup_menu_meshgrid(drawing_area,window,main_area); g_signal_connect_swapped(G_OBJECT(drawing_area), "button_press_event", G_CALLBACK(button_press_event_popup_menu_meshgrid),menu); return(window); } static GdkGLConfig * configure_mesh_grid_window(void) { GdkGLConfig *glconfig; /* try double buffered */ glconfig=gdk_gl_config_new_by_mode(GDK_GL_MODE_RGB| GDK_GL_MODE_DEPTH | GDK_GL_MODE_DOUBLE); if (glconfig== NULL) { g_print("\n*** Cannot find the double buffered visual.\n"); g_print("\n*** Trying single-buffered visual.\n"); /* single bufferd visual */ glconfig=gdk_gl_config_new_by_mode(GDK_GL_MODE_RGB| GDK_GL_MODE_DEPTH); if ( glconfig==NULL) { g_print("*** No appropriate OpenGL capable visual found.\n"); exit(1); } } return(glconfig); } /* display 3d view */ void display_mesh_grid(GtkWidget *widget, gpointer data) { /* widget we get as parameter is the drawing_area */ GtkWidget *window; GdkGLConfig *glconfig; if( global_surf_mesh_window==NULL ) { glconfig=configure_mesh_grid_window(); window=create_mesh_grid_window(glconfig, GTK_WIDGET(data)); /* copy window address back to gloabal variable */ /* or set flag to 1 */ global_surf_mesh_window=window; gtk_widget_show(window); } } #endif /* WIN32 */