/************************************************************************** * * Copyright 2010 Luca Barbieri * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice (including the * next paragraph) shall be included in all copies or substantial * portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * **************************************************************************/ #include #include "d3d11blit.hlsl.ps.h" #include "d3d11blit.hlsl.vs.h" template struct triangle_list_indices : public std::vector { unsigned base; bool flip; triangle_list_indices() : base(0), flip(false) {} void poly(unsigned a, unsigned b, unsigned c) { this->push_back(base + a); this->push_back(base + (flip ? c : b)); this->push_back(base + (flip ? b : c)); } void poly(unsigned a, unsigned b, unsigned c, unsigned d) { poly(a, b, c); poly(a, c, d); } void poly(unsigned a, unsigned b, unsigned c, unsigned d, unsigned e) { poly(a, b, c, d); poly(a, d, e); } void poly(unsigned a, unsigned b, unsigned c, unsigned d, unsigned e, unsigned f) { poly(a, b, c, d, e); poly(a, e, f); } void poly(unsigned a, unsigned b, unsigned c, unsigned d, unsigned e, unsigned f, unsigned g) { poly(a, b, c, d, e, f); poly(a, f, g); } void poly(unsigned a, unsigned b, unsigned c, unsigned d, unsigned e, unsigned f, unsigned g, unsigned h) { poly(a, b, c, d, e, f, g); poly(a, g, h); } }; struct mesh { ID3D11InputLayout* layout; ID3D11Buffer* buffer; D3D11_PRIMITIVE_TOPOLOGY topology; unsigned vertex_size; unsigned draw_count; DXGI_FORMAT index_format; unsigned index_offset; mesh(ID3D11Device* dev, D3D11_PRIMITIVE_TOPOLOGY topology, const D3D11_INPUT_ELEMENT_DESC *elements, unsigned num_elements, const void* vs, unsigned vs_size, const void* vertices, unsigned vertex_size, unsigned num_vertices, const void* indices = 0, unsigned index_size = 0, unsigned num_indices = 0) : topology(topology), vertex_size(vertex_size), draw_count(index_size ? num_indices : num_vertices) { dev->CreateInputLayout(elements, num_elements, vs, vs_size, &layout); if(index_size == 2) index_format = DXGI_FORMAT_R16_UINT; else if(index_size == 4) index_format = DXGI_FORMAT_R32_UINT; else index_format = DXGI_FORMAT_UNKNOWN; this->vertex_size = vertex_size; index_offset = vertex_size * num_vertices; D3D11_BUFFER_DESC bufferd; memset(&bufferd, 0, sizeof(bufferd)); bufferd.Usage = D3D11_USAGE_IMMUTABLE; bufferd.BindFlags = D3D11_BIND_VERTEX_BUFFER; if(index_format) bufferd.BindFlags |= D3D11_BIND_INDEX_BUFFER; bufferd.ByteWidth = index_offset + index_format * num_indices; char* data = (char*)malloc(bufferd.ByteWidth); memcpy(data, vertices, vertex_size * num_vertices); memcpy(data + index_offset, indices, index_size * num_indices); D3D11_SUBRESOURCE_DATA buffersd; buffersd.pSysMem = data; ensure(dev->CreateBuffer(&bufferd, &buffersd, &buffer)); free(data); } ~mesh() { layout->Release(); buffer->Release(); } void bind(ID3D11DeviceContext* ctx) { unsigned offset = 0; ctx->IASetPrimitiveTopology(topology); ctx->IASetInputLayout(layout); if(index_format) ctx->IASetIndexBuffer(buffer, index_format, index_offset); ctx->IASetVertexBuffers(0, 1, &buffer, &vertex_size, &offset); } void draw_bound(ID3D11DeviceContext* ctx) { if(index_format) ctx->DrawIndexed(draw_count, 0, 0); else ctx->Draw(draw_count, 0); } void bind_and_draw(ID3D11DeviceContext* ctx) { bind(ctx); draw_bound(ctx); } }; mesh* create_tex_quad(ID3D11Device* dev, const BYTE* vs, unsigned vs_size) { float quad_data[] = { -1, -1, 0, 1, -1, 1, 0, 0, 1, -1, 1, 1, 1, 1, 1, 0, }; D3D11_INPUT_ELEMENT_DESC elements[2] = { {"POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0}, {"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 8, D3D11_INPUT_PER_VERTEX_DATA, 0}, }; return new mesh(dev, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP, elements, 2, vs, vs_size, quad_data, 4 * sizeof(float), 4, 0, 0, 0); } struct d3d11_blitter { mesh* quad; ID3D11VertexShader* vs; ID3D11PixelShader* ps; ID3D11SamplerState* sampler[2]; d3d11_blitter(ID3D11Device* dev) { quad = create_tex_quad(dev, g_vs_blit, sizeof(g_vs_blit)); dev->CreateVertexShader(g_vs_blit, sizeof(g_vs_blit), 0, &vs); dev->CreatePixelShader(g_ps_blit, sizeof(g_ps_blit), 0, &ps); for(unsigned i = 0; i < 2; ++i) { D3D11_SAMPLER_DESC samplerd; memset(&samplerd, 0, sizeof(samplerd)); samplerd.Filter = i ? D3D11_FILTER_MIN_MAG_MIP_LINEAR : D3D11_FILTER_MIN_MAG_MIP_LINEAR; samplerd.AddressU = samplerd.AddressV = samplerd.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP; dev->CreateSamplerState(&samplerd, &sampler[i]); } } void bind(ID3D11DeviceContext* ctx, ID3D11ShaderResourceView* srv, ID3D11RenderTargetView* rtv, float x, float y, float width, float height, bool linear) { D3D11_VIEWPORT vp; vp.TopLeftX = x; vp.TopLeftY = y; vp.Width = width; vp.Height = height; vp.MinDepth = 0; vp.MaxDepth = 1; ctx->RSSetViewports(1, &vp); ctx->RSSetState(0); ctx->OMSetBlendState(0, 0, ~0); ctx->OMSetDepthStencilState(0, 0); ctx->OMSetRenderTargets(1, &rtv, 0); ctx->VSSetShader(vs, 0, 0); ctx->PSSetShader(ps, 0, 0); ctx->PSSetShaderResources(0, 1, &srv); ctx->PSSetSamplers(0, 1, &sampler[!!linear]); quad->bind(ctx); } void draw_bound(ID3D11DeviceContext* ctx) { quad->draw_bound(ctx); } void bind_draw_and_unbind(ID3D11DeviceContext* ctx, ID3D11ShaderResourceView* srv, ID3D11RenderTargetView* rtv, float x, float y, float width, float height, bool linear) { bind(ctx, srv, rtv, x, y, width, height, linear); draw_bound(ctx); unbind(ctx); } void unbind(ID3D11DeviceContext* ctx) { void* null = 0; ctx->PSSetShaderResources(0, 1, (ID3D11ShaderResourceView**)&null); ctx->PSSetSamplers(0, 1, (ID3D11SamplerState**)&null); } }; template struct vec_t { T v[n]; T& operator [](unsigned i) { return v[i]; } const T& operator [](unsigned i) const { return v[i]; } }; template vec_t operator -(const vec_t a) { vec_t r; for(unsigned i = 0; i < n; ++i) r[i] = -a[i]; return r; } template vec_t operator +(const vec_t& a, const vec_t& b) { vec_t r; for(unsigned i = 0; i < n; ++i) r[i] = a[i] + b[i]; return r; } template vec_t& operator +=(vec_t& a, const vec_t& b) { for(unsigned i = 0; i < n; ++i) a[i] += b[i]; return a; } template struct mat_t : public vec_t, c> {}; template vec_t operator *(const vec_t& a, const T& b) { vec_t r; for(unsigned i = 0; i < n; ++i) r[i] = a[i] * b; return r; } template vec_t operator *(const T& b, const vec_t& a) { vec_t r; for(unsigned i = 0; i < n; ++i) r[i] = a[i] * b; return r; } template vec_t operator *(const mat_t& m, const vec_t& b) { vec_t r; r = m[0] * b[0]; for(unsigned i = 1; i < d; ++i) r += m[i] * b[i]; return r; } template mat_t operator *(const mat_t& m, const mat_t& b) { mat_t r; for(unsigned i = 0; i < d; ++i) r[i] = m * b[i]; return r; } template vec_t vec(T a, T b, T c) { vec_t v; v[0] = a; v[1] = b; v[2] = c; return v; } template vec_t vec(T a, T b, T c, T d) { vec_t v; v[0] = a; v[1] = b; v[2] = c; v[3] = d; return v; } typedef mat_t float4x4; typedef mat_t float4x3; typedef mat_t float3x4; typedef mat_t float3x3; typedef vec_t float3; typedef vec_t float4; template mat_t mat4x4_frustum(T left, T right, T bottom, T top, T nearval, T farval) { T x = (2.0f * nearval) / (right - left); T y = (2.0f * nearval) / (top - bottom); T a = (right + left) / (right - left); T b = (top + bottom) / (top - bottom); T c = -(farval + nearval) / (farval - nearval); T d = -(2.0f * farval * nearval) / (farval - nearval); T _0 = (T)0; mat_t m; m[0] = vec(x, _0, _0, _0); m[1] = vec(_0, y, _0, _0); m[2] = vec(a, b, c, (T)-1); m[3] = vec(_0, _0, d, _0); return m; } template mat_t mat3x3_diag(T v) { mat_t m; T _0 = (T)0; m[0] = vec(v, _0, _0); m[1] = vec(_0, v, _0); m[2] = vec(_0, _0, v); return m; } template mat_t mat4x4_diag(T v) { mat_t m; T _0 = (T)0; m[0] = vec(v, _0, _0, _0); m[1] = vec(_0, v, _0, _0); m[2] = vec(_0, _0, v, _0); m[3] = vec(_0, _0, _0, v); return m; } template mat_t mat_push_rotate(const mat_t& m, unsigned axis, T angle) { T s = (T)sin(angle); T c = (T)cos(angle); mat_t r = m; unsigned a = (axis + 1) % 3; unsigned b = (axis + 2) % 3; r[a] = (m[a] * c) + (m[b] * s); r[b] = -(m[a] * s) + (m[b] * c); return r; } template mat_t mat_push_translate(const mat_t& m, float x, float y, float z) { mat_t r = m; vec_t v; v[0] = x; v[1] = y; v[2] = z; if(n >= 4) v[3] = (T)0; r[3] += m * v; return r; }