Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Connect GUI to the Lod system.

  • Loading branch information...
commit e96bb20e73aa78aa8760ac32250dde0e649177df 1 parent c713dbb
@sajty authored
View
6 src/components/ogre/scripting/bindings/lua/EmberOgre.pkg
@@ -68,12 +68,18 @@ $pfile "ModelDefinition.pkg"
$pfile "Convert.pkg"
+$pfile "LodDefinition.pkg"
+$pfile "LodDefinitionManager.pkg"
+$pfile "LodManager.pkg"
$pfile "SimpleRenderContext.pkg"
$pfile "MovableObjectRenderer.pkg"
$pfile "OgreEntityRenderer.pkg"
$pfile "ModelRenderer.pkg"
$pfile "ListHolder.pkg"
+
+$pfile "MeshInfoProvider.pkg"
+
//$pfile "MaterialPicker.pkg"
$pfile "IWorldPickListener.pkg"
View
193 src/components/ogre/scripting/bindings/lua/LodDefinition.pkg
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2012 Peter Szucs <peter.szucs.dev@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+namespace Ember
+{
+namespace OgreView
+{
+namespace Lod
+{
+
+/**
+ * @brief Improved version of Ogre::ProgressiveMesh.
+ */
+class ProgressiveMeshGenerator
+{
+public:
+ /**
+ * @brief Type of the reduction.
+ *
+ * Note: The vertex count is determined by unique vertices per submesh.
+ * A mesh may have duplicate vertices with same position.
+ */
+ enum VertexReductionMethod {
+ /**
+ * @brief Percentage of vertexes to be removed from each submesh.
+ *
+ * Valid range is a number between 0.0 and 1.0
+ */
+ VRM_PROPORTIONAL,
+
+ /**
+ * @brief Exact vertex count to be removed from each submesh.
+ *
+ * Pass only integers or it will be rounded.
+ */
+ VRM_CONSTANT,
+
+ /**
+ * @brief Reduces the vertices, until the cost is bigger then the given value.
+ *
+ * Collapse cost is equal to the amount of artifact the reduction causes.
+ * This generates the best Lod output, but the collapse cost depends on implementation.
+ */
+ VRM_COLLAPSE_COST
+ };
+};
+
+/**
+ * @brief Lod Distance config container.
+ */
+class LodDistance
+{
+public:
+
+ /**
+ * @brief Enumeration of Distance types.
+ */
+ enum LodDistanceType {
+
+ /**
+ * @brief A built in algorithm should reduce the vertex count.
+ */
+ LDT_AUTOMATIC_VERTEX_REDUCTION,
+
+ /**
+ * @brief User created mesh should be used.
+ */
+ LDT_USER_CREATED_MESH
+ };
+
+ /**
+ * @brief Returns the type of the Lod Distance.
+ */
+ Ember::OgreView::Lod::LodDistance::LodDistanceType getType() const;
+
+ /**
+ * @brief Sets the type of the Lod Distance
+ */
+ void setType(Ember::OgreView::Lod::LodDistance::LodDistanceType type);
+
+ /**
+ * @brief Returns the mesh name of the Lod Distance, which is used in user created meshes.
+ */
+ const std::string& getMeshName() const;
+
+ /**
+ * @brief Sets the mesh name of the Lod Distance, which is used in user created meshes.
+ */
+ void setMeshName(const std::string& meshName);
+
+ /**
+ * @brief Returns the vertex reduction method of the Lod Distance, which is used in automatic vertex reduction.
+ */
+ Ember::OgreView::Lod::ProgressiveMeshGenerator::VertexReductionMethod getReductionMethod() const;
+
+ /**
+ * @brief Sets the vertex reduction method of the Lod Distance, which is used in automatic vertex reduction.
+ */
+ void setReductionMethod(Ember::OgreView::Lod::ProgressiveMeshGenerator::VertexReductionMethod reductionMethod);
+
+ /**
+ * @brief Returns the vertex reduction value of the Lod Distance, which is used in automatic vertex reduction.
+ */
+ float getReductionValue() const;
+
+ /**
+ * @brief Sets the vertex reduction value of the Lod Distance, which is used in automatic vertex reduction.
+ */
+ void setReductionValue(float reductionValue);
+};
+
+/**
+ * @brief Lod Definition resource. Each *.loddef file is represented by a LodDefinition instance.
+ */
+class LodDefinition :
+ public Ogre::Resource
+{
+public:
+ /**
+ * @brief Returns whether automatic mesh Lod management is used.
+ */
+ bool getUseAutomaticLod() const;
+
+ /**
+ * @brief Sets whether automatic mesh Lod management should be used.
+ */
+ void setUseAutomaticLod(bool useAutomaticLod);
+
+ /**
+ * @brief Adds a Lod distance to the manual Lod configuration.
+ */
+ void addLodDistance(float distVal, const Ember::OgreView::Lod::LodDistance& distance);
+
+ /**
+ * @brief Returns whether a Lod distance is existing in a manual Lod configuration.
+ */
+ bool hasLodDistance(float distVal) const;
+
+ /**
+ * @brief Returns a Lod distance from the manual Lod configuration.
+ */
+ Ember::OgreView::Lod::LodDistance& getLodDistance(float distVal);
+
+ /**
+ * @brief Returns a Lod distance count for the manual Lod configuration.
+ */
+ int getLodDistanceCount();
+
+ /**
+ * @brief Creates a list of distances in a sorted order.
+ *
+ * This is meant for lua calls only.
+ */
+ std::vector<float> createListOfDistances();
+
+ /**
+ * @brief Creates a distance.
+ *
+ * This is meant for lua calls only. Use addLodDistance() if you can.
+ */
+ LodDistance& createDistance(float distance);
+
+ /**
+ * @brief Removes a Lod distance from the manual Lod configuration.
+ */
+ void removeLodDistance(float distVal);
+};
+
+class LodDefinitionPtr
+{
+ virtual ~LodDefinitionPtr();
+ Ember::OgreView::Lod::LodDefinition* get();
+};
+
+}
+}
+}
+
View
37 src/components/ogre/scripting/bindings/lua/LodDefinitionManager.pkg
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2012 Peter Szucs <peter.szucs.dev@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+namespace Ember
+{
+namespace OgreView
+{
+namespace Lod
+{
+
+class LodDefinitionManager : public Ogre::ResourceManager
+{
+public:
+ static LodDefinitionManager& getSingleton();
+ void exportScript(std::string meshName, Ember::OgreView::Lod::LodDefinitionPtr definition);
+ Ember::OgreView::Lod::LodDefinitionPtr create(const std::string& name, const std::string& group);
+ Ember::OgreView::Lod::LodDefinitionPtr getByName(const std::string& name);
+};
+
+}
+}
+}
View
36 src/components/ogre/scripting/bindings/lua/LodManager.pkg
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2012 Peter Szucs <peter.szucs.dev@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+namespace Ember
+{
+namespace OgreView
+{
+namespace Lod
+{
+
+class LodManager
+{
+public:
+ static LodManager& getSingleton();
+ void loadLod(Ogre::Mesh& mesh);
+ void loadLod(Ogre::Mesh& mesh, const Ember::OgreView::Lod::LodDefinition& definition);
+};
+
+}
+}
+}
View
41 src/components/ogre/scripting/bindings/lua/MeshInfoProvider.pkg
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2012 Peter Szucs <peter.szucs.dev@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+namespace Ember
+{
+namespace OgreView
+{
+namespace Gui
+{
+
+class MeshInfoProvider
+{
+public:
+ sigc::signal<void> EventLodChanged;
+
+ MeshInfoProvider(OgreEntityRenderer* entityRenderer);
+ ~MeshInfoProvider();
+ std::string getInfo(int submeshIndex);
+ std::string getPreviewInfo();
+ void postqueueEntityMeshLodChanged(const Ogre::EntityMeshLodChangedEvent& evt);
+ int getLodIndex();
+};
+
+}
+}
+}
View
1  src/components/ogre/scripting/bindings/lua/ModelDefinition.pkg
@@ -189,6 +189,7 @@ class ModelDefinition : public Ogre::Resource {
MODEL_WIDTH = 2,
MODEL_DEPTH = 3,
MODEL_HEIGHT = 4
+
};
/**
View
2  src/components/ogre/scripting/bindings/lua/OgreEntityRenderer.pkg
@@ -43,6 +43,8 @@ public:
*/
void showEntity(const std::string& mesh);
+ void unloadEntity();
+
/**
* Returns the current rendered Entity, or null if none is set.
* @return
View
2  src/components/ogre/scripting/bindings/lua/ogre/OgreMesh.pkg
@@ -306,7 +306,7 @@ namespace Ogre {
// void _setSubMeshLodFaceList(unsigned short subIdx, unsigned short level, IndexData* facedata);
/** Removes all LOD data from this Mesh. */
-// void removeLodLevels(void);
+ void removeLodLevels(void);
/** Sets the policy for the vertex buffers to be used when loading
this Mesh.
View
6 src/components/ogre/scripting/bindings/lua/required.h
@@ -26,6 +26,10 @@
#include "components/ogre/model/Model.h"
#include "components/ogre/model/SubModel.h"
+#include "components/ogre/lod/LodDefinition.h"
+#include "components/ogre/lod/LodDefinitionManager.h"
+#include "components/ogre/lod/LodManager.h"
+
#include "components/ogre/widgets/Widget.h"
#include "components/ogre/Convert.h"
@@ -40,8 +44,10 @@
#include "components/ogre/widgets/StackableContainer.h"
#include "components/ogre/widgets/ConsoleAdapter.h"
#include "components/ogre/widgets/ColouredListItem.h"
+#include "components/ogre/widgets/MeshInfoProvider.h"
#include "components/ogre/widgets/adapters/atlas/MapAdapter.h"
+
#include "components/ogre/widgets/IconBar.h"
#include "components/ogre/widgets/IconBase.h"
//#include "components/ogre/widgets/MaterialPicker.h"
View
2  src/components/ogre/scripting/bindings/lua/stdlib.pkg
@@ -1,7 +1,7 @@
namespace std {
class vector {
- TEMPLATE_BIND(T, std::string, Ember::OgreView::Model::SubModelDefinition*, Ember::OgreView::Model::PartDefinition*, Ember::OgreView::Model::SubEntityDefinition*, Eris::Task*, Ember::OgreView::EntityPickResult, Ember::OgreView::Model::AttachPointDefinition, Ember::OgreView::Model::AnimationPartDefinition*, Ember::OgreView::Model::AnimationDefinition*, Ember::OgreView::Model::SoundDefinition*, Ember::OgreView::Model::ActivationDefinition*, Ember::OgreView::Model::ActionDefinition*)
+ TEMPLATE_BIND(T, std::string, float, Ember::OgreView::Model::SubModelDefinition*, Ember::OgreView::Model::PartDefinition*, Ember::OgreView::Model::SubEntityDefinition*, Eris::Task*, Ember::OgreView::EntityPickResult, Ember::OgreView::Model::AttachPointDefinition, Ember::OgreView::Model::AnimationPartDefinition*, Ember::OgreView::Model::AnimationDefinition*, Ember::OgreView::Model::SoundDefinition*, Ember::OgreView::Model::ActivationDefinition*, Ember::OgreView::Model::ActionDefinition*)
void clear();
int size() const;
View
392 src/components/ogre/widgets/AssetsManager.layout
@@ -95,96 +95,338 @@
</Window>
</Window>
<Window Type='DefaultWindow' Name='Meshes'>
- <Property Name='UnifiedSize' Value='{{1.0,0.0},{1.0,0.0}}'/>
<Property Name='Text' Value='Meshes'/>
- <Property Name='InheritsAlpha' Value='false'/>
- <Property Name='Visible' Value='false'/>
+ <Property Name='InheritsAlpha' Value='False'/>
+ <Property Name='UnifiedAreaRect' Value='{{0,0},{0,0},{1,0},{1,0}}'/>
<Window Type='EmberLook/Editbox' Name='FilterMeshes'>
- <Property Name='UnifiedPosition' Value='{{0,0},{1.0,-50}}'/>
- <Property Name='UnifiedSize' Value='{{0,75},{0,25}}'/>
- <Property Name='InheritsAlpha' Value='True'/>
+ <Property Name='MaxTextLength' Value='1073741823'/>
+ <Property Name='UnifiedAreaRect' Value='{{0,4},{1,-29},{0,139},{1,-4}}'/>
+ <Property Name='TextParsingEnabled' Value='False'/>
</Window>
<Window Type='EmberLook/Button' Name='MeshesRefresh'>
- <Property Name='UnifiedPosition' Value='{{0,0},{1.0,-20}}'/>
- <Property Name='UnifiedSize' Value='{{0,75},{0,20}}'/>
<Property Name='Text' Value='Refresh'/>
- <Property Name='InheritsAlpha' Value='True'/>
+ <Property Name='UnifiedAreaRect' Value='{{0,145},{1,-27},{0,200},{1,-4}}'/>
</Window>
<Window Type='EmberLook/Listbox' Name='MeshesList'>
- <Property Name='UnifiedPosition' Value='{{0,4},{0,4}}'/>
- <Property Name='UnifiedSize' Value='{{0,200},{1,-70}}'/>
- <Property Name='InheritsAlpha' Value='True'/>
+ <Property Name='UnifiedAreaRect' Value='{{0,6},{0,6},{0,203},{1,-31}}'/>
</Window>
<Window Type='EmberLook/StaticText' Name='MeshInfo'>
- <Property Name='UnifiedPosition' Value='{{0,205},{0,4}}'/>
- <Property Name='UnifiedSize' Value='{{1,-210},{1,-70}}'/>
- <Property Name='Text' Value=''/>
- <Property Name='InheritsAlpha' Value='True'/>
- <Property Name='VertFormatting' Value='TopAligned'/>
<Property Name='HorzFormatting' Value='WordWrapLeftAligned'/>
- <Window Type='EmberLook/StaticImage' Name='MeshInfo/Preview'>
- <Property Name='UnifiedPosition' Value='{{0,0},{0,0}}'/>
- <Property Name='UnifiedSize' Value='{{1,0},{1,-30}}'/>
- <Window Type='EmberLook/StaticText' Name='MeshInfoEdit'>
- <Property Name='UnifiedPosition' Value='{{0,0},{0,0}}'/>
- <Property Name='UnifiedSize' Value='{{1,0},{0.5,0}}'/>
- <Property Name='Text' Value=''/>
- <Property Name='InheritsAlpha' Value='True'/>
- <Property Name='VertFormatting' Value='TopAligned'/>
- <Property Name='HorzFormatting' Value='WordWrapLeftAligned'/>
- <Property Name='Visible' Value='False'/>
- <Window Type='EmberLook/Listbox' Name='SubMeshesList'>
- <Property Name='UnifiedPosition' Value='{{0,0},{0,30}}'/>
- <Property Name='UnifiedSize' Value='{{0,200},{1,-40}}'/>
- <Property Name='InheritsAlpha' Value='True'/>
- </Window>
- <Window Type='EmberLook/Listbox' Name='SubMeshMaterialsList'>
- <Property Name='UnifiedPosition' Value='{{0,210},{0,5}}'/>
- <Property Name='UnifiedSize' Value='{{0,200},{1,-45}}'/>
- <Property Name='InheritsAlpha' Value='True'/>
+ <Property Name='VertFormatting' Value='TopAligned'/>
+ <Property Name='UnifiedAreaRect' Value='{{0,210},{0,4},{1,-4},{1,-4}}'/>
+ <Property Name='HorzScrollPageSize' Value='764'/>
+ <Property Name='HorzScrollPosition' Value='0'/>
+ <Property Name='VertScrollPageSize' Value='543'/>
+ <Property Name='VertScrollPosition' Value='0'/>
+ <Property Name='HorzScrollDocumentSize' Value='0'/>
+ <Property Name='VertScrollDocumentSize' Value='0'/>
+ <Window Type='EmberLook/Listbox' Name='SubMeshesList'>
+ <Property Name='UnifiedAreaRect' Value='{{0,4},{0,60},{0,155},{1,-400}}'/>
+ </Window>
+ <Window Type='EmberLook/Listbox' Name='SubMeshMaterialsList'>
+ <Property Name='UnifiedAreaRect' Value='{{0,158},{0,59},{0,325},{1,-262}}'/>
+ </Window>
+ <Window Type='EmberLook/Editbox' Name='SubMeshMaterialsFilter'>
+ <Property Name='MaxTextLength' Value='1073741823'/>
+ <Property Name='UnifiedAreaRect' Value='{{0,159},{1,-259},{0,325},{1,-234}}'/>
+ <Property Name='TextParsingEnabled' Value='False'/>
+ </Window>
+ <Window Type='EmberLook/StaticText' Name='MeshSkeletonPathText'>
+ <Property Name='Text'>Skeleton
+ </Property>
+ <Property Name='HorzExtent' Value='34'/>
+ <Property Name='VertExtent' Value='9.3125'/>
+ <Property Name='FrameEnabled' Value='False'/>
+ <Property Name='HorzFormatting' Value='HorzCentred'/>
+ <Property Name='UnifiedAreaRect' Value='{{0,161},{0,0},{0,322},{0,20}}'/>
+ <Property Name='BackgroundEnabled' Value='False'/>
+ <Property Name='HorzScrollPageSize' Value='161'/>
+ <Property Name='HorzScrollPosition' Value='0'/>
+ <Property Name='VertScrollPageSize' Value='20'/>
+ <Property Name='VertScrollPosition' Value='0'/>
+ <Property Name='HorzScrollDocumentSize' Value='34'/>
+ <Property Name='VertScrollDocumentSize' Value='9.3125'/>
+ </Window>
+ <Window Type='EmberLook/Editbox' Name='MeshSkeletonPath'>
+ <Property Name='MaxTextLength' Value='1073741823'/>
+ <Property Name='UnifiedAreaRect' Value='{{0,159},{0,19},{0,324},{0,45}}'/>
+ <Property Name='TextParsingEnabled' Value='False'/>
+ </Window>
+ <Window Type='EmberLook/Checkbox' Name='EnableAutomaticLOD'>
+ <Property Name='Text' Value='Enable automatic mesh Lod management'/>
+ <Property Name='UnifiedAreaRect' Value='{{0,4},{1,-235},{0,300},{1,-210}}'/>
+ </Window>
+ <Window Type='EmberLook/Static' Name='ManualLODContainer'>
+ <Property Name='UnifiedAreaRect' Value='{{0,4},{1,-212},{1,-4},{1,-4}}'/>
+ <Property Name='BackgroundEnabled' Value='False'/>
+ <Window Type='EmberLook/Listbox' Name='LODDistances'>
+ <Property Name='Sort' Value='True'/>
+ <Property Name='UnifiedAreaRect' Value='{{0.00709466,0},{0.108646,0},{0.141162,0},{0.705454,0}}'/>
+ </Window>
+ <Window Type='EmberLook/Static' Name='LODConfigContainer'>
+ <Property Name='UnifiedAreaRect' Value='{{0.148038,0},{0,4},{1,-4},{1,-4}}'/>
+ <Property Name='BackgroundEnabled' Value='False'/>
+ <Window Type='EmberLook/Combobox' Name='LODTypeCombobox'>
+ <Property Name='Text' Value='Automatic vertex reduction'/>
+ <Property Name='ReadOnly' Value='True'/>
+ <Property Name='UnifiedAreaRect' Value='{{0,4},{0,9},{0.255268,0},{0.388408,0}}'/>
+ <Property Name='MaxEditTextLength' Value='1073741823'/>
</Window>
- <Window Type='EmberLook/Editbox' Name='SubMeshMaterialsFilter'>
- <Property Name='UnifiedPosition' Value='{{0,210},{1,-35}}'/>
- <Property Name='UnifiedSize' Value='{{0,150},{0,25}}'/>
- </Window>
- <Window Type='EmberLook/StaticText' Name='MeshSkeletonPathText'>
- <Property Name='UnifiedPosition' Value='{{0,420},{0,5}}'/>
- <Property Name='UnifiedSize' Value='{{0,75},{0,25}}'/>
- <Property Name='FrameEnabled' Value='false' />
- <Property Name='BackgroundEnabled' Value='false' />
- <Property Name='Text' Value='Skeleton path:' />
+ <Window Type='EmberLook/Static' Name='ManuallyCreatedLODContainer'>
+ <Property Name='Visible' Value='False'/>
+ <Property Name='UnifiedAreaRect' Value='{{0,4},{0.172712,0},{1,-4},{1,-4}}'/>
+ <Property Name='BackgroundEnabled' Value='False'/>
+ <Window Type='EmberLook/StaticText' Name='ManuallyCreatedLODDescription_text'>
+ <Property Name='Text'>Manually created LOD allows you to create
+ each LOD level in blender as separated meshes.
+ </Property>
+ <Property Name='HorzExtent' Value='199'/>
+ <Property Name='VertExtent' Value='18.625'/>
+ <Property Name='FrameEnabled' Value='False'/>
+ <Property Name='HorzFormatting' Value='HorzCentred'/>
+ <Property Name='UnifiedAreaRect' Value='{{0.642743,0},{0.0311913,0},{0.989639,0},{0.214714,0}}'/>
+ <Property Name='BackgroundEnabled' Value='False'/>
+ <Property Name='HorzScrollPageSize' Value='220'/>
+ <Property Name='HorzScrollPosition' Value='0'/>
+ <Property Name='VertScrollPageSize' Value='30'/>
+ <Property Name='VertScrollPosition' Value='0'/>
+ <Property Name='HorzScrollDocumentSize' Value='199'/>
+ <Property Name='VertScrollDocumentSize' Value='18.625'/>
+ </Window>
+ <Window Type='EmberLook/Editbox' Name='UserMeshFilter'>
+ <Property Name='MaxTextLength' Value='1073741823'/>
+ <Property Name='UnifiedAreaRect' Value='{{0.008,0},{0.8,0},{0.38,0},{0.97,0}}'/>
+ <Property Name='TextParsingEnabled' Value='False'/>
+ </Window>
+ <Window Type='EmberLook/Listbox' Name='UserMeshList'>
+ <Property Name='UnifiedAreaRect' Value='{{0.008,0},{0.033436,0},{0.54,0},{0.800201,0}}'/>
+ </Window>
+ <Window Type='EmberLook/Button' Name='UserMeshRefresh'>
+ <Property Name='Text' Value='Refresh'/>
+ <Property Name='UnifiedAreaRect' Value='{{0.384229,0},{0.8,0},{0.54,0},{0.97,0}}'/>
+ </Window>
</Window>
- <Window Type='EmberLook/Editbox' Name='MeshSkeletonPath'>
- <Property Name='UnifiedPosition' Value='{{0,420},{0,30}}'/>
- <Property Name='UnifiedSize' Value='{{0,200},{0,25}}'/>
- </Window>
- <Window Type='EmberLook/StaticText' Name='MeshLodLevelText'>
- <Property Name='UnifiedPosition' Value='{{0,420},{0,60}}'/>
- <Property Name='UnifiedSize' Value='{{0,75},{0,25}}'/>
- <Property Name='FrameEnabled' Value='false' />
- <Property Name='BackgroundEnabled' Value='false' />
- <Property Name='Text' Value='Lod level:' />
- </Window>
- <Window Type='EmberLook/Listbox' Name='MeshLodLevel'>
- <Property Name='UnifiedPosition' Value='{{0,420},{0,90}}'/>
- <Property Name='UnifiedSize' Value='{{0,100},{0,100}}'/>
- </Window>
- <Window Type='EmberLook/Button' Name='MeshInfoSaveButton'>
- <Property Name='UnifiedPosition' Value='{{0,55},{0,5}}'/>
- <Property Name='UnifiedSize' Value='{{0,50},{0,25}}'/>
- <Property Name='Text' Value='Save'/>
- <Property Name='InheritsAlpha' Value='True'/>
- <Property Name='Tooltip' Value='Save the mesh to disk' />
+ <Window Type='EmberLook/Static' Name='AutomaticVertexReductionContainer'>
+ <Property Name='UnifiedAreaRect' Value='{{0,4},{0.172712,0},{1,-4},{1,-4}}'/>
+ <Property Name='BackgroundEnabled' Value='False'/>
+ <Window Type='EmberLook/StaticText' Name='LODVertexReductionDescription_text'>
+ <Property Name='Text'>Automatic vertex reduction uses an algorithm to reduce vertex count.
+ There are two algorithms availible and each has a different parameter:
+
+ -Proportional: You need to pass the percent of reduced vertices.
+ -Constant: You need to pass a fixed vertex count to reduce.
+ </Property>
+ <Property Name='HorzExtent' Value='302'/>
+ <Property Name='VertExtent' Value='37.25'/>
+ <Property Name='FrameEnabled' Value='False'/>
+ <Property Name='VertFormatting' Value='TopAligned'/>
+ <Property Name='UnifiedAreaRect' Value='{{0.509811,0},{0.061043,0},{0.980437,0},{0.528173,0}}'/>
+ <Property Name='BackgroundEnabled' Value='False'/>
+ <Property Name='HorzScrollPageSize' Value='298'/>
+ <Property Name='HorzScrollPosition' Value='0'/>
+ <Property Name='VertScrollPageSize' Value='75'/>
+ <Property Name='VertScrollPosition' Value='0'/>
+ <Property Name='HorzScrollDocumentSize' Value='302'/>
+ <Property Name='VertScrollDocumentSize' Value='37.25'/>
+ </Window>
+ <Window Type='EmberLook/Combobox' Name='LODReductionTypeCombobox'>
+ <Property Name='Text' Value='Proportional'/>
+ <Property Name='ReadOnly' Value='True'/>
+ <Property Name='UnifiedAreaRect' Value='{{0.247391,0},{0.037798,0},{0.446224,0},{0.349673,0}}'/>
+ <Property Name='MaxEditTextLength' Value='1073741823'/>
+ </Window>
+ <Window Type='EmberLook/StaticText' Name='LODReductionType_text'>
+ <Property Name='Text' Value='Reduction algorithm:'/>
+ <Property Name='HorzExtent' Value='91'/>
+ <Property Name='VertExtent' Value='9.3125'/>
+ <Property Name='FrameEnabled' Value='False'/>
+ <Property Name='HorzFormatting' Value='RightAligned'/>
+ <Property Name='UnifiedAreaRect' Value='{{0.0221421,0},{0.0523937,0},{0.20837,0},{0.161608,0}}'/>
+ <Property Name='BackgroundEnabled' Value='False'/>
+ <Property Name='HorzScrollPageSize' Value='118'/>
+ <Property Name='HorzScrollPosition' Value='0'/>
+ <Property Name='VertScrollPageSize' Value='18'/>
+ <Property Name='VertScrollPosition' Value='0'/>
+ <Property Name='HorzScrollDocumentSize' Value='91'/>
+ <Property Name='VertScrollDocumentSize' Value='9.3125'/>
+ </Window>
+ <Window Type='EmberLook/StaticText' Name='LODReductionParameter_text'>
+ <Property Name='Text' Value='Parameter:'/>
+ <Property Name='HorzExtent' Value='47'/>
+ <Property Name='VertExtent' Value='9.3125'/>
+ <Property Name='FrameEnabled' Value='False'/>
+ <Property Name='HorzFormatting' Value='RightAligned'/>
+ <Property Name='UnifiedAreaRect' Value='{{0.005486,0},{0.204266,0},{0.211594,0},{0.31163,0}}'/>
+ <Property Name='BackgroundEnabled' Value='False'/>
+ <Property Name='HorzScrollPageSize' Value='131'/>
+ <Property Name='HorzScrollPosition' Value='0'/>
+ <Property Name='VertScrollPageSize' Value='17'/>
+ <Property Name='VertScrollPosition' Value='0'/>
+ <Property Name='HorzScrollDocumentSize' Value='47'/>
+ <Property Name='VertScrollDocumentSize' Value='9.3125'/>
+ </Window>
+ <Window Type='EmberLook/Editbox' Name='LODReductionParameterTextbox'>
+ <Property Name='MaxTextLength' Value='1073741823'/>
+ <Property Name='UnifiedAreaRect' Value='{{0.249004,0},{0.198553,0},{0.442456,0},{0.333085,0}}'/>
+ <Property Name='TextParsingEnabled' Value='False'/>
+ </Window>
</Window>
</Window>
- <Window Type='EmberLook/Button' Name='MeshInfoEditShowButton'>
- <Property Name='UnifiedPosition' Value='{{0,5},{0,5}}'/>
- <Property Name='UnifiedSize' Value='{{0,50},{0,25}}'/>
- <Property Name='Text' Value='Edit'/>
- <Property Name='InheritsAlpha' Value='True'/>
- <Property Name='AlwaysOnTop' Value='true'/>
+ <Window Type='EmberLook/StaticText' Name='LODDistances_text'>
+ <Property Name='Text' Value='Lod distances'/>
+ <Property Name='HorzExtent' Value='56'/>
+ <Property Name='VertExtent' Value='9.3125'/>
+ <Property Name='FrameEnabled' Value='False'/>
+ <Property Name='HorzFormatting' Value='HorzCentred'/>
+ <Property Name='UnifiedAreaRect' Value='{{0.00861785,0},{0.0221597,0},{0.137764,0},{0.0986613,0}}'/>
+ <Property Name='BackgroundEnabled' Value='False'/>
+ <Property Name='HorzScrollPageSize' Value='98'/>
+ <Property Name='HorzScrollPosition' Value='0'/>
+ <Property Name='VertScrollPageSize' Value='16'/>
+ <Property Name='VertScrollPosition' Value='0'/>
+ <Property Name='HorzScrollDocumentSize' Value='56'/>
+ <Property Name='VertScrollDocumentSize' Value='9.3125'/>
+ </Window>
+ <Window Type='EmberLook/Button' Name='LODAddButton'>
+ <Property Name='Text' Value='Add'/>
+ <Property Name='UnifiedAreaRect' Value='{{0.00639016,0},{0.729041,0},{0.0709729,0},{0.832929,0}}'/>
+ </Window>
+ <Window Type='EmberLook/Button' Name='LODDeleteButton'>
+ <Property Name='Text' Value='Delete'/>
+ <Property Name='UnifiedAreaRect' Value='{{0.0764352,0},{0.729041,0},{0.141018,0},{0.832929,0}}'/>
+ </Window>
+ <Window Type='EmberLook/Button' Name='LODCopyButton'>
+ <Property Name='Text' Value='Copy'/>
+ <Property Name='UnifiedAreaRect' Value='{{0.00639016,0},{0.864582,0},{0.0709729,0},{0.96847,0}}'/>
+ </Window>
+ <Window Type='EmberLook/Button' Name='LODPasteButton'>
+ <Property Name='Text' Value='Paste'/>
+ <Property Name='UnifiedAreaRect' Value='{{0.0764352,0},{0.864582,0},{0.141018,0},{0.96847,0}}'/>
+ </Window>
+ </Window>
+ <Window Type='EmberLook/Button' Name='MeshInfoSaveMeshButton'>
+ <Property Name='Text' Value='Save mesh'/>
+ <Property Name='Tooltip' Value='Save the mesh to disk'/>
+ <Property Name='UnifiedAreaRect' Value='{{0,4},{0,4},{0,78},{0,38}}'/>
+ </Window>
+ <Window Type='EmberLook/StaticImage' Name='MeshInfo/Preview'>
+ <Property Name='UnifiedAreaRect' Value='{{0,330},{0.007396,4},{1,-4},{1,-220}}'/>
+ <Window Type='EmberLook/StaticText' Name='PreviewInfo'>
+ <Property Name='Font' Value='DejaVuSans-14'/>
+ <Property Name='TextColours' Value='tl:FFFFFFFF tr:FFFFFFFF bl:FFFFFFFF br:FFFFFFFF'/>
+ <Property Name='FrameEnabled' Value='False'/>
+ <Property Name='VertFormatting' Value='TopAligned'/>
+ <Property Name='UnifiedAreaRect' Value='{{0,10},{0,10},{1,-10},{0,100}}'/>
+ <Property Name='BackgroundEnabled' Value='False'/>
+ <Property Name='HorzScrollPageSize' Value='412'/>
+ <Property Name='HorzScrollPosition' Value='0'/>
+ <Property Name='VertScrollPageSize' Value='90'/>
+ <Property Name='VertScrollPosition' Value='0'/>
+ <Property Name='HorzScrollDocumentSize' Value='0'/>
+ <Property Name='VertScrollDocumentSize' Value='0'/>
+ </Window>
+ <Window Type='EmberLook/Checkbox' Name='EnableAutomaticLOD1'>
+ <Property Name='Text' Value=' [colour=&apos;FFFFFFFF&apos;]Force selected Lod distance'/>
+ <Property Name='Visible' Value='False'/>
+ <Property Name='UnifiedAreaRect' Value='{{0,10},{1,-30},{0,247},{1,0}}'/>
</Window>
</Window>
+ <Window Type='EmberLook/StaticText' Name='SubmeshesText'>
+ <Property Name='Text'>Submeshes
+ </Property>
+ <Property Name='HorzExtent' Value='46'/>
+ <Property Name='VertExtent' Value='9.3125'/>
+ <Property Name='FrameEnabled' Value='False'/>
+ <Property Name='HorzFormatting' Value='HorzCentred'/>
+ <Property Name='UnifiedAreaRect' Value='{{0,0},{0,45},{0,155},{0,60}}'/>
+ <Property Name='BackgroundEnabled' Value='False'/>
+ <Property Name='HorzScrollPageSize' Value='155'/>
+ <Property Name='HorzScrollPosition' Value='0'/>
+ <Property Name='VertScrollPageSize' Value='15'/>
+ <Property Name='VertScrollPosition' Value='0'/>
+ <Property Name='HorzScrollDocumentSize' Value='46'/>
+ <Property Name='VertScrollDocumentSize' Value='9.3125'/>
+ </Window>
+ <Window Type='EmberLook/StaticText' Name='MaterialsText'>
+ <Property Name='Text'>Materials
+ </Property>
+ <Property Name='HorzExtent' Value='40'/>
+ <Property Name='VertExtent' Value='9.3125'/>
+ <Property Name='FrameEnabled' Value='False'/>
+ <Property Name='HorzFormatting' Value='HorzCentred'/>
+ <Property Name='UnifiedAreaRect' Value='{{0,160},{0,45},{0,325},{0,60}}'/>
+ <Property Name='BackgroundEnabled' Value='False'/>
+ <Property Name='HorzScrollPageSize' Value='165'/>
+ <Property Name='HorzScrollPosition' Value='0'/>
+ <Property Name='VertScrollPageSize' Value='15'/>
+ <Property Name='VertScrollPosition' Value='0'/>
+ <Property Name='HorzScrollDocumentSize' Value='40'/>
+ <Property Name='VertScrollDocumentSize' Value='9.3125'/>
+ </Window>
+ <Window Type='EmberLook/Button' Name='MeshInfoLoadMeshButton'>
+ <Property Name='Text' Value='Load mesh'/>
+ <Property Name='Tooltip' Value='Load the mesh from disk'/>
+ <Property Name='UnifiedAreaRect' Value='{{0,82},{0,5},{0,156},{0,39}}'/>
+ </Window>
+ <Window Type='EmberLook/Button' Name='MeshInfoSaveLoddefButton'>
+ <Property Name='Text' Value='Save loddef'/>
+ <Property Name='Tooltip' Value='Save the loddef to disk'/>
+ <Property Name='UnifiedAreaRect' Value='{{0,4},{1,-269},{0,78},{1,-235}}'/>
+ </Window>
+ <Window Type='EmberLook/Button' Name='MeshInfoLoadLoddefButton'>
+ <Property Name='Text' Value='Load loddef'/>
+ <Property Name='Tooltip' Value='Load the loddef from disk'/>
+ <Property Name='UnifiedAreaRect' Value='{{0,82},{1,-269},{0,156},{1,-235}}'/>
+ </Window>
+ <Window Type='EmberLook/StaticText' Name='SubmeshInfoText'>
+ <Property Name='Font' Value='DejaVuSans-8'/>
+ <Property Name='FrameEnabled' Value='False'/>
+ <Property Name='VertFormatting' Value='TopAligned'/>
+ <Property Name='UnifiedAreaRect' Value='{{0,8},{1,-396},{0,150},{1,-273}}'/>
+ <Property Name='BackgroundEnabled' Value='False'/>
+ <Property Name='HorzScrollPageSize' Value='142'/>
+ <Property Name='HorzScrollPosition' Value='0'/>
+ <Property Name='VertScrollPageSize' Value='123'/>
+ <Property Name='VertScrollPosition' Value='0'/>
+ <Property Name='HorzScrollDocumentSize' Value='0'/>
+ <Property Name='VertScrollDocumentSize' Value='0'/>
+ </Window>
+ </Window>
+ <Window Type='EmberLook/FrameWindow' Name='InputWindow'>
+ <Property Name='Text' Value='Input'/>
+ <Property Name='Visible' Value='False'/>
+ <Property Name='TitlebarFont' Value='DejaVuSans-14'/>
+ <Property Name='CaptionColour' Value='00FFFFFF'/>
+ <Property Name='TitlebarEnabled' Value='True'/>
+ <Property Name='UnifiedAreaRect' Value='{{0.5,-200},{0.5,-100},{0.5,100},{0.5,50}}'/>
+ <Window Type='EmberLook/StaticText' Name='InputQuestion_text'>
+ <Property Name='Text' Value='Please enter the name of the model.'/>
+ <Property Name='HorzExtent' Value='152'/>
+ <Property Name='VertExtent' Value='9.3125'/>
+ <Property Name='FrameEnabled' Value='False'/>
+ <Property Name='HorzFormatting' Value='HorzCentred'/>
+ <Property Name='VertFormatting' Value='BottomAligned'/>
+ <Property Name='UnifiedAreaRect' Value='{{0,0},{0,0},{1,0},{0,40}}'/>
+ <Property Name='HorzScrollPageSize' Value='292'/>
+ <Property Name='HorzScrollPosition' Value='0'/>
+ <Property Name='VertScrollPageSize' Value='40'/>
+ <Property Name='VertScrollPosition' Value='0'/>
+ <Property Name='HorzScrollDocumentSize' Value='152'/>
+ <Property Name='VertScrollDocumentSize' Value='9.3125'/>
+ </Window>
+ <Window Type='EmberLook/Editbox' Name='InputAnswerTextbox'>
+ <Property Name='MaxTextLength' Value='1073741823'/>
+ <Property Name='UnifiedAreaRect' Value='{{0.5,-100},{0,44},{0.5,100},{0.569081,0}}'/>
+ <Property Name='TextParsingEnabled' Value='False'/>
+ </Window>
+ <Window Type='EmberLook/Button' Name='InputOkButton'>
+ <Property Name='Text' Value='Ok'/>
+ <Property Name='UnifiedAreaRect' Value='{{0.5,-60},{0,75},{0.5,-10},{0,100}}'/>
+ </Window>
+ <Window Type='EmberLook/Button' Name='InputCancelButton'>
+ <Property Name='Text' Value='Cancel'/>
+ <Property Name='UnifiedAreaRect' Value='{{0.5,10},{0,75},{0.5,60},{0,100}}'/>
+ </Window>
</Window>
</Window>
<Window Type='DefaultWindow' Name='Images'>
@@ -247,7 +489,7 @@
<Property Name='UnifiedPosition' Value='{{0,4},{0,4}}'/>
<Property Name='UnifiedSize' Value='{{0,200},{1,-70}}'/>
<Property Name='InheritsAlpha' Value='True'/>
- <Property Name='MultiSelect' Value='True' />
+ <Property Name='MultiSelect' Value='True'/>
</Window>
<Window Type='EmberLook/StaticText' Name='ShadersInfo'>
<Property Name='UnifiedPosition' Value='{{0,205},{0,4}}'/>
View
386 src/components/ogre/widgets/AssetsManager.lua
@@ -68,13 +68,6 @@ function AssetsManager:MaterialsReload_Clicked(args)
return true
end
-function AssetsManager:MeshInfoEditShowButton_Clicked(args)
- local editWindow = self.widget:getWindow("MeshInfoEdit")
- if editWindow ~= nil then
- editWindow:setVisible(not editWindow:isVisible())
- end
-end
-
function AssetsManager:RefreshShaders_Clicked(args)
self.shaders.refresh(self)
end
@@ -124,9 +117,24 @@ function AssetsManager:MeshesRefresh_Clicked(args)
return true
end
+function AssetsManager:UserMeshRefresh_Clicked(args)
+ self.meshes.userrefresh(self)
+ return true
+end
+
function AssetsManager:MeshesList_ItemSelectionChanged(args)
local item = self.meshes.controls.listbox:getFirstSelectedItem()
- self:showMesh(item:getText())
+ if item then
+ self:showMesh(item:getText())
+ end
+ return true
+end
+
+function AssetsManager:UserMeshList_ItemSelectionChanged(args)
+ local item = self.meshes.controls.userlistbox:getFirstSelectedItem()
+ if item then
+ self.meshes.controls.userlistboxSelected = item:getText()
+ end
return true
end
@@ -134,11 +142,13 @@ function AssetsManager:SubMeshesList_ItemSelectionChanged(args)
local item = self.meshes.controls.submeshesListbox:getFirstSelectedItem()
if item ~= nil then
local submeshIndex = item:getID()
-
+ self.meshes.current.submeshIndex = submeshIndex
local mesh = self.meshes.current.meshPtr.get()
self.meshes.current.submesh = mesh:getSubMesh(submeshIndex)
self:selectMaterial(self.meshes.current.submesh)
+ local info = self.meshes.rendererStats:getInfo(submeshIndex)
+ self:updateMeshInfo()
end
return true
end
@@ -155,7 +165,7 @@ function AssetsManager:SubMeshMaterialsList_ItemSelectionChanged(args)
return true
end
-function AssetsManager:MeshInfoSaveButton_Clicked(args)
+function AssetsManager:MeshInfoSaveMeshButton_Clicked(args)
if self.meshes.current ~= nil and self.meshes.current.meshPtr ~= nil then
local mesh = self.meshes.current.meshPtr.get()
mesh:setSkeletonName(self.meshes.controls.skeletonPath:getText())
@@ -178,21 +188,51 @@ function AssetsManager:showMesh(meshName)
self.meshes.current.meshPtr.get = function()
return manager:getByName(meshName):get()
end
-
self:fillSubMeshList(meshPtr)
local mesh = meshPtr:get()
self.meshes.controls.skeletonPath:setText(mesh:getSkeletonName())
- self.meshes.controls.lodlevelsList:resetList()
- for i = 0, mesh:getNumLodLevels() - 1 do
- local item = Ember.OgreView.Gui.ColouredListItem:new(string.format("%i", i), i)
- self.meshes.controls.lodlevelsList:addItem(item)
+ -- Fill distances list.
+ local lodDefManager = Ember.OgreView.Lod.LodDefinitionManager:getSingleton()
+ self.meshes.current.lodDefPtr = {}
+ self.meshes.current.lodDefPtr.get = function()
+ return lodDefManager:getByName(self:getLodDefName(meshName)):get()
end
-
+ local lodlevelsList = self.widget:getWindow("LODDistances")
+ lodlevelsList = CEGUI.toListbox(lodlevelsList)
+ lodlevelsList:resetList()
+ local loddef = self.meshes.current.lodDefPtr.get()
+ local distances = loddef:createListOfDistances()
+ local size = distances:size()
+ for i = 0, size - 1 do
+ local value = self:round(distances[i], 6)
+ local item = Ember.OgreView.Gui.ColouredListItem:new(tostring(value), value)
+ lodlevelsList:addItem(item)
+ end
+ local window = self.widget:getWindow("SubmeshInfoText")
+ window:setText("")
+ -- TODO: Save changes before switching to other mesh
+ -- We need to clear the data after changing selection.
+ self.meshes.current.selectedDistance = nil
+ self.meshes.current.submesh = nil
+ self.meshes.current.submeshIndex = nil
+ self:LODUpdateSelection()
+ self:updatePreviewInfo()
+ self:updateMeshInfo()
+end
+-- Strips directories and extension from meshName, then adds .loddef extension.
+-- For example "../acorn.mesh" will be "acorn.loddef".
+function AssetsManager:getLodDefName(meshName)
+ return string.match(string.match(meshName, "[^\\/]*$"), "^[^%.]*") .. ".loddef"
end
+-- Rounds a number to given decimal characters.
+function AssetsManager:round(num, decimals)
+ local mult = 10^(decimals or 0)
+ return math.floor(num * mult + 0.5) / mult
+end
function AssetsManager:getSubMeshName(mesh, index)
local submeshname = Ember.OgreView.OgreUtils:getSubMeshName(mesh, index)
if submeshname == "" then
@@ -330,6 +370,186 @@ function AssetsManager:addEntity(entity, level)
-- end
end
+function AssetsManager:getInput(question, answerFunc)
+ if not self.waitingAnswer then
+ self.waitingAnswer = true
+ self.answerFunc = answerFunc
+
+ self.widget:getWindow("InputQuestion_text"):setText(question)
+ self.widget:getWindow("InputAnswerTextbox"):setText("")
+ self.widget:getWindow("InputWindow"):setVisible(true)
+ self.widget:getWindow("InputWindow"):moveToFront()
+ end
+end
+
+function AssetsManager:fillLODTypeCombobox()
+ local types = self.widget:getWindow("LODTypeCombobox")
+ types = CEGUI.toCombobox(types)
+
+ local item = Ember.OgreView.Gui.ColouredListItem:new("Automatic vertex reduction", 0)
+ types:addItem(item)
+
+ local item = Ember.OgreView.Gui.ColouredListItem:new("User created LOD", 1)
+ types:addItem(item)
+end
+
+function AssetsManager:fillLODReductionTypeCombobox()
+ local methods = self.widget:getWindow("LODReductionTypeCombobox")
+ methods = CEGUI.toCombobox(methods)
+
+ local item = Ember.OgreView.Gui.ColouredListItem:new("Proportional", 0)
+ methods:addItem(item)
+
+ local item = Ember.OgreView.Gui.ColouredListItem:new("Constant", 1)
+ methods:addItem(item)
+end
+
+function AssetsManager:LODSave(dist)
+ local loddef = self.meshes.current.lodDefPtr.get();
+ if dist == nil or dist < 0 or not loddef:hasLodDistance(dist) then return end
+
+ distdef = loddef:getLodDistance(dist);
+
+ local combobox = self.widget:getWindow("LODTypeCombobox")
+ combobox = CEGUI.toCombobox(combobox)
+ local item = combobox:getSelectedItem();
+ local type = combobox:getItemIndex(item)
+ distdef:setType(type)
+
+ local combobox = self.widget:getWindow("LODReductionTypeCombobox")
+ combobox = CEGUI.toCombobox(combobox)
+ local item = combobox:getSelectedItem();
+ local reductionMethod = combobox:getItemIndex(item)
+ distdef:setReductionMethod(reductionMethod)
+
+ local editbox = self.widget:getWindow("LODReductionParameterTextbox")
+ local reductionValue = editbox:getText()
+ distdef:setReductionValue(reductionValue)
+
+ local meshName = self.meshes.controls.userlistboxSelected or ""
+ distdef:setMeshName(meshName)
+end
+
+function AssetsManager:LODLoad(dist)
+ local loddef = self.meshes.current.lodDefPtr.get();
+ local container = self.widget:getWindow("LODConfigContainer")
+ if dist == nil or dist < 0 or not loddef:hasLodDistance(dist) then
+ container:setEnabled(false)
+ return
+ else
+ container:setEnabled(true)
+ end
+
+ distdef = loddef:getLodDistance(dist);
+
+ local combobox = self.widget:getWindow("LODTypeCombobox")
+ combobox = CEGUI.toCombobox(combobox)
+ combobox:setItemSelectState(distdef:getType(), true)
+
+ local combobox = self.widget:getWindow("LODReductionTypeCombobox")
+ combobox = CEGUI.toCombobox(combobox)
+ combobox:setItemSelectState(distdef:getReductionMethod(), true)
+
+ local editbox = self.widget:getWindow("LODReductionParameterTextbox")
+ editbox:setText(self:round(distdef:getReductionValue(), 6))
+
+ self.meshes.controls.userlistboxSelected = distdef:getMeshName()
+
+ self:LODTypes_SelectionChanged()
+end
+
+function AssetsManager:LODUpdateSelection()
+ self:LODSave(self.meshes.current.selectedDistance)
+ self.meshes.current.selectedDistance = self:LODGetSelected()
+ self:LODLoad(self.meshes.current.selectedDistance)
+end
+
+function AssetsManager:LODTypes_SelectionChanged()
+ local combobox = self.widget:getWindow("LODTypeCombobox")
+ local selected = combobox:getText()
+ local automatic = self.widget:getWindow("AutomaticVertexReductionContainer")
+ local manual = self.widget:getWindow("ManuallyCreatedLODContainer")
+ if ( selected == "Automatic vertex reduction" ) then
+ -- Automatic vertex reduction.
+ automatic:setVisible(true);
+ manual:setVisible(false);
+ else -- if ( selected == "Manually created LOD" ) then
+ -- Manually created LOD.
+ manual:setVisible(true);
+ automatic:setVisible(false);
+ end
+end
+
+function AssetsManager:LODGetSelected()
+ local listbox = self.widget:getWindow("LODDistances")
+ listbox = CEGUI.toListbox(listbox)
+ local item = listbox:getFirstSelectedItem()
+ if (item == nil) then
+ return -1
+ else
+ return tonumber(item:getText())
+ end
+end
+
+function AssetsManager:LODAdd(distance)
+ local loddef = self.meshes.current.lodDefPtr.get();
+ distance = tonumber(distance)
+ if not distance or loddef:hasLodDistance(distance) then return end
+
+ distdef = loddef:createDistance(distance)
+ local selected = self:LODGetSelected()
+ self:LODSave(selected)
+ local listbox = self.widget:getWindow("LODDistances")
+ listbox = CEGUI.toListbox(listbox)
+ local item = Ember.OgreView.Gui.ColouredListItem:new(distance, distance)
+ listbox:addItem(item)
+ listbox:clearAllSelections()
+ listbox:setItemSelectState(item, true)
+ self:LODLoad(distance)
+end
+
+function AssetsManager:LODPaste(distance)
+ local loddef = self.meshes.current.lodDefPtr.get();
+ distance = tonumber(distance)
+ if not distance or loddef:hasLodDistance(distance) then return end
+
+ local listbox = self.widget:getWindow("LODDistances")
+ listbox = CEGUI.toListbox(listbox)
+ distdef = loddef:createDistance(distance)
+
+ local type = self.clipboard.type
+ distdef:setType(type)
+
+ local meshname = self.clipboard.meshName
+ distdef:setMeshName(meshname)
+
+ local reductionMethod = self.clipboard.reductionMethod
+ distdef:setReductionMethod(reductionMethod)
+
+ local reductionValue = self.clipboard.reductionValue
+ distdef:setReductionValue(reductionValue)
+
+ local selected = self:LODGetSelected()
+ self:LODSave(selected)
+ local item = Ember.OgreView.Gui.ColouredListItem:new(distance, distance)
+ listbox:addItem(item)
+ listbox:clearAllSelections()
+ listbox:setItemSelectState(item, true)
+ self:LODLoad(distance)
+end
+
+function AssetsManager:updateMeshInfo()
+ if self.meshes.current.submesh then
+ local info = self.meshes.rendererStats:getInfo(self.meshes.current.submeshIndex)
+ local window = self.widget:getWindow("SubmeshInfoText")
+ window:setText(info)
+ end
+end
+function AssetsManager:updatePreviewInfo()
+ local info = self.meshes.rendererStats:getPreviewInfo()
+ self.meshes.previewInfo:setText(info)
+ return true
+end
function AssetsManager:buildWidget()
self.widget = guiManager:createWidget()
@@ -430,26 +650,20 @@ function AssetsManager:buildWidget()
--the meshes part
self.meshes.controls.listbox = CEGUI.toListbox(self.widget:getWindow("MeshesList"))
+ self.meshes.controls.userlistbox = CEGUI.toListbox(self.widget:getWindow("UserMeshList"))
self.meshes.controls.submeshesListbox = CEGUI.toListbox(self.widget:getWindow("SubMeshesList"))
self.meshes.controls.materialListbox = CEGUI.toListbox(self.widget:getWindow("SubMeshMaterialsList"))
self.meshes.controls.materialFilter = CEGUI.toEditbox(self.widget:getWindow("SubMeshMaterialsFilter"))
self.meshes.controls.skeletonPath = CEGUI.toEditbox(self.widget:getWindow("MeshSkeletonPath"))
- self.meshes.controls.lodlevelsList = CEGUI.toListbox(self.widget:getWindow("MeshLodLevel"))
- self.meshes.controls.lodlevelsList:subscribeEvent("ItemSelectionChanged", function(args)
- local entity = self.meshes.renderer:getEntity()
- if entity then
- local item = self.meshes.controls.lodlevelsList:getFirstSelectedItem()
- if item then
- local level = item:getID()
- entity:setMeshLodBias(0.001, level, level)
- end
- end
- return true
- end)
self.meshes.controls.filter = CEGUI.toEditbox(self.widget:getWindow("FilterMeshes"))
self.meshes.listholder = Ember.OgreView.Gui.ListHolder:new(self.meshes.controls.listbox, self.meshes.controls.filter)
+ self.meshes.controls.userfilter = CEGUI.toEditbox(self.widget:getWindow("UserMeshFilter"))
+ self.meshes.userlistholder = Ember.OgreView.Gui.ListHolder:new(self.meshes.controls.userlistbox, self.meshes.controls.userfilter)
self.meshes.controls.textureView = self.widget:getWindow("MeshInfo/Preview")
self.meshes.renderer = Ember.OgreView.Gui.OgreEntityRenderer:new(self.meshes.controls.textureView)
+ self.meshes.rendererStats = Ember.OgreView.Gui.MeshInfoProvider:new(self.meshes.renderer)
+ self.meshes.previewInfo = self.widget:getWindow("PreviewInfo")
+ connect(self.connectors, self.meshes.rendererStats.EventLodChanged, self.updatePreviewInfo, self)
self.meshes.materialListholder = Ember.OgreView.Gui.ListHolder:new(self.meshes.controls.materialListbox, self.meshes.controls.materialFilter)
self.meshes.refresh = function(self)
self.meshes.listholder:resetList()
@@ -463,12 +677,25 @@ function AssetsManager:buildWidget()
self.meshes.listholder:addItem(item)
end
end
+ self.meshes.userrefresh = function(self)
+ self.meshes.userlistholder:resetList()
+
+ local manager = Ember.OgreView.Model.ModelDefinitionManager:getSingleton()
+ local meshes = manager:getAllMeshes()
+
+ for i = 0, meshes:size() - 1 do
+ local name = meshes[i]
+ local item = Ember.OgreView.Gui.ColouredListItem:new(name, i)
+ self.meshes.userlistholder:addItem(item)
+ end
+ end
self.widget:getWindow("MeshesRefresh"):subscribeEvent("Clicked", self.MeshesRefresh_Clicked, self)
self.widget:getWindow("MeshesList"):subscribeEvent("ItemSelectionChanged", self.MeshesList_ItemSelectionChanged, self)
+ self.widget:getWindow("UserMeshRefresh"):subscribeEvent("Clicked", self.UserMeshRefresh_Clicked, self)
+ self.widget:getWindow("UserMeshList"):subscribeEvent("ItemSelectionChanged", self.UserMeshList_ItemSelectionChanged, self)
self.widget:getWindow("SubMeshesList"):subscribeEvent("ItemSelectionChanged", self.SubMeshesList_ItemSelectionChanged, self)
self.widget:getWindow("SubMeshMaterialsList"):subscribeEvent("ItemSelectionChanged", self.SubMeshMaterialsList_ItemSelectionChanged, self)
- self.widget:getWindow("MeshInfoSaveButton"):subscribeEvent("Clicked", self.MeshInfoSaveButton_Clicked, self)
- self.widget:getWindow("MeshInfoEditShowButton"):subscribeEvent("Clicked", self.MeshInfoEditShowButton_Clicked, self)
+ self.widget:getWindow("MeshInfoSaveMeshButton"):subscribeEvent("Clicked", self.MeshInfoSaveMeshButton_Clicked, self)
--the shaders part
self.shaders.controls.listbox = CEGUI.toListbox(self.widget:getWindow("ShadersList"))
@@ -483,7 +710,102 @@ function AssetsManager:buildWidget()
self.widget:getWindow("ShadersReload"):subscribeEvent("Clicked", self.ShadersReload_Clicked, self)
self.widget:getWindow("ShadersList"):subscribeEvent("ItemSelectionChanged", self.ShadersList_ItemSelectionChanged, self)
-
+
+ self.widget:getWindow("MeshInfoSaveLoddefButton"):subscribeEvent("Clicked", function(args)
+ self:LODUpdateSelection()
+ local mesh = self.meshes.current.meshPtr.get()
+ local meshName = mesh:getName()
+ local lodManager = Ember.OgreView.Lod.LodManager:getSingleton()
+ local lodDefManager = Ember.OgreView.Lod.LodDefinitionManager:getSingleton()
+ local lodDefPtr = lodDefManager:getByName(self:getLodDefName(meshName))
+ local lodDef = lodDefPtr:get()
+ lodDefManager:exportScript(meshName, lodDefPtr)
+ self.meshes.renderer:unloadEntity()
+ mesh:removeLodLevels()
+ lodManager:loadLod(mesh, lodDef)
+ self.meshes.renderer:showEntity(self.meshes.current.meshPtr.get():getName())
+ self:updatePreviewInfo()
+ self:updateMeshInfo()
+
+ return true
+ end)
+
+ self.widget:getWindow("InputOkButton"):subscribeEvent("Clicked", function(args)
+ self.widget:getWindow("InputWindow"):setVisible(false)
+ self.waitingAnswer = false
+ local name = self.widget:getWindow("InputAnswerTextbox"):getText()
+ self:answerFunc(name)
+ return true
+ end)
+
+ self.widget:getWindow("InputCancelButton"):subscribeEvent("Clicked", function(args)
+ self.widget:getWindow("InputWindow"):setVisible(false)
+ self.waitingAnswer = false
+ return true
+ end)
+
+ -- subscribe LOD events.
+ self.widget:getWindow("EnableAutomaticLOD"):subscribeEvent("CheckStateChanged", function(args)
+ local container = self.widget:getWindow("ManualLODContainer")
+ local isDisabled = container:isDisabled()
+ container:setEnabled(isDisabled)
+ self:LODUpdateSelection()
+ return true
+ end)
+
+ self.widget:getWindow("LODAddButton"):subscribeEvent("Clicked", function(args)
+ self:getInput("Please enter the distance.", self.LODAdd)
+ return true
+ end)
+
+ self.widget:getWindow("LODDeleteButton"):subscribeEvent("Clicked", function(args)
+ local dist = self:LODGetSelected()
+ if dist then
+ local listbox = self.widget:getWindow("LODDistances")
+ listbox = CEGUI.toListbox(listbox)
+ local item = listbox:getFirstSelectedItem()
+ listbox:removeItem(item)
+ local loddef = self.meshes.current.lodDefPtr.get()
+ loddef:removeLodDistance(dist)
+ end
+ return true
+ end)
+
+ self.widget:getWindow("LODCopyButton"):subscribeEvent("Clicked", function(args)
+ local loddef = self.meshes.current.lodDefPtr.get()
+ local distance = self:LODGetSelected()
+ if not distance or not loddef:hasLodDistance(distance) then return end
+
+ distdef = loddef:getLodDistance(distance);
+
+ self:LODSave(distance)
+ self.clipboard = {}
+ self.clipboard.type = distdef:getType()
+ self.clipboard.meshName = distdef:getMeshName()
+ self.clipboard.reductionMethod = distdef:getReductionMethod()
+ self.clipboard.reductionValue = distdef:getReductionValue()
+ return true
+ end)
+
+ self.widget:getWindow("LODPasteButton"):subscribeEvent("Clicked", function(args)
+ self:getInput("Please enter the distance.", self.LODPaste)
+ return true
+ end)
+
+ self.widget:getWindow("LODTypeCombobox"):subscribeEvent("ListSelectionAccepted", function(args)
+ self:LODTypes_SelectionChanged()
+ return true
+ end)
+
+ self.widget:getWindow("LODDistances"):subscribeEvent("ItemSelectionChanged", function(args)
+ self:LODUpdateSelection()
+ return true
+ end)
+
+ -- Fill LOD Comboboxes.
+ self:fillLODTypeCombobox()
+ self:fillLODReductionTypeCombobox()
+
self.helper = Ember.OgreView.Gui.AssetsManager:new()
@@ -513,8 +835,10 @@ function AssetsManager:shutdown()
deleteSafe(self.helper)
deleteSafe(self.shaders.listholder)
deleteSafe(self.meshes.materialListholder)
+ deleteSafe(self.meshes.rendererStats)
deleteSafe(self.meshes.renderer)
deleteSafe(self.meshes.listholder)
+ deleteSafe(self.meshes.userlistholder)
deleteSafe(self.windows.listholder)
deleteSafe(self.images.listholder)
deleteSafe(self.materials.listholder)
View
186 src/components/ogre/widgets/MeshInfoProvider.cpp
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2012 Peter Szucs <peter.szucs.dev@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "MeshInfoProvider.h"
+#include "components/ogre/lod/LodManager.h"
+#include "components/ogre/lod/LodDefinition.h"
+#include "components/ogre/lod/LodDefinitionManager.h"
+#include "components/ogre/lod/EmberOgreMesh.h"
+#include <OgrePrerequisites.h>
+#include <OgreMesh.h>
+#include <OgreSubMesh.h>
+#include <OgreProgressiveMesh.h>
+
+#include <sstream>
+
+
+namespace Ember
+{
+namespace OgreView
+{
+namespace Gui
+{
+
+void MeshInfoProvider::calcUniqueVertexCount(VertexSet& vertices, const Ogre::VertexData& data)
+{
+ // Locate position element and the buffer to go with it.
+ const Ogre::VertexElement* posElem = data.vertexDeclaration->findElementBySemantic(Ogre::VES_POSITION);
+ Ogre::HardwareVertexBufferSharedPtr vbuf = data.vertexBufferBinding->getBuffer(posElem->getSource());
+
+ // Lock the buffer for reading.
+ unsigned char* pVertex = static_cast<unsigned char*>(
+ vbuf->lock(Ogre::HardwareBuffer::HBL_READ_ONLY));
+ int vSize = vbuf->getVertexSize();
+ unsigned char* pEnd = pVertex + data.vertexCount * vSize;
+
+ // Loop through all vertices and insert them to the HashMap.
+ for (; pVertex <= pEnd; pVertex += vSize) {
+ float* pFloat;
+ posElem->baseVertexPointerToElement(pVertex, &pFloat);
+
+ // TODO: use C++11 emplace for speedup.
+ vertices.insert(Ogre::Vector3(pFloat[0], pFloat[1], pFloat[2]));
+ }
+ vbuf->unlock();
+}
+
+size_t MeshInfoProvider::calcUniqueVertexCount(const Ogre::MeshPtr& mesh)
+{
+ bool addedShared = false;
+
+ // TODO: use C++11 unordered_set and remove VectorLessComparator struct.
+ VertexSet vertices;
+
+ for (unsigned short i = 0; i < mesh->getNumSubMeshes(); ++i) {
+ const Ogre::SubMesh& submesh = *mesh->getSubMesh(i);
+ // We only need to add the shared vertices once.
+ if (submesh.useSharedVertices) {
+ if (!addedShared) {
+ addedShared = true;
+ calcUniqueVertexCount(vertices, *mesh->sharedVertexData);
+ }
+ } else {
+ calcUniqueVertexCount(vertices, *submesh.vertexData);
+ }
+ }
+
+ return vertices.size();
+}
+
+size_t MeshInfoProvider::calcUniqueVertexCount(const Ogre::VertexData& data)
+{
+ bool addedShared = false;
+
+ // TODO: use C++11 unordered_set and remove VectorLessComparator struct.
+ VertexSet vertices;
+ calcUniqueVertexCount(vertices, data);
+
+ return vertices.size();
+}
+int MeshInfoProvider::getVertexSize(const Ogre::VertexData* data)
+{
+ int size = 0;
+ for (size_t i = 0; i < data->vertexDeclaration->getMaxSource() + 1; i++) {
+ size += data->vertexDeclaration->getVertexSize(i);
+ }
+ return size;
+}
+std::string MeshInfoProvider::getInfo(int submeshIndex)
+{
+ const Ogre::MeshPtr& mesh = mEntityRenderer->getEntity()->getMesh();
+ size_t count = calcUniqueVertexCount(mesh);
+ std::stringstream str;
+ const Ogre::SubMesh& submesh = *mesh->getSubMesh(submeshIndex);
+ // We only need to add the shared vertices once
+ Ogre::VertexData* vertexData = submesh.useSharedVertices ? mesh->sharedVertexData : submesh.vertexData;
+ Ogre::HardwareIndexBufferSharedPtr ibuf = submesh.indexData->indexBuffer;
+ str << "Unique vertex count: " << count << std::endl;
+ str << "Vertex count: " << vertexData->vertexCount << std::endl;
+ str << "Vertex size: " << getVertexSize(vertexData) << std::endl;
+ str << "Index count: " << submesh.indexData->indexCount << std::endl;
+ str << "Index size: " << (ibuf->getType() == Ogre::HardwareIndexBuffer::IT_16BIT ? 2 : 4) << std::endl;
+ str << "Shared vertices: " << (submesh.useSharedVertices ? "[colour='FF00AA00']yes" : "[colour='FFFF0000']no") <<
+ "[colour='FF000000']" << std::endl;
+ str << "Edge data: " << (submesh.isBuildEdgesEnabled() ? "[colour='FFFF0000']yes" : "[colour='FF00AA00']no") <<
+ "[colour='FF000000']" << std::endl;
+ return str.str();
+}
+
+std::string MeshInfoProvider::getPreviewInfo()
+{
+ std::stringstream str;
+ Ogre::Entity* entity = mEntityRenderer->getEntity();
+ if (!entity) {
+ return "";
+ }
+ const Ogre::MeshPtr& mesh = entity->getMesh();
+ mLodIndex = std::min(mesh->getNumLodLevels() - 1, mLodIndex);
+ const Ogre::MeshLodUsage& lod = mesh->getLodLevel(mLodIndex);
+ if (mesh->isLodManual()) {
+ str << lod.manualName << std::endl;
+ } else {
+ bool addedShared;
+ size_t indexCount = 0;
+
+ int count = mesh->getNumSubMeshes();
+ for (unsigned short i = 0; i < count; ++i) {
+ const Ogre::SubMesh& submesh = *mesh->getSubMesh(i);
+
+ if (mLodIndex > 0) {
+ indexCount += submesh.mLodFaceList[mLodIndex - 1]->indexCount;
+ } else {
+ indexCount += submesh.indexData->indexCount;
+ }
+
+ }
+
+ str << indexCount << " indices" << std::endl;
+ str << (indexCount / 3) << " triangles" << std::endl;
+ }
+
+ return str.str();
+}
+bool MeshInfoProvider::prequeueEntityMeshLodChanged(Ogre::EntityMeshLodChangedEvent& evt)
+{
+ if (evt.entity == mEntityRenderer->getEntity() && mLodIndex != evt.newLodIndex) {
+ mLodIndex = evt.newLodIndex;
+ EventLodChanged.emit();
+ }
+ return false;
+}
+
+int MeshInfoProvider::getLodIndex()
+{
+ return mLodIndex;
+}
+
+MeshInfoProvider::MeshInfoProvider(OgreEntityRenderer* entityRenderer) :
+ mEntityRenderer(entityRenderer),
+ mLodIndex(0)
+{
+ mEntityRenderer->getSceneManager()->addLodListener(this);
+}
+
+MeshInfoProvider::~MeshInfoProvider()
+{
+ mEntityRenderer->getSceneManager()->removeLodListener(this);
+}
+
+}
+}
+}
View
74 src/components/ogre/widgets/MeshInfoProvider.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2012 Peter Szucs <peter.szucs.dev@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "components/ogre/widgets/OgreEntityRenderer.h"
+#include <OgreLodListener.h>
+
+namespace Ember
+{
+namespace OgreView
+{
+namespace Gui
+{
+
+class MeshInfoProvider :
+public Ogre::LodListener
+{
+public:
+
+ sigc::signal<void> EventLodChanged;
+
+ MeshInfoProvider(OgreEntityRenderer * entityRenderer);
+ ~MeshInfoProvider();
+ std::string getInfo(int submeshIndex);
+ std::string getPreviewInfo();
+ bool prequeueEntityMeshLodChanged(Ogre::EntityMeshLodChangedEvent& evt);
+ int getLodIndex();
+
+private:
+
+ struct VectorLessComparator {
+ bool operator() (const Ogre::Vector3 & v1, const Ogre::Vector3 & v2) const
+ {
+ if (v1.x < v2.x) {
+ return true;
+ }
+ if (v1.x == v2.x && v1.y < v2.y) {
+ return true;
+ }
+ if (v1.x == v2.x && v1.y == v2.y && v1.z < v2.z) {
+ return true;
+ }
+
+ return false;
+ }
+ };
+ typedef std::set<Ogre::Vector3, VectorLessComparator> VertexSet;
+
+ int MeshInfoProvider::getVertexSize(const Ogre::VertexData* data);
+ void MeshInfoProvider::calcUniqueVertexCount(VertexSet& vertices, const Ogre::VertexData& data);
+ size_t MeshInfoProvider::calcUniqueVertexCount(const Ogre::MeshPtr& mesh);
+ size_t MeshInfoProvider::calcUniqueVertexCount(const Ogre::VertexData& data);
+
+ Ember::OgreView::Gui::OgreEntityRenderer* mEntityRenderer;
+ int mLodIndex;
+};
+
+}
+}
+}
Please sign in to comment.
Something went wrong with that request. Please try again.