1 //------------------------------------------------------------------------------
2 //  texcube.d - Example Sokol Texcube
3 //
4 //  Texture creation, rendering with texture, packed vertex components.
5 //------------------------------------------------------------------------------
6 module examples.texcube;
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.texcube;
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 
29     Mat4 view()
30     {
31         return Mat4.lookAt(Vec3(0.0, 1.5, 6.0), Vec3.zero(), Vec3.up());
32     }
33 }
34 
35 struct Vertex
36 {
37     float x = 0.0, y = 0.0, z = 0.0;
38     int color = 0;
39     short u = 0, v = 0;
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     Vertex[24] vertices = [
51         Vertex(-1.0, -1.0, -1.0, 0xFF0000FF, 0, 0),
52         Vertex(1.0, -1.0, -1.0, 0xFF0000FF, 32_767, 0),
53         Vertex(1.0, 1.0, -1.0, 0xFF0000FF, 32_767, 32_767),
54         Vertex(-1.0, 1.0, -1.0, 0xFF0000FF, 0, 32_767),
55 
56         Vertex(-1.0, -1.0, 1.0, 0xFF00FF00, 0, 0),
57         Vertex(1.0, -1.0, 1.0, 0xFF00FF00, 32_767, 0),
58         Vertex(1.0, 1.0, 1.0, 0xFF00FF00, 32_767, 32_767),
59         Vertex(-1.0, 1.0, 1.0, 0xFF00FF00, 0, 32_767),
60 
61         Vertex(-1.0, -1.0, -1.0, 0xFFFF0000, 0, 0),
62         Vertex(-1.0, 1.0, -1.0, 0xFFFF0000, 32_767, 0),
63         Vertex(-1.0, 1.0, 1.0, 0xFFFF0000, 32_767, 32_767),
64         Vertex(-1.0, -1.0, 1.0, 0xFFFF0000, 0, 32_767),
65 
66         Vertex(1.0, -1.0, -1.0, 0xFFFF007F, 0, 0),
67         Vertex(1.0, 1.0, -1.0, 0xFFFF007F, 32_767, 0),
68         Vertex(1.0, 1.0, 1.0, 0xFFFF007F, 32_767, 32_767),
69         Vertex(1.0, -1.0, 1.0, 0xFFFF007F, 0, 32_767),
70 
71         Vertex(-1.0, -1.0, -1.0, 0xFFFF7F00, 0, 0),
72         Vertex(-1.0, -1.0, 1.0, 0xFFFF7F00, 32_767, 0),
73         Vertex(1.0, -1.0, 1.0, 0xFFFF7F00, 32_767, 32_767),
74         Vertex(1.0, -1.0, -1.0, 0xFFFF7F00, 0, 32_767),
75 
76         Vertex(-1.0, 1.0, -1.0, 0xFF007FFF, 0, 0),
77         Vertex(-1.0, 1.0, 1.0, 0xFF007FFF, 32_767, 0),
78         Vertex(1.0, 1.0, 1.0, 0xFF007FFF, 32_767, 32_767),
79         Vertex(1.0, 1.0, -1.0, 0xFF007FFF, 0, 32_767),
80     ];
81 
82     sg.BufferDesc vbufd = {data: {ptr: vertices.ptr, size: vertices.sizeof},};
83     state.bind.vertex_buffers[0] = sg.makeBuffer(vbufd);
84 
85     ushort[36] indices = [
86         0, 1, 2, 0, 2, 3,
87         6, 5, 4, 7, 6, 4,
88         8, 9, 10, 8, 10, 11,
89         14, 13, 12, 15, 14, 12,
90         16, 17, 18, 16, 18, 19,
91         22, 21, 20, 23, 22, 20,
92     ];
93 
94     int[4][4] colors = [
95         [0xFFFFFFFF, 0xFF000000, 0xFFFFFFFF, 0xFF000000],
96         [0xFF000000, 0xFFFFFFFF, 0xFF000000, 0xFFFFFFFF],
97         [0xFFFFFFFF, 0xFF000000, 0xFFFFFFFF, 0xFF000000],
98         [0xFF000000, 0xFFFFFFFF, 0xFF000000, 0xFFFFFFFF]
99     ];
100     // dfmt off
101     sg.BufferDesc ibufd = {
102         type: sg.BufferType.Indexbuffer,
103         data: {ptr: indices.ptr, size: indices.sizeof},
104     };
105     state.bind.index_buffer = sg.makeBuffer(ibufd);
106 
107     sg.PipelineDesc pld = {
108         layout: {
109             attrs: [
110                 shd.ATTR_TEXCUBE_POS: {format: sg.VertexFormat.Float3},
111                 shd.ATTR_TEXCUBE_COLOR0: {format: sg.VertexFormat.Ubyte4n},
112                 shd.ATTR_TEXCUBE_TEXCOORD0: {format: sg.VertexFormat.Short2n},
113             ],
114         },
115         shader: sg.makeShader(shd.texcubeShaderDesc(sg.queryBackend())),
116         index_type: sg.IndexType.Uint16,
117         cull_mode: sg.CullMode.Back,
118         depth: {
119             write_enabled: true,
120             compare: sg.CompareFunc.Less_equal
121         },
122     };
123     sg.ImageData img_data = {
124         subimage: [[{
125             ptr: cast(ubyte*)colors.ptr,
126             size: colors.sizeof,
127         }]]
128     };
129     // create a small checker-board texture
130     sg.ImageDesc img_desc = {
131         width: 4,
132         height: 4,
133         data: img_data,
134     };
135     // dfmt on
136     state.bind.images[shd.IMG_TEX] = sg.makeImage(img_desc);
137 
138     sg.SamplerDesc smpld = {};
139     state.bind.samplers[shd.SMP_SMP] = sg.makeSampler(smpld);
140 
141     state.pip = sg.makePipeline(pld);
142 }
143 
144 void frame()
145 {
146     immutable float t = cast(float)(app.frameDuration() * 60.0);
147 
148     state.rx += 1.0 * t;
149     state.ry += 2.0 * t;
150 
151     shd.VsParams vsParams = {mvp: computeMvp(state.rx, state.ry)};
152 
153     sg.Pass pass = {action: state.passAction, swapchain: sglue.swapchain()};
154     sg.beginPass(pass);
155     sg.applyPipeline(state.pip);
156     sg.applyBindings(state.bind);
157     sg.Range r = {ptr: &vsParams, size: vsParams.sizeof};
158     sg.applyUniforms(shd.UB_VS_PARAMS, r);
159     sg.draw(0, 36, 1);
160     sg.endPass();
161     sg.commit();
162 }
163 
164 void cleanup()
165 {
166     sg.shutdown();
167 }
168 
169 Mat4 computeMvp(float rx, float ry)
170 {
171     immutable proj = Mat4.perspective(60.0, app.widthf() / app.heightf(), 0.01, 10.0);
172     immutable rxm = Mat4.rotate(rx, Vec3(1.0, 0.0, 0.0));
173     immutable rym = Mat4.rotate(ry, Vec3(0.0, 1.0, 0.0));
174     immutable model = Mat4.mul(rxm, rym);
175     immutable view_proj = Mat4.mul(proj, state.view());
176     return Mat4.mul(view_proj, model);
177 }
178 
179 // dfmt off
180 void main()
181 {
182     app.Desc runner = {
183         window_title: "texcube.d",
184         init_cb: &init,
185         frame_cb: &frame,
186         cleanup_cb: &cleanup,
187         width: 800,
188         height: 600,
189         sample_count: 4,
190         icon: {sokol_default: true},
191         logger: {func: &log.func}
192     };
193     app.run(runner);
194 }
195 // dfmt on