I have built a simple library which worked perfectly for 2D sprites. However when I ported this over to DXUT I am getting strange blending problems. At first everything seemed fine as the alpha channels for the sprites were transparent against the background, but when the sprites crossed each other the bounding box of the sprite became visible. See file attached.
I have created the simplest piece of code I can to demonstrate how I am doing things. I have based this on EmptyProject10.cpp that is comes with the DirectX SDK:
..\MicrosoftDirectXSDKJune2010\Samples\C++\Direct3D10\EmptyProject10
within this there are only two callback functions that I use OnD3D10ResizedSwapChain() and OnD3D10FrameRender(). All the code and the variables are below.
Any help would be greatly appreciated as I have been stuck on this for a long time.
Edit: I have also just realised that the colours are washed out when I am using DXUT. I have read somewhere that this is related to DXUT using DXGI_FORMAT_R8G8B8A8_UNORM_SRGB. However I have already spent ages tinkering with either trying to get DXUT to use DXGI_FORMAT_R8G8B8A8_UNORM or to get my textures to be DXGI_FORMAT_R8G8B8A8_UNORM_SRGB.
#define NUM_POOL_SPRITES 32
D3DX10_SPRITE spritePool[NUM_POOL_SPRITES];
ID3DX10Sprite *pSpriteObject = NULL;
ID3D10ShaderResourceView *gSpriteTextureRV = NULL;
#define MAX_SPRITES 4
// Sprite structure
typedef struct
{
// sprite details
float width;
float height;
// sprite position
float posX;
float posY;
// sprite movement
float moveX;
float moveY;
BOOL visible;
}GameSprite2;
GameSprite2 sprites[MAX_SPRITES] = {0};
// the number of active sprites
int numActiveSprites = 0;
HRESULT CALLBACK GameApplication::OnD3D10ResizedSwapChain( ID3D10Device* pd3dDevice, IDXGISwapChain* pSwapChain,
const DXGI_SURFACE_DESC* pBackBufferSurfaceDesc, void* pUserContext )
{
// create and set the viewport
D3D10_VIEWPORT viewPort;
viewPort.Width = DXUTGetWindowHeight();
viewPort.Height = DXUTGetWindowWidth();
viewPort.MinDepth = 0.0f;
viewPort.MaxDepth = 1.0f;
viewPort.TopLeftX = 0;
viewPort.TopLeftY = 0;
DXUTGetD3D10Device()->RSSetViewports(1, &viewPort);
// Create the default projection matrix
D3DXMatrixOrthoOffCenterLH(&matProjection,
(float)viewPort.TopLeftX,
(float)viewPort.Width,
(float)viewPort.TopLeftY,
(float)viewPort.Height,
0.1f,
10);
ID3D10Texture2D* texture = NULL;
ID3D10Resource* pRes = NULL;
//HRESULT hr = D3DX10CreateTextureFromFile(DXUTGetD3D10Device(), TEXT("./brick.bmp"), NULL, NULL, &pRes, NULL);
HRESULT hr = D3DX10CreateTextureFromFile(DXUTGetD3D10Device(), TEXT("./bitmaps/spheremapsmall.png"), NULL, NULL, &pRes, NULL);
testHr("OnD3D10ResizedSwapChain:D3DX10CreateTextureFromFile",hr);
// Translates the ID3D10Resource object into a ID3D10Texture2D object
pRes->QueryInterface(__uuidof( ID3D10Texture2D ), (LPVOID*)&texture);
pRes->Release();
if (texture == NULL)
{
CLogger::WriteInfoLog("failed to create texture");
return false;
}
// Get the texture details
D3D10_TEXTURE2D_DESC desc;
texture->GetDesc(&desc);
// Create a shader resource view of the texture
D3D10_SHADER_RESOURCE_VIEW_DESC SRVDesc;
ZeroMemory(&SRVDesc, sizeof(SRVDesc));
SRVDesc.Format = desc.Format;
SRVDesc.ViewDimension = D3D10_SRV_DIMENSION_TEXTURE2D;
SRVDesc.Texture2D.MipLevels = desc.MipLevels;
hr=DXUTGetD3D10Device()->CreateShaderResourceView(texture, &SRVDesc, &gSpriteTextureRV);
testHr("OnD3D10ResizedSwapChain:CreateShaderResourceView",hr);
// release the texture
texture->Release();
// Create the Sprite Batch, all sprite drawing is done through
// this object
hr = D3DX10CreateSprite(DXUTGetD3D10Device(), 0, &pSpriteObject);
testHr("OnD3D10ResizedSwapChain:D3DX10CreateSprite",hr);
// Initialize the blend state for alpha drawing
D3D10_BLEND_DESC StateDesc;
ZeroMemory(&StateDesc, sizeof(D3D10_BLEND_DESC));
StateDesc.AlphaToCoverageEnable = FALSE;
StateDesc.BlendEnable[0] = TRUE;
StateDesc.SrcBlend = D3D10_BLEND_SRC_ALPHA;
StateDesc.DestBlend = D3D10_BLEND_INV_SRC_ALPHA;
StateDesc.BlendOp = D3D10_BLEND_OP_ADD;
StateDesc.SrcBlendAlpha = D3D10_BLEND_ZERO;
StateDesc.DestBlendAlpha = D3D10_BLEND_ZERO;
StateDesc.BlendOpAlpha = D3D10_BLEND_OP_ADD;
StateDesc.RenderTargetWriteMask[0] = D3D10_COLOR_WRITE_ENABLE_ALL;
hr=DXUTGetD3D10Device()->CreateBlendState(&StateDesc, &pBlendState10);
testHr("OnD3D10ResizedSwapChain:CreateBlendState",hr);
// Loop through and set the defaults for the
// sprites in the pool
for (int i = 0; i < NUM_POOL_SPRITES; i++)
{
// Texture for this sprite to use
spritePool.pTexture = gSpriteTextureRV;
spritePool.TextureIndex = 0;
// top-left location in U,V coords
spritePool.TexCoord.x = 0;
spritePool.TexCoord.y = 0;
// Determine the texture size in U,V coords
spritePool.TexSize.x = 1;
spritePool.TexSize.y = 1;
spritePool.ColorModulate = D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f);
}
// Create a diagonal line of overlapping sprites
for (int curSprite = 0; curSprite < MAX_SPRITES-1; curSprite++)
{
// Set the width and height of the sprite
sprites[curSprite].width = 64.0f;
sprites[curSprite].height = 64.0f;
// position in a diagonal so you can see overlap
sprites[curSprite].posX = 300+(curSprite*15);
sprites[curSprite].posY = 100+(curSprite*15);
sprites[curSprite].moveX = 0;
sprites[curSprite].moveY = 0;
// This sprite is visible
sprites[curSprite].visible = TRUE;
}
//create a single sprite on its own
sprites[MAX_SPRITES-1].width = 64.0f;
sprites[MAX_SPRITES-1].height = 64.0f;
sprites[MAX_SPRITES-1].posX = 100;
sprites[MAX_SPRITES-1].posY = 100;
sprites[MAX_SPRITES-1].visible = TRUE;
D3DXMATRIX matScaling;
D3DXMATRIX matTranslation;
int curPoolIndex = 0;
// Loop through the sprites
for (int i = 0; i < MAX_SPRITES; i++)
{
// only update visible sprites
if (sprites.visible)
{
CLogger::WriteInfoLog("OnFrameMove: moving sprites");
// set the proper scale for the sprite
D3DXMatrixScaling(&matScaling, sprites.width, sprites.height, 1.0f);
// Move the sprite to spritePosX, spritePosY
// SpriteWidth and SpriteHeight are divided by 2 to move the
// translation point to the top-left sprite corner instead of
// the center of the sprite.
D3DXMatrixTranslation(&matTranslation,
(float)sprites.posX + (sprites.width/2),
(float)(DXUTGetWindowHeight() - sprites.posY - (sprites.height/2)), 0.1f);
// Update the sprites position and scale
spritePool[curPoolIndex].matWorld = matScaling * matTranslation;
// Increment the pool index
curPoolIndex++;
}
}
// set the number of active sprites
numActiveSprites = curPoolIndex;
return S_OK;
}
void CALLBACK GameApplication::OnD3D10FrameRender( ID3D10Device* pd3dDevice, double fTime, float fElapsedTime, void* pUserContext )
{
float ClearColor[4] = { 0.176f, 0.196f, 0.667f, 0.0f };
pd3dDevice->ClearRenderTargetView( DXUTGetD3D10RenderTargetView(), ClearColor );
//pd3dDevice->ClearRenderTargetView( DXUTGetD3D10RenderTargetView(), D3DXCOLOR(0.0f, 0.0f, 0.0f, 0.0f) );
pd3dDevice->ClearDepthStencilView( DXUTGetD3D10DepthStencilView(), D3D10_CLEAR_DEPTH, 1.0, 0 );
FLOAT OriginalBlendFactor[4];
UINT OriginalSampleMask = 0;
if (DXUTGetD3D10Device() != NULL)
{
// clear the target buffer
//pD3DDevice->ClearRenderTargetView(pRenderTargetView, D3DXCOLOR(0.0f, 0.0f, 0.0f, 0.0f));
if (pSpriteObject != NULL)
{
HRESULT hr = pSpriteObject->SetProjectionTransform(&matProjection);
testHr("OnD3D10FrameRender:SetProjectionTransform",hr);
// start drawing the sprites
hr=pSpriteObject->Begin(D3DX10_SPRITE_SORT_TEXTURE);
testHr("OnD3D10FrameRender:Begin",hr);
// Draw all the sprites in the pool
hr=pSpriteObject->DrawSpritesBuffered(spritePool, numActiveSprites);
testHr("OnD3D10FrameRender:DrawSpritesBuffered",hr);
// Save the current blend state
DXUTGetD3D10Device()->OMGetBlendState(&pOriginalBlendState10, OriginalBlendFactor, &OriginalSampleMask);
// Set the blend state for alpha drawing
if(pBlendState10)
{
FLOAT NewBlendFactor[4] = {0,0,0,0};
DXUTGetD3D10Device()->OMSetBlendState(pBlendState10, NewBlendFactor, 0xffffffff);
}
// Finish up and send the sprites to the hardware
hr=pSpriteObject->Flush();
testHr("OnD3D10FrameRender:Flush",hr);
hr=pSpriteObject->End();
testHr("OnD3D10FrameRender:End",hr);
}
// Restore the previous blend state
DXUTGetD3D10Device()->OMSetBlendState(pOriginalBlendState10, OriginalBlendFactor, OriginalSampleMask);
}
}