WebGPU in C++


Set enviorement


To make it simple I'm going to use sokol app.

          
  sapp_desc sokol_main(int argc, char **argv)
  {
    sapp_desc app = {};
    app.width = gWindowWidth;
    app.height = gWindowHeight;
    app.frame_cb = onFrame;
    app.init_cb = onInit;
    app.cleanup_cb = onEnd;
    // app.win32_console_create = true;
    app.win32_console_attach = true;
    return app;
  }
          
        


On Init


When we star the program, we are going to load gladGL, init the shaders, upload the mesh & configurate the triangles draw.

          
  static float gRawMesh0[3 * 3] = {
    -0.86f, -0.49f, 0.0f,
    0.0f, 1.0f, 0.0f, 
    0.86f, -0.49f, 0.0f,
  };
          
  static unsigned int gIndices[3] = {
  // note that we start from 0!
    0, 1, 2,
  };

  static unsigned int gVBO0 = 0, gVAO0 = 0, gEBO0 = 0;
  
  void onInit()
  {
    gladLoadGL();
        
    stm_setup(); // Init time libreria SOKOL
           
    // Shaders
    char *vertex_shader_source = (char *)ReadSrcCode("vertex.glslv");
    char *fragment_shader_source = (char *)ReadSrcCode("fragment.glslf");
           
    ShadersInit(gShaderProgram, vertex_shader_source, fragment_shader_source);
           
    // Custom own function
    UploadMesh(gRawMesh0, sizeof(gRawMesh0), gIndices, sizeof(gIndices), 
               gVBO0, gVAO0, gEBO0);
    
    // Triangles draw configuration
    glDisable(GL_CULL_FACE);
    glCullFace(GL_BACK);
            
    glEnable(GL_DEPTH_TEST);
  
    // Uniforms
    gLocationColor = glGetUniformLocation(gShaderProgram, "RawColor");
  }
          
        


Upload Mesh function


Here we Upload a mesh object that has a vertex array and a index array.

          
static void UploadMesh(float *mesh, int mesh_size,
            unsigned int *indices, int indices_size,
            unsigned int &VBO, unsigned int &VAO, unsigned int &EBO)
{

// Generamos 2 instancias de objetos OGL: array y buffer (sin inicializar)
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glGenBuffers(1, &EBO);

// Enfocamos ambos objetos, VAO y VBO
// Esto es recomendable, sino podriamos tocar atributos de VBOs y 
// VAOs usados anteriormente
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);

/*  
  Configuramos el buffer (tipo y cantidad de memoria). 
  EN ESTE MOMENTO SE COPIAN LOS VERTICES
  STATIC_DRAW significa que los datos no se modificaran en el futuro
*/
glBufferData(GL_ARRAY_BUFFER, mesh_size, mesh, GL_STATIC_DRAW);

// Idem  para los indices
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices_size, indices, GL_STATIC_DRAW);

/* 
  Configuramos el array describiendo los atributos de la estructura 
  (posicion, normal, uv, etc)
  Es un array de vertices de 3 floats, con una separacion entre ellos de 12 bytes
  El indice de attributo 0 se refiere normalmente a vertices (X,Y,X),
  el 1 a normales (X,Y,Z) y el 2 a coord. textura (U,V). Pero no esta recomendado
  usarlos asi, sino con (ej,) glGetAttribLocation(program, "position")
  Ademas, glVertexAttribPointer relacion el buffer con este array por el ultimo "bind"
*/
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void *)0);
glEnableVertexAttribArray(0);
/* 
  Se quita el foco del VAO y el VBO; glVertexAttribPointer ya se ha 
  quedado las referencias.
  Quitar el foco evita que otras llamadas puedan modificar estos 
  objetos accidentalmente.
  (No se debe quitar el foco del EBO mientras el VAO este en foco, 
  o perdera la referencia)
*/
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
          
        


On Frame


To make it simple I'm going to use sokol app.

          
static unsigned int gShaderProgram = 0;
static int gLocationColor = 0;

void onFrame()
{
  gWindowWidth = sapp_width();
  gWindowHeight = sapp_height();
  double time = stm_ms(stm_now());
            
  // Transformaciones de objeto y perspectiva (la camara se supone fija mirando a Z)
  glm::mat4 model = glm::mat4(1.0f);
  glm::mat4 projection = glm::mat4(1.0f);

  // Ponemos nuestra triangulo frente a la camara
  model = glm::translate(model, glm::vec3(0.0f, 0.0f, -4.0f));
  model = glm::rotate(model, 0.001f * (float)time, glm::vec3(0.0f, 1.0f, 0.0f));
  model = glm::rotate(model, 0.002f * (float)time, glm::vec3(1.0f, 0.0f, 0.0f));
  model = glm::rotate(model, 0.003f * (float)time, glm::vec3(0.0f, 0.0f, 1.0f));

  // Proyeccion con un FOV de 45 grados
  projection = glm::perspective(glm::radians(45.0f), 
               ((float)gWindowWidth) / (float)gWindowHeight, 0.1f, 100.0f);
            
  // Render
  glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
            
  glUseProgram(gShaderProgram);
           
  glUniform4f(gLocationColor, 1.0f, 0.4f, 1.0f, 1.0f);
            
  // Obtenemos los identificadores (location) de los "uniform" de los shaders
  unsigned int modelLoc = glGetUniformLocation(gShaderProgram, "model");
  unsigned int projLoc = glGetUniformLocation(gShaderProgram, "projection");
  
  // ...y enviamos las matrices a los shaders
  glUniformMatrix4fv(modelLoc, 1, GL_FALSE, &model[0][0]);
  glUniformMatrix4fv(projLoc, 1, GL_FALSE, &projection[0][0]);
            
  glBindVertexArray(gVAO0);
  
  // Draw elements dibuja primitivas indexadas (en nuestros caso, 
  // mallas de triangulos)
  glDrawElements(GL_TRIANGLES, sizeof(gIndices) / sizeof(unsigned int), 
  GL_UNSIGNED_INT, 0);
}
          
        


On End


Here we need to free the memory if we don't want any memory leak. We free the buffers and the shader program.

          
  void onEnd()
  {
    glDeleteVertexArrays(1, &gVAO0);
    glDeleteBuffers(1, &gVBO0);
    glDeleteBuffers(1, &gEBO0);
    glDeleteProgram(gShaderProgram);
  }