ok -- you'll need a basic shader:
Code:
Texture2D tex;
SamplerState sam_point
{
Filter = MIN_MAG_MIP_POINT;
AddressU = Clamp;
AddressV = Clamp;
};
matrix world;
matrix view;
matrix proj;
struct VS_INPUT
{
float4 pos : POSITION;
float2 tex : TEXCOORD;
};
struct PS_INPUT
{
float4 pos : SV_POSITION;
float2 tex : TEXCOORD0;
};
PS_INPUT VS (VS_INPUT input)
{
PS_INPUT output = (PS_INPUT)0;
output.pos = mul (input.pos, world);
output.pos = mul (output.pos, view);
output.pos = mul (output.pos, proj);
output.tex = input.tex;
return output;
};
float4 PS (PS_INPUT input) : SV_Target
{
float4 r = tex.Sample(sam_point, input.tex);
r.w = 1.0;
return r;
}
technique10 render
{
pass P0
{
SetVertexShader(CompileShader(vs_4_0, VS()));
SetGeometryShader(NULL);
SetPixelShader(CompileShader(ps_4_0, PS()));
}
}
Save it as shader.fx in the same directory as the .exe.
And here's the code. Try it out and let me know if you have any questions.
Code:
#include "windows.h"
#include "d3d10.h"
#include "d3dx10.h"
#include "stdio.h"
#pragma comment (lib, "d3d10.lib")
#pragma comment (lib, "d3dx10.lib")
#define release_com(x) { if(x) {x->Release(); x = 0;} }
bool vsync = false;
char *title = "2d";
int client_width = 640;
int client_height = 480;
int tex_width = 256;
int tex_height = 256;
HWND hwnd;
IDXGISwapChain *swapchain = 0;
ID3D10Device *d3d_dev = 0;
ID3D10Texture2D *depth_stencil_buffer = 0;
ID3D10RenderTargetView *render_target_view = 0;
ID3D10DepthStencilView *depth_stencil_view = 0;
ID3D10Texture2D *tex = 0;
ID3D10EffectTechnique *technique = 0;
ID3D10EffectMatrixVariable *var_world;
ID3D10EffectMatrixVariable *var_view;
ID3D10EffectMatrixVariable *var_proj;
ID3D10EffectShaderResourceVariable *var_tex;
ID3D10InputLayout *vertex_layout;
ID3D10Buffer *vertex_buffer;
D3DXMATRIX matrix_world;
D3DXMATRIX matrix_view;
D3DXMATRIX matrix_proj;
int frame_count = 0;
LARGE_INTEGER prev_time;
LARGE_INTEGER cur_time;
LARGE_INTEGER counter_freq;
struct vertex
{
D3DXVECTOR3 pos;
D3DXVECTOR2 tex;
};
void on_resize()
{
release_com(depth_stencil_buffer);
release_com(render_target_view);
release_com(depth_stencil_view);
swapchain->ResizeBuffers(1, client_width, client_height, DXGI_FORMAT_R8G8B8A8_UNORM, 0);
ID3D10Texture2D *back_buffer;
swapchain->GetBuffer(0, __uuidof(ID3D10Texture2D), (void **)(&back_buffer));
d3d_dev->CreateRenderTargetView(back_buffer, 0, &render_target_view);
release_com(back_buffer);
D3D10_TEXTURE2D_DESC depth_stencil_desc;
depth_stencil_desc.Width = client_width;
depth_stencil_desc.Height = client_height;
depth_stencil_desc.MipLevels = 1;
depth_stencil_desc.ArraySize = 1;
depth_stencil_desc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
depth_stencil_desc.SampleDesc.Count = 1;
depth_stencil_desc.SampleDesc.Quality = 0;
depth_stencil_desc.Usage = D3D10_USAGE_DEFAULT;
depth_stencil_desc.BindFlags = D3D10_BIND_DEPTH_STENCIL;
depth_stencil_desc.CPUAccessFlags = 0;
depth_stencil_desc.MiscFlags = 0;
d3d_dev->CreateTexture2D(&depth_stencil_desc, 0, &depth_stencil_buffer);
d3d_dev->CreateDepthStencilView(depth_stencil_buffer, 0, &depth_stencil_view);
d3d_dev->OMSetRenderTargets(1, &render_target_view, depth_stencil_view);
D3D10_VIEWPORT vp;
vp.TopLeftX = 0;
vp.TopLeftY = 0;
vp.Width = client_width;
vp.Height = client_height;
vp.MinDepth = 0.0f;
vp.MaxDepth = 1.0f;
d3d_dev->RSSetViewports(1, &vp);
D3DXMatrixPerspectiveFovLH(&matrix_proj, D3DX_PI/4.0f, (float)client_width/(float)client_height, 1.0f, 1000.0f);
}
void init_d3d()
{
DXGI_SWAP_CHAIN_DESC sd;
sd.BufferDesc.Width = client_width;
sd.BufferDesc.Height = client_height;
sd.BufferDesc.RefreshRate.Numerator = 0;
sd.BufferDesc.RefreshRate.Denominator = 1;
sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
sd.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
sd.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
sd.SampleDesc.Count = 1;
sd.SampleDesc.Quality = 0;
sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
sd.BufferCount = 1;
sd.OutputWindow = hwnd;
sd.Windowed = true;
sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
sd.Flags = 0;
HRESULT hr = D3D10CreateDeviceAndSwapChain(
0,
D3D10_DRIVER_TYPE_HARDWARE,
0,
0,
D3D10_SDK_VERSION,
&sd,
&swapchain,
&d3d_dev
);
if (FAILED(hr))
{
MessageBox(NULL, "D3D10CreateDeviceAndSwapChain failed.", 0, 0);
PostQuitMessage(0);
return;
}
on_resize();
D3D10_INPUT_ELEMENT_DESC element_desc[] =
{
{ TEXT("POSITION"), 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0 },
{ TEXT("TEXCOORD"), 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D10_INPUT_PER_VERTEX_DATA, 0 }
};
UINT num_elements = sizeof(element_desc)/sizeof(element_desc[0]);
ID3D10Effect *effect = 0;
hr = D3DX10CreateEffectFromFile("shader.fx", NULL, NULL, "fx_4_0", 0, 0, d3d_dev, NULL, NULL, &effect, NULL, NULL);
if (FAILED(hr))
{
MessageBox(NULL, "D3DX10CreateEffectFromFile failed", 0, 0);
PostQuitMessage(0);
return;
}
technique = effect->GetTechniqueByName("render");
var_world = effect->GetVariableByName("world")->AsMatrix();
var_view = effect->GetVariableByName("view")->AsMatrix();
var_proj = effect->GetVariableByName("proj")->AsMatrix();
var_tex = effect->GetVariableByName("tex")->AsShaderResource();
D3D10_PASS_DESC pass_desc;
technique->GetPassByIndex(0)->GetDesc(&pass_desc);
d3d_dev->CreateInputLayout(element_desc, num_elements, pass_desc.pIAInputSignature, pass_desc.IAInputSignatureSize, &vertex_layout);
vertex vertices[] =
{
{ D3DXVECTOR3( -4.0f/3.0f, -1.0f, 0.0f ), D3DXVECTOR2(0.0f, 1.0f) },
{ D3DXVECTOR3( -4.0f/3.0f, 1.0f, 0.0f ), D3DXVECTOR2(0.0f, 0.0f) },
{ D3DXVECTOR3( 4.0f/3.0f, -1.0f, 0.0f ), D3DXVECTOR2(1.0f, 1.0f) },
{ D3DXVECTOR3( 4.0f/3.0f, 1.0f, 0.0f ), D3DXVECTOR2(1.0f, 0.0f) },
};
D3D10_BUFFER_DESC buffer_desc;
buffer_desc.Usage = D3D10_USAGE_DEFAULT;
buffer_desc.ByteWidth = sizeof(vertex) * 4;
buffer_desc.BindFlags = D3D10_BIND_VERTEX_BUFFER;
buffer_desc.CPUAccessFlags = 0;
buffer_desc.MiscFlags = 0;
D3D10_SUBRESOURCE_DATA init_data;
init_data.pSysMem = vertices;
hr = d3d_dev->CreateBuffer(&buffer_desc, &init_data, &vertex_buffer);
D3D10_TEXTURE2D_DESC tex_desc;
tex_desc.Width = tex_width;
tex_desc.Height = tex_height;
tex_desc.MipLevels = 1;
tex_desc.ArraySize = 1;
tex_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
tex_desc.SampleDesc.Count = 1;
tex_desc.SampleDesc.Quality = 0;
tex_desc.Usage = D3D10_USAGE_DYNAMIC;
tex_desc.BindFlags = D3D10_BIND_SHADER_RESOURCE;
tex_desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
tex_desc.MiscFlags = 0;
d3d_dev->CreateTexture2D(&tex_desc, 0, &tex);
D3D10_SHADER_RESOURCE_VIEW_DESC desc_rv;
desc_rv.Format = tex_desc.Format;
desc_rv.ViewDimension = D3D10_SRV_DIMENSION_TEXTURE2D;
desc_rv.Texture2D.MipLevels = 1;
desc_rv.Texture2D.MostDetailedMip = 0;
ID3D10ShaderResourceView *tex_rv;
d3d_dev->CreateShaderResourceView(tex, &desc_rv, &tex_rv);
D3DXMatrixIdentity(&matrix_world);
D3DXMatrixLookAtLH(
&matrix_view,
&D3DXVECTOR3(0.0f, 0.0f, -(1.0 / tan( (D3DX_PI/4)/2.0 ))),
&D3DXVECTOR3(0.0f, 0.0f, 0.0f),
&D3DXVECTOR3(0.0f, 1.0f, 0.0f));
var_tex->SetResource(tex_rv);
}
void draw_scene()
{
UINT stride = sizeof(vertex);
UINT offset = 0;
d3d_dev->IASetInputLayout(vertex_layout);
d3d_dev->IASetVertexBuffers(0, 1, &vertex_buffer, &stride, &offset);
d3d_dev->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
D3D10_MAPPED_TEXTURE2D map;
map.pData = 0;
tex->Map(0, D3D10_MAP_WRITE_DISCARD, NULL, &map);
//*** plot pixels here ***
int *p = 0;
for (int y = 0; y < tex_height; ++y)
{
p = (int*)map.pData + y * (map.RowPitch / 4);
for (int x = 0; x < tex_width; ++x)
{
*p++ = (0xFF << 24) | (x << 16) | y;
}
}
tex->Unmap(0);
D3DXMatrixTranslation(&matrix_world, 0.0f, 0.0f, 0.0f);
var_proj->SetMatrix((float*)&matrix_proj);
var_view->SetMatrix((float*)&matrix_view);
var_world->SetMatrix((float*)&matrix_world);
technique->GetPassByIndex(0)->Apply(0);
d3d_dev->Draw(4, 0);
}
void run()
{
MSG msg = {0};
while (msg.message != WM_QUIT)
{
if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
d3d_dev->ClearRenderTargetView(render_target_view, D3DXCOLOR(0.0f, 0.0f, 0.0f, 1.0f));
d3d_dev->ClearDepthStencilView(depth_stencil_view, D3D10_CLEAR_DEPTH | D3D10_CLEAR_STENCIL, 1.0f, 0);
draw_scene();
swapchain->Present(vsync ? 1 : 0, 0);
frame_count++;
}
}
}
LRESULT CALLBACK wnd_proc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_SIZE:
client_width = LOWORD(lParam);
client_height = HIWORD(lParam);
if (d3d_dev)
on_resize();
return 0;
case WM_GETMINMAXINFO:
((MINMAXINFO*)lParam)->ptMinTrackSize.x = 100;
((MINMAXINFO*)lParam)->ptMinTrackSize.y = 100;
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_TIMER:
switch (wParam)
{
case 0:
QueryPerformanceCounter(&cur_time);
double elapsed = ((cur_time.QuadPart - prev_time.QuadPart) * 1000) / (double)counter_freq.QuadPart;
double fps = frame_count / (elapsed / 1000.0);
char buf[32];
_snprintf(buf, 32, "%s - %.2f fps", title, fps);
SetWindowText(hwnd, buf);
frame_count = 0;
prev_time = cur_time;
return 0;
}
break;
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}
void init(HINSTANCE hinstance)
{
WNDCLASS wc;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = wnd_proc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hinstance;
wc.hIcon = LoadIcon(0, IDI_APPLICATION);
wc.hCursor = LoadCursor(0, IDC_ARROW);
wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
wc.lpszMenuName = 0;
wc.lpszClassName = "2d_wnd_class";
RegisterClass(&wc);
RECT r = {0, 0, client_width, client_height};
AdjustWindowRect(&r, WS_OVERLAPPEDWINDOW, false);
int width = r.right - r.left;
int height = r.bottom - r.top;
hwnd = CreateWindow("2d_wnd_class",
title,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
width,
height,
0,
0,
hinstance,
NULL
);
ShowWindow(hwnd, SW_SHOW);
UpdateWindow(hwnd);
QueryPerformanceFrequency(&counter_freq);
QueryPerformanceCounter(&prev_time);
}
int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE hprevinstance, LPSTR lp_cmdline, int n_showcmd)
{
init(hinstance);
init_d3d();
SetTimer(hwnd, 0, 1000, NULL);
run();
}
James