BearishSun пре 9 година
родитељ
комит
f87a58f0b9

+ 301 - 0
Documentation/Manuals/Managed/BSL.md

@@ -0,0 +1,301 @@
+# Banshee Shading Language
+BansheeSL is a material definition language that allows you to specify non-programmable render states together with programmable ones. For example BSL will allow you to define a set of input parameters, rasterizer, depth-stencil and blend states along with actual vertex/fragment GPU program code.
+
+Code code itself it written in any of the standard languages: HLSL or GLSL. A unified shading language is in the works so you do not need to write separate code for DirectX and OpenGL renderers.
+
+All BFX syntax can be represented using this primitive:
+	Type [Name] [= Value|Block] [: Modifier];
+
+Where:
+ - Type is one of the built-in language constructs. Most types are only allowed to be used in a certain context.
+ - Name is a user-defined name of the object. Certain Types have no names.
+ - Value is an integer, floating point value (including vectors and matrices of such), boolean, a string (surrounded by quotes, “value”), or one of the built-in values. Which type of value is accepted depends on the Type. 
+ - Block is a part of code that contains more primitives. As a special case blocks can also contain HLSL or GLSL code.
+
+A simple program that renders a mesh all in white looks like this:
+	Parameters =
+	{
+		mat4x4		gMatWorldViewProj;
+		mat4x4		gMatWorld;
+		mat4x4		gMatInvWorld;
+	};
+
+	Blocks =
+	{
+		Block PerObject;
+	};
+
+	Technique =
+	{
+		Language = "HLSL11";
+		
+		Pass =
+		{
+			Common = 
+			{
+				struct VStoFS
+				{
+					float4 position : SV_Position;
+				};
+				
+				cbuffer PerObject
+				{
+					float4x4 gMatWorldViewProj;
+					float4x4 gMatWorld;
+					float4x4 gMatInvWorld;
+				}					
+			};
+
+			Vertex =
+			{			
+				struct VertexInput
+				{
+					float3 position : POSITION;
+				};
+				
+				VStoFS main(VertexInput input)
+				{
+					VStoFS output;
+				
+					output.position = mul(gMatWorldViewProj, input.position);			
+					return output;
+				}
+			};
+			
+			Fragment =
+			{
+				float4 main(in VStoFS input) : SV_Target0
+				{
+					return float4(1.0f, 1.0f, 1.0f 1.0f); 
+				}	
+			};
+		};
+	};
+
+	
+On the top-most level the program consists out of three blocks:
+ - Parameters - Contains a list of input parameters into the program (constants/uniforms).
+ - Blocks - Contains a list of blocks that group input parameters (constant buffers/uniform buffers).
+ - Technique - Contains one or multiple passes that contain the pipeline state for rendering. This is the meat of the program.
+
+## Parameters
+All parameters specified in this block will be exposed to the Shader object. These parameters will be accessible from the editor's inspector, or directly from the Material object. You are still allowed to define uniforms/constants within shader code, without defining them in the parameter list, but they will not be visible to high level code. This might be useful if you are working on a lower level, like directly with the renderer.
+
+Types supported in this block are:
+ - int - signed integer
+ - int2 - 2D vector of signed integers
+ - int3 - 3D vector of signed integers
+ - int4 - 4D vector of signed integers
+ - float - floating point value
+ - float2 - 2D vector of floating point values
+ - float3 - 3D vector of floating point values
+ - float4 - 4D vector of floating point values
+ - color - 4D vector of floating point values (the same as float4)
+ - mat2x2 - 2x2 matrix of floating point values
+ - mat2x3 - 2x3 matrix of floating point values
+ - mat2x4 - 2x4 matrix of floating point values
+ - mat3x2 - 3x2 matrix of floating point values
+ - mat3x3 - 3x3 matrix of floating point values
+ - mat3x4 - 3x4 matrix of floating point values
+ - mat4x2 - 4x2 matrix of floating point values
+ - mat4x3 - 4x3 matrix of floating point values
+ - mat4x4 - 4x4 matrix of floating point values
+ - Sampler1D - Sampler state for a 1D texture
+ - Sampler2D - Sampler state for a 2D texture
+ - Sampler3D - Sampler state for a 3D texture
+ - SamplerCUBE - Sampler state for a cube texture
+ - Sampler2DMS - Sampler state for a multi-sampled 2D texture
+ - Texture1D - 1D texture
+ - Texture2D - 2D texture
+ - Texture3D - 3D texture
+ - TextureCUBE - Cube texture
+ - Texture2DMS - Multi-sampled 2D texture
+ - ByteBuffer - Readable buffer of raw bytes
+ - StructBuffer - Readable buffer of structs
+ - ByteBufferRW - Read/Write buffer of raw bytes (UAV/load-store buffer)
+ - StructBufferRW  - Read/Write buffer of structs (UAV/load-store buffer)
+ - AppendBuffer - Buffer that is used for appending data in a stack-like fashion
+ - ConsumeBuffer - Buffer that is used for consuming data in a stack-like fashion
+ 
+Each parameter must have at least a type followed by a unique name. The name must match the name of the parameter in actual shader code:
+	mat4x4 gMatWorldViewProj;
+	
+You are also allowed to specify a default value for primitive types:
+	float gMyFloat = 5.0f;
+	
+Or:
+	mat2x2 gMyMat = { 1.0f, 0.0f, 0.0f, 1.0f };
+	
+Textures can also have default values. Currently the accepted ones are "White", "Black" and "Normal". "Normal" will provide a normal texture with all normals pointing upwards, and "White" and "Black" will provide a white and black texture, respectively. For example:
+	Texture2D gMyTexture = "White";
+	
+Sampler states support more complex default values in the form of their own block. For example:
+	Sampler2D gMySampler = { ... };
+	
+Actual values in the sampler state will be explained later.
+
+Final element that parameter can have are modifiers. Modifiers are in the format of ": Modifier(Value)". Supported modifiers are:
+ - auto - Accepts a string that contains a semantic name. For example: "mat4x4 gMatWorldViewProj : auto("WVP");". If the semantic "WVP" is recognized by the active renderer this value will be automatically assigned by the renderer. Automatic values cannot be manually set through the editor inspector or the Material interface. Generally you only need this if you are working with the renderer on the lower level. The default renderer doesn't support any parameter semantics, it instead works using block semantics (see below).
+ - alias - Accepts a string that contains an alternative name for the element. This can only be used for samplers, and is used for interfacing with render APIs that do not have separate objects for textures and samplers (e.g. OpenGL). You can use this to give your sampler the same name as the texture so such API will recognize it.
+
+## Blocks
+Blocks are containers for parameters. Parameters don't have to belong to a block but if they do you can set parameter values as a batch, which is more efficient than setting them manually.
+
+Blocks all begin with the Block keyword, followed by a name. The name must match the name of the constant/uniform block in actual shader code:
+	Block MyBlock;
+	
+## Technique
+
+This is the meat of your program. A technique contains code for your vertex/fragment/geometry/hull/domain/compute shaders, as well as blend/rasterizer/depth-stencil states. A shader can contain multiple techniques but only a single technique is ever used at once. Different techniques can be specified for each shading language (e.g. HLSL, GLSL) and different renderer (in case you're using something other than the default).
+
+### Properties
+
+Technique block should therefore always contain a "Language" property like so:
+	Language = "HLSL"
+
+Supported values are "HLSL" (DirectX 11 HLSL), "HLSL9" (DirectX 9 HLSL), and "GLSL".
+
+You can also specify a renderer using the "Renderer" property:
+	Renderer = "Default"
+	
+Supported values are "Any", or "Default". More values could be available if you are using a custom renderer, but otherwise you don't need to set this property.
+
+Once the base properties are defined you can start defining code blocks and states.
+
+### Code blocks
+Code blocks are elements in the technique that will contain HLSL/GLSL (or other supported language) code. There are six supported code blocks:
+ - Vertex
+ - Fragment
+ - Geometry
+ - Hull
+ - Domain
+ - Compute
+ 
+Each corresponding to the programmable GPU pipline stage of the same name. A code block looks like this:
+Vertex =
+{
+	...raw HLSL/GLSL code...
+};
+
+Within a code block BSL parsing rules do not work, anything inside them is treated as native shader code in the language specified. BSL expects that main entry methods for each programmable stage are named "main" (similar to the OpenGL requirement). You can use any name for non-entry methods.
+
+Aside from the mentioned code blocks you can also use a "Common" code block. All code in the "Common" code block will be available in all other code blocks.
+
+### States
+Each technique can define properties for blend, depth-stencil and rasterizer state. See a list below of all supported properties and their accepted values:
+**Rasterizer**
+ - Fill = [WIRE/SOLID];
+ - Cull = [CW/CCW/NOCULL];
+ - DepthBias = float;
+ - ScaledDepthBias = float;
+ - DepthClip = [true/false];
+ - Scissor = [true/false];
+ - Multisample = [true/false];
+ - AALine = [true/false];
+ 
+**Depth-stencil**
+ - DepthRead = [true/false];
+ - DepthWrite = [true/false];
+ - CompareFunc = [FAIL/PASS/LT/GT/LTE/GTE/EQ/NEQ];
+ - Stencil = [true/false];
+ - StencilReadMask = int;
+ - StencilWriteMask = int;
+ - StencilOpFront = StencilOpBlock;
+ - StencilOpBack = StencilOpBlock;
+ - StencilRef = int;
+ 
+Where StencilOpBlock has properties:
+ - Fail = [KEEP/ZERO/REPLACE/INC/DEC/INCWRAP/DECWRAP/INV];
+ - ZFail = [KEEP/ZERO/REPLACE/INC/DEC/INCWRAP/DECWRAP/INV];
+ - Pass = [KEEP/ZERO/REPLACE/INC/DEC/INCWRAP/DECWRAP/INV];
+ - CompareFunc = [FAIL/PASS/LT/GT/LTE/GTE/EQ/NEQ];
+ 
+StencilOpBlock can also be defined in short form without having to specify property names. Parameters are ordered as listed here. For example:
+ - StencilOpFront = { KEEP, KEEP, REPLACE, PASS };
+
+**Blend state**
+ - AlphaToCoverage = [true/false];
+ - IndependantBlend = [true/false];
+ - Target = BlendTargetBlock;
+ 
+Where BlendTargetBlock has properties:
+ - Index = int;
+ - Blend = [true/false];
+ - Color = BlendDefinitionBlock;
+ - Alpha = BlendDefinitionBlock;
+ - WriteMask = [NOCOLOR/R/G/B/A/RG/RB/RA/GB/GA/BA/RGB/RGA/RBA/GBA/RGBA];
+ 
+Where BlendDefinitionBlock has properties:
+ - Source = [ONE/ZERO/DSTRGB/SRCRGB/DSTIRGB/SRCIRGB/DSTA/SRCA/DSTIA/SRCIA];
+ - Dest = [ONE/ZERO/DSTRGB/SRCRGB/DSTIRGB/SRCIRGB/DSTA/SRCA/DSTIA/SRCIA];
+ - Op = [ADD/SUB/RSUB/MIN/MAX];
+ 
+BlendDefinitionBlock can also be specified in short form similar as StencilOpBlock (parameters in order as listed here).
+ 
+Entries in brackets represent the supported keywords for the specified properties, while the other values represent data types.
+
+Take a look at BlendState, RasterizerState and DepthStencilState documentation for an explanation of these states. 
+
+### Passes
+Each technique can support one or multiple passes. By default you do not have to specify any passes in technique if your shader only requires a single pass. If multiple passes are required use the "Pass" block.
+
+A "Pass" block supports all the code-block and state properties the Technique supports. It also supports an additional "Index" property that accepts an integer and allows you to specify an order in which the passes are executed. It also allows the pass to be uniquely identified if merging passes (see later sections for information about merging). By default index is not needed and pass order of execution is assumed to be sequential.
+
+If you specify code blocks and/or states in both a Technique and a Pass block, then the values under the Technique block will be inherited by all Pass blocks of that technique.
+
+## Advanced
+
+### Block merging
+If multiple Techniques using the same "Language" and "Renderer" are found in the file, they will internally be merged into a single larger technique. You may also use value of "Any" for both "Language" or "Renderer" properties to allow the technique to be merged with techniques that don't match it exactly.
+
+When merging passes within techniques, pass "Index" properties are compared and passes with the same index are merged. If no index is specified, passes are merged sequentially according to their order in the techniques.
+
+Code blocks are also merged, in the order they are defined.
+
+### Pre-processor
+Use #include "Path/To/File.bslinc" to share code by including other BSL files. Included files must end with a .bslinc extension but otherwise their syntax is the same as a normal BSL file. The provided path is a path to the shader relative to the project library. You can also use built-in $ENGINE$ and $EDITOR$ folders to access builtin shaders. e.g.
+	#include "$ENGINE$/SpringImage.bslinc"
+	
+Be aware that $EDITOR$ folder will not be available in your standalone game.
+
+Use #define/#undef/#ifdef/#ifndef/#else/#elif/#endif to conditionally compile parts of the BSL file.
+
+Macros using #defines are not supported in BSL code, but are within code-blocks. So while you are allowed to write:
+	#define PI 3.14
+
+Any references to PI outside of code-blocks will not be replaced with 3.14 and will likely result in an error due to an unrecognized identifier.
+
+### Global shader properties
+On the top-most level you may also specify additional parameters along with "Parameters", "Blocks" and "Technique":
+ - Separable = [true/false]; - Specifies if passes within the shader need to be executed sequentially, or could some other shader be executed in-between them. This is an optimization as it can allow the system to render geometry sharing the same passes all at once. False by default.
+ - Sort - [FRONTTOBACK/BACKTOFRONT/NONE]; - Specifies in what order are the objects using this shader sorted before rendering.
+ - Priority - int; - Specifies when will objects with this shader be rendered compared to other objects. Higher value means the objects will be rendered sooner. Priority has higher importance than sorting.
+ - Transparent - [true/false]; - Determines whether the shader renders transparent surfaces. Allows the renderer to better handle the shader.
+ 
+### Sampler state default values
+Earlier we mentioned that sampler states can be provided a set of default values in a form of their own block, but didn't specify their properties. Sampler state properties are:
+ - AddressMode = AddressModeBlock;
+ - MinFilter = [NOFILTER/POINT/LINEAR/ANISO/POINTC/LINEARC/ANISOC];
+ - MaxFilter = [NOFILTER/POINT/LINEAR/ANISO/POINTC/LINEARC/ANISOC];
+ - MipFiler = [NOFILTER/POINT/LINEAR/ANISO/POINTC/LINEARC/ANISOC];
+ - MaxAniso = int;
+ - MipmapBias = float;
+ - MipMin = float;
+ - MipMax = float;
+ - BorderColor = { float, float, float, float };
+ - CompareFunc = [FAIL/PASS/LT/GT/LTE/GTE/EQ/NEQ];
+ 
+Where AddressModeBlock has the following properties:
+ - U = [WRAP/MIRROR/CLAMP/BORDER];
+ - V = [WRAP/MIRROR/CLAMP/BORDER];
+ - W = [WRAP/MIRROR/CLAMP/BORDER];
+ 
+It can also be specified in short form, where parameters are in order as above. For example:
+ - AddressMode = { WRAP, WRAP, WRAP };
+ 
+See SamplerState for documentation about the meaning of these properties. 
+ 
+### Modifiers
+Modifiers can be applied to either parameters or block. They are in the format of ": Modifier(Value)". Supported modifiers are:
+ - auto - Accepts a string that contains a semantic name. For example: "mat4x4 gMatWorldViewProj : auto("WVP");". If the semantic "WVP" is recognized by the active renderer this value will be automatically assigned by the renderer. Automatic values cannot be manually set through the editor inspector or the Material interface. Generally you only need this if you are working with the renderer on the lower level. Alternatively you can just hardcore the parameter names in the renderer, but semantics offer a more flexible approach. The default renderer doesn't support any parameter semantics but it does support some block semantics. See the [renderer guide](TODOLINK) for more information.
+ - alias - Accepts a string that contains an alternative name for the element. This can only be used for samplers, and is used for interfacing with render APIs that do not have separate objects for textures and samplers (e.g. OpenGL). You can use this to give your sampler the same name as the texture so such API will recognize it.

+ 25 - 0
Documentation/Manuals/Native/import.md

@@ -0,0 +1,25 @@
+Creating custom importers						{#customImporters}
+===============
+[TOC]
+
+Importers process a raw resource in a third-party format (like FBX mesh or a PNG image) into an engine-ready format (e.g. a @ref BansheeEngine::Mesh "Mesh" or a @ref BansheeEngine::Texture "Texture"). Banshee has an extensible importer system so you may easily add your own, either for existing resource types, or for new ones. If you are also interested in creating new resource types check out [this manual](@ref customResources).
+
+On the user-facing level resource import works through the @ref BansheeEngine::Importer "Importer" module. You call its @ref BansheeEngine::Importer::import "Importer::import" method which takes a path to the resource you want to import, and the system automatically finds the necessary importer plugin (if one is available) and returns the resource in an engine ready format. Optionally you can also supply the importer with @ref BansheeEngine::ImportOptions "ImportOptions" to control resource import in more details.
+
+To implement your own importer you need to implement the @ref BansheeEngine::SpecificImporter "SpecificImporter" interface.
+
+# Implementing SpecificImporter # {#customImporters_a}
+Implementing this interface involves implementation of the following methods:
+ * @ref BansheeEngine::SpecificImporter::isExtensionSupported "isExtensionSupported" - Receives an extension and return true or false depending if the importer can process that file. Used by the importer to find which importer plugin to use for import of a specific file.
+ * @ref BansheeEngine::SpecificImporter::isMagicNumberSupported "isMagicNumberSupported" - Similar to the method above, but receives a magic number (first few bytes of a file) instead of the extension, as this is the more common way of identifying files on non-Windows systems.
+ * @ref BansheeEngine::SpecificImporter::import "import" - Receives a path to a file, as well as a set of import options. This is the meat of the importer where you will read the file and convert it into engine ready format. When done the method returns a @ref BansheeEngine::Resource "Resource" of a valid type, or null if it failed. The method should take into account the import options it was provided (if your importer supports any).
+ 
+You may also optionally implement the following methods:
+ * @ref BansheeEngine::SpecificImporter::createImportOptions "createImportOptions" - If your importer supports specific import options this should return a brand new empty instance of such import options. These will eventually be provided to the @ref BansheeEngine::SpecificImporter::import "import" method. Import options must implement @ref BansheeEngine::ImportOptions "ImportOptions" and you may include any necessary fields in your implementation. You must also [implement RTTI](@ref rtti) for your custom import options. You should strive to use same type of import options for same resource types (for example all textures use @ref BansheeEngine::TextureImportOptions "TextureImportOptions").
+ * @ref BansheeEngine::SpecificImporter::importAll "importAll" - Sometimes a single third-party resource can contain multiple engine resources (for a example an .fbx may contain both a mesh and animation). In such cases you will want to implement this method, which allows you to return multiple resources, each with a unique identifier. One of the resources must always be considered primary, and that's the resource that should be returned by @ref BansheeEngine::SpecificImporter::import "import" (others should be ignored). In this method the primary resource must have the "primary" identifier, while you are free to add custom identifiers for every other resource.
+ 
+Once your importer is implemented you must register it with the global importer system. You may do this by calling @ref BansheeEngine::Importer::_registerAssetImporter "_registerAssetImporter" with an instance of your importer. It should be allocated using the general allocator and will be freed automatically on system shutdown.
+
+Optionally you can do this on the higher level by providing a list of importers to @ref BansheeEngine::Application::startUp "Application::startUp" method. This methods expects a list of dynamic library file-names, which means you must implement your importer as a [plugin](@ref customPlugins).
+
+See @ref BansheeEngine::PlainTextImporter "PlainTextImporter" for an implementation of a very simple importer that just imports raw textual files.

+ 70 - 0
Documentation/Manuals/Native/plugins.md

@@ -0,0 +1,70 @@
+Creating custom plugins						{#customPlugins}
+===============
+[TOC]
+
+Many systems in Banshee are implemented through plugins, libraries that are separate from the core of the engine and can be dynamically loaded or unloaded. If possible, it is the prefered way of extending the engine.
+
+The default Banshee @ref BansheeEngine::CoreApplication "Application" supports plugins for the following systems:
+ - Rendering API - Wrappers for render APIs like DirectX or OpenGL. See the manual about working with [low level render API] (@ref renderAPI) for more information.
+ - Renderer - Renderer that determines how is the scene displayed (lighting, shadows, post-processing, etc.). See the manual about implementing [custom renderers](@ref customRenderers).
+ - Input - Reports input events (mouse, keyboard, gamepad, etc.)
+ - Physics - Runs the physics simulation (like NVIDIA PhysX)
+ - Importers - Importers that handle conversion of some third party resource format into an engine-ready format. See the manual about implementing [custom importers](@ref customImporters).
+ 
+The supported plugins will be automatically loaded and unloaded by the application as needed, all you need to do is to provide names of their libraries to the @ref BansheeEngine::START_UP_DESC "START_UP_DESC" used to initialize the application. All plugins should be in the same folder as the main application executable. 
+
+Aside from the supported plugins you can also create a fully custom plugins that you load or unload manually.
+
+# Implementing supported plugins {#customPlugins_a}
+All supported plugins implement an informal interface through global "extern" methods. The interface supports three methods:
+ - loadPlugin() - Called when the plugin is initially loaded
+ - updatePlugin() - Called every frame
+ - unloadPlugin() - Called just before the plugin is unloaded
+ 
+You may choose to implement some, or none of these, although usually at least `loadPlugin()` method is needed so the plugin can register itself with the necessary system. A simple implementation might look like so:
+~~~~~~~~~~~~~{.cpp}
+
+extern "C" BS_MYPLUGIN_EXPORT void* loadPlugin()
+{
+	// Do something on load
+	return nullptr; // Not used
+}
+
+extern "C" BS_MYPLUGIN_EXPORT void updatePlugin()
+{
+	// Do something every frame
+}
+
+extern "C" BS_MYPLUGIN_EXPORT void unloadPlugin()
+{
+	// Do something before unload
+}
+
+~~~~~~~~~~~~~
+
+It's important that all instances of types (classes/structs) from the plugin are deleted before plugin unload happens. If this doesn't happen, and an object instance is deleted after the plugin has been unloaded you will end up with a corrupt virtual function table and a crash. Normally this is handled for you, but is good to keep in mind depending on what your plugin is doing.
+
+The exact implementations of these methods differ depending for which system are you implementing a plugin for, but we won't go into details for individual systems here. In most cases it just involves registering the plugin instance using some global manager. For example check "BsSLPlugin.cpp" in the @ref BansheeSL plugin, which registers a new importer that supports ".bsl" files.
+
+# Custom plugins {#customPlugins_b}
+Custom plugins can do whatever you wish, engine has no expectations from them so its up to your to load/unload them and to call their methods.
+
+To load a custom plugin you can use the @ref BansheeEngine::DynLibManager "DynLibManager". It has two methods:
+ - @ref BansheeEngine::DynLibManager::load "DynLibManager::load" - Accepts a file name to the library, and returns the @ref BansheeEngine::DynLib "DynLib" object if the load is successful or null otherwise. 
+ - @ref BansheeEngine::DynLibManager::unload "DynLibManager::unload" - Unloads a previously loaded library.
+ 
+Once the library is loaded you can use the @ref BansheeEngine::DynLib "DynLib" object, and its @ref BansheeEngine::DynLib::getSymbol "DynLib::getSymbol" method to retrieve a function pointer within the dynamic library, and call into it. For example if we wanted to retrieve a function pointer for the `loadPlugin` method from the previous chapter:
+~~~~~~~~~~~~~{.cpp}
+// Load library
+DynLib* myLibrary = DynLibManager::instance().load("myPlugin");
+
+// Retrieve function pointer (symbol)
+typedef void* (*LoadPluginFunc)();
+LoadPluginFunc loadPluginFunc = (LoadPluginFunc)myLibrary->getSymbol("loadPlugin");
+
+// Call the function
+loadPluginFunc();
+
+// Assuming we're done, unload the plugin
+DynLibManager::instance().unload(myLibrary);
+~~~~~~~~~~~~~

+ 292 - 0
Documentation/Manuals/Native/rtti.md

@@ -0,0 +1,292 @@
+Run-time type information						{#rtti}
+===============
+[TOC]
+
+This manual describes how is run-time type information (RTTI) used to provide meta-information about C++ classes during program execution. In Banshee specifically it allows you to:
+ - Ability to serialize/deserialize objects with no additional code 
+ - Get name of a class, and exact polymorphic type of an object (including safe casting)
+ - Get the hierarchy of base/derived classes of a specific type
+ - Iterate over all fields in an object, find their name and type, get/set their value
+ - Create new instances of a type with only its type-name
+ - Generate "diffs" of objects
+ 
+It is primarily used for saving/loading of objects (e.g. serialization/deserialization of a level), searching for objects (e.g. finding all resources used by a level) and generating "diffs" (Prefabs use diffs to persist/apply instance specific changes when the original changes).
+
+RTTI doesn't automatically work on all classes. You must manually specify the information required by the RTTI system. This involves two things:
+ - Making sure your class derives from `IReflectable` and implements the required methods
+ - Implement a `RTTIType` class
+ 
+# Adding RTTI to your own objects
+Assume you have a simple object you want to serialize:
+~~~~~~~~~~~~~{.cpp}
+class Texture
+{
+	int width, height;
+};
+~~~~~~~~~~~~~
+
+First off ensure it implements `IReflectable` and `getRTTIStatic` and `getRTTI` methods:
+~~~~~~~~~~~~~{.cpp}
+class Texture : public IReflectable
+{
+   int width, height;
+
+   static RTTITypeBase* getRTTIStatic()
+   { return TextureRTTI::instance(); }
+
+   RTTITypeBase* getRTTI() const override
+   { return Texture::getRTTIStatic(); }
+};
+~~~~~~~~~~~~~
+	
+This interface and its methods only serve to return an instance of `TextureRTTI`, which derives from `RTTIType` and contains all the necessary RTTI information. You will also usually want to make the RTTI type a `friend` of the type so it can easily access its private and protected fields.
+
+A basic implementation of `RTTIType` must provide information about the type name, unique ID of the type, its base class (`IReflectable` if it doesn't derive from anything else), a way to create a new instance of the type and a list of fields with their getter/setter methods. A simple one for our example `Texture` class might look like so:
+~~~~~~~~~~~~~{.cpp}
+class TextureRTTI : public RTTIType<Texture, IReflectable, TextureRTTI> // Specify type the RTTI is for, its base type, and RTTI type itself
+{
+	// Specify getter/setter methods for each field we want to be able to access from RTTI.
+	// Each getter/setter method always accepts a pointer to the instance being queried as the first parameter.
+	int& getWidth(Texture* obj) { return obj->width; }
+	void setWidth(Texture* obj, int& value) { obj->width = value; }
+	
+	int& getHeight(Texture* obj) { return obj->height; }
+	void setHeight(Texture* obj, int& value) { obj->height = value; }
+
+	TextureRTTI ()
+	{
+		// Register the getter/setter methods above. You must specify a name and field id (both must be unique within the type).
+		addPlainField(“width”, 0, &TextureRTTI::getWidth, &TextureRTTI::setWidth);
+		addPlainField(“height”, 1, &TextureRTTI::getHeight, &TextureRTTI::setHeight);
+	}
+
+	const String& getRTTIName() override
+	{
+		static String name = "Texture"; // Returns human readable name of the type
+		return name;
+	}
+
+	UINT32 getRTTIId() override
+	{
+		return TID_Texture; // User-provided globally unique integer for the type
+	}
+
+	SPtr<IReflectable> newRTTIObject() override
+	{
+		return bs_shared_ptr_new<Texture>(); // Create a brand new empty instance
+	}
+};
+~~~~~~~~~~~~~
+
+This is the minimum you need to do to add a RTTI type. However there are some advanced features that you might be interested in. You may specify different types of fields that can handle references to other complex objects, as well as provide arrays, or supply a pre- and post- processing steps for serialization. We'll cover this in the next chapters.
+
+Important thing to note about RTTI type fields is that they all require a unique ID. This ID ensures that serialized data isn't broken if the layout of the object changes during development. This means you can add new fields, or remove old ones and expect data saved using an older version to "just work". You do need to ensure never to assign an ID of a previously removed field to a new field. You also need to change the ID if the field's type changes (i.e. it used to be `int` but now it's `long`).
+
+# Advanced field types
+
+When registering fields with the RTTI type, the systems supports a several sets of `add*Field` methods, each expecting a unique name/id, but different getter/setter methods and each field type has a special purpose.
+
+## Plain fields
+In the example above we have shown how to provide getter/setter methods for fields of `int` type. These fields are considered "plain" fields by the engine, and fields for types like `float`, `bool` and any other built-in language type also falls into this category.
+
+You register plain fields by calling `addPlainField`. The getter/setter methods must return/accept a reference to the value of the field.
+
+## Reflectable fields
+Reflectable fields contain types deriving from `IReflectable`, that is complex objects that contain their own RTTI types. For example if we were to add a `Material` class to our example, it might contain a texture. In such case we would provide getter/setter methods like so:
+~~~~~~~~~~~~~{.cpp}
+class Material : public IReflectable
+{ 
+	Texture texture;
+	
+	... 
+};
+
+class MaterialRTTI : public RTTIType<Material, IReflectable, MaterialRTTI>
+{
+	Texture& getTexture(Material* obj) { return obj->texture; }
+	void setTexture(Material* obj, Texture& value) { obj->texture = value; }
+	
+	MaterialRTTI ()
+	{
+		addReflectableField("texture", 0, &MaterialRTTI::getTexture, &MaterialRTTI::setTexture);
+	}
+	
+	...
+};
+~~~~~~~~~~~~~
+
+As you can see the reflectable field is similar to a plain field, only the `addReflectableField` method is used. 
+
+The problem with this approach is that during serialization whenever a material references a texture, that entire texture will end up being serialized with it. This is something you normally want to avoid since multiple materials will usually be referencing the same texture. For that purpose "Reflectable pointer" fields exist.
+
+## Reflectable pointer fields
+This fields are similar to reflectable fields, as they also contain types deriving from `IReflectable`. However they only return a pointer to the owned object, instead of copying the object by value. This is relevant for serialization as the system will be smart enough to detect multiple fields pointing to the same instance of an `IReflectable` object, and only serialize it once (instead of every time it is encountered). When deserializing the system will also properly restore the pointers, so that all fields keep pointing to the same instance.
+
+Reflectable pointer getter/setter methods must return shared pointers to the instance. For example if we modified our Material class like so:
+~~~~~~~~~~~~~{.cpp}
+class Material : public IReflectable
+{ 
+	SPtr<Texture> texture;
+	
+	... 
+};
+
+class MaterialRTTI : public RTTIType<Material, IReflectable, MaterialRTTI>
+{
+	SPtr<Texture> getTexture(Material* obj) { return obj->texture; }
+	void setTexture(Material* obj, SPtr<Texture> value) { obj->texture = value; }
+	
+	MaterialRTTI ()
+	{
+		addReflectablePtrField("texture", 0, &MaterialRTTI::getTexture, &MaterialRTTI::setTexture);
+	}
+	
+	...
+};
+~~~~~~~~~~~~~
+
+## Array fields
+Each of the valid field types (plain/reflectable/reflectable pointer), also come in array form. The array form requires two additional getter/setter methods that return/set array size, and normal getter/setter require an extra index parameter. For example if we wanted to extend our material so it contains multiple textures:
+~~~~~~~~~~~~~{.cpp}
+class Material : public IReflectable
+{ 
+	Vector<SPtr<Texture>> textures;
+	
+	... 
+};
+
+class MaterialRTTI : public RTTIType<Material, IReflectable, MaterialRTTI>
+{
+	SPtr<Texture> getTexture(Material* obj, UINT32 idx) { return obj->textures[idx]; }
+	void setTexture(Material* obj, UINT32 idx, SPtr<Texture> value) { obj->textures[idx] = value; }
+	
+	UINT32 getNumTextures(Material* obj) { return obj->textures.size(); }
+	void setNumTextures(Material* obj, UINT32 size) { obj->textures.resize(size); }
+	
+	MaterialRTTI ()
+	{
+		addReflectablePtrArrayField("texture", 0, &MaterialRTTI::getTexture, &MaterialRTTI::getNumTextures, 
+			&MaterialRTTI::setTexture, &MaterialRTTI::setNumTextures);
+	}
+	
+	...
+};
+~~~~~~~~~~~~~
+
+Methods for registering array fields are:
+ - addPlainArrayField
+ - addReflectableArrayField
+ - addReflectablePtrArrayField
+
+They all follow the same syntax as in the example above.
+ 
+## Advanced plain fields
+Although plain fields are primarily intended for simple built-in types, sometimes it also needs to be used on complex types. For example a `std::string` is often used as a field type, but it is not a simple built-in type, nor can we make it derive from `IReflectable`. For these purposes you can use `RTTIPlainType`. This is a templated class you can specialize for your specific type. 
+
+It provides methods for serializing/deserializing and retrieving object size. It has no advanced functionality like versioning (so if the structure of the type changes, it will break any previously serialized data), or keeping references to other objects.
+
+For example if we wanted to serialize a string:
+~~~~~~~~~~~~~{.cpp}
+template<> struct RTTIPlainType<String>
+{	
+	enum { id = 20 }; enum { hasDynamicSize = 1 }; // Provide unique ID, and a flag whether the size of the structure is dynamic.
+
+	static void toMemory(const String& data, char* memory)
+	{ 
+		UINT32 size = getDynamicSize(data);
+
+		memcpy(memory, &size, sizeof(UINT32));
+		memory += sizeof(UINT32);
+		size -= sizeof(UINT32);
+		memcpy(memory, data.data(), size); 
+	}
+
+	static UINT32 fromMemory(String& data, char* memory)
+	{ 
+		UINT32 size;
+		memcpy(&size, memory, sizeof(UINT32)); 
+		memory += sizeof(UINT32);
+
+		UINT32 stringSize = size - sizeof(UINT32);
+		data = String(memory, stringSize);
+
+		return size;
+	}
+
+	static UINT32 getDynamicSize(const String& data)	
+	{ 
+		UINT64 dataSize = data.size() * sizeof(String::value_type) + sizeof(UINT32);
+		return (UINT32)dataSize;
+	}	
+}; 
+~~~~~~~~~~~~~
+
+Each specialization must implement all three (toMemory/fromMemory/getDynamicSize) methods. It must also provide a flag whether or not it has dynamic size. Any structure whose size varies with each instance must set this flag to true. You must also set it to true if the size is static but larger than 255 bytes (This flag is just an optimization that can save a little space in serialized data when disabled).
+
+After you implement this class you will be able to use it in getters/setters for `addPlainField`. You can also use the BS_ALLOW_MEMCPY_SERIALIZATION macro for simple structures. It will create a basic `RTTIPlainType` specialization which uses memcpy()/sizeof() to implement the necessary methods.
+
+If possible you should prefer implementing an `IReflectable` for complex objects instead of this approach. But it can be useful for types where no other option is available (like third party or standard library types) or types you are sure won't change or require other advanced functionality.
+
+`RTTIPlainType` specializations can also be used as a more traditional form of serialization in case you find the RTTI system an overkill. For example if you needed to transfer data over a network. The system provides helper methods that allow you to easily work with plain types in such case:
+ - char* rttiReadElem(Type&, char*); // Deserializes the element from the provided buffer and returns offset into the buffer after the read data
+ - char* rttiWriteElem(Type&, char*); // Serializes the element into the provided buffer and returns offset into the buffer after the written data
+ - UINT32 rttiGetElemSize(Type&); // Returns a size of a specific plain type
+
+# Advanced serialization
+Implementations of `RTTIType` can optionally implement `onSerializationStarted´, `onSerializationEnded`, `onDeserializationStarted` and `onDeserializationEnded` methods. As their names imply they will get called during serialization/deserialization and allow you to do any pre- or post-processing of the data. Most other systems (other than serialization) that access field data will also call these functions before reading, and after writing field data.
+
+Each of those methods accepts an `IReflectable` pointer to the object currently being processed. Each type that implements `IReflectable` also comes with a `mRTTIData` field which is of `Any` type, and can be used for storing temporary data during serialization/deserialization (primarily along the methods above).
+
+# Using RTTI
+Once you have an object with a RTTI type fully implement it you can use it for various purposes:
+
+## Getting object information
+~~~~~~~~~~~~~{.cpp}
+IReflectable* myObject = ...;
+
+rtti_is_of_type<Texture>(myObject); // Check if the object's type matches the provided type
+rtti_is_subclass<Texture>(myObject); // Check if type of the object is a subclass of the provided type
+rtti_create(TID_Texture); // Create a new empty instance of the object
+
+myObject->getTypeName(); // Name of the object's type
+myObject->getTypeId(); // Unique identifier of the object's type
+
+RTTITypeBase* rttiType = myObject->getRTTI(); // Returns the RTTIType object
+rttiType->getBaseClass(); // Get RTTI type for the base class
+rttiType->getDerivedClasses(); // Get all derived classes for an object
+rttiType->getNumFields(); // Get number of RTTI fields 
+rttiType->getField(index); // Get information about a field from its sequential index
+RTTIField* rttiField = rttiType->findField(name); // Get information about a field from its name
+rttiType->setPlainValue(myObject, "myField", someValue); // Set a value of a RTTI field (similar operations for all field types, including getters, and array fields)
+
+rttiField->isPlainType(); // Is field storing a plain type
+rttiField->isReflectableType(); // Is field storing a plain type
+rttiField->isReflectablePtrType(); // Is field storing a plain type
+rttiField->isArray(); // Does the field contain an array
+
+// Cast RTTIField* to RTTIPlainFieldBase*, RTTIReflectableFieldBase* or RTTIReflectablePtrFieldBase* according to exact type.
+// Use that type to access the field values (not shown here, but has the same effect as get/set methods on RTTIType* shown above, only more efficient)
+~~~~~~~~~~~~~
+
+## Serialization
+Serialization uses all the features shown in the chapter above in order to serialize an `IReflectable` object into a stream of bytes, and vice versa. By default binary serialization is used, but user can implement textual serialization (like XML or JSON) using the RTTI system, if needed.
+
+Binary serialized data can be output to memory, or to a file using: `MemorySerializer`, `FileEncoder`, `FileDecoder`. Their usage is simple:
+~~~~~~~~~~~~~{.cpp}
+IReflectable* myObject = ...;
+
+// Encode to file, then decode from it
+FileEncoder fe("Path\To\My\File.asset");
+fe.encode(myObject);
+
+FileDecoder fd("Path\To\My\File.asset");
+SPtr<IReflectable> myObjectCopy = fd.decode();
+
+// Encode to memory, then decode from it
+MemorySerializer ms;
+UINT32 size;
+UINT8* data = ms.encode(myObject, size);
+SPtr<IReflectable> myObjectCopy2 = ms.decode(data, size);
+
+bs_free(data);
+~~~~~~~~~~~~~