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