OSDN Git Service

Boost.MSMでメニュー部分を実装
[shooting3/shootinggame.git] / ShootingGame / BasicSprites.cpp
index 76701de..71dd425 100644 (file)
 #endif
 
 using namespace Microsoft::WRL;
-using namespace BasicSprites;
+namespace BasicSprites
+{
+
 
-SpriteBatch::SpriteBatch() :
-    m_capacity(0)
+struct ReplicationVertex
 {
-}
+    float4 pos;
+    float2 tex;
+    unsigned int color;
+};
 
-void SpriteBatch::Initialize(
-    _In_ ID3D11Device1* d3dDevice,
-    _In_ int capacity = 1024
-    )
+struct InstancingVertex
 {
-    m_d3dDevice = d3dDevice;
-    m_d3dDevice->GetImmediateContext1(&m_d3dContext);
-    m_capacity = capacity;
+    float4 pos;
+    float2 tex;
+};
 
-    // Determine the technique that will be used to render the sprites.
-    auto featureLevel = m_d3dDevice->GetFeatureLevel();
+struct InstanceData
+{
+    float4 origin;
+    float2 offset;
+    float rotation;
+       float4 textureCellInfo;
+       unsigned int color;
+};
 
-    if (featureLevel >= D3D_FEATURE_LEVEL_10_0)
-    {
-        // On DirectX 10+ devices, the Geometry Shader allows the sprite vertices to be 
-        // generated on the GPU, significantly reducing memory bandwidth requirements.
-        m_technique = RenderTechnique::GeometryShader;
-    }
-    else if (featureLevel >= D3D_FEATURE_LEVEL_9_3)
-    {
-        // On DirectX 9.3+ devices, instancing allows shared sprite geometry with unique
-        // per-sprite instance parameters, eliminating redundant data transfer.
-        m_technique = RenderTechnique::Instancing;
-    }
-    else
-    {
-        // On devices that do not support Instancing, sprite vertex data must be replicated
-        // in order to achieve the desired effect.
-        m_technique = RenderTechnique::Replication;
+struct TextureMapElement
+{
+    Microsoft::WRL::ComPtr<ID3D11ShaderResourceView> srv;
+    float2 size;
+       float2 textureCellSize;
+};
 
-        if (capacity > static_cast<int>(Parameters::MaximumCapacityCompatible))
-        {
-            // The index buffer format for feature-level 9.1 devices may only be 16 bits.
-            // With 4 vertices per sprite, this allows a maximum of (1 << 16) / 4 sprites.
-            throw ref new Platform::InvalidArgumentException();
-        }
-    }
+struct SpritePrepInfo
+{
+       ReplicationVertex replicationVertex[4];
+       InstanceData instanceData;
+    ID3D11ShaderResourceView* textureView;
+    ID3D11BlendState1* blendState;
+       float2 textureSize;
+       float2 textureCellSize;
+       float2 textureCellOffset;
+};
+
+struct SpriteRunInfo
+{
+    ID3D11ShaderResourceView* textureView;
+    ID3D11BlendState1* blendState;
+//     float4 textureCellInfo;
+    unsigned int numSprites;
+};
 
