2
* Copyright (C) 1999-2001 Brian Paul All Rights Reserved.
3
* Copyright (C) 2009-2010 Luca Barbieri All Rights Reserved.
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:
12
* The above copyright notice and this permission notice shall be included
13
* in all copies or substantial portions of the Software.
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.
24
* This is a port of the infamous "glxgears" demo to straight EGL
25
* Port by Dane Rushton 10 July 2005
27
* This a rewrite of the 'eglgears' demo in straight Gallium
28
* Port by Luca Barbieri
30
* This a port of the 'galliumgears' demo to Direct3D 11
31
* Port by Luca Barbieri
34
#define _USE_MATH_DEFINES
37
#include "d3d11gears.hlsl.ps.h"
38
#include "d3d11gears.hlsl.vs.h"
73
vertex(float x, float y, float z, float nx, float ny, float nz)
84
#define VERT(x, y, z) vertices.push_back(vertex((x), (y), (z), (nx), (ny), (nz)))
86
static mesh* build_gear(ID3D11Device* dev, int triangle_budget, float inner_radius, float outer_radius, float width, int teeth, float tooth_depth)
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;
108
r1 = outer_radius - tooth_depth / 2.0f;
109
r2 = outer_radius + tooth_depth / 2.0f;
111
da = (float)(2.0 * M_PI / (teeth * segs * divs));
112
for(i = 0; i < teeth * segs * divs; ++i) {
113
float angle = da * i;
118
for(i = 0; i < teeth * segs; ++i) {
124
for(face = -1; face <= 1; face += 2) {
125
float z = width * face * 0.5f;
130
indices.flip = face > 0;
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);
140
for(i = 0; i < teeth * segs * divs; ++i) {
141
VERT(r0 * dc[i], r0 * ds[i], z);
144
for(i = 0; i < teeth; ++i) {
145
for(j = i * segs; j < (i + 1) * segs; ++j) {
147
if(nextj == teeth * segs)
150
for(k = j * divs; k < (j + 1) * divs; ++k) {
152
if(nextk == teeth * segs * divs)
154
indices.poly(teeth * segs + k, j, teeth * segs + nextk);
157
indices.poly(teeth * segs + nextj * divs, j, nextj);
161
indices.base += teeth * segs * (1 + divs);
166
float z = width * 0.5f;
168
float* coords = (float*)malloc((segs + 1) * 2 * sizeof(float));
170
for(i = 0; i < teeth; i++) {
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];
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);
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);
197
indices.poly(0, 1, 3, 2);
203
/* inner part - simulate a cylinder */
205
for(i = 0; i < teeth * segs * divs; i++) {
207
if(next == teeth * segs * divs)
212
VERT(r0 * dc[i], r0 * ds[i], -width * 0.5f);
213
VERT(r0 * dc[i], r0 * ds[i], width * 0.5f);
215
indices.poly(i * 2, i * 2 + 1, next * 2 + 1, next * 2);
218
indices.base += teeth * segs * divs * 2;
224
D3D11_INPUT_ELEMENT_DESC elements[2] =
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},
230
return new mesh(dev, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST,
233
&vertices[0], sizeof(vertices[0]), vertices.size(),
234
&indices[0], sizeof(indices[0]), indices.size());
237
struct d3d11gears : public d3d11_application
246
unsigned impressions;
254
ID3D11DepthStencilView* zsv;
255
ID3D11RenderTargetView* offscreen_rtv;
256
ID3D11ShaderResourceView* offscreen_srv;
259
ID3D11BlendState* blend;
260
ID3D11DepthStencilState* zsa;
262
ID3D11PixelShader* ps;
263
ID3D11VertexShader* vs;
266
d3d11_blitter* blitter;
269
: cur_width(-1), cur_height(-1), zsv(0), offscreen_rtv(0), offscreen_srv(0)
271
view_rotx = (float)(M_PI / 9.0);
272
view_roty = (float)(M_PI / 6.0);
282
void draw_one(ID3D11DeviceContext* ctx, cbuf_t& cbd, const float4x4& modelview, float angle)
284
for(unsigned i = blue_only ? 2 : 0; i < 3; ++i)
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);
291
cbd.diffuse = gears[i].color;
292
cbd.specular = gears[i].color;
293
cbd.specular_power = 5.0f;
295
ctx->UpdateSubresource(cb, 0, 0, &cbd, 0, 0);
297
gears[i].mesh->bind_and_draw(ctx);
301
float get_angle(double time)
303
// designed so that 1 = original glxgears speed
304
float mod_speed = M_PI * 70.0f / 180.0f * speed;
306
return (float)(time * mod_speed);
308
return (float)(cos(time / period) * period * mod_speed);
311
void init_for_dimensions(unsigned width, unsigned height)
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));
329
ID3D11Texture2D* offscreen;
332
offscreen_rtv->Release();
333
offscreen_srv->Release();
340
DXGI_FORMAT formats[] = {
341
DXGI_FORMAT_R32G32B32A32_FLOAT,
342
DXGI_FORMAT_R16G16B16A16_UNORM,
343
DXGI_FORMAT_R16G16B16A16_FLOAT,
344
DXGI_FORMAT_R10G10B10A2_UNORM,
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)
351
dev->CheckFormatSupport(DXGI_FORMAT_R32G32B32A32_FLOAT, &support);
352
if((support & needed_support) == needed_support)
360
D3D11_TEXTURE2D_DESC offscreend;
361
memset(&offscreend, 0, sizeof(offscreend));
362
offscreend.Width = width;
363
offscreend.Height = height;
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();
380
void draw(ID3D11DeviceContext* ctx, ID3D11RenderTargetView* rtv, unsigned width, unsigned height, double time)
383
memset(&vp, 0, sizeof(vp));
384
vp.Width = (float)width;
385
vp.Height = (float)height;
388
if((int)width != cur_width || (int)height != cur_height)
389
init_for_dimensions(width, height);
391
float4 lightpos = vec(5.0f, 5.0f, 10.0f, 0.0f);
392
float black[4] = {0.0, 0.0, 0.0, 0};
397
float xr = (float)width / (float)height;
403
proj = mat4x4_frustum(-xr, xr, -yr, yr, 5.0f, 60.0f);
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);
413
cbd.projection = proj;
414
cbd.light = lightpos;
416
float blend_factor[4] = {1.0f / (float)impressions, 1.0f / (float)impressions, 1.0f / (float)impressions, 1.0f / (float)impressions};
418
ID3D11RenderTargetView* render_rtv;
422
render_rtv = offscreen_rtv;
424
ctx->RSSetViewports(1, &vp);
425
ctx->ClearRenderTargetView(render_rtv, black);
427
ctx->PSSetShader(ps, 0, 0);
428
ctx->VSSetShader(vs, 0, 0);
430
ctx->PSSetConstantBuffers(0, 1, &cb);
431
ctx->VSSetConstantBuffers(0, 1, &cb);
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));
443
ctx->OMSetBlendState(blend, blend_factor, ~0);
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)
450
float impression_time = base_time + time_delta_per_impression * impression;
452
ctx->ClearDepthStencilView(zsv, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0, 0);
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)
459
ctx->OMSetRenderTargets(0, 0, zsv);
460
ctx->OMSetDepthStencilState(0, 0);
464
ctx->OMSetRenderTargets(1, &render_rtv, zsv);
465
ctx->OMSetDepthStencilState(zsa, 0);
468
draw_one(ctx, cbd, m, get_angle(impression_time));
472
blitter->bind_draw_and_unbind(ctx, offscreen_srv, rtv, 0, 0, (float)width, (float)height, false);
474
last_time = (float)time;
477
bool init(ID3D11Device* dev, int argc, char** argv)
481
for(char** p = argv + 1; *p; ++p) {
482
if(!strcmp(*p, "-w"))
484
else if(!strcmp(*p, "-b"))
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);
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");
509
ensure(dev->CreatePixelShader(g_ps, sizeof(g_ps), NULL, &ps));
510
ensure(dev->CreateVertexShader(g_vs, sizeof(g_vs), NULL, &vs));
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);
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);
522
gears[0].wmul = 1.0f;
523
gears[0].t0 = 0.0 * M_PI / 180.0f;
527
gears[1].wmul = -2.0f;
528
gears[1].t0 = -9.0f * (float)M_PI / 180.0f;
532
gears[2].wmul = -2.0f;
533
gears[2].t0 = -25.0f * (float)M_PI / 180.0f;
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));
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
553
blendd.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
554
ensure(dev->CreateBlendState(&blendd, &blend));
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));
563
blitter = new d3d11_blitter(dev);
570
d3d11_application* d3d11_application_create()
572
return new d3d11gears();