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