Restore SceneGraph deletion in destructor.
[GoMoku3D.git] / src / gui / 3d / SceneGraph.cpp
blob8063798c22844318a05dda592eea228e9461e9e5
1 /********************************************************************
3 * Copyright (C) 2008 Tobia Zorzan
5 * This file is part of GoMoku3D.
7 * GoMoku3D is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
12 * GoMoku3D is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with GoMoku3D. If not, see <http://www.gnu.org/licenses/>.
20 *******************************************************************/
22 #include "SceneGraph.h"
24 SceneGraph::SceneGraph(CubeRenderArea *render, int dim) : _renderarea(render),
25 _dim(dim),
26 _selectedCube(0),
27 _directionOfExplosion(CubeRenderArea::NO_ORIENTATION),
28 _desiredDirectionOfExplosion(CubeRenderArea::NO_ORIENTATION),
29 _allImplosion(false),
30 _explodedLevels(0)
32 //allocating all new nodes for the scene graph
34 //root of the graph, must be referenced manually, all its childs don't need it
35 _root = new SoSeparator();
36 _root->ref();
37 //new camera
38 _camera = new SoPerspectiveCamera();
39 //new light
40 _light = new SoDirectionalLight();
41 //container for all cubes, make them clickable
42 _selector = new SoSelection();
43 //group for the fixed part of the cube
44 _fixedCubes = new SoGroup();
46 //List of SoSeparator *, all cubes moved by the explosion
47 _movedCubes = new SoBaseList(dim - 1);
48 //List of Sotranslation *, used for animation
49 _movers = new SoBaseList(dim - 1);
50 //List of SoInterpolateVec3f, used for animation
51 _interpolators = new SoBaseList(dim - 1);
52 //List of SoOneShot *, used for animation
53 _timers = new SoBaseList(dim - 1);
55 //shape shared by all the cubes
56 _shape = new SoCube();
57 //trigger to invoke explosion method
58 _explodeSensor = new SoOneShotSensor();
59 //trigger to invoke implosion method
60 _implodeSensor = new SoOneShotSensor();
61 //matrix to have a direct acces to cubes by indexes
62 _graphMatrix = new SoSeparator*[dim * dim * dim];
64 _explodeSensor->setFunction(SceneGraph::explodeCube);
65 _explodeSensor->setData(this);
67 _implodeSensor->setFunction(SceneGraph::implodeCube);
68 _implodeSensor->setData(this);
70 _selector->policy = SoSelection::SINGLE;
71 _selector->renderCaching = SoSeparator::ON;
72 _selector->boundingBoxCaching = SoSeparator::ON;
73 _selector->renderCulling = SoSeparator::ON;
74 _selector->pickCulling = SoSeparator::ON;
76 _root->addChild(_light);
77 _root->addChild(_camera);
78 _root->addChild(_selector);
79 _selector->addChild(_fixedCubes);
81 SoShapeHints *hints = new SoShapeHints();
82 hints->vertexOrdering = SoShapeHints::COUNTERCLOCKWISE;
83 hints->shapeType = SoShapeHints::SOLID;
85 GUISettings settings;
86 QColor defaultColor = settings.defaultCubeColor();
87 //qDebug() << "Default cube color is:" << defaultColor << ".";
88 SbColor coincolor;
89 CubeRenderArea::convertColor(defaultColor).getRGB(coincolor);
91 for (int x = 0; x < dim; x++) {
92 for (int y = 0; y < dim; y++) {
93 for (int z = 0; z < dim; z++) {
94 SoSeparator *cubeInstance = new SoSeparator();
96 SoTranslation *cubeTranslation = new SoTranslation();
97 cubeTranslation->translation = SbVec3f(x * 3.0, y * 3.0, z * 3.0);
99 SoMaterial *cubeMaterial = new SoMaterial();
102 cubeMaterial->diffuseColor.setValue(coincolor);
103 cubeMaterial->shininess.setValue(0.2);
104 cubeMaterial->transparency.setValue(defaultColor.alphaF());
106 cubeInstance->addChild(cubeTranslation);
107 cubeInstance->addChild(cubeMaterial);
108 cubeInstance->addChild(hints);
109 cubeInstance->addChild(_shape);
111 _fixedCubes->addChild(cubeInstance);
113 _graphMatrix[x * dim * dim + y * dim + z] = cubeInstance;
119 SceneGraph::~SceneGraph()
121 delete _explodeSensor;
122 delete _implodeSensor;
124 // Destructor for the scene graph
125 _root->unref();
127 delete[] _graphMatrix;
129 delete _movedCubes;
130 delete _movers;
131 delete _timers;
132 delete _interpolators;
135 void SceneGraph::applyRotationToCamera(SbRotation rotation)
137 // Find global coordinates of focal point.
138 SbVec3f direction;
139 _camera->orientation.getValue().multVec(SbVec3f(0, 0, -1), direction);
140 SbVec3f focalpoint = _camera->position.getValue() + _camera->focalDistance.getValue() * direction;
142 // Set new orientation value by accumulating the new rotation.
143 _camera->orientation = rotation * _camera->orientation.getValue();
145 // Reposition camera so we are still pointing at the same old focal point.
146 _camera->orientation.getValue().multVec(SbVec3f(0, 0, -1), direction);
147 _camera->position = focalpoint - _camera->focalDistance.getValue() * direction;
149 //update CubeRenderArea::frontside/upside
151 int max = 0;
152 for (int i = 0; i < 3; i++) {
153 if (SoQtAbs(direction[i]) > SoQtAbs(direction[max])) {
154 max = i;
157 switch (max) {
158 case 0 : {
159 if (direction[max] < 0) {
160 _renderarea->setFrontside(CubeRenderArea::X_MINUS);
161 } else {
162 _renderarea->setFrontside(CubeRenderArea::X_PLUS);
164 break;
166 case 1 : {
167 if (direction[max] < 0) {
168 _renderarea->setFrontside(CubeRenderArea::Y_MINUS);
169 } else {
170 _renderarea->setFrontside(CubeRenderArea::Y_PLUS);
172 break;
174 case 2 : {
175 if (direction[max] < 0) {
176 _renderarea->setFrontside(CubeRenderArea::Z_MINUS);
177 } else {
178 _renderarea->setFrontside(CubeRenderArea::Z_PLUS);
180 break;
185 SbVec3f upside;
186 _camera->orientation.getValue().multVec(SbVec3f(0, 1, 0), upside);
187 int maxu = 0;
188 for (int i = 0; i < 3; i++) {
189 if (SoQtAbs(upside[i]) > SoQtAbs(upside[maxu])) {
190 maxu = i;
193 switch (maxu) {
194 case 0: {
195 if (upside[maxu] < 0) {
196 _renderarea->setUpside(CubeRenderArea::X_MINUS);
197 } else {
198 _renderarea->setUpside(CubeRenderArea::X_PLUS);
200 break;
202 case 1: {
203 if (upside[maxu] < 0) {
204 _renderarea->setUpside(CubeRenderArea::Y_MINUS);
205 } else {
206 _renderarea->setUpside(CubeRenderArea::Y_PLUS);
208 break;
210 case 2: {
211 if (upside[maxu] < 0) {
212 _renderarea->setUpside(CubeRenderArea::Z_MINUS);
213 } else {
214 _renderarea->setUpside(CubeRenderArea::Z_PLUS);
216 break;
219 qDebug() << "Rotation:" << _renderarea->frontside() << " " << _renderarea->upside();
220 return;
222 void SceneGraph::applyTranslationToCamera(int delta)
224 SbVec3f direction;
225 _camera->orientation.getValue().multVec(SbVec3f(0, 0, -1), direction);
226 SbVec3f oldpos = _camera->position.getValue();
227 SbVec3f newpos = oldpos + (delta) * - direction;
229 _camera->position = newpos;
230 _camera->focalDistance.setValue(_camera->focalDistance.getValue() + delta);
231 _camera->farDistance.setValue(_camera->farDistance.getValue() + delta);
233 return;
236 void SceneGraph::explodeCube(void *userdata, SoSensor *sensor)
238 //qDebug() << "Explosion sensor callback.";
239 Q_UNUSED(sensor);
240 SceneGraph *scene = (SceneGraph *) userdata;
241 scene->applyExplosionToCube(scene->desiredDirectionOfExplosion());
242 return;
245 void SceneGraph::implodeCube(void *userdata, SoSensor *sensor)
247 //qDebug() << "Implosion sensor callback.";
248 Q_UNUSED(sensor);
249 SceneGraph *scene = (SceneGraph *) userdata;
250 scene->applyImplosionToCube(scene->allImplosion());
251 return;
254 void SceneGraph::applyExplosionToCube(CubeRenderArea::ORIENTATION desired)
256 //qDebug() << "Apply EXPLOSION to cube.\nDesired direction : " << desired << ".\nCurrent direction : " << _directionOfExplosion << ".";
257 Q_ASSERT(_selectedCube);
258 SoTranslation *cursorPosition = static_cast<SoTranslation *>(_selectedCube->getChild(0));
260 if (desired != _directionOfExplosion) {
261 //clean lists and graph
262 //qDebug() << "New direction of explosion. Cleaning scene graph....done!";
263 _directionOfExplosion = CubeRenderArea::NO_ORIENTATION;
264 _explodedLevels = 0;
266 //qDebug() << "Lists size: " << _movedCubes->getLength() <<".";
268 for (int i = 0; i < _movedCubes->getLength(); i++) {
269 SoSeparator *oldGroup = static_cast<SoSeparator *>(_movedCubes->get(i));
270 SoChildList *cubeList = oldGroup->getChildren();
271 for (int j = 1; j < cubeList->getLength(); j++) {
272 _fixedCubes->addChild(static_cast<SoSeparator *>(cubeList->get(j)));
274 oldGroup->removeAllChildren();
275 _selector->removeChild(oldGroup);
278 _movedCubes->truncate(0);
279 _movers->truncate(0);
280 _interpolators->truncate(0);
281 _timers->truncate(0);
283 //Fix cube path in _selector
284 Point p(static_cast<int>(cursorPosition->translation.getValue()[0]) / 3, static_cast<int>(cursorPosition->translation.getValue()[1]) / 3, static_cast<int>(cursorPosition->translation.getValue()[2]) / 3);
285 _renderarea->selectCube(p);
287 _directionOfExplosion = desired;
290 //New Explosion to apply
292 //calculate number of levels to explode
294 int levelsToExplode = 0;
295 switch (_directionOfExplosion) {
296 case CubeRenderArea::X_PLUS : {
297 levelsToExplode = static_cast<int>(cursorPosition->translation.getValue()[0]) / 3 - _explodedLevels;
298 break;
300 case CubeRenderArea::X_MINUS : {
301 levelsToExplode = _dim - static_cast<int>(cursorPosition->translation.getValue()[0]) / 3 - _explodedLevels - 1;
302 break;
304 case CubeRenderArea::Y_PLUS : {
305 levelsToExplode = static_cast<int>(cursorPosition->translation.getValue()[1]) / 3 - _explodedLevels;
306 break;
308 case CubeRenderArea::Y_MINUS : {
309 levelsToExplode = _dim - static_cast<int>(cursorPosition->translation.getValue()[1]) / 3 - _explodedLevels - 1;
310 break;
312 case CubeRenderArea::Z_PLUS : {
313 levelsToExplode = static_cast<int>(cursorPosition->translation.getValue()[2]) / 3 - _explodedLevels;
314 break;
316 case CubeRenderArea::Z_MINUS : {
317 levelsToExplode = _dim - static_cast<int>(cursorPosition->translation.getValue()[2]) / 3 - _explodedLevels - 1;
318 break;
320 default : {
321 break;
324 //qDebug() << "Need to explode " << levelsToExplode << " levels.";
326 //call explodeLevel() n times to explode n levels
327 for (int i = 0; i < levelsToExplode; i++) {
328 this->explodeLevel();
331 if (_directionOfExplosion != CubeRenderArea::NO_ORIENTATION) {
332 _renderarea->setIsExploded(true);
334 return;
336 void SceneGraph::applyImplosionToCube(bool all)
338 //qDebug() << "Apply IMPLOSION to cube.\nBoolean is: " << all << ".";
340 int levelsToImplode = 0;
342 if (all) {
343 levelsToImplode = _explodedLevels;
344 _renderarea->setIsExploded(false);
345 } else {
346 SoTranslation *cursorPosition = static_cast<SoTranslation *>(_selectedCube->getChild(0));
348 switch (_directionOfExplosion) {
349 case CubeRenderArea::X_PLUS : {
350 levelsToImplode = _explodedLevels - static_cast<int>(cursorPosition->translation.getValue()[0]) / 3;
351 break;
353 case CubeRenderArea::X_MINUS : {
354 levelsToImplode = _explodedLevels - _dim + 1 + static_cast<int>(cursorPosition->translation.getValue()[0]) / 3;
355 break;
357 case CubeRenderArea::Y_PLUS : {
358 levelsToImplode = _explodedLevels - static_cast<int>(cursorPosition->translation.getValue()[1]) / 3;
359 break;
361 case CubeRenderArea::Y_MINUS : {
362 levelsToImplode = _explodedLevels - _dim + 1 + static_cast<int>(cursorPosition->translation.getValue()[1]) / 3;
363 break;
365 case CubeRenderArea::Z_PLUS : {
366 levelsToImplode = _explodedLevels - static_cast<int>(cursorPosition->translation.getValue()[2]) / 3;
367 break;
369 case CubeRenderArea::Z_MINUS : {
370 levelsToImplode = _explodedLevels - _dim + 1 + static_cast<int>(cursorPosition->translation.getValue()[2]) / 3;
371 break;
373 case CubeRenderArea::NO_ORIENTATION : {
374 qDebug() << "Error: Cannot apply Implosion with _directionOfExplosion == NO_ORIENTATION.";
375 break;
380 //qDebug() << "Need to implode " << levelsToImplode << " levels.";
382 for (int i = 0; i < levelsToImplode;i++) {
383 this->implodeLevel();
386 return;
389 void SceneGraph::explodeLevel()
391 _explodedLevels++;
392 if (_explodedLevels - 1 < _movedCubes->getLength()) {
393 //qDebug() << "Restore old explosion for level: " << _explodedLevels-1 << ".";
395 SoInterpolateVec3f *levelInterpolator = static_cast<SoInterpolateVec3f *>(_interpolators->get(_explodedLevels - 1));
396 SoOneShot *levelTimer = static_cast<SoOneShot *>(_timers->get(_explodedLevels - 1));
397 levelInterpolator->input1 = levelInterpolator->input0;
398 levelInterpolator->input0 = SbVec3f(0, 0, 0);
399 levelTimer->trigger.touch();
401 } else {
402 //qDebug() << "New explosion for level: " << _explodedLevels - 1 << ".";
404 SoGroup *newGroup = new SoSeparator();
405 SoTranslation *newMover = new SoTranslation();
406 SoInterpolateVec3f *newInterpolator = new SoInterpolateVec3f();
407 SoOneShot *newTimer = new SoOneShot();
409 _movedCubes->append(newGroup);
410 _movers->append(newMover);
411 _interpolators->append(newInterpolator);
412 _timers->append(newTimer);
414 _selector->addChild(newGroup);
415 newGroup->addChild(newMover);
416 newMover->translation.connectFrom(&newInterpolator->output);
417 newInterpolator->input0 = SbVec3f(0, 0, 0);
418 newInterpolator->alpha.connectFrom(&newTimer->ramp);
419 newTimer->flags = SoOneShot::HOLD_FINAL;
422 SbVec3f targetPosition = SbVec3f(0, 0, 0);
423 for (int i = 0; i < _dim; i++) {
424 for (int j = 0; j < _dim; j++) {
425 switch (_directionOfExplosion) {
426 case CubeRenderArea::X_PLUS : {
427 qDebug() << "Explosion: " << _explodedLevels - 1 << " " << i << " " << j << " selected for move.";
429 SoSeparator *cubeInstance = _graphMatrix[(_explodedLevels-1) * _dim * _dim + i * _dim + j];
430 newGroup->addChild(cubeInstance);
431 _fixedCubes->removeChild(cubeInstance);
433 targetPosition = SbVec3f(0, 0, _dim * 3);
434 break;
436 case CubeRenderArea::X_MINUS : {
437 qDebug() << "Explosion: " << _dim - _explodedLevels << " " << i << " " << j << " selected for move.";
439 SoSeparator *cubeInstance = _graphMatrix[(_dim-_explodedLevels) * _dim * _dim + i * _dim + j];
440 newGroup->addChild(cubeInstance);
441 _fixedCubes->removeChild(cubeInstance);
443 targetPosition = SbVec3f(0, 0, -_dim * 3);
444 break;
446 case CubeRenderArea::Y_PLUS : {
447 qDebug() << "Explosion: " << i << " " << _explodedLevels - 1 << " " << j << " selected for move.";
449 SoSeparator *cubeInstance = _graphMatrix[i * _dim * _dim + (_explodedLevels-1) * _dim + j];
450 newGroup->addChild(cubeInstance);
451 _fixedCubes->removeChild(cubeInstance);
453 targetPosition = SbVec3f(_dim * 3, 0, 0);
454 break;
456 case CubeRenderArea::Y_MINUS : {
457 qDebug() << "Explosion: " << i << " " << _dim - _explodedLevels << " " << j << " selected for move.";
459 SoSeparator *cubeInstance = _graphMatrix[i * _dim * _dim + (_dim-_explodedLevels) * _dim + j];
460 newGroup->addChild(cubeInstance);
461 _fixedCubes->removeChild(cubeInstance);
463 targetPosition = SbVec3f(-_dim * 3, 0, 0);
464 break;
466 case CubeRenderArea::Z_PLUS : {
467 qDebug() << "Explosion: " << j << " " << i << " " << _explodedLevels - 1 << " selected for move.";
469 SoSeparator *cubeInstance = _graphMatrix[j * _dim * _dim + i * _dim + _explodedLevels-1];
470 newGroup->addChild(cubeInstance);
471 _fixedCubes->removeChild(cubeInstance);
473 targetPosition = SbVec3f(_dim * 3, 0, 0);
474 break;
476 case CubeRenderArea::Z_MINUS : {
477 qDebug() << "Explosion: " << j << " " << i << " " << _dim - _explodedLevels << " selected for move.";
479 SoSeparator *cubeInstance = _graphMatrix[j * _dim * _dim + i * _dim + _dim-_explodedLevels];
480 newGroup->addChild(cubeInstance);
481 _fixedCubes->removeChild(cubeInstance);
483 targetPosition = SbVec3f(-_dim * 3, 0, 0);
484 break;
486 case CubeRenderArea::NO_ORIENTATION : {
487 qDebug() << "Error: Cannot apply Explosion with frontside == NO_ORIENTATION.";
488 break;
493 //FIX ME:
494 //target position is not upside dependent.
495 //not so pretty...
496 newInterpolator->input1 = targetPosition;
498 //Start animation
499 newTimer->trigger.touch();
501 //qDebug() << "Explosion for level " << _explodedLevels - 1 << "done.";
502 return;
505 void SceneGraph::implodeLevel()
507 //qDebug() << "Implosion for level " << _explodedLevels -1 << ".";
508 _explodedLevels--;
509 SoInterpolateVec3f *levelInterpolator = static_cast<SoInterpolateVec3f *>(_interpolators->get(_explodedLevels));
510 SoOneShot *levelTimer = static_cast<SoOneShot *>(_timers->get(_explodedLevels));
511 levelInterpolator->input0 = levelInterpolator->input1;
512 levelInterpolator->input1 = SbVec3f(0, 0, 0);
513 levelTimer->trigger.touch();
514 return;
517 CubeRenderArea *SceneGraph::renderarea()
519 return _renderarea;
521 SoSeparator *SceneGraph::root()
523 return _root;
525 SoCamera *SceneGraph::camera()
527 return _camera;
529 SoSelection *SceneGraph::selector()
531 return _selector;
533 SoGroup *SceneGraph::fixedCubes()
535 return _fixedCubes;
537 SoBaseList *SceneGraph::movedCubes()
539 return _movedCubes;
541 SoShape *SceneGraph::shape()
543 return _shape;
545 SoBaseList *SceneGraph::movers()
547 return _movers;
549 SoBaseList *SceneGraph::interpolators()
551 return _interpolators;
553 SoBaseList *SceneGraph::timers()
555 return _timers;
557 SoOneShotSensor *SceneGraph::explodeSensor()
559 return _explodeSensor;
561 SoOneShotSensor *SceneGraph::implodeSensor()
563 return _implodeSensor;
565 SoSeparator **SceneGraph::graphMatrix()
567 return _graphMatrix;
569 SoSeparator *SceneGraph::selectedCube()
571 return _selectedCube;
573 CubeRenderArea::ORIENTATION SceneGraph::directionOfExplosion()
575 return _directionOfExplosion;
577 CubeRenderArea::ORIENTATION SceneGraph::desiredDirectionOfExplosion()
579 return _desiredDirectionOfExplosion;
581 bool SceneGraph::allImplosion()
583 return _allImplosion;
585 int SceneGraph::explodedLevels()
587 return _explodedLevels;
590 void SceneGraph::setSelectedCube(SoSeparator *cube)
592 _selectedCube = cube;
593 return;
595 void SceneGraph::setDirectionOfExplosion(CubeRenderArea::ORIENTATION direction)
597 _directionOfExplosion = direction;
598 return;
600 void SceneGraph::setDesiredDirectionOfExplosion(CubeRenderArea::ORIENTATION direction)
602 _desiredDirectionOfExplosion = direction;
603 return;
605 void SceneGraph::setAllImplosion(bool value)
607 _allImplosion = value;
608 return;
610 void SceneGraph::setExplodedLevels(int num)
612 _explodedLevels = num;
613 return;