//[-------------------------------------------------------]
//[ Public virtual IApplication methods                   ]
//[-------------------------------------------------------]
void FirstGeometryShader::onInitialization()
{
	// Call the base implementation
	IApplicationRenderer::onInitialization();

	// Get and check the renderer instance
	// -> Geometry shaders supported?
	Renderer::IRendererPtr renderer(getRenderer());
	if (nullptr != renderer && renderer->getCapabilities().maximumNumberOfGsOutputVertices)
	{
		// Begin debug event
		RENDERER_BEGIN_DEBUG_EVENT_FUNCTION(renderer)

		// Decide which shader language should be used (for example "GLSL", "HLSL" or "Cg")
		Renderer::IShaderLanguagePtr shaderLanguage(renderer->getShaderLanguage());
		if (nullptr != shaderLanguage)
		{
			{ // Create the program
				// Get the shader source code (outsourced to keep an overview)
				const char *vertexShaderSourceCode = nullptr;
				const char *geometryShaderSourceCode = nullptr;
				const char *fragmentShaderSourceCode = nullptr;
				#include "FirstGeometryShader_GLSL_330.h"
				#include "FirstGeometryShader_HLSL_D3D10_D3D11.h"
				#include "FirstGeometryShader_Null.h"

				// Create the program
				mProgram = shaderLanguage->createProgram(
					shaderLanguage->createVertexShader(vertexShaderSourceCode),
					shaderLanguage->createGeometryShader(geometryShaderSourceCode, Renderer::GsInputPrimitiveTopology::POINTS, Renderer::GsOutputPrimitiveTopology::TRIANGLE_STRIP, 3),
					shaderLanguage->createFragmentShader(fragmentShaderSourceCode));
			}

			// TODO(co) Attribute less rendering (aka "drawing without data") possible with OpenGL? For me it appears not to work, I see nothing and also get no error...
			// -> Tested with: "Radeon HD 6970M", driver "catalyst_12-7_beta_windows7_20120629.exe"
			// -> According to http://renderingpipeline.com/2012/03/are-vertex-shaders-obsolete/ it should work
			// -> Apparently there are currently some issues when using this approach: http://www.opengl.org/discussion_boards/showthread.php/177372-Rendering-simple-shapes-without-passing-vertices
			if (nullptr != mProgram && 0 == strcmp(renderer->getName(), "OpenGL"))
			{
				// Create the vertex buffer object (VBO)
				static const float VERTEX_POSITION[] =
				{			// Vertex ID
					42.0f	// 0
				};
				Renderer::IVertexBufferPtr vertexBuffer(renderer->createVertexBuffer(sizeof(VERTEX_POSITION), VERTEX_POSITION, Renderer::BufferUsage::STATIC_DRAW));

				// Create vertex array object (VAO)
				// -> The vertex array object (VAO) keeps a reference to the used vertex buffer object (VBO)
				// -> This means that there's no need to keep an own vertex buffer object (VBO) reference
				// -> When the vertex array object (VAO) is destroyed, it automatically decreases the
				//    reference of the used vertex buffer objects (VBO). If the reference counter of a
				//    vertex buffer object (VBO) reaches zero, it's automatically destroyed.
				const Renderer::VertexArrayAttribute vertexArray[] =
				{
					{ // Attribute 0
						// Data destination
						Renderer::VertexArrayFormat::FLOAT_1,	// vertexArrayFormat (Renderer::VertexArrayFormat::Enum)
						"Position",								// name[64] (char)
						"POSITION",								// semantic[64] (char)
						0,										// semanticIndex (unsigned int)
						// Data source
						vertexBuffer,							// vertexBuffer (Renderer::IVertexBuffer *)
						0,										// offset (unsigned int)
						sizeof(float),							// stride (unsigned int)
						// Data source, instancing part
						0										// instancesPerElement (unsigned int)
					}
				};
				mVertexArray = mProgram->createVertexArray(sizeof(vertexArray) / sizeof(Renderer::VertexArrayAttribute), vertexArray);
			}
		}

		// End debug event
		RENDERER_END_DEBUG_EVENT(renderer)
	}
Exemplo n.º 2
0
//[-------------------------------------------------------]
//[ Public virtual IApplication methods                   ]
//[-------------------------------------------------------]
void FirstTriangle::onInitialization()
{
	// Call the base implementation
	IApplicationRenderer::onInitialization();

	// Get and check the renderer instance
	Renderer::IRendererPtr renderer(getRenderer());
	if (nullptr != renderer)
	{
		// Begin debug event
		RENDERER_BEGIN_DEBUG_EVENT_FUNCTION(renderer)

		// Decide which shader language should be used (for example "GLSL", "HLSL" or "Cg")
		Renderer::IShaderLanguagePtr shaderLanguage(renderer->getShaderLanguage());
		if (nullptr != shaderLanguage)
		{
			{ // Create the program
				// Get the shader source code (outsourced to keep an overview)
				const char *vertexShaderSourceCode = nullptr;
				const char *fragmentShaderSourceCode = nullptr;
				#include "FirstTriangle_Cg.h"
				#include "FirstTriangle_GLSL_110.h"
				#include "FirstTriangle_GLSL_ES2.h"
				#include "FirstTriangle_HLSL_D3D9_D3D10_D3D11.h"
				#include "FirstTriangle_Null.h"

				// Create the vertex shader
				Renderer::IVertexShader *vertexShader = shaderLanguage->createVertexShader(vertexShaderSourceCode);
				RENDERER_SET_RESOURCE_DEBUG_NAME(vertexShader, "Triangle VS")

				// Create the fragment shader
				Renderer::IFragmentShader *fragmentShader = shaderLanguage->createFragmentShader(fragmentShaderSourceCode);
				RENDERER_SET_RESOURCE_DEBUG_NAME(fragmentShader, "Triangle FS")

				// Create the program
				mProgram = shaderLanguage->createProgram(vertexShader, fragmentShader);
				RENDERER_SET_RESOURCE_DEBUG_NAME(mProgram, "Triangle program")
			}

			// Is there a valid program?
			if (nullptr != mProgram)
			{
				// Create the vertex buffer object (VBO)
				// -> Clip space vertex positions, left/bottom is (-1,-1) and right/top is (1,1)
				static const float VERTEX_POSITION[] =
				{					// Vertex ID	Triangle on screen
					 0.0f, 1.0f,	// 0				0
					 1.0f, 0.0f,	// 1			   .   .
					-0.5f, 0.0f		// 2			  2.......1
				};
				Renderer::IVertexBufferPtr vertexBuffer(renderer->createVertexBuffer(sizeof(VERTEX_POSITION), VERTEX_POSITION, Renderer::BufferUsage::STATIC_DRAW));
				RENDERER_SET_RESOURCE_DEBUG_NAME(vertexBuffer, "Triangle VBO")

				// Create vertex array object (VAO)
				// -> The vertex array object (VAO) keeps a reference to the used vertex buffer object (VBO)
				// -> This means that there's no need to keep an own vertex buffer object (VBO) reference
				// -> When the vertex array object (VAO) is destroyed, it automatically decreases the
				//    reference of the used vertex buffer objects (VBO). If the reference counter of a
				//    vertex buffer object (VBO) reaches zero, it's automatically destroyed.
				const Renderer::VertexArrayAttribute vertexArray[] =
				{
					{ // Attribute 0
						// Data destination
						Renderer::VertexArrayFormat::FLOAT_2,	// vertexArrayFormat (Renderer::VertexArrayFormat::Enum)
						"Position",								// name[64] (char)
						"POSITION",								// semantic[64] (char)
						0,										// semanticIndex (unsigned int)
						// Data source
						vertexBuffer,							// vertexBuffer (Renderer::IVertexBuffer *)
						0,										// offset (unsigned int)
						sizeof(float) * 2,						// stride (unsigned int)
						// Data source, instancing part
						0										// instancesPerElement (unsigned int)
					}
				};
				mVertexArray = mProgram->createVertexArray(sizeof(vertexArray) / sizeof(Renderer::VertexArrayAttribute), vertexArray);
				RENDERER_SET_RESOURCE_DEBUG_NAME(mVertexArray, "Triangle VAO")
			}
		}
Exemplo n.º 3
0
//[-------------------------------------------------------]
//[ Public virtual IApplication methods                   ]
//[-------------------------------------------------------]
void Fxaa::onInitialization()
{
	// Call the base implementation
	IApplicationRenderer::onInitialization();

	// Get and check the renderer instance
	Renderer::IRendererPtr renderer(getRenderer());
	if (nullptr != renderer)
	{
		// Begin debug event
		RENDERER_BEGIN_DEBUG_EVENT_FUNCTION(renderer)

		// Create the framebuffer object (FBO) instance by using the current window size
		recreateFramebuffer();

		{ // Create sampler state
		  // -> Our texture does not have any mipmaps, set "Renderer::SamplerState::maxLOD" to zero
		  //    in order to ensure a correct behaviour across the difference graphics APIs
		  // -> When not doing this you usually have no issues when using OpenGL, OpenGL ES 2, Direct 10,
		  //    Direct3D 11 or Direct3D 9 with the "ps_2_0"-profile, but when using Direct3D 9 with the
		  //    "ps_3_0"-profile you might get into trouble due to another internal graphics API behaviour
			Renderer::SamplerState samplerState = Renderer::ISamplerState::getDefaultSamplerState();
			samplerState.maxLOD = 0.0f;	// We don't use mipmaps
			mSamplerState = renderer->createSamplerState(samplerState);
		}

		{ // Depth stencil state
		  // -> By default depth test is enabled
		  // -> In this simple example we don't need depth test, so, disable it so we don't need to care about the depth buffer

			// Create depth stencil state
			Renderer::DepthStencilState depthStencilState = Renderer::IDepthStencilState::getDefaultDepthStencilState();
			depthStencilState.depthEnable = false;
			mDepthStencilState = renderer->createDepthStencilState(depthStencilState);

			// Set the depth stencil state directly within this initialization phase, we don't change it later on
			renderer->omSetDepthStencilState(mDepthStencilState);
		}

		// Decide which shader language should be used (for example "GLSL", "HLSL" or "Cg")
		Renderer::IShaderLanguagePtr shaderLanguage(renderer->getShaderLanguage());
		if (nullptr != shaderLanguage)
		{
			{ // Create the program for scene rendering
				// Get the shader source code (outsourced to keep an overview)
				const char *vertexShaderSourceCode = nullptr;
				const char *fragmentShaderSourceCode = nullptr;
				#include "Fxaa_SceneRendering_Cg.h"
				#include "Fxaa_SceneRendering_GLSL_120.h"
				#include "Fxaa_SceneRendering_GLSL_ES2.h"
				#include "Fxaa_SceneRendering_HLSL_D3D9_D3D10_D3D11.h"
				#include "Fxaa_SceneRendering_Null.h"

				// Create the program for scene rendering
				mProgramSceneRendering = shaderLanguage->createProgram(shaderLanguage->createVertexShader(vertexShaderSourceCode), shaderLanguage->createFragmentShader(fragmentShaderSourceCode));
			}

			// Is there a valid program for scene rendering?
			if (nullptr != mProgramSceneRendering)
			{
				// Create the vertex buffer object (VBO)
				// -> Clip space vertex positions, left/bottom is (-1,-1) and right/top is (1,1)
				static const float VERTEX_POSITION[] =
				{					// Vertex ID	Triangle on screen
					 0.0f, 1.0f,	// 0				0
					 1.0f, 0.0f,	// 1			   .   .
					-0.5f, 0.0f		// 2			  2.......1
				};
				Renderer::IVertexBufferPtr vertexBuffer(renderer->createVertexBuffer(sizeof(VERTEX_POSITION), VERTEX_POSITION, Renderer::BufferUsage::STATIC_DRAW));

				// Create vertex array object (VAO)
				// -> The vertex array object (VAO) keeps a reference to the used vertex buffer object (VBO)
				// -> This means that there's no need to keep an own vertex buffer object (VBO) reference
				// -> When the vertex array object (VAO) is destroyed, it automatically decreases the
				//    reference of the used vertex buffer objects (VBO). If the reference counter of a
				//    vertex buffer object (VBO) reaches zero, it's automatically destroyed.
				const Renderer::VertexArrayAttribute vertexArray[] =
				{
					{ // Attribute 0
						// Data destination
						Renderer::VertexArrayFormat::FLOAT_2,	// vertexArrayFormat (Renderer::VertexArrayFormat::Enum)
						"Position",								// name[64] (char)
						"POSITION",								// semantic[64] (char)
						0,										// semanticIndex (unsigned int)
						// Data source
						vertexBuffer,							// vertexBuffer (Renderer::IVertexBuffer *)
						0,										// offset (unsigned int)
						sizeof(float) * 2,						// stride (unsigned int)
						// Data source, instancing part
						0										// instancesPerElement (unsigned int)
					}
				};
				mVertexArraySceneRendering = mProgramSceneRendering->createVertexArray(sizeof(vertexArray) / sizeof(Renderer::VertexArrayAttribute), vertexArray);
			}

			// Create the post-processing program instance by using the current window size
			recreatePostProcessingProgram();

			// Is there a valid program for post-processing?
			if (nullptr != mProgramPostProcessing)
			{
				// Create the vertex buffer object (VBO)
				// -> Clip space vertex positions, left/bottom is (-1,-1) and right/top is (1,1)
				static const float VERTEX_POSITION[] =
				{					// Vertex ID	Triangle strip on screen
					-1.0f, -1.0f,	// 0			  1.......3
					-1.0f,  1.0f,	// 1			  .	  .   .
					 1.0f, -1.0f,	// 2			  0.......2
					 1.0f,  1.0f	// 3
				};
				Renderer::IVertexBufferPtr vertexBuffer(renderer->createVertexBuffer(sizeof(VERTEX_POSITION), VERTEX_POSITION, Renderer::BufferUsage::STATIC_DRAW));

				// Create vertex array object (VAO)
				// -> The vertex array object (VAO) keeps a reference to the used vertex buffer object (VBO)
				// -> This means that there's no need to keep an own vertex buffer object (VBO) reference
				// -> When the vertex array object (VAO) is destroyed, it automatically decreases the
				//    reference of the used vertex buffer objects (VBO). If the reference counter of a
				//    vertex buffer object (VBO) reaches zero, it's automatically destroyed.
				const Renderer::VertexArrayAttribute vertexArray[] =
				{
					{ // Attribute 0
						// Data destination
						Renderer::VertexArrayFormat::FLOAT_2,	// vertexArrayFormat (Renderer::VertexArrayFormat::Enum)
						"Position",								// name[64] (char)
						"POSITION",								// semantic[64] (char)
						0,										// semanticIndex (unsigned int)
						// Data source
						vertexBuffer,							// vertexBuffer (Renderer::IVertexBuffer *)
						0,										// offset (unsigned int)
						sizeof(float) * 2,						// stride (unsigned int)
						// Data source, instancing part
						0										// instancesPerElement (unsigned int)
					}
				};
				mVertexArrayPostProcessing = mProgramSceneRendering->createVertexArray(sizeof(vertexArray) / sizeof(Renderer::VertexArrayAttribute), vertexArray);
			}
		}

		// End debug event
		RENDERER_END_DEBUG_EVENT(renderer)
	}
Exemplo n.º 4
0
//[-------------------------------------------------------]
//[ Public virtual IApplication methods                   ]
//[-------------------------------------------------------]
void FirstMesh::onInitialization()
{
    // Call the base implementation
    IApplicationRendererRuntime::onInitialization();

    // Get and check the renderer runtime instance
    RendererRuntime::IRendererRuntime* rendererRuntime = getRendererRuntime();
    if (nullptr != rendererRuntime)
    {
        Renderer::IRendererPtr renderer(getRenderer());

        // Create uniform buffers
        // -> Direct3D 9 and OpenGL ES 2 do not support uniform buffers
        // -> Direct3D 10, 11 and 12 do not support individual uniforms
        // -> The renderer is just a light weight abstraction layer, so we need to handle the differences
        if ((0 == strcmp(renderer->getName(), "Direct3D10") || 0 == strcmp(renderer->getName(), "Direct3D11") || 0 == strcmp(renderer->getName(), "Direct3D12")))
        {
            // Allocate enough memory for two 4x4 floating point matrices
            mUniformBuffer = rendererRuntime->getBufferManager().createUniformBuffer(2 * 4 * 4 * sizeof(float), nullptr, Renderer::BufferUsage::DYNAMIC_DRAW);
        }

        // Decide which shader language should be used (for example "GLSL" or "HLSL")
        Renderer::IShaderLanguagePtr shaderLanguage(renderer->getShaderLanguage());
        if (nullptr != shaderLanguage)
        {
            // Vertex input layout
            const Renderer::VertexAttribute vertexAttributesLayout[] =
            {
                {   // Attribute 0
                    // Data destination
                    Renderer::VertexAttributeFormat::FLOAT_3,	// vertexAttributeFormat (Renderer::VertexAttributeFormat)
                    "Position",									// name[32] (char)
                    "POSITION",									// semanticName[32] (char)
                    0,											// semanticIndex (uint32_t)
                    // Data source
                    0,											// inputSlot (uint32_t)
                    0,											// alignedByteOffset (uint32_t)
                    // Data source, instancing part
                    0											// instancesPerElement (uint32_t)
                },
                {   // Attribute 1
                    // Data destination
                    Renderer::VertexAttributeFormat::SHORT_2,	// vertexAttributeFormat (Renderer::VertexAttributeFormat)
                    "TexCoord",									// name[32] (char)
                    "TEXCOORD",									// semanticName[32] (char)
                    0,											// semanticIndex (uint32_t)
                    // Data source
                    0,											// inputSlot (uint32_t)
                    sizeof(float) * 3,							// alignedByteOffset (uint32_t)
                    // Data source, instancing part
                    0											// instancesPerElement (uint32_t)
                },
                {   // Attribute 2
                    // Data destination
                    Renderer::VertexAttributeFormat::SHORT_4,	// vertexAttributeFormat (Renderer::VertexAttributeFormat)
                    "QTangent",									// name[32] (char)
                    "TEXCOORD",									// semanticName[32] (char)
                    1,											// semanticIndex (uint32_t)
                    // Data source
                    0,											// inputSlot (uint32_t)
                    sizeof(float) * 3 + sizeof(short) * 2,		// alignedByteOffset (uint32_t)
                    // Data source, instancing part
                    0											// instancesPerElement (uint32_t)
                }
            };
            const Renderer::VertexAttributes vertexAttributes(glm::countof(vertexAttributesLayout), vertexAttributesLayout);

            {   // Create the root signature
                Renderer::DescriptorRangeBuilder ranges[6];
                ranges[0].initialize(Renderer::DescriptorRangeType::UBV, 1, 0, "UniformBlockDynamicVs", 0);
                ranges[1].initializeSampler(1, 0);
                ranges[2].initialize(Renderer::DescriptorRangeType::SRV, 1, 0, "DiffuseMap", 1);
                ranges[3].initialize(Renderer::DescriptorRangeType::SRV, 1, 1, "EmissiveMap", 1);
                ranges[4].initialize(Renderer::DescriptorRangeType::SRV, 1, 2, "NormalMap", 1);
                ranges[5].initialize(Renderer::DescriptorRangeType::SRV, 1, 3, "SpecularMap", 1);

                Renderer::RootParameterBuilder rootParameters[6];
                rootParameters[0].initializeAsDescriptorTable(1, &ranges[0], Renderer::ShaderVisibility::VERTEX);
                rootParameters[1].initializeAsDescriptorTable(1, &ranges[1], Renderer::ShaderVisibility::FRAGMENT);
                rootParameters[2].initializeAsDescriptorTable(1, &ranges[2], Renderer::ShaderVisibility::FRAGMENT);
                rootParameters[3].initializeAsDescriptorTable(1, &ranges[3], Renderer::ShaderVisibility::FRAGMENT);
                rootParameters[4].initializeAsDescriptorTable(1, &ranges[4], Renderer::ShaderVisibility::FRAGMENT);
                rootParameters[5].initializeAsDescriptorTable(1, &ranges[5], Renderer::ShaderVisibility::FRAGMENT);

                // Setup
                Renderer::RootSignatureBuilder rootSignature;
                rootSignature.initialize(glm::countof(rootParameters), rootParameters, 0, nullptr, Renderer::RootSignatureFlags::ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT);

                // Create the instance
                mRootSignature = renderer->createRootSignature(rootSignature);
            }

            // Create the program
            Renderer::IProgramPtr program;
            {
                // Get the shader source code (outsourced to keep an overview)
                const char *vertexShaderProfile = nullptr;
                const char *vertexShaderSourceCode = nullptr;
                const char *fragmentShaderProfile = nullptr;
                const char *fragmentShaderSourceCode = nullptr;
#include "FirstMesh_GLSL_410.h"
#include "FirstMesh_GLSL_ES2.h"
#include "FirstMesh_HLSL_D3D9.h"
#include "FirstMesh_HLSL_D3D10_D3D11_D3D12.h"
#include "FirstMesh_Null.h"

                // Create the program
                mProgram = program = shaderLanguage->createProgram(
                                         *mRootSignature,
                                         vertexAttributes,
                                         shaderLanguage->createVertexShaderFromSourceCode(vertexAttributes, vertexShaderSourceCode, vertexShaderProfile),
                                         shaderLanguage->createFragmentShaderFromSourceCode(fragmentShaderSourceCode, fragmentShaderProfile));
            }

            // Is there a valid program?
            if (nullptr != program)
            {
                // Create the pipeline state object (PSO)
                mPipelineState = renderer->createPipelineState(Renderer::PipelineStateBuilder(mRootSignature, program, vertexAttributes));

                // Optimization: Cached data to not bother the renderer API too much
                if (nullptr == mUniformBuffer)
                {
                    mObjectSpaceToClipSpaceMatrixUniformHandle = program->getUniformHandle("ObjectSpaceToClipSpaceMatrix");
                    mObjectSpaceToViewSpaceMatrixUniformHandle = program->getUniformHandle("ObjectSpaceToViewSpaceMatrix");
                }
            }

            // Create mesh instance
            mMeshResourceId = rendererRuntime->getMeshResourceManager().loadMeshResourceByAssetId("Example/Mesh/Character/Imrod");

            {   // Load in the diffuse, emissive, normal and specular texture
                // -> The tangent space normal map is stored with three components, two would be enough to recalculate the third component within the fragment shader
                // -> The specular map could be put into the alpha channel of the diffuse map instead of storing it as an individual texture
                RendererRuntime::TextureResourceManager& textureResourceManager = rendererRuntime->getTextureResourceManager();
                mDiffuseTextureResourceId  = textureResourceManager.loadTextureResourceByAssetId("Example/Texture/Character/ImrodDiffuseMap");
                mNormalTextureResourceId   = textureResourceManager.loadTextureResourceByAssetId("Example/Texture/Character/ImrodEmissiveMap");
                mSpecularTextureResourceId = textureResourceManager.loadTextureResourceByAssetId("Example/Texture/Character/ImrodNormalMap");
                mEmissiveTextureResourceId = textureResourceManager.loadTextureResourceByAssetId("Example/Texture/Character/ImrodSpecularMap");
            }

            {   // Create sampler state
                Renderer::SamplerState samplerStateSettings = Renderer::ISamplerState::getDefaultSamplerState();
                samplerStateSettings.addressU = Renderer::TextureAddressMode::WRAP;
                samplerStateSettings.addressV = Renderer::TextureAddressMode::WRAP;
                mSamplerState = renderer->createSamplerState(samplerStateSettings);
            }
        }
    }
}
Exemplo n.º 5
0
//[-------------------------------------------------------]
//[ Public virtual IApplication methods                   ]
//[-------------------------------------------------------]
void FirstGeometryShader::onInitialization()
{
	// Call the base implementation
	IApplicationRenderer::onInitialization();

	// Get and check the renderer instance
	// -> Geometry shaders supported?
	Renderer::IRendererPtr renderer(getRenderer());
	if (nullptr != renderer && renderer->getCapabilities().maximumNumberOfGsOutputVertices)
	{
		// Create the buffer manager
		mBufferManager = renderer->createBufferManager();

		{ // Create the root signature
			// Setup
			Renderer::RootSignatureBuilder rootSignature;
			rootSignature.initialize(0, nullptr, 0, nullptr, Renderer::RootSignatureFlags::ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT);

			// Create the instance
			mRootSignature = renderer->createRootSignature(rootSignature);
		}

		// Vertex input layout
		const Renderer::VertexAttribute vertexAttributesLayout[] =
		{
			{ // Attribute 0
				// Data destination
				Renderer::VertexAttributeFormat::FLOAT_1,	// vertexAttributeFormat (Renderer::VertexAttributeFormat)
				"Position",									// name[32] (char)
				"POSITION",									// semanticName[32] (char)
				0,											// semanticIndex (uint32_t)
				// Data source
				0,											// inputSlot (uint32_t)
				0,											// alignedByteOffset (uint32_t)
				// Data source, instancing part
				0											// instancesPerElement (uint32_t)
			}
		};
		const Renderer::VertexAttributes vertexAttributes(glm::countof(vertexAttributesLayout), vertexAttributesLayout);

		{ // Create vertex array object (VAO)
			// Create the vertex buffer object (VBO)
			static const float VERTEX_POSITION[] =
			{			// Vertex ID
				42.0f	// 0
			};
			Renderer::IVertexBufferPtr vertexBuffer(mBufferManager->createVertexBuffer(sizeof(VERTEX_POSITION), VERTEX_POSITION, Renderer::BufferUsage::STATIC_DRAW));

			// Create vertex array object (VAO)
			// -> The vertex array object (VAO) keeps a reference to the used vertex buffer object (VBO)
			// -> This means that there's no need to keep an own vertex buffer object (VBO) reference
			// -> When the vertex array object (VAO) is destroyed, it automatically decreases the
			//    reference of the used vertex buffer objects (VBO). If the reference counter of a
			//    vertex buffer object (VBO) reaches zero, it's automatically destroyed.
			const Renderer::VertexArrayVertexBuffer vertexArrayVertexBuffers[] =
			{
				{ // Vertex buffer 0
					vertexBuffer,	// vertexBuffer (Renderer::IVertexBuffer *)
					sizeof(float)	// strideInBytes (uint32_t)
				}
			};
			mVertexArray = mBufferManager->createVertexArray(vertexAttributes, glm::countof(vertexArrayVertexBuffers), vertexArrayVertexBuffers);
		}

		// Create the program: Decide which shader language should be used (for example "GLSL" or "HLSL")
		Renderer::IShaderLanguagePtr shaderLanguage(renderer->getShaderLanguage());
		if (nullptr != shaderLanguage)
		{
			// Create the program
			Renderer::IProgramPtr program;
			{
				// Get the shader source code (outsourced to keep an overview)
				const char *vertexShaderSourceCode = nullptr;
				const char *geometryShaderSourceCode = nullptr;
				const char *fragmentShaderSourceCode = nullptr;
				#include "FirstGeometryShader_GLSL_410.h"
				#include "FirstGeometryShader_HLSL_D3D10_D3D11_D3D12.h"
				#include "FirstGeometryShader_Null.h"

				// Create the program
				program = shaderLanguage->createProgram(
					*mRootSignature,
					vertexAttributes,
					shaderLanguage->createVertexShaderFromSourceCode(vertexAttributes, vertexShaderSourceCode),
					shaderLanguage->createGeometryShaderFromSourceCode(geometryShaderSourceCode, Renderer::GsInputPrimitiveTopology::POINTS, Renderer::GsOutputPrimitiveTopology::TRIANGLE_STRIP, 3),
					shaderLanguage->createFragmentShaderFromSourceCode(fragmentShaderSourceCode));
			}

			// Create the pipeline state object (PSO)
			if (nullptr != program)
			{
				Renderer::PipelineState pipelineState = Renderer::PipelineStateBuilder(mRootSignature, program, vertexAttributes);
				pipelineState.primitiveTopologyType = Renderer::PrimitiveTopologyType::POINT;
				mPipelineState = renderer->createPipelineState(pipelineState);
			}
		}

		// Since we're always submitting the same commands to the renderer, we can fill the command buffer once during initialization and then reuse it multiple times during runtime
		fillCommandBuffer();
	}
}
//[-------------------------------------------------------]
//[ Public methods                                        ]
//[-------------------------------------------------------]
CubeRendererDrawInstanced::CubeRendererDrawInstanced(Renderer::IRenderer &renderer, unsigned int numberOfTextures, unsigned int sceneRadius) :
	mRenderer(&renderer),
	mNumberOfTextures(numberOfTextures),
	mSceneRadius(sceneRadius),
	mMaximumNumberOfInstancesPerBatch(0),
	mNumberOfBatches(0),
	mBatches(nullptr)
{
	// Begin debug event
	RENDERER_BEGIN_DEBUG_EVENT_FUNCTION(&renderer)

	// Check number of textures (limit of this implementation and renderer limit)
	if (mNumberOfTextures > MAXIMUM_NUMBER_OF_TEXTURES)
	{
		mNumberOfTextures = MAXIMUM_NUMBER_OF_TEXTURES;
	}
	if (mNumberOfTextures > mRenderer->getCapabilities().maximumNumberOf2DTextureArraySlices)
	{
		mNumberOfTextures = mRenderer->getCapabilities().maximumNumberOf2DTextureArraySlices;
	}

	// Get the maximum number of instances per batch
	// -> In this application, this depends on the maximum texture buffer size
	// -> /2 -> One instance requires two texels
	mMaximumNumberOfInstancesPerBatch = mRenderer->getCapabilities().maximumTextureBufferSize / 2;

	{ // Create the textures
		static const unsigned int TEXTURE_WIDTH   = 128;
		static const unsigned int TEXTURE_HEIGHT  = 128;
		static const unsigned int NUMBER_OF_BYTES = TEXTURE_WIDTH * TEXTURE_HEIGHT * 4;

		// Allocate memory for the 2D texture array
		unsigned char *data = new unsigned char[NUMBER_OF_BYTES * mNumberOfTextures];

		{ // Fill the texture content
			// TODO(co) Be a little bit more creative while filling the texture data
			unsigned char *dataCurrent = data;
			const float colors[][MAXIMUM_NUMBER_OF_TEXTURES] =
			{
				{ 1.0f, 0.0f, 0.0f},
				{ 0.0f, 0.1f, 0.0f},
				{ 0.0f, 0.0f, 0.1f},
				{ 0.5f, 0.5f, 0.5f},
				{ 1.0f, 1.0f, 1.0f},
				{ 0.1f, 0.2f, 0.2f},
				{ 0.2f, 0.5f, 0.5f},
				{ 0.1f, 0.8f, 0.2f}
			};
			for (unsigned int j = 0; j < mNumberOfTextures; ++j)
			{
				// Random content
				for (unsigned int i = 0; i < TEXTURE_WIDTH * TEXTURE_HEIGHT; ++i)
				{
					*dataCurrent = static_cast<unsigned char>((rand() % 255) * colors[j][0]);
					++dataCurrent;
					*dataCurrent = static_cast<unsigned char>((rand() % 255) * colors[j][1]);
					++dataCurrent;
					*dataCurrent = static_cast<unsigned char>((rand() % 255) * colors[j][2]);
					++dataCurrent;
					*dataCurrent = 255;
					++dataCurrent;
				}
			}
		}

		// Create the texture instance
		// -> By using 2D array textures together with OpenGL/Direct3D 11 instancing we get a handy implementation
		// -> This limits of course the cross platform support, fallback solutions might be a good idea in productive code
		// -> A fallback is not really required in our example situation because we're using draw instanced which already requires a more modern graphics card
		mTexture2DArray = mRenderer->createTexture2DArray(TEXTURE_WIDTH, TEXTURE_HEIGHT, mNumberOfTextures, Renderer::TextureFormat::R8G8B8A8, data, Renderer::TextureFlag::MIPMAPS);

		// Free texture memory
		delete [] data;
	}

	// Create sampler state
	mSamplerState = mRenderer->createSamplerState(Renderer::ISamplerState::getDefaultSamplerState());

	// Decide which shader language should be used (for example "GLSL", "HLSL" or "Cg")
	Renderer::IShaderLanguagePtr shaderLanguage(mRenderer->getShaderLanguage());
	if (nullptr != shaderLanguage)
	{
		// Uniform buffer object (UBO, "constant buffer" in Direct3D terminology) supported?
		// -> If they are there, we really want to use them (performance and ease of use)
		if (mRenderer->getCapabilities().uniformBuffer)
		{
			{ // Create and set constant program uniform buffer at once
				// TODO(co) Uggly fixed hacked in model-view-projection matrix
				// TODO(co) OpenGL matrix, Direct3D has minor differences within the projection matrix we have to compensate
				static const float MVP[] =
				{
					 1.2803299f,	-0.97915620f,	-0.58038759f,	-0.57922798f,
					 0.0f,			 1.9776078f,	-0.57472473f,	-0.573576453f,
					-1.2803299f,	-0.97915620f,	-0.58038759f,	-0.57922798f,
					 0.0f,			 0.0f,			 9.8198195f,	 10.0f
				};
				mUniformBufferStaticVs = shaderLanguage->createUniformBuffer(sizeof(MVP), MVP, Renderer::BufferUsage::STATIC_DRAW);
			}

			// Create dynamic uniform buffers
			mUniformBufferDynamicVs = shaderLanguage->createUniformBuffer(sizeof(float) * 2, nullptr, Renderer::BufferUsage::DYNAMIC_DRAW);
			mUniformBufferDynamicFs = shaderLanguage->createUniformBuffer(sizeof(float) * 3, nullptr, Renderer::BufferUsage::DYNAMIC_DRAW);
		}

		{ // Create the program
			// Get the shader source code (outsourced to keep an overview)
			const char *vertexShaderSourceCode = nullptr;
			const char *fragmentShaderSourceCode = nullptr;
			#include "CubeRendererDrawInstanced_GLSL_140.h"
			#include "CubeRendererDrawInstanced_HLSL_D3D10_D3D11.h"
			#include "CubeRendererDrawInstanced_Null.h"

			// Create the program
			mProgram = shaderLanguage->createProgram(
				shaderLanguage->createVertexShader(vertexShaderSourceCode),
				shaderLanguage->createFragmentShader(fragmentShaderSourceCode));
		}

		// Is there a valid program?
		if (nullptr != mProgram)
		{
			// Create the vertex buffer object (VBO)
			static const float VERTEX_POSITION[] =
			{
				// Front face
				// Position					TexCoord		 Normal				// Vertex ID
				-0.5f, -0.5f,  0.5f,		0.0f, 0.0f,		 0.0f, 0.0f, 1.0f,	// 0
				 0.5f, -0.5f,  0.5f,		1.0f, 0.0f,		 0.0f, 0.0f, 1.0f,	// 1
				 0.5f,  0.5f,  0.5f,		1.0f, 1.0f,		 0.0f, 0.0f, 1.0f,	// 2
				-0.5f,  0.5f,  0.5f,		0.0f, 1.0f,		 0.0f, 0.0f, 1.0f,	// 3
				// Back face
				-0.5f, -0.5f, -0.5f,		1.0f, 0.0f,		 0.0f, 0.0f,-1.0f,	// 4
				-0.5f,  0.5f, -0.5f,		1.0f, 1.0f,		 0.0f, 0.0f,-1.0f,	// 5
				 0.5f,  0.5f, -0.5f,		0.0f, 1.0f,		 0.0f, 0.0f,-1.0f, 	// 6
				 0.5f, -0.5f, -0.5f,		0.0f, 0.0f,		 0.0f, 0.0f,-1.0f,	// 7
				// Top face
				-0.5f,  0.5f, -0.5f,		0.0f, 1.0f,		 0.0f, 1.0f, 0.0f,	// 8
				-0.5f,  0.5f,  0.5f,		0.0f, 0.0f,		 0.0f, 1.0f, 0.0f,	// 9
				 0.5f,  0.5f,  0.5f,		1.0f, 0.0f,		 0.0f, 1.0f, 0.0f,	// 10
				 0.5f,  0.5f, -0.5f,		1.0f, 1.0f,		 0.0f, 1.0f, 0.0f,	// 11
				// Bottom face
				-0.5f, -0.5f, -0.5f,		1.0f, 1.0f,		 0.0f,-1.0f, 0.0f,	// 12
				 0.5f, -0.5f, -0.5f,		0.0f, 1.0f,		 0.0f,-1.0f, 0.0f,	// 13
				 0.5f, -0.5f,  0.5f,		0.0f, 0.0f,		 0.0f,-1.0f, 0.0f,	// 14
				-0.5f, -0.5f,  0.5f,		1.0f, 0.0f,		 0.0f,-1.0f, 0.0f,	// 15
				// Right face
				 0.5f, -0.5f, -0.5f,		1.0f, 0.0f,		 1.0f, 0.0f, 0.0f,	// 16
				 0.5f,  0.5f, -0.5f,		1.0f, 1.0f,		 1.0f, 0.0f, 0.0f,	// 17
				 0.5f,  0.5f,  0.5f,		0.0f, 1.0f,		 1.0f, 0.0f, 0.0f,	// 18
				 0.5f, -0.5f,  0.5f,		0.0f, 0.0f,		 1.0f, 0.0f, 0.0f,	// 19
				// Left face
				-0.5f, -0.5f, -0.5f,		0.0f, 0.0f,		-1.0f, 0.0f, 0.0f,	// 20
				-0.5f, -0.5f,  0.5f,		1.0f, 0.0f,		-1.0f, 0.0f, 0.0f,	// 21
				-0.5f,  0.5f,  0.5f,		1.0f, 1.0f,		-1.0f, 0.0f, 0.0f,	// 22
				-0.5f,  0.5f, -0.5f,		0.0f, 1.0f,		-1.0f, 0.0f, 0.0f	// 23
			};
			Renderer::IVertexBufferPtr vertexBuffer(mRenderer->createVertexBuffer(sizeof(VERTEX_POSITION), VERTEX_POSITION, Renderer::BufferUsage::STATIC_DRAW));

			// Create the index buffer object (IBO)
			static const unsigned short INDICES[] =
			{
				// Front face	Triangle ID
				 1,  0,  2,		// 0
				 3,  2,  0,		// 1
				// Back face
				 6,  5,  4,		// 2
				 4,  7,  6,		// 3
				// Top face
				 9,  8, 10,		// 4
				11, 10,  8,		// 5
				// Bottom face
				13, 12, 14,		// 6
				15, 14, 12,		// 7
				// Right face
				17, 16, 18,		// 8
				19, 18, 16,		// 9
				// Left face
				21, 20, 22,		// 10
				23, 22, 20		// 11
			};
			Renderer::IIndexBuffer *indexBuffer = mRenderer->createIndexBuffer(sizeof(INDICES), Renderer::IndexBufferFormat::UNSIGNED_SHORT, INDICES, Renderer::BufferUsage::STATIC_DRAW);

			// Create vertex array object (VAO)
			// -> The vertex array object (VAO) keeps a reference to the used vertex buffer object (VBO)
			// -> This means that there's no need to keep an own vertex buffer object (VBO) reference
			// -> When the vertex array object (VAO) is destroyed, it automatically decreases the
			//    reference of the used vertex buffer objects (VBO). If the reference counter of a
			//    vertex buffer object (VBO) reaches zero, it's automatically destroyed.
			const Renderer::VertexArrayAttribute vertexArray[] =
			{
				{ // Attribute 0
					// Data destination
					Renderer::VertexArrayFormat::FLOAT_3,	// vertexArrayFormat (Renderer::VertexArrayFormat::Enum)
					"Position",								// name[64] (char)
					"POSITION",								// semantic[64] (char)
					0,										// semanticIndex (unsigned int)
					// Data source
					vertexBuffer,							// vertexBuffer (Renderer::IVertexBuffer *)
					0,										// offset (unsigned int)
					sizeof(float) * (3 + 2 + 3),			// stride (unsigned int)
					// Data source, instancing part
					0										// instancesPerElement (unsigned int)
				},
				{ // Attribute 1
					// Data destination
					Renderer::VertexArrayFormat::FLOAT_2,	// vertexArrayFormat (Renderer::VertexArrayFormat::Enum)
					"TexCoord",								// name[64] (char)
					"TEXCOORD",								// semantic[64] (char)
					0,										// semanticIndex (unsigned int)
					// Data source
					vertexBuffer,							// vertexBuffer (Renderer::IVertexBuffer *)
					sizeof(float) * 3,						// offset (unsigned int)
					sizeof(float) * (3 + 2 + 3),			// stride (unsigned int)
					// Data source, instancing part
					0										// instancesPerElement (unsigned int)
				},
				{ // Attribute 2
					// Data destination
					Renderer::VertexArrayFormat::FLOAT_3,	// vertexArrayFormat (Renderer::VertexArrayFormat::Enum)
					"Normal",								// name[64] (char)
					"NORMAL",								// semantic[64] (char)
					0,										// semanticIndex (unsigned int)
					// Data source
					vertexBuffer,							// pertexBuffer (Renderer::IVertexBuffer *)
					sizeof(float) * (3 + 2),				// offset (unsigned int)
					sizeof(float) * (3 + 2 + 3),			// stride (unsigned int)
					// Data source, instancing part
					0										// instancesPerElement (unsigned int)
				}
			};
			mVertexArray = mProgram->createVertexArray(sizeof(vertexArray) / sizeof(Renderer::VertexArrayAttribute), vertexArray, indexBuffer);
		}
	}

	// End debug event
	RENDERER_END_DEBUG_EVENT(&renderer)
}
//[-------------------------------------------------------]
//[ Public virtual IApplication methods                   ]
//[-------------------------------------------------------]
void IcosahedronTessellation::onInitialization()
{
	// Call the base implementation
	IApplicationRenderer::onInitialization();

	// Get and check the renderer instance
	// -> Uniform buffer object (UBO, "constant buffer" in Direct3D terminology) supported?
	// -> Geometry shaders supported?
	// -> Tessellation control and tessellation evaluation shaders supported?
	Renderer::IRendererPtr renderer(getRenderer());
	if (nullptr != renderer && renderer->getCapabilities().uniformBuffer && renderer->getCapabilities().maximumNumberOfGsOutputVertices > 0 && renderer->getCapabilities().maximumNumberOfPatchVertices > 0)
	{
		// Begin debug event
		RENDERER_BEGIN_DEBUG_EVENT_FUNCTION(renderer)

		// Decide which shader language should be used (for example "GLSL", "HLSL" or "Cg")
		Renderer::IShaderLanguagePtr shaderLanguage(renderer->getShaderLanguage());
		if (nullptr != shaderLanguage)
		{
			// Create uniform buffers and fill the static buffers at once
			mUniformBufferDynamicTcs = shaderLanguage->createUniformBuffer(sizeof(float) * 2, nullptr, Renderer::BufferUsage::DYNAMIC_DRAW);
			{	// "ObjectSpaceToClipSpaceMatrix"
				// TODO(co) Cleanup, correct aspect ratio
				glm::mat4 View = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, -3.0f));
				glm::mat4 Model = glm::scale(glm::mat4(1.0f), glm::vec3(1.0f));
				glm::mat4 Projection = glm::perspective(45.0f, 4.0f / 3.0f, 0.001f, 1000.0f);
				glm::mat4 MVP = Projection * View; 
//				glm::mat4 MVP = Projection * View * Model; 
				mUniformBufferStaticTes = shaderLanguage->createUniformBuffer(sizeof(float) * 4 * 4, glm::value_ptr(MVP), Renderer::BufferUsage::STATIC_DRAW);
				{	// "NormalMatrix"

					View = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, 0.0f));
					Model = glm::scale(glm::mat4(1.0f), glm::vec3(1.0f));
					Projection = glm::perspective(45.0f, 4.0f / 3.0f, 0.001f, 1000.0f);
					MVP = Projection * View; 
					glm::mat3 nMVP(MVP);
					glm::mat4 tMVP(nMVP);
					mUniformBufferStaticGs = shaderLanguage->createUniformBuffer(sizeof(float) * 4 * 4, glm::value_ptr(tMVP), Renderer::BufferUsage::STATIC_DRAW);
				}
			}
			{ // Light and material
				static const float LIGHT_AND_MATERIAL[] =
				{
					0.25f, 0.25f, 1.0f, 1.0,	// "LightPosition"
					 0.0f, 0.75f, 0.75f,1.0, 	// "DiffuseMaterial"
					0.04f, 0.04f, 0.04f,1.0,	// "AmbientMaterial"
				};
				mUniformBufferStaticFs = shaderLanguage->createUniformBuffer(sizeof(LIGHT_AND_MATERIAL), LIGHT_AND_MATERIAL, Renderer::BufferUsage::STATIC_DRAW);
			}

			{ // Create the program
				// Get the shader source code (outsourced to keep an overview)
				const char *vertexShaderSourceCode = nullptr;
				const char *tessellationControlShaderSourceCode = nullptr;
				const char *tessellationEvaluationShaderSourceCode = nullptr;
				const char *geometryShaderSourceCode = nullptr;
				const char *fragmentShaderSourceCode = nullptr;
				#include "IcosahedronTessellation_GLSL_400.h"
				#include "IcosahedronTessellation_HLSL_D3D11.h"
				#include "IcosahedronTessellation_Null.h"

				// Create the program
				mProgram = shaderLanguage->createProgram(
					shaderLanguage->createVertexShader(vertexShaderSourceCode),
					shaderLanguage->createTessellationControlShader(tessellationControlShaderSourceCode),
					shaderLanguage->createTessellationEvaluationShader(tessellationEvaluationShaderSourceCode),
					shaderLanguage->createGeometryShader(geometryShaderSourceCode, Renderer::GsInputPrimitiveTopology::TRIANGLES, Renderer::GsOutputPrimitiveTopology::TRIANGLE_STRIP, 3),
					shaderLanguage->createFragmentShader(fragmentShaderSourceCode));
			}

			// Is there a valid program?
			if (nullptr != mProgram)
			{
				// Create the vertex buffer object (VBO)
				// -> Geometry is from: http://prideout.net/blog/?p=48 (Philip Rideout, "The Little Grasshopper - Graphics Programming Tips")
				static const float VERTEX_POSITION[] =
				{								// Vertex ID
					 0.000f,  0.000f,  1.000f,	// 0
					 0.894f,  0.000f,  0.447f,	// 1
					 0.276f,  0.851f,  0.447f,	// 2
					-0.724f,  0.526f,  0.447f,	// 3
					-0.724f, -0.526f,  0.447f,	// 4
					 0.276f, -0.851f,  0.447f,	// 5
					 0.724f,  0.526f, -0.447f,	// 6
					-0.276f,  0.851f, -0.447f,	// 7
					-0.894f,  0.000f, -0.447f,	// 8
					-0.276f, -0.851f, -0.447f,	// 9
					 0.724f, -0.526f, -0.447f,	// 10
					 0.000f,  0.000f, -1.000f	// 11
				};
				Renderer::IVertexBufferPtr vertexBuffer(renderer->createVertexBuffer(sizeof(VERTEX_POSITION), VERTEX_POSITION, Renderer::BufferUsage::STATIC_DRAW));

				// Create the index buffer object (IBO)
				// -> Geometry is from: http://prideout.net/blog/?p=48 (Philip Rideout, "The Little Grasshopper - Graphics Programming Tips")
				static const unsigned short INDICES[] =
				{				// Triangle ID
					 2,  1,  0,	// 0
					 3,  2,  0,	// 1
					 4,  3,  0,	// 2
					 5,  4,  0,	// 3
					 1,  5,  0,	// 4
					11,  6,  7,	// 5
					11,  7,  8,	// 6
					11,  8,  9,	// 7
					11,  9, 10,	// 8
					11, 10,  6,	// 9
					 1,  2,  6,	// 10
					 2,  3,  7,	// 11
					 3,  4,  8,	// 12
					 4,  5,  9,	// 13
					 5,  1, 10,	// 14
					 2,  7,  6,	// 15
					 3,  8,  7,	// 16
					 4,  9,  8,	// 17
					 5, 10,  9,	// 18
					 1,  6, 10	// 19
				};
				Renderer::IIndexBuffer *indexBuffer = renderer->createIndexBuffer(sizeof(INDICES), Renderer::IndexBufferFormat::UNSIGNED_SHORT, INDICES, Renderer::BufferUsage::STATIC_DRAW);

				// Create vertex array object (VAO)
				// -> The vertex array object (VAO) keeps a reference to the used vertex buffer object (VBO)
				// -> This means that there's no need to keep an own vertex buffer object (VBO) reference
				// -> When the vertex array object (VAO) is destroyed, it automatically decreases the
				//    reference of the used vertex buffer objects (VBO). If the reference counter of a
				//    vertex buffer object (VBO) reaches zero, it's automatically destroyed.
				const Renderer::VertexArrayAttribute vertexArray[] =
				{
					{ // Attribute 0
						// Data destination
						Renderer::VertexArrayFormat::FLOAT_3,	// vertexArrayFormat (Renderer::VertexArrayFormat::Enum)
						"Position",								// name[64] (char)
						"POSITION",								// semantic[64] (char)
						0,										// semanticIndex (unsigned int)
						// Data source
						vertexBuffer,							// vertexBuffer (Renderer::IVertexBuffer *)
						0,										// offset (unsigned int)
						sizeof(float) * 3,						// stride (unsigned int)
						// Data source, instancing part
						0										// instancesPerElement (unsigned int)
					}
				};
				mVertexArray = mProgram->createVertexArray(sizeof(vertexArray) / sizeof(Renderer::VertexArrayAttribute), vertexArray, indexBuffer);
			}
		}

		// End debug event
		RENDERER_END_DEBUG_EVENT(renderer)
	}