Procházet zdrojové kódy

More work on user manuals

BearishSun před 9 roky
rodič
revize
39627c97f2

+ 66 - 0
Documentation/Manuals/Native/User/guiLocalization.md

@@ -0,0 +1,66 @@
+Localization 						{#guiLocalization}
+===============
+
+So far we haven't mentioned why all GUI elements use the @ref bs::HString "HString" type for holding string information, instead of the raw **String** or **WString** types.
+
+**HString** is a localizable string, meaning the actual value of the string can be changed by changing the active language. This ensures you can easily create translations for GUI elements.
+
+# Localizing strings
+When creating a **HString** it takes an identifier as input, which must be unique.
+
+~~~~~~~~~~~~~{.cpp}
+HString myLocalizedString(L"_myStringId");
+~~~~~~~~~~~~~
+
+You can then assign values to that identifier through a @ref bs::StringTable "StringTable" resource. You create a **StringTable** by calling @ref bs::StringTable::create "StringTable::create()".
+
+~~~~~~~~~~~~~{.cpp}
+HStringTable stringTable = StringTable::create();
+~~~~~~~~~~~~~
+
+You can then use the string table to assign actual language strings for your localized string. This is done by calling @ref bs::StringTable::setString "StringTable::setString()". 
+
+~~~~~~~~~~~~~{.cpp}
+stringTable->setString(L"_myStringId", Language::EnglishUS, L"Hello!");
+stringTable->setString(L"_myStringId", Language::German, L"Hallo!");
+stringTable->setString(L"_myStringId", Language::Spanish, L"!Hola!");
+~~~~~~~~~~~~~
+
+Finally, you need to register the string table with @ref bs::StringTableManager "StringTableManager" by calling @ref bs::StringTableManager::setTable "StringTableManager::setTable()". **StringTableManager** is accessible globally through @ref bs::gStringTableManager "gStringTableManager()".
+
+~~~~~~~~~~~~~{.cpp}
+gStringTableManager().setTable(0, stringTable);
+~~~~~~~~~~~~~
+
+> Note: Multiple string tables are supported by giving them different identifiers. By default all **HString**%s will use the 0th string table, so it is suggest to always set that one for most common localizations.
+
+After the string table is set you can call @ref bs::StringTableManager::setActiveLanguage "StringTableManager::setActiveLanguage()" to change the current language. If the string table has a localization for the specified language, it will be used by any GUI elements referencing the localized string. The default language is English.
+
+~~~~~~~~~~~~~{.cpp}
+gStringTableManager().setActiveLanguage(Language::German);
+~~~~~~~~~~~~~
+
+# Default localization
+If you skip the step of creating the string table and assigning it to **StringTableManager**, the **HString** will use its identifier as the display string. In cases where you don't need localization you can just use actual display strings in the identifier field (as we have been doing so far).
+
+~~~~~~~~~~~~~{.cpp}
+HString myLocalizedString(L"Hello!");
+~~~~~~~~~~~~~
+
+> You can still localize this string. It will use "Hello!" as its value for the default language (English), which is also its identifier and can be used for assigning other values for it in a string table.
+
+# Parameters
+Localized strings can use parameters as placeholders to insert other data. This is useful when a localized string needs to contain information like numbers or other non-localized information. Use identifiers like "{0}", "{1}", etc. to specify parameters.
+
+~~~~~~~~~~~~~{.cpp}
+HString myLocalizedString(L"Hello my name is {0}, and I am {1} years old.");
+~~~~~~~~~~~~~
+
+Parameters can then be assigned by calling @ref bs::HString::setParameter "HString::setParameter()".
+
+~~~~~~~~~~~~~{.cpp}
+myLocalizedString.setParameter(0, L"John");
+myLocalizedString.setParameter(1, L"30");
+~~~~~~~~~~~~~
+
+> Note that translations in all languages should share the same number of parameters.

+ 187 - 0
Documentation/Manuals/Native/User/sceneQueries.md

@@ -0,0 +1,187 @@
+Scene queries						{#sceneQueries}
+===============
+
+Scene queries allow you to specify a geometric object and perform a query if that object intersects or overlaps any physics object in the scene. Most queries also return detailed information about the intersection. All queries are performed through the global @ref bs::Physics "Physics" interface, accessible through @ref bs::gPhysics "gPhysics()".
+
+Here is a short example of a basic query, to give you a better idea:
+
+~~~~~~~~~~~~~{.cpp}
+// Ray starting at origin, traveling towards negative Z
+Vector3 origin(0, 0, 0);
+Vector3 direction(0, 0, -1);
+Ray ray(origin, direction);
+
+PhysicsQueryHit hitInfo;
+
+// Cast a ray into the scene and return information about first object hit
+if(gPhysics().rayCast(ray, hitInfo))
+{
+	HCollider hitCollider = hitInfo.collider;
+	String hitSceneObjectName = hitCollider->SO()->getName();
+	
+	Vector3 contactPoint = hitInfo.point;
+	gDebug().logDebug("Hit " + hitSceneObjectName + " at point " + toString(contactPoint));
+}
+~~~~~~~~~~~~~
+
+There are two major types of queries:
+  - Casts - Check if an object hits something if traveling along a certain direction
+  - Overlaps - Check if object overlaps something at a specific position
+  
+# Casts
+Casts are types of queries in which you provide a shape, origin point and a direction, and the system check if the shape intersects anything along the way.
+
+Cast can be used with different objects (shapes):
+ - Ray
+ - Box
+ - Sphere
+ - Capsule
+ - Convex mesh
+ 
+> Note that only convex meshes are supported when performing mesh casts. Read the physics mesh manual to learn about convex meshes.
+
+They can also be categorized by the type of values they return:
+  - All hits - Most expensive type of cast query, returns information about all hit objects.
+  - Any hit - Cheapest type of cast query, just returns a boolean if hit occurred or not.
+  - Closest - Returns information only about the closest hit. Cheaper than *All*, more expensive than *Any*.
+  
+## All hit casts
+As the name implies, these type of queries perform a cast and then return information about all hit objects. Relevant methods are:
+ - @ref bs::Physics::rayCastAll "Physics::rayCastAll()"
+ - @ref bs::Physics::boxCastAll "Physics::boxCastAll()"
+ - @ref bs::Physics::sphereCastAll "Physics::sphereCastAll()"
+ - @ref bs::Physics::capsuleCastAll "Physics::capsuleCastAll()"
+ - @ref bs::Physics::convexCastAll "Physics::convexCastAll()"
+ 
+They all share a common interface, where as the first parameter they accept a shape with its starting position and orientation, travel direction, and finally an optional maximum range. They return an array of @ref bs::PhysicsQueryHit "PhysicsQueryHit" objects.
+
+~~~~~~~~~~~~~{.cpp}
+// Sphere centered at origin with radius 0.5
+Sphere sphere(Vector3(0, 0, 0), 0.5f);
+
+// Check negative Z direction
+Vector3 direction(0, 0, -1);
+
+// Find all objects intersecting the sphere traveling in the specified direction
+Vector<PhysicsQueryHit> hits = gPhysics().sphereCastAll(sphere, direction);
+
+for(auto& entry : hits)
+{
+	HCollider hitCollider = entry.collider;
+	String hitSceneObjectName = hitCollider->SO()->getName();
+	
+	Vector3 contactPoint = entry.point;
+	gDebug().logDebug("Found hit with " + hitSceneObjectName + " at point " + toString(contactPoint));
+}
+~~~~~~~~~~~~~
+
+**PhysicsQueryHit** object contains information about each individual hit, and it contains:
+ - **Collider** component that was hit
+ - Position and normal of the contact point
+ - Distance of the contact point from the query origin
+ - Index of the triangle that was hit (if hit collider is a **MeshCollider**)
+ - Barycentric coordinates of the triangle that was hit (if hit collider is a **MeshCollider**)
+ 
+## Closest hit casts
+Closest hit casts are nearly identical to all hit casts, with the main difference is that they return a boolean value if a hit occurred or not, and output a single **PhysicsQueryHit** object. Hit information returned always concerns the closest found hit. 
+
+Checking for closest hit is cheaper than checking for them all, and is usually adequate for most applications. Relevant methods are:
+ - @ref bs::Physics::rayCast "Physics::rayCast()"
+ - @ref bs::Physics::boxCast "Physics::boxCast()"
+ - @ref bs::Physics::sphereCast "Physics::sphereCast()"
+ - @ref bs::Physics::capsuleCast "Physics::capsuleCast()"
+ - @ref bs::Physics::convexCast "Physics::convexCast()"
+ 
+They also share a common interface where as the first parameter they accept a shape with its starting position and orientation, travel direction, reference to a **PhysicsQueryHit** object to receive the results, and finally an optional maximum range. They return a boolean value that returns true if anything was hit.
+
+~~~~~~~~~~~~~{.cpp}
+// Axis aligned box centered at origin with extents 0.5 in all directions
+AABox box(Vector3(-0.5f, -0.5f, -0.5f), Vector3(0.5f, 0.5f, 0.5f));
+
+// Check negative Z direction
+Vector3 direction(0, 0, -1);
+
+// Find closest object intersecting the box traveling in the specified direction
+PhysicsQueryHit hitInfo;
+if(gPhysics().boxCast(box, direction, hitInfo))
+{
+	HCollider hitCollider = hitInfo.collider;
+	String hitSceneObjectName = hitCollider->SO()->getName();
+	
+	Vector3 contactPoint = hitInfo.point;
+	gDebug().logDebug("Found hit with " + hitSceneObjectName + " at point " + toString(contactPoint));
+}
+~~~~~~~~~~~~~
+
+## Any hit casts
+Finally, any hit casts are the simplest (and cheapest) of them all. They simply return a boolean value if a hit occurred or not. They do not return any further information about the hit.
+
+Relevant methods are:
+ - @ref bs::Physics::rayCastAny "Physics::rayCastAny()"
+ - @ref bs::Physics::boxCastAny "Physics::boxCastAny()"
+ - @ref bs::Physics::sphereCastAny "Physics::sphereCastAny()"
+ - @ref bs::Physics::capsuleCastAny "Physics::capsuleCastAny()"
+ - @ref bs::Physics::convexCastAny "Physics::convexCastAny()"
+ 
+~~~~~~~~~~~~~{.cpp}
+// Ray starting at origin, traveling towards negative Z
+Vector3 origin(0, 0, 0);
+Vector3 direction(0, 0, -1);
+Ray ray(origin, direction);
+
+// See if the ray intersects anything while traveling in the specified direction
+if(gPhysics().rayCastAny(ray))
+	gDebug().logDebug("Found hit!");
+~~~~~~~~~~~~~
+
+# Overlaps
+Overlap queries simply check if an object standing still at a specific position/orientation overlaps any other objects. 
+
+Overlaps can be used with different shapes:
+ - Box
+ - Sphere
+ - Capsule
+ - Convex mesh
+ 
+They can also be categorized by the type of values they return:
+  - All overlaps - Most expensive type of overlap query, returns all overlapping objects.
+  - Any overlap - Cheapest type of overlap query, just returns a boolean if overlap occurred or not.
+  
+## All overlap methods
+These overlap methods return an array of **Collider**%s consisting of all the objects the provided shape is currently overlapping. Relevant methods are:
+ - @ref bs::Physics::boxOverlap "Physics::boxOverlap()"
+ - @ref bs::Physics::sphereOverlap "Physics::sphereOverlap()"
+ - @ref bs::Physics::capsuleOverlap "Physics::capsuleOverlap()"
+ - @ref bs::Physics::convexOverlap "Physics::convexOverlap()"
+ 
+They all share a common interface. As input they take a shape with its starting position and orientation, and return an array of overlapping objects. 
+
+~~~~~~~~~~~~~{.cpp}
+// Sphere centered at origin with radius 0.5
+Sphere sphere(Vector3(0, 0, 0), 0.5f);
+
+// Find all objects overlapping the sphere
+Vector<HCollider> overlaps = gPhysics().sphereOverlap(sphere);
+
+for(auto& entry : overlaps)
+{
+	String overlappingSceneObjectName = entry->SO()->getName();
+	gDebug().logDebug("Found overlap with " + overlappingSceneObjectName);
+}
+~~~~~~~~~~~~~
+
+## Any overlap methods
+This is a set of overlap methods that returns only a boolean value if the overlap occurred or not, without a list of colliders that are overlapping. This is cheaper than querying for all overlaps. The relevant methods are:
+ - @ref bs::Physics::boxOverlapAny "Physics::boxOverlapAny()"
+ - @ref bs::Physics::sphereOverlapAny "Physics::sphereOverlapAny()"
+ - @ref bs::Physics::capsuleOverlapAny "Physics::capsuleOverlapAny()"
+ - @ref bs::Physics::convexOverlapAny "Physics::convexOverlapAny()"
+ 
+ ~~~~~~~~~~~~~{.cpp}
+// Sphere centered at origin with radius 0.5
+Sphere sphere(Vector3(0, 0, 0), 0.5f);
+
+// Check if sphere overlaps anything 
+if(gPhysics().sphereOverlapAny(sphere))
+	gDebug().logDebug("Found overlap!");
+~~~~~~~~~~~~~

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

@@ -39,6 +39,7 @@ Manuals									{#manuals}
  - [Layouts](@ref guiLayouts)
  - [Styles](@ref guiStyles)
  - [Importing fonts](@ref importingFonts)
+ - [Localization](@ref guiLocalization)
 - **Audio**
  - [Importing audio files](@ref importingAudio)
  - [Playing audio](@ref playingAudio)
@@ -49,6 +50,7 @@ Manuals									{#manuals}
  - [Dynamic objects](@ref rigidbodies)
  - [Physics material](@ref physicsMaterial)
  - [Character controller](@ref characterController)
+ - [Scene queries](@ref sceneQueries)
  
 # Developer guides
 

+ 1 - 1
Source/BansheeCore/Include/BsPhysicsCommon.h

@@ -68,7 +68,7 @@ namespace bs
 	{
 		Vector3 point; /**< Position of the hit in world space. */
 		Vector3 normal; /**< Normal to the surface that was hit. */
-		Vector2 uv; /**< UV coordinates of the triangle that was hit (only applicable when triangle meshes are hit). */
+		Vector2 uv; /**< Barycentric coordinates of the triangle that was hit (only applicable when triangle meshes are hit). */
 		float distance = 0.0f; /**< Distance from the query origin to the hit position. */
 		UINT32 triangleIdx = 0; /**< Index of the triangle that was hit (only applicable when triangle meshes are hit). */
 		Collider* colliderRaw = nullptr; /**< Collider that was hit. */

+ 3 - 0
Source/BansheeCore/Include/BsStringTableManager.h

@@ -41,5 +41,8 @@ namespace bs
 		UnorderedMap<UINT32, HStringTable> mTables;
 	};
 
+	/** Provides easier access to StringTableManager. */
+	BS_CORE_EXPORT StringTableManager& gStringTableManager();
+
 	/** @} */
 }

+ 5 - 0
Source/BansheeCore/Source/BsStringTableManager.cpp

@@ -45,4 +45,9 @@ namespace bs
 		if (table != nullptr)
 			table->setActiveLanguage(mActiveLanguage);
 	}
+
+	StringTableManager& gStringTableManager()
+	{
+		return StringTableManager::instance();
+	}
 }