-    // Create the texture sampler.
-
-    D3D11_SAMPLER_DESC samplerDesc;
-    ZeroMemory(&samplerDesc, sizeof(samplerDesc));
-//    samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
-       samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
-
-    samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
-    samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
-    samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
-    samplerDesc.MipLODBias = 0.0f;
-    samplerDesc.MaxAnisotropy = 0;
-    samplerDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;
-    samplerDesc.BorderColor[0] = 0.0f;
-    samplerDesc.BorderColor[1] = 0.0f;
-    samplerDesc.BorderColor[2] = 0.0f;
-    samplerDesc.BorderColor[3] = 0.0f;
-    samplerDesc.MinLOD = 0.0f;
-    samplerDesc.MaxLOD = FLT_MAX;
-
-    DX::ThrowIfFailed(
-        m_d3dDevice->CreateSamplerState(
-            &samplerDesc,
-            &m_linearSampler
-            )
-        );
+struct SpriteDrawerBase : public SpriteDrawer
+{
+       SpriteDrawerBase(){}
+
+       virtual void Initialize(
+               ID3D11Device1* d3dDevice,
+               int capacity
+               )
+       {
+               m_d3dDevice = d3dDevice;
+               m_d3dDevice->GetImmediateContext1(&m_d3dContext);
+               m_capacity = capacity;
+
+               // Create the texture sampler.
+
+               D3D11_SAMPLER_DESC samplerDesc;
+               ZeroMemory(&samplerDesc, sizeof(samplerDesc));
+               //    samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
+               samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
+
+               samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
+               samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
+               samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
+               samplerDesc.MipLODBias = 0.0f;
+               samplerDesc.MaxAnisotropy = 0;
+               samplerDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;
+               samplerDesc.BorderColor[0] = 0.0f;
+               samplerDesc.BorderColor[1] = 0.0f;
+               samplerDesc.BorderColor[2] = 0.0f;
+               samplerDesc.BorderColor[3] = 0.0f;
+               samplerDesc.MinLOD = 0.0f;
+               samplerDesc.MaxLOD = FLT_MAX;
+
+               DX::ThrowIfFailed(
+                       m_d3dDevice->CreateSamplerState(
+                       &samplerDesc,
+                       &m_linearSampler
+                       )
+                       );
+
+               // Create the blend states.
+
+               D3D11_BLEND_DESC1 blendDesc;
+               ZeroMemory(&blendDesc, sizeof(blendDesc));
+               blendDesc.AlphaToCoverageEnable = false;
+               blendDesc.IndependentBlendEnable = false;
+               blendDesc.RenderTarget[0].BlendEnable = true;
+               blendDesc.RenderTarget[0].LogicOpEnable = false;
+               blendDesc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
+               blendDesc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
+               blendDesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
+               blendDesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
+               blendDesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ONE;
+               blendDesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
+               blendDesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
+
+               DX::ThrowIfFailed(
+                       m_d3dDevice->CreateBlendState1(
+                       &blendDesc,
+                       &m_blendStateAlpha
+                       )
+                       );
+
+               blendDesc.RenderTarget[0].DestBlend = D3D11_BLEND_ONE;
+
+               DX::ThrowIfFailed(
+                       m_d3dDevice->CreateBlendState1(
+                       &blendDesc,
+                       &m_blendStateAdditive
+                       )
+                       );
+
+               DX::ThrowIfFailed(
+                       m_d3dDevice->CreateBuffer(
+                       &CD3D11_BUFFER_DESC(
+                       16, // Constant buffer sizes must be a multiple of 16 bytes.  16 is sufficient for the required float2 data.
+                       D3D11_BIND_CONSTANT_BUFFER,
+                       D3D11_USAGE_DYNAMIC,
+                       D3D11_CPU_ACCESS_WRITE
+                       ),
+                       nullptr,
+                       &textureOffset_
+                       )
+                       );
+
+
+       };
+
+       virtual void AddTexture(
+               ID3D11Texture2D* texture,float2 textureCellSize
+               )
+       {
+               TextureMapElement mapElement;
+               DX::ThrowIfFailed(
+                       m_d3dDevice->CreateShaderResourceView(
+                       texture,
+                       &CD3D11_SHADER_RESOURCE_VIEW_DESC(
+                       texture,
+                       D3D11_SRV_DIMENSION_TEXTURE2D
+                       ),
+                       &mapElement.srv
+                       )
+                       );
+
+               D3D11_TEXTURE2D_DESC textureDesc;
+               texture->GetDesc(&textureDesc);
+               mapElement.size = float2(
+                       static_cast<float>(textureDesc.Width),
+                       static_cast<float>(textureDesc.Height)
+                       );
+               if(textureCellSize.x == 0 && textureCellSize.y == 0)
+               {
+                       mapElement.textureCellSize = mapElement.size;
+               } else {
+                       mapElement.textureCellSize = textureCellSize;
+               }
+               m_textureMap[texture] = mapElement;
+
+       }
+
+       virtual void RemoveTexture(
+               ID3D11Texture2D* texture
+               )
+       {
+               m_textureMap.erase(texture);
+       }
+
+       virtual void Begin()
+       {
+               // Reset internal sprite data.
+
+               m_numSpritesDrawn = 0;
+               m_spriteRuns.clear();
+               spritePrepInfos_.clear();
+               // Get the current render target dimensions and logical DPI.
+
+               ComPtr<ID3D11RenderTargetView> renderTargetView;
+               m_d3dContext->OMGetRenderTargets(
+                       1,
+                       &renderTargetView,
+                       nullptr
+                       );
+
+               ComPtr<ID3D11Resource> renderTarget;
+               renderTargetView->GetResource(&renderTarget);
+
+               ComPtr<ID3D11Texture2D> renderTargetTexture;
+               renderTarget.As(&renderTargetTexture);
+
+               D3D11_TEXTURE2D_DESC renderTargetTextureDesc;
+               renderTargetTexture->GetDesc(&renderTargetTextureDesc);
+
+               m_renderTargetSize = float2(
+                       static_cast<float>(renderTargetTextureDesc.Width),
+                       static_cast<float>(renderTargetTextureDesc.Height)
+                       );
+
+               m_dpi = Windows::Graphics::Display::DisplayProperties::LogicalDpi;
+       }
+
+       virtual void End(){};
+
+       virtual void Draw(
+               ID3D11Texture2D* texture,
+                float4 position,
+                PositionUnits positionUnits,
+                float2 size,
+                SizeUnits sizeUnits,
+                float4 color,
+                float rotation,
+                BlendMode blendMode,
+                float2 textureCellOffset
+               )
+       {
+               // Fail if drawing this sprite would exceed the capacity of the sprite batch.
+               if (m_numSpritesDrawn >= m_capacity)
+               {
+                       throw ref new Platform::OutOfBoundsException();
+               }
 
-    // Create the blend states.
-
-    D3D11_BLEND_DESC1 blendDesc;
-    ZeroMemory(&blendDesc, sizeof(blendDesc));
-    blendDesc.AlphaToCoverageEnable = false;
-    blendDesc.IndependentBlendEnable = false;
-    blendDesc.RenderTarget[0].BlendEnable = true;
-    blendDesc.RenderTarget[0].LogicOpEnable = false;
-    blendDesc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
-    blendDesc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
-    blendDesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
-    blendDesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
-    blendDesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ONE;
-    blendDesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
-    blendDesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
-
-    DX::ThrowIfFailed(
-        m_d3dDevice->CreateBlendState1(
-            &blendDesc,
-            &m_blendStateAlpha
-            )
-        );
+               SpritePrepInfo info;
+               InitSpritePrepInfo(info,texture,position,positionUnits,size,sizeUnits,color,rotation,blendMode,textureCellOffset);
+               AddSpritePrepInfo(info);
+
+       };
+protected:
+       unsigned int MakeUnorm(float4 color)
+       {
+               unsigned int r = max(0, min(255, static_cast<unsigned int>(color.r * 255.0f)));
+               unsigned int g = max(0, min(255, static_cast<unsigned int>(color.g * 255.0f)));
+               unsigned int b = max(0, min(255, static_cast<unsigned int>(color.b * 255.0f)));
+               unsigned int a = max(0, min(255, static_cast<unsigned int>(color.a * 255.0f)));
+               return
+                       (a << 24) |
+                       (b << 16) |
+                       (g << 8) |
+                       r;
+       }
+
+       float4 StandardOrigin(float4 position, PositionUnits positionUnits, float2 renderTargetSize, float dpi)
+       {
+               float4 origin;
+
+               origin.z = position.z;
+               origin.w = position.w;
+
+               if (positionUnits == PositionUnits::Pixels)
+               {
+                       origin.x = (position.x / renderTargetSize.x) * 2.0f - 1.0f;
+                       origin.y = 1.0f - (position.y / renderTargetSize.y) * 2.0f;
+               }
+               else if (positionUnits == PositionUnits::DIPs)
+               {
+                       origin.x = ((position.x * dpi / 96.0f) / renderTargetSize.x) * 2.0f - 1.0f;
+                       origin.y = 1.0f - ((position.y * dpi / 96.0f) / renderTargetSize.y) * 2.0f;
+               }
+               else if (positionUnits == PositionUnits::Normalized)
+               {
+                       origin.x = position.x * 2.0f - 1.0f;
+                       origin.y = 1.0f - position.y * 2.0f;
+               }
+               else if (positionUnits == PositionUnits::UniformWidth)
+               {
+                       origin.x = position.x * 2.0f - 1.0f;
+                       origin.y = 1.0f - position.y * (renderTargetSize.x / renderTargetSize.y) * 2.0f;
+               }
+               else if (positionUnits == PositionUnits::UniformHeight)
+               {
+                       origin.x = position.x * (renderTargetSize.y / renderTargetSize.x) * 2.0f - 1.0f;
+                       origin.y = 1.0f - position.y * 2.0f;
+               }
+               return origin;
+
+       }
+
+       float2 StandardOffset(float2 size, SizeUnits sizeUnits, float2 spriteSize, float dpi)
+       {
+               float2 offset;
+               if (sizeUnits == SizeUnits::Pixels)
+               {
+                       offset = size;
+               }
+               else if (sizeUnits == SizeUnits::DIPs)
+               {
+                       offset = size * dpi / 96.0f;
+               }
+               else if (sizeUnits == SizeUnits::Normalized)
+               {
+                       offset = spriteSize * size;
+               }
+               return offset;
+
+       }
+
+       void InitSpritePrepInfo(
+               SpritePrepInfo& info,
+               ID3D11Texture2D* texture,
+               float4 position,
+               PositionUnits positionUnits,
+               float2 size,
+               SizeUnits sizeUnits,
+               float4 color,
+               float rotation,
+               BlendMode blendMode,
+               float2 textureCellOffset
+               )
+       {
+               InitSpritePrepInfo(info,texture,blendMode,textureCellOffset);
+
+               // Add the sprite to the buffer.
+
+               float4 origin = StandardOrigin(position, positionUnits, m_renderTargetSize, m_dpi);
+               float2 offset = StandardOffset(size, sizeUnits, info.textureSize, m_dpi);
 
-    blendDesc.RenderTarget[0].DestBlend = D3D11_BLEND_ONE;
+               info.instanceData.origin = origin;
+               info.instanceData.offset = offset;
+               info.instanceData.rotation = rotation;
+               info.instanceData.color = MakeUnorm(color);
+       }
+
+       void InitSpritePrepInfo
+               (
+               SpritePrepInfo& info,
+               ID3D11Texture2D* texture,
+               BlendMode blendMode,
+               float2 textureCellOffset
+               )
+       {
+               // Retrieve information about the sprite.
+               TextureMapElement element = m_textureMap[texture];
+               ID3D11ShaderResourceView* textureView = element.srv.Get();
+               float2 textureSize = element.size;
+               ID3D11BlendState1* blendState = blendMode == BlendMode::Additive ? m_blendStateAdditive.Get() : m_blendStateAlpha.Get();
+
+               // Fail if the texture has not previously been added to the sprite batch.
+               if (textureView == nullptr)
+               {
+                       throw ref new Platform::NullReferenceException();
+               }
 
-    DX::ThrowIfFailed(
-        m_d3dDevice->CreateBlendState1(
-            &blendDesc,
-            &m_blendStateAdditive
-            )
+               info.textureView = textureView;
+               info.blendState  = blendState;
+               info.textureSize = textureSize;
+               info.textureCellSize = element.textureCellSize;
+               info.textureCellOffset = textureCellOffset;
+       }
+
+       void AddSpritePrepInfo(SpritePrepInfo& info)
+       {
+               if(spritePrepInfos_.empty()){
+                       spritePrepInfos_.push_back(info);
+               } else {
+                       std::list<SpritePrepInfo>::const_iterator it = spritePrepInfos_.cbegin();
+                       while(it != spritePrepInfos_.end())
+                       {
+                               if(it->instanceData.origin.z > info.instanceData.origin.z)
+                               {
+                                       ++it;
+                               } else {
+                                       if(it->instanceData.origin.z == info.instanceData.origin.z)
+                                       {
+                                               if(it->textureView == info.textureView && it->blendState == info.blendState)
+                                               {
+                                                       spritePrepInfos_.insert(it,info);
+                                                       break;
+                                               } else {
+                                                       ++it;
+                                               }
+                                       } else {
+                                               spritePrepInfos_.insert(it,info);
+                                               break;
+                                       }
+                               }
+                       }
+
+                       if(it == spritePrepInfos_.end())
+                       {
+                               spritePrepInfos_.push_back(info);
+                       }
+               }
+               m_numSpritesDrawn++;
+       }
+
+       void AddSpriteRun(std::unique_ptr<InstanceData[]>& instanceData)
+       {
+                               // Save the final sprite run info.
+               int index = 0;
+               int spriteInRun= 0;
+               std::for_each(spritePrepInfos_.begin(),spritePrepInfos_.end(),
+                       [&](SpritePrepInfo& info)
+               {
+                       if(index != 0
+                               && (m_spriteRuns.end() - 1)->textureView == info.textureView && (m_spriteRuns.end() - 1)->blendState == info.blendState)
+                       {
+                               ++spriteInRun;
+                               (m_spriteRuns.end() - 1)->numSprites = spriteInRun;
+                       } else {
+                               spriteInRun = 1;
+                               SpriteRunInfo runInfo;
+                               runInfo.textureView = info.textureView;
+                               runInfo.blendState = info.blendState;
+                               runInfo.numSprites = spriteInRun;
+                               m_spriteRuns.push_back(runInfo);
+                       }
+
+                       info.instanceData.textureCellInfo.x = info.textureCellOffset.x / info.textureSize.x;
+                       info.instanceData.textureCellInfo.y = info.textureCellOffset.y / info.textureSize.y;
+                       info.instanceData.textureCellInfo.z = info.textureCellSize.x / info.textureSize.x;
+                       info.instanceData.textureCellInfo.w = info.textureCellSize.y / info.textureSize.y;
+
+                       instanceData[index] = info.instanceData;
+                       ++index;
+               }
+               );
+
+       }
+
+       Microsoft::WRL::ComPtr<ID3D11Device1> m_d3dDevice;
+       Microsoft::WRL::ComPtr<ID3D11DeviceContext1> m_d3dContext;
+       Microsoft::WRL::ComPtr<ID3D11Buffer> m_indexBuffer;
+       Microsoft::WRL::ComPtr<ID3D11Buffer> m_vertexBuffer;
+       Microsoft::WRL::ComPtr<ID3D11BlendState1> m_blendStateAlpha;
+       Microsoft::WRL::ComPtr<ID3D11BlendState1> m_blendStateAdditive;
+       Microsoft::WRL::ComPtr<ID3D11InputLayout> m_inputLayout;
+       Microsoft::WRL::ComPtr<ID3D11VertexShader> m_vertexShader;
+       Microsoft::WRL::ComPtr<ID3D11GeometryShader> m_geometryShader;
+       Microsoft::WRL::ComPtr<ID3D11PixelShader> m_pixelShader;
+       Microsoft::WRL::ComPtr<ID3D11SamplerState> m_linearSampler;
+       Microsoft::WRL::ComPtr<ID3D11Buffer> m_renderTargetInfoCbuffer;
+       Microsoft::WRL::ComPtr<ID3D11Buffer> textureOffset_;
+
+       std::map<ID3D11Texture2D*, TextureMapElement> m_textureMap;
+       std::vector<SpriteRunInfo> m_spriteRuns;
+       std::list<SpritePrepInfo> spritePrepInfos_;
+
+       ID3D11ShaderResourceView* m_currentTextureView;
+       ID3D11BlendState1* m_currentBlendState;
+       float2 m_renderTargetSize;
+       int m_capacity;
+//     int m_spritesInRun;
+       int m_numSpritesDrawn;
+       float m_dpi;
+};
+
+struct GeometryShaderSpriteDrawer : public SpriteDrawerBase
+{
+public:
+       GeometryShaderSpriteDrawer(){};
+       virtual void Initialize(
+                ID3D11Device1* d3dDevice,
+                int capacity
+               ) 
+       {
+               SpriteDrawerBase::Initialize(d3dDevice,capacity);
+
+               BasicLoader^ loader = ref new BasicLoader(m_d3dDevice.Get());
+               D3D11_INPUT_ELEMENT_DESC layoutDesc[] = 
+               {
+                       { "TRANSFORM", 0, DXGI_FORMAT_R32G32B32A32_FLOAT,   0, 0,  D3D11_INPUT_PER_INSTANCE_DATA, 1 },
+                       { "TRANSFORM", 1, DXGI_FORMAT_R32G32_FLOAT,   0, 16,  D3D11_INPUT_PER_INSTANCE_DATA, 1 },
+                       { "TRANSFORM", 2, DXGI_FORMAT_R32_FLOAT,      0, 24, D3D11_INPUT_PER_INSTANCE_DATA, 1 },
+                       { "TRANSFORM", 3, DXGI_FORMAT_R32G32B32A32_FLOAT,   0, 28,  D3D11_INPUT_PER_INSTANCE_DATA, 1 },
+                       { "COLOR",     0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, 44, D3D11_INPUT_PER_INSTANCE_DATA, 1 },
+               };
+               loader->LoadShader(
+                       "BasicSprites.GeometryShader.vs.cso",
+                       layoutDesc,
+                       ARRAYSIZE(layoutDesc),
+                       &m_vertexShader,
+                       &m_inputLayout
+                       );
+               loader->LoadShader(
+                       "BasicSprites.GeometryShader.gs.cso",
+                       &m_geometryShader
+                       );
+
+               loader->LoadShader(
+        "BasicSprites.ps.cso",
+        &m_pixelShader
         );
 
-    BasicLoader^ loader = ref new BasicLoader(m_d3dDevice.Get());
+               // Create the instance data buffer.
+
+               DX::ThrowIfFailed(
+                       m_d3dDevice->CreateBuffer(
+                       &CD3D11_BUFFER_DESC(
+                       m_capacity * sizeof(InstanceData),
+                       D3D11_BIND_VERTEX_BUFFER,
+                       D3D11_USAGE_DEFAULT,
+                       0
+                       ),
+                       nullptr,
+                       &m_instanceDataBuffer
+                       )
+                       );
+
+               m_instanceData.reset(new InstanceData[m_capacity]);
+
+               // Both the Geometry Shader and Instancing techniques scale geometry in shader code.
+               // As a result, they require information about the render target size.
+               DX::ThrowIfFailed(
+                       m_d3dDevice->CreateBuffer(
+                       &CD3D11_BUFFER_DESC(
+                       16, // Constant buffer sizes must be a multiple of 16 bytes.  16 is sufficient for the required float2 data.
+                       D3D11_BIND_CONSTANT_BUFFER,
+                       D3D11_USAGE_DYNAMIC,
+                       D3D11_CPU_ACCESS_WRITE
+                       ),
+                       nullptr,
+                       &m_renderTargetInfoCbuffer
+                       )
+                       );
+
+       }
+
+
+       virtual void End() 
+       {
+               // If no sprites were drawn, do nothing.
+               if (m_numSpritesDrawn == 0)
+               {
+                       return;
+               }
 
-    if (m_technique == RenderTechnique::GeometryShader)
-    {
-        D3D11_INPUT_ELEMENT_DESC layoutDesc[] = 
-        {
-            { "TRANSFORM", 0, DXGI_FORMAT_R32G32B32A32_FLOAT,   0, 0,  D3D11_INPUT_PER_INSTANCE_DATA, 1 },
-            { "TRANSFORM", 1, DXGI_FORMAT_R32G32_FLOAT,   0, 16,  D3D11_INPUT_PER_INSTANCE_DATA, 1 },
-            { "TRANSFORM", 2, DXGI_FORMAT_R32_FLOAT,      0, 24, D3D11_INPUT_PER_INSTANCE_DATA, 1 },
-            { "COLOR",     0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, 28, D3D11_INPUT_PER_INSTANCE_DATA, 1 }
-        };
-        loader->LoadShader(
-            "BasicSprites.GeometryShader.vs.cso",
-            layoutDesc,
-            ARRAYSIZE(layoutDesc),
-            &m_vertexShader,
-            &m_inputLayout
-            );
-        loader->LoadShader(
-            "BasicSprites.GeometryShader.gs.cso",
-            &m_geometryShader
-            );
-    }
-    else if (m_technique == RenderTechnique::Instancing)
-    {
+               AddSpriteRun(m_instanceData);
+
+               // Update the buffer data.
+
+               m_d3dContext->UpdateSubresource(
+                       m_instanceDataBuffer.Get(),
+                       0,
+                       &CD3D11_BOX(0, 0, 0, sizeof(InstanceData) * m_numSpritesDrawn, 1, 1),
+                       m_instanceData.get(),
+                       0,
+                       0
+                       );
+
+               D3D11_MAPPED_SUBRESOURCE mappedSubresource;
+               m_d3dContext->Map(
+                       m_renderTargetInfoCbuffer.Get(),
+                       0,
+                       D3D11_MAP_WRITE_DISCARD,
+                       0,
+                       &mappedSubresource
+                       );
+               *static_cast<float2*>(mappedSubresource.pData) = m_renderTargetSize;
+               m_d3dContext->Unmap(
+                       m_renderTargetInfoCbuffer.Get(),
+                       0
+                       );
+
+               // Set the pipeline state
+
+               m_d3dContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_POINTLIST);
+               m_d3dContext->GSSetShader(
+                       m_geometryShader.Get(),
+                       nullptr,
+                       0
+                       );
+               m_d3dContext->IASetInputLayout(m_inputLayout.Get());
+
+               m_d3dContext->VSSetShader(
+                       m_vertexShader.Get(),
+                       nullptr,
+                       0
+                       );
+
+               m_d3dContext->GSSetConstantBuffers(
+                       0,
+                       1,
+                       m_renderTargetInfoCbuffer.GetAddressOf()
+                       );
+
+               m_d3dContext->PSSetShader(
+                       m_pixelShader.Get(),
+                       nullptr,
+                       0
+                       );
+
+               m_d3dContext->PSSetSamplers(
+                       0,
+                       1,
+                       m_linearSampler.GetAddressOf()
+                       );
+
+               unsigned int stride = sizeof(InstanceData);
+               unsigned int offset = 0;
+               m_d3dContext->IASetVertexBuffers(
+                       0,
+                       1,
+                       m_instanceDataBuffer.GetAddressOf(),
+                       &stride,
+                       &offset
+                       );
+
+               // Draw each sprite run
+
+               unsigned int indexBase = 0;
+               for (auto runIterator = m_spriteRuns.begin(); runIterator != m_spriteRuns.end(); runIterator++)
+               {
+                       m_d3dContext->PSSetShaderResources(
+                               0,
+                               1,
+                               &runIterator->textureView
+                               );
+
+                       const FLOAT blendFactor[] = {0.0f, 0.0f, 0.0f, 0.0f};
+
+                       m_d3dContext->OMSetBlendState(
+                               runIterator->blendState,
+                               nullptr,
+                               0xFFFFFFFF
+                               );
+
+                       unsigned int instancesToDraw = runIterator->numSprites;
+                       m_d3dContext->DrawInstanced(
+                               1,
+                               instancesToDraw,
+                               0,
+                               indexBase
+                               );
+                       indexBase += instancesToDraw;
+               }
+       };
+
+private:
+       std::unique_ptr<InstanceData[]> m_instanceData;
+       Microsoft::WRL::ComPtr<ID3D11Buffer> m_instanceDataBuffer;
+};
+
+struct InstancingSpriteDrawer : public SpriteDrawerBase
+{
+       virtual void Initialize(
+                ID3D11Device1* d3dDevice,
+                int capacity
+               ) 
+       {
+               SpriteDrawerBase::Initialize(d3dDevice,capacity);
+               BasicLoader^ loader = ref new BasicLoader(m_d3dDevice.Get());
         D3D11_INPUT_ELEMENT_DESC layoutDesc[] = 
         {
             { "POSITION",  0, DXGI_FORMAT_R32G32B32A32_FLOAT,   0, 0,  D3D11_INPUT_PER_VERTEX_DATA,   0 },
@@ -152,7 +674,8 @@ void SpriteBatch::Initialize(
             { "TRANSFORM", 0, DXGI_FORMAT_R32G32B32A32_FLOAT,   1, 0,  D3D11_INPUT_PER_INSTANCE_DATA, 1 },
             { "TRANSFORM", 1, DXGI_FORMAT_R32G32_FLOAT,   1, 16,  D3D11_INPUT_PER_INSTANCE_DATA, 1 },
             { "TRANSFORM", 2, DXGI_FORMAT_R32_FLOAT,      1, 24, D3D11_INPUT_PER_INSTANCE_DATA, 1 },
-            { "COLOR",     0, DXGI_FORMAT_R8G8B8A8_UNORM, 1, 28, D3D11_INPUT_PER_INSTANCE_DATA, 1 }
+            { "TRANSFORM", 3, DXGI_FORMAT_R32G32B32A32_FLOAT,      1, 28, D3D11_INPUT_PER_INSTANCE_DATA, 1 },
+            { "COLOR",     0, DXGI_FORMAT_R8G8B8A8_UNORM, 1, 44, D3D11_INPUT_PER_INSTANCE_DATA, 1 }
         };
         loader->LoadShader(
             "BasicSprites.Instancing.vs.cso",
@@ -161,54 +684,12 @@ void SpriteBatch::Initialize(
             &m_vertexShader,
             &m_inputLayout
             );
-    }
-    else if (m_technique == RenderTechnique::Replication)
-    {
-        D3D11_INPUT_ELEMENT_DESC layoutDesc[] = 
-        {
-            { "POSITIONT", 0, DXGI_FORMAT_R32G32B32A32_FLOAT,   0, 0,  D3D11_INPUT_PER_VERTEX_DATA, 0 },
-            { "TEXCOORD",  0, DXGI_FORMAT_R32G32_FLOAT,   0, 16,  D3D11_INPUT_PER_VERTEX_DATA, 0 },
-            { "COLOR",     0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, 24, D3D11_INPUT_PER_VERTEX_DATA, 0 }
-        };
-        loader->LoadShader(
-            "BasicSprites.Replication.vs.cso",
-            layoutDesc,
-            ARRAYSIZE(layoutDesc),
-            &m_vertexShader,
-            &m_inputLayout
-            );
-    }
 
-    loader->LoadShader(
+               loader->LoadShader(
         "BasicSprites.ps.cso",
         &m_pixelShader
         );
 
-    // Create buffers.
-
-    if (m_technique == RenderTechnique::GeometryShader)
-    {
-        // Create the instance data buffer.
-
-        DX::ThrowIfFailed(
-            m_d3dDevice->CreateBuffer(
-                &CD3D11_BUFFER_DESC(
-                    m_capacity * sizeof(InstanceData),
-                    D3D11_BIND_VERTEX_BUFFER,
-                    D3D11_USAGE_DEFAULT,
-                    0
-                    ),
-                nullptr,
-                &m_instanceDataBuffer
-                )
-            );
-
-        m_instanceData.reset(new InstanceData[m_capacity]);
-    }
-    else if (m_technique == RenderTechnique::Instancing)
-    {
-        // Create the vertex buffer.
-
         InstancingVertex vertexBufferData[] = 
         {
             { float4(-1.0f,  1.0f , 0.0f , 0.0f), float2(0.0f, 0.0f) },
@@ -216,6 +697,7 @@ void SpriteBatch::Initialize(
             { float4(-1.0f, -1.0f , 0.0f , 0.0f), float2(0.0f, 1.0f) },
             { float4( 1.0f, -1.0f , 0.0f , 0.0f), float2(1.0f, 1.0f) }
         };
+        // Create the vertex buffer.
 
         D3D11_SUBRESOURCE_DATA vertexInitialData;
         vertexInitialData.pSysMem = vertexBufferData;
@@ -277,9 +759,183 @@ void SpriteBatch::Initialize(
                 &m_indexBuffer
                 )
             );
-    }
-    else if (m_technique == RenderTechnique::Replication)
-    {
+
+               // Both the Geometry Shader and Instancing techniques scale geometry in shader code.
+               // As a result, they require information about the render target size.
+               DX::ThrowIfFailed(
+                       m_d3dDevice->CreateBuffer(
+                       &CD3D11_BUFFER_DESC(
+                       16, // Constant buffer sizes must be a multiple of 16 bytes.  16 is sufficient for the required float2 data.
+                       D3D11_BIND_CONSTANT_BUFFER,
+                       D3D11_USAGE_DYNAMIC,
+                       D3D11_CPU_ACCESS_WRITE
+                       ),
+                       nullptr,
+                       &m_renderTargetInfoCbuffer
+                       )
+                       );
+
+  };
+
+
+       virtual void End() 
+       {
+               // If no sprites were drawn, do nothing.
+               if (m_numSpritesDrawn == 0)
+               {
+                       return;
+               }
+
+
+               AddSpriteRun(m_instanceData);
+
+               // Update the buffer data.
+
+               m_d3dContext->UpdateSubresource(
+                       m_instanceDataBuffer.Get(),
+                       0,
+                       &CD3D11_BOX(0, 0, 0, sizeof(InstanceData) * m_numSpritesDrawn, 1, 1),
+                       m_instanceData.get(),
+                       0,
+                       0
+                       );
+
+               D3D11_MAPPED_SUBRESOURCE mappedSubresource;
+               m_d3dContext->Map(
+                       m_renderTargetInfoCbuffer.Get(),
+                       0,
+                       D3D11_MAP_WRITE_DISCARD,
+                       0,
+                       &mappedSubresource
+                       );
+               *static_cast<float2*>(mappedSubresource.pData) = m_renderTargetSize;
+               m_d3dContext->Unmap(
+                       m_renderTargetInfoCbuffer.Get(),
+                       0
+                       );
+
+               // Set the pipeline state
+
+               m_d3dContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
+               m_d3dContext->IASetIndexBuffer(
+                       m_indexBuffer.Get(),
+                       DXGI_FORMAT_R32_UINT,
+                       0
+                       );
+
+               m_d3dContext->IASetInputLayout(m_inputLayout.Get());
+
+               m_d3dContext->VSSetShader(
+                       m_vertexShader.Get(),
+                       nullptr,
+                       0
+                       );
+
+               m_d3dContext->VSSetConstantBuffers(
+                       0,
+                       1,
+                       m_renderTargetInfoCbuffer.GetAddressOf()
+                       );
+
+               m_d3dContext->PSSetShader(
+                       m_pixelShader.Get(),
+                       nullptr,
+                       0
+                       );
+
+               m_d3dContext->PSSetSamplers(
+                       0,
+                       1,
+                       m_linearSampler.GetAddressOf()
+                       );
+
+               unsigned int stride = sizeof(InstancingVertex);
+               unsigned int offset = 0;
+               m_d3dContext->IASetVertexBuffers(
+                       0,
+                       1,
+                       m_vertexBuffer.GetAddressOf(),
+                       &stride,
+                       &offset
+                       );
+
+               // Draw each sprite run
+
+               unsigned int indexBase = 0;
+               for (auto runIterator = m_spriteRuns.begin(); runIterator != m_spriteRuns.end(); runIterator++)
+               {
+                       m_d3dContext->PSSetShaderResources(
+                               0,
+                               1,
+                               &runIterator->textureView
+                               );
+
+                       const FLOAT blendFactor[] = {0.0f, 0.0f, 0.0f, 0.0f};
+
+                       m_d3dContext->OMSetBlendState(
+                               runIterator->blendState,
+                               nullptr,
+                               0xFFFFFFFF
+                               );
+
+                       unsigned int instancesToDraw = runIterator->numSprites;
+                       unsigned int stride = sizeof(InstanceData);
+                       unsigned int offset = indexBase * stride;
+                       // Instance data offset must be zero for the draw call on feature level 9.3 and below.
+                       // Instead, set the offset in the input assembler.
+                       m_d3dContext->IASetVertexBuffers(
+                               1,
+                               1,
+                               m_instanceDataBuffer.GetAddressOf(),
+                               &stride,
+                               &offset
+                               );
+                       m_d3dContext->DrawIndexedInstanced(
+                               6,
+                               instancesToDraw,
+                               0,
+                               0,
+                               0
+                               );
+                       indexBase += instancesToDraw;
+               }
+       }
+
+private:
+       std::unique_ptr<InstanceData[]> m_instanceData;
+       Microsoft::WRL::ComPtr<ID3D11Buffer> m_instanceDataBuffer;
+};
+
+struct ReplicationSpriteDrawer : public SpriteDrawerBase
+{
+
+       virtual void Initialize(
+                ID3D11Device1* d3dDevice,
+                int capacity
+               ) 
+               {
+               SpriteDrawerBase::Initialize(d3dDevice,capacity);
+               BasicLoader^ loader = ref new BasicLoader(m_d3dDevice.Get());
+
+        D3D11_INPUT_ELEMENT_DESC layoutDesc[] = 
+        {
+            { "POSITIONT", 0, DXGI_FORMAT_R32G32B32A32_FLOAT,   0, 0,  D3D11_INPUT_PER_VERTEX_DATA, 0 },
+            { "TEXCOORD",  0, DXGI_FORMAT_R32G32_FLOAT,   0, 16,  D3D11_INPUT_PER_VERTEX_DATA, 0 },
+            { "COLOR",     0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, 24, D3D11_INPUT_PER_VERTEX_DATA, 0 }
+        };
+        loader->LoadShader(
+            "BasicSprites.Replication.vs.cso",
+            layoutDesc,
+            ARRAYSIZE(layoutDesc),
+            &m_vertexShader,
+            &m_inputLayout
+            );
+
+               loader->LoadShader(
+        "BasicSprites.ps.cso",
+        &m_pixelShader
+        );
+
         // Create the vertex buffer.
 
         DX::ThrowIfFailed(
@@ -328,96 +984,11 @@ void SpriteBatch::Initialize(
                 &m_indexBuffer
                 )
             );
-    }
-
-    if (m_technique == RenderTechnique::GeometryShader || m_technique == RenderTechnique::Instancing)
-    {
-        // Both the Geometry Shader and Instancing techniques scale geometry in shader code.
-        // As a result, they require information about the render target size.
-        DX::ThrowIfFailed(
-            m_d3dDevice->CreateBuffer(
-                &CD3D11_BUFFER_DESC(
-                    16, // Constant buffer sizes must be a multiple of 16 bytes.  16 is sufficient for the required float2 data.
-                    D3D11_BIND_CONSTANT_BUFFER,
-                    D3D11_USAGE_DYNAMIC,
-                    D3D11_CPU_ACCESS_WRITE
-                    ),
-                nullptr,
-                &m_renderTargetInfoCbuffer
-                )
-            );
-    }
-}
-
-void SpriteBatch::AddTexture(
-    _In_ ID3D11Texture2D* texture
-    )
-{
-    TextureMapElement mapElement;
-    DX::ThrowIfFailed(
-        m_d3dDevice->CreateShaderResourceView(
-            texture,
-            &CD3D11_SHADER_RESOURCE_VIEW_DESC(
-                texture,
-                D3D11_SRV_DIMENSION_TEXTURE2D
-                ),
-            &mapElement.srv
-            )
-        );
-
-    D3D11_TEXTURE2D_DESC textureDesc;
-    texture->GetDesc(&textureDesc);
-    mapElement.size = float2(
-        static_cast<float>(textureDesc.Width),
-        static_cast<float>(textureDesc.Height)
-        );
-
-    m_textureMap[texture] = mapElement;
-}
-
-void SpriteBatch::RemoveTexture(
-    _In_ ID3D11Texture2D* texture
-    )
-{
-    m_textureMap.erase(texture);
-}
-
-void SpriteBatch::Begin()
-{
-    // Reset internal sprite data.
-
-    m_numSpritesDrawn = 0;
-    m_spritesInRun = 0;
-    m_spriteRuns.clear();
-       spritePrepInfos_.clear();
-    // Get the current render target dimensions and logical DPI.
-    
-    ComPtr<ID3D11RenderTargetView> renderTargetView;
-    m_d3dContext->OMGetRenderTargets(
-        1,
-        &renderTargetView,
-        nullptr
-        );
-
-    ComPtr<ID3D11Resource> renderTarget;
-    renderTargetView->GetResource(&renderTarget);
-
-    ComPtr<ID3D11Texture2D> renderTargetTexture;
-    renderTarget.As(&renderTargetTexture);
-
-    D3D11_TEXTURE2D_DESC renderTargetTextureDesc;
-    renderTargetTexture->GetDesc(&renderTargetTextureDesc);
-
-    m_renderTargetSize = float2(
-        static_cast<float>(renderTargetTextureDesc.Width),
-        static_cast<float>(renderTargetTextureDesc.Height)
-        );
 
-    m_dpi = Windows::Graphics::Display::DisplayProperties::LogicalDpi;
-}
+       };
 
-void SpriteBatch::End()
-{
+       virtual void End() 
+       {
     // If no sprites were drawn, do nothing.
     if (m_numSpritesDrawn == 0)
     {
@@ -444,34 +1015,16 @@ void SpriteBatch::End()
                                m_spriteRuns.push_back(runInfo);
                        }
 
-                       if (m_technique == RenderTechnique::GeometryShader || m_technique == RenderTechnique::Instancing)
-                       {
-                               m_instanceData[index] = info.instanceData;
-                       } else if (m_technique == RenderTechnique::Replication) {
-                               m_vertexData[index * 4 + 0] = info.replicationVertex[0];
-                               m_vertexData[index * 4 + 1] = info.replicationVertex[1];
-                               m_vertexData[index * 4 + 2] = info.replicationVertex[2];
-                               m_vertexData[index * 4 + 3] = info.replicationVertex[3];
-                       }
+                       m_vertexData[index * 4 + 0] = info.replicationVertex[0];
+                       m_vertexData[index * 4 + 1] = info.replicationVertex[1];
+                       m_vertexData[index * 4 + 2] = info.replicationVertex[2];
+                       m_vertexData[index * 4 + 3] = info.replicationVertex[3];
+
                        ++index;
                }
        );
 
     // Update the buffer data.
-
-    if (m_technique == RenderTechnique::GeometryShader || m_technique == RenderTechnique::Instancing)
-    {
-        m_d3dContext->UpdateSubresource(
-            m_instanceDataBuffer.Get(),
-            0,
-            &CD3D11_BOX(0, 0, 0, sizeof(InstanceData) * m_numSpritesDrawn, 1, 1),
-            m_instanceData.get(),
-            0,
-            0
-            );
-    }
-    else if (m_technique == RenderTechnique::Replication)
-    {
         m_d3dContext->UpdateSubresource(
             m_vertexBuffer.Get(),
             0,
@@ -480,54 +1033,15 @@ void SpriteBatch::End()
             0,
             0
             );
-    }
-
-    if (m_technique == RenderTechnique::GeometryShader || m_technique == RenderTechnique::Instancing)
-    {
-        D3D11_MAPPED_SUBRESOURCE mappedSubresource;
-        m_d3dContext->Map(
-            m_renderTargetInfoCbuffer.Get(),
-            0,
-            D3D11_MAP_WRITE_DISCARD,
-            0,
-            &mappedSubresource
-            );
-        *static_cast<float2*>(mappedSubresource.pData) = m_renderTargetSize;
-        m_d3dContext->Unmap(
-            m_renderTargetInfoCbuffer.Get(),
-            0
-            );
-    }
 
     // Set the pipeline state
 
-    if (m_technique == RenderTechnique::Instancing)
-    {
-        m_d3dContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
-        m_d3dContext->IASetIndexBuffer(
-            m_indexBuffer.Get(),
-            DXGI_FORMAT_R32_UINT,
-            0
-            );
-    }
-    else if (m_technique == RenderTechnique::Replication)
-    {
         m_d3dContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
         m_d3dContext->IASetIndexBuffer(
             m_indexBuffer.Get(),
             DXGI_FORMAT_R16_UINT,
             0
             );
-    }
-    else if (m_technique == RenderTechnique::GeometryShader)
-    {
-        m_d3dContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_POINTLIST);
-        m_d3dContext->GSSetShader(
-            m_geometryShader.Get(),
-            nullptr,
-            0
-            );
-    }
 
     m_d3dContext->IASetInputLayout(m_inputLayout.Get());
 
@@ -537,23 +1051,6 @@ void SpriteBatch::End()
         0
         );
 
-    if (m_technique == RenderTechnique::GeometryShader)
-    {
-        m_d3dContext->GSSetConstantBuffers(
-            0,
-            1,
-            m_renderTargetInfoCbuffer.GetAddressOf()
-            );
-    }
-    else if (m_technique == RenderTechnique::Instancing)
-    {
-        m_d3dContext->VSSetConstantBuffers(
-            0,
-            1,
-            m_renderTargetInfoCbuffer.GetAddressOf()
-            );
-    }
-
     m_d3dContext->PSSetShader(
         m_pixelShader.Get(),
         nullptr,
@@ -566,32 +1063,6 @@ void SpriteBatch::End()
         m_linearSampler.GetAddressOf()
         );
 
-    if (m_technique == RenderTechnique::GeometryShader)
-    {
-        unsigned int stride = sizeof(InstanceData);
-        unsigned int offset = 0;
-        m_d3dContext->IASetVertexBuffers(
-            0,
-            1,
-            m_instanceDataBuffer.GetAddressOf(),
-            &stride,
-            &offset
-            );
-    }
-    else if (m_technique == RenderTechnique::Instancing)
-    {
-        unsigned int stride = sizeof(InstancingVertex);
-        unsigned int offset = 0;
-        m_d3dContext->IASetVertexBuffers(
-            0,
-            1,
-            m_vertexBuffer.GetAddressOf(),
-            &stride,
-            &offset
-            );
-    }
-    else if (m_technique == RenderTechnique::Replication)
-    {
         unsigned int stride = sizeof(ReplicationVertex);
         unsigned int offset = 0;
         m_d3dContext->IASetVertexBuffers(
@@ -601,7 +1072,6 @@ void SpriteBatch::End()
             &stride,
             &offset
             );
-    }
 
     // Draw each sprite run
 
@@ -622,115 +1092,181 @@ void SpriteBatch::End()
             0xFFFFFFFF
             );
 
