text: //------------------------------------------------------------------------------
  //  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.
  //------------------------------------------------------------------------------
  #define HANDMADE_MATH_IMPLEMENTATION
  #define HANDMADE_MATH_NO_SSE
  #include "HandmadeMath.h"
  #define GLFW_INCLUDE_NONE
  #include "GLFW/glfw3.h"
  #include "flextgl/flextGL.h"
  #define SOKOL_IMPL
  #define SOKOL_GLCORE33
  #include "sokol_gfx.h"
  
  /* a uniform block with a model-view-projection matrix */
  typedef struct {
      hmm_mat4 mvp;
  } params_t;
  
  int main() {
      const int WIDTH = 800;
      const int HEIGHT = 600;
  
      /* create GLFW window and initialize GL */
      glfwInit();
      glfwWindowHint(GLFW_SAMPLES, 4);
      glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
      glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
      glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE);
      glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
      GLFWwindow* w = glfwCreateWindow(WIDTH, HEIGHT, "Sokol Non-Interleaved Vertex Data GLFW", 0, 0);
      glfwMakeContextCurrent(w);
      glfwSwapInterval(1);
      flextInit();
  
      /* setup sokol_gfx */
      sg_desc desc = {0};
      sg_setup(&desc);
      assert(sg_isvalid());
  
      /* 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)
      });
  
      /* create shader */
      sg_shader shd = sg_make_shader(&(sg_shader_desc) {
          .vs.uniform_blocks[0] = {
              .size = sizeof(params_t),
              .uniforms = {
                  [0] = { .name="mvp", .type=SG_UNIFORMTYPE_MAT4 }
              }
          },
          .vs.source =
              "#version 330\n"
              "uniform mat4 mvp;\n"
              "layout(location=0) in vec4 position;\n"
              "layout(location=1) in vec4 color0;\n"
              "out vec4 color;\n"
              "void main() {\n"
              "  gl_Position = mvp * position;\n"
              "  color = color0;\n"
              "}\n",
          .fs.source =
              "#version 330\n"
              "in vec4 color;\n"
              "out vec4 frag_color;\n"
              "void main() {\n"
              "  frag_color = color;\n"
              "}\n"
      });
  
      /* create pipeline object */
      sg_pipeline 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,
      });
  
      /* define 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.
      */
      sg_bindings bind = {
          .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
      };
  
      /* default pass action */
      sg_pass_action pass_action = { 0 };
  
      /* 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));
      hmm_mat4 view_proj = HMM_MultiplyMat4(proj, view);
  
      params_t vs_params;
      float rx = 0.0f, ry = 0.0f;
      while (!glfwWindowShouldClose(w)) {
          /* rotated model matrix */
          rx += 1.0f; ry += 2.0f;
          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 */
          vs_params.mvp = HMM_MultiplyMat4(view_proj, model);
  
          int cur_width, cur_height;
          glfwGetFramebufferSize(w, &cur_width, &cur_height);
          sg_begin_default_pass(&pass_action, cur_width, cur_height);
          sg_apply_pipeline(pip);
          sg_apply_bindings(&bind);
          sg_apply_uniforms(SG_SHADERSTAGE_VS, 0, &SG_RANGE(vs_params));
          sg_draw(0, 36, 1);
          sg_end_pass();
          sg_commit();
          glfwSwapBuffers(w);
          glfwPollEvents();
      }
  
      sg_shutdown();
      glfwTerminate();
  }
  
  