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