upgrading copyright year from 2015 to 2016
[hkl.git] / gui / hkl-gui-3d.c
blob64e8c04b717e7f5e5f0f6a62f777f748fff9d4ca
1 /* This file is part of the hkl library.
3 * The hkl library is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
8 * The hkl library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with the hkl library. If not, see <http://www.gnu.org/licenses/>.
16 * Copyright (C) 2003-2016 Synchrotron SOLEIL
17 * L'Orme des Merisiers Saint-Aubin
18 * BP 48 91192 GIF-sur-YVETTE CEDEX
20 * Authors: Picca Frédéric-Emmanuel <picca@synchrotron-soleil.fr>
21 * Oussama Sboui <oussama.sboui@synchrotron-soleil.fr>
23 #include <gtk/gtkgl.h>
24 #include <GL/gl.h>
25 #include <g3d/quat.h>
27 #include "hkl3d.h"
28 #include "hkl/ccan/compiler/compiler.h"
29 #include "hkl-gui.h"
30 #include "hkl-gui-macros.h"
31 #include "hkl-gui-3d.h"
32 #include "hkl-gui-3d-gl.h"
35 * updates glarea widget (redraw)
37 static void glarea_update(GtkWidget *glarea)
39 gtk_widget_queue_draw_area(glarea,
40 0, 0,
41 glarea->allocation.width,
42 glarea->allocation.height);
46 typedef enum {
47 HKL_GUI_3D_COL_NAME = 0,
48 HKL_GUI_3D_COL_HIDE,
49 HKL_GUI_3D_COL_MODEL,
50 HKL_GUI_3D_COL_OBJECT,
51 HKL_GUI_3D_COL_NUM_COLS
52 } HklGui3DCol;
54 enum {
55 PROP_0,
57 PROP_FILENAME,
58 PROP_GEOMETRY,
60 N_PROPERTIES
63 /* Keep a pointer to the properties definition */
64 static GParamSpec *obj_properties[N_PROPERTIES] = { NULL, };
66 enum {
67 CHANGED,
69 N_SIGNALS
72 static NEEDED guint signals[N_SIGNALS] = { 0 };
75 struct _HklGui3D {
76 GObject parent_instance;
78 /*< private >*/
79 HklGui3DPrivate * priv;
82 struct _HklGui3DClass {
83 GObjectClass parent_class;
87 struct _HklGui3DPrivate {
88 /* Properties */
89 char *filename;
90 HklGeometry *geometry;
91 /* Properties */
93 GtkBuilder *builder;
95 GtkFrame *frame1;
96 GtkVBox *vbox1;
97 GtkTreeView *treeview1;
98 GtkToolButton *toolbutton1;
99 GtkToolButton *toolbutton2;
100 GtkToolButton *toolbutton3;
101 GtkFileChooserDialog *filechooserdialog1;
102 GtkButton *button1;
103 GtkButton *button2;
104 GtkTreeStore *treestore1;
105 GtkDrawingArea *drawingarea1;
107 Hkl3D *hkl3d;
109 /* opengl connected to the drawingarea1 */
110 G3DGLRenderOptions renderoptions;
111 struct {
112 gint32 beginx;
113 gint32 beginy;
114 } mouse;
115 gboolean aabb;
118 G_DEFINE_TYPE (HklGui3D, hkl_gui_3d, G_TYPE_OBJECT);
120 #define HKL_GUI_3D_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), HKL_GUI_TYPE_3D, HklGui3DPrivate))
123 static void hkl_gui_3d_update_hkl3d_objects_TreeStore(HklGui3D *self)
125 HklGui3DPrivate *priv = HKL_GUI_3D_GET_PRIVATE(self);
126 size_t i;
127 size_t j;
129 gtk_tree_store_clear(priv->treestore1);
131 for(i=0; i<priv->hkl3d->config->len; ++i){
132 GtkTreeIter iter = {0};
134 gtk_tree_store_append(priv->treestore1, &iter, NULL);
135 gtk_tree_store_set(priv->treestore1, &iter,
136 HKL_GUI_3D_COL_NAME, priv->hkl3d->config->models[i]->filename,
137 HKL_GUI_3D_COL_MODEL, priv->hkl3d->config->models[i],
138 HKL_GUI_3D_COL_OBJECT, NULL,
139 -1);
141 for(j=0; j<priv->hkl3d->config->models[i]->len; ++j){
142 GtkTreeIter citer = {0};
144 gtk_tree_store_append(priv->treestore1, &citer, &iter);
145 gtk_tree_store_set(priv->treestore1, &citer,
146 HKL_GUI_3D_COL_NAME, priv->hkl3d->config->models[i]->objects[j]->axis_name,
147 HKL_GUI_3D_COL_HIDE, priv->hkl3d->config->models[i]->objects[j]->hide,
148 HKL_GUI_3D_COL_MODEL, priv->hkl3d->config->models[i],
149 HKL_GUI_3D_COL_OBJECT, priv->hkl3d->config->models[i]->objects[j],
150 -1);
155 /* properties */
157 static const char *
158 hkl_gui_3d_get_filename(HklGui3D *self)
160 HklGui3DPrivate *priv = HKL_GUI_3D_GET_PRIVATE(self);
162 return priv->filename;
165 static HklGeometry *
166 hkl_gui_3d_get_geometry(HklGui3D *self)
168 HklGui3DPrivate *priv = HKL_GUI_3D_GET_PRIVATE(self);
170 return priv->geometry;
173 void _filename_and_geometry(HklGui3D *self)
175 HklGui3DPrivate *priv = HKL_GUI_3D_GET_PRIVATE(self);
176 if(priv->filename && priv->geometry){
177 if (priv->hkl3d)
178 hkl3d_free(priv->hkl3d);
179 priv->hkl3d = hkl3d_new(priv->filename, priv->geometry);
180 if(priv->hkl3d){
181 /* priv->scene = hkl_gui_3d_scene_new(priv->hkl3d, FALSE, FALSE, FALSE, FALSE); */
183 hkl_gui_3d_update_hkl3d_objects_TreeStore(self);
184 /* gtk_box_pack_start(GTK_BOX(priv->vbox1), */
185 /* GTK_WIDGET(priv->scene), */
186 /* TRUE, TRUE, 0); */
187 /* gtk_widget_show_all(GTK_WIDGET(priv->vbox1)); */
192 static void
193 hkl_gui_3d_set_filename(HklGui3D *self, const char *filename)
195 HklGui3DPrivate *priv = HKL_GUI_3D_GET_PRIVATE(self);
197 if(priv->filename)
198 g_free(priv->filename);
199 priv->filename = g_strdup(filename);
201 _filename_and_geometry(self);
204 static void
205 hkl_gui_3d_set_geometry(HklGui3D *self, HklGeometry *geometry)
207 HklGui3DPrivate *priv = HKL_GUI_3D_GET_PRIVATE(self);
209 priv->geometry = geometry;
210 _filename_and_geometry(self);
213 static void
214 set_property (GObject *object, guint prop_id,
215 const GValue *value, GParamSpec *pspec)
217 HklGui3D *self = HKL_GUI_3D (object);
219 switch (prop_id) {
220 case PROP_FILENAME:
221 hkl_gui_3d_set_filename(self, g_value_get_string (value));
222 break;
223 case PROP_GEOMETRY:
224 hkl_gui_3d_set_geometry(self, g_value_get_pointer (value));
225 break;
226 default:
227 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
228 break;
232 static void
233 get_property (GObject *object, guint prop_id,
234 GValue *value, GParamSpec *pspec)
236 HklGui3D *self = HKL_GUI_3D (object);
238 switch (prop_id)
240 case PROP_FILENAME:
241 g_value_set_string (value, hkl_gui_3d_get_filename (self));
242 break;
243 case PROP_GEOMETRY:
244 g_value_set_pointer (value, hkl_gui_3d_get_geometry (self));
245 break;
246 default:
247 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
248 break;
252 static void
253 finalize (GObject* object)
255 HklGui3DPrivate *priv = HKL_GUI_3D_GET_PRIVATE(object);
258 g_free(priv->filename);
260 g_object_unref(priv->builder);
262 hkl3d_free(priv->hkl3d);
264 G_OBJECT_CLASS (hkl_gui_3d_parent_class)->finalize (object);
267 HklGui3D*
268 hkl_gui_3d_new (const char *filename, HklGeometry *geometry)
270 return g_object_new (HKL_GUI_TYPE_3D,
271 "filename", filename,
272 "geometry", geometry,
273 NULL);
276 GtkFrame *hkl_gui_3d_frame_get(HklGui3D *self)
278 HklGui3DPrivate *priv = HKL_GUI_3D_GET_PRIVATE(self);
280 return priv->frame1;
283 void hkl_gui_3d_is_colliding(HklGui3D *self)
285 HklGui3DPrivate *priv = HKL_GUI_3D_GET_PRIVATE(self);
287 if(priv->hkl3d)
288 hkl3d_is_colliding(priv->hkl3d);
291 void hkl_gui_3d_invalidate(HklGui3D *self)
293 HklGui3DPrivate *priv = HKL_GUI_3D_GET_PRIVATE(self);
295 priv->renderoptions.updated = TRUE;
296 glarea_update(GTK_WIDGET(priv->drawingarea1));
299 /************/
300 /* Callback */
301 /************/
303 void hkl_gui_3d_cellrenderertext2_toggled_cb(GtkCellRendererToggle* renderer,
304 const gchar* path, gpointer user_data)
306 HklGui3D *self = HKL_GUI_3D(user_data);
307 HklGui3DPrivate *priv = HKL_GUI_3D_GET_PRIVATE(user_data);
308 guint hide;
309 Hkl3DObject *object;
310 GtkTreeIter iter = {0};
313 gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL(priv->treestore1),
314 &iter, path);
315 gtk_tree_model_get (GTK_TREE_MODEL(priv->treestore1),
316 &iter,
317 HKL_GUI_3D_COL_OBJECT, &object,
318 -1);
320 hide = !gtk_cell_renderer_toggle_get_active(renderer);
322 if(object){
323 hkl3d_hide_object(priv->hkl3d, object, hide);
324 gtk_tree_store_set (priv->treestore1,
325 &iter,
326 HKL_GUI_3D_COL_HIDE, hide,
327 -1);
328 hkl_gui_3d_is_colliding(self);
329 hkl_gui_3d_invalidate(self);
330 }else{
331 Hkl3DModel *model;
333 gtk_tree_model_get (GTK_TREE_MODEL(priv->treestore1),
334 &iter,
335 HKL_GUI_3D_COL_MODEL, &model,
336 -1);
337 if(model){
338 GtkTreeIter children = {0};
339 gboolean valid;
340 size_t i = 0;
342 gtk_tree_store_set (priv->treestore1,
343 &iter,
344 HKL_GUI_3D_COL_HIDE, hide,
345 -1);
347 /* set all the children rows */
348 valid = gtk_tree_model_iter_children(GTK_TREE_MODEL(priv->treestore1),
349 &children, &iter);
350 while(valid){
351 hkl3d_hide_object(priv->hkl3d, model->objects[i++], hide);
352 gtk_tree_store_set (priv->treestore1,
353 &children,
354 HKL_GUI_3D_COL_HIDE, hide,
355 -1);
357 valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(priv->treestore1), &children);
359 hkl_gui_3d_is_colliding(self);
360 hkl_gui_3d_invalidate(self);
365 void hkl_gui_3d_treeview1_cursor_changed_cb(GtkTreeView *tree_view,
366 gpointer user_data)
368 int i;
369 int j;
370 HklGui3D *self = user_data;
371 HklGui3DPrivate *priv = HKL_GUI_3D_GET_PRIVATE(user_data);
372 GtkTreeIter iter = {0};
373 Hkl3DObject *object;
374 GtkTreePath *path;
375 GtkTreeViewColumn * column;
377 gtk_tree_view_get_cursor(priv->treeview1, &path, &column);
378 gtk_tree_model_get_iter(GTK_TREE_MODEL(priv->treestore1), &iter, path);
379 gtk_tree_path_free(path);
381 /* need to unselect of objects of all 3d models */
382 for(i=0; i<priv->hkl3d->config->len; ++i)
383 for(j=0; j<priv->hkl3d->config->models[i]->len; ++j)
384 priv->hkl3d->config->models[i]->objects[j]->selected = FALSE;
386 /* now select the right object */
387 gtk_tree_model_get (GTK_TREE_MODEL(priv->treestore1),
388 &iter,
389 HKL_GUI_3D_COL_OBJECT, &object,
390 -1);
391 if(object)
392 object->selected = TRUE;
394 hkl_gui_3d_invalidate(self);
397 void hkl_gui_3d_toolbutton1_clicked_cb(GtkToolButton *toolbutton,
398 gpointer user_data)
400 HklGui3DPrivate *priv = HKL_GUI_3D_GET_PRIVATE(user_data);
402 gtk_widget_show(GTK_WIDGET(priv->filechooserdialog1));
405 /* remove an object from the model */
406 void hkl_gui_3d_toolbutton2_clicked_cb(GtkToolButton *toolbutton,
407 gpointer user_data)
409 HklGui3D *self = user_data;
410 HklGui3DPrivate *priv = HKL_GUI_3D_GET_PRIVATE(user_data);
411 GtkTreeIter iter = {0};
412 GtkTreePath *path;
413 GtkTreeViewColumn * column;
414 Hkl3DObject *object;
416 gtk_tree_view_get_cursor(priv->treeview1, &path, &column);
417 gtk_tree_model_get_iter(GTK_TREE_MODEL(priv->treestore1), &iter, path);
418 gtk_tree_path_free(path);
420 gtk_tree_model_get (GTK_TREE_MODEL(priv->treestore1),
421 &iter,
422 HKL_GUI_3D_COL_OBJECT, &object,
423 -1);
424 if(object){
425 hkl3d_remove_object(priv->hkl3d, object);
426 hkl_gui_3d_update_hkl3d_objects_TreeStore(self);
427 hkl_gui_3d_invalidate(self);
431 static void
432 reset_3d(G3DGLRenderOptions *renderoptions)
434 /* renderoptions */
435 renderoptions->updated = TRUE;
436 renderoptions->initialized = FALSE;
437 renderoptions->zoom = 7;
438 renderoptions->bgcolor[0] = 0.9;
439 renderoptions->bgcolor[1] = 0.8;
440 renderoptions->bgcolor[2] = 0.6;
441 renderoptions->bgcolor[3] = 1.0;
442 renderoptions->glflags =
443 // G3D_FLAG_GL_ISOMETRIC |
444 G3D_FLAG_GL_SPECULAR |
445 G3D_FLAG_GL_SHININESS |
446 G3D_FLAG_GL_TEXTURES |
447 G3D_FLAG_GL_COLORS|
448 G3D_FLAG_GL_COORD_AXES;
450 g3d_quat_trackball(renderoptions->quat, 0.0, 0.0, 0.0, 0.0, 0.8);
452 /* rotate a little bit */
453 gfloat q1[4], q2[4];
454 gfloat a1[3] = { 0.0, 1.0, 0.0 }, a2[3] = {1.0, 0.0, 1.0};
456 g3d_quat_rotate(q1, a1, - 45.0 * G_PI / 180.0);
457 g3d_quat_rotate(q2, a2, - 45.0 * G_PI / 180.0);
458 g3d_quat_add(renderoptions->quat, q1, q2);
461 /* re-initialize the 3d view */
462 void hkl_gui_3d_toolbutton3_clicked_cb(GtkToolButton *toolbutton,
463 gpointer user_data)
465 HklGui3D *self = user_data;
466 HklGui3DPrivate *priv = HKL_GUI_3D_GET_PRIVATE(user_data);
468 reset_3d(&priv->renderoptions);
469 hkl_gui_3d_invalidate(self);
472 void hkl_gui_3d_toolbutton4_toggled_cb(GtkToggleToolButton *toggle_tool_button,
473 gpointer user_data)
475 HklGui3D *self = user_data;
476 HklGui3DPrivate *priv = HKL_GUI_3D_GET_PRIVATE(user_data);
478 priv->aabb = gtk_toggle_tool_button_get_active(toggle_tool_button);
479 hkl_gui_3d_invalidate(self);
482 void hkl_gui_3d_button1_clicked_cb(GtkButton *button,
483 gpointer user_data)
485 HklGui3D *self = user_data;
486 HklGui3DPrivate *priv = HKL_GUI_3D_GET_PRIVATE(user_data);
487 GSList *filenames;
488 GSList *filename;
490 filenames = gtk_file_chooser_get_files(GTK_FILE_CHOOSER(priv->filechooserdialog1));
491 filename = filenames;
492 while(filename){
493 GFile *file = filename->data;
494 GFile *directory = g_file_get_parent(file);
495 char *basename = g_file_get_basename(file);
496 char *path = g_file_get_path(directory);
498 hkl3d_add_model_from_file(priv->hkl3d, basename, path);
499 hkl3d_connect_all_axes(priv->hkl3d);
501 g_free(path);
502 g_free(basename);
503 g_object_unref(G_OBJECT(directory));
504 g_object_unref(G_OBJECT(file));
505 filename = g_slist_next(filename);
508 hkl_gui_3d_update_hkl3d_objects_TreeStore(self);
509 gtk_widget_hide(GTK_WIDGET(priv->filechooserdialog1));
510 g_slist_free(filenames);
513 void hkl_gui_3d_button2_clicked_cb(GtkButton *button,
514 gpointer user_data)
516 HklGui3DPrivate *priv = HKL_GUI_3D_GET_PRIVATE(user_data);
518 gtk_widget_hide(GTK_WIDGET(priv->filechooserdialog1));
521 /***************/
522 /* OpenGL part */
523 /***************/
525 enum DisplayList {
526 MODEL = 1,
527 BULLET,
528 COLLISION,
529 AABBBOX,
530 HIGHLIGHT
533 static void hkl_gui_3d_draw_g3dmodel(HklGui3D *self)
535 int i;
536 int j;
537 HklGui3DPrivate *priv = HKL_GUI_3D_GET_PRIVATE(self);
539 /* set the alpha canal to 0.5 if there is a collision */
540 for(i=0; i<priv->hkl3d->config->len; i++)
541 for(j=0; j<priv->hkl3d->config->models[i]->len; j++){
542 GSList *faces;
543 G3DFace *face;
544 double alpha;
546 if(priv->hkl3d->config->models[i]->objects[j]->is_colliding)
547 alpha = 0.5;
548 else
549 alpha = 1;
551 faces = priv->hkl3d->config->models[i]->objects[j]->g3d->faces;
552 while(faces){
553 face = (G3DFace *)(faces->data);
554 face->material->a = alpha;
555 faces = g_slist_next(faces);
559 /* draw the G3DObjects */
560 gl_draw(&priv->renderoptions, priv->hkl3d->model);
563 static void draw_g3dObject(G3DObject *object)
565 GSList *faces;
566 float *vertex;
568 faces = object->faces;
569 vertex = object->vertex_data;
571 glPushMatrix();
573 /* apply the transformation of the object */
574 if(object->transformation)
575 glMultMatrixf(object->transformation->matrix);
577 /* draw all faces with the current stencil */
578 while(faces){
579 G3DFace * face;
581 face = (G3DFace*)faces->data;
582 glBegin(GL_TRIANGLES);
583 glVertex3d(vertex[3*(face->vertex_indices[0])],
584 vertex[3*(face->vertex_indices[0])+1],
585 vertex[3*(face->vertex_indices[0])+2]);
586 glVertex3d(vertex[3*(face->vertex_indices[1])],
587 vertex[3*(face->vertex_indices[1])+1],
588 vertex[3*(face->vertex_indices[1])+2]);
589 glVertex3d(vertex[3*(face->vertex_indices[2])],
590 vertex[3*(face->vertex_indices[2])+1],
591 vertex[3*(face->vertex_indices[2])+2]);
592 glEnd();
593 faces = g_slist_next(faces);
596 glPopMatrix();
599 void hkl_gui_3d_draw_selected(HklGui3D *self)
601 int i;
602 int j;
603 HklGui3DPrivate *priv = HKL_GUI_3D_GET_PRIVATE(self);
605 /* glDisable(GL_LIGHTING); */
607 for(i=0; i<priv->hkl3d->config->len; i++)
608 for(j=0; j<priv->hkl3d->config->models[i]->len; j++){
609 if(priv->hkl3d->config->models[i]->objects[j]->selected
610 && !priv->hkl3d->config->models[i]->objects[j]->hide){
611 // Push the GL attribute bits so that we don't wreck any settings
612 glPushAttrib( GL_ALL_ATTRIB_BITS );
614 // Enable polygon offsets, and offset filled polygons forward by 2.5
615 glEnable( GL_POLYGON_OFFSET_FILL );
616 glPolygonOffset( -2.5, -2.5);
618 // Set the render mode to be line rendering with a thick line width
619 glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
620 glLineWidth( 3.f );
621 // Set the colour to be pink
622 glColor3f( 1.f, .0f, 1.f );
623 // Render the object
624 draw_g3dObject(priv->hkl3d->config->models[i]->objects[j]->g3d);
625 // Set the polygon mode to be filled triangles
626 glLineWidth( 1.f );
627 glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
628 // Set the colour to the background
629 glCullFace(GL_FRONT);
630 glColor3f( 0.0f, 0.0f, 0.0f );
631 // Render the object
632 draw_g3dObject(priv->hkl3d->config->models[i]->objects[j]->g3d);
634 // Pop the state changes off the attribute
635 // to set things back how they were
636 glPopAttrib();
639 /* glEnable(GL_LIGHTING); */
642 static void draw_sphere(float radius, int lats, int longs)
644 int i, j;
645 for(i=0;i<=lats;i++){
646 float lat0 = M_PI * (-0.5 + (float) (i - 1) / lats);
647 float z0 = radius * sin(lat0);
648 float zr0 = radius * cos(lat0);
650 float lat1 = M_PI * (-0.5 + (float) i / lats);
651 float z1 = radius * sin(lat1);
652 float zr1 = radius * cos(lat1);
654 glBegin(GL_QUAD_STRIP);
655 for(j=0;j<=longs;j++) {
656 float lng = 2 * M_PI * (float) (j - 1) / longs;
657 float x = cos(lng);
658 float y = sin(lng);
660 glNormal3f(x * zr1, y * zr1, z1);
661 glVertex3f(x * zr1, y * zr1, z1);
662 glNormal3f(x * zr0, y * zr0, z0);
663 glVertex3f(x * zr0, y * zr0, z0);
665 glEnd();
669 void hkl_gui_3d_draw_collisions(HklGui3D *self)
671 int i;
672 int numManifolds;
673 HklGui3DPrivate *priv = HKL_GUI_3D_GET_PRIVATE(self);
675 /* glDisable(GL_LIGHTING); */
676 ///one way to draw all the contact points is iterating over contact manifolds / points:
677 numManifolds = hkl3d_get_nb_manifolds(priv->hkl3d);
678 for (i=0; i<numManifolds; i++){
679 int numContacts;
680 int j;
682 // now draw the manifolds / points
683 numContacts = hkl3d_get_nb_contacts(priv->hkl3d, i);
684 for (j=0; j<numContacts; j++){
685 double xa, ya, za;
686 double xb, yb, zb;
688 hkl3d_get_collision_coordinates(priv->hkl3d, i, j,
689 &xa, &ya, &za, &xb, &yb, &zb);
691 glDisable(GL_DEPTH_TEST);
692 glBegin(GL_LINES);
693 glColor4f(0, 0, 0, 1);
694 glVertex3d(xa, ya, za);
695 glVertex3d(xb, yb, zb);
696 glEnd();
697 glColor4f(1, 0, 0, 1);
698 glPushMatrix();
699 glTranslatef (xb, yb, zb);
700 glScaled(0.05,0.05,0.05);
702 draw_sphere(1, 10, 10);
704 glPopMatrix();
705 glColor4f(1, 1, 0, 1);
706 glPushMatrix();
707 glTranslatef (xa, ya, za);
708 glScaled(0.05,0.05,0.05);
710 draw_sphere(1, 10, 10);
712 glPopMatrix();
713 glEnable(GL_DEPTH_TEST);
716 glFlush();
719 static void draw_line(const float from[3], const float to[3],
720 const float fromColor[3], const float toColor[3])
722 glBegin(GL_LINES);
723 glColor3f(fromColor[0], fromColor[1], fromColor[2]);
724 glVertex3d(from[0], from[1], from[2]);
725 glColor3f(toColor[0], toColor[1], toColor[2]);
726 glVertex3d(to[0], to[1], to[2]);
727 glEnd();
730 static void draw_aabb(const float from[3], const float to[3], const float color[3])
732 float halfExtents[3] = {
733 (to[0] - from[0]) * .5,
734 (to[1] - from[1]) * .5,
735 (to[2] - from[2]) * .5
737 float center[3] = {
738 (to[0] + from[0]) * .5,
739 (to[1] + from[1]) * .5,
740 (to[2] + from[2]) * .5
742 int i, j;
744 float edgecoord[3] = {1., 1., 1.};
746 for (i=0;i<4;i++){
747 for (j=0;j<3;j++){
748 float pa[3] = {
749 edgecoord[0] * halfExtents[0] + center[0],
750 edgecoord[1] * halfExtents[1] + center[1],
751 edgecoord[2] * halfExtents[2] + center[2]
754 int othercoord = j % 3;
755 edgecoord[othercoord] *= -1.f;
757 float pb[3] = {
758 edgecoord[0] * halfExtents[0] + center[0],
759 edgecoord[1] * halfExtents[1] + center[1],
760 edgecoord[2] * halfExtents[2] + center[2]
762 draw_line(pa, pb, color, color);
764 edgecoord[0] = -1;
765 edgecoord[1] = -1;
766 edgecoord[2] = -1;
767 if (i < 3)
768 edgecoord[i] *= -1;
772 static void
773 hkl_gui_3d_draw_aabb_object(const Hkl3DObject *self)
775 GLfloat from[3];
776 GLfloat to[3];
777 GLfloat color[3] = {1, 0, 0};
779 if(self->hide)
780 return;
782 hkl3d_object_aabb_get(self, from, to);
783 draw_aabb(from, to, color);
786 void
787 hkl_gui_3d_draw_aabb(const HklGui3D *self)
789 int i;
790 int j;
791 HklGui3DPrivate *priv = HKL_GUI_3D_GET_PRIVATE(self);
793 for(i=0; i<priv->hkl3d->config->len; i++)
794 for(j=0; j<priv->hkl3d->config->models[i]->len; j++)
795 hkl_gui_3d_draw_aabb_object(priv->hkl3d->config->models[i]->objects[j]);
796 glFlush();
800 /* void hkl_gui_3d_draw_bullet_object(const Hkl3DObject *self) */
801 /* { */
802 /* int i; */
803 /* int j; */
804 /* btScalar m[16]; */
805 /* btVector3 worldBoundsMin; */
806 /* btVector3 worldBoundsMax; */
807 /* btVector3 aabbMin,aabbMax; */
809 /* /\* get the bounding box from bullet *\/ */
810 /* hkl3d_get_bounding_boxes(_hkl3d, &worldBoundsMin, &worldBoundsMax); */
812 /* object = _hkl3d->config->models[i]->objects[j]; */
813 /* if(!object->hide){ */
814 /* btCollisionObject *btObject; */
816 /* btObject = object->btObject; */
817 /* btObject->getWorldTransform().getOpenGLMatrix( m ); */
818 /* m_shapeDrawer.drawOpenGL(m, */
819 /* btObject->getCollisionShape(), */
820 /* *object->color, */
821 /* 0, /\* debug mode *\/ */
822 /* worldBoundsMin, */
823 /* worldBoundsMax); */
824 /* } */
825 /* glFlush(); */
826 /* } */
828 /* void */
829 /* hkl_gui_3d_draw_bullet(const HklGui3D *self) */
830 /* { */
831 /* int i; */
832 /* int j; */
833 /* HklGui3DPrivate *priv = HKL_GUI_3D_GET_PRIVATE(self); */
835 /* for(i=0; i<priv->hkl3d->config->len; i++) */
836 /* for(j=0; j<priv->hkl3d->config->models[i]->len; j++) */
837 /* hkl_gui_3d_draw_bullet_object(priv->hkl3d->config->models[i]->objects[j]); */
838 /* glFlush(); */
839 /* } */
841 gboolean
842 hkl_gui_3d_drawingarea1_expose_cb(GtkWidget *drawing_area, GdkEventExpose *event, gpointer user_data)
844 GtkAllocation alloc;
845 HklGui3D *self = HKL_GUI_3D(user_data);
846 HklGui3DPrivate *priv = HKL_GUI_3D_GET_PRIVATE(user_data);
847 GdkGLContext *gl_context = gtk_widget_get_gl_context(drawing_area);
848 GdkGLDrawable *gl_drawable = gtk_widget_get_gl_drawable(drawing_area);
850 /* Delimits the begining of the OpenGL execution. */
851 if (!gdk_gl_drawable_gl_begin(gl_drawable, gl_context))
852 g_assert_not_reached();
854 gtk_widget_get_allocation(drawing_area, &alloc);
855 glViewport(0,0, alloc.width, alloc.height);
856 priv->renderoptions.aspect = (gfloat)alloc.width / (gfloat)alloc.height;
858 hkl_gui_3d_draw_g3dmodel(self);
859 hkl_gui_3d_draw_selected(self);
860 hkl_gui_3d_draw_collisions(self);
861 if(priv->aabb)
862 hkl_gui_3d_draw_aabb(self);
863 /* hkl_gui_3d_draw_bullet(self); */
865 /* swap buffer if we're using double-buffering */
866 if (gdk_gl_drawable_is_double_buffered(gl_drawable))
867 gdk_gl_drawable_swap_buffers(gl_drawable);
868 else {
869 glFlush();
872 /* Delimits the end of the OpenGL execution. */
873 gdk_gl_drawable_gl_end(gl_drawable);
875 return FALSE;
878 gboolean
879 hkl_gui_3d_drawingarea1_configure_event_cb(GtkWidget *drawing_area,
880 GdkEventConfigure *event,
881 gpointer user_data)
883 GtkAllocation alloc;
884 HklGui3DPrivate *priv = HKL_GUI_3D_GET_PRIVATE(user_data);
885 GdkGLContext *gl_context = gtk_widget_get_gl_context(drawing_area);
886 GdkGLDrawable *gl_drawable = gtk_widget_get_gl_drawable(drawing_area);
888 /* Delimits the begining of the OpenGL execution. */
889 if (!gdk_gl_drawable_gl_begin(gl_drawable, gl_context))
890 g_assert_not_reached();
892 gtk_widget_get_allocation(drawing_area, &alloc);
893 glViewport(0,0, alloc.width, alloc.height);
894 priv->renderoptions.aspect = (gfloat)alloc.width / (gfloat)alloc.height;
896 /* Delimits the end of the OpenGL execution. */
897 gdk_gl_drawable_gl_end(gl_drawable);
899 return FALSE;
902 gboolean
903 hkl_gui_3d_idle_cb(gpointer user_data)
905 /* update control data/params in this function if needed */
906 GtkWidget *drawing_area = GTK_WIDGET(user_data);
908 glarea_update(drawing_area);
910 return FALSE;
913 gboolean
914 hkl_gui_3d_drawingarea1_button_press_event_cb(GtkWidget *drawing_area,
915 GdkEventButton* event,
916 gpointer user_data)
918 HklGui3DPrivate *priv = HKL_GUI_3D_GET_PRIVATE(user_data);
920 /* left mouse buttom: rotate object */
921 if(event->button == 1)
923 priv->mouse.beginx = event->x;
924 priv->mouse.beginy = event->y;
925 return TRUE;
928 // don't block
929 return FALSE;
932 gboolean
933 hkl_gui_3d_drawingarea1_scroll_event_cb(GtkWidget *drawing_area,
934 GdkEventScroll *event,
935 gpointer user_data)
937 GtkAllocation alloc;
938 HklGui3DPrivate *priv = HKL_GUI_3D_GET_PRIVATE(user_data);
940 gtk_widget_get_allocation(drawing_area, &alloc);
942 #define ZOOM_BY 10
943 if(event->direction == GDK_SCROLL_DOWN)
944 priv->renderoptions.zoom += ZOOM_BY;
945 else
946 priv->renderoptions.zoom -= ZOOM_BY;
947 #undef ZOOM_BY
949 if(priv->renderoptions.zoom < 1)
950 priv->renderoptions.zoom = 1;
951 if(priv->renderoptions.zoom > 120)
952 priv->renderoptions.zoom = 120;
954 glarea_update(drawing_area);
956 return FALSE;
959 gboolean
960 hkl_gui_3d_drawingarea1_motion_notify_event_cb(GtkWidget *drawing_area,
961 GdkEventMotion* event,
962 gpointer user_data)
964 HklGui3DPrivate *priv = HKL_GUI_3D_GET_PRIVATE(user_data);
965 GtkAllocation alloc;
966 gint x, y;
967 GdkModifierType state;
969 gtk_widget_get_allocation(drawing_area, &alloc);
971 if(event->is_hint)
972 gdk_window_get_pointer(event->window, &x, &y, &state);
973 else
975 x = event->x;
976 y = event->y;
977 state = event->state;
980 /* left button pressed */
981 if(state & GDK_BUTTON1_MASK)
983 if(state & GDK_SHIFT_MASK)
985 /* shift pressed, translate view */
986 priv->renderoptions.offx += (float)(x - priv->mouse.beginx) / alloc.width / priv->renderoptions.zoom;
987 priv->renderoptions.offy -= (float)(y - priv->mouse.beginy) / alloc.height / priv->renderoptions.zoom;
989 else
991 /* rotate view */
992 gfloat spin_quat[4];
993 g3d_quat_trackball(spin_quat,
994 (2.0 * priv->mouse.beginx - alloc.width) / alloc.width,
995 (alloc.height - 2.0 * priv->mouse.beginy) / alloc.height,
996 (2.0 * x - alloc.width) / alloc.width,
997 (alloc.height - 2.0 * y) / alloc.height,
998 0.8 /* trackball radius */);
999 g3d_quat_add(priv->renderoptions.quat,
1000 spin_quat, priv->renderoptions.quat);
1001 /* normalize quat some times */
1002 priv->renderoptions.norm_count ++;
1003 if(priv->renderoptions.norm_count > 97) {
1004 priv->renderoptions.norm_count = 0;
1005 g3d_quat_normalize(priv->renderoptions.quat);
1008 /* g3d_quat_to_rotation_xyz(priv->renderoptions.quat, */
1009 /* &rx, &ry, &rz); */
1010 /* text = g_strdup_printf("%-.2f°, %-.2f°, %-.2f°", */
1011 /* rx * 180.0 / G_PI, ry * 180.0 / G_PI, rz * 180.0 / G_PI); */
1012 /* gui_glade_status(priv, text); */
1013 /* g_free(text); */
1016 glarea_update(GTK_WIDGET(priv->drawingarea1));
1019 /* middle mouse button */
1020 if(state & GDK_BUTTON2_MASK)
1022 priv->renderoptions.zoom +=
1023 ((y - priv->mouse.beginy) / (gfloat)alloc.height) * 40;
1024 if(priv->renderoptions.zoom < 1)
1025 priv->renderoptions.zoom = 1;
1026 if(priv->renderoptions.zoom > 120)
1027 priv->renderoptions.zoom = 120;
1029 glarea_update(GTK_WIDGET(priv->drawingarea1));
1031 priv->mouse.beginx = x;
1032 priv->mouse.beginy = y;
1034 return FALSE;
1037 /*********************************************/
1038 /* HklGui3D and HklGui3DClass initialization */
1039 /*********************************************/
1041 static void
1042 hkl_gui_3d_class_init (HklGui3DClass *class)
1044 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
1046 g_type_class_add_private (class, sizeof (HklGui3DPrivate));
1048 /* virtual method */
1049 gobject_class->finalize = finalize;
1050 gobject_class->set_property = set_property;
1051 gobject_class->get_property = get_property;
1053 /* properties */
1054 obj_properties[PROP_FILENAME] =
1055 g_param_spec_string ("filename",
1056 "Filename",
1057 "The confuration filename",
1058 NULL,
1059 G_PARAM_CONSTRUCT_ONLY |
1060 G_PARAM_READWRITE |
1061 G_PARAM_STATIC_STRINGS);
1063 obj_properties[PROP_GEOMETRY] =
1064 g_param_spec_pointer ("geometry",
1065 "Geometry",
1066 "The Hkl Geometry used underneath",
1067 G_PARAM_CONSTRUCT_ONLY |
1068 G_PARAM_READWRITE |
1069 G_PARAM_STATIC_STRINGS);
1071 g_object_class_install_properties (gobject_class,
1072 N_PROPERTIES,
1073 obj_properties);
1077 static void hkl_gui_3d_init (HklGui3D * self)
1079 HklGui3DPrivate *priv = HKL_GUI_3D_GET_PRIVATE(self);
1080 GtkBuilder *builder;
1082 /* properties */
1083 priv->filename = NULL;
1084 priv->geometry = NULL;
1086 priv->builder = builder = gtk_builder_new ();
1088 get_ui(builder, "3d.ui");
1090 // widgets
1091 get_object(builder, GTK_FRAME, priv, frame1);
1092 get_object(builder, GTK_VBOX, priv, vbox1);
1093 get_object(builder, GTK_TREE_VIEW, priv, treeview1);
1094 get_object(builder, GTK_TOOL_BUTTON, priv, toolbutton1);
1095 get_object(builder, GTK_TOOL_BUTTON, priv, toolbutton2);
1096 get_object(builder, GTK_TOOL_BUTTON, priv, toolbutton3);
1097 get_object(builder, GTK_FILE_CHOOSER_DIALOG, priv, filechooserdialog1);
1098 get_object(builder, GTK_BUTTON, priv, button1);
1099 get_object(builder, GTK_BUTTON, priv, button2);
1100 get_object(builder, GTK_TREE_STORE, priv, treestore1);
1101 get_object(builder, GTK_DRAWING_AREA, priv, drawingarea1);
1103 gtk_builder_connect_signals (builder, self);
1105 /* OPENGL */
1107 /* renderoptions */
1108 reset_3d(&priv->renderoptions);
1109 priv->aabb = FALSE;
1111 /* attache GL capability to drawingarea1 */
1112 GdkGLConfig *gl_config = gdk_gl_config_new_by_mode(GDK_GL_MODE_RGBA |
1113 GDK_GL_MODE_DEPTH |
1114 GDK_GL_MODE_DOUBLE);
1115 if (!gl_config)
1116 g_assert_not_reached();
1117 if (!gtk_widget_set_gl_capability(GTK_WIDGET(priv->drawingarea1), gl_config, NULL, TRUE,
1118 GDK_GL_RGBA_TYPE))
1119 g_assert_not_reached();
1121 gtk_widget_set_can_focus(GTK_WIDGET(priv->drawingarea1), TRUE);
1122 gtk_widget_add_events(GTK_WIDGET(priv->drawingarea1),
1123 GDK_BUTTON1_MOTION_MASK |
1124 GDK_BUTTON2_MOTION_MASK |
1125 GDK_BUTTON_PRESS_MASK |
1126 GDK_VISIBILITY_NOTIFY_MASK);
1128 /* connect the GL callbacks */
1129 const gdouble TIMEOUT_PERIOD = 1000 / 60;
1130 g_timeout_add(TIMEOUT_PERIOD, hkl_gui_3d_idle_cb, priv->drawingarea1);
1131 g_signal_connect(priv->drawingarea1, "expose-event",
1132 G_CALLBACK(hkl_gui_3d_drawingarea1_expose_cb), self);
1133 g_signal_connect(priv->drawingarea1, "button-press-event",
1134 G_CALLBACK(hkl_gui_3d_drawingarea1_button_press_event_cb), self);
1135 g_signal_connect(priv->drawingarea1, "motion-notify-event",
1136 G_CALLBACK(hkl_gui_3d_drawingarea1_motion_notify_event_cb), self);