blob: a731117ead2dccd6ae8140c21044e80427dde917 [file] [log] [blame] [edit]
// https://github.com/floooh/sokol-samples/blob/master/html5/arraytex-emsc.c
//------------------------------------------------------------------------------
// arraytex-glfw.c
//------------------------------------------------------------------------------
#include <stddef.h> /* offsetof */
#include <GLES3/gl3.h>
#define HANDMADE_MATH_IMPLEMENTATION
#define HANDMADE_MATH_NO_SSE
#include "HandmadeMath.h"
#define SOKOL_IMPL
#define SOKOL_GLES3
#include "sokol_gfx.h"
#include "emsc.h"
static sg_pass_action pass_action;
static sg_pipeline pip;
static sg_bindings bind;
static float rx, ry;
static int frame_index;
typedef struct {
hmm_mat4 mvp;
hmm_vec2 offset0;
hmm_vec2 offset1;
hmm_vec2 offset2;
} params_t;
#define IMG_LAYERS (3)
#define IMG_WIDTH (16)
#define IMG_HEIGHT (16)
static void draw();
int main() {
/* setup WebGL2 context */
emsc_init("#canvas", EMSC_TRY_WEBGL2);
/* setup sokol_gfx */
sg_desc desc = {
.context.gl.force_gles2 = emsc_webgl_fallback()
};
sg_setup(&desc);
assert(sg_isvalid());
/* not much useful things to do in this demo if WebGL2 is not supported,
so just drop out and later render a dark red screen */
if (desc.context.gl.force_gles2) {
puts("no WebGL2 :(");
return 1;
}
/* a 16x16 array texture with 3 layers and a checkerboard pattern */
static uint32_t pixels[IMG_LAYERS][IMG_HEIGHT][IMG_WIDTH];
for (int layer=0, even_odd=0; layer<IMG_LAYERS; layer++) {
for (int y = 0; y < IMG_HEIGHT; y++, even_odd++) {
for (int x = 0; x < IMG_WIDTH; x++, even_odd++) {
if (even_odd & 1) {
switch (layer) {
case 0: pixels[layer][y][x] = 0x000000FF; break;
case 1: pixels[layer][y][x] = 0x0000FF00; break;
case 2: pixels[layer][y][x] = 0x00FF0000; break;
}
}
else {
pixels[layer][y][x] = 0;
}
}
}
}
sg_image img = sg_make_image(&(sg_image_desc) {
.type = SG_IMAGETYPE_ARRAY,
.width = IMG_WIDTH,
.height = IMG_HEIGHT,
.layers = IMG_LAYERS,
.pixel_format = SG_PIXELFORMAT_RGBA8,
.min_filter = SG_FILTER_LINEAR,
.mag_filter = SG_FILTER_LINEAR,
.content.subimage[0][0] = {
.ptr = pixels,
.size = sizeof(pixels)
}
});
/* cube vertex buffer */
float vertices[] = {
/* pos uvs */
-1.0f, -1.0f, -1.0f, 0.0f, 0.0f,
1.0f, -1.0f, -1.0f, 1.0f, 0.0f,
1.0f, 1.0f, -1.0f, 1.0f, 1.0f,
-1.0f, 1.0f, -1.0f, 0.0f, 1.0f,
-1.0f, -1.0f, 1.0f, 0.0f, 0.0f,
1.0f, -1.0f, 1.0f, 1.0f, 0.0f,
1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
-1.0f, 1.0f, 1.0f, 0.0f, 1.0f,
-1.0f, -1.0f, -1.0f, 0.0f, 0.0f,
-1.0f, 1.0f, -1.0f, 1.0f, 0.0f,
-1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
-1.0f, -1.0f, 1.0f, 0.0f, 1.0f,
1.0f, -1.0f, -1.0f, 0.0f, 0.0f,
1.0f, 1.0f, -1.0f, 1.0f, 0.0f,
1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
1.0f, -1.0f, 1.0f, 0.0f, 1.0f,
-1.0f, -1.0f, -1.0f, 0.0f, 0.0f,
-1.0f, -1.0f, 1.0f, 1.0f, 0.0f,
1.0f, -1.0f, 1.0f, 1.0f, 1.0f,
1.0f, -1.0f, -1.0f, 0.0f, 1.0f,
-1.0f, 1.0f, -1.0f, 0.0f, 0.0f,
-1.0f, 1.0f, 1.0f, 1.0f, 0.0f,
1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
1.0f, 1.0f, -1.0f, 0.0f, 1.0f
};
sg_buffer vbuf = sg_make_buffer(&(sg_buffer_desc){
.size = sizeof(vertices),
.content = 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,
.size = sizeof(indices),
.content = indices,
});
/* define the resource bindings */
bind = (sg_bindings){
.vertex_buffers[0] = vbuf,
.index_buffer = ibuf,
.fs_images[0] = img
};
/* shader to sample from array texture */
sg_shader shd = sg_make_shader(&(sg_shader_desc){
.attrs = {
[0].name = "position",
[1].name = "texcoord0"
},
.vs.uniform_blocks[0] = {
.size = sizeof(params_t),
.uniforms = {
[0] = { .name="mvp", .type=SG_UNIFORMTYPE_MAT4 },
[1] = { .name="offset0", .type=SG_UNIFORMTYPE_FLOAT2 },
[2] = { .name="offset1", .type=SG_UNIFORMTYPE_FLOAT2 },
[3] = { .name="offset2", .type=SG_UNIFORMTYPE_FLOAT2 }
}
},
.fs.images[0] = { .name="tex", .type=SG_IMAGETYPE_ARRAY },
.vs.source =
"#version 300 es\n"
"uniform mat4 mvp;\n"
"uniform vec2 offset0;\n"
"uniform vec2 offset1;\n"
"uniform vec2 offset2;\n"
"in vec4 position;\n"
"in vec2 texcoord0;\n"
"out vec3 uv0;\n"
"out vec3 uv1;\n"
"out vec3 uv2;\n"
"void main() {\n"
" gl_Position = mvp * position;\n"
" uv0 = vec3(texcoord0 + offset0, 0.0);\n"
" uv1 = vec3(texcoord0 + offset1, 1.0);\n"
" uv2 = vec3(texcoord0 + offset2, 2.0);\n"
"}\n",
.fs.source =
"#version 300 es\n"
"precision mediump float;\n"
"precision lowp sampler2DArray;\n"
"uniform sampler2DArray tex;\n"
"in vec3 uv0;\n"
"in vec3 uv1;\n"
"in vec3 uv2;\n"
"out vec4 frag_color;\n"
"void main() {\n"
" vec4 c0 = texture(tex, uv0);\n"
" vec4 c1 = texture(tex, uv1);\n"
" vec4 c2 = texture(tex, uv2);\n"
" frag_color = vec4(c0.xyz + c1.xyz + c2.xyz, 1.0);\n"
"}\n"
});
/* create pipeline object */
pip = sg_make_pipeline(&(sg_pipeline_desc){
.layout = {
.attrs = {
[0].format=SG_VERTEXFORMAT_FLOAT3,
[1].format=SG_VERTEXFORMAT_FLOAT2
}
},
.shader = shd,
.index_type = SG_INDEXTYPE_UINT16,
.depth_stencil = {
.depth_compare_func = SG_COMPAREFUNC_LESS_EQUAL,
.depth_write_enabled = true
},
.rasterizer.cull_mode = SG_CULLMODE_BACK
});
/* default pass action */
pass_action = (sg_pass_action){
.colors[0] = { .action=SG_ACTION_CLEAR, .val={0.0f, 0.0f, 0.0f, 1.0f} }
};
draw();
return 0;
}
void draw() {
/* rotated model matrix */
rx += 0.25f; ry += 0.5f;
hmm_mat4 rxm = HMM_Rotate(rx, HMM_Vec3(1.0f, 0.0f, 0.0f));
hmm_mat4 rym = HMM_Rotate(ry, HMM_Vec3(0.0f, 1.0f, 0.0f));
hmm_mat4 model = HMM_MultiplyMat4(rxm, rym);
/* model-view-projection matrix for vertex shader */
hmm_mat4 proj = HMM_Perspective(60.0f, (float)emsc_width()/(float)emsc_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));
hmm_mat4 view_proj = HMM_MultiplyMat4(proj, view);
params_t vs_params;
vs_params.mvp = HMM_MultiplyMat4(view_proj, model);
/* uv offsets */
float offset = (float)frame_index * 0.0001f;
vs_params.offset0 = HMM_Vec2(-offset, offset);
vs_params.offset1 = HMM_Vec2(offset, -offset);
vs_params.offset2 = HMM_Vec2(0.0f, 0.0f);
sg_begin_default_pass(&pass_action, emsc_width(), emsc_height());
sg_apply_pipeline(pip);
sg_apply_bindings(&bind);
sg_apply_uniforms(SG_SHADERSTAGE_VS, 0, &vs_params, sizeof(vs_params));
sg_draw(0, 36, 1);
sg_end_pass();
sg_commit();
frame_index++;
}