1 //------------------------------------------------------------------------------
2 //  blend.d - Example Sokol Blend
3 //
4 //  Shader with uniform data.
5 //------------------------------------------------------------------------------
6 module examples.blend;
7 
8 private:
9 
10 import sg = sokol.gfx;
11 import app = sokol.app;
12 import log = sokol.log;
13 import handmade.math : Mat4, Vec3;
14 import sglue = sokol.glue;
15 import shd = examples.shaders.blend;
16 
17 extern (C):
18 @safe:
19 
20 immutable NUM_BLEND_FACTORS = 15;
21 
22 struct State
23 {
24     float r = 0.0f;
25     sg.Pipeline bg_pip;
26     sg.Pipeline[NUM_BLEND_FACTORS][NUM_BLEND_FACTORS] pips;
27     sg.Bindings bind;
28     sg.PassAction passAction = {
29         colors: [{load_action: sg.LoadAction.Dontcare}],
30         depth: {load_action: sg.LoadAction.Dontcare},
31         stencil: {load_action: sg.LoadAction.Dontcare}
32     };
33     shd.QuadVsParams quad_vs_params;
34     shd.BgFsParams bg_fs_params;
35 }
36 
37 static State state;
38 
39 void init()
40 {
41     sg.Desc gfx = {
42         pipeline_pool_size: NUM_BLEND_FACTORS * NUM_BLEND_FACTORS + 1,
43         environment: sglue.environment,
44         logger: {func: &log.func}
45     };
46     sg.setup(gfx);
47 
48     float[28] vertices = [
49         // pos            color
50         -1.0, -1.0, 0.0, 1.0, 0.0, 0.0, 0.5,
51         1.0, -1.0, 0.0, 0.0, 1.0, 0.0, 0.5,
52         -1.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.5,
53         1.0, 1.0, 0.0, 1.0, 1.0, 0.0, 0.5,
54     ];
55 
56     // create vertex buffer
57     sg.BufferDesc vbufd = {data: {ptr: vertices.ptr,
58     size: vertices.sizeof,}};
59     state.bind.vertex_buffers[0] = sg.makeBuffer(vbufd);
60 
61     sg.PipelineDesc pld = {
62         shader: sg.makeShader(shd.bgShaderDesc(sg.queryBackend())),
63         layout: {
64             buffers: [{stride: 28}],
65             attrs: [
66                 shd.ATTR_BG_POSITION: {format: sg.VertexFormat.Float2},
67             ],
68         },
69         primitive_type: sg.PrimitiveType.Triangle_strip
70     };
71     state.bg_pip = sg.makePipeline(pld);
72 
73     sg.PipelineDesc pip_desc = {
74         shader: sg.makeShader(shd.quadShaderDesc(sg.queryBackend())),
75         layout: {
76             attrs: [
77                 shd.ATTR_QUAD_POSITION: {format: sg.VertexFormat.Float3},
78                 shd.ATTR_QUAD_COLOR0: {format: sg.VertexFormat.Float4},
79             ],
80         },
81         primitive_type: sg.PrimitiveType.Triangle_strip,
82         blend_color: {r: 1.0, g: 0.0, b: 0.0, a: 1.0},
83         colors: [
84             {
85                 blend: {
86                     enabled: true,
87                     src_factor_alpha: sg.BlendFactor.One,
88                     dst_factor_alpha: sg.BlendFactor.Zero
89                 }
90             }
91         ]
92     };
93     foreach (src; 0 .. NUM_BLEND_FACTORS)
94     {
95         foreach (dst; 0 .. NUM_BLEND_FACTORS)
96         {
97             pip_desc.colors[0].blend.src_factor_rgb = cast(sg.BlendFactor)(src + 1);
98             pip_desc.colors[0].blend.dst_factor_rgb = cast(sg.BlendFactor)(dst + 1);
99             state.pips[src][dst] = sg.makePipeline(pip_desc);
100         }
101     }
102 }
103 
104 void frame()
105 {
106     immutable float t = cast(float)(app.frameDuration() * 60.0);
107 
108     state.r += 0.6 * t;
109     state.bg_fs_params.tick += 1.0 * t;
110 
111     // view-projection matrix
112     immutable proj = Mat4.perspective(90.0, app.widthf() / app.heightf(), 0.01, 100.0);
113     immutable view = Mat4.lookAt(Vec3(0.0, 0.0, 25.0), Vec3.zero(), Vec3.up());
114     immutable view_proj = Mat4.mul(proj, view);
115 
116     sg.Pass pass = {action: state.passAction, swapchain: sglue.swapchain()};
117     sg.beginPass(pass);
118     sg.Range r = {ptr: &state.bg_fs_params,
119     size: state.bg_fs_params.sizeof,};
120     sg.applyPipeline(state.bg_pip);
121     sg.applyBindings(state.bind);
122     sg.applyUniforms(shd.UB_BG_FS_PARAMS, r);
123     sg.draw(0, 4, 1);
124 
125     // draw the blended quads
126     float r0 = state.r;
127     foreach (src; 0 .. NUM_BLEND_FACTORS)
128     {
129         foreach (dst; 0 .. NUM_BLEND_FACTORS)
130         {
131             // compute model-view-proj matrix
132             auto rm = Mat4.rotate(state.r, Vec3(0.0, 1.0, 0.0));
133             immutable x = (dst - (NUM_BLEND_FACTORS / 2)) * 3.0;
134             immutable y = (src - (NUM_BLEND_FACTORS / 2)) * 2.2;
135             immutable model = Mat4.mul(Mat4.translate(Vec3(x, y, 0.0)), rm);
136             state.quad_vs_params.mvp = Mat4.mul(view_proj, model);
137             sg.Range rg = {
138                 ptr: &state.quad_vs_params,
139                 size: state.quad_vs_params.sizeof,
140             };
141             sg.applyPipeline(state.pips[src][dst]);
142             sg.applyBindings(state.bind);
143             sg.applyUniforms(shd.UB_QUAD_VS_PARAMS, rg);
144             sg.draw(0, 4, 1);
145             r0 += 0.6;
146         }
147     }
148     sg.endPass();
149     sg.commit();
150 }
151 
152 void cleanup()
153 {
154     sg.shutdown();
155 }
156 
157 void main()
158 {
159     app.Desc runner = {
160         window_title: "blend.d",
161         init_cb: &init,
162         frame_cb: &frame,
163         cleanup_cb: &cleanup,
164         width: 800,
165         height: 600,
166         sample_count: 4,
167         icon: {sokol_default: true},
168         logger: {func: &log.func}
169     };
170     app.run(runner);
171 }