-
Notifications
You must be signed in to change notification settings - Fork 81
/
Copy pathnoninterleaved-metal.c
178 lines (163 loc) · 6.37 KB
/
noninterleaved-metal.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
//------------------------------------------------------------------------------
// noninterleaved-glfw.c
// How to use non-interleaved vertex data (vertex components in
// separate non-interleaved chunks in the same vertex buffers). Note
// that only 4 separate chunks are currently possible because there
// are 4 vertex buffer bind slots in sg_bindings, but you can keep
// several related vertex components interleaved in the same chunk.
//------------------------------------------------------------------------------
#include "osxentry.h"
#include "sokol_gfx.h"
#include "sokol_log.h"
#define HANDMADE_MATH_IMPLEMENTATION
#define HANDMADE_MATH_NO_SSE
#include "HandmadeMath.h"
#define WIDTH (640)
#define HEIGHT (480)
#define SAMPLE_COUNT (4)
static struct {
sg_pass_action pass_action;
sg_pipeline pip;
sg_bindings bind;
float rx, ry;
hmm_mat4 view_proj;
} state;
typedef struct {
hmm_mat4 mvp;
} vs_params_t;
static void init(void) {
// setup sokol
sg_setup(&(sg_desc){
.environment = osx_environment(),
.logger.func = slog_func,
});
// cube vertex buffer
float vertices[] = {
// positions
-1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, -1.0,
-1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, 1.0,
-1.0, -1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0,
1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0,
-1.0, -1.0, -1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0, -1.0, -1.0,
-1.0, 1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0,
// colors
1.0, 0.5, 0.0, 1.0, 1.0, 0.5, 0.0, 1.0, 1.0, 0.5, 0.0, 1.0, 1.0, 0.5, 0.0, 1.0,
0.5, 1.0, 0.0, 1.0, 0.5, 1.0, 0.0, 1.0, 0.5, 1.0, 0.0, 1.0, 0.5, 1.0, 0.0, 1.0,
0.5, 0.0, 1.0, 1.0, 0.5, 0.0, 1.0, 1.0, 0.5, 0.0, 1.0, 1.0, 0.5, 0.0, 1.0, 1.0,
1.0, 0.5, 1.0, 1.0, 1.0, 0.5, 1.0, 1.0, 1.0, 0.5, 1.0, 1.0, 1.0, 0.5, 1.0, 1.0,
0.5, 1.0, 1.0, 1.0, 0.5, 1.0, 1.0, 1.0, 0.5, 1.0, 1.0, 1.0, 0.5, 1.0, 1.0, 1.0,
1.0, 1.0, 0.5, 1.0, 1.0, 1.0, 0.5, 1.0, 1.0, 1.0, 0.5, 1.0, 1.0, 1.0, 0.5, 1.0,
};
sg_buffer vbuf = sg_make_buffer(&(sg_buffer_desc){
.data = SG_RANGE(vertices)
});
// create an index buffer for the cube
uint16_t indices[] = {
0, 1, 2, 0, 2, 3,
6, 5, 4, 7, 6, 4,
8, 9, 10, 8, 10, 11,
14, 13, 12, 15, 14, 12,
16, 17, 18, 16, 18, 19,
22, 21, 20, 23, 22, 20
};
sg_buffer ibuf = sg_make_buffer(&(sg_buffer_desc){
.type = SG_BUFFERTYPE_INDEXBUFFER,
.data = SG_RANGE(indices)
});
// a shader, note that Metal only needs to know uniform block sizes, but
// not their internal layout
sg_shader shd = sg_make_shader(&(sg_shader_desc){
.vertex_func.source =
"#include <metal_stdlib>\n"
"using namespace metal;\n"
"struct params_t {\n"
" float4x4 mvp;\n"
"};\n"
"struct vs_in {\n"
" float4 position [[attribute(0)]];\n"
" float4 color [[attribute(1)]];\n"
"};\n"
"struct vs_out {\n"
" float4 pos [[position]];\n"
" float4 color;\n"
"};\n"
"vertex vs_out _main(vs_in in [[stage_in]], constant params_t& params [[buffer(0)]]) {\n"
" vs_out out;\n"
" out.pos = params.mvp * in.position;\n"
" out.color = in.color;\n"
" return out;\n"
"}\n",
.fragment_func.source =
"#include <metal_stdlib>\n"
"using namespace metal;\n"
"fragment float4 _main(float4 color [[stage_in]]) {\n"
" return color;\n"
"}\n",
.uniform_blocks[0] = {
.stage = SG_SHADERSTAGE_VERTEX,
.size = sizeof(vs_params_t),
.msl_buffer_n = 0,
},
});
// a pipeline object
state.pip = sg_make_pipeline(&(sg_pipeline_desc){
.layout = {
// note how the vertex components are pulled from different buffer bind slots
.attrs = {
// positions come from vertex buffer slot 0
[0] = { .format=SG_VERTEXFORMAT_FLOAT3, .buffer_index=0 },
// colors come from vertex buffer slot 1
[1] = { .format=SG_VERTEXFORMAT_FLOAT4, .buffer_index=1 }
}
}, .shader = shd,
.index_type = SG_INDEXTYPE_UINT16,
.depth = {
.compare = SG_COMPAREFUNC_LESS_EQUAL,
.write_enabled = true
},
.cull_mode = SG_CULLMODE_BACK,
});
// fill the resource bindings, note how the same vertex
// buffer is bound to the first two slots, and the vertex-buffer-offsets
// are used to point to the position- and color-components.
state.bind = (sg_bindings){
.vertex_buffers = {
[0] = vbuf,
[1] = vbuf
},
.vertex_buffer_offsets = {
// position components are at start of buffer
[0] = 0,
// byte offset of color components in buffer
[1] = 24 * 3 * sizeof(float)
},
.index_buffer = ibuf
};
// view-projection matrix
hmm_mat4 proj = HMM_Perspective(60.0f, (float)WIDTH/(float)HEIGHT, 0.01f, 10.0f);
hmm_mat4 view = HMM_LookAt(HMM_Vec3(0.0f, 1.5f, 6.0f), HMM_Vec3(0.0f, 0.0f, 0.0f), HMM_Vec3(0.0f, 1.0f, 0.0f));
state.view_proj = HMM_MultiplyMat4(proj, view);
}
static void frame(void) {
// compute model-view-projection matrix for vertex shader
vs_params_t vs_params;
state.rx += 1.0f; state.ry += 2.0f;
hmm_mat4 rxm = HMM_Rotate(state.rx, HMM_Vec3(1.0f, 0.0f, 0.0f));
hmm_mat4 rym = HMM_Rotate(state.ry, HMM_Vec3(0.0f, 1.0f, 0.0f));
hmm_mat4 model = HMM_MultiplyMat4(rxm, rym);
vs_params.mvp = HMM_MultiplyMat4(state.view_proj, model);
sg_begin_pass(&(sg_pass){ .action = state.pass_action, .swapchain = osx_swapchain() });
sg_apply_pipeline(state.pip);
sg_apply_bindings(&state.bind);
sg_apply_uniforms(0, &SG_RANGE(vs_params));
sg_draw(0, 36, 1);
sg_end_pass();
sg_commit();
}
static void shutdown(void) {
sg_shutdown();
}
int main() {
osx_start(WIDTH, HEIGHT, SAMPLE_COUNT, SG_PIXELFORMAT_DEPTH, "noninterleaved-metal", init, frame, shutdown);
return 0;
}