TDME2  1.9.200
SceneEditorTabView.cpp
Go to the documentation of this file.
2 
3 #include <memory>
4 #include <string>
5 #include <unordered_set>
6 
7 #include <tdme/tdme.h>
8 #include <tdme/audio/Audio.h>
13 #include <tdme/engine/Color4.h>
21 #include <tdme/engine/Camera.h>
22 #include <tdme/engine/Engine.h>
25 #include <tdme/engine/Light.h>
26 #include <tdme/engine/Object.h>
28 #include <tdme/engine/Timing.h>
32 #include <tdme/gui/GUI.h>
33 #include <tdme/gui/GUIParser.h>
42 #include <tdme/utilities/Action.h>
44 #include <tdme/utilities/Console.h>
46 #include <tdme/utilities/Float.h>
48 
49 using std::make_unique;
50 using std::string;
51 using std::to_string;
52 using std::unique_ptr;
53 using std::unordered_set;
54 
56 
57 using tdme::audio::Audio;
81 using tdme::gui::GUI;
96 
97 SceneEditorTabView::SceneEditorTabView(EditorView* editorView, const string& tabId, Scene* scene): Gizmo(nullptr, "le")
98 {
99  this->editorView = editorView;
100  this->tabId = tabId;
101  this->popUps = editorView->getPopUps();
102  engine = unique_ptr<Engine>(Engine::createOffScreenInstance(512, 512, true, true, true));
103  engine->setSceneColor(Color4(39.0f / 255.0f, 39.0f / 255.0f, 39.0f / 255.0f, 1.0f));
104  engine->setSkyShaderEnabled(true);
105  this->scene = unique_ptr<Scene>(scene);
106  this->cameraInputHandler = make_unique<CameraInputHandler>(engine.get(), this);
107  this->keyControl = false;
108  this->keyShift = false;
109  this->keyEscape = false;
110  this->placeEntityYRotation = 0;
113  this->mouseDragging = false;
114  this->pasteMode = false;
115  this->pasteModeValid = false;
116  this->placeEntityMode = false;
117  this->placeEntityValid = false;
118  this->snappingX = 0.0f;
119  this->snappingZ = 0.0f;
120  this->snappingEnabled = false;
121  this->gridEnabled = false;
122  this->gridY = 0.0f;
123  this->gridModel = unique_ptr<Model>(Tools::createGridModel());
124 
125  //
126  setEngine(engine.get());
127  updateLights();
128 
129  //
130  entityColors["red"] = EntityColor(1.5f, 0.8f, 0.8f, 0.5f, 0.0f, 0.0f);
131  entityColors["green"] = EntityColor(0.8f, 1.5f, 0.8f, 0.0f, 0.5f, 0.0f);
132  entityColors["blue"] = EntityColor(0.8f, 0.8f, 1.5f, 0.0f, 0.0f, 0.5f);
133  entityColors["yellow"] = EntityColor(1.5f, 1.5f, 0.8f, 0.5f, 0.5f, 0.0f);
134  entityColors["magenta"] = EntityColor(1.5f, 0.8f, 1.5f, 0.5f, 0.0f, 0.5f);
135  entityColors["cyan"] = EntityColor(0.8f, 1.5f, 1.5f, 0.0f, 0.5f, 0.5f);
136  entityColors["none"] = EntityColor(1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f);
137 
138  //
139  {
140  // entity picking filter for no grid
141  class PrototypePickingFilterNoGrid: public virtual EntityPickingFilter
142  {
143  public:
144  bool filterEntity(Entity* entity) override {
145  return entity->getId() != "tdme.sceneeditor.grid";
146  }
147 
148  /**
149  * Public constructor
150  * @param SceneEditorTabView scene editor tab view
151  */
152  PrototypePickingFilterNoGrid(SceneEditorTabView* sceneEditorTabView): sceneEditorTabView(sceneEditorTabView) {
153  }
154 
155  private:
156  SceneEditorTabView* sceneEditorTabView;
157  };
158  //
159  entityPickingFilterNoGrid = make_unique<PrototypePickingFilterNoGrid>(this);
160  }
161 
162  //
163  {
164  // entity picking filter for no placing object
165  class PrototypePickingFilterPlacing: public virtual EntityPickingFilter
166  {
167  public:
168  bool filterEntity(Entity* entity) override {
169  return
170  entity->getId() != "tdme.sceneeditor.placeentity" &&
171  StringTools::startsWith(entity->getId(), "tdme.sceneeditor.paste.") == false &&
172  StringTools::startsWith(entity->getId(), "le.tdme.gizmo.") == false;
173  }
174 
175  /**
176  * Public constructor
177  * @param sceneEditorTabView scene editor tab view
178  */
179  PrototypePickingFilterPlacing(SceneEditorTabView* sceneEditorTabView): sceneEditorTabView(sceneEditorTabView) {
180  }
181 
182  private:
183  SceneEditorTabView* sceneEditorTabView;
184  };
185  //
186  entityPickingFilterPlacing = make_unique<PrototypePickingFilterPlacing>(this);
187  }
188 
189  //
191 }
192 
194 }
195 
197 {
198  // if scene is running, no not do HID input except camera
199  if (applicationClient != nullptr) {
200  auto gui = engine->getGUI();
201  // handle events in GUI
202  gui->handleEvents(false);
203  // forward HID to logics
204  applicationClient->handleHIDEvents(gui->getMouseEvents(), gui->getKeyboardEvents());
205  // clear events
206  gui->getMouseEvents().clear();
207  gui->getKeyboardEvents().clear();
208  //
209  return;
210  }
211 
212  //
213  auto keyControlX = false;
214  auto keyControlC = false;
215  auto keyControlV = false;
216  auto keyDelete = false;
217  for (auto& event: engine->getGUI()->getKeyboardEvents()) {
218  if (event.isProcessed() == true) continue;
219  if (event.getType() == GUIKeyboardEvent::KEYBOARDEVENT_KEY_TYPED) continue;
220  auto isKeyDown = event.getType() == GUIKeyboardEvent::KEYBOARDEVENT_KEY_PRESSED;
221  if (event.getKeyCode() == KEYBOARD_KEYCODE_LEFT_SHIFT) {
222  keyShift = isKeyDown;
223  event.setProcessed(true);
224  }
225  if (event.getKeyCode() == KEYBOARD_KEYCODE_LEFT_CTRL) {
226  keyControl = isKeyDown;
227  event.setProcessed(true);
228  }
229  if (event.getKeyCode() == GUIKeyboardEvent::KEYCODE_ESCAPE) {
230  keyEscape = isKeyDown;
231  event.setProcessed(true);
232  }
233  if (event.getKeyCode() == GUIKeyboardEvent::KEYCODE_BACKSPACE ||
234  event.getKeyCode() == GUIKeyboardEvent::KEYCODE_DELETE) {
235  keyDelete = isKeyDown;
236  event.setProcessed(true);
237  }
238  // determine cut, copy, paste
239  if (Character::toLowerCase(event.getKeyChar()) == 'x' && keyControl == true) {
240  keyControlX = isKeyDown;
241  event.setProcessed(true);
242  }
243  if (Character::toLowerCase(event.getKeyChar()) == 'c' && keyControl == true) {
244  keyControlC = isKeyDown;
245  event.setProcessed(true);
246  }
247  if (Character::toLowerCase(event.getKeyChar()) == 'v' && keyControl == true) {
248  keyControlV = isKeyDown;
249  event.setProcessed(true);
250  }
251  // handle them
252  if (Character::toLowerCase(event.getKeyChar()) == '.' && !isKeyDown == false) {
254  event.setProcessed(true);
255  }
256  if (Character::toLowerCase(event.getKeyChar()) == ',' && !isKeyDown == false) {
258  event.setProcessed(true);
259  }
260  if (Character::toLowerCase(event.getKeyChar()) == '1' && isKeyDown == true) {
262  updateGizmo();
263  event.setProcessed(true);
264  }
265  if (Character::toLowerCase(event.getKeyChar()) == '2' && isKeyDown == true) {
267  updateGizmo();
268  event.setProcessed(true);
269  }
270  if (Character::toLowerCase(event.getKeyChar()) == '3' && isKeyDown == true) {
272  updateGizmo();
273  event.setProcessed(true);
274  }
275  if (Character::toLowerCase(event.getKeyChar()) == '4' && isKeyDown == true) {
277  updateGizmo();
278  event.setProcessed(true);
279  }
280  }
281  for (auto& event: engine->getGUI()->getMouseEvents()) {
282  if ((event.getType() == GUIMouseEvent::MOUSEEVENT_MOVED ||
283  event.getType() == GUIMouseEvent::MOUSEEVENT_DRAGGED) &&
284  event.getXUnscaled() >= 0 &&
285  event.getYUnscaled() >= 0) {
286  placeEntityMouseX = event.getXUnscaled();
287  placeEntityMouseY = event.getYUnscaled();
288  }
289 
290  if (event.isProcessed() == true) continue;
291 
292  if (event.getButton() == MOUSE_BUTTON_LEFT) {
293  if (event.getType() == GUIMouseEvent::MOUSEEVENT_DRAGGED) {
294  if (mouseDragging == false) {
295  mouseDragging = true;
296  mouseDraggingLastEntity = nullptr;
297  event.setProcessed(true);
298  }
299  } else {
300  if (mouseDragging == true) {
301  mouseDragging = false;
302  mouseDraggingLastEntity = nullptr;
303  event.setProcessed(true);
304  }
305  }
306  }
307  if (event.getButton() == MOUSE_BUTTON_LEFT) {
308  if (event.getType() == GUIMouseEvent::MOUSEEVENT_RELEASED) {
309  if (pasteMode == true && pasteModeValid == true) {
310  pasteEntities(false);
311  if (keyShift == false) unsetPasteMode();
312  } else
313  if (placeEntityMode == true && placeEntityValid == true) {
314  placeEntity();
315  if (keyShift == false) unsetPlaceEntityMode(false);
316  } else
317  if (getGizmoMode() != GIZMOMODE_NONE) {
318  for (const auto& selectedEntityId: selectedEntityIds) {
319  auto _selectedEntity = engine->getEntity(selectedEntityId);
320  if (_selectedEntity == nullptr) continue;
321  auto sceneEntity = scene->getEntity(_selectedEntity->getId());
322  if (sceneEntity == nullptr) continue;
323  auto rotationEuler = _selectedEntity->getRotationsQuaternion().computeMatrix().computeEulerAngles();
324  _selectedEntity->setRotationAngle(scene->getRotationOrder()->getAxisXIndex(), rotationEuler[0]);
325  _selectedEntity->setRotationAngle(scene->getRotationOrder()->getAxisYIndex(), rotationEuler[1]);
326  _selectedEntity->setRotationAngle(scene->getRotationOrder()->getAxisZIndex(), rotationEuler[2]);
327  while (_selectedEntity->getRotationCount() > 3) _selectedEntity->removeRotation(_selectedEntity->getRotationCount() - 1);
328  _selectedEntity->update();
329  sceneEntity->getTransform().setTransform(_selectedEntity->getTransform());
330  }
332  updateGizmo();
333  }
334  event.setProcessed(true);
335  } else
336  if (placeEntityMode == false) {
337  Node* selectedEntityNode = nullptr;
338  Entity* selectedEntity = nullptr;
339  if (getGizmoMode() == GIZMOMODE_NONE) selectedEntity = engine->getEntityByMousePosition(event.getXUnscaled(), event.getYUnscaled(), entityPickingFilterNoGrid.get(), &selectedEntityNode);
340  if (mouseDragging == true) {
341  Vector3 deltaTranslation;
342  Vector3 deltaRotation;
343  Vector3 absoluteScale;
344  if (determineGizmoDeltaTransformations(event.getXUnscaled(), event.getYUnscaled(), deltaTranslation, deltaRotation, absoluteScale) == true) {
345  auto gizmoEntity = getGizmoObject();
346  if (gizmoEntity != nullptr) {
347  for (const auto& selectedEntityId: selectedEntityIds) {
348  auto _selectedEntity = engine->getEntity(selectedEntityId);
349  if (_selectedEntity != nullptr && StringTools::startsWith(_selectedEntity->getId(), "tdme.sceneeditor.") == false) {
350  auto sceneEntity = scene->getEntity(_selectedEntity->getId());
351  if (sceneEntity == nullptr) continue;
352  _selectedEntity->setTranslation(_selectedEntity->getTransform().getTranslation().clone().add(deltaTranslation));
353  auto scale = _selectedEntity->getScale().clone().scale(absoluteScale);
354  if (Math::abs(scale.getX()) < 0.01f) scale.setX(Math::sign(scale.getX()) * 0.01f);
355  if (Math::abs(scale.getY()) < 0.01f) scale.setY(Math::sign(scale.getY()) * 0.01f);
356  if (Math::abs(scale.getZ()) < 0.01f) scale.setZ(Math::sign(scale.getZ()) * 0.01f);
357  if (Math::abs(scale.getX()) > 100.0f) scale.setX(Math::sign(scale.getX()) * 100.0f);
358  if (Math::abs(scale.getY()) > 100.0f) scale.setY(Math::sign(scale.getY()) * 100.0f);
359  if (Math::abs(scale.getZ()) > 100.0f) scale.setZ(Math::sign(scale.getZ()) * 100.0f);
360  _selectedEntity->setScale(scale);
361  if ((sceneEntity->getPrototype()->getType()->getGizmoTypeMask() & Gizmo::GIZMOTYPE_ROTATE) == Gizmo::GIZMOTYPE_ROTATE &&
362  deltaRotation.computeLengthSquared() > Math::square(Math::EPSILON) * 3.0f) {
363  if (_selectedEntity->getRotationCount() == 3) {
364  _selectedEntity->addRotation(scene->getRotationOrder()->getAxis0(), 0.0f);
365  _selectedEntity->addRotation(scene->getRotationOrder()->getAxis1(), 0.0f);
366  _selectedEntity->addRotation(scene->getRotationOrder()->getAxis2(), 0.0f);
367  }
368  _selectedEntity->setRotationAngle(3 + scene->getRotationOrder()->getAxisXIndex(), _selectedEntity->getRotationAngle(3 + scene->getRotationOrder()->getAxisXIndex()) + deltaRotation[0]);
369  _selectedEntity->setRotationAngle(3 + scene->getRotationOrder()->getAxisYIndex(), _selectedEntity->getRotationAngle(3 + scene->getRotationOrder()->getAxisYIndex()) + deltaRotation[1]);
370  _selectedEntity->setRotationAngle(3 + scene->getRotationOrder()->getAxisZIndex(), _selectedEntity->getRotationAngle(3 + scene->getRotationOrder()->getAxisZIndex()) + deltaRotation[2]);
371  }
372  _selectedEntity->update();
373  }
374  }
375  if (selectedEntityIds.size() == 1) {
376  auto _selectedEntity = engine->getEntity(selectedEntityIds[0]);
377  if (_selectedEntity != nullptr) {
378  sceneEditorTabController->updateEntityDetails(_selectedEntity->getTransform());
379  setGizmoRotation(_selectedEntity->getTransform());
380  }
381  } else {
382  multipleSelectionTranslation+= deltaTranslation;
383  multipleSelectionRotation+= deltaRotation;
384  multipleSelectionScale = absoluteScale;
386  }
387  }
388  if (Math::abs(deltaTranslation.getX()) > Math::EPSILON ||
389  Math::abs(deltaTranslation.getY()) > Math::EPSILON ||
390  Math::abs(deltaTranslation.getZ()) > Math::EPSILON) {
391  updateGizmo();
392  }
393  }
394  } else
395  if (determineGizmoMode(selectedEntity, selectedEntityNode) == true) {
396  // no op
397  } else {
398  if (selectedEntity != nullptr && scene->getEntity(selectedEntity->getId()) == nullptr) selectedEntity = nullptr;
399  if (keyControl == false) {
400  vector<Entity*> entitiesToRemove;
401  for (const auto& selectedEntityId: selectedEntityIds) {
402  auto selectedEntity = engine->getEntity(selectedEntityId);
403  if (mouseDragging == true && mouseDraggingLastEntity == selectedEntity) {
404  // no op
405  } else {
406  if (selectedEntity != nullptr) entitiesToRemove.push_back(selectedEntity);
407  }
408  }
409  for (const auto& entityToRemove: entitiesToRemove) {
410  selectedEntityIds.erase(remove(selectedEntityIds.begin(), selectedEntityIds.end(), entityToRemove->getId()), selectedEntityIds.end());
411  auto selectedEntitiyIdByIdIt = selectedEntityIdsById.find(entityToRemove->getId());
412  if (selectedEntitiyIdByIdIt != selectedEntityIdsById.end()) {
413  selectedEntityIdsById.erase(selectedEntitiyIdByIdIt);
414  }
415  sceneEditorTabController->unselectEntity(entityToRemove->getId());
416  resetEntity(entityToRemove);
417  }
418  }
419  if (selectedEntity != nullptr) {
420  if (selectedEntityIdsById.find(selectedEntity->getId()) == selectedEntityIdsById.end()) {
421  selectEntityInternal(selectedEntity);
422  selectedEntityIds.push_back(selectedEntity->getId());
423  selectedEntityIdsById.insert(selectedEntity->getId());
424  sceneEditorTabController->selectEntity(selectedEntity->getId());
425  } else {
426  resetEntity(selectedEntity);
427  selectedEntityIds.erase(remove(selectedEntityIds.begin(), selectedEntityIds.end(), selectedEntity->getId()), selectedEntityIds.end());
428  auto selectedEntityIdsByIdIt = selectedEntityIdsById.find(selectedEntity->getId());
429  if (selectedEntityIdsByIdIt != selectedEntityIdsById.end()) {
430  selectedEntityIdsById.erase(selectedEntityIdsByIdIt);
431  }
432  sceneEditorTabController->unselectEntity(selectedEntity->getId());
433  }
434  if (selectedEntityIds.size() == 1) {
435  auto sceneEntity = scene->getEntity(selectedEntity->getId());
436  if (sceneEntity != nullptr && sceneEntity->getPrototype()->getType()->hasNonEditScaleDownMode() == true) {
437  selectedEntity->setTransform(sceneEntity->getTransform());
438  }
439  setGizmoRotation(selectedEntity->getTransform());
440  sceneEditorTabController->setEntityDetails(selectedEntity->getId());
441  } else
442  if (selectedEntityIds.size() > 1) {
445  multipleSelectionRotation.set(0.0f, 0.0f, 0.0f);
446  multipleSelectionScale.set(1.0f, 1.0f, 1.0f);
448  }
449  }
450  mouseDraggingLastEntity = selectedEntity;
451  updateGizmo();
452  }
453  event.setProcessed(true);
454  }
455  }
456  }
457  if (keyDelete == true) {
458  removeGizmo();
459  removeEntities();
460  }
461  if (keyControlX == true) {
462  removeGizmo();
463  copyEntities();
464  removeEntities();
465  }
466  if (keyControlC == true) {
467  copyEntities();
468  }
469  if (keyControlV == true) {
470  removeGizmo();
471  setPasteMode();
472  }
473 
474  //
475  cameraInputHandler->handleInputEvents();
476 }
477 
479 {
480  // if scene is running, no not do HID input except camera
481  if (applicationClient != nullptr) {
482  //
483  sceneEditorTabController->updateInfoText(MutableString(engine->getTiming()->getAvarageFPS()).append(" FPS"));
484  //
485  applicationClient->update();
486  engine->display();
487  engine->getGUI()->render();
488  //
489  return;
490  }
491 
492  //
493  if ((placeEntityMode == true || pasteMode == true) && keyEscape == true) {
495  unsetPasteMode();
496  keyEscape = false;
497  }
498 
499  {
500  auto selectedEngineEntity = engine->getEntity("tdme.sceneeditor.placeentity");
501  Vector3 worldCoordinate;
502  placeEntityValid = false;
503  pasteModeValid = false;
504  if ((placeEntityMode == true || pasteMode == true) && engine->getEntityByMousePosition(placeEntityMouseX, placeEntityMouseY, worldCoordinate, entityPickingFilterPlacing.get()) != nullptr) {
505  if (placeEntityMode == true) {
506  Transform transform;
507  transform.setTranslation(worldCoordinate);
508  transform.addRotation(scene->getRotationOrder()->getAxis0(), 0.0f);
509  transform.addRotation(scene->getRotationOrder()->getAxis1(), 0.0f);
510  transform.addRotation(scene->getRotationOrder()->getAxis2(), 0.0f);
511  transform.update();
512  if (selectedEngineEntity == nullptr && selectedPrototype != nullptr) {
513  selectedEngineEntity = createEntity(selectedPrototype, "tdme.sceneeditor.placeentity", transform);
514  if (selectedEngineEntity != nullptr) engine->addEntity(selectedEngineEntity);
515  }
516  if (selectedEngineEntity != nullptr) {
517  if (snappingEnabled == true && (snappingX > Math::EPSILON || snappingZ > Math::EPSILON)) {
518  if (snappingX > Math::EPSILON) worldCoordinate.setX(static_cast<int>(worldCoordinate.getX() / snappingX) * snappingX);
519  if (snappingZ > Math::EPSILON) worldCoordinate.setZ(static_cast<int>(worldCoordinate.getZ() / snappingZ) * snappingZ);
520  Vector3 snappedWorldCoordinate;
521  if (engine->doRayCasting(worldCoordinate.clone().setY(10000.0f), worldCoordinate.clone().setY(-10000.0f), snappedWorldCoordinate, entityPickingFilterPlacing.get()) != nullptr) {
522  worldCoordinate = snappedWorldCoordinate;
523  }
524  }
525  transform.setTranslation(worldCoordinate);
526  transform.setRotationAngle(scene->getRotationOrder()->getAxisYIndex(), static_cast<float>(placeEntityYRotation) * 90.0f);
527  transform.update();
528  selectedEngineEntity->setTransform(transform);
530  placeEntityValid = true;
531  }
532  } else
533  if (pasteMode == true) {
534  if (snappingEnabled == true && (snappingX > Math::EPSILON || snappingZ > Math::EPSILON)) {
535  if (snappingX > Math::EPSILON) worldCoordinate.setX(static_cast<int>(worldCoordinate.getX() / snappingX) * snappingX);
536  if (snappingZ > Math::EPSILON) worldCoordinate.setZ(static_cast<int>(worldCoordinate.getZ() / snappingZ) * snappingZ);
537  Vector3 snappedWorldCoordinate;
538  if (engine->doRayCasting(worldCoordinate.clone().setY(10000.0f), worldCoordinate.clone().setY(-10000.0f), snappedWorldCoordinate, entityPickingFilterPlacing.get()) != nullptr) {
539  worldCoordinate = snappedWorldCoordinate;
540  }
541  }
542  placeEntityTranslation = worldCoordinate;
543  pasteModeValid = true;
544  pasteEntities(true);
545  }
546  }
547  }
548 
549  //
550  updateGrid();
551 
552  //
553  sceneEditorTabController->updateInfoText(MutableString(engine->getTiming()->getAvarageFPS()).append(" FPS"));
554 
555  //
556  engine->display();
557 
558  //
559  if (needsGizmoUpdate == true) {
560  updateGizmo();
561  needsGizmoUpdate = false;
562  }
563 }
564 
566 {
567  try {
568  sceneEditorTabController = make_unique<SceneEditorTabController>(this);
570  } catch (Exception& exception) {
571  Console::println("SceneEditorTabView::initialize(): An error occurred: " + string(exception.what()));
572  }
573  //
574  SceneConnector::setLights(engine.get(), scene.get());
575  SceneConnector::addScene(engine.get(), scene.get(), true, true, true, true, true);
576  cameraInputHandler->setSceneCenter(scene->getCenter());
579  updateGrid();
580  // TODO: load settings
581 }
582 
584 {
585  shutdownScene();
586  engine->dispose();
587 }
588 
590 }
591 
593  return engine.get();
594 }
595 
598  sceneEditorTabController->setOutlinerAddDropDownContent();
599  sceneEditorTabController->setOutlinerContent();
602 }
603 
607 }
608 
610  const auto& skyShaderParameters = scene->getSkyShaderParameters();
611  for (const auto& parameterName: Engine::getShaderParameterNames("sky")) {
612  engine->setShaderParameter("sky", parameterName, skyShaderParameters.getShaderParameter(parameterName));
613  }
614 }
615 
617  //
618  engine->resetPostProcessingPrograms();
619  //
620  for (const auto& shaderId: Engine::getRegisteredShader(Engine::SHADERTYPE_POSTPROCESSING, false)) {
621  //
622  if (scene->isPostProcessingShaderEnabled(shaderId) == true) {
623  engine->addPostProcessingProgram(shaderId);
624  }
625  //
626  for (const auto& parameterName: Engine::getShaderParameterNames(shaderId)) {
627  //
628  auto parameterDefaults = Engine::getDefaultShaderParameter(shaderId, parameterName);
629  if (parameterDefaults == nullptr) {
630  continue;
631  }
632  //
633  auto shaderParameters = scene->getPostProcessingShaderParameters(shaderId);
634  if (shaderParameters == nullptr) {
635  continue;
636  }
637  //
638  engine->setShaderParameter(shaderId, parameterName, shaderParameters->getShaderParameter(parameterName));
639  }
640  }
641 }
642 
644  //
645  SceneConnector::resetEngine(engine.get(), scene.get());
646  //
647  keyControl = false;
648  keyShift = false;
649  keyEscape = false;
650 
651  placeEntityMode = false;
652  placeEntityValid = false;
653  mouseDragging = false;
654  mouseDraggingLastEntity = nullptr;
655 
656  pasteMode = false;
657  pasteModeValid = false;
658 
659  selectedPrototype = nullptr;
660  selectedEntityIds.clear();
661  selectedEntityIdsById.clear();
662  copiedEntities.clear();
663 }
664 
666  clearScene();
667  SceneConnector::addScene(engine.get(), scene.get(), true, true, true, true, true);
668 }
669 
671  sceneEditorTabController->setOutlinerContent();
673 }
674 
675 void SceneEditorTabView::reloadOutliner(const string& outlinerNode) {
676  sceneEditorTabController->setOutlinerContent();
679 }
680 
682  needsGizmoUpdate = true;
683 }
684 
686  needsGizmoUpdate = true;
687 }
688 
690  needsGizmoUpdate = true;
691 }
692 
694  SceneConnector::setLights(engine.get(), scene.get());
695 }
696 
698 {
699  auto sceneEntity = scene->getEntity(entity->getId());
700  if (sceneEntity != nullptr && sceneEntity->getPrototype()->getType() == Prototype_Type::DECAL) {
701  auto decalEntityHierarchy = dynamic_cast<EntityHierarchy*>(entity);
702  auto decalObbEntity = decalEntityHierarchy != nullptr?decalEntityHierarchy->getEntity("tdme.prototype.bv.0"):nullptr;
703  if (decalObbEntity != nullptr) decalObbEntity->setEnabled(true);
704  }
705  const auto& red = entityColors["red"];
706  entity->setEffectColorAdd(Color4(red.colorAddR, red.colorAddG, red.colorAddB, 0.0f));
707  entity->setEffectColorMul(Color4(red.colorMulR, red.colorMulG, red.colorMulB, 1.0f));
708 }
709 
711 {
712  const auto& color = entityColors["none"];
713  entity->setEffectColorAdd(Color4(color.colorAddR, color.colorAddG, color.colorAddB, 0.0f));
714  entity->setEffectColorMul(Color4(color.colorMulR, color.colorMulG, color.colorMulB, 1.0f));
715  auto sceneEntity = scene->getEntity(entity->getId());
716  if (sceneEntity == nullptr) return;
717  auto colorProperty = sceneEntity->getProperty("object.color");
718  if (colorProperty == nullptr) colorProperty = sceneEntity->getPrototype()->getProperty("object.color");
719  if (colorProperty != nullptr) {
720  auto entityColorIt = entityColors.find(colorProperty->getValue());
721  if (entityColorIt != entityColors.end()) {
722  const auto& entityColor = entityColorIt->second;
723  entity->setEffectColorAdd(Color4(entity->getEffectColorAdd().getRed() + entityColor.colorAddR, entity->getEffectColorAdd().getGreen() + entityColor.colorAddG, entity->getEffectColorAdd().getBlue() + entityColor.colorAddB, 0.0f));
724  entity->setEffectColorMul(Color4(entity->getEffectColorMul().getRed() * entityColor.colorMulR, entity->getEffectColorMul().getGreen() * entityColor.colorMulG, entity->getEffectColorMul().getBlue() * entityColor.colorMulB, 1.0f));
725  }
726  }
727  if (sceneEntity != nullptr && sceneEntity->getPrototype()->getType() == Prototype_Type::DECAL) {
728  auto decalEntityHierarchy = dynamic_cast<EntityHierarchy*>(entity);
729  auto decalObbEntity = decalEntityHierarchy != nullptr?decalEntityHierarchy->getEntity("tdme.prototype.bv.0"):nullptr;
730  if (decalObbEntity != nullptr) decalObbEntity->setEnabled(false);
731  }
732 }
733 
735  if (entity == nullptr) return;
736  unselectEntityInternal(entity);
737  auto sceneEntity = scene->getEntity(entity->getId());
738  if (sceneEntity == nullptr) return;
739  if (sceneEntity->getPrototype()->getType()->hasNonEditScaleDownMode() == false) return;
740  entity->setTransform(sceneEntity->getTransform());
741  entity->setScale(
742  sceneEntity->getPrototype()->getType()->getNonEditScaleDownModeDimension().
743  clone().
744  scale(
745  Vector3(
746  1.0f / (sceneEntity->getTransform().getScale().getX() * entity->getBoundingBox()->getDimensions().getX()),
747  1.0f / (sceneEntity->getTransform().getScale().getY() * entity->getBoundingBox()->getDimensions().getY()),
748  1.0f / (sceneEntity->getTransform().getScale().getZ() * entity->getBoundingBox()->getDimensions().getZ())
749  )
750  )
751  );
752  entity->update();
753 }
754 
755 void SceneEditorTabView::selectEntities(const vector<string>& entityIds)
756 {
757  removeGizmo();
758  for (const auto& entityIdToRemove: selectedEntityIds) {
759  auto entityToRemove = engine->getEntity(entityIdToRemove);
760  if (entityToRemove != nullptr) unselectEntityInternal(entityToRemove);
761  }
762  selectedEntityIds.clear();
763  selectedEntityIdsById.clear();
764  for (const auto& entityId: entityIds) {
765  auto selectedEntity = engine->getEntity(entityId);
766  if (selectedEntity == nullptr) continue;
767  selectEntityInternal(selectedEntity);
768  selectedEntityIds.push_back(entityId);
769  selectedEntityIdsById.insert(entityId);
770  }
771 
772  if (entityIds.size() == 1) {
773  auto selectedEntity = engine->getEntity(entityIds[0]);
774  if (selectedEntity != nullptr) {
775  setGizmoRotation(selectedEntity->getTransform());
776  sceneEditorTabController->setEntityDetails(selectedEntity->getId());
777  }
778  } else
779  if (entityIds.size() > 1) {
783  }
784  updateGizmo();
785 }
786 
788 {
789  removeGizmo();
790  for (const auto& entityIdToUnselect: selectedEntityIds) {
791  auto entityToUnselect = engine->getEntity(entityIdToUnselect);
792  if (entityToUnselect == nullptr) continue;
793  resetEntity(entityToUnselect);
794  }
795  selectedEntityIds.clear();
796  selectedEntityIdsById.clear();
797 }
798 
800 {
801  copiedEntities.clear();
802  for (const auto& selectedEntityId: selectedEntityIds) {
803  auto selectedEntity = engine->getEntity(selectedEntityId);
804  if (selectedEntity != nullptr && StringTools::startsWith(selectedEntity->getId(), "tdme.sceneeditor.") == false) {
805  auto sceneEntity = scene->getEntity(selectedEntity->getId());
806  if (sceneEntity == nullptr) continue;
807  copiedEntities.push_back(sceneEntity);
808  }
809  }
810 }
811 
814  selectedPrototype = prototype;
815  placeEntityMode = true;
816  placeEntityValid = false;
817 }
818 
820  placeEntityMode = false;
821  placeEntityValid = false;
822  selectedPrototype = nullptr;
823  engine->removeEntity("tdme.sceneeditor.placeentity");
824  //
825  if (cancelled == false || selectedEntityIds.empty() == false) {
826  reloadOutliner();
827  // select selected entities
828  sceneEditorTabController->unselectEntities();
829  for (const auto& entityId: selectedEntityIds) {
830  sceneEditorTabController->selectEntity(entityId);
831  }
833  }
834 }
835 
837 {
838  if (selectedPrototype == nullptr) return;
839 
840  Transform sceneEntityTransform;
841  sceneEntityTransform.setTranslation(placeEntityTranslation);
842  sceneEntityTransform.setScale(Vector3(1.0f, 1.0f, 1.0f));
843  sceneEntityTransform.addRotation(scene->getRotationOrder()->getAxis0(), 0.0f);
844  sceneEntityTransform.addRotation(scene->getRotationOrder()->getAxis1(), 0.0f);
845  sceneEntityTransform.addRotation(scene->getRotationOrder()->getAxis2(), 0.0f);
846  sceneEntityTransform.setRotationAngle(scene->getRotationOrder()->getAxisYIndex(), placeEntityYRotation * 90.0f);
847  sceneEntityTransform.update();
848  for (auto i = 0; i < scene->getEntityCount(); i++) {
849  auto sceneEntity = scene->getEntityAt(i);
850  if (sceneEntity->getPrototype() == selectedPrototype && sceneEntity->getTransform().getTranslation().equals(sceneEntityTransform.getTranslation())) {
851  return;
852  }
853  }
854  auto sceneEntity = new SceneEntity(
855  selectedPrototype->getName() + "_" + to_string(scene->allocateEntityId()),
856  "",
857  sceneEntityTransform,
859  );
860  scene->addEntity(sceneEntity);
861  selectedEntityIds.push_back(sceneEntity->getId());
862  auto entity = createEntity(sceneEntity);
863  if (entity != nullptr) {
864  resetEntity(entity);
865  entity->setPickable(true);
866  engine->addEntity(entity);
867  }
868  scene->update();
869  cameraInputHandler->setSceneCenter(Vector3(scene->getCenter().getX(), scene->getBoundingBox()->getMax().getY() + 3.0f, scene->getCenter().getZ()));
870 }
871 
872 bool SceneEditorTabView::placeEntity(Prototype* prototype, int mouseX, int mouseY) {
873  if (engine->getEntityByMousePosition(mouseX, mouseY, placeEntityTranslation, entityPickingFilterPlacing.get()) != nullptr) {
874  setPlaceEntityMode(prototype);
875  placeEntity();
876  unsetPlaceEntityMode(false);
877  return true;
878  }
879  return false;
880 }
881 
883 {
884  removeGizmo();
885  vector<Entity*> entitiesToRemove;
886  for (const auto& selectedEntityId: selectedEntityIds) {
887  Entity* selectedEntity = engine->getEntity(selectedEntityId);
888  if (selectedEntity != nullptr && StringTools::startsWith(selectedEntity->getId(), "tdme.sceneeditor.") == false) {
889  scene->removeEntity(selectedEntity->getId());
890  engine->removeEntity(selectedEntity->getId());
891  entitiesToRemove.push_back(selectedEntity);
892  }
893  }
894  for (const auto& entityToRemove: entitiesToRemove) {
895  selectedEntityIds.erase(remove(selectedEntityIds.begin(), selectedEntityIds.end(), entityToRemove->getId()), selectedEntityIds.end());
896  auto selectedEntityIdsByIdIt = selectedEntityIdsById.find(entityToRemove->getId());
897  if (selectedEntityIdsByIdIt != selectedEntityIdsById.end()) {
898  selectedEntityIdsById.erase(selectedEntityIdsByIdIt);
899  }
900  }
901  scene->update();
902  cameraInputHandler->setSceneCenter(Vector3(scene->getCenter().getX(), scene->getBoundingBox()->getMax().getY() + 3.0f, scene->getCenter().getZ()));
903 
904  //
905  reloadOutliner("scene.entities");
906 }
907 
910  sceneEditorTabController->unselectEntities();
911  pasteMode = true;
912  pasteModeValid = false;
913 }
914 
916  auto pasteEntityIdx = 0;
917  for (const auto& pasteEntity: copiedEntities) {
918  auto pastePrototype = pasteEntity->getPrototype();
919  auto entityId = "tdme.sceneeditor.paste." + pastePrototype->getName() + "." + to_string(pasteEntityIdx);
920  engine->removeEntity(entityId);
921  pasteEntityIdx++;
922  }
923  pasteMode = false;
924  pasteModeValid = false;
925 }
926 
927 void SceneEditorTabView::pasteEntities(bool displayOnly)
928 {
929  auto pasteEntitiesMinX = Float::MAX_VALUE;
930  auto pasteEntitiesMinZ = Float::MAX_VALUE;
931  auto pasteEntitiesMinY = Float::MAX_VALUE;
932  auto pasteEntitiesMaxX = Float::MIN_VALUE;
933  auto pasteEntitiesMaxZ = Float::MIN_VALUE;
934  auto pasteEntitiesMaxY = Float::MIN_VALUE;
935  for (const auto& copiedEntity: copiedEntities) {
936  auto entity = engine->getEntity(copiedEntity->getId());
937  if (entity == nullptr) continue;
938  BoundingBox cbv;
939  cbv.fromBoundingVolumeWithTransform(entity->getBoundingBox(), copiedEntity->getTransform());
940  const auto& entityBBMin = cbv.getMin();
941  if (entityBBMin[0] < pasteEntitiesMinX) pasteEntitiesMinX = entityBBMin[0];
942  if (entityBBMin[1] < pasteEntitiesMinY) pasteEntitiesMinY = entityBBMin[1];
943  if (entityBBMin[2] < pasteEntitiesMinZ) pasteEntitiesMinZ = entityBBMin[2];
944  const auto& entityBBMax = cbv.getMax();
945  if (entityBBMax[0] > pasteEntitiesMaxX) pasteEntitiesMaxX = entityBBMax[0];
946  if (entityBBMax[1] > pasteEntitiesMaxY) pasteEntitiesMaxY = entityBBMax[1];
947  if (entityBBMax[2] > pasteEntitiesMaxZ) pasteEntitiesMaxZ = entityBBMax[2];
948  }
949  auto centerX = (pasteEntitiesMaxX - pasteEntitiesMinX) / 2.0f;
950  auto centerZ = (pasteEntitiesMaxZ - pasteEntitiesMinZ) / 2.0f;
951  auto pasteEntitiesIdx = 0;
952  vector<string> entitiesToSelect;
953  for (const auto& copiedEntity: copiedEntities) {
954  auto pastePrototype = copiedEntity->getPrototype();
955  Transform sceneEntityTransform;
956  sceneEntityTransform.setTransform(copiedEntity->getTransform());
957  auto entityDiffX = copiedEntity->getTransform().getTranslation().getX() - pasteEntitiesMinX;
958  auto entityDiffY = copiedEntity->getTransform().getTranslation().getY() - pasteEntitiesMinY;
959  auto entityDiffZ = copiedEntity->getTransform().getTranslation().getZ() - pasteEntitiesMinZ;
960  sceneEntityTransform.setTranslation(
961  Vector3(
962  placeEntityTranslation.getX() + entityDiffX - centerX,
963  placeEntityTranslation.getY() + entityDiffY,
964  placeEntityTranslation.getZ() + entityDiffZ - centerZ
965  )
966  );
967  sceneEntityTransform.update();
968  if (displayOnly == false) {
969  //
970  auto sceneEntityId = pastePrototype->getName() + "_" + to_string(scene->allocateEntityId());
971  auto sceneEntity = new SceneEntity(
972  sceneEntityId,
973  "",
974  sceneEntityTransform,
975  pastePrototype
976  );
977  BaseProperties* properties = copiedEntity;
978  for (auto property: properties->getProperties()) {
979  sceneEntity->addProperty(property->getName(), property->getValue());
980  }
981  scene->addEntity(sceneEntity);
982  auto entity = createEntity(pastePrototype, sceneEntityId, sceneEntityTransform);
983  if (entity != nullptr) {
984  resetEntity(entity);
985  entity->setPickable(true);
986  engine->addEntity(entity);
987  }
988  entitiesToSelect.push_back(sceneEntityId);
989  } else {
990  auto entityId = "tdme.sceneeditor.paste." + pastePrototype->getName() + "." + to_string(pasteEntitiesIdx);
991  auto entity = engine->getEntity(entityId);
992  if (entity != nullptr) {
993  entity->setTransform(sceneEntityTransform);
994  } else {
995  entity = createEntity(pastePrototype, entityId, sceneEntityTransform);
996  if (entity != nullptr) {
997  unselectEntityInternal(entity);
998  entity->setPickable(true);
999  engine->addEntity(entity);
1000  }
1001  }
1002  }
1003  pasteEntitiesIdx++;
1004  }
1005 
1006  //
1007  if (displayOnly == false) {
1008  reloadOutliner();
1009  // select selected entities
1010  sceneEditorTabController->unselectEntities();
1011  for (const auto& entityId: entitiesToSelect) {
1012  sceneEditorTabController->selectEntity(entityId);
1013  }
1014  selectEntities(entitiesToSelect);
1015  }
1016 }
1017 
1019  Vector3 pivot;
1020  auto entityCount = 0;
1021  for (const auto& selectedEntityId: selectedEntityIds) {
1022  auto selectedEntity = engine->getEntity(selectedEntityId);
1023  if (selectedEntity != nullptr && StringTools::startsWith(selectedEntity->getId(), "tdme.sceneeditor.") == false) {
1024  auto sceneEntity = scene->getEntity(selectedEntity->getId());
1025  if (sceneEntity == nullptr) continue;
1026  pivot.add(sceneEntity->getTransform().getTranslation());
1027  entityCount++;
1028  }
1029  }
1030  if (entityCount > 1) pivot.scale(1.0f / entityCount);
1031  return pivot;
1032 }
1033 
1035  string selectedEnvironmentMappingId;
1036  for (const auto& selectedEntityId: selectedEntityIds) {
1037  auto selectedEntity = engine->getEntity(selectedEntityId);
1038  if (selectedEntity != nullptr && StringTools::startsWith(selectedEntity->getId(), "tdme.sceneeditor.") == false) {
1039  auto sceneEntity = scene->getEntity(selectedEntity->getId());
1040  if (sceneEntity == nullptr) continue;
1041  if (selectedEnvironmentMappingId.empty() == true) {
1042  selectedEnvironmentMappingId = sceneEntity->getReflectionEnvironmentMappingId();
1043  } else
1044  if (selectedEnvironmentMappingId != sceneEntity->getReflectionEnvironmentMappingId()) {
1045  selectedEnvironmentMappingId.clear();
1046  return selectedEnvironmentMappingId;
1047  }
1048  }
1049  }
1050  return selectedEnvironmentMappingId;
1051 }
1052 
1054 {
1055  if (selectedEntityIds.size() == 0) {
1056  return;
1057  }
1058  Vector3 center;
1059  for (const auto& selectedEntityId: selectedEntityIds) {
1060  auto selectedEntity = engine->getEntity(selectedEntityId);
1061  if (selectedEntity == nullptr) continue;
1062  center.add(selectedEntity->getWorldBoundingBox()->getMin().clone().add(selectedEntity->getWorldBoundingBox()->getMax()).scale(0.5f));
1063  }
1064  engine->getCamera()->setLookAt(center.scale(1.0f / selectedEntityIds.size()));
1065 }
1066 
1068 {
1069  if (selectedEntityIds.size() == 0) {
1070  return;
1071  }
1072  sceneEditorTabController->unselectEntities();
1073 
1074  auto sceneEntity = scene->getEntity(selectedEntityIds[0]);
1075  auto prototype = sceneEntity != nullptr?sceneEntity->getPrototype():nullptr;
1076  vector<string> entitiesToSelect;
1077  for (auto _sceneEntity: scene->getEntities()) {
1078  if (_sceneEntity->getPrototype() != prototype) continue;
1079  sceneEditorTabController->selectEntity(_sceneEntity->getId());
1080  entitiesToSelect.push_back(_sceneEntity->getId());
1081  }
1082  selectEntities(entitiesToSelect);
1083 }
1084 
1086  if (selectedEntityIds.size() == 0) {
1087  return;
1088  }
1089 
1090  sceneEditorTabController->unselectEntities();
1091 
1092  auto sceneEntity = scene->getEntity(selectedEntityIds[0]);
1093  auto prototype = sceneEntity != nullptr?sceneEntity->getPrototype():nullptr;
1094  if (prototype == nullptr || prototype->getFileName().empty() == true) {
1095  sceneEditorTabController->showInfoPopUp("Warning", "Prototype is embedded and can not be opened");
1096  } else {
1097  editorView->getScreenController()->openFile(prototype->getFileName());
1098  }
1099 }
1100 
1102  if (selectedEntityIds.size() == 0) {
1103  removeGizmo();
1104  return;
1105  }
1106 
1107  // rotation for gizmo
1108  Transform transform;
1109 
1110  //
1111  Vector3 gizmoCenter;
1112  auto entityCount = 0;
1113  for (const auto& selectedEntityId: selectedEntityIds) {
1114  auto selectedEntity = engine->getEntity(selectedEntityId);
1115  if (selectedEntity != nullptr && StringTools::startsWith(selectedEntity->getId(), "tdme.sceneeditor.") == false) {
1116  auto sceneEntity = scene->getEntity(selectedEntity->getId());
1117  if (sceneEntity == nullptr) continue;
1118  gizmoCenter.add(selectedEntity->getTransform().getTranslation());
1119  entityCount++;
1120  }
1121  }
1122  if (entityCount == 0) {
1123  removeGizmo();
1124  return;
1125  } else
1126  if (entityCount == 1) {
1127  auto selectedSceneEntity = scene->getEntity(selectedEntityIds[0]);
1128  auto selectedPrototype = selectedSceneEntity != nullptr?selectedSceneEntity->getPrototype():nullptr;
1129  if (selectedSceneEntity != nullptr) transform.setTransform(selectedSceneEntity->getTransform());
1131  if (selectedSceneEntity == nullptr || selectedPrototype == nullptr) {
1132  removeGizmo();
1133  }
1134  } else {
1135  gizmoCenter.scale(1.0f / entityCount);
1136  }
1137 
1138  //
1139  Gizmo::updateGizmo(gizmoCenter, transform);
1140 }
1141 
1142 bool SceneEditorTabView::applyBase(const string& name, const string& description) {
1143  if (selectedEntityIds.size() != 1) return false;
1144 
1145  auto selectedEntity = engine->getEntity(selectedEntityIds[0]);
1146  if (selectedEntity == nullptr || StringTools::startsWith(selectedEntity->getId(), "tdme.sceneeditor.")) return false;
1147 
1148  auto sceneEntity = scene->getEntity(selectedEntity->getId());
1149  if (sceneEntity == nullptr) return false;
1150 
1151  sceneEntity->setDescription(description);
1152  auto oldName = sceneEntity->getId();
1153  if (oldName == name) return true;
1154 
1155  if (engine->getEntity(name) != nullptr) return false;
1156  if (scene->renameEntity(sceneEntity->getId(), name) == true) {
1157  engine->removeEntity(oldName);
1158  selectedEntityIds.clear();
1159  selectedEntityIdsById.clear();
1160  auto entity = createEntity(sceneEntity);
1161  if (entity == nullptr) {
1162  return false;
1163  } else {
1164  selectEntityInternal(entity);
1165  selectedEntityIds.push_back(entity->getId());
1166  selectedEntityIdsById.insert(entity->getId());
1167  entity->setPickable(true);
1168  engine->addEntity(entity);
1169  //
1170  reloadOutliner("scene.entities." + entity->getId());
1171  }
1172  return true;
1173  } else {
1174  return false;
1175  }
1176 }
1177 
1179  if (selectedEntityIds.size() == 0)
1180  return;
1181 
1182  if (selectedEntityIds.size() == 1) {
1183  auto selectedEntity = engine->getEntity(selectedEntityIds[0]);
1184  if (selectedEntity == nullptr) return;
1185  auto sceneEntity = scene->getEntity(selectedEntity->getId());
1186  if (sceneEntity == nullptr) return;
1187 
1188  sceneEntity->getTransform().setTranslation(translation);
1189  sceneEntity->getTransform().update();
1190  selectedEntity->setTransform(sceneEntity->getTransform());
1191  } else
1192  if (selectedEntityIds.size() > 1) {
1193  for (const auto& selectedEntityId: selectedEntityIds) {
1194  auto selectedEntity = engine->getEntity(selectedEntityId);
1195  if (selectedEntity == nullptr) continue;
1196  auto sceneEntity = scene->getEntity(selectedEntity->getId());
1197  if (sceneEntity == nullptr) continue;
1198 
1199  sceneEntity->getTransform().setTranslation(
1200  sceneEntity->getTransform().getTranslation().clone().add(translation.clone().sub(multipleSelectionTranslation))
1201  );
1202  sceneEntity->getTransform().update();
1203  selectedEntity->setTransform(sceneEntity->getTransform());
1204  }
1206  }
1207  scene->update();
1208  cameraInputHandler->setSceneCenter(Vector3(scene->getCenter().getX(), scene->getBoundingBox()->getMax().getY() + 3.0f, scene->getCenter().getZ()));
1209  updateGizmo();
1210 }
1211 
1213  if (selectedEntityIds.size() == 0)
1214  return;
1215 
1216  if (selectedEntityIds.size() == 1) {
1217  auto selectedEntity = engine->getEntity(selectedEntityIds[0]);
1218  if (selectedEntity == nullptr) return;
1219  auto sceneEntity = scene->getEntity(selectedEntity->getId());
1220  if (sceneEntity == nullptr) return;
1221  sceneEntity->getTransform().getRotation(scene->getRotationOrder()->getAxisXIndex()).setAngle(rotation.getX());
1222  sceneEntity->getTransform().getRotation(scene->getRotationOrder()->getAxisYIndex()).setAngle(rotation.getY());
1223  sceneEntity->getTransform().getRotation(scene->getRotationOrder()->getAxisZIndex()).setAngle(rotation.getZ());
1224  sceneEntity->getTransform().update();
1225  selectedEntity->setTransform(sceneEntity->getTransform());
1226  } else
1227  if (selectedEntityIds.size() > 1) {
1228  for (const auto& selectedEntityId: selectedEntityIds) {
1229  auto selectedEntity = engine->getEntity(selectedEntityId);
1230  if (selectedEntity == nullptr) continue;
1231  auto sceneEntity = scene->getEntity(selectedEntity->getId());
1232  if (sceneEntity == nullptr) continue;
1233  if ((sceneEntity->getPrototype()->getType()->getGizmoTypeMask() & Gizmo::GIZMOTYPE_ROTATE) == Gizmo::GIZMOTYPE_ROTATE) {
1234  sceneEntity->getTransform().getRotation(scene->getRotationOrder()->getAxisXIndex()).setAngle(sceneEntity->getTransform().getRotation(scene->getRotationOrder()->getAxisXIndex()).getAngle() + (rotation.getX() - multipleSelectionRotation.getX()));
1235  sceneEntity->getTransform().getRotation(scene->getRotationOrder()->getAxisYIndex()).setAngle(sceneEntity->getTransform().getRotation(scene->getRotationOrder()->getAxisYIndex()).getAngle() + (rotation.getY() - multipleSelectionRotation.getY()));
1236  sceneEntity->getTransform().getRotation(scene->getRotationOrder()->getAxisZIndex()).setAngle(sceneEntity->getTransform().getRotation(scene->getRotationOrder()->getAxisZIndex()).getAngle() + (rotation.getZ() - multipleSelectionRotation.getZ()));
1237  }
1238  sceneEntity->getTransform().update();
1239  selectedEntity->setTransform(sceneEntity->getTransform());
1240  }
1242  }
1243  scene->update();
1244  cameraInputHandler->setSceneCenter(Vector3(scene->getCenter().getX(), scene->getBoundingBox()->getMax().getY() + 3.0f, scene->getCenter().getZ()));
1245  updateGizmo();
1246 }
1247 
1249  if (selectedEntityIds.size() == 0)
1250  return;
1251 
1252  if (selectedEntityIds.size() == 1) {
1253  auto selectedEntity = engine->getEntity(selectedEntityIds[0]);
1254  if (selectedEntity == nullptr) return;
1255  auto sceneEntity = scene->getEntity(selectedEntity->getId());
1256  if (sceneEntity == nullptr) return;
1257 
1258  sceneEntity->getTransform().setScale(Vector3(scale));
1259  sceneEntity->getTransform().update();
1260  selectedEntity->setTransform(sceneEntity->getTransform());
1261  } else
1262  if (selectedEntityIds.size() > 1) {
1263  for (const auto& selectedEntityId: selectedEntityIds) {
1264  auto selectedEntity = engine->getEntity(selectedEntityId);
1265  if (selectedEntity == nullptr) continue;
1266  auto sceneEntity = scene->getEntity(selectedEntity->getId());
1267  if (sceneEntity == nullptr) continue;
1268 
1269  sceneEntity->getTransform().setScale(sceneEntity->getTransform().getScale().clone().scale(scale / multipleSelectionScale));
1270  sceneEntity->getTransform().update();
1271  selectedEntity->setTransform(sceneEntity->getTransform());
1272  }
1274  }
1275  scene->update();
1276  cameraInputHandler->setSceneCenter(Vector3(scene->getCenter().getX(), scene->getBoundingBox()->getMax().getY() + 3.0f, scene->getCenter().getZ()));
1277  updateGizmo();
1278 }
1279 
1280 void SceneEditorTabView::applyReflectionEnvironmentMappingId(const string& reflectionEnvironmentMappingId) {
1281  if (selectedEntityIds.size() == 0)
1282  return;
1283 
1284  for (const auto& selectedEntityId: selectedEntityIds) {
1285  auto selectedEntity = engine->getEntity(selectedEntityId);
1286  if (selectedEntity == nullptr) continue;
1287  auto sceneEntity = scene->getEntity(selectedEntity->getId());
1288  if (sceneEntity == nullptr) continue;
1289 
1290  auto object = dynamic_cast<Object*>(selectedEntity);
1291  if (object != nullptr) object->setReflectionEnvironmentMappingId(reflectionEnvironmentMappingId);
1292  sceneEntity->setReflectionEnvironmentMappingId(reflectionEnvironmentMappingId);
1293  }
1294 }
1295 
1297 {
1298  return gridEnabled;
1299 }
1300 
1302 {
1303  this->gridEnabled = gridEnabled;
1304  if (gridEnabled) {
1305  updateGrid();
1306  } else {
1307  removeGrid();
1308  }
1309 }
1310 
1312 {
1313  return gridY;
1314 }
1315 
1317 {
1318  if (gridEnabled == true) removeGrid();
1319  this->gridY = gridY;
1320  if (gridEnabled == true) updateGrid();
1321 
1322 }
1323 
1325 {
1326  if (gridEnabled == false) return;
1327 
1328  string entityId = "tdme.sceneeditor.grid";
1329  auto entity = engine->getEntity(entityId);
1330  if (entity == nullptr) {
1331  entity = new Object(entityId, gridModel.get());
1332  entity->setFrustumCulling(false);
1333  entity->addRotation(scene->getRotationOrder()->getAxis0(), 0.0f);
1334  entity->addRotation(scene->getRotationOrder()->getAxis1(), 0.0f);
1335  entity->addRotation(scene->getRotationOrder()->getAxis2(), 0.0f);
1336  entity->setTranslation(
1337  Vector3(
1338  -5000.0f,
1339  gridY - 0.05f,
1340  -5000.0f
1341  )
1342  );
1343  entity->setEnabled(true);
1344  entity->setPickable(true);
1345  entity->update();
1346  auto selectedEntityIdsByIdIt = selectedEntityIdsById.find(entity->getId());
1347  if (selectedEntityIdsByIdIt != selectedEntityIdsById.end()) {
1348  selectEntityInternal(entity);
1349  } else {
1350  unselectEntityInternal(entity);
1351  }
1352  engine->addEntity(entity);
1353  }
1354 }
1355 
1357 {
1358  engine->removeEntity("tdme.sceneeditor.grid");
1359 }
1360 
1361 void SceneEditorTabView::getSnapping(bool& snappingEnabled, float& snappingX, float& snappingZ) {
1363  snappingX = this->snappingX;
1364  snappingZ = this->snappingZ;
1365 }
1366 
1367 void SceneEditorTabView::setSnapping(bool snappingEnabled, float snappingX, float snappingZ) {
1368  this->snappingEnabled = snappingEnabled;
1369  this->snappingX = snappingX;
1370  this->snappingZ = snappingZ;
1371 }
1372 
1374  try {
1375  prototype->setEmbedded(false);
1376  auto sceneLibrary = scene->getLibrary();
1377  if (prototype->getType() == Prototype_Type::TERRAIN) {
1378  while (sceneLibrary->getTerrainPrototype() != nullptr) {
1379  for (auto prototype: sceneLibrary->getPrototypes()) {
1380  if (prototype->getType() == Prototype_Type::TERRAIN) {
1381  sceneLibrary->removePrototype(prototype->getId());
1382  break;
1383  }
1384  }
1385  }
1386  sceneLibrary->addPrototype(prototype);
1387  SceneConnector::resetEngine(engine.get(), scene.get());
1388  SceneConnector::setLights(engine.get(), scene.get());
1389  SceneConnector::addScene(engine.get(), scene.get(), true, true, true, true, true);
1390  scene->update();
1391  cameraInputHandler->setSceneCenter(scene->getCenter());
1392  cameraInputHandler->reset();
1393  } else {
1394  sceneLibrary->addPrototype(prototype);
1395  }
1396  } catch (Exception& exception) {
1397  Console::println("SceneEditorTabView::addPrototype(): An error occurred: " + string(exception.what()));
1398  sceneEditorTabController->showInfoPopUp("Warning", string(exception.what()));
1399  }
1400  reloadOutliner("scene.prototypes." + to_string(prototype->getId()));
1401 }
1402 
1403 Entity* SceneEditorTabView::createEntity(Prototype* prototype, const string& id, const Transform& transform, int instances) {
1404  if (prototype->getType() == Prototype_Type::DECAL) {
1405  return SceneConnector::createEditorDecalEntity(prototype, id, transform, instances);
1406  } else {
1407  return SceneConnector::createEntity(prototype, id, transform, instances);
1408  }
1409 }
1410 
1411 Entity* SceneEditorTabView::createEntity(SceneEntity* sceneEntity, const Vector3& translation, int instances) {
1412  if (sceneEntity->getPrototype()->getType() == Prototype_Type::DECAL) {
1413  return SceneConnector::createEditorDecalEntity(sceneEntity, translation, instances);
1414  } else {
1415  return SceneConnector::createEntity(sceneEntity, translation, instances);
1416  }
1417 }
1418 
1420  // stop scene
1421  stopScene();
1422 
1423  //
1424  removeGizmo();
1425 
1426  // execute scene
1427  {
1428  auto world = make_unique<World>("applicationclient-world");
1429  SceneConnector::addScene(world.get(), scene.get(), true);
1430  auto applicationContext = make_unique<Context>(false);
1431  applicationContext->setApplicationRootPathName(editorView->getScreenController()->getProjectPath());
1432  applicationContext->setScene(scene.get());
1433  applicationContext->setEngine(engine.get());
1434  applicationContext->setAudio(Audio::getInstance());
1435  applicationContext->setWorld(world.release());
1436  applicationContext->setSoundPoolSize(1);
1437  applicationClient = make_unique<ApplicationClient>(applicationContext.release());
1438  applicationClient->getContext()->initialize();
1439  }
1440 
1441  // add gui
1442  if (scene->getGUIFileName().empty() == false) {
1443  try {
1444  auto screenNode = GUIParser::parse(
1445  Tools::getPathName(scene->getGUIFileName()),
1446  Tools::getFileName(scene->getGUIFileName()),
1447  {},
1448  MiniScript::ScriptVariable(),
1449  applicationClient->getContext()
1450  );
1451  engine->getGUI()->addScreen(screenNode->getId(), screenNode);
1452  engine->getGUI()->addRenderScreen(screenNode->getId());
1453  } catch (Exception& exception) {
1454  Console::println("SceneEditorTabView::runScene(): an error occurred: " + string(exception.what()));
1455  }
1456  }
1457 
1458  // add logics
1459  // TODO: exception handling
1460  auto valid = true;
1461  string invalidScripts;
1462  for (auto entity: scene->getEntities()) {
1463  if (entity->getPrototype()->hasScript() == true) {
1464  auto miniScript = make_unique<LogicMiniScript>();
1465  miniScript->parseScript(
1466  Tools::getPathName(entity->getPrototype()->getScript()),
1467  Tools::getFileName(entity->getPrototype()->getScript())
1468  );
1469  if (miniScript->isValid() == false) {
1470  //
1471  invalidScripts+=
1472  Tools::getRelativeResourcesFileName(
1473  editorView->getScreenController()->getProjectPath(), Tools::getPathName(entity->getPrototype()->getScript()) + "/" + Tools::getFileName(entity->getPrototype()->getScript())
1474  );
1475  //
1476  if (miniScript->getParseErrors().empty() == true) {
1477  invalidScripts+= "\n";
1478  } else {
1479  //
1480  invalidScripts+= ":\n";
1481  //
1482  for (const auto& parseError: miniScript->getParseErrors())
1483  invalidScripts+= "\t" + parseError + "\n";
1484  //
1485  invalidScripts+= "\n";
1486  }
1487  //
1488  valid = false;
1489  //
1490  continue;
1491  }
1492  applicationClient->getContext()->addLogic(
1493  make_unique<MiniScriptLogic>(
1494  applicationClient->getContext(),
1495  entity->getId(),
1496  entity->getPrototype()->isScriptHandlingHID(),
1497  miniScript.release(),
1498  entity->getPrototype(),
1499  true
1500  ).release()
1501  );
1502  }
1503  }
1504 
1505  //
1506  if (valid == false) {
1507  sceneEditorTabController->setRunButtonMode(false);
1508  //
1509  sceneEditorTabController->showInfoPopUp("Error", "Not all scripts are valid to be run:\n\n" + invalidScripts);
1510  //
1511  applicationClient->getContext()->unsetEngine();
1512  applicationClient->getContext()->unsetScene();
1513  //
1514  applicationClient = nullptr;
1515  // reset scene
1516  engine->getGUI()->reset();
1517  SceneConnector::resetEngine(engine.get(), scene.get());
1518  SceneConnector::setLights(engine.get(), scene.get());
1519  SceneConnector::addScene(engine.get(), scene.get(), true, true, true, true, true);
1520  scene->update();
1521  cameraInputHandler->setSceneCenter(scene->getCenter());
1522  cameraInputHandler->reset();
1523  //
1524  return;
1525  }
1526 
1527  //
1528  sceneEditorTabController->setRunButtonMode(true);
1529 
1530  // and go
1531  applicationClient->start();
1532 }
1533 
1535  //
1536  sceneEditorTabController->setRunButtonMode(false);
1537 
1538  //
1539  shutdownScene();
1540 
1541  // reset scene
1542  engine->getGUI()->reset();
1543  SceneConnector::setLights(engine.get(), scene.get());
1544  SceneConnector::addScene(engine.get(), scene.get(), true, true, true, true, true);
1545  scene->update();
1546  cameraInputHandler->setSceneCenter(scene->getCenter());
1547  cameraInputHandler->reset();
1548 }
1549 
1551  //
1552  if (applicationClient == nullptr) return;
1553  // shutdown application client
1554  applicationClient->stop();
1555  applicationClient->join();
1556  //
1557  SceneConnector::resetEngine(engine.get(), scene.get());
1558  //
1559  applicationClient->getContext()->unsetEngine();
1560  applicationClient->getContext()->unsetScene();
1561  //
1562  applicationClient = nullptr;
1563 }
#define KEYBOARD_KEYCODE_LEFT_CTRL
#define MOUSE_BUTTON_LEFT
#define KEYBOARD_KEYCODE_LEFT_SHIFT
Interface to audio module.
Definition: Audio.h:29
Color 4 definition class.
Definition: Color4.h:18
float getRed() const
Definition: Color4.h:92
float getGreen() const
Definition: Color4.h:107
float getBlue() const
Definition: Color4.h:122
Engine main class.
Definition: Engine.h:131
Entity hierarchy to be used with engine class.
Entity * getEntity(const string &id)
Engine entity.
Definition: Entity.h:30
virtual void setScale(const Vector3 &scale)=0
Set scale.
virtual BoundingBox * getBoundingBox()=0
virtual const string & getId()=0
virtual const Color4 & getEffectColorAdd() const =0
The effect color will be added to fragment color.
virtual void setEffectColorMul(const Color4 &effectColorMul)=0
Set effect color that will be multiplied with fragment color.
virtual const Transform & getTransform() const =0
virtual void update()=0
Update transform.
virtual void setTransform(const Transform &transform)=0
Set transform.
virtual const Color4 & getEffectColorMul() const =0
The effect color will be multiplied with fragment color.
virtual void setEffectColorAdd(const Color4 &effectColorAdd)=0
Set effect color that will be added to fragment color.
virtual void setEnabled(bool enabled)=0
Enable/disable rendering.
Light representation.
Definition: Light.h:33
Object to be used with engine class.
Definition: Object.h:60
void setReflectionEnvironmentMappingId(const string &reflectionEnvironmentMappingId)
Definition: Object.h:387
Scene engine/physics connector.
Timing class.
Definition: Timing.h:16
Transform which contain scale, rotations and translation.
Definition: Transform.h:29
virtual void setTransform(const Transform &transform)
Set transform.
Definition: Transform.h:177
void setRotationAngle(const int idx, const float angle)
Definition: Transform.h:155
void setTranslation(const Vector3 &translation)
Set translation.
Definition: Transform.h:64
void setScale(const Vector3 &scale)
Set scale.
Definition: Transform.h:79
virtual void update()
Computes transform matrix.
Definition: Transform.cpp:33
const Vector3 & getTranslation() const
Definition: Transform.h:56
void addRotation(const Vector3 &axis, const float angle)
Add rotation.
Definition: Transform.h:113
Model node.
Definition: Node.h:32
Dynamic physics world class.
Definition: World.h:38
Axis aligned bounding box used for frustum, this is not directly connectable with physics engine.
Definition: BoundingBox.h:26
void fromBoundingVolumeWithTransform(BoundingBox *original, const Transform &transform)
Create bounding volume from given original(of same type) with applied transform.
Definition: BoundingBox.h:150
const Vector3 & getDimensions() const
Definition: BoundingBox.h:128
ConstUniquePtrSequenceIterator< BaseProperty > getProperties() const
bool addProperty(const string &name, const string &value)
Add a property.
Base property model class.
Definition: BaseProperty.h:15
Prototype definition.
Definition: Prototype.h:55
void setEmbedded(bool embedded)
Set embedded.
Definition: Prototype.h:147
Scene entity definition.
Definition: SceneEntity.h:23
Scene prototype library definition.
Definition: SceneLibrary.h:32
Scene definition.
Definition: Scene.h:50
GUI parser.
Definition: GUIParser.h:40
GUI module class.
Definition: GUI.h:64
GUI screen node that represents a screen that can be rendered via GUI system.
Definition: GUIScreenNode.h:72
Vector3 class representing vector3 mathematical structure and operations with x, y,...
Definition: Vector3.h:20
float getY() const
Definition: Vector3.h:117
Vector3 & setX(float x)
Sets x component.
Definition: Vector3.h:109
float getX() const
Definition: Vector3.h:100
float getZ() const
Definition: Vector3.h:134
Vector3 & add(float scalar)
Adds a scalar.
Definition: Vector3.h:153
Vector3 & setY(float y)
Sets y component.
Definition: Vector3.h:126
float computeLengthSquared() const
Definition: Vector3.h:281
Vector3 clone() const
Clones this vector3.
Definition: Vector3.h:374
Vector3 & sub(float scalar)
Subtracts a scalar.
Definition: Vector3.h:177
Vector3 & scale(float scalar)
Scales by scalar.
Definition: Vector3.h:201
Vector3 & set(float x, float y, float z)
Sets this vector3 by its components.
Definition: Vector3.h:70
Vector3 & setZ(float z)
Sets z component.
Definition: Vector3.h:143
void setOutlinerSelection(const string &newSelectionValue)
Set outliner selection.
void restoreOutlinerState(const TabView::OutlinerState &outlinerState)
Restore outliner state.
void storeOutlinerState(TabView::OutlinerState &outlinerState)
Store outliner state.
void openFile(const string &absoluteFileName)
Open file.
Gizmo tool for views.
Definition: Gizmo.h:31
void setGizmoRotation(const Transform &transform)
Set gizmo rotation.
Definition: Gizmo.cpp:542
void setGizmoMode(GizmoMode gizmoMode)
Set GIZMO mode.
Definition: Gizmo.h:167
void setEngine(Engine *engine)
Set engine.
Definition: Gizmo.h:120
bool determineGizmoDeltaTransformations(int mouseX, int mouseY, Vector3 &deltaTranslation, Vector3 &deltaRotation, Vector3 &deltaScale)
Determine GIZMO delta transform.
Definition: Gizmo.cpp:329
void removeGizmo()
Remove gizmo.
Definition: Gizmo.cpp:208
void setGizmoType(GizmoType gizmoType)
Set GIZMO type.
Definition: Gizmo.h:151
GizmoMode getGizmoMode() const
Definition: Gizmo.h:159
bool determineGizmoMode(Entity *selectedEntity, Node *selectedEntityNode)
Select GIZMO mode.
Definition: Gizmo.cpp:515
void setGizmoTypeMask(int gizmoTypeMask)
Set GIZMO type mask.
Definition: Gizmo.h:135
void applyTranslation(const Vector3 &translation)
Apply translation.
void unselectEntityInternal(Entity *object)
Unselect entity.
void pasteEntities(bool displayOnly)
Paste entities.
void placeEntity()
Places selected entity on selected object.
void onCameraRotation() override
On rotation event to be overloaded.
const Vector3 computeMultipleSelectionPivot()
Compute multiple selection pivot.
unordered_map< string, EntityColor > entityColors
unique_ptr< EntityPickingFilter > entityPickingFilterNoGrid
bool applyBase(const string &name, const string &description)
Apply base information.
void setSnapping(bool snappingEnabled, float snappingX, float snappingZ)
Set snapping.
const string getSelectedReflectionEnvironmentMappingId()
Get selected reflection environment mapping id.
void resetEntity(Entity *object)
Reset scale to scene editor object scale.
void handleInputEvents() override
Handle input events that have not yet been processed.
void setGridY(float gridY)
Set grid y position.
void onCameraTranslation() override
On translation event to be overloaded.
void selectEntities(const vector< string > &entityIds)
Select entities.
void getSnapping(bool &snappingEnabled, float &snappingX, float &snappingZ)
Get snapping.
void unsetPlaceEntityMode(bool cancelled)
Finish place entity mode.
unique_ptr< CameraInputHandler > cameraInputHandler
void shutdownScene()
Stop/Shutdown scene, to be used when closing tab.
void applyPostProcessingShaderParameters()
Apply post processing shader parameters.
void applyScale(const Vector3 &scale)
Apply scale.
void setPlaceEntityMode(Prototype *prototype)
Initialize place entity mode.
static Entity * createEntity(Prototype *prototype, const string &id, const Transform &transform, int instances=1)
Create engine entity.
void copyEntities()
Copy current selected entities.
void applySkyShaderParameters()
Apply sky shader parameters.
void addPrototype(Prototype *prototype)
Add prototype to scene.
void applyReflectionEnvironmentMappingId(const string &reflectionEnvironmentMappingId)
Apply reflection environment mapping id.
void selectEntityInternal(Entity *object)
Select entity.
unique_ptr< EntityPickingFilter > entityPickingFilterPlacing
unique_ptr< SceneEditorTabController > sceneEditorTabController
void onCameraScale() override
On scale event to be overloaded.
void applyRotation(const Vector3 &rotation)
Apply rotation.
EditorScreenController * getScreenController()
Definition: EditorView.h:69
Character class.
Definition: Character.h:17
Console class.
Definition: Console.h:29
Float class.
Definition: Float.h:27
Mutable utf8 aware string class.
Definition: MutableString.h:23
MutableString & append(char c)
Append character.
String tools class.
Definition: StringTools.h:22
std::exception Exception
Exception base class.
Definition: Exception.h:18
Action Interface.
Definition: Action.h:11