i'm trying to swapping the colors using a texture as index and a second one as palette.
Here is the full listing of the code:
#include <windows.h>
#include <windowsx.h>
#include <vector>
#include <dxgi.h>
#include <d3dcommon.h>
#include <d3d11.h>
#include <d3dx11.h>
#include <d3dcompiler.h>
#include <xnamath.h>
#pragma comment(lib, "dxgi.lib")
#pragma comment(lib, "d3d11.lib")
#pragma comment(lib, "d3dx11.lib")
#pragma comment(lib, "d3dx10.lib")
#pragma comment(lib, "D3dcompiler.lib")
// define the screen resolution
#define SCREEN_WIDTH 300
#define SCREEN_HEIGHT 180
const float SCREEN_DEPTH = 1000.0f;
const float SCREEN_NEAR = 0.1f;
struct SIMPLEVERTEX
{
XMFLOAT3 Pos;
XMFLOAT2 Tex;
XMFLOAT4 Color;
};
struct CONSTANTBUFFER
{
XMMATRIX Scaling;
XMMATRIX World;
XMMATRIX View;
XMMATRIX Projection;
};
// the WindowProc function prototype
LRESULT CALLBACK WindowProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam );
// Gestione delle DirectX 11
bool InitializeDirectX11( HWND p_Hwnd );
void CleanupDirectX11();
void BeginScene(float red, float green, float blue, float alpha);
void EndScene();
void Render();
// the entry point for any Windows program
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
{
WNDCLASSEX wc = {};
wc.cbSize = sizeof( WNDCLASSEX );
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.hCursor = LoadCursor( NULL, IDC_ARROW );
//wc.hbrBackground = (HBRUSH)( COLOR_WINDOW + 1 );
wc.lpszClassName = L"WindowClass";
RegisterClassEx( &wc );
unsigned int width, height;
width = GetSystemMetrics(SM_CXSCREEN);
height = GetSystemMetrics(SM_CYSCREEN);
RECT rect;
rect.left = 0;
rect.top = 0;
rect.right = SCREEN_WIDTH;
rect.bottom = SCREEN_HEIGHT;
AdjustWindowRect( &rect, WS_OVERLAPPEDWINDOW, FALSE );
rect.right -= rect.left;
rect.bottom -= rect.top;
rect.left = (width - rect.right) / 2;
rect.top = (height - rect.bottom) / 2;
// Creazione della window.
HWND hWnd;
hWnd = CreateWindowEx( NULL, L"WindowClass", L"Palette swapping", WS_OVERLAPPEDWINDOW, rect.left, rect.top, rect.right, rect.bottom, NULL, NULL, hInstance, NULL );
// Inizializza DirectX 11.
InitializeDirectX11(hWnd);
ShowWindow( hWnd, nCmdShow );
// enter the main loop:
MSG msg;
while( TRUE )
{
while( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
if( msg.message == WM_QUIT )
break;
else
{
// Render
Render();
}
}
CleanupDirectX11();
return msg.wParam;
}
// this is the main message handler for the program
LRESULT CALLBACK WindowProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
switch( message )
{
case WM_KEYUP:
{
if( wParam == VK_ESCAPE )
{
DestroyWindow( hWnd );
return 0;
}
}
break;
case WM_DESTROY:
{
PostQuitMessage( 0 );
return 0;
}
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
BeginPaint( hWnd, &ps );
EndPaint( hWnd, &ps );
}
return 0;
}
return DefWindowProc ( hWnd, message, wParam, lParam );
}
IDXGIFactory * g_Factory = NULL;
IDXGIAdapter * g_Adapter = NULL;
ID3D11Device * g_Device = NULL;
ID3D11DeviceContext * g_Context = NULL;
IDXGISwapChain * g_Swapchain = NULL;
ID3D11RenderTargetView * g_Targetview = NULL;
ID3D11VertexShader * g_VertexShader = NULL;
ID3D11InputLayout * g_VertexLayout = NULL;
ID3D11PixelShader * g_PixelShader = NULL;
ID3D11ShaderResourceView * g_TextureRV = NULL;
ID3D11ShaderResourceView * g_PaletteRV = NULL;
ID3D11SamplerState * g_Sampler = NULL;
ID3D11BlendState * g_BlendState = NULL;
ID3D11Buffer * g_VertexBuffer = NULL;
ID3D11Buffer * g_ConstantBuffer = NULL;
XMMATRIX g_World;
XMMATRIX g_View;
XMMATRIX g_Projection;
XMMATRIX g_Scaling;
XMMATRIX g_2nd;
ID3D11Texture2D * g_pDepthStencil = NULL;
ID3D11DepthStencilView * g_pDepthStencilView = NULL;
bool InitializeDirectX11( HWND p_Hwnd )
{
// Create DXGI factory.
if( FAILED( CreateDXGIFactory( __uuidof( IDXGIFactory ), (void**)&g_Factory ) ) )
return false;
// Main adapter.
g_Factory->EnumAdapters( 0, &g_Adapter );
D3D_FEATURE_LEVEL Featurerequested = D3D_FEATURE_LEVEL_11_0;
UINT Featurelevel = 1;
D3D_FEATURE_LEVEL Featuresupported;
// Watch out, you must pass D3D_DRIVER_TYPE_UNKNOWN to avoid E_INVALIDARG result.
if( FAILED( D3D11CreateDevice( g_Adapter, D3D_DRIVER_TYPE_UNKNOWN, NULL, D3D11_CREATE_DEVICE_DEBUG, &Featurerequested, Featurelevel, D3D11_SDK_VERSION, &g_Device, &Featuresupported, &g_Context ) ) )
return false;
DXGI_SWAP_CHAIN_DESC Chaindesc;
Chaindesc.BufferCount = 1;
Chaindesc.BufferDesc.Width = SCREEN_WIDTH;
Chaindesc.BufferDesc.Height = SCREEN_HEIGHT;
Chaindesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
Chaindesc.BufferDesc.RefreshRate.Numerator = 0;
Chaindesc.BufferDesc.RefreshRate.Denominator = 1;
Chaindesc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
Chaindesc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
Chaindesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
Chaindesc.OutputWindow = p_Hwnd;
Chaindesc.SampleDesc.Count = 1;
Chaindesc.SampleDesc.Quality = 0;
Chaindesc.Windowed = true;
Chaindesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
Chaindesc.Flags = 0;
if( FAILED( g_Factory->CreateSwapChain( g_Device, &Chaindesc, &g_Swapchain ) ) )
return false;
// Get the pointer to the back buffer.
ID3D11Texture2D * Backbuffer;
if( FAILED( g_Swapchain->GetBuffer( 0, __uuidof(ID3D11Texture2D), (LPVOID*)&Backbuffer ) ) )
return false;
// Create the render target view with the back buffer pointer.
if( FAILED( g_Device->CreateRenderTargetView( Backbuffer, NULL, &g_Targetview ) ) )
return false;
// Release pointer to the back buffer as we no longer need it.
Backbuffer->Release();
// Create depth stencil texture
D3D11_TEXTURE2D_DESC descDepth;
ZeroMemory( &descDepth, sizeof(descDepth) );
descDepth.Width = SCREEN_WIDTH;
descDepth.Height = SCREEN_HEIGHT;
descDepth.MipLevels = 1;
descDepth.ArraySize = 1;
descDepth.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
descDepth.SampleDesc.Count = 1;
descDepth.SampleDesc.Quality = 0;
descDepth.Usage = D3D11_USAGE_DEFAULT;
descDepth.BindFlags = D3D11_BIND_DEPTH_STENCIL;
descDepth.CPUAccessFlags = 0;
descDepth.MiscFlags = 0;
HRESULT hr = g_Device->CreateTexture2D( &descDepth, NULL, &g_pDepthStencil );
if( FAILED( hr ) )
return false;
D3D11_DEPTH_STENCIL_DESC dsDesc;
// Depth test parameters
dsDesc.DepthEnable = true;
dsDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
dsDesc.DepthFunc = D3D11_COMPARISON_LESS_EQUAL;
// Stencil test parameters
dsDesc.StencilEnable = true;
dsDesc.StencilReadMask = 0xFF;
dsDesc.StencilWriteMask = 0xFF;
// Stencil operations if pixel is front-facing
dsDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
dsDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_INCR;
dsDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
dsDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
// Stencil operations if pixel is back-facing
dsDesc.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
dsDesc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_DECR;
dsDesc.BackFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
dsDesc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
// Create depth stencil state
ID3D11DepthStencilState * pDSState;
g_Device->CreateDepthStencilState(&dsDesc, &pDSState);
// Bind depth stencil state
g_Context->OMSetDepthStencilState(pDSState, 1);
// Create the depth stencil view
D3D11_DEPTH_STENCIL_VIEW_DESC descDSV;
ZeroMemory( &descDSV, sizeof(descDSV) );
descDSV.Format = descDepth.Format;
descDSV.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
descDSV.Texture2D.MipSlice = 0;
hr = g_Device->CreateDepthStencilView( g_pDepthStencil, &descDSV, &g_pDepthStencilView );
if( FAILED( hr ) )
return false;
g_Context->OMSetRenderTargets( 1, &g_Targetview, g_pDepthStencilView );
// Setup the Viewport for rendering.
D3D11_VIEWPORT Viewport;
Viewport.Width = (float)SCREEN_WIDTH;
Viewport.Height = (float)SCREEN_HEIGHT;
Viewport.MinDepth = 0.0f;
Viewport.MaxDepth = 1.0f;
Viewport.TopLeftX = 0.0f;
Viewport.TopLeftY = 0.0f;
// Create the Viewport.
g_Context->RSSetViewports( 1, &Viewport );
// Compile the vertex shader
ID3DBlob * Errorblob = NULL;
ID3DBlob * VSBlob = NULL;
if( FAILED( D3DX11CompileFromFile( L"Palette.fx", NULL, NULL, "VS", "vs_5_0", D3DCOMPILE_ENABLE_STRICTNESS, 0, NULL, &VSBlob, &Errorblob, NULL ) ) )
return false;
// Create the vertex shader
if( FAILED( g_Device->CreateVertexShader( VSBlob->GetBufferPointer(), VSBlob->GetBufferSize(), NULL, &g_VertexShader ) ) )
{
VSBlob->Release();
return false;
}
// Define the input Layout
D3D11_INPUT_ELEMENT_DESC Layout[] =
{
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 }
};
UINT Elements = ARRAYSIZE( Layout );
// Create the input Layout
g_Device->CreateInputLayout( Layout, Elements, VSBlob->GetBufferPointer(), VSBlob->GetBufferSize(), &g_VertexLayout );
VSBlob->Release();
if( !g_VertexLayout )
return false;
// Set the input layout
g_Context->IASetInputLayout( g_VertexLayout );
// Compile the pixel shader
ID3DBlob * PSBlob = NULL;
if( FAILED( D3DX11CompileFromFile( L"Palette.fx", NULL, NULL, "PS", "ps_5_0", D3DCOMPILE_ENABLE_STRICTNESS, 0, NULL, &PSBlob, &Errorblob, NULL ) ) )
{
LPSTR text = (char *)Errorblob->GetBufferPointer();
return false;
}
// Create the pixel shader
g_Device->CreatePixelShader( PSBlob->GetBufferPointer(), PSBlob->GetBufferSize(), NULL, &g_PixelShader );
PSBlob->Release();
if( !g_PixelShader )
return false;
// Create vertex buffer
SIMPLEVERTEX Vertices[] =
{
{ XMFLOAT3( -0.5f, -0.5f, 0.0f ), XMFLOAT2( 0.0f, 1.0f ), XMFLOAT4( 1.0f, 1.0f, 1.0f, 1.0f ) },
{ XMFLOAT3( -0.5f, 0.5f, 0.0f ), XMFLOAT2( 0.0f, 0.0f ), XMFLOAT4( 1.0f, 1.0f, 1.0f, 1.0f ) },
{ XMFLOAT3( 0.5f, -0.5f, 0.0f ), XMFLOAT2( 1.0f, 1.0f ), XMFLOAT4( 1.0f, 1.0f, 1.0f, 1.0f ) },
{ XMFLOAT3( 0.5f, 0.5f, 0.0f ), XMFLOAT2( 1.0f, 0.0f ), XMFLOAT4( 1.0f, 1.0f, 1.0f, 1.0f ) }
};
D3D11_BUFFER_DESC Buffer = {};
Buffer.Usage = D3D11_USAGE_DEFAULT;
Buffer.ByteWidth = sizeof( SIMPLEVERTEX ) * ARRAYSIZE( Vertices );
Buffer.BindFlags = D3D11_BIND_VERTEX_BUFFER;
Buffer.CPUAccessFlags = 0;
D3D11_SUBRESOURCE_DATA Initdata = {};
Initdata.pSysMem = Vertices;
if( FAILED( g_Device->CreateBuffer( &Buffer, &Initdata, &g_VertexBuffer ) ) )
return false;
// Set vertex buffer
UINT Stride = sizeof( SIMPLEVERTEX );
UINT Offset = 0;
g_Context->IASetVertexBuffers( 0, 1, &g_VertexBuffer, &Stride, &Offset );
// Set primitive topology
g_Context->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
// Create the constant buffer
Buffer.Usage = D3D11_USAGE_DEFAULT;
Buffer.ByteWidth = sizeof(CONSTANTBUFFER);
Buffer.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
Buffer.CPUAccessFlags = 0;
if( FAILED( g_Device->CreateBuffer( &Buffer, NULL, &g_ConstantBuffer ) ) )
return false;
// Create index texture.
if( FAILED( D3DX11CreateShaderResourceViewFromFile( g_Device, L"Vortex.png", NULL, NULL, &g_TextureRV, NULL ) ) )
return false;
// Create palette texture.
if( FAILED( D3DX11CreateShaderResourceViewFromFile( g_Device, L"Palette8x1.png", NULL, NULL, &g_PaletteRV, NULL ) ) )
return false;
// Create the sample state
D3D11_SAMPLER_DESC Sampler;
ZeroMemory( &Sampler, sizeof(Sampler) );
Sampler.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
Sampler.AddressU = D3D11_TEXTURE_ADDRESS_BORDER;
Sampler.AddressV = D3D11_TEXTURE_ADDRESS_BORDER;
Sampler.AddressW = D3D11_TEXTURE_ADDRESS_BORDER;
Sampler.ComparisonFunc = D3D11_COMPARISON_ALWAYS;
Sampler.MinLOD = 0;
Sampler.MaxLOD = D3D11_FLOAT32_MAX;
if( FAILED( g_Device->CreateSamplerState( &Sampler, &g_Sampler ) ) )
return false;
// Create the blend state
D3D11_BLEND_DESC BlendState;
ZeroMemory( &BlendState, sizeof(D3D11_BLEND_DESC) );
BlendState.RenderTarget[0].BlendEnable = true;
BlendState.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
BlendState.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
BlendState.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
BlendState.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_SRC_ALPHA;
BlendState.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA;
BlendState.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
BlendState.RenderTarget[0].RenderTargetWriteMask = 0x0f;
g_Device->CreateBlendState( &BlendState, &g_BlendState );
float blendFactor[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
UINT sampleMask = 0xffffffff;
g_Context->OMSetBlendState( g_BlendState, blendFactor, sampleMask );
// Initialize the world matrix
g_World = XMMatrixIdentity();
g_World = XMMatrixTranslation( 0, 0, 22 );
g_2nd = XMMatrixIdentity();
g_2nd = XMMatrixTranslation( 42, -36, 20 );
// Initialize the view matrix
XMVECTOR Eye = XMVectorSet( 0.0f, 1.0f, -1.0f, 0.0f );
XMVECTOR At = XMVectorSet( 0.0f, 1.0f, 0.0f, 0.0f );
XMVECTOR Up = XMVectorSet( 0.0f, 1.0f, 0.0f, 0.0f );
g_View = XMMatrixLookAtLH( Eye, At, Up );
// Initialize the projection matrix
g_Projection = XMMatrixOrthographicLH((FLOAT) SCREEN_WIDTH, (FLOAT) SCREEN_HEIGHT, 0.0f, 10000.0f);
// Scaling.
g_Scaling = XMMatrixIdentity();
g_Scaling._11 = 64.0;
g_Scaling._22 = 64.0;
return true;
}
void CleanupDirectX11()
{
// Rilascio.
if( g_ConstantBuffer ) g_ConstantBuffer->Release();
if( g_VertexBuffer ) g_VertexBuffer->Release();
if( g_PixelShader ) g_PixelShader->Release();
if( g_VertexLayout ) g_VertexLayout->Release();
if( g_VertexShader ) g_VertexShader->Release();
if( g_Targetview ) g_Targetview->Release();
if( g_Swapchain ) g_Swapchain->Release();
if( g_Device) g_Device->Release();
if( g_Adapter) g_Adapter->Release();
if( g_Factory ) g_Factory->Release();
}
void BeginScene(float red, float green, float blue, float alpha)
{
float color[4];
// Setup the color to clear the buffer to.
color[0] = red;
color[1] = green;
color[2] = blue;
color[3] = alpha;
// Clear the back buffer.
g_Context->ClearRenderTargetView( g_Targetview, color );
return;
}
void EndScene()
{
g_Swapchain->Present( 0, 0 );
return;
}
void Render()
{
// Clear the back buffer
float Clearcolor[4] = { 0.0f, 0.5f, 1.0f, 1.0f }; // red,green,blue,alpha
g_Context->ClearRenderTargetView( g_Targetview, Clearcolor );
// Clear the depth buffer to 1.0 (max depth)
g_Context->ClearDepthStencilView( g_pDepthStencilView, D3D11_CLEAR_DEPTH, 1.0f, 0 );
// Update variables
CONSTANTBUFFER Buffer;
Buffer.World = XMMatrixTranspose( g_World );
Buffer.View = XMMatrixTranspose( g_View );
Buffer.Projection = XMMatrixTranspose( g_Projection );
Buffer.Scaling = XMMatrixTranspose( g_Scaling );
g_Context->UpdateSubresource( g_ConstantBuffer, 0, NULL, &Buffer, 0, 0 );
// Render
g_Context->VSSetShader( g_VertexShader, NULL, 0 );
g_Context->VSSetConstantBuffers( 0, 1, &g_ConstantBuffer );
g_Context->PSSetShaderResources( 0, 1, &g_TextureRV );
g_Context->PSSetShaderResources( 1, 1, &g_PaletteRV);
g_Context->PSSetSamplers( 0, 1, &g_Sampler );
g_Context->PSSetShader( g_PixelShader, NULL, 0 );
g_Context->Draw( 4, 0 );
// Present our back buffer to our front buffer
g_Swapchain->Present( 0, 0 );
}
and the shaders:
//--------------------------------------------------------------------------------------
// File: Tutorial04.fx
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//--------------------------------------------------------------------------------------
Texture2D txTexture : register( t0 );
Texture2D txPalette : register( t1 );
SamplerState sampling : register( s0 );
//--------------------------------------------------------------------------------------
// Constant Buffer Variables
//--------------------------------------------------------------------------------------
cbuffer ConstantBuffer : register( b0 )
{
matrix Scaling;
matrix World;
matrix View;
matrix Projection;
}
//--------------------------------------------------------------------------------------
struct VS_INPUT
{
float4 Pos : POSITION;
float2 Tex : TEXCOORD0;
float4 Color : COLOR0;
};
struct PS_INPUT
{
float4 Pos : SV_POSITION;
float2 Tex : TEXCOORD0;
float4 Color : COLOR0;
};
//--------------------------------------------------------------------------------------
// Vertex Shader
//--------------------------------------------------------------------------------------
PS_INPUT VS( VS_INPUT input )
{
PS_INPUT output = (PS_INPUT)0;
output.Pos = mul( input.Pos, Scaling);
output.Pos = mul( output.Pos, World );
output.Pos = mul( output.Pos, View );
output.Pos = mul( output.Pos, Projection );
output.Tex = input.Tex;
output.Color = input.Color;
return output;
}
//--------------------------------------------------------------------------------------
// Pixel Shader
//--------------------------------------------------------------------------------------
float4 PS( PS_INPUT input ) : SV_Target
{
float4 Index = txTexture.Sample( sampling, input.Tex );
float w, h;
txPalette.GetDimensions( w, h );
return txPalette.Sample( sampling, float2( ( Index.r * 255.0 ) / w, 0 ) );
}
The final rendering has some garbage on the texture, but i don't know WHAT cause it. Sampling, blending? What i'm missing?
The correct one is on the right.
The first texture use the red channel as index for the right texel on the second texture.
@Andon Coleman
This image show the texture ( the rightmost one) with +0.5 added to get the center of the texel.
float2( ( Index.r * 255.0 + 0.5 ) / w, 0.5 )
instead. Now each of your U/V coordinates will sample your palette texture exactly at the center of a texel instead of at the border. \$\endgroup\$txPalette.Load(int3(Index.r, 0, 0))
(which uses integer coordinates) to avoid any sampling, filtering or mipmapping. (You might also want to change the type of your index texture to int or uint as well) \$\endgroup\$