-        if (m_technique == RenderTechnique::GeometryShader)
-        {
-            unsigned int instancesToDraw = runIterator->numSprites;
-            m_d3dContext->DrawInstanced(
-                1,
-                instancesToDraw,
-                0,
-                indexBase
-                );
-            indexBase += instancesToDraw;
-        }
-        else if (m_technique == RenderTechnique::Instancing)
-        {
-            unsigned int instancesToDraw = runIterator->numSprites;
-            unsigned int stride = sizeof(InstanceData);
-            unsigned int offset = indexBase * stride;
-            // Instance data offset must be zero for the draw call on feature level 9.3 and below.
-            // Instead, set the offset in the input assembler.
-            m_d3dContext->IASetVertexBuffers(
-                1,
-                1,
-                m_instanceDataBuffer.GetAddressOf(),
-                &stride,
-                &offset
-                );
-            m_d3dContext->DrawIndexedInstanced(
-                6,
-                instancesToDraw,
-                0,
-                0,
-                0
-                );
-            indexBase += instancesToDraw;
-        }
-        else if (m_technique == RenderTechnique::Replication)
-        {
             unsigned int indicesToDraw = runIterator->numSprites * 6;
             m_d3dContext->DrawIndexed(indicesToDraw, indexBase, 0);
             indexBase += indicesToDraw;
-        }        
     }
