Edit

kc3-lang/kc3/gl/gl_object.c

Branch :

  • gl/gl_object.c
  • /* kc3
     * Copyright from 2022 to 2025 kmx.io <contact@kmx.io>
     *
     * Permission is hereby granted to use this software granted the above
     * copyright notice and this permission paragraph are included in all
     * copies and substantial portions of this software.
     *
     * THIS SOFTWARE IS PROVIDED "AS-IS" WITHOUT ANY GUARANTEE OF
     * PURPOSE AND PERFORMANCE. IN NO EVENT WHATSOEVER SHALL THE
     * AUTHOR BE CONSIDERED LIABLE FOR THE USE AND PERFORMANCE OF
     * THIS SOFTWARE.
     */
    #include "../libkc3/kc3.h"
    #include "gl_deprecated.h"
    #include "gl_object.h"
    #include "gl_vertex.h"
    
    s_gl_object * gl_object_allocate (s_gl_object *object, uw vertex_count,
                                      uw triangle_count)
    {
      assert(object);
      assert(vertex_count);
      if (! array_init(&object->vertex, sym_1("GL.Vertex[]"), 1,
                       &vertex_count) ||
          ! array_allocate(&object->vertex) ||
          ! array_init(&object->triangle, sym_1("GL.Triangle[]"), 1,
                       &triangle_count) ||
          ! array_allocate(&object->triangle))
        return NULL;
      return object;
    }
    
    void gl_object_clean (s_gl_object *object)
    {
      assert(object);
      assert(glGetError() == GL_NO_ERROR);
      if (object->gl_vbo)
        glDeleteBuffers(1, &object->gl_vbo);
      assert(glGetError() == GL_NO_ERROR);
      if (object->gl_ebo)
        glDeleteBuffers(1, &object->gl_ebo);
      assert(glGetError() == GL_NO_ERROR);
      array_clean(&object->vertex);
      array_clean(&object->triangle);
    }
    
    s_gl_object * gl_object_init (s_gl_object *object)
    {
      s_gl_object tmp = {0};
      assert(glGetError() == GL_NO_ERROR);
      glGenBuffers(1, &tmp.gl_vbo);
      assert(glGetError() == GL_NO_ERROR);
      glGenBuffers(1, &tmp.gl_ebo);
      assert(glGetError() == GL_NO_ERROR);
      *object = tmp;
      return object;
    }
    
    void gl_object_render (const s_gl_object *object)
    {
      GLenum error;
      assert(object);
      assert(glGetError() == GL_NO_ERROR);
      if (object->triangle.count == 0) {
        err_puts("gl_object_render: triangle count is 0!");
        return;
      }
      glBindBuffer(GL_ARRAY_BUFFER, object->gl_vbo);
      glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(s_gl_vertex),
                            (void*)offsetof(s_gl_vertex, pos_x));
      glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(s_gl_vertex),
                            (void*)offsetof(s_gl_vertex, normal_x));
      glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(s_gl_vertex),
                            (void*)offsetof(s_gl_vertex, tex_coord_x));
      glEnableVertexAttribArray(0);
      glEnableVertexAttribArray(1);
      glEnableVertexAttribArray(2);
      assert(glGetError() == GL_NO_ERROR);
      glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, object->gl_ebo);
      assert(glGetError() == GL_NO_ERROR);
      glDrawElements(GL_TRIANGLES, object->triangle.count * 3,
                     GL_UNSIGNED_INT,
                     NULL);
      if ((error = glGetError()) != GL_NO_ERROR) {
        err_write_1("gl_object_render: glDrawElements: ");
        err_puts(gl_error_string(error));
        assert(! "gl_object_render: glDrawElements");
      }
      assert(glGetError() == GL_NO_ERROR);
    }
    
    void gl_object_render_points (const s_gl_object *object, u32 count)
    {
      GLenum error;
      assert(object);
      assert(glGetError() == GL_NO_ERROR);
      glBindBuffer(GL_ARRAY_BUFFER, object->gl_vbo);
      glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(s_gl_vertex),
                            (void*)offsetof(s_gl_vertex, pos_x));
      glEnableVertexAttribArray(0);
      assert(glGetError() == GL_NO_ERROR);
      glDrawArrays(GL_POINTS, 0, count);
      if ((error = glGetError()) != GL_NO_ERROR) {
        err_write_1("gl_object_render_points: glDrawArrays: ");
        err_puts(gl_error_string(error));
        assert(! "gl_object_render_points: glDrawArrays");
      }
    }
    
    void gl_object_render_triangles (const s_gl_object *object,
                                     u32 triangle_count)
    {
      GLenum error;
      assert(object);
      glBindBuffer(GL_ARRAY_BUFFER, object->gl_vbo);
      glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(s_gl_vertex),
                            (void*)offsetof(s_gl_vertex, pos_x));
      glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(s_gl_vertex),
                            (void*)offsetof(s_gl_vertex, normal_x));
      glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(s_gl_vertex),
                            (void*)offsetof(s_gl_vertex, tex_coord_x));
      glEnableVertexAttribArray(0);
      glEnableVertexAttribArray(1);
      glEnableVertexAttribArray(2);
      assert(glGetError() == GL_NO_ERROR);
      glDrawArrays(GL_TRIANGLES, 0, triangle_count * 3);
      if ((error = glGetError()) != GL_NO_ERROR) {
        err_write_1("gl_object_render_triangles: glDrawArrays: ");
        err_puts(gl_error_string(error));
        assert(! "gl_object_render_triangles: glDrawArrays");
      }
    }
    
    void gl_object_render_wireframe (const s_gl_object *object)
    {
      assert(object);
      assert(glGetError() == GL_NO_ERROR);
      glBindBuffer(GL_ARRAY_BUFFER, object->gl_vbo);
      glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(s_gl_vertex),
                            (void*)offsetof(s_gl_vertex, pos_x));
      glEnableVertexAttribArray(0);
      assert(glGetError() == GL_NO_ERROR);
      glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, object->gl_ebo);
      assert(glGetError() == GL_NO_ERROR);
      glDrawElements(GL_LINE_LOOP, object->triangle.count * 3,
                     GL_UNSIGNED_INT,
                     NULL);
      assert(glGetError() == GL_NO_ERROR);
    }
    
    void gl_object_transform (s_gl_object *object, const s_mat4 *matrix)
    {
      u32 i;
      s_gl_vertex *vertex;
      assert(object);
      assert(matrix);
      vertex = object->vertex.data;
      i = 0;
      while (i < object->vertex.count) {
        gl_vertex_transform(vertex, matrix);
        vertex++;
        i++;
      }
    }
    
    bool gl_object_update (s_gl_object *object)
    {
      //GLenum gl_error;
      assert(object);
      assert(object->gl_vbo);
      assert(object->gl_ebo);
      assert(object->vertex.data);
      assert(object->triangle.data);
      assert(glGetError() == GL_NO_ERROR);
      /* glBindVertexArray(object->gl_vao); // VAO not supported in GLES 2.0 */
      assert(glGetError() == GL_NO_ERROR);
      glBindBuffer(GL_ARRAY_BUFFER, object->gl_vbo);
      assert(glGetError() == GL_NO_ERROR);
      glBufferData(GL_ARRAY_BUFFER,
                   object->vertex.count * sizeof(s_gl_vertex),
                   object->vertex.data, GL_DYNAMIC_DRAW);
      assert(glGetError() == GL_NO_ERROR);
      gl_vertex_attrib();
      assert(glGetError() == GL_NO_ERROR);
      glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, object->gl_ebo);
      assert(glGetError() == GL_NO_ERROR);
      glBufferData(GL_ELEMENT_ARRAY_BUFFER,
                   object->triangle.count * sizeof(s_gl_triangle),
                   object->triangle.data, GL_DYNAMIC_DRAW);
      assert(glGetError() == GL_NO_ERROR);
      return true;
    }