BearishSun 9 лет назад
Родитель
Сommit
c300d7f5fc

+ 94 - 0
Documentation/Manuals/Native/User/prefabs.md

@@ -0,0 +1,94 @@
+Prefabs				{#prefabs}
+===============
+
+We talked about prefabs when discussing on how to save a game scene, but they can actually be used for saving of any group of scene objects. Contents of such prefabs can then be easily instantiated throughout the scene, allowing you to build complex scenes more easily. Prefabs can be nested within other prefabs with no limits (where the top level prefab is the "scene") and provide other useful functionality we'll talk about.
+
+For example you might create a scene object that contains a **Renderable** displaying a mesh of a house a material referencing the relevant textures. The scene object could also contain physics objects like a **Collider** and even child scene objects. You could then group all the scene objects and their components into a single prefab, which you can then easily re-use all over your scene.
+
+# Creation
+To create such a prefab call @ref bs::Prefab::create "Prefab::create()" with the first parameter being a **SceneObject** from which to create the prefab from. All child scene objects will be included in the prefab as well. Second parameter of **Prefab::create()** should equal to false, indicating this prefab doesn't represent a scene.
+
+~~~~~~~~~~~~~{.cpp}
+// Create a renderable object as normal
+HSceneObject renderableSO = SceneObject::create("3D object");
+HRenderable renderable = renderableSO->addComponent<CRenderable>();
+// Set up renderable mesh & material
+
+HPrefab renderablePrefab = Prefab::create(renderableSO, false);
+~~~~~~~~~~~~~
+
+# Instantiation
+Once created you can now instantiate the prefab as many times as you wish by calling @ref bs::Prefab::instantiate "Prefab::instantiate()". This will return a scene object, which will by default be parented to scene root.
+
+~~~~~~~~~~~~~{.cpp}
+HSceneObject instance1 = renderablePrefab->instantiate();
+HSceneObject instance2 = renderablePrefab->instantiate();
+~~~~~~~~~~~~~
+
+# Updates
+Often you might want to modify the contents of a prefab. To do that call @ref bs::Prefab::update "Prefab::update()", preferably with the same scene object it was created with.
+
+~~~~~~~~~~~~~{.cpp}
+// Update mesh on our renderable prefab
+renderable->setMesh(differentMesh);
+
+// Save the updated data into the prefab
+renderablePrefab->update(renderableSO);
+~~~~~~~~~~~~~
+
+Once a prefab has been updated, you might also want to update any instances of that prefab. A prefab instance is any scene object resulting from **Prefab::instantiate()**, and the scene object used for originally creating the prefab.
+
+You can update the instances by calling @ref bs::PrefabUtility::updateFromPrefab() "PrefabUtility::updateFromPrefab()".
+
+~~~~~~~~~~~~~{.cpp}
+// Update all the instances of our prefab with new prefab data (renderableSO is also an instance, but we don't update it since it was the source of the changes, so there's no need)
+
+PrefabUtility::updateFromPrefab(instance1);
+PrefabUtility::updateFromPrefab(instance2);
+~~~~~~~~~~~~~
+
+Note that this process is recursive, so you can call **PrefabUtility::updateFromPrefab()** on the entire scene, in order to update all prefabs.
+
+~~~~~~~~~~~~~{.cpp}
+PrefabUtility::updateFromPrefab(gSceneManager().getRootNode());
+~~~~~~~~~~~~~
+
+## Links
+You'll notice we didn't need to provide a reference to **Prefab** when performing prefab updates. This is because every prefab instance is linked to its prefab. You can break the link by calling @ref bs::SceneObject::breakPrefabLink "SceneObject::breakPrefabLink()". This will make it into a regular scene object and it will no longer be updated from the prefab.
+
+~~~~~~~~~~~~~{.cpp}
+instance1->breakPrefabLink();
+~~~~~~~~~~~~~
+
+## Saving
+If a scene using prefabs is saved to disk, and if you plan on updating the prefab later, you must save the prefabs same as we save scenes. Otherwise the next time you call **PrefabUtility::updateFromPrefab()** the system will be unable to find the prefab.
+
+~~~~~~~~~~~~~{.cpp}
+gResources().save(renderablePrefab, "myPrefab.asset");
+~~~~~~~~~~~~~
+
+> Prefabs generally won't be updated during normal application runs, and therefore non-scene prefabs don't need to be distributed with your application or used outside of development.
+
+# Instance modifications
+All prefab instances are by default identical, and if you make any changes to the instances any calls to **PrefabUtility::updateFromPrefab()** will discard those changes and update the instance with latest data from the prefab. You can choose to break the prefab link by calling **SceneObject::breakPrefabLink()** but in that case you can no longer update the scene object if the source prefab changes.
+
+The solution for this problem are instance modifications. Using this system you can modify prefab instance same as a normal scene object, as long as you call @ref bs::PrefabUtility::recordPrefabDiff "PrefabUtility::recordPrefabDiff()" after.
+
+~~~~~~~~~~~~~{.cpp}
+// Change the material of the prefab instance's renderable
+HRenderable instanceRenderable = instance2->getComponent<CRenderable>();
+instanceRenderable->setMaterial(0, differentMaterial);
+
+PrefabUtility::recordPrefabDiff(instanceRenderable);
+// Now it's safe to call PrefabUtility::updateFromPrefab() and our material change will remain even after update
+~~~~~~~~~~~~~
+
+Note the system will automatically call **PrefabUtility::recordPrefabDiff()** when a new prefab is created or updated. Meaning this will also be done automatically when you're saving scenes, and therefore there should be rare need to call it manually. 
+
+## Reverting
+Sometimes you might want to discard all instance modifications, and revert back to original data from the prefab. In that case you can call @ref bs::PrefabUtility::revertToPrefab "PrefabUtility::revertToPrefab()".
+
+~~~~~~~~~~~~~{.cpp}
+// Discard any instance specific changes and update from the latest data from the prefab
+PrefabUtility::revertToPrefab(instance2);
+~~~~~~~~~~~~~

+ 60 - 0
Documentation/Manuals/Native/User/profiling.md

@@ -0,0 +1,60 @@
+Profiling				{#cpuProfiling}
+===============
+
+Code profiling is an important process to determine performance bottlenecks. Profiling measures code execution times and memory allocations. Banshee provides a built-in profiler through the @ref bs::ProfilerCPU "ProfilerCPU" module. This module can be globally accessed through @ref bs::gProfilerCPU() "gProfilerCPU()".
+
+The profiler allows you to profile blocks of code and output information about how long the block took to execute, as well as information about number and amount of memory allocations.
+
+The profiler supports two separate measuring modes, the normal mode measures time in milliseconds, while the precise mode measures time in CPU cycles. The precise mode does have drawbacks as it is inacurrate for longer code as it will not account for OS context switches and similar. Usually you will be using the normal measuring mode, and reserve the precise mode when you need to know exactly how many cycles some relatively small operation takes.
+
+# Recording
+To start profiling a block call surround it with either:
+ - @ref bs::ProfilerCPU::beginSample "ProfilerCPU::beginSample()" / @ref bs::ProfilerCPU::endSample "ProfilerCPU::endSample()" - Records timing information (in milliseconds) about the code in-between, as well as memory allocation information
+ - @ref bs::ProfilerCPU::beginSamplePrecise "ProfilerCPU::beginSamplePrecise()" / @ref bs::ProfilerCPU::endSamplePrecise "ProfilerCPU::endSamplePrecise()" - Records timing information (in CPU cyles) about the code in-between, as well as memory allocation information
+ 
+All of the methods above expect a name as a parameter, which is arbitrary and it is used so you can later identify the profiling information. 
+
+~~~~~~~~~~~~~{.cpp}
+void doSomethingIntensive()
+{
+	// ...
+}
+
+gProfilerCPU().beginSample("myProfilingBlock");
+doSomethingIntensive();
+gProfilerCPU().endSample("myProfilingBlock");
+~~~~~~~~~~~~~
+
+Each sample needs to have a *begin()* and an *end()* pair. Samples can be nested between other samples.
+
+# Reporting
+Once you have placed sample points around your code, you can retrieve the profiling report by calling @ref bs::ProfilerCPU::generateReport() "ProfilerCPU::generateReport()". This will return a @ref bs::CPUProfilerReport "CPUProfilerReport" object, which contains a list of normal and precise samples.
+
+Each sampling entry is represented either by @ref bs::CPUProfilerBasicSamplingEntry "CPUProfilerBasicSamplingEntry" or @ref bs::CPUProfilerPreciseSamplingEntry "CPUProfilerPreciseSamplingEntry". Sampling entries contain information about the time it took to execute the code in the sampled block of code, as well as number of memory allocations & deallocations, and total number of allocated and deallocated bytes. Each sample also contains a list of child samples (if any).
+
+~~~~~~~~~~~~~{.cpp}
+CPUProfilerReport report = gProfilerCPU().generateReport();
+for(CPUProfilerBasicSamplingEntry& entry : report.getBasicSamplingData())
+{ /* ... */ }
+
+for(CPUProfilerPreciseSamplingEntry& entry : report.getPreciseSamplingData())
+{ /* ... */ }
+~~~~~~~~~~~~~
+
+After retrieving the data, you can log it, display it on screen, or similar.
+
+## Profiler overlay
+You can easily display the profiler reports on screen by adding the @ref bs::CProfilerOverlay "ProfilerOverlay" component to the scene and assigning it a camera. It will then automatically read profiler reports every frame and display them on the provided camera.
+
+~~~~~~~~~~~~~{.cpp}
+HCamera camera = ...; // Add a scene camera
+
+HSceneObject profilerOverlaySO = SceneObject::create("Profiler overlay");
+HProfilerOverlay profilerOverlay = profilerOverlaySO->addComponent<CProfilerOverlay>(camera);
+~~~~~~~~~~~~~
+
+## Threads
+The profiler is thread-safe, but if you are profiling code on threads not managed by the engine, you must manually call @ref bs::ProfilerCPU::beginThread "ProfilerCPU::beginThread" before any sample calls, and @ref bs::ProfilerCPU::endThread "ProfilerCPU::endThread" after all sample calls.
+
+## Overhead
+Profiler code itself will introduce a certain amount of overhead which will slightly skew profiling results. The profiler attempts to estimate this error, which is reported in the returned reports. You can choose to take this into consideration if you need really precise results.

+ 2 - 0
Documentation/Manuals/Native/manuals.md

@@ -66,7 +66,9 @@ A complete set of manuals covering all major functionality provided by Banshee,
  - [Creating meshes](@ref creatingMeshes)
  - [Advanced startup](@ref advancedStartup)
  - [Advanced RTTI](@ref advancedRtti)
+ - [Prefabs](@ref prefabs)
  - [Cursors](@ref cursors)
+ - [Profiling](@ref cpuProfiling)
  
 # Developer manuals
 A set of manuals covering advanced functionality intented for those wanting to extend the engine or tinker with the internals, rather than for normal users. You are expected to have read the user manuals first.

+ 2 - 2
Source/BansheeEngine/Include/BsPrerequisites.h

@@ -186,7 +186,7 @@ namespace bs
 	class GUICanvas;
 
 	class RenderableHandler;
-	class ProfilerOverlay;
+	class CProfilerOverlay;
 	class ProfilerOverlayInternal;
 	class DrawHelper;
 	class PlainText;
@@ -202,7 +202,7 @@ namespace bs
 	struct SpriteMaterialInfo;
 
 	typedef GameObjectHandle<CGUIWidget> HGUIWidget;
-	typedef GameObjectHandle<ProfilerOverlay> HProfilerOverlay;
+	typedef GameObjectHandle<CProfilerOverlay> HProfilerOverlay;
 
 	typedef ResourceHandle<SpriteTexture> HSpriteTexture;
 	typedef ResourceHandle<PlainText> HPlainText;

+ 4 - 4
Source/BansheeEngine/Include/BsProfilerOverlay.h

@@ -28,12 +28,12 @@ namespace bs
 	 *			
 	 * @note	Component wrapper of ProfilerOverlayInternal.
 	 */
-	class BS_EXPORT ProfilerOverlay : public Component
+	class BS_EXPORT CProfilerOverlay : public Component
 	{
 	public:
 		/**	Constructs a new overlay attached to the specified parent and displayed on the provided viewport. */
-		ProfilerOverlay(const HSceneObject& parent, const SPtr<Camera>& target);
-		~ProfilerOverlay();
+		CProfilerOverlay(const HSceneObject& parent, const SPtr<Camera>& target);
+		~CProfilerOverlay();
 
 		/**	Changes the camera to display the overlay on. */
 		void setTarget(const SPtr<Camera>& target);
@@ -58,7 +58,7 @@ namespace bs
 		static RTTITypeBase* getRTTIStatic();
 		RTTITypeBase* getRTTI() const override;
 
-		ProfilerOverlay(); // Serialization only
+		CProfilerOverlay(); // Serialization only
 	};
 
 	/**	Handles rendering of Profiler information as an overlay in a viewport. */

+ 2 - 2
Source/BansheeEngine/Include/BsProfilerOverlayRTTI.h

@@ -14,7 +14,7 @@ namespace bs
 	 *  @{
 	 */
 
-	class BS_EXPORT ProfilerOverlayRTTI : public RTTIType <ProfilerOverlay, Component, ProfilerOverlayRTTI>
+	class BS_EXPORT ProfilerOverlayRTTI : public RTTIType <CProfilerOverlay, Component, ProfilerOverlayRTTI>
 	{
 	private:
 
@@ -35,7 +35,7 @@ namespace bs
 
 		SPtr<IReflectable> newRTTIObject() override
 		{
-			return GameObjectRTTI::createGameObject<ProfilerOverlay>();
+			return GameObjectRTTI::createGameObject<CProfilerOverlay>();
 		}
 	};
 

+ 10 - 10
Source/BansheeEngine/Source/BsProfilerOverlay.cpp

@@ -291,51 +291,51 @@ namespace bs
 
 	const UINT32 ProfilerOverlayInternal::MAX_DEPTH = 4;
 
-	ProfilerOverlay::ProfilerOverlay()
+	CProfilerOverlay::CProfilerOverlay()
 	{
 		setFlag(ComponentFlag::AlwaysRun, true);
 	}
 
-	ProfilerOverlay::ProfilerOverlay(const HSceneObject& parent, const SPtr<Camera>& target)
+	CProfilerOverlay::CProfilerOverlay(const HSceneObject& parent, const SPtr<Camera>& target)
 		:Component(parent), mInternal(nullptr)
 	{
 		setFlag(ComponentFlag::AlwaysRun, true);
 		mInternal = bs_new<ProfilerOverlayInternal>(target);
 	}
 
-	ProfilerOverlay::~ProfilerOverlay()
+	CProfilerOverlay::~CProfilerOverlay()
 	{
 		bs_delete(mInternal);
 	}
 
-	void ProfilerOverlay::setTarget(const SPtr<Camera>& target)
+	void CProfilerOverlay::setTarget(const SPtr<Camera>& target)
 	{
 		mInternal->setTarget(target);
 	}
 
-	void ProfilerOverlay::show(ProfilerOverlayType type)
+	void CProfilerOverlay::show(ProfilerOverlayType type)
 	{
 		mInternal->show(type);
 	}
 
-	void ProfilerOverlay::hide()
+	void CProfilerOverlay::hide()
 	{
 		mInternal->hide();
 	}
 
-	void ProfilerOverlay::update()
+	void CProfilerOverlay::update()
 	{
 		mInternal->update();
 	}
 
-	RTTITypeBase* ProfilerOverlay::getRTTIStatic()
+	RTTITypeBase* CProfilerOverlay::getRTTIStatic()
 	{
 		return ProfilerOverlayRTTI::instance();
 	}
 
-	RTTITypeBase* ProfilerOverlay::getRTTI() const
+	RTTITypeBase* CProfilerOverlay::getRTTI() const
 	{
-		return ProfilerOverlay::getRTTIStatic();
+		return CProfilerOverlay::getRTTIStatic();
 	}
 
 	ProfilerOverlayInternal::ProfilerOverlayInternal(const SPtr<Camera>& camera)

+ 1 - 1
Source/ExampleProject/Source/Main.cpp

@@ -442,7 +442,7 @@ namespace bs
 		elemLayout->addElement(toggleFullscreenButton);
 
 		// Add a profiler overlay object that is responsible for displaying CPU and GPU profiling GUI
-		profilerOverlay = guiSO->addComponent<ProfilerOverlay>(guiCamera->_getCamera());
+		profilerOverlay = guiSO->addComponent<CProfilerOverlay>(guiCamera->_getCamera());
 
 		// Set up video mode list box
 		// First get a list of output devices