-}
+       }
+
+       virtual void Draw(
+                ID3D11Texture2D* texture,
+                float4 position,
+                PositionUnits positionUnits,
+                float2 size,
+                SizeUnits sizeUnits,
+                float4 color,
+                float rotation,
+                BlendMode blendMode,
+                float2 textureCellOffset
+               ) 
+       {
+               // Fail if drawing this sprite would exceed the capacity of the sprite batch.
+               if (m_numSpritesDrawn >= m_capacity)
+               {
+                       throw ref new Platform::OutOfBoundsException();
+               }
+
+               SpritePrepInfo info;
+               InitSpritePrepInfo(info,texture,blendMode,textureCellOffset);
+
+               // Unless this is the first sprite run, save out the previous run info if a new run is required.
+               //if (
+               //    m_numSpritesDrawn > 0 && (
+               //        textureView != m_currentTextureView ||
+               //        blendState != m_currentBlendState
+               //        )
+               //    )
+               //{
+               //    SpriteRunInfo runInfo;
+               //    runInfo.textureView = m_currentTextureView;
+               //    runInfo.blendState = m_currentBlendState;
+               //    runInfo.numSprites = m_spritesInRun;
+               //    m_spriteRuns.push_back(runInfo);
+               //    m_spritesInRun = 0; // Reset for the next sprite run.
+               //}
+               //m_currentTextureView = textureView;
+               //m_currentBlendState = blendState;
+
+               // Add the sprite to the buffer.
+
+               float4 origin = StandardOrigin(position, positionUnits, m_renderTargetSize, m_dpi);
+               float2 offset = StandardOffset(size, sizeUnits, info.textureSize, m_dpi);
+
+               float2 offsets[4] = 
+               {
+                       float2(-offset.x,  offset.y),
+                       float2( offset.x,  offset.y),
+                       float2(-offset.x, -offset.y),
+                       float2( offset.x, -offset.y)
+               };
+
+               float sinRotation = sinf(rotation);
+               float cosRotation = cosf(rotation);
+
+               for (int i = 0; i < 4; i++)
+               {
+                       offsets[i] = float2(
+                               offsets[i].x * cosRotation - offsets[i].y * sinRotation,
+                               offsets[i].x * sinRotation + offsets[i].y * cosRotation
+                               );
+                       offsets[i].x /= m_renderTargetSize.x;
+                       offsets[i].y /= m_renderTargetSize.y;
+               }
 
-unsigned int SpriteBatch::MakeUnorm(float4 color)
+               float textureCellOffsetX = info.textureCellOffset.x / info.textureSize.x;
+               float textureCellOffsetY = info.textureCellOffset.y / info.textureSize.y;
+               float textureCellOffsetWidth = info.textureCellSize.x / info.textureSize.x;
+               float textureCellOffsetHeight = info.textureCellSize.y / info.textureSize.y;
+
+               // Write vertex buffer data.
+
+               //ReplicationVertex* singleSpriteVertices = &m_vertexData[m_numSpritesDrawn * 4];
+               unsigned int colorUnorm = MakeUnorm(color);
+               info.replicationVertex[0].pos = float4(origin.x + offsets[0].x,origin.y + offsets[0].y,origin.z,origin.w);
+               info.replicationVertex[1].pos = float4(origin.x + offsets[1].x,origin.y + offsets[1].y,origin.z,origin.w);
+               info.replicationVertex[2].pos = float4(origin.x + offsets[2].x,origin.y + offsets[2].y,origin.z,origin.w);
+               info.replicationVertex[3].pos = float4(origin.x + offsets[3].x,origin.y + offsets[3].y,origin.z,origin.w);
+               info.replicationVertex[0].color = colorUnorm;
+               info.replicationVertex[1].color = colorUnorm;
+               info.replicationVertex[2].color = colorUnorm;
+               info.replicationVertex[3].color = colorUnorm;
+               info.replicationVertex[0].tex = float2(textureCellOffsetX,textureCellOffsetY);
+               info.replicationVertex[1].tex = float2(textureCellOffsetX + textureCellOffsetWidth, textureCellOffsetY);
+               info.replicationVertex[2].tex = float2(textureCellOffsetX,textureCellOffsetY +  textureCellOffsetHeight);
+               info.replicationVertex[3].tex = float2(textureCellOffsetX + textureCellOffsetWidth,textureCellOffsetY +  textureCellOffsetHeight);
+
+               AddSpritePrepInfo(info);
+       }
+private:
+       std::unique_ptr<ReplicationVertex[]> m_vertexData;
+};
+
+SpriteBatch::SpriteBatch()
 {
-    unsigned int r = max(0, min(255, static_cast<unsigned int>(color.r * 255.0f)));
-    unsigned int g = max(0, min(255, static_cast<unsigned int>(color.g * 255.0f)));
-    unsigned int b = max(0, min(255, static_cast<unsigned int>(color.b * 255.0f)));
-    unsigned int a = max(0, min(255, static_cast<unsigned int>(color.a * 255.0f)));
-    return
-        (a << 24) |
-        (b << 16) |
-        (g << 8) |
-        r;
 }
 
