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