1 //------------------------------------------------------------------------------
2 //  cube.d - Example Sokol Cube
3 //
4 //  Shader with uniform data.
5 //------------------------------------------------------------------------------
6 module examples.cube;
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.cube;
16 
17 extern (C):
18 @safe:
19 
20 struct State
21 {
22     float rx = 0;
23     float ry = 0;
24 
25     sg.Pipeline pip;
26     sg.Bindings bind;
27     sg.PassAction passAction = {
28         colors: [
29             {
30                 load_action: sg.LoadAction.Clear,
31                 clear_value: {r: 0.25, g: 0.5, b: 0.75, a: 1.0}
32             }
33         ]
34     };
35 
36     Mat4 view()
37     {
38         return Mat4.lookAt(Vec3(0.0, 1.5, 6.0), Vec3.zero(), Vec3.up());
39     }
40 }
41 
42 static State state;
43 
44 void init()
45 {
46     sg.Desc gfxd = {environment: sglue.environment,
47     logger: {func: &log.func}};
48     sg.setup(gfxd);
49 
50     float[168] vertices = [
51         -1.0, -1.0, -1.0, 1.0, 0.0, 0.0, 1.0,
52         1.0, -1.0, -1.0, 1.0, 0.0, 0.0, 1.0,
53         1.0, 1.0, -1.0, 1.0, 0.0, 0.0, 1.0,
54         -1.0, 1.0, -1.0, 1.0, 0.0, 0.0, 1.0,
55 
56         -1.0, -1.0, 1.0, 0.0, 1.0, 0.0, 1.0,
57         1.0, -1.0, 1.0, 0.0, 1.0, 0.0, 1.0,
58         1.0, 1.0, 1.0, 0.0, 1.0, 0.0, 1.0,
59         -1.0, 1.0, 1.0, 0.0, 1.0, 0.0, 1.0,
60 
61         -1.0, -1.0, -1.0, 0.0, 0.0, 1.0, 1.0,
62         -1.0, 1.0, -1.0, 0.0, 0.0, 1.0, 1.0,
63         -1.0, 1.0, 1.0, 0.0, 0.0, 1.0, 1.0,
64         -1.0, -1.0, 1.0, 0.0, 0.0, 1.0, 1.0,
65 
66         1.0, -1.0, -1.0, 1.0, 0.5, 0.0, 1.0,
67         1.0, 1.0, -1.0, 1.0, 0.5, 0.0, 1.0,
68         1.0, 1.0, 1.0, 1.0, 0.5, 0.0, 1.0,
69         1.0, -1.0, 1.0, 1.0, 0.5, 0.0, 1.0,
70 
71         -1.0, -1.0, -1.0, 0.0, 0.5, 1.0, 1.0,
72         -1.0, -1.0, 1.0, 0.0, 0.5, 1.0, 1.0,
73         1.0, -1.0, 1.0, 0.0, 0.5, 1.0, 1.0,
74         1.0, -1.0, -1.0, 0.0, 0.5, 1.0, 1.0,
75 
76         -1.0, 1.0, -1.0, 1.0, 0.0, 0.5, 1.0,
77         -1.0, 1.0, 1.0, 1.0, 0.0, 0.5, 1.0,
78         1.0, 1.0, 1.0, 1.0, 0.0, 0.5, 1.0,
79         1.0, 1.0, -1.0, 1.0, 0.0, 0.5, 1.0
80     ];
81     sg.BufferDesc vbufd = {data: {ptr: vertices.ptr, size: vertices.sizeof},};
82     state.bind.vertex_buffers[0] = sg.makeBuffer(vbufd);
83 
84     ushort[36] indices = [
85         0, 1, 2, 0, 2, 3,
86         6, 5, 4, 7, 6, 4,
87         8, 9, 10, 8, 10, 11,
88         14, 13, 12, 15, 14, 12,
89         16, 17, 18, 16, 18, 19,
90         22, 21, 20, 23, 22, 20,
91     ];
92     sg.BufferDesc ibufd = {
93         type: sg.BufferType.Indexbuffer,
94         data: {ptr: indices.ptr, size: indices.sizeof},
95     };
96     state.bind.index_buffer = sg.makeBuffer(ibufd);
97 
98     sg.PipelineDesc pld = {
99         layout: {
100             attrs: [
101                 shd.ATTR_CUBE_POSITION: {format: sg.VertexFormat.Float3},
102                 shd.ATTR_CUBE_COLOR0: {format: sg.VertexFormat.Float4},
103             ],
104         },
105         shader: sg.makeShader(shd.cubeShaderDesc(sg.queryBackend())),
106         index_type: sg.IndexType.Uint16,
107         cull_mode: sg.CullMode.Back,
108         depth: {write_enabled: true,
109         compare: sg.CompareFunc.Less_equal},
110     };
111     state.pip = sg.makePipeline(pld);
112 }
113 
114 void frame()
115 {
116     immutable float t = cast(float)(app.frameDuration() * 60.0);
117 
118     state.rx += 1.0 * t;
119     state.ry += 2.0 * t;
120 
121     shd.VsParams vsParams = {mvp: computeMvp(state.rx, state.ry)};
122 
123     sg.Pass pass = {action: state.passAction, swapchain: sglue.swapchain()};
124     sg.beginPass(pass);
125     sg.applyPipeline(state.pip);
126     sg.applyBindings(state.bind);
127     sg.Range r = {ptr: &vsParams, size: vsParams.sizeof};
128     sg.applyUniforms(shd.UB_VS_PARAMS, r);
129     sg.draw(0, 36, 1);
130     sg.endPass();
131     sg.commit();
132 }
133 
134 void cleanup()
135 {
136     sg.shutdown();
137 }
138 
139 Mat4 computeMvp(float rx, float ry)
140 {
141     immutable proj = Mat4.perspective(60.0, app.widthf() / app.heightf(), 0.01, 10.0);
142     immutable rxm = Mat4.rotate(rx, Vec3(1.0, 0.0, 0.0));
143     immutable rym = Mat4.rotate(ry, Vec3(0.0, 1.0, 0.0));
144     immutable model = Mat4.mul(rxm, rym);
145     immutable view_proj = Mat4.mul(proj, state.view());
146     return Mat4.mul(view_proj, model);
147 }
148 
149 void main()
150 {
151     app.Desc runner = {
152         window_title: "cube.d",
153         init_cb: &init,
154         frame_cb: &frame,
155         cleanup_cb: &cleanup,
156         width: 800,
157         height: 600,
158         sample_count: 4,
159         icon: {sokol_default: true},
160         logger: {func: &log.func}
161     };
162     app.run(runner);
163 }