1 // https://github.com/floooh/sokol-samples/blob/master/html5/mipmap-emsc.c
2 //------------------------------------------------------------------------------
3 // mipmap-glfw.c
4 // Test mipmapping behaviour.
5 // Top row: NEAREST_MIPMAP_NEAREST to LINEAR_MIPMAP_LINEAR
6 // Bottom row: anistropy levels 2, 4, 8 and 16
7 //------------------------------------------------------------------------------
8 #include <GLES3/gl3.h>
9 #define HANDMADE_MATH_IMPLEMENTATION
10 #define HANDMADE_MATH_NO_SSE
11 #include "HandmadeMath.h"
12 #define SOKOL_IMPL
13 #define SOKOL_GLES3
14 #include "sokol_gfx.h"
15 #include "emsc.h"
16
17 typedef struct {
18 hmm_mat4 mvp;
19 } vs_params_t;
20
21 static struct {
22 uint32_t mip0[65536]; /* 256x256 */
23 uint32_t mip1[16384]; /* 128x128 */
24 uint32_t mip2[4096]; /* 64*64 */
25 uint32_t mip3[1024]; /* 32*32 */
26 uint32_t mip4[256]; /* 16*16 */
27 uint32_t mip5[64]; /* 8*8 */
28 uint32_t mip6[16]; /* 4*4 */
29 uint32_t mip7[4]; /* 2*2 */
30 uint32_t mip8[1]; /* 1*2 */
31 } pixels;
32
33 static uint32_t mip_colors[9] = {
34 0xFF0000FF, /* red */
35 0xFF00FF00, /* green */
36 0xFFFF0000, /* blue */
37 0xFFFF00FF, /* magenta */
38 0xFFFFFF00, /* cyan */
39 0xFF00FFFF, /* yellow */
40 0xFFFF00A0, /* violet */
41 0xFFFFA0FF, /* orange */
42 0xFFA000FF, /* purple */
43 };
44
45 static sg_pipeline pip;
46 static sg_bindings bind;
47 static sg_image img[12];
48 static float r;
49
50 static void draw();
51
main()52 int main() {
53 /* try to setup WebGL2 context (for the mipmap min/max lod stuff) */
54 emsc_init("#canvas", EMSC_TRY_WEBGL2);
55
56 /* setup sokol_gfx */
57 sg_desc desc = {
58 .context.gl.force_gles2 = emsc_webgl_fallback()
59 };
60 sg_setup(&desc);
61
62 /* a plane vertex buffer */
63 float vertices[] = {
64 -1.0, -1.0, 0.0, 0.0, 0.0,
65 +1.0, -1.0, 0.0, 1.0, 0.0,
66 -1.0, +1.0, 0.0, 0.0, 1.0,
67 +1.0, +1.0, 0.0, 1.0, 1.0,
68 };
69 bind.vertex_buffers[0] = sg_make_buffer(&(sg_buffer_desc){
70 .size = sizeof(vertices),
71 .content = vertices
72 });
73
74 /* initialize mipmap content, different colors and checkboard pattern */
75 sg_image_content img_content;
76 uint32_t* ptr = pixels.mip0;
77 bool even_odd = false;
78 for (int mip_index = 0; mip_index <= 8; mip_index++) {
79 const int dim = 1<<(8-mip_index);
80 img_content.subimage[0][mip_index].ptr = ptr;
81 img_content.subimage[0][mip_index].size = dim * dim * 4;
82 for (int y = 0; y < dim; y++) {
83 for (int x = 0; x < dim; x++) {
84 *ptr++ = even_odd ? mip_colors[mip_index] : 0xFF000000;
85 even_odd = !even_odd;
86 }
87 even_odd = !even_odd;
88 }
89 }
90 /* the first 4 images are just different min-filters, the last
91 4 images are different anistropy levels */
92 sg_image_desc img_desc = {
93 .width = 256,
94 .height = 256,
95 .num_mipmaps = 9,
96 .pixel_format = SG_PIXELFORMAT_RGBA8,
97 .mag_filter = SG_FILTER_LINEAR,
98 .content = img_content
99 };
100 sg_filter min_filter[] = {
101 SG_FILTER_NEAREST_MIPMAP_NEAREST,
102 SG_FILTER_LINEAR_MIPMAP_NEAREST,
103 SG_FILTER_NEAREST_MIPMAP_LINEAR,
104 SG_FILTER_LINEAR_MIPMAP_LINEAR,
105 };
106 for (int i = 0; i < 4; i++) {
107 img_desc.min_filter = min_filter[i];
108 img[i] = sg_make_image(&img_desc);
109 }
110 img_desc.min_lod = 2.0f;
111 img_desc.max_lod = 4.0f;
112 for (int i = 4; i < 8; i++) {
113 img_desc.min_filter = min_filter[i-4];
114 img[i] = sg_make_image(&img_desc);
115 }
116 img_desc.min_lod = 0.0f;
117 img_desc.max_lod = 0.0f; /* for max_lod, zero-initialized means "FLT_MAX" */
118 for (int i = 8; i < 12; i++) {
119 img_desc.max_anisotropy = 1<<(i-7);
120 img[i] = sg_make_image(&img_desc);
121 }
122
123 /* shader */
124 sg_shader shd = sg_make_shader(&(sg_shader_desc){
125 .attrs = {
126 [0].name = "position",
127 [1].name = "texcoord0"
128 },
129 .vs = {
130 .uniform_blocks[0] = {
131 .size = sizeof(vs_params_t),
132 .uniforms = {
133 [0] = { .name="mvp", .type=SG_UNIFORMTYPE_MAT4 }
134 }
135 },
136 .source =
137 "uniform mat4 mvp;\n"
138 "attribute vec4 position;\n"
139 "attribute vec2 texcoord0;\n"
140 "varying vec2 uv;\n"
141 "void main() {\n"
142 " gl_Position = mvp * position;\n"
143 " uv = texcoord0;\n"
144 "}\n"
145 },
146 .fs = {
147 .images[0] = { .name="tex", .type = SG_IMAGETYPE_2D },
148 .source =
149 "precision mediump float;"
150 "uniform sampler2D tex;"
151 "varying vec2 uv;\n"
152 "void main() {\n"
153 " gl_FragColor = texture2D(tex, uv);\n"
154 "}\n"
155 }
156 });
157
158 /* pipeline state */
159 pip = sg_make_pipeline(&(sg_pipeline_desc) {
160 .layout = {
161 .attrs = {
162 [0].format=SG_VERTEXFORMAT_FLOAT3,
163 [1].format=SG_VERTEXFORMAT_FLOAT2
164 }
165 },
166 .shader = shd,
167 .primitive_type = SG_PRIMITIVETYPE_TRIANGLE_STRIP,
168 });
169
170 draw();
171 return 0;
172 }
173
draw()174 void draw() {
175 for (int t = 0; t < 400; t++) {
176 /* view-projection matrix */
177 hmm_mat4 proj = HMM_Perspective(90.0f, (float)emsc_width()/(float)emsc_height(), 0.01f, 10.0f);
178 hmm_mat4 view = HMM_LookAt(HMM_Vec3(0.0f, 0.0f, 5.0f), HMM_Vec3(0.0f, 0.0f, 0.0f), HMM_Vec3(0.0f, 1.0f, 0.0f));
179 hmm_mat4 view_proj = HMM_MultiplyMat4(proj, view);
180
181 vs_params_t vs_params;
182 r += 0.1f;
183 hmm_mat4 rm = HMM_Rotate(r, HMM_Vec3(1.0f, 0.0f, 0.0f));
184
185 sg_begin_default_pass(&(sg_pass_action){0}, emsc_width(), emsc_height());
186 sg_apply_pipeline(pip);
187 for (int i = 0; i < 12; i++) {
188 const float x = ((float)(i & 3) - 1.5f) * 2.0f;
189 const float y = ((float)(i / 4) - 1.0f) * -2.0f;
190 hmm_mat4 model = HMM_MultiplyMat4(HMM_Translate(HMM_Vec3(x, y, 0.0f)), rm);
191 vs_params.mvp = HMM_MultiplyMat4(view_proj, model);
192
193 bind.fs_images[0] = img[i];
194 if (t == 399) {
195 sg_apply_bindings(&bind);
196 sg_apply_uniforms(SG_SHADERSTAGE_VS, 0, &vs_params, sizeof(vs_params));
197 sg_draw(0, 4, 1);
198 }
199 }
200 sg_end_pass();
201 }
202 sg_commit();
203 }
204