Home | History | Annotate | Download | only in d3d11gears
      1 /*
      2 * Copyright (C) 1999-2001 Brian Paul All Rights Reserved.
      3 * Copyright (C) 2009-2010 Luca Barbieri All Rights Reserved.
      4 *
      5 * Permission is hereby granted, free of charge, to any person obtaining a
      6 * copy of this software and associated documentation files (the "Software"),
      7 * to deal in the Software without restriction, including without limitation
      8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      9 * and/or sell copies of the Software, and to permit persons to whom the
     10 * Software is furnished to do so, subject to the following conditions:
     11 *.
     12 * The above copyright notice and this permission notice shall be included
     13 * in all copies or substantial portions of the Software.
     14 *
     15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     16 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
     18 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
     19 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
     20 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     21 */
     22 
     23 /*
     24 * This is a port of the infamous "glxgears" demo to straight EGL
     25 * Port by Dane Rushton 10 July 2005
     26 *
     27 * This a rewrite of the 'eglgears' demo in straight Gallium
     28 * Port by Luca Barbieri
     29 *
     30 * This a port of the 'galliumgears' demo to Direct3D 11
     31 * Port by Luca Barbieri
     32 */
     33 
     34 #define _USE_MATH_DEFINES
     35 #include "d3d11app.h"
     36 #include "d3d11u.h"
     37 #include "d3d11gears.hlsl.ps.h"
     38 #include "d3d11gears.hlsl.vs.h"
     39 
     40 #include <stdlib.h>
     41 #include <stdio.h>
     42 #include <math.h>
     43 #include <float.h>
     44 
     45 struct gear
     46 {
     47 	struct mesh* mesh;
     48 	float x;
     49 	float y;
     50 	float t0;
     51 	float wmul;
     52 	float4 color;
     53 };
     54 
     55 struct cbuf_t
     56 {
     57 	float4x4 projection;
     58 	float4x4 modelview;
     59 	float4 light;
     60 	float4 diffuse;
     61 	float4 specular;
     62 	float specular_power;
     63 	float padding[3];
     64 };
     65 
     66 struct gear gears[3];
     67 
     68 struct vertex
     69 {
     70 	float position[3];
     71 	float normal[3];
     72 
     73 	vertex(float x, float y, float z, float nx, float ny, float nz)
     74 	{
     75 		position[0] = x;
     76 		position[1] = y;
     77 		position[2] = z;
     78 		normal[0] = nx;
     79 		normal[1] = ny;
     80 		normal[2] = nz;
     81 	}
     82 };
     83 
     84 #define VERT(x, y, z) vertices.push_back(vertex((x), (y), (z), (nx), (ny), (nz)))
     85 
     86 static mesh* build_gear(ID3D11Device* dev, int triangle_budget, float inner_radius, float outer_radius, float width, int teeth, float tooth_depth)
     87 {
     88 	int i, j, k;
     89 	float r0, r1, r2;
     90 	float da;
     91 	float nx, ny, nz;
     92 	int face;
     93 	int segs = 4;
     94 	int base_triangles = teeth * segs * 2 * 2;
     95 	int divs0 = (triangle_budget / base_triangles) - 1;
     96 	int divs = (divs0 > 0) ? divs0 : 1;
     97 	float* c = (float*)malloc(teeth * segs * sizeof(float));
     98 	float* s = (float*)malloc(teeth * segs * sizeof(float));
     99 	float* dc = (float*)malloc(teeth * segs * divs * sizeof(float));
    100 	float* ds = (float*)malloc(teeth * segs * divs * sizeof(float));
    101 	int num_vertices = teeth * segs * 2 * (3 + 2 * divs);
    102 	int num_triangles = base_triangles * (1 + divs);
    103 	printf("Creating gear with %i teeth using %i vertices used in %i triangles\n", teeth, num_vertices, num_triangles);
    104 	triangle_list_indices<> indices;
    105 	std::vector<vertex> vertices;
    106 
    107 	r0 = inner_radius;
    108 	r1 = outer_radius - tooth_depth / 2.0f;
    109 	r2 = outer_radius + tooth_depth / 2.0f;
    110 
    111 	da = (float)(2.0 * M_PI / (teeth * segs * divs));
    112 	for(i = 0; i < teeth * segs * divs; ++i) {
    113 		float angle = da * i;
    114 		ds[i] = sin(angle);
    115 		dc[i] = cos(angle);
    116 	}
    117 
    118 	for(i = 0; i < teeth * segs; ++i) {
    119 		s[i] = ds[i * divs];
    120 		c[i] = dc[i * divs];
    121 	}
    122 
    123 	/* faces */
    124 	for(face = -1; face <= 1; face += 2) {
    125 		float z = width * face * 0.5f;
    126 		nx = 0.0f;
    127 		ny = 0.0f;
    128 		nz = (float)face;
    129 
    130 		indices.flip = face > 0;
    131 
    132 		assert(segs == 4);
    133 		for(i = 0; i < teeth; ++i) {
    134 			VERT(r1 * c[segs * i], r1 * s[segs * i], z);
    135 			VERT(r2 * c[segs * i + 1], r2 * s[segs * i + 1], z);
    136 			VERT(r2 * c[segs * i + 2], r2 * s[segs * i + 2], z);
    137 			VERT(r1 * c[segs * i + 3], r1 * s[segs * i + 3], z);
    138 		}
    139 
    140 		for(i = 0; i < teeth * segs * divs; ++i) {
    141 			VERT(r0 * dc[i], r0 * ds[i], z);
    142 		}
    143 
    144 		for(i = 0; i < teeth; ++i) {
    145 			for(j = i * segs; j < (i + 1) * segs; ++j) {
    146 				int nextj = j + 1;
    147 				if(nextj == teeth * segs)
    148 					nextj = 0;
    149 
    150 				for(k = j * divs; k < (j + 1) * divs; ++k) {
    151 					int nextk = k + 1;
    152 					if(nextk == teeth * segs * divs)
    153 						nextk = 0;
    154 					indices.poly(teeth * segs + k, j, teeth * segs + nextk);
    155 				}
    156 
    157 				indices.poly(teeth * segs + nextj * divs, j, nextj);
    158 			}
    159 		}
    160 
    161 		indices.base += teeth * segs * (1 + divs);
    162 	}
    163 
    164 	/* teeth faces */
    165 	indices.flip = true;
    166 	float z = width * 0.5f;
    167 
    168 	float* coords = (float*)malloc((segs + 1) * 2 * sizeof(float));
    169 	nz = 0;
    170 	for(i = 0; i < teeth; i++) {
    171 		int next = i + 1;
    172 		if(next == teeth)
    173 			next = 0;
    174 
    175 		coords[0] = r1 * c[segs * i];
    176 		coords[1] = r1 * s[segs * i];
    177 		coords[2] = r2 * c[segs * i + 1];
    178 		coords[3] = r2 * s[segs * i + 1];
    179 		coords[4] = r2 * c[segs * i + 2];
    180 		coords[5] = r2 * s[segs * i + 2];
    181 		coords[6] = r1 * c[segs * i + 3];
    182 		coords[7] = r1 * s[segs * i + 3];
    183 		coords[8] = r1 * c[segs * next];
    184 		coords[9] = r1 * s[segs * next];
    185 
    186 		for(int j = 0; j < segs; ++j) {
    187 			float dx = coords[j * 2] - coords[j * 2 + 2];
    188 			float dy = coords[j * 2 + 1] - coords[j * 2 + 3];
    189 			float len = hypotf(dx, dy);
    190 			nx = -dy / len;
    191 			ny = dx / len;
    192 			VERT(coords[j * 2], coords[j * 2 + 1], z);
    193 			VERT(coords[j * 2], coords[j * 2 + 1], -z);
    194 			VERT(coords[j * 2 + 2], coords[j * 2 + 3], z);
    195 			VERT(coords[j * 2 + 2], coords[j * 2 + 3], -z);
    196 
    197 			indices.poly(0, 1, 3, 2);
    198 			indices.base += 4;
    199 		}
    200 	}
    201 	free(coords);
    202 
    203 	/* inner part - simulate a cylinder */
    204 	indices.flip = true;
    205 	for(i = 0; i < teeth * segs * divs; i++) {
    206 		int next = i + 1;
    207 		if(next == teeth * segs * divs)
    208 			next = 0;
    209 
    210 		nx = -dc[i];
    211 		ny = -ds[i];
    212 		VERT(r0 * dc[i], r0 * ds[i], -width * 0.5f);
    213 		VERT(r0 * dc[i], r0 * ds[i], width * 0.5f);
    214 
    215 		indices.poly(i * 2, i * 2 + 1, next * 2 + 1, next * 2);
    216 	}
    217 
    218 	indices.base += teeth * segs * divs * 2;
    219 	free(c);
    220 	free(s);
    221 	free(dc);
    222 	free(ds);
    223 
    224 	D3D11_INPUT_ELEMENT_DESC elements[2] =
    225 	{
    226 		{"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0},
    227 		{"NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0},
    228 	};
    229 
    230 	return new mesh(dev, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST,
    231 		elements, 2,
    232 		g_vs, sizeof(g_vs),
    233 		&vertices[0], sizeof(vertices[0]), vertices.size(),
    234 		&indices[0], sizeof(indices[0]), indices.size());
    235 }
    236 
    237 struct d3d11gears : public d3d11_application
    238 {
    239 	float view_rotx;
    240 	float view_roty;
    241 	float view_rotz;
    242 	int wireframe;
    243 	int triangles;
    244 	float speed;
    245 	float period;
    246 	unsigned impressions;
    247 	bool blue_only;
    248 
    249 	float last_time;
    250 
    251 	int cur_width;
    252 	int cur_height;
    253 
    254 	ID3D11DepthStencilView* zsv;
    255 	ID3D11RenderTargetView* offscreen_rtv;
    256 	ID3D11ShaderResourceView* offscreen_srv;
    257 
    258 	ID3D11Device* dev;
    259 	ID3D11BlendState* blend;
    260 	ID3D11DepthStencilState* zsa;
    261 
    262 	ID3D11PixelShader* ps;
    263 	ID3D11VertexShader* vs;
    264 	ID3D11Buffer* cb;
    265 
    266 	d3d11_blitter* blitter;
    267 
    268 	d3d11gears()
    269 		: cur_width(-1), cur_height(-1), zsv(0), offscreen_rtv(0), offscreen_srv(0)
    270 	{
    271 		view_rotx = (float)(M_PI / 9.0);
    272 		view_roty = (float)(M_PI / 6.0);
    273 		view_rotz = 0.0f;
    274 		wireframe = 0;
    275 		triangles = 3200;
    276 		speed = 1.0f;
    277 		period = -1.0f;
    278 		impressions = 1;
    279 		blue_only = false;
    280 	}
    281 
    282 	void draw_one(ID3D11DeviceContext* ctx, cbuf_t& cbd, const float4x4& modelview, float angle)
    283 	{
    284 		for(unsigned i = blue_only ? 2 : 0; i < 3; ++i)
    285 		{
    286 			float4x4 m2 = modelview;
    287 			m2 = mat_push_translate(m2, gears[i].x, gears[i].y, 0.0f);
    288 			m2 = mat_push_rotate(m2, 2, angle * gears[i].wmul + gears[i].t0);
    289 
    290 			cbd.modelview = m2;
    291 			cbd.diffuse = gears[i].color;
    292 			cbd.specular = gears[i].color;
    293 			cbd.specular_power = 5.0f;
    294 
    295 			ctx->UpdateSubresource(cb, 0, 0, &cbd, 0, 0);
    296 
    297 			gears[i].mesh->bind_and_draw(ctx);
    298 		}
    299 	}
    300 
    301 	float get_angle(double time)
    302 	{
    303 		// designed so that 1 = original glxgears speed
    304 		float mod_speed = M_PI * 70.0f / 180.0f * speed;
    305 		if(period < 0)
    306 			return (float)(time * mod_speed);
    307 		else
    308 			return (float)(cos(time / period) * period * mod_speed);
    309 	}
    310 
    311 	void init_for_dimensions(unsigned width, unsigned height)
    312 	{
    313 		if(zsv)
    314 			zsv->Release();
    315 		ID3D11Texture2D* zsbuf;
    316 		D3D11_TEXTURE2D_DESC zsbufd;
    317 		memset(&zsbufd, 0, sizeof(zsbufd));
    318 		zsbufd.Width = width;
    319 		zsbufd.Height = height;
    320 		zsbufd.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
    321 		zsbufd.ArraySize = 1;
    322 		zsbufd.MipLevels = 1;
    323 		zsbufd.SampleDesc.Count = 1;
    324 		zsbufd.BindFlags = D3D11_BIND_DEPTH_STENCIL;
    325 		ensure(dev->CreateTexture2D(&zsbufd, 0, &zsbuf));
    326 		ensure(dev->CreateDepthStencilView(zsbuf, 0, &zsv));
    327 		zsbuf->Release();
    328 
    329 		ID3D11Texture2D* offscreen;
    330 		if(offscreen_rtv)
    331 		{
    332 			offscreen_rtv->Release();
    333 			offscreen_srv->Release();
    334 			offscreen_rtv = 0;
    335 			offscreen_srv = 0;
    336 		}
    337 
    338 		if(impressions > 1)
    339 		{
    340 			DXGI_FORMAT formats[] = {
    341 				DXGI_FORMAT_R32G32B32A32_FLOAT,
    342 				DXGI_FORMAT_R16G16B16A16_UNORM,
    343 				DXGI_FORMAT_R16G16B16A16_FLOAT,
    344 				DXGI_FORMAT_R10G10B10A2_UNORM,
    345 			};
    346 			DXGI_FORMAT format = DXGI_FORMAT_R8G8B8A8_UNORM; // this won't work well at all
    347 			unsigned needed_support = D3D11_FORMAT_SUPPORT_RENDER_TARGET | D3D11_FORMAT_SUPPORT_BLENDABLE | D3D11_FORMAT_SUPPORT_SHADER_SAMPLE;
    348 			for(unsigned i = 0; i < sizeof(formats); ++i)
    349 			{
    350 				unsigned support;
    351 				dev->CheckFormatSupport(DXGI_FORMAT_R32G32B32A32_FLOAT, &support);
    352 				if((support & needed_support) == needed_support)
    353 				{
    354 					format = formats[i];
    355 					break;
    356 				}
    357 			}
    358 
    359 
    360 			D3D11_TEXTURE2D_DESC offscreend;
    361 			memset(&offscreend, 0, sizeof(offscreend));
    362 			offscreend.Width = width;
    363 			offscreend.Height = height;
    364 
    365 			offscreend.Format = format;
    366 			offscreend.MipLevels = 1;
    367 			offscreend.ArraySize = 1;
    368 			offscreend.SampleDesc.Count = 1;
    369 			offscreend.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
    370 			ensure(dev->CreateTexture2D(&offscreend, 0, &offscreen));
    371 			ensure(dev->CreateRenderTargetView(offscreen, 0, &offscreen_rtv));
    372 			ensure(dev->CreateShaderResourceView(offscreen, 0, &offscreen_srv));
    373 			offscreen->Release();
    374 		}
    375 
    376 		cur_width = width;
    377 		cur_height = height;
    378 	}
    379 
    380 	void draw(ID3D11DeviceContext* ctx, ID3D11RenderTargetView* rtv, unsigned width, unsigned height, double time)
    381 	{
    382 		D3D11_VIEWPORT vp;
    383 		memset(&vp, 0, sizeof(vp));
    384 		vp.Width = (float)width;
    385 		vp.Height = (float)height;
    386 		vp.MaxDepth = 1.0f;
    387 
    388 		if((int)width != cur_width || (int)height != cur_height)
    389 			init_for_dimensions(width, height);
    390 
    391 		float4 lightpos = vec(5.0f, 5.0f, 10.0f, 0.0f);
    392 		float black[4] = {0.0, 0.0, 0.0, 0};
    393 
    394 		float4x4 proj;
    395 		float4x4 m;
    396 
    397 		float xr = (float)width / (float)height;
    398 		float yr = 1.0f;
    399 		if(xr < 1.0f) {
    400 			yr /= xr;
    401 			xr = 1.0f;
    402 		}
    403 		proj = mat4x4_frustum(-xr, xr, -yr, yr, 5.0f, 60.0f);
    404 
    405 		m = mat4x4_diag(1.0f);
    406 		m = mat_push_translate(m, 0.0f, 0.0f, -40.0f);
    407 		m = mat_push_rotate(m, 0, view_rotx);
    408 		m = mat_push_rotate(m, 1, view_roty);
    409 		m = mat_push_rotate(m, 2, view_rotz);
    410 
    411 		cbuf_t cbd;
    412 
    413 		cbd.projection = proj;
    414 		cbd.light = lightpos;
    415 
    416 		float blend_factor[4] = {1.0f / (float)impressions, 1.0f / (float)impressions, 1.0f / (float)impressions, 1.0f / (float)impressions};
    417 
    418 		ID3D11RenderTargetView* render_rtv;
    419 		if(impressions == 1)
    420 			render_rtv = rtv;
    421 		else
    422 			render_rtv = offscreen_rtv;
    423 
    424 		ctx->RSSetViewports(1, &vp);
    425 		ctx->ClearRenderTargetView(render_rtv, black);
    426 
    427 		ctx->PSSetShader(ps, 0, 0);
    428 		ctx->VSSetShader(vs, 0, 0);
    429 
    430 		ctx->PSSetConstantBuffers(0, 1, &cb);
    431 		ctx->VSSetConstantBuffers(0, 1, &cb);
    432 
    433 		if(impressions == 1)
    434 		{
    435 			ctx->OMSetBlendState(0, 0, ~0);
    436 			ctx->OMSetDepthStencilState(0, 0);
    437 			ctx->OMSetRenderTargets(1, &rtv, zsv);
    438 			ctx->ClearDepthStencilView(zsv, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0, 0);
    439 			draw_one(ctx, cbd, m, get_angle(time));
    440 		}
    441 		else
    442 		{
    443 			ctx->OMSetBlendState(blend, blend_factor, ~0);
    444 
    445 			float time_delta = (float)time - last_time;
    446 			float time_delta_per_impression = time_delta / impressions;
    447 			float base_time = last_time + time_delta_per_impression / 2;
    448 			for(unsigned impression = 0; impression < impressions; ++impression)
    449 			{
    450 				float impression_time = base_time + time_delta_per_impression * impression;
    451 
    452 				ctx->ClearDepthStencilView(zsv, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0, 0);
    453 
    454 				// do early z-pass since we must not write any pixel more than once due to blending
    455 				for(unsigned pass = 0; pass < 2; ++pass)
    456 				{
    457 					if(pass == 0)
    458 					{
    459 						ctx->OMSetRenderTargets(0, 0, zsv);
    460 						ctx->OMSetDepthStencilState(0, 0);
    461 					}
    462 					else
    463 					{
    464 						ctx->OMSetRenderTargets(1, &render_rtv, zsv);
    465 						ctx->OMSetDepthStencilState(zsa, 0);
    466 					}
    467 
    468 					draw_one(ctx, cbd, m, get_angle(impression_time));
    469 				}
    470 			}
    471 
    472 			blitter->bind_draw_and_unbind(ctx, offscreen_srv, rtv, 0, 0, (float)width, (float)height, false);
    473 		}
    474 		last_time = (float)time;
    475 	}
    476 
    477 	bool init(ID3D11Device* dev, int argc, char** argv)
    478 	{
    479 		this->dev = dev;
    480 
    481 		for(char** p = argv + 1; *p; ++p) {
    482 			if(!strcmp(*p, "-w"))
    483 				wireframe = 1;
    484 			else if(!strcmp(*p, "-b"))
    485 				blue_only = true;
    486 			else if(!strcmp(*p, "-t"))
    487 				triangles = atoi(*++p);
    488 			else if(!strcmp(*p, "-m"))
    489 				impressions = (float)atof(*++p);
    490 			else if(!strcmp(*p, "-p"))
    491 				period = (float)atof(*++p);
    492 			else if(!strcmp(*p, "-s"))
    493 				speed = (float)atof(*++p);
    494 			else {
    495 				fprintf(stderr, "Usage: d3d11gears [-v|-w] [-t TRIANGLES]\n");
    496 				fprintf(stderr, "d3d11gears is an enhanced port of glxgears to Direct3D 11\n");
    497 				fprintf(stderr, "\n");
    498 				//fprintf(stderr, "-v\t\tuse per-vertex diffuse-only lighting (classic glxgears look)\n");
    499 				fprintf(stderr, "-w\t\twireframe mode\n");
    500 				fprintf(stderr, "-t TRIANGLES\ttriangle budget (default is 3200)\n");
    501 				fprintf(stderr, "-m IMPRESSIONS\tmotion blur impressions (default is 1)\n");
    502 				fprintf(stderr, "-p PERIOD\tspeed reversal period (default is infinite)\n");
    503 				fprintf(stderr, "-s SPEED\tgear speed (default is 1.0)\n");
    504 				fprintf(stderr, "-b\tonly show blue gear (for faster motion blur)\n");
    505 				return false;
    506 			}
    507 		}
    508 
    509 		ensure(dev->CreatePixelShader(g_ps, sizeof(g_ps), NULL, &ps));
    510 		ensure(dev->CreateVertexShader(g_vs, sizeof(g_vs), NULL, &vs));
    511 
    512 		gears[0].color = vec(0.8f, 0.1f, 0.0f, 1.0f);
    513 		gears[1].color = vec(0.0f, 0.8f, 0.2f, 1.0f);
    514 		gears[2].color = vec(0.2f, 0.2f, 1.0f, 1.0f);
    515 
    516 		gears[0].mesh = build_gear(dev, triangles / 2, 1.0f, 4.0f, 1.0f, 20, 0.7f);
    517 		gears[1].mesh = build_gear(dev, triangles / 4, 0.5f, 2.0f, 2.0f, 10, 0.7f);
    518 		gears[2].mesh = build_gear(dev, triangles / 4, 1.3f, 2.0f, 0.5f, 10, 0.7f);
    519 
    520 		gears[0].x = -3.0f;
    521 		gears[0].y = -2.0f;
    522 		gears[0].wmul = 1.0f;
    523 		gears[0].t0 = 0.0 * M_PI / 180.0f;
    524 
    525 		gears[1].x = 3.1f;
    526 		gears[1].y = -2.0f;
    527 		gears[1].wmul = -2.0f;
    528 		gears[1].t0 = -9.0f * (float)M_PI / 180.0f;
    529 
    530 		gears[2].x = -3.1f;
    531 		gears[2].y = 4.2f;
    532 		gears[2].wmul = -2.0f;
    533 		gears[2].t0 = -25.0f * (float)M_PI / 180.0f;
    534 
    535 		D3D11_BUFFER_DESC bufferd;
    536 		memset(&bufferd, 0, sizeof(bufferd));
    537 		bufferd.ByteWidth = sizeof(cbuf_t);
    538 		bufferd.Usage = D3D11_USAGE_DEFAULT;
    539 		bufferd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
    540 		ensure(dev->CreateBuffer(&bufferd, 0, &cb));
    541 
    542 		if(impressions > 1)
    543 		{
    544 			D3D11_BLEND_DESC blendd;
    545 			memset(&blendd, 0, sizeof(blendd));
    546 			blendd.RenderTarget[0].BlendEnable = TRUE;
    547 			blendd.RenderTarget[0].BlendOp = blendd.RenderTarget[0].BlendOpAlpha
    548 				= D3D11_BLEND_OP_ADD;
    549 			blendd.RenderTarget[0].SrcBlend = blendd.RenderTarget[0].SrcBlendAlpha
    550 				= D3D11_BLEND_BLEND_FACTOR;
    551 			blendd.RenderTarget[0].DestBlend = blendd.RenderTarget[0].DestBlendAlpha
    552 				= D3D11_BLEND_ONE;
    553 			blendd.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
    554 			ensure(dev->CreateBlendState(&blendd, &blend));
    555 
    556 			D3D11_DEPTH_STENCIL_DESC zsad;
    557 			memset(&zsad, 0, sizeof(zsad));
    558 			zsad.DepthEnable = TRUE;
    559 			zsad.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO;
    560 			zsad.DepthFunc = D3D11_COMPARISON_EQUAL;
    561 			ensure(dev->CreateDepthStencilState(&zsad, &zsa));
    562 
    563 			blitter = new d3d11_blitter(dev);
    564 		}
    565 
    566 		return true;
    567 	}
    568 };
    569 
    570 d3d11_application* d3d11_application_create()
    571 {
    572 	return new d3d11gears();
    573 }
    574