5d8410462be2ff446c2c1ca39225f981f15d3d12
[blender.git] / intern / bsp / test / BSP_GhostTest / BSP_GhostTest3D.cpp
1 /**
2  * $Id$
3  * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version. The Blender
9  * Foundation also sells licenses for use in proprietary software under
10  * the Blender License.  See http://www.blender.org/BL/ for information
11  * about this.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software Foundation,
20  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21  *
22  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
23  * All rights reserved.
24  *
25  * The Original Code is: all of this file.
26  *
27  * Contributor(s): none yet.
28  *
29  * ***** END GPL/BL DUAL LICENSE BLOCK *****
30  */
31
32 /**
33
34 * $Id$
35 * Copyright (C) 2001 NaN Technologies B.V.
36 */
37 #ifdef HAVE_CONFIG_H
38 #include <config.h>
39 #endif
40
41 #if defined(WIN32) || defined(__APPLE__)
42 #       ifdef WIN32
43 #               include <windows.h>
44 #               include <GL/gl.h>
45 #               include <GL/glu.h>
46 #       else // WIN32
47 #               include <AGL/gl.h>
48 #       endif // WIN32
49 #else // defined(WIN32) || defined(__APPLE__)
50 #       include <GL/gl.h>
51 #       include <GL/glu.h>
52 #endif // defined(WIN32) || defined(__APPLE__)
53
54
55 #include "BSP_GhostTest3D.h"
56 #include "BSP_MeshDrawer.h"
57
58 #include "GHOST_ISystem.h"
59 #include "GHOST_IWindow.h"
60
61 #include "MT_Quaternion.h"
62 #include "MT_Transform.h"
63 #include "CSG_BooleanOps.h"
64
65 #include <iostream>
66
67
68 using namespace std;
69
70
71 BSP_GhostTestApp3D::
72 BSP_GhostTestApp3D(
73 ) :
74         m_window(NULL),
75         m_system(NULL),
76         m_finish_me_off(false),
77         m_current_object(0)
78 {
79         //nothing to do;
80 }
81
82         void
83 BSP_GhostTestApp3D::
84 SetMesh(
85         MEM_SmartPtr<BSP_TMesh> mesh
86 ){
87         m_meshes.push_back(mesh);
88
89         BSP_RotationSetting rotation_setting;
90         BSP_TranslationSetting translation_setting;
91
92         rotation_setting.m_angle_x = MT_Scalar(0);
93         rotation_setting.m_angle_y = MT_Scalar(0);
94         rotation_setting.m_moving = false;
95         rotation_setting.x_old = 0;
96         rotation_setting.y_old = 0;
97
98         translation_setting.m_t_x = MT_Scalar(0);
99         translation_setting.m_t_y = MT_Scalar(0);
100         translation_setting.m_t_z = MT_Scalar(0);
101         translation_setting.m_moving = false;
102         translation_setting.x_old = 0;
103         translation_setting.y_old = 0;
104
105         m_rotation_settings.push_back(rotation_setting);
106         m_translation_settings.push_back(translation_setting);
107         m_render_modes.push_back(e_wireframe_shaded);
108         m_scale_settings.push_back(MT_Scalar(1));
109
110 }
111
112         void
113 BSP_GhostTestApp3D::
114 Swap(
115         int i
116 ){
117
118         if (!m_rotation_settings[i].m_moving && !m_translation_settings[i].m_moving) {
119                 swap(m_meshes[i],m_meshes.back());
120                 swap(m_rotation_settings[i],m_rotation_settings.back());
121                 swap(m_translation_settings[i],m_translation_settings.back());
122                 swap(m_scale_settings[i],m_scale_settings.back());
123                 swap(m_render_modes[i],m_render_modes.back());
124         }
125 }
126
127
128
129
130
131
132         MT_Transform
133 BSP_GhostTestApp3D::
134 GetTransform(
135         int i
136 ){
137
138         MT_Quaternion q_ax(MT_Vector3(0,1,0),m_rotation_settings[i].m_angle_x);
139         MT_Quaternion q_ay(MT_Vector3(1,0,0),m_rotation_settings[i].m_angle_y);
140
141         MT_Point3 tr(
142                 m_translation_settings[i].m_t_x,
143                 m_translation_settings[i].m_t_y,
144                 m_translation_settings[i].m_t_z
145         );
146         
147
148         MT_Matrix3x3 rotx(q_ax);
149         MT_Matrix3x3 roty(q_ay);
150
151         MT_Matrix3x3 rot = rotx * roty;
152
153         MT_Transform trans(tr,rot);
154
155         MT_Transform scalet;
156         scalet.setIdentity();
157         scalet.scale(m_scale_settings[i],m_scale_settings[i],m_scale_settings[i]);
158
159         return trans * scalet;
160 }
161
162         void
163 BSP_GhostTestApp3D::
164 Operate(
165         int type
166 ){
167
168         CSG_VertexIteratorDescriptor * vA = VertexIt_Construct(m_meshes[0],GetTransform(0));
169         CSG_FaceIteratorDescriptor * fA = FaceIt_Construct(m_meshes[0]);
170                                                 
171         CSG_VertexIteratorDescriptor * vB = VertexIt_Construct(m_meshes[1],GetTransform(1));
172         CSG_FaceIteratorDescriptor * fB = FaceIt_Construct(m_meshes[1]);
173
174         // describe properties.
175
176         CSG_MeshPropertyDescriptor props;
177         props.mesh_property_flags = 0;
178         props.user_data_size = 0;
179
180         CSG_BooleanOperation * op =  CSG_NewBooleanFunction();
181         props = CSG_DescibeOperands(op,props,props);
182
183         CSG_PerformBooleanOperation(op,CSG_OperationType(type),
184                 *fA,*vA,*fB,*vB
185         );
186
187         CSG_FaceIteratorDescriptor * out_f = CSG_OutputFaceDescriptor(op);
188         CSG_VertexIteratorDescriptor * out_v = CSG_OutputVertexDescriptor(op);
189
190         MEM_SmartPtr<BSP_TMesh> new_mesh (BuildMesh(props,*out_f,*out_v));
191
192         // free stuff
193
194         CSG_FreeVertexDescriptor(out_v);
195         CSG_FreeFaceDescriptor(out_f);
196         CSG_FreeBooleanOperation(op);
197
198         op = NULL;
199         SetMesh(new_mesh);
200 }
201
202
203         void 
204 BSP_GhostTestApp3D::
205 UpdateFrame(
206 ){
207 if (m_window) {
208
209         GHOST_Rect v_rect;
210         m_window->getClientBounds(v_rect);
211         
212         glViewport(0,0,v_rect.getWidth(),v_rect.getHeight());
213         
214 }
215 }
216
217
218 MT_Vector3
219 BSP_GhostTestApp3D::
220 UnProject(
221         const MT_Vector3 & vec
222 ) {
223
224         GLint viewport[4];
225         GLdouble mvmatrix[16],projmatrix[16];
226
227         glGetIntegerv(GL_VIEWPORT,viewport);
228         glGetDoublev(GL_MODELVIEW_MATRIX,mvmatrix);
229         glGetDoublev(GL_PROJECTION_MATRIX,projmatrix);
230         
231         GLdouble realy = viewport[3] - vec.y() - 1;
232         GLdouble outx,outy,outz;
233
234         gluUnProject(vec.x(),realy,vec.z(),mvmatrix,projmatrix,viewport,&outx,&outy,&outz);
235
236         return MT_Vector3(outx,outy,outz);
237 }
238
239
240         bool
241 BSP_GhostTestApp3D::
242 InitApp(
243 ){
244
245         // create a system and window with opengl
246         // rendering context.
247
248         GHOST_TSuccess success = GHOST_ISystem::createSystem();
249         if (success == GHOST_kFailure) return false;
250
251         m_system = GHOST_ISystem::getSystem();
252         if (m_system == NULL) return false;
253
254         m_system->addEventConsumer(this);
255         
256         m_window = m_system->createWindow(
257                 "GHOST crud3D!",
258                 100,100,640,480,GHOST_kWindowStateNormal,
259                 GHOST_kDrawingContextTypeOpenGL
260         );
261
262         if (
263                 m_window == NULL
264         ) {
265                 m_system = NULL;
266                 GHOST_ISystem::disposeSystem();
267                 return false;
268         }
269
270         // make an opengl frustum for this wind
271
272         MT_Vector3 min,max;
273
274         min = m_meshes[0]->m_min;
275         max = m_meshes[0]->m_max;
276         InitOpenGl(min,max);
277
278         return true;
279 }
280
281         void
282 BSP_GhostTestApp3D::
283 Run(
284 ){
285         if (m_system == NULL) {
286                 return;
287         }
288
289         while (!m_finish_me_off) {
290                 m_system->processEvents(true);
291                 m_system->dispatchEvents();
292         };
293 }
294
295         bool 
296 BSP_GhostTestApp3D::
297 processEvent(
298         GHOST_IEvent* event
299 ){
300
301         bool handled = false;
302
303         switch(event->getType()) {
304                 case GHOST_kEventWindowSize:
305                 case GHOST_kEventWindowActivate:
306                         UpdateFrame();
307                 case GHOST_kEventWindowUpdate:
308                         DrawPolies();
309                         handled = true;
310                         break;
311                 case GHOST_kEventButtonDown:
312                 {
313                         int x,y;
314                         m_system->getCursorPosition(x,y);
315         
316                         int wx,wy;
317                         m_window->screenToClient(x,y,wx,wy);
318
319                         GHOST_TButtonMask button = 
320                                 static_cast<GHOST_TEventButtonData *>(event->getData())->button;
321                         
322                         if (button == GHOST_kButtonMaskLeft) {
323                                 m_rotation_settings[m_current_object].m_moving = true;
324                                 m_rotation_settings[m_current_object].x_old = x;
325                                 m_rotation_settings[m_current_object].y_old = y;        
326                         } else 
327                         if (button == GHOST_kButtonMaskRight) {
328                                 m_translation_settings[m_current_object].m_moving = true;
329                                 m_translation_settings[m_current_object].x_old = x;
330                                 m_translation_settings[m_current_object].y_old = y;     
331                         } else 
332                 
333                         m_window->invalidate();
334                         handled = true;
335                         break;
336
337                 }
338
339                 case GHOST_kEventButtonUp:
340                 {
341
342                         GHOST_TButtonMask button = 
343                                 static_cast<GHOST_TEventButtonData *>(event->getData())->button;
344                         
345                         if (button == GHOST_kButtonMaskLeft) {
346                                 m_rotation_settings[m_current_object].m_moving = false;
347                                 m_rotation_settings[m_current_object].x_old = 0;
348                                 m_rotation_settings[m_current_object].y_old = 0;
349                         } else 
350                         if (button == GHOST_kButtonMaskRight) {
351                                 m_translation_settings[m_current_object].m_moving = false;
352                                 m_translation_settings[m_current_object].x_old;
353                                 m_translation_settings[m_current_object].y_old;
354
355                         }
356                         m_window->invalidate();
357                         handled = true;
358                         break;
359
360                 }
361
362                 case GHOST_kEventCursorMove:
363                 {               
364                         int x,y;
365                         m_system->getCursorPosition(x,y);       
366                         int wx,wy;
367                         m_window->screenToClient(x,y,wx,wy);
368
369                         if (m_rotation_settings[m_current_object].m_moving) {
370                                 m_rotation_settings[m_current_object].m_angle_x = MT_Scalar(wx)/20;
371                                 m_rotation_settings[m_current_object].x_old = wx;
372                                 m_rotation_settings[m_current_object].m_angle_y = MT_Scalar(wy)/20;
373                                 m_rotation_settings[m_current_object].y_old = wy;
374
375                                 m_window->invalidate();
376                         }
377                         if (m_translation_settings[m_current_object].m_moving) {
378
379                                 // project current objects bounding box centre into screen space.
380                                 // unproject mouse point into object space using z-value from 
381                                 // projected bounding box centre.
382
383                                 GHOST_Rect bounds;
384                                 m_window->getClientBounds(bounds);
385
386                                 int w_h = bounds.getWidth();
387
388                                 y = w_h - wy;
389
390                                 double mvmatrix[16];
391                                 double projmatrix[16];
392                                 GLint viewport[4];
393
394                                 double px, py, pz,sz;
395
396                                 /* Get the matrices needed for gluUnProject */
397                                 glGetIntegerv(GL_VIEWPORT, viewport);
398                                 glGetDoublev(GL_MODELVIEW_MATRIX, mvmatrix);
399                                 glGetDoublev(GL_PROJECTION_MATRIX, projmatrix);
400
401                                 // work out the position of the end effector in screen space
402
403                                 GLdouble ex,ey,ez;
404
405                                 MT_Vector3 bbox_min, bbox_max;
406                                 
407                                 bbox_min = m_meshes[0]->m_min;
408                                 bbox_max = m_meshes[0]->m_max;
409
410                                 MT_Vector3 bbox_centre = (bbox_min + bbox_max)/2;
411
412                                 ex = bbox_centre.x();
413                                 ey = bbox_centre.y();
414                                 ez = bbox_centre.z();
415
416                                 gluProject(ex, ey, ez, mvmatrix, projmatrix, viewport, &px, &py, &sz);
417                                 gluUnProject((GLdouble) x, (GLdouble) y, sz, mvmatrix, projmatrix, viewport, &px, &py, &pz);
418
419                                 m_translation_settings[m_current_object].m_t_x = px;
420                                 m_translation_settings[m_current_object].m_t_y = py;
421                                 m_translation_settings[m_current_object].m_t_z = pz;
422                                 m_window->invalidate();
423
424                         }               
425         
426                         handled = true;
427                         break;
428                 }
429
430                 case GHOST_kEventKeyDown :
431                 {
432                         GHOST_TEventKeyData *kd = 
433                                 static_cast<GHOST_TEventKeyData *>(event->getData());
434
435
436                         switch(kd->key) {
437                                 case GHOST_kKeyI:
438                                 {               
439                                         // now intersect meshes.
440                                         Operate(e_csg_intersection);
441                                         handled = true;
442                                         m_window->invalidate();
443                                         break;                                  
444                                 }
445                                 case GHOST_kKeyU:       
446                                 {               
447                                         Operate(e_csg_union);
448                                         handled = true;
449                                         m_window->invalidate();
450                                         break;                                  
451                                 }
452                                 case GHOST_kKeyD:       
453                                 {               
454                                         Operate(e_csg_difference);
455                                         handled = true;
456                                         m_window->invalidate();
457                                         break;                                  
458                                 }
459
460                                 case GHOST_kKeyA:
461                                 {
462
463                                         m_scale_settings[m_current_object] *= 1.1;
464                                         handled = true;
465                                         m_window->invalidate();
466                                         break;                                  
467                                 }
468                                 case GHOST_kKeyZ:
469                                 {
470                                         m_scale_settings[m_current_object] *= 0.8;
471
472                                         handled = true;
473                                         m_window->invalidate();
474                                         break;                                  
475                                 }
476
477                                 case GHOST_kKeyR:
478
479                                         m_render_modes[m_current_object]++;
480
481                                         if (m_render_modes[m_current_object] > e_last_render_mode) {
482                                                 m_render_modes[m_current_object] = e_first_render_mode;
483                                         }
484
485                                         handled = true;
486                                         m_window->invalidate();
487                                         break;                                  
488
489
490
491                                 case GHOST_kKeyB:
492                                         handled = true;
493                                         m_window->invalidate();
494                                         break;                                  
495         
496                                 case GHOST_kKeyQ:
497                                         m_finish_me_off = true;
498                                         handled = true;
499                                         break;
500
501                                 case GHOST_kKeyS:
502                                         Swap(m_current_object);
503                                         m_window->invalidate();
504                                         handled = true;
505                                         break;
506                         
507                                 case GHOST_kKeySpace:
508                                                 
509                                         // increment the current object only if the object is not being
510                                         // manipulated.
511                                         if (! (m_rotation_settings[m_current_object].m_moving || m_translation_settings[m_current_object].m_moving)) {
512                                                 m_current_object ++;
513                                                 if (m_current_object >= m_meshes.size()) {
514                                                         m_current_object = 0;
515                                                 }
516                                         }
517                                         m_window->invalidate();
518                                         
519
520                                         handled = true;
521                                         break;
522                                 default :
523                                         break;
524                         }
525                 }                       
526
527                 default :
528                         break;
529         }
530
531         return handled;
532         
533 };
534
535 BSP_GhostTestApp3D::
536 ~BSP_GhostTestApp3D(
537 ){
538
539         if (m_window) {
540                 m_system->disposeWindow(m_window);
541                 m_window = NULL;
542                 GHOST_ISystem::disposeSystem();
543                 m_system = NULL;
544         }
545 };
546         
547         void
548 BSP_GhostTestApp3D::
549 DrawPolies(
550 ){
551         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
552
553         for (int i = 0; i < m_meshes.size(); ++i) {
554
555                 MT_Transform trans = GetTransform(i);
556
557                 float opengl_mat[16];
558                 trans.getValue(opengl_mat);
559
560                 opengl_mat[14] -= 30;
561                         
562                 glPushMatrix();
563                 glLoadMatrixf(opengl_mat);
564
565                 MT_Vector3 color(1.0,1.0,1.0);
566
567                 if (i == m_current_object) {
568                         color = MT_Vector3(1.0,0,0);
569                 }
570         
571                 BSP_MeshDrawer::DrawMesh(m_meshes[i].Ref(),m_render_modes[i]);
572
573                 glPopMatrix();  
574         }
575
576         m_window->swapBuffers();
577 }
578
579         void
580 BSP_GhostTestApp3D::
581 InitOpenGl(
582         const MT_Vector3 &min,
583         const MT_Vector3 &max
584 ){
585
586         GLfloat light_diffuse0[] = {1.0, 0.0, 0.0, 0.5};  /* Red diffuse light. */
587         GLfloat light_position0[] = {1.0, 1.0, 1.0, 0.0};  /* Infinite light location. */
588
589         GLfloat light_diffuse1[] = {1.0, 1.0, 1.0, 0.5};  /* Red diffuse light. */
590         GLfloat light_position1[] = {1.0, 0, 0, 0.0};  /* Infinite light location. */
591
592         /* Enable a single OpenGL light. */
593         glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse0);
594         glLightfv(GL_LIGHT0, GL_POSITION, light_position0);
595
596         glLightfv(GL_LIGHT1, GL_DIFFUSE, light_diffuse1);
597         glLightfv(GL_LIGHT1, GL_POSITION, light_position1);
598
599           glEnable(GL_LIGHT0);
600           glEnable(GL_LIGHT1);
601           glEnable(GL_LIGHTING);
602
603         // make sure there is no back face culling.
604 //      glDisable(GL_CULL_FACE);
605
606
607         // use two sided lighting model
608         
609          glLightModeli(GL_LIGHT_MODEL_TWO_SIDE,GL_TRUE);
610
611         /* Use depth buffering for hidden surface elimination. */
612         glEnable(GL_DEPTH_TEST);
613
614         /* Setup the view of the cube. */
615         glMatrixMode(GL_PROJECTION);
616
617         // centre of the box + 3* depth of box
618
619         MT_Vector3 centre = (min + max) * 0.5;
620         MT_Vector3 diag = max - min;
621
622         float depth = diag.length();
623         float distance = 5;
624
625         gluPerspective( 
626         /* field of view in degree */ 40.0,
627         /* aspect ratio */ 1.0,
628         /* Z near */ 1.0, 
629         /* Z far */ distance * depth * 2
630         );
631         glMatrixMode(GL_MODELVIEW);     
632
633         gluLookAt(
634                 centre.x(), centre.y(), centre.z() + distance*depth, //eye  
635                 centre.x(), centre.y(), centre.z(), //centre      
636                 0.0, 1.0, 0.);      /* up is in positive Y direction */
637
638 }       
639
640                         
641
642
643
644
645         
646         
647
648         
649
650
651
652
653
654
655
656         
657
658
659