#include "StdAfx.h"
#include "SpriteManager.h"
#include "Sprite.h"
using namespace System::Collections;
#define LIST_GRANULARITY 10
namespace Sunlight
{
namespace DirectX
{
namespace Graphics
{
SpriteManager::ObjectListElement::ObjectListElement(Sprite *pSprite)
{
TextureObject = pSprite->TextureObject;
SpriteVertex __pin *pVertices = &Vertices[0];
pSprite->FillVertexArray(pVertices);
Shadowed = false;
}
SpriteManager::ObjectListElement::ObjectListElement(Sprite *pSprite, int nShadowDepth)
{
TextureObject = pSprite->TextureObject;
SpriteVertex __pin *pVertices = &Vertices[0];
pSprite->FillVertexArray(pVertices);
if (nShadowDepth > 0)
{
for (int i = 0; i < 4; i++)
{
pVertices[i].x += nShadowDepth;
pVertices[i].y += nShadowDepth;
pVertices[i].dwColor = 0xC0000000;
}
Shadowed = true;
}
else
Shadowed = false;
}
SpriteManager::SpriteManager() :
m_pDevice(NULL),
m_vb(NULL),
m_plistObjects(new ArrayList(LIST_GRANULARITY)),
m_nVBSize(0)
{
}
SpriteManager::~SpriteManager()
{
Destroy();
}
void SpriteManager::Destroy()
{
if (m_vb != NULL)
{
m_vb->Release();
m_vb = NULL;
}
m_nVBSize = 0;
}
void SpriteManager::OnDeviceRelease(Object * , EventArgs * )
{
Destroy();
}
void SpriteManager::Draw(Sprite *sprite)
{
if (sprite->ShadowDepth > 0)
m_plistObjects->Add(new ObjectListElement(sprite, sprite->ShadowDepth));
m_plistObjects->Add(new ObjectListElement(sprite));
}
void SpriteManager::FinishDraw()
{
if (m_pDevice == NULL)
throw new ArgumentNullException(S"DeviceObject");
if (!m_pDevice->IsCreated)
return;
IDirect3DDevice8 *dev = m_pDevice->Direct3DDevice;
if ((m_nVBSize < m_plistObjects->Count) || (m_vb == NULL))
{
if (m_vb != NULL)
{
m_vb->Release();
m_vb = NULL;
}
IDirect3DVertexBuffer8 __nogc *pVB;
HRESULT h = dev->CreateVertexBuffer((m_plistObjects->Count + LIST_GRANULARITY) * 4 * sizeof(SpriteVertex),
D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC, VertexFormat,
D3DPOOL_DEFAULT, &pVB);
if (FAILED(h))
throw new Sunlight::DirectX::DirectXException(S"IDirect3DDevice8::CreateVertexBuffer", h);
m_vb = pVB;
m_nVBSize = m_plistObjects->Count + LIST_GRANULARITY;
}
if (m_nVBSize == 0)
return;
SpriteVertex *pVertices;
m_vb->Lock(0, 0, (BYTE **)&pVertices, D3DLOCK_DISCARD);
for (int i = 0; i < m_plistObjects->Count; i++)
{
ObjectListElement *s = static_cast<ObjectListElement *>(m_plistObjects->Item[i]);
SpriteVertex __pin *pSrcVertices = &s->Vertices[0];
memcpy(pVertices, pSrcVertices, 4 * sizeof(SpriteVertex));
pVertices += 4;
}
m_vb->Unlock();
dev->SetStreamSource(0, m_vb, sizeof(SpriteVertex));
dev->SetVertexShader(VertexFormat);
for (int i = 0; i < m_plistObjects->Count; i++)
{
ObjectListElement *s = static_cast<ObjectListElement *>(m_plistObjects->Item[i]);
dev->SetTexture(0, s->TextureObject->Direct3DTexture);
if (s->Shadowed)
{
dev->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
dev->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
dev->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);
dev->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
dev->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_ALPHAREPLICATE | D3DTA_COMPLEMENT | D3DTA_TEXTURE);
}
else
{
dev->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
dev->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
dev->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
dev->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
}
dev->DrawPrimitive(D3DPT_TRIANGLESTRIP, i * 4, 2);
}
m_plistObjects->Clear();
}
void SpriteManager::AbortDraw()
{
m_plistObjects->Clear();
}
Device *SpriteManager::get_DeviceObject()
{
return m_pDevice;
}
void SpriteManager::set_DeviceObject(Device *pDevice)
{
if (pDevice == m_pDevice)
return;
if (m_vb != NULL)
Destroy();
if (m_pDevice != NULL)
__unhook(&Device::Lost, m_pDevice, &SpriteManager::OnDeviceRelease, this);
m_pDevice = pDevice;
__hook(&Device::Lost, m_pDevice, &SpriteManager::OnDeviceRelease, this);
}
}
}
}