2 * ***** BEGIN GPL LICENSE BLOCK *****
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.
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.
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.
18 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19 * All rights reserved.
21 * The Original Code is: all of this file.
23 * Contributor(s): none yet.
25 * ***** END GPL LICENSE BLOCK *****
30 * Copyright (C) 2001 NaN Technologies B.V.
32 #if defined(WIN32) || defined(__APPLE__)
40 #else // defined(WIN32) || defined(__APPLE__)
43 #endif // defined(WIN32) || defined(__APPLE__)
46 #include "BSP_GhostTest3D.h"
47 #include "BSP_MeshDrawer.h"
49 #include "GHOST_ISystem.h"
50 #include "GHOST_IWindow.h"
52 #include "MT_Quaternion.h"
53 #include "MT_Transform.h"
54 #include "CSG_BooleanOps.h"
78 m_finish_me_off(false),
87 MEM_SmartPtr<BSP_TMesh> mesh
89 m_meshes.push_back(mesh);
91 BSP_RotationSetting rotation_setting;
92 BSP_TranslationSetting translation_setting;
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;
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;
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));
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());
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);
140 m_translation_settings[i].m_t_x,
141 m_translation_settings[i].m_t_y,
142 m_translation_settings[i].m_t_z
146 MT_Matrix3x3 rotx(q_ax);
147 MT_Matrix3x3 roty(q_ay);
149 MT_Matrix3x3 rot = rotx * roty;
151 MT_Transform trans(tr,rot);
154 scalet.setIdentity();
155 scalet.scale(m_scale_settings[i],m_scale_settings[i],m_scale_settings[i]);
157 return trans * scalet;
166 CSG_VertexIteratorDescriptor * vA = VertexIt_Construct(m_meshes[0],GetTransform(0));
167 CSG_FaceIteratorDescriptor * fA = FaceIt_Construct(m_meshes[0]);
169 CSG_VertexIteratorDescriptor * vB = VertexIt_Construct(m_meshes[1],GetTransform(1));
170 CSG_FaceIteratorDescriptor * fB = FaceIt_Construct(m_meshes[1]);
172 // describe properties.
174 CSG_MeshPropertyDescriptor props;
175 props.user_face_vertex_data_size = 0;
176 props.user_data_size = 0;
178 CSG_BooleanOperation * op = CSG_NewBooleanFunction();
179 props = CSG_DescibeOperands(op,props,props);
181 CSG_PerformBooleanOperation(
182 op,CSG_OperationType(type),
183 *fA,*vA,*fB,*vB,EmptyInterpFunc
186 CSG_FaceIteratorDescriptor out_f;
187 CSG_OutputFaceDescriptor(op,&out_f);
189 CSG_VertexIteratorDescriptor out_v;
190 CSG_OutputVertexDescriptor(op,&out_v);
192 MEM_SmartPtr<BSP_TMesh> new_mesh (BuildMesh(props,out_f,out_v));
196 CSG_FreeVertexDescriptor(&out_v);
197 CSG_FreeFaceDescriptor(&out_f);
198 CSG_FreeBooleanOperation(op);
212 m_window->getClientBounds(v_rect);
214 glViewport(0,0,v_rect.getWidth(),v_rect.getHeight());
223 const MT_Vector3 & vec
227 GLdouble mvmatrix[16],projmatrix[16];
229 glGetIntegerv(GL_VIEWPORT,viewport);
230 glGetDoublev(GL_MODELVIEW_MATRIX,mvmatrix);
231 glGetDoublev(GL_PROJECTION_MATRIX,projmatrix);
233 GLdouble realy = viewport[3] - vec.y() - 1;
234 GLdouble outx,outy,outz;
236 gluUnProject(vec.x(),realy,vec.z(),mvmatrix,projmatrix,viewport,&outx,&outy,&outz);
238 return MT_Vector3(outx,outy,outz);
247 // create a system and window with opengl
248 // rendering context.
250 GHOST_TSuccess success = GHOST_ISystem::createSystem();
251 if (success == GHOST_kFailure) return false;
253 m_system = GHOST_ISystem::getSystem();
254 if (m_system == NULL) return false;
256 m_system->addEventConsumer(this);
258 m_window = m_system->createWindow(
260 100,100,512,512,GHOST_kWindowStateNormal,
261 GHOST_kDrawingContextTypeOpenGL,false
268 GHOST_ISystem::disposeSystem();
272 // make an opengl frustum for this wind
276 min = m_meshes[0]->m_min;
277 max = m_meshes[0]->m_max;
287 if (m_system == NULL) {
291 while (!m_finish_me_off) {
292 m_system->processEvents(true);
293 m_system->dispatchEvents();
303 bool handled = false;
305 switch(event->getType()) {
306 case GHOST_kEventWindowSize:
307 case GHOST_kEventWindowActivate:
309 case GHOST_kEventWindowUpdate:
313 case GHOST_kEventButtonDown:
316 m_system->getCursorPosition(x,y);
320 m_window->screenToClient(x,y,wx,wy);
322 GHOST_TButtonMask button =
323 static_cast<GHOST_TEventButtonData *>(event->getData())->button;
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;
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;
336 m_window->invalidate();
342 case GHOST_kEventButtonUp:
345 GHOST_TButtonMask button =
346 static_cast<GHOST_TEventButtonData *>(event->getData())->button;
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;
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;
360 m_window->invalidate();
366 case GHOST_kEventCursorMove:
369 m_system->getCursorPosition(x,y);
371 m_window->screenToClient(x,y,wx,wy);
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;
379 m_window->invalidate();
381 if (m_translation_settings[m_current_object].m_moving) {
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.
388 m_window->getClientBounds(bounds);
390 int w_h = bounds.getHeight();
396 double projmatrix[16];
399 double px, py, pz,sz;
401 /* Get the matrices needed for gluUnProject */
402 glGetIntegerv(GL_VIEWPORT, viewport);
403 glGetDoublev(GL_MODELVIEW_MATRIX, mvmatrix);
404 glGetDoublev(GL_PROJECTION_MATRIX, projmatrix);
406 // work out the position of the end effector in screen space
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;
414 gluProject(ex, ey, ez, mvmatrix, projmatrix, viewport, &px, &py, &sz);
415 gluUnProject((GLdouble) x, (GLdouble) y, sz, mvmatrix, projmatrix, viewport, &px, &py, &pz);
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();
428 case GHOST_kEventKeyDown :
430 GHOST_TEventKeyData *kd =
431 static_cast<GHOST_TEventKeyData *>(event->getData());
437 // now intersect meshes.
438 Operate(e_csg_intersection);
440 m_window->invalidate();
445 Operate(e_csg_union);
447 m_window->invalidate();
452 Operate(e_csg_difference);
454 m_window->invalidate();
461 m_scale_settings[m_current_object] *= 1.1;
463 m_window->invalidate();
468 m_scale_settings[m_current_object] *= 0.8;
471 m_window->invalidate();
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;
481 m_window->invalidate();
486 m_window->invalidate();
490 m_finish_me_off = true;
495 Swap(m_current_object);
496 m_window->invalidate();
500 case GHOST_kKeySpace:
502 // increment the current object only if the object is not being
504 if (! (m_rotation_settings[m_current_object].m_moving || m_translation_settings[m_current_object].m_moving)) {
506 if (m_current_object >= m_meshes.size()) {
507 m_current_object = 0;
511 m_window->invalidate();
530 m_system->disposeWindow(m_window);
532 GHOST_ISystem::disposeSystem();
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);
548 float opengl_mat[16];
549 trans.getValue(opengl_mat);
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);
557 BSP_MeshDrawer::DrawMesh(m_meshes[i].Ref(),m_render_modes[i]);
562 m_window->swapBuffers();
569 const MT_Vector3 &min,
570 const MT_Vector3 &max
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. */
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. */
579 /* Enable a single OpenGL light. */
581 glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse0);
582 glLightfv(GL_LIGHT0, GL_POSITION, light_position0);
584 glLightfv(GL_LIGHT1, GL_DIFFUSE, light_diffuse1);
585 glLightfv(GL_LIGHT1, GL_POSITION, light_position1);
590 glEnable(GL_LIGHTING);
592 // make sure there is no back face culling.
593 // glDisable(GL_CULL_FACE);
595 // use two sided lighting model
596 glLightModeli(GL_LIGHT_MODEL_TWO_SIDE,GL_TRUE);
598 /* Use depth buffering for hidden surface elimination. */
600 glEnable(GL_DEPTH_TEST);
602 /* Setup the view of the cube. */
604 glMatrixMode(GL_PROJECTION);
606 // center of the box + 3* depth of box
608 MT_Vector3 center = (min + max) * 0.5;
609 MT_Vector3 diag = max - min;
611 float depth = diag.length();
615 /* field of view in degree */ 40.0,
616 /* aspect ratio */ 1.0,
618 /* Z far */ distance * depth * 2
620 glMatrixMode(GL_MODELVIEW);
623 center.x(), center.y(), center.z() + distance*depth, //eye
624 center.x(), center.y(), center.z(), //center
626 ); /* up is in positive Y direction */