-float4 SpriteBatch::StandardOrigin(float4 position, PositionUnits positionUnits, float2 renderTargetSize, float dpi)
+void SpriteBatch::Initialize(
+    _In_ ID3D11Device1* d3dDevice,
+    _In_ int capacity = 1024
+    )
 {
-    float4 origin;
-       
-       origin.z = position.z;
-       origin.w = position.w;
+    //m_d3dDevice = d3dDevice;
+    //m_d3dDevice->GetImmediateContext1(&m_d3dContext);
+    //m_capacity = capacity;
 
-    if (positionUnits == PositionUnits::Pixels)
-    {
-        origin.x = (position.x / renderTargetSize.x) * 2.0f - 1.0f;
-        origin.y = 1.0f - (position.y / renderTargetSize.y) * 2.0f;
-    }
-    else if (positionUnits == PositionUnits::DIPs)
-    {
-        origin.x = ((position.x * dpi / 96.0f) / renderTargetSize.x) * 2.0f - 1.0f;
-        origin.y = 1.0f - ((position.y * dpi / 96.0f) / renderTargetSize.y) * 2.0f;
-    }
-    else if (positionUnits == PositionUnits::Normalized)
+    // Determine the technique that will be used to render the sprites.
+    auto featureLevel = d3dDevice->GetFeatureLevel();
+
+    if (featureLevel >= D3D_FEATURE_LEVEL_10_0)
     {
-        origin.x = position.x * 2.0f - 1.0f;
-        origin.y = 1.0f - position.y * 2.0f;
+        // On DirectX 10+ devices, the Geometry Shader allows the sprite vertices to be 
+        // generated on the GPU, significantly reducing memory bandwidth requirements.
+               drawer_.reset(new GeometryShaderSpriteDrawer());
+               drawer_->Initialize(d3dDevice,capacity);
     }
-    else if (positionUnits == PositionUnits::UniformWidth)
+    else if (featureLevel >= D3D_FEATURE_LEVEL_9_3)
     {
-        origin.x = position.x * 2.0f - 1.0f;
-        origin.y = 1.0f - position.y * (renderTargetSize.x / renderTargetSize.y) * 2.0f;
+        // On DirectX 9.3+ devices, instancing allows shared sprite geometry with unique
+        // per-sprite instance parameters, eliminating redundant data transfer.
+               drawer_.reset(new InstancingSpriteDrawer());
+               drawer_->Initialize(d3dDevice,capacity);
     }
-    else if (positionUnits == PositionUnits::UniformHeight)
+    else
     {
-        origin.x = position.x * (renderTargetSize.y / renderTargetSize.x) * 2.0f - 1.0f;
-        origin.y = 1.0f - position.y * 2.0f;
+        // On devices that do not support Instancing, sprite vertex data must be replicated
+        // in order to achieve the desired effect.
+        // m_technique = RenderTechnique::Replication;
+
+        if (capacity > static_cast<int>(Parameters::MaximumCapacityCompatible))
+        {
+            // The index buffer format for feature-level 9.1 devices may only be 16 bits.
+            // With 4 vertices per sprite, this allows a maximum of (1 << 16) / 4 sprites.
+            throw ref new Platform::InvalidArgumentException();
+        }
+               drawer_.reset(new ReplicationSpriteDrawer());
+               drawer_->Initialize(d3dDevice,capacity);
+
     }
-    return origin;
+
 }
 
