TDME2  1.9.200
TerrainEditorTabView.cpp
Go to the documentation of this file.
2 
3 #include <memory>
4 #include <string>
5 #include <unordered_map>
6 #include <unordered_set>
7 #include <vector>
8 
9 #include <tdme/tdme.h>
12 #include <tdme/engine/Texture.h>
18 #include <tdme/engine/Engine.h>
21 #include <tdme/engine/Light.h>
22 #include <tdme/engine/Object.h>
25 #include <tdme/engine/Timing.h>
29 #include <tdme/gui/GUI.h>
30 #include <tdme/math/Vector3.h>
36 #include <tdme/utilities/Console.h>
38 #include <tdme/utilities/Integer.h>
40 #include <tdme/utilities/Terrain.h>
41 
42 using std::make_unique;
43 using std::string;
44 using std::unique_ptr;
45 using std::unordered_map;
46 using std::unordered_set;
47 using std::vector;
48 
50 
70 using tdme::gui::GUI;
81 
82 TerrainEditorTabView::TerrainEditorTabView(EditorView* editorView, const string& tabId, Prototype* prototype)
83 {
84  this->editorView = editorView;
85  this->tabId = tabId;
86  this->popUps = editorView->getPopUps();
87  this->prototype = unique_ptr<Prototype>(prototype);
88  engine = unique_ptr<Engine>(Engine::createOffScreenInstance(512, 512, true, true, true));
89  engine->setSceneColor(Color4(39.0f / 255.0f, 39.0f / 255.0f, 39.0f / 255.0f, 1.0f));
90  engine->setSkyShaderEnabled(true);
91  SceneConnector::setNaturalLights(engine.get());
92  this->cameraInputHandler = make_unique<CameraInputHandler>(engine.get());
94 }
95 
97 }
98 
100 {
101  brushMoved = false;
102  for (auto& event:engine->getGUI()->getMouseEvents()) {
103  if (event.isProcessed() == true) continue;
104 
105  if (event.getType() == GUIMouseEvent::MOUSEEVENT_WHEEL_MOVED) {
106  if (event.isShiftDown() == true) {
107  setBrushScale(Math::clamp(brushScale + 0.1f * event.getWheelY(), 0.1f, 100.0f));
108  event.setProcessed(true);
109  }
110  if (event.isControlDown() == true) {
111  setBrushDensityStrength(Math::clamp(brushDensityStrength + 0.1f * event.getWheelY(), 0.1f, 100.0f));
112  event.setProcessed(true);
113  }
114  } else
115  if (event.getType() == GUIMouseEvent::MOUSEEVENT_MOVED) {
116  brushMoved = true;
117  engine->getEntityByMousePosition(event.getXUnscaled(), event.getYUnscaled(), brushCenterPosition);
118  if (terrainEditorTabController->getTerrainBrushOperation() == Terrain::BRUSHOPERATION_RAMP && rampMode == 0) {
120  //
121  auto brushEnabled = rampVertices[1].clone().sub(rampVertices[0]).computeLength() > 0.1f;
122  brushCenterPosition = rampVertices[0].clone().add(rampVertices[1]).scale(0.5f);
123  engine->setShaderParameter("terraineditor", "brushEnabled", brushEnabled);
124  if (brushEnabled == true) {
125  auto brushRotation = -(Vector3::computeAngle(rampVertices[1].clone().sub(rampVertices[0]).setY(0.0f).normalize(), Vector3(0.0f, 0.0f, -1.0f), Vector3(0.0f, 1.0f, 0.0f)) - 180.0f);
126  if (Math::abs(rampVertices[0].getY() - rampVertices[1].getY()) > Math::EPSILON && rampVertices[0].getY() < rampVertices[1].getY()) brushRotation = brushRotation + 180.0f;
127  engine->setShaderParameter("terraineditor", "brushRotation", brushRotation);
128  engine->setShaderParameter("terraineditor", "brushScale",
129  Vector2(
130  (brushScale * 5.0f) / engine->getShaderParameter("terraineditor", "brushDimension").getVector2Value().getX(),
131  1.0f / (engine->getShaderParameter("terraineditor", "brushDimension").getVector2Value().getY() / rampVertices[1].clone().sub(rampVertices[0]).computeLength())
132  )
133  );
134  }
135  }
136  } else
137  if (event.getButton() == MOUSE_BUTTON_RIGHT) {
138  if (event.getType() == GUIMouseEvent::MOUSEEVENT_RELEASED) {
139  if (terrainEditorTabController->getTerrainBrushOperation() == Terrain::BRUSHOPERATION_RAMP) {
140  rampMode = -1;
141  engine->setShaderParameter("terraineditor", "brushEnabled", false);
142  engine->setShaderParameter("terraineditor", "brushRotation", 0.0f);
143  engine->setShaderParameter("terraineditor", "brushScale", Vector2(1.0f, 1.0f));
144  }
145  event.setProcessed(true);
146  }
147  } else
148  if (event.getButton() == MOUSE_BUTTON_LEFT) {
149  if (event.getType() == GUIMouseEvent::MOUSEEVENT_RELEASED) {
150  if (terrainEditorTabController->getTerrainBrushOperation() == Terrain::BRUSHOPERATION_RAMP) {
151  if (engine->getEntityByMousePosition(event.getXUnscaled(), event.getYUnscaled(), brushCenterPosition) != nullptr &&
153  //
154  rampMode++;
156  if (rampMode == 0) {
157  // no op
158  } else
159  if (rampMode == 1) {
160  // place ramp
161  brushCenterPosition = rampVertices[0].clone().add(rampVertices[1]).scale(0.5f);
162  terrainEditorTabController->applyRampTerrainBrush(
166  engine->getShaderParameter("terraineditor", "brushRotation").getFloatValue(),
167  engine->getShaderParameter("terraineditor", "brushScale").getVector2Value(),
168  Math::min(rampHeight[0], rampHeight[1]),
169  Math::max(rampHeight[0], rampHeight[1])
170  );
171  //
172  rampMode = -1;
173  engine->setShaderParameter("terraineditor", "brushEnabled", false);
174  engine->setShaderParameter("terraineditor", "brushRotation", 0.0f);
175  engine->setShaderParameter("terraineditor", "brushScale", Vector2(1.0f, 1.0f));
176  }
177  }
178  } else {
180  temporaryPartitionIdxs.clear();
181  brushingEnabled = false;
182  terrainEditorTabController->unsetCurrentBrushFlattenHeight();
183  }
184  event.setProcessed(true);
185  } else
186  if (event.getType() == GUIMouseEvent::MOUSEEVENT_PRESSED ||
187  event.getType() == GUIMouseEvent::MOUSEEVENT_DRAGGED) {
188  brushMoved = true;
189  if (terrainEditorTabController->getTerrainBrushOperation() != Terrain::BRUSHOPERATION_RAMP) {
190  engine->getEntityByMousePosition(event.getXUnscaled(), event.getYUnscaled(), brushCenterPosition);
191  }
192  if (terrainEditorTabController->getTerrainBrushOperation() == Terrain::BRUSHOPERATION_RAMP) {
193  // no op
194  } else
195  if (terrainEditorTabController->getTerrainBrushOperation() == Terrain::BRUSHOPERATION_WATER_ADD) {
196  if (terrainEditorTabController->determineCurrentBrushHeight(terrainBoundingBox, terrainModels, brushCenterPosition) == true) {
197  vector<Model*> waterModels;
198  Vector3 waterReflectionEnvironmentMappingPosition;
199  terrainEditorTabController->createWater(terrainBoundingBox, brushCenterPosition, waterModels, waterReflectionEnvironmentMappingPosition);
200  brushingEnabled = false;
201  terrainEditorTabController->unsetCurrentBrushFlattenHeight();
202  //
203  for (auto waterModel: waterModels) {
204  auto waterObject = new Object(waterModel->getId(), waterModel);
205  waterObject->setRenderPass(Entity::RENDERPASS_WATER);
206  waterObject->setShader("water");
207  waterObject->setContributesShadows(false);
208  waterObject->setReceivesShadows(false);
209  waterObject->setReflectionEnvironmentMappingId("sky_environment_mapping");
210  waterObject->setReflectionEnvironmentMappingPosition(waterReflectionEnvironmentMappingPosition);
211  waterObject->setPickable(true);
212  engine->addEntity(waterObject);
213  }
214  }
215  } else
216  if (terrainEditorTabController->getTerrainBrushOperation() == Terrain::BRUSHOPERATION_WATER_DELETE) {
217  auto selectedEntity = engine->getEntityByMousePosition(event.getXUnscaled(), event.getYUnscaled());
218  if (selectedEntity != nullptr && StringTools::startsWith(selectedEntity->getId(), "water.") == true) {
219  auto waterBeginIdx = selectedEntity->getId().find('.', selectedEntity->getId().find('.') + 1) + 1;
220  auto waterEndIdx = selectedEntity->getId().find('.', waterBeginIdx + 1);
221  auto waterPositionMapIdx = Integer::parse(StringTools::substring(selectedEntity->getId(), waterBeginIdx, waterEndIdx));
222  terrainEditorTabController->deleteWater(waterPositionMapIdx);
223  } else {
224  brushingEnabled = true;
225  }
226  } else {
227  brushingEnabled = true;
228  }
229  event.setProcessed(true);
230  }
231  }
232  }
233  for (auto& event: engine->getGUI()->getKeyboardEvents()) {
234  if (event.isProcessed() == true) continue;
235  if (event.getType() == GUIKeyboardEvent::KEYBOARDEVENT_KEY_TYPED) continue;
236  auto isKeyDown = event.getType() == GUIKeyboardEvent::KEYBOARDEVENT_KEY_PRESSED;
237  if (event.getKeyCode() == GUIKeyboardEvent::KEYCODE_ESCAPE) {
238  if (isKeyDown == true) {
239  if (terrainEditorTabController->getTerrainBrushOperation() == Terrain::BRUSHOPERATION_RAMP) {
240  rampMode = -1;
241  engine->setShaderParameter("terraineditor", "brushEnabled", false);
242  engine->setShaderParameter("terraineditor", "brushRotation", 0.0f);
243  engine->setShaderParameter("terraineditor", "brushScale", Vector2(1.0f, 1.0f));
244  }
245  }
246  event.setProcessed(true);
247  }
248  }
249  cameraInputHandler->handleInputEvents();
250 }
251 
253 {
254  //
255  engine->setShaderParameter("terraineditor", "brushPosition", Vector2(brushCenterPosition.getX(), brushCenterPosition.getZ()));
256 
257  //
258  terrainEditorTabController->updateInfoText(MutableString(engine->getTiming()->getAvarageFPS()).append(" FPS"));
259 
260  // actually do the brushing
261  if (brushingEnabled == true && terrainEditorTabController->determineCurrentBrushHeight(terrainBoundingBox, terrainModels, brushCenterPosition) == true) {
262  if (terrainEditorTabController->getTerrainBrushOperation() != Terrain::BRUSHOPERATION_NONE) {
263  terrainEditorTabController->applyTerrainBrush(terrainBoundingBox, terrainModels, brushCenterPosition, engine->getTiming()->getDeltaTime());
264  }
265  if (terrainEditorTabController->getFoliageBrushOperation() != Terrain::BRUSHOPERATION_NONE) {
266  if (brushMoved == true) {
267  terrainEditorTabController->applyFoliageBrush(terrainBoundingBox, brushCenterPosition, engine->getTiming()->getDeltaTime());
268  }
269  }
270  }
271 
272  //
273  engine->display();
274 }
275 
277 {
278  try {
279  terrainEditorTabController = make_unique<TerrainEditorTabController>(this);
281  } catch (Exception& exception) {
282  Console::println("TerrainEditorTabView::initialize(): An error occurred: " + string(exception.what()));
283  }
284  // TODO: load settings
286 }
287 
289 {
290  engine->dispose();
291  unsetTerrain();
292  unsetWater();
293 }
294 
296 }
297 
299  return engine.get();
300 }
301 
303  terrainEditorTabController->setOutlinerAddDropDownContent();
304  terrainEditorTabController->setOutlinerContent();
308 }
309 
312 }
313 
315  terrainEditorTabController->setOutlinerContent();
318 }
319 
320 void TerrainEditorTabView::saveFile(const string& pathName, const string& fileName)
321 {
322  PrototypeWriter::write(pathName, fileName, prototype.get());
323 }
324 
326  engine->reset();
327  for (auto terrainModel: terrainModels) delete terrainModel;
329  terrainModels.clear();
330  unsetWater();
331  //
332  auto environmentMapping = new EnvironmentMapping("sky_environment_mapping", Engine::getEnvironmentMappingWidth(), Engine::getEnvironmentMappingHeight(), BoundingBox(Vector3(-30.0f, 0.0f, -30.0f), Vector3(30.0f, 60.0f, -30.0f)));
333  environmentMapping->setFrustumCulling(false);
334  environmentMapping->setRenderPassMask(Entity::RENDERPASS_NOFRUSTUMCULLING);
335  environmentMapping->setTimeRenderUpdateFrequency(33LL);
336  environmentMapping->update();
337  engine->addEntity(environmentMapping);
338 }
339 
341  reset();
342 
343  //
344  partitionFoliageIdx.clear();
345  temporaryPartitionIdxs.clear();
346 
347  //
348  terrainEditorTabController->initializeTerrain();
349 
350  //
351  if (terrainModels.empty() == false) {
352  auto idx = 0;
353  for (auto terrainModel: terrainModels) {
354  auto terrainObject = new Object("terrain." + to_string(idx), terrainModel);
355  terrainObject->setRequiresPreRender(true);
356  terrainObject->setRenderPass(Entity::RENDERPASS_TERRAIN);
357  terrainObject->setShader("terraineditor");
358  terrainObject->setContributesShadows(true);
359  terrainObject->setReceivesShadows(true);
360  terrainObject->setPickable(true);
361  engine->addEntity(terrainObject);
362  idx++;
363  }
364 
365  Vector3 sceneCenter = terrainBoundingBox.getCenter();
366  sceneCenter.set(Vector3(sceneCenter.getX(), terrainBoundingBox.getMax().getY() + 3.0f, sceneCenter.getZ()));
367  cameraInputHandler->setSceneCenter(sceneCenter);
368  }
369 
370  //
371  if (waters.empty() == false) {
372  for (const auto& [waterIdx, water]: waters) {
373  for (const auto waterModel: water.waterModels) {
374  auto waterObject = new Object(waterModel->getId(), waterModel);
375  waterObject->setRenderPass(Entity::RENDERPASS_WATER);
376  waterObject->setShader("water");
377  waterObject->setContributesShadows(false);
378  waterObject->setReceivesShadows(false);
379  waterObject->setReflectionEnvironmentMappingId("sky_environment_mapping");
380  waterObject->setReflectionEnvironmentMappingPosition(water.waterReflectionEnvironmentMappingPosition);
381  waterObject->setPickable(true);
382  engine->addEntity(waterObject);
383  }
384  }
385  }
386 
387  //
388  cameraInputHandler->reset();
389 }
390 
392  for (const auto& [waterIdx, water]: waters) {
393  for (const auto waterModel: water.waterModels) {
394  engine->removeEntity(waterModel->getId());
395  delete waterModel;
396  }
397  }
398  this->waters.clear();
399 }
400 
402  if (prototype == nullptr) return;
403 
404  //
405  const auto& foliageMaps = prototype->getTerrain()->getFoliageMaps();
406 
407  //
408  auto partitionIdx = 0;
409  for (auto& foliageMapPartition: foliageMaps) {
410  engine->removeEntity("foliage.entityhierarchy." + to_string(partitionIdx));
411  auto shaderParameterIdx = 0;
412  while (engine->removeEntity("foliage.objectrendergroup." + to_string(partitionIdx) + "." + to_string(shaderParameterIdx)) == true) shaderParameterIdx++;
413  auto partitionPrototypeInstanceCount = 0;
414  for (const auto& [prototypeIdx, transformVector]: foliageMapPartition) {
415  partitionPrototypeInstanceCount+= transformVector.size();
416  }
417  if (partitionPrototypeInstanceCount > 0) {
418  unordered_map<string, ObjectRenderGroup*> objectRenderGroupByShaderParameters;
419  for (const auto& [prototypeIdx, transformVector]: foliageMapPartition) {
420  if (transformVector.empty() == false) {
421  auto foliagePrototype = prototype->getTerrain()->getFoliagePrototype(prototypeIdx);
422  ObjectRenderGroup* foliagePartitionObjectRenderGroup = nullptr;
423  auto foliagePartitionObjectRenderGroupIt = objectRenderGroupByShaderParameters.find(foliagePrototype->getShaderParameters().getShaderParametersHash());
424  if (foliagePartitionObjectRenderGroupIt != objectRenderGroupByShaderParameters.end()) {
425  foliagePartitionObjectRenderGroup = foliagePartitionObjectRenderGroupIt->second;
426  }
427  if (foliagePartitionObjectRenderGroup == nullptr) {
428  foliagePartitionObjectRenderGroup = new ObjectRenderGroup(
429  "foliage.objectrendergroup." + to_string(partitionIdx) + "." + to_string(objectRenderGroupByShaderParameters.size()),
430  1,
431  25.0f,
432  50.0f,
433  4,
434  16,
435  false
436  );
437  foliagePartitionObjectRenderGroup->setContributesShadows(true);
438  foliagePartitionObjectRenderGroup->setReceivesShadows(true);
439  foliagePartitionObjectRenderGroup->setShader(foliagePrototype->getShader());
440  for (const auto& parameterName: Engine::getShaderParameterNames(foliagePrototype->getShader())) {
441  auto parameterValue = foliagePrototype->getShaderParameters().getShaderParameter(parameterName);
442  foliagePartitionObjectRenderGroup->setShaderParameter(parameterName, parameterValue);
443  }
444  engine->addEntity(foliagePartitionObjectRenderGroup);
445  objectRenderGroupByShaderParameters[foliagePrototype->getShaderParameters().getShaderParametersHash()] = foliagePartitionObjectRenderGroup;
446  }
447  for (const auto& transform: transformVector) {
448  foliagePartitionObjectRenderGroup->addObject(foliagePrototype->getModel(), transform);
449  }
450  }
451  }
452  for (const auto& [shaderHash, objectRenderGroup]: objectRenderGroupByShaderParameters) {
453  objectRenderGroup->updateRenderGroup();
454  }
455  }
456  partitionIdx++;
457  }
458 }
459 
460 void TerrainEditorTabView::addTemporaryFoliage(const vector<unordered_map<int, vector<Transform>>>& newFoliageMaps) {
461  if (prototype == nullptr) return;
462 
463  //
464  const auto& foliageMaps = prototype->getTerrain()->getFoliageMaps();
465 
466  //
467  auto partitionIdx = 0;
468  for (auto& foliageMapPartition: newFoliageMaps) {
469  auto partitionPrototypeInstanceCount = 0;
470  for (const auto& [prototypeIdx, transformVector]: foliageMapPartition) {
471  partitionPrototypeInstanceCount+= transformVector.size();
472  }
473  if (partitionPrototypeInstanceCount > 0) {
474  //
475  temporaryPartitionIdxs.insert(partitionIdx);
476 
477  //
478  auto foliagePartitionObjectRenderGroup = engine->getEntity("foliage.objectrendergroup." + to_string(partitionIdx) + ".0");
479  if (foliagePartitionObjectRenderGroup != nullptr) {
480  auto shaderParameterIdx = 0;
481  while (engine->removeEntity("foliage.objectrendergroup." + to_string(partitionIdx) + "." + to_string(shaderParameterIdx)) == true) shaderParameterIdx++;
482  recreateTemporaryFoliage(partitionIdx);
483  }
484  auto foliagePartitionEntityHierarchy = dynamic_cast<EntityHierarchy*>(engine->getEntity("foliage.entityhierarchy." + to_string(partitionIdx)));
485  if (foliagePartitionEntityHierarchy == nullptr) {
486  foliagePartitionEntityHierarchy = new EntityHierarchy("foliage.entityhierarchy." + to_string(partitionIdx));
487  foliagePartitionEntityHierarchy->setContributesShadows(true);
488  foliagePartitionEntityHierarchy->setReceivesShadows(true);
489  engine->addEntity(foliagePartitionEntityHierarchy);
490  }
491  for (const auto& [prototypeIdx, transformVector]: foliageMapPartition) {
492  if (transformVector.empty() == false) {
493  auto foliagePrototype = prototype->getTerrain()->getFoliagePrototype(prototypeIdx);
494  auto foliageIdx = partitionFoliageIdx[partitionIdx];
495  for (const auto& transform: transformVector) {
496  auto foliageEntity = SceneConnector::createEntity(foliagePrototype, foliagePartitionEntityHierarchy->getId() + "." + to_string(prototypeIdx) + "." + to_string(foliageIdx), transform);
497  foliagePartitionEntityHierarchy->addEntity(foliageEntity);
498  foliageIdx++;
499  }
500  }
501  }
502  foliagePartitionEntityHierarchy->update();
503  }
504  partitionIdx++;
505  }
506 }
507 
508 void TerrainEditorTabView::updateTemporaryFoliage(const unordered_set<int>& partitionIdxSet) {
509  if (prototype == nullptr) return;
510 
511  //
512  const auto& foliageMaps = prototype->getTerrain()->getFoliageMaps();
513 
514  //
515  auto partitionIdx = 0;
516  for (auto partitionIdx: partitionIdxSet) {
517  const auto& foliageMapPartition = foliageMaps[partitionIdx];
518  auto partitionPrototypeInstanceCount = 0;
519  for (const auto& [prototypeIdx, transformVector]: foliageMapPartition) {
520  partitionPrototypeInstanceCount+= transformVector.size();
521  }
522  if (partitionPrototypeInstanceCount > 0) {
523  //
524  temporaryPartitionIdxs.insert(partitionIdx);
525 
526  //
527  auto foliagePartitionObjectRenderGroup = engine->getEntity("foliage.objectrendergroup." + to_string(partitionIdx) + ".0");
528  auto foliagePartitionEntityHierarchy = dynamic_cast<EntityHierarchy*>(engine->getEntity("foliage.entityhierarchy." + to_string(partitionIdx)));
529  if (foliagePartitionObjectRenderGroup != nullptr || foliagePartitionEntityHierarchy == nullptr) {
530  auto shaderParameterIdx = 0;
531  while (engine->removeEntity("foliage.objectrendergroup." + to_string(partitionIdx) + "." + to_string(shaderParameterIdx)) == true) shaderParameterIdx++;
532  recreateTemporaryFoliage(partitionIdx);
533  }
534  if (foliagePartitionEntityHierarchy == nullptr) foliagePartitionEntityHierarchy = dynamic_cast<EntityHierarchy*>(engine->getEntity("foliage.entityhierarchy." + to_string(partitionIdx)));
535  auto foliageIdx = 0;
536  for (const auto& [prototypeIdx, transformVector]: foliageMapPartition) {
537  for (const auto& transform: transformVector) {
538  foliagePartitionEntityHierarchy->getEntities()[foliageIdx]->setTransform(transform);
539  foliageIdx++;
540  }
541  }
542  foliagePartitionEntityHierarchy->update();
543  }
544  partitionIdx++;
545  }
546 }
547 
549  if (prototype == nullptr) return;
550 
551  //
552  temporaryPartitionIdxs.insert(partitionIdx);
553 
554  //
555  const auto& foliageMaps = prototype->getTerrain()->getFoliageMaps();
556 
557  //
558  const auto& foliageMapPartition = foliageMaps[partitionIdx];
559  engine->removeEntity("foliage.entityhierarchy." + to_string(partitionIdx));
560  auto shaderParameterIdx = 0;
561  while (engine->removeEntity("foliage.objectrendergroup." + to_string(partitionIdx) + "." + to_string(shaderParameterIdx)) == true) shaderParameterIdx++;
562  auto partitionPrototypeInstanceCount = 0;
563  for (const auto& [prototypeIdx, transformVector]: foliageMapPartition) {
564  partitionPrototypeInstanceCount+= transformVector.size();
565  }
566  if (partitionPrototypeInstanceCount > 0) {
567  auto foliagePartitionEntityHierarchy = new EntityHierarchy("foliage.entityhierarchy." + to_string(partitionIdx));
568  foliagePartitionEntityHierarchy->setContributesShadows(true);
569  foliagePartitionEntityHierarchy->setReceivesShadows(true);
570  engine->addEntity(foliagePartitionEntityHierarchy);
571  for (const auto& [prototypeIdx, transformVector]: foliageMapPartition) {
572  auto foliagePrototype = prototype->getTerrain()->getFoliagePrototype(prototypeIdx);
573  auto foliageIdx = partitionFoliageIdx[partitionIdx];
574  for (const auto& transform: transformVector) {
575  auto foliageEntity = SceneConnector::createEntity(foliagePrototype, foliagePartitionEntityHierarchy->getId() + "." + to_string(prototypeIdx) + "." + to_string(foliageIdx), transform);
576  foliagePartitionEntityHierarchy->addEntity(foliageEntity);
577  foliageIdx++;
578  }
579  }
580  foliagePartitionEntityHierarchy->update();
581  }
582 }
583 
584 void TerrainEditorTabView::recreateFoliage(const unordered_set<int>& partitionIdxSet) {
585  if (prototype == nullptr) return;
586 
587  //
588  auto& foliageMaps = prototype->getTerrain()->getFoliageMaps();
589 
590  //
591  for (auto partitionIdx: partitionIdxSet) {
592  const auto& foliageMapPartition = foliageMaps[partitionIdx];
593  engine->removeEntity("foliage.entityhierarchy." + to_string(partitionIdx));
594  auto shaderParameterIdx = 0;
595  while (engine->removeEntity("foliage.objectrendergroup." + to_string(partitionIdx) + "." + to_string(shaderParameterIdx)) == true) shaderParameterIdx++;
596  auto partitionPrototypeInstanceCount = 0;
597  for (const auto& [prototypeIdx, transformVector]: foliageMapPartition) {
598  partitionPrototypeInstanceCount+= transformVector.size();
599  }
600  if (partitionPrototypeInstanceCount > 0) {
601  unordered_map<string, ObjectRenderGroup*> objectRenderGroupByShaderParameters;
602  for (const auto& [prototypeIdx, transformVector]: foliageMapPartition) {
603  if (transformVector.empty() == false) {
604  auto foliagePrototype = prototype->getTerrain()->getFoliagePrototype(prototypeIdx);
605  ObjectRenderGroup* foliagePartitionObjectRenderGroup = nullptr;
606  auto foliagePartitionObjectRenderGroupIt = objectRenderGroupByShaderParameters.find(foliagePrototype->getShaderParameters().getShaderParametersHash());
607  if (foliagePartitionObjectRenderGroupIt != objectRenderGroupByShaderParameters.end()) {
608  foliagePartitionObjectRenderGroup = foliagePartitionObjectRenderGroupIt->second;
609  }
610  if (foliagePartitionObjectRenderGroup == nullptr) {
611  foliagePartitionObjectRenderGroup = new ObjectRenderGroup(
612  "foliage.objectrendergroup." + to_string(partitionIdx) + "." + to_string(objectRenderGroupByShaderParameters.size()),
613  1,
614  25.0f,
615  50.0f,
616  4,
617  16,
618  false
619  );
620  foliagePartitionObjectRenderGroup->setContributesShadows(true);
621  foliagePartitionObjectRenderGroup->setReceivesShadows(true);
622  foliagePartitionObjectRenderGroup->setShader(foliagePrototype->getShader());
623  for (const auto& parameterName: Engine::getShaderParameterNames(foliagePrototype->getShader())) {
624  auto parameterValue = foliagePrototype->getShaderParameters().getShaderParameter(parameterName);
625  foliagePartitionObjectRenderGroup->setShaderParameter(parameterName, parameterValue);
626  }
627  engine->addEntity(foliagePartitionObjectRenderGroup);
628  objectRenderGroupByShaderParameters[foliagePrototype->getShaderParameters().getShaderParametersHash()] = foliagePartitionObjectRenderGroup;
629  }
630  for (const auto& transform: transformVector) {
631  foliagePartitionObjectRenderGroup->addObject(foliagePrototype->getModel(), transform);
632  }
633  }
634  }
635  for (const auto& [shaderHash, objectRenderGroup]: objectRenderGroupByShaderParameters) {
636  objectRenderGroup->updateRenderGroup();
637  }
638  }
639  }
640 }
641 
643  const auto& water = waters[waterIdx];
644  for (auto waterModel: water.waterModels) {
645  engine->removeEntity(waterModel->getId());
646  delete waterModel;
647  }
648  waters.erase(waterIdx);
649 }
650 
651 void TerrainEditorTabView::addWater(int waterIdx, vector<Model*> waterModels, const Vector3& waterReflectionEnvironmentMappingPosition) {
652  auto& water = waters[waterIdx];
653  for (auto waterModel: water.waterModels) {
654  engine->removeEntity(waterModel->getId());
655  delete waterModel;
656  }
657  water.waterModels = waterModels;
658  water.waterReflectionEnvironmentMappingPosition = waterReflectionEnvironmentMappingPosition;
659 }
660 
662  for (auto terrainModel: this->terrainModels) delete terrainModel;
664  this->terrainModels.clear();
665  this->partitionFoliageIdx.clear();
666 }
667 
668 void TerrainEditorTabView::setTerrain(BoundingBox& terrainBoundingBox, vector<Model*> terrainModels) {
669  unsetTerrain();
670  this->terrainBoundingBox = terrainBoundingBox;
671  this->terrainModels = terrainModels;
672  this->partitionFoliageIdx.resize(terrainModels.size());
673 }
674 
675 void TerrainEditorTabView::setBrush(Texture* texture, float scale, float densityStrength) {
676  unsetBrush();
677  if (brushTexture != nullptr) {
678  engine->getTextureManager()->removeTexture(brushTexture);
680  }
681  brushTexture = texture;
682  if (brushTexture != nullptr) brushTexture->acquireReference();
683  //
684  brushScale = scale;
685  rampMode = -1;
686  brushDensityStrength = densityStrength;
687  engine->setShaderParameter("terraineditor", "brushTexture", brushTexture == nullptr?0:engine->getTextureManager()->addTexture(brushTexture));
688  engine->setShaderParameter(
689  "terraineditor",
690  "brushEnabled",
691  (terrainEditorTabController->getTerrainBrushOperation() != Terrain::BRUSHOPERATION_NONE && terrainEditorTabController->getTerrainBrushOperation() != Terrain::BRUSHOPERATION_RAMP) ||
692  terrainEditorTabController->getFoliageBrushOperation() != Terrain::BRUSHOPERATION_NONE
693  );
694  if (texture == nullptr) return;
695  auto _scale = terrainEditorTabController->getTerrainBrushOperation() != Terrain::BRUSHOPERATION_RAMP?scale:1.0f;
696  engine->setShaderParameter("terraineditor", "brushDimension", Vector2(static_cast<int>(texture->getTextureWidth()) * _scale, static_cast<int>(texture->getTextureHeight()) * _scale));
697 }
698 
700  if (brushTexture == nullptr ||
701  terrainEditorTabController->getTerrainBrushOperation() == Terrain::BRUSHOPERATION_RAMP ||
702  terrainEditorTabController->getTerrainBrushOperation() == Terrain::BRUSHOPERATION_WATER_ADD ||
703  (terrainEditorTabController->getTerrainBrushOperation() == Terrain::BRUSHOPERATION_NONE && terrainEditorTabController->getFoliageBrushOperation() == Terrain::BRUSHOPERATION_NONE)) return;
704  engine->setShaderParameter("terraineditor", "brushDimension", Vector2(static_cast<int>(brushTexture->getTextureWidth()) * scale, static_cast<int>(brushTexture->getTextureHeight()) * scale));
705  brushScale = scale;
706  terrainEditorTabController->setBrushScale(scale);
707 }
708 
710  if (brushTexture == nullptr ||
711  terrainEditorTabController->getTerrainBrushOperation() == Terrain::BRUSHOPERATION_RAMP ||
712  terrainEditorTabController->getTerrainBrushOperation() == Terrain::BRUSHOPERATION_WATER_ADD ||
713  (terrainEditorTabController->getTerrainBrushOperation() == Terrain::BRUSHOPERATION_NONE && terrainEditorTabController->getFoliageBrushOperation() == Terrain::BRUSHOPERATION_NONE)) return;
714  brushDensityStrength = densityStrength;
715  terrainEditorTabController->setBrushDensityStrength(densityStrength);
716 }
717 
719  if (brushTexture != nullptr) {
720  engine->getTextureManager()->removeTexture(brushTexture->getId());
722  brushTexture = nullptr;
723  engine->setShaderParameter("terraineditor", "brushEnabled", false);
724  }
725 }
#define MOUSE_BUTTON_LEFT
#define MOUSE_BUTTON_RIGHT
Color 4 definition class.
Definition: Color4.h:18
Engine main class.
Definition: Engine.h:131
Entity hierarchy to be used with engine class.
const vector< Entity * > & getEntities()
Environment mapping entity.
Light representation.
Definition: Light.h:33
Object render group for static objects that might be animated by shaders.
void setShader(const string &id)
Set shader id.
void setReceivesShadows(bool receivesShadows) override
Enable/disable receives shadows.
void setShaderParameter(const string &parameterName, const ShaderParameter &parameterValue)
Set shader parameter for given parameter name.
void addObject(Model *model, const Transform &transform)
Adds a instance to this render group.
void setContributesShadows(bool contributesShadows) override
Enable/disable contributes shadows.
Object to be used with engine class.
Definition: Object.h:60
Scene engine/physics connector.
Texture entity.
Definition: Texture.h:24
const string & getId() const
Definition: Texture.h:172
uint16_t getTextureHeight() const
Definition: Texture.h:211
uint16_t getTextureWidth() const
Definition: Texture.h:218
Timing class.
Definition: Timing.h:16
Represents a material.
Definition: Material.h:23
Represents specular material properties.
Axis aligned bounding box used for frustum, this is not directly connectable with physics engine.
Definition: BoundingBox.h:26
const Vector3 & getCenter() const
Definition: BoundingBox.h:121
Prototype definition.
Definition: Prototype.h:55
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
Vector2 class representing vector2 mathematical structure and operations with x, y components.
Definition: Vector2.h:20
Vector3 class representing vector3 mathematical structure and operations with x, y,...
Definition: Vector3.h:20
float getY() const
Definition: Vector3.h:117
float getX() const
Definition: Vector3.h:100
float getZ() const
Definition: Vector3.h:134
Vector3 & set(float x, float y, float z)
Sets this vector3 by its components.
Definition: Vector3.h:70
void restoreOutlinerState(const TabView::OutlinerState &outlinerState)
Restore outliner state.
void storeOutlinerState(TabView::OutlinerState &outlinerState)
Store outliner state.
void setDetailsContent(const string &xml)
Set details content.
void saveFile(const string &pathName, const string &fileName)
Saving prototype as tmodel prototype.
void recreateFoliage(const unordered_set< int > &partitionIdxSet)
Recreate foliage using render groups at given partition indices that has been transformed to temporar...
void addTemporaryFoliage(const vector< unordered_map< int, vector< Transform >>> &newFoliageMaps)
Add temporary foliage.
void addWater(int waterIdx, vector< Model * > waterModels, const Vector3 &waterReflectionEnvironmentMappingPosition)
Add water.
void updateTemporaryFoliage(const unordered_set< int > &partitionIdxSet)
Update temporary foliage.
void addFoliage()
Add foliage using render groups at given partition indices.
void setBrushDensityStrength(float densityStrength)
Set brush density/strength.
void handleInputEvents() override
Handle input events that have not yet been processed.
void recreateTemporaryFoliage(const unordered_set< int > &partitionIdxSet)
Recreate temporary foliage at given partition indices.
unique_ptr< TerrainEditorTabController > terrainEditorTabController
void setBrush(Texture *texture, float scale, float densityStrength)
Set brush.
void setTerrain(BoundingBox &terrainBoundingBox, vector< Model * > terrainModels)
Set terrain models.
EditorScreenController * getScreenController()
Definition: EditorView.h:69
Console class.
Definition: Console.h:29
Integer class.
Definition: Integer.h:25
Mutable utf8 aware string class.
Definition: MutableString.h:23
MutableString & append(char c)
Append character.
virtual void releaseReference()
Releases a reference, thus decrementing the counter and delete it if reference counter is zero.
Definition: Reference.h:38
virtual void acquireReference()
Acquires a reference, incrementing the counter.
Definition: Reference.h:31
String tools class.
Definition: StringTools.h:22
Terrain utility.
Definition: Terrain.h:33
std::exception Exception
Exception base class.
Definition: Exception.h:18