1 /**************************************************************************
2  *
3  * Copyright 2010 Luca Barbieri
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining
6  * a copy of this software and associated documentation files (the
7  * "Software"), to deal in the Software without restriction, including
8  * without limitation the rights to use, copy, modify, merge, publish,
9  * distribute, sublicense, and/or sell copies of the Software, and to
10  * permit persons to whom the Software is furnished to do so, subject to
11  * the following conditions:
12  *
13  * The above copyright notice and this permission notice (including the
14  * next paragraph) shall be included in all copies or substantial
15  * portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20  * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
21  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24  *
25  **************************************************************************/
26 
27 #include <vector>
28 
29 #include "d3d11blit.hlsl.ps.h"
30 #include "d3d11blit.hlsl.vs.h"
31 
32 template<typename index_type = unsigned>
33 struct triangle_list_indices : public std::vector<index_type>
34 {
35 	unsigned base;
36 	bool flip;
37 
triangle_list_indicestriangle_list_indices38 	triangle_list_indices()
39 	: base(0), flip(false)
40 	{}
41 
polytriangle_list_indices42 	void poly(unsigned a, unsigned b, unsigned c)
43 	{
44 		this->push_back(base + a);
45 		this->push_back(base + (flip ? c : b));
46 		this->push_back(base + (flip ? b : c));
47 	}
48 
polytriangle_list_indices49 	void poly(unsigned a, unsigned b, unsigned c, unsigned d)
50 	{
51 		poly(a, b, c);
52 		poly(a, c, d);
53 	}
54 
polytriangle_list_indices55 	void poly(unsigned a, unsigned b, unsigned c, unsigned d, unsigned e)
56 	{
57 		poly(a, b, c, d);
58 		poly(a, d, e);
59 	}
60 
polytriangle_list_indices61 	void poly(unsigned a, unsigned b, unsigned c, unsigned d, unsigned e, unsigned f)
62 	{
63 		poly(a, b, c, d, e);
64 		poly(a, e, f);
65 	}
66 
polytriangle_list_indices67 	void poly(unsigned a, unsigned b, unsigned c, unsigned d, unsigned e, unsigned f, unsigned g)
68 	{
69 		poly(a, b, c, d, e, f);
70 		poly(a, f, g);
71 	}
72 
polytriangle_list_indices73 	void poly(unsigned a, unsigned b, unsigned c, unsigned d, unsigned e, unsigned f, unsigned g, unsigned h)
74 	{
75 		poly(a, b, c, d, e, f, g);
76 		poly(a, g, h);
77 	}
78 };
79 
80 struct mesh
81 {
82 	ID3D11InputLayout* layout;
83 	ID3D11Buffer* buffer;
84 	D3D11_PRIMITIVE_TOPOLOGY topology;
85 	unsigned vertex_size;
86 	unsigned draw_count;
87 	DXGI_FORMAT index_format;
88 	unsigned index_offset;
89 
90 	mesh(ID3D11Device* dev, D3D11_PRIMITIVE_TOPOLOGY topology,
91 		const D3D11_INPUT_ELEMENT_DESC *elements, unsigned num_elements,
92 		const void* vs, unsigned vs_size,
93 		const void* vertices, unsigned vertex_size, unsigned num_vertices,
94 		const void* indices = 0, unsigned index_size = 0, unsigned num_indices = 0)
topologymesh95 		: topology(topology), vertex_size(vertex_size), draw_count(index_size ? num_indices : num_vertices)
96 	{
97 		dev->CreateInputLayout(elements, num_elements, vs, vs_size, &layout);
98 		if(index_size == 2)
99 			index_format = DXGI_FORMAT_R16_UINT;
100 		else if(index_size == 4)
101 			index_format = DXGI_FORMAT_R32_UINT;
102 		else
103 			index_format = DXGI_FORMAT_UNKNOWN;
104 		this->vertex_size = vertex_size;
105 		index_offset = vertex_size * num_vertices;
106 
107 	 	D3D11_BUFFER_DESC bufferd;
108 		memset(&bufferd, 0, sizeof(bufferd));
109 		bufferd.Usage = D3D11_USAGE_IMMUTABLE;
110 		bufferd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
111 		if(index_format)
112 			bufferd.BindFlags |= D3D11_BIND_INDEX_BUFFER;
113 		bufferd.ByteWidth = index_offset + index_format * num_indices;
114 
115 		char* data = (char*)malloc(bufferd.ByteWidth);
116 		memcpy(data, vertices, vertex_size * num_vertices);
117 		memcpy(data + index_offset, indices, index_size * num_indices);
118 
119 		D3D11_SUBRESOURCE_DATA buffersd;
120 		buffersd.pSysMem = data;
121 
122 		ensure(dev->CreateBuffer(&bufferd, &buffersd, &buffer));
123 		free(data);
124 	}
125 
~meshmesh126 	~mesh()
127 	{
128 		layout->Release();
129 		buffer->Release();
130 	}
131 
bindmesh132 	void bind(ID3D11DeviceContext* ctx)
133 	{
134 		unsigned offset = 0;
135 		ctx->IASetPrimitiveTopology(topology);
136 		ctx->IASetInputLayout(layout);
137 		if(index_format)
138 			ctx->IASetIndexBuffer(buffer, index_format, index_offset);
139 		ctx->IASetVertexBuffers(0, 1, &buffer, &vertex_size, &offset);
140 	}
141 
draw_boundmesh142 	void draw_bound(ID3D11DeviceContext* ctx)
143 	{
144 		if(index_format)
145 			ctx->DrawIndexed(draw_count, 0, 0);
146 		else
147 			ctx->Draw(draw_count, 0);
148 	}
149 
bind_and_drawmesh150 	void bind_and_draw(ID3D11DeviceContext* ctx)
151 	{
152 		bind(ctx);
153 		draw_bound(ctx);
154 	}
155 };
156 
create_tex_quad(ID3D11Device * dev,const BYTE * vs,unsigned vs_size)157 mesh* create_tex_quad(ID3D11Device* dev, const BYTE* vs, unsigned vs_size)
158 {
159 	float quad_data[] = {
160 		-1, -1, 0, 1,
161 		-1, 1, 0, 0,
162 		1, -1, 1, 1,
163 		1, 1, 1, 0,
164 	};
165 
166 	D3D11_INPUT_ELEMENT_DESC elements[2] =
167 	{
168 		{"POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0},
169 		{"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 8, D3D11_INPUT_PER_VERTEX_DATA, 0},
170 	};
171 
172 	return new mesh(dev, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP,
173 		elements, 2,
174 		vs, vs_size,
175 		quad_data, 4 * sizeof(float), 4,
176 		0, 0, 0);
177 }
178 
179 struct d3d11_blitter
180 {
181 	mesh* quad;
182 	ID3D11VertexShader* vs;
183 	ID3D11PixelShader* ps;
184 	ID3D11SamplerState* sampler[2];
185 
d3d11_blitterd3d11_blitter186 	d3d11_blitter(ID3D11Device* dev)
187 	{
188 		quad = create_tex_quad(dev, g_vs_blit, sizeof(g_vs_blit));
189 
190 		dev->CreateVertexShader(g_vs_blit, sizeof(g_vs_blit), 0, &vs);
191 		dev->CreatePixelShader(g_ps_blit, sizeof(g_ps_blit), 0, &ps);
192 
193 		for(unsigned i = 0; i < 2; ++i)
194 		{
195 			D3D11_SAMPLER_DESC samplerd;
196 			memset(&samplerd, 0, sizeof(samplerd));
197 			samplerd.Filter = i ? D3D11_FILTER_MIN_MAG_MIP_LINEAR : D3D11_FILTER_MIN_MAG_MIP_LINEAR;
198 			samplerd.AddressU = samplerd.AddressV = samplerd.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
199 			dev->CreateSamplerState(&samplerd, &sampler[i]);
200 		}
201 	}
202 
bindd3d11_blitter203 	void bind(ID3D11DeviceContext* ctx, ID3D11ShaderResourceView* srv, ID3D11RenderTargetView* rtv, float x, float y, float width, float height, bool linear)
204 	{
205 		D3D11_VIEWPORT vp;
206 		vp.TopLeftX = x;
207 		vp.TopLeftY = y;
208 		vp.Width = width;
209 		vp.Height = height;
210 		vp.MinDepth = 0;
211 		vp.MaxDepth = 1;
212 		ctx->RSSetViewports(1, &vp);
213 		ctx->RSSetState(0);
214 		ctx->OMSetBlendState(0, 0, ~0);
215 		ctx->OMSetDepthStencilState(0, 0);
216 		ctx->OMSetRenderTargets(1, &rtv, 0);
217 		ctx->VSSetShader(vs, 0, 0);
218 		ctx->PSSetShader(ps, 0, 0);
219 		ctx->PSSetShaderResources(0, 1, &srv);
220 		ctx->PSSetSamplers(0, 1, &sampler[!!linear]);
221 		quad->bind(ctx);
222 	}
223 
draw_boundd3d11_blitter224 	void draw_bound(ID3D11DeviceContext* ctx)
225 	{
226 		quad->draw_bound(ctx);
227 	}
228 
bind_draw_and_unbindd3d11_blitter229 	void bind_draw_and_unbind(ID3D11DeviceContext* ctx, ID3D11ShaderResourceView* srv, ID3D11RenderTargetView* rtv, float x, float y, float width, float height, bool linear)
230 	{
231 		bind(ctx, srv, rtv, x, y, width, height, linear);
232 		draw_bound(ctx);
233 		unbind(ctx);
234 	}
235 
unbindd3d11_blitter236 	void unbind(ID3D11DeviceContext* ctx)
237 	{
238 		void* null = 0;
239 		ctx->PSSetShaderResources(0, 1, (ID3D11ShaderResourceView**)&null);
240 		ctx->PSSetSamplers(0, 1, (ID3D11SamplerState**)&null);
241 	}
242 };
243 
244 template<typename T, unsigned n>
245 struct vec_t
246 {
247 	T v[n];
248 
249 	T& operator [](unsigned i)
250 	{
251 		return v[i];
252 	}
253 
254 	const T& operator [](unsigned i) const
255 	{
256 		return v[i];
257 	}
258 };
259 
260 template<typename T, unsigned n>
261 vec_t<T, n> operator -(const vec_t<T, n> a)
262 {
263 	vec_t<T, n> r;
264 	for(unsigned i = 0; i < n; ++i)
265 		r[i] = -a[i];
266 	return r;
267 }
268 
269 template<typename T, unsigned n>
270 vec_t<T, n> operator +(const vec_t<T, n>& a, const vec_t<T, n>& b)
271 {
272 	vec_t<T, n> r;
273 	for(unsigned i = 0; i < n; ++i)
274 		r[i] = a[i] + b[i];
275 	return r;
276 }
277 
278 template<typename T, unsigned n>
279 vec_t<T, n>& operator +=(vec_t<T, n>& a, const vec_t<T, n>& b)
280 {
281 	for(unsigned i = 0; i < n; ++i)
282 		a[i] += b[i];
283 	return a;
284 }
285 
286 template<typename T, unsigned r, unsigned c>
287 struct mat_t : public vec_t<vec_t<T, r>, c>
288 {};
289 
290 template<typename T, unsigned n>
291 vec_t<T, n> operator *(const vec_t<T, n>& a, const T& b)
292 {
293 	vec_t<T, n> r;
294 	for(unsigned i = 0; i < n; ++i)
295 		r[i] = a[i] * b;
296 	return r;
297 }
298 
299 template<typename T, unsigned n>
300 vec_t<T, n> operator *(const T& b, const vec_t<T, n>& a)
301 {
302 	vec_t<T, n> r;
303 	for(unsigned i = 0; i < n; ++i)
304 		r[i] = a[i] * b;
305 	return r;
306 }
307 
308 template<typename T, unsigned d, unsigned e>
309 vec_t<T, e> operator *(const mat_t<T, e, d>& m, const vec_t<T, d>& b)
310 {
311 	vec_t<T, e> r;
312 	r = m[0] * b[0];
313 	for(unsigned i = 1; i < d; ++i)
314 		r += m[i] * b[i];
315 	return r;
316 }
317 
318 template<typename T, unsigned d, unsigned e, unsigned f>
319 mat_t<T, e, f> operator *(const mat_t<T, e, d>& m, const mat_t<T, d, f>& b)
320 {
321 	mat_t<T, e, f> r;
322 	for(unsigned i = 0; i < d; ++i)
323 		r[i] = m * b[i];
324 	return r;
325 }
326 
327 template<typename T>
vec(T a,T b,T c)328 vec_t<T, 3> vec(T a, T b, T c)
329 {
330 	vec_t<T, 4> v;
331 	v[0] = a;
332 	v[1] = b;
333 	v[2] = c;
334 	return v;
335 }
336 
337 template<typename T>
vec(T a,T b,T c,T d)338 vec_t<T, 4> vec(T a, T b, T c, T d)
339 {
340 	vec_t<T, 4> v;
341 	v[0] = a;
342 	v[1] = b;
343 	v[2] = c;
344 	v[3] = d;
345 	return v;
346 }
347 
348 typedef mat_t<float, 4, 4> float4x4;
349 typedef mat_t<float, 4, 3> float4x3;
350 typedef mat_t<float, 3, 4> float3x4;
351 typedef mat_t<float, 3, 3> float3x3;
352 
353 typedef vec_t<float, 3> float3;
354 typedef vec_t<float, 4> float4;
355 
356 template<typename T>
mat4x4_frustum(T left,T right,T bottom,T top,T nearval,T farval)357 mat_t<T, 4, 4> mat4x4_frustum(T left, T right, T bottom, T top, T nearval, T farval)
358 {
359 	T x = (2.0f * nearval) / (right - left);
360 	T y = (2.0f * nearval) / (top - bottom);
361 	T a = (right + left) / (right - left);
362 	T b = (top + bottom) / (top - bottom);
363 	T c = -(farval + nearval) / (farval - nearval);
364 	T d = -(2.0f * farval * nearval) / (farval - nearval);
365 	T _0 = (T)0;
366 
367 	mat_t<T, 4, 4> m;
368 	m[0] = vec(x, _0, _0, _0);
369 	m[1] = vec(_0, y, _0, _0);
370 	m[2] = vec(a, b, c, (T)-1);
371 	m[3] = vec(_0, _0, d, _0);
372 	return m;
373 }
374 
375 template<typename T>
mat3x3_diag(T v)376 mat_t<T, 3, 3> mat3x3_diag(T v)
377 {
378 	mat_t<T, 3, 3> m;
379 	T _0 = (T)0;
380 	m[0] = vec(v, _0, _0);
381 	m[1] = vec(_0, v, _0);
382 	m[2] = vec(_0, _0, v);
383 	return m;
384 }
385 
386 template<typename T>
mat4x4_diag(T v)387 mat_t<T, 4, 4> mat4x4_diag(T v)
388 {
389 	mat_t<T, 4, 4> m;
390 	T _0 = (T)0;
391 	m[0] = vec(v, _0, _0, _0);
392 	m[1] = vec(_0, v, _0, _0);
393 	m[2] = vec(_0, _0, v, _0);
394 	m[3] = vec(_0, _0, _0, v);
395 	return m;
396 }
397 
398 template<typename T, unsigned n>
mat_push_rotate(const mat_t<T,n,n> & m,unsigned axis,T angle)399 mat_t<T, n, n> mat_push_rotate(const mat_t<T, n, n>& m, unsigned axis, T angle)
400 {
401 	T s = (T)sin(angle);
402 	T c = (T)cos(angle);
403 
404 	mat_t<T, n, n> r = m;
405 	unsigned a = (axis + 1) % 3;
406 	unsigned b = (axis + 2) % 3;
407 	r[a] = (m[a] * c) + (m[b] * s);
408 	r[b] = -(m[a] * s) + (m[b] * c);
409 	return r;
410 }
411 
412 template<typename T, unsigned n>
mat_push_translate(const mat_t<T,n,n> & m,float x,float y,float z)413 mat_t<T, n, n> mat_push_translate(const mat_t<T, n, n>& m, float x, float y, float z)
414 {
415 	mat_t<T, n, n> r = m;
416 	vec_t<T, n> v;
417 	v[0] = x;
418 	v[1] = y;
419 	v[2] = z;
420 	if(n >= 4)
421 		v[3] = (T)0;
422 	r[3] += m * v;
423 	return r;
424 }
425