-float2 SpriteBatch::StandardOffset(float2 size, SizeUnits sizeUnits, float2 spriteSize, float dpi)
+void SpriteBatch::AddTexture(
+    _In_ ID3D11Texture2D* texture,float2 textureCellSize
+    )
 {
-    float2 offset;
-    if (sizeUnits == SizeUnits::Pixels)
-    {
-        offset = size;
-    }
-    else if (sizeUnits == SizeUnits::DIPs)
-    {
-        offset = size * dpi / 96.0f;
-    }
-    else if (sizeUnits == SizeUnits::Normalized)
-    {
-        offset = spriteSize * size;
-    }
-    return offset;
+       drawer_->AddTexture(texture,textureCellSize);
 }
 
+void SpriteBatch::RemoveTexture(
+    _In_ ID3D11Texture2D* texture
+    )
+{
+       drawer_->RemoveTexture(texture);
+}
+
+void SpriteBatch::Begin()
+{
+       drawer_->Begin();
+}
+
+void SpriteBatch::End()
+{
+       drawer_->End();
+}
+
+
+
+
 void SpriteBatch::Draw(
     _In_ ID3D11Texture2D* texture,
     _In_ float4 position,
@@ -817,166 +1353,32 @@ void SpriteBatch::Draw(
     _In_ BlendMode blendMode
     )
 {
-    // Fail if drawing this sprite would exceed the capacity of the sprite batch.
-    if (m_numSpritesDrawn >= m_capacity)
-    {
-        throw ref new Platform::OutOfBoundsException();
-    }
-
-    // Retrieve information about the sprite.
-    TextureMapElement element = m_textureMap[texture];
-    ID3D11ShaderResourceView* textureView = element.srv.Get();
-    float2 textureSize = element.size;
-    ID3D11BlendState1* blendState = blendMode == BlendMode::Additive ? m_blendStateAdditive.Get() : m_blendStateAlpha.Get();
-
-    // Fail if the texture has not previously been added to the sprite batch.
-    if (textureView == nullptr)
-    {
-        throw ref new Platform::NullReferenceException();
-    }
-
-       SpritePrepInfo info;
-
-       // Unless this is the first sprite run, save out the previous run info if a new run is required.
-    //if (
-    //    m_numSpritesDrawn > 0 && (
-    //        textureView != m_currentTextureView ||
-    //        blendState != m_currentBlendState
-    //        )
-    //    )
-    //{
-    //    SpriteRunInfo runInfo;
-    //    runInfo.textureView = m_currentTextureView;
-    //    runInfo.blendState = m_currentBlendState;
-    //    runInfo.numSprites = m_spritesInRun;
-    //    m_spriteRuns.push_back(runInfo);
-    //    m_spritesInRun = 0; // Reset for the next sprite run.
-    //}
-    //m_currentTextureView = textureView;
-    //m_currentBlendState = blendState;
-
-       info.textureView = textureView;
-       info.blendState  = blendState;
-
-    // Add the sprite to the buffer.
-
-    float4 origin = StandardOrigin(position, positionUnits, m_renderTargetSize, m_dpi);
-    float2 offset = StandardOffset(size, sizeUnits, textureSize, m_dpi);
-
-
-       if (m_technique == RenderTechnique::GeometryShader || m_technique == RenderTechnique::Instancing)
-    {
-               
-               info.instanceData.origin = origin;
-               info.instanceData.offset = offset;
-               info.instanceData.rotation = rotation;
-               info.instanceData.color = MakeUnorm(color);
-               if(spritePrepInfos_.empty()){
-                       spritePrepInfos_.push_back(info);
-               } else {
-                       std::list<SpritePrepInfo>::const_iterator it = spritePrepInfos_.cbegin();
-                       while(it != spritePrepInfos_.end())
-                       {
-                               if(it->instanceData.origin.z > info.instanceData.origin.z)
-                               {
-                                       ++it;
-                               } else {
-                                       if(it->instanceData.origin.z == info.instanceData.origin.z)
-                                       {
-                                               if(it->textureView == info.textureView)
-                                               {
-                                                       spritePrepInfos_.insert(it,info);
-                                                       break;
-                                               } else {
-                                                       ++it;
-                                               }
-                                       } else {
-                                               spritePrepInfos_.insert(it,info);
-                                               break;
-                                       }
-                               }
-                       }
-
-                       if(it == spritePrepInfos_.end())
-                       {
-                               spritePrepInfos_.push_back(info);
-                       }
-               }
-
-               //m_instanceData[m_numSpritesDrawn].origin = origin;
-        //m_instanceData[m_numSpritesDrawn].offset = offset;
-        //m_instanceData[m_numSpritesDrawn].rotation = rotation;
-        //m_instanceData[m_numSpritesDrawn].color = MakeUnorm(color);
-    }
-    else if (m_technique == RenderTechnique::Replication)
-    {
-        float2 offsets[4] = 
-        {
-            float2(-offset.x,  offset.y),
-            float2( offset.x,  offset.y),
-            float2(-offset.x, -offset.y),
-            float2( offset.x, -offset.y)
-        };
-
-        float sinRotation = sinf(rotation);
-        float cosRotation = cosf(rotation);
-
-        for (int i = 0; i < 4; i++)
-        {
-            offsets[i] = float2(
-                offsets[i].x * cosRotation - offsets[i].y * sinRotation,
-                offsets[i].x * sinRotation + offsets[i].y * cosRotation
-                );
-            offsets[i].x /= m_renderTargetSize.x;
-            offsets[i].y /= m_renderTargetSize.y;
-        }
-
-        // Write vertex buffer data.
-
-        //ReplicationVertex* singleSpriteVertices = &m_vertexData[m_numSpritesDrawn * 4];
-        unsigned int colorUnorm = MakeUnorm(color);
-        info.replicationVertex[0].pos = float4(origin.x + offsets[0].x,origin.y + offsets[0].y,origin.z,origin.w);
-        info.replicationVertex[1].pos = float4(origin.x + offsets[1].x,origin.y + offsets[1].y,origin.z,origin.w);
-        info.replicationVertex[2].pos = float4(origin.x + offsets[2].x,origin.y + offsets[2].y,origin.z,origin.w);
-        info.replicationVertex[3].pos = float4(origin.x + offsets[3].x,origin.y + offsets[3].y,origin.z,origin.w);
-        info.replicationVertex[0].color = colorUnorm;
-        info.replicationVertex[1].color = colorUnorm;
-        info.replicationVertex[2].color = colorUnorm;
-        info.replicationVertex[3].color = colorUnorm;
-        info.replicationVertex[0].tex = float2(0.0f, 0.0f);
-        info.replicationVertex[1].tex = float2(1.0f, 0.0f);
-        info.replicationVertex[2].tex = float2(0.0f, 1.0f);
-        info.replicationVertex[3].tex = float2(1.0f, 1.0f);
-               std::list<SpritePrepInfo>::const_iterator it = spritePrepInfos_.cbegin();
-               while(it != spritePrepInfos_.end())
-               {
-                       if(it->replicationVertex[0].pos.z < info.replicationVertex[0].pos.z)
-                       {
-                               ++it;
-                       } else {
-                               if(it->replicationVertex[0].pos.z == info.replicationVertex[0].pos.z)
-                               {
-                                       if(it->textureView == info.textureView)
-                                       {
-                                               spritePrepInfos_.insert(it,info);
-                                               break;
-                                       } else {
-                                               ++it;
-                                       }
-                               } else {
-                                       spritePrepInfos_.insert(it,info);
-                                       break;
-                               }
-                       }
-               }
-
-               if(it == spritePrepInfos_.end())
-               {
-                       spritePrepInfos_.push_back(info);
-               }
+    Draw(
+        texture,
+        position,
+        positionUnits,
+        size,
+        sizeUnits,
+        color,
+        rotation,
+        blendMode,
+               float2(0.0f,0.0f)
+        );
 
-    }
+}
 
-//    m_spritesInRun++;
-    m_numSpritesDrawn++;
+void SpriteBatch::Draw(
+    _In_ ID3D11Texture2D* texture,
+    _In_ float4 position,
+    _In_ PositionUnits positionUnits,
+    _In_ float2 size,
+    _In_ SizeUnits sizeUnits,
+    _In_ float4 color,
+    _In_ float rotation,
+    _In_ BlendMode blendMode,
+       _In_ float2 textureOffset
+    )
+{
+       drawer_->Draw(texture,position,positionUnits,size,sizeUnits,color,rotation,blendMode,textureOffset);
 }
+}
\ No newline at end of file