~indefini/cypher

d97d18c6b0774d0fb69794cdb1b1fa6b8b37ea53 — chris 5 months ago main
Opengl wrapper
A  => .gitignore +3 -0
@@ 1,3 @@
/target
**/*.rs.bk
Cargo.lock

A  => Cargo.toml +16 -0
@@ 1,16 @@
[package]
name = "cypher-sys"
version = "0.1.0"
authors = ["chris <chris@indefini.org>"]
edition = "2021"

links = "cypher"
build = "build.rs"

[dependencies]
libc = "0.2"

[build-dependencies]
pkg-config = "0.3"
cc = "1.0"


A  => LICENSE +21 -0
@@ 1,21 @@
MIT License

Copyright (c) 2024 Christophe Sadoine

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

A  => README +1 -0
@@ 1,1 @@
OpenGL wrapper

A  => build.rs +32 -0
@@ 1,32 @@
use std::env;
use std::path::PathBuf;

fn main() {
    let paths = Vec::new();
    build_cypher(&paths);
}

fn build_cypher(include_paths: &[PathBuf]) {
    let mut config = cc::Build::new();

    for path in include_paths {
        config.include(path);
    }

    config
        .file("src/buffer.c")
        .file("src/cypher.c")
        .file("src/fbo.c")
        .file("src/shader.c")
        .file("src/texture.c");

    config.compile("libcypher.a");

    let out_dir = env::var("OUT_DIR").unwrap();

    println!("cargo:rustc-link-search=native={}", out_dir);
    println!(
        "cargo:include={}/src",
        env::current_dir().unwrap().display()
    );
}

A  => src/buffer.c +75 -0
@@ 1,75 @@
#include "buffer.h"
#include "log.h"

CglBuffer*
cgl_buffer_init(const void* data, uint count)
{
  CglBuffer* b = calloc(1, sizeof *b);
  b->target = GL_ARRAY_BUFFER;

  glGenBuffers(1, &b->id);
  glBindBuffer(b->target, b->id);
  glBufferData(
        b->target,
        //b->size,
        count * sizeof(GLfloat), //TODO size of f32
        data,
        GL_DYNAMIC_DRAW);

  return b;
}

CglBuffer*
cgl_buffer_index_init(const void* data, uint count)
{
  CglBuffer* b = calloc(1, sizeof *b);
  b->target = GL_ELEMENT_ARRAY_BUFFER;

  glGenBuffers(1, &b->id);
  glBindBuffer(b->target, b->id);
  glBufferData(
        b->target,
        //b->size,
        count * sizeof(GLuint), //TODO
        data,
        GL_DYNAMIC_DRAW);

  return b;
}

void
cgl_buffer_update(
    CglBuffer* b,
    const void* data,
    uint count)
{
  glBindBuffer(b->target, b->id);
  glBufferSubData(
        b->target,
        0,
        //b->size,
        count * sizeof(GLfloat), //TODO size of f32
        data);
}

void
cgl_buffer_index_update(
    CglBuffer* b,
    const void* data,
    uint count)
{
  glBindBuffer(b->target, b->id);
  glBufferSubData(
        b->target,
        0,
        //b->size,
        count * sizeof(GLuint), //TODO
        data);
}

void cgl_buffer_clean(CglBuffer* b)
{
  glDeleteBuffers(1, &b->id);
  free(b);
}


A  => src/buffer.h +21 -0
@@ 1,21 @@
#ifndef __buffer__
#define __buffer__
#include "gl.h"

typedef struct _CglBuffer CglBuffer;

struct _CglBuffer
{
  GLuint id;
  GLenum target;
};

CglBuffer* cgl_buffer_init(const void* data, uint count);
void cgl_buffer_update(CglBuffer* b, const void* data, uint count);

CglBuffer* cgl_buffer_index_init(const void* data, uint count);
void cgl_buffer_index_update(CglBuffer* b, const void* data, uint count);

void cgl_buffer_clean(CglBuffer* buf);

#endif

A  => src/cypher.c +165 -0
@@ 1,165 @@
#include "cypher.h"
#include "gl.h"
#include "stdio.h"
#include "shader.h"
#include "buffer.h"

void cypher_init_simple()
{
  // uncomment to display version
  //const GLubyte* ver_gl = glGetString(GL_VERSION);
  //const GLubyte* ver_glsl = glGetString(GL_SHADING_LANGUAGE_VERSION);
  //printf("cypher_init: GL %s, GLSL %s \n", ver_gl, ver_glsl);

  glEnable(GL_DEPTH_TEST);
  glEnable(GL_STENCIL_TEST);
  glDepthFunc(GL_LEQUAL);
  glClearDepthf(1.0f);
  glClearStencil(0);
}

void cypher_init(rust_callback cb_init, void* data)
{
  cypher_init_simple();

  if (cb_init && data) {
    cb_init(data);
  }
}

void cypher_draw_start(int w, int h)
{
  glViewport(0, 0, w, h);

  //glClearColor(0.2, 0.4, 0.2, 1.0);
  glClearColor(0.1, 0.1, 0.1, 1.0);
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

  glEnable(GL_BLEND);
  glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}

void cypher_viewport_set(int x, int y, int w, int h)
{
  glViewport(x, y, w, h);
}

void cypher_viewport_get(int* v)
{
  glGetIntegerv(GL_VIEWPORT, v);
}


//use for profiling
void cypher_draw_end()
{
  glFinish();
}

void cypher_draw(rust_callback cb_draw, void* data, int w, int h)
{
  cypher_draw_start(w, h);

  if (cb_draw && data) {
    cb_draw(data);
  }
}

void cypher_resize_simple(int w, int h)
{
  // GL Viewport stuff. you can avoid doing this if viewport is all the
  // same as last frame if you want
  glViewport(0, 0, w, h);
}

void cypher_resize(resize_callback cb_resize, void* data, int w, int h)
{
  cypher_resize_simple(w, h);

  if (cb_resize && data) {
    cb_resize(data, w, h);
  }
}

void cgl_clear()
{
  glClear(GL_DEPTH_BUFFER_BIT);
}

static CglShaderAttribute* _position_attribute;
static CglShader* shader;

void demo_attribute_add(void* data, const char* name, CglShaderAttribute* att)
{
  printf("adding attribute %s, %p \n", name, data);
  _position_attribute = att;
}

void cypher_demo_init()
{
  printf("init demo \n");
  cypher_init_simple();
  glViewport(0, 0, 1000, 1000);

  const char * vert = "\
    attribute vec3 position;\
    void main(void)\
    {\
      gl_Position = vec4(position, 1.0);\
    }\
  ";

  const char * frag = "\
  void main(void)\
  {\
    gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\
  }";

  shader = cgl_shader_init_string(vert, frag);
  cgl_shader_attributes_init(shader, demo_attribute_add, NULL);

  cgl_shader_use(shader);

  int datalen = 3*3;
  float data[] = {
    /*
    0.0,0.0,-1.0,
    0.0,1.0,-1.0,
    1.0,0.0,-1.0
    */
    -1.0,-1.0,-1.0,
    -1.0,1.0,-1.0,
    1.0,-1.0,-1.0,
  };

  CglBuffer* buffer = cgl_buffer_init(data, datalen);
  cgl_shader_attribute_send(_position_attribute, buffer);
}

void cypher_demo_draw()
{
  glClearColor(0.2, 0.4, 0.2, 1.0);
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

  glEnable(GL_BLEND);
  glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

  cgl_shader_use(shader);
  int vertex_count = 3;
  cgl_draw( vertex_count);

  printf("drawing demo \n");
}

void cypher_cull(int cull)
{
  if (cull == 0) {
    //glDisable(GL_CULL_FACE);
    glCullFace(GL_BACK);
  }
  else {
    glEnable(GL_CULL_FACE);
    glCullFace(GL_FRONT);
  }
}


A  => src/cypher.h +19 -0
@@ 1,19 @@
#ifndef __cypher__
#define __cypher__

typedef void (*rust_callback)(void* data);
typedef void (*resize_callback)(void* data, int w, int h);

void cypher_init_simple();
void cypher_init(rust_callback cb_init, void* data);
void cypher_draw(rust_callback cb_draw, void* data, int w, int h);
void cypher_draw_start(int w, int h);
void cypher_draw_end();
void cypher_resize_simple(int w, int h);
void cypher_resize(resize_callback cb_resize, void* data, int w, int h);

void cgl_clear();

void cypher_cull(int cull);

#endif

A  => src/fbo.c +292 -0
@@ 1,292 @@
#include "fbo.h"
#include "log.h"
#include <stdio.h>

CglFbo*
cgl_create_fbo()
{
  CglFbo* f = calloc(1, sizeof *f);
  f->has_color = 1;

  glGenTextures(1, &f->texture_depth_stencil_id);
  glBindTexture(GL_TEXTURE_2D, f->texture_depth_stencil_id);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

  //TODO texture resolution
  int width = 1200;
  int height = 400;
  /*
  glTexImage2D(
        GL_TEXTURE_2D,
        0,
        GL_DEPTH_COMPONENT,
        width,
        height,
        0,
        GL_DEPTH_COMPONENT,
        GL_FLOAT,
        NULL);
        */
  glTexImage2D(
        GL_TEXTURE_2D,
        0,
        GL_DEPTH_STENCIL_OES,
        width,
        height,
        0,
        GL_DEPTH_STENCIL_OES,
        GL_UNSIGNED_INT_24_8_OES,
        NULL);

  glBindTexture(GL_TEXTURE_2D, 0);

  glGenTextures(1, &f->texture_color);
  glBindTexture(GL_TEXTURE_2D, f->texture_color);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

  glTexImage2D(
        GL_TEXTURE_2D,
        0,
        GL_RGB,
        width,
        height,
        0,
        GL_RGB, //GL_DEPTH_STENCIL_OES,
        GL_UNSIGNED_SHORT_5_6_5, //GL_UNSIGNED_INT_24_8_OES,
        NULL);

  glBindTexture(GL_TEXTURE_2D, 0);


  /*
  glGenRenderbuffers(1, &f->rb);
  glBindRenderbuffer(GL_RENDERBUFFER, f->rb);
  glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA, width, height);
  //glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8_OES, width, height);
  glBindRenderbuffer(GL_RENDERBUFFER, 0);
  */

  glGenFramebuffers(1, &f->fbo);
  glBindFramebuffer(GL_FRAMEBUFFER, f->fbo);

  glFramebufferTexture2D(
        GL_FRAMEBUFFER,
        GL_DEPTH_ATTACHMENT,
        GL_TEXTURE_2D,
        f->texture_depth_stencil_id,
        0);

  glFramebufferTexture2D(
        GL_FRAMEBUFFER,
        GL_STENCIL_ATTACHMENT,
        GL_TEXTURE_2D,
        f->texture_depth_stencil_id,
        0);

  glFramebufferTexture2D(
        GL_FRAMEBUFFER,
        GL_COLOR_ATTACHMENT0,
        GL_TEXTURE_2D,
        f->texture_color,
        0);

  /*
  glFramebufferRenderbuffer(
        GL_FRAMEBUFFER,
        GL_COLOR_ATTACHMENT0,
        GL_RENDERBUFFER,
        f->rb);
        */


  GLenum e = glCheckFramebufferStatus(GL_FRAMEBUFFER);

  if (e != GL_FRAMEBUFFER_COMPLETE) {
    printf("cypher::fbo, error : not complete\n");
  }

  glBindFramebuffer(GL_FRAMEBUFFER, 0);

  return f;
}

void
cgl_fbo_use(CglFbo* f)
{
  glBindTexture(GL_TEXTURE_2D, 0);
  glBindFramebuffer(GL_FRAMEBUFFER, f->fbo);
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT) ;
  glEnable(GL_STENCIL_TEST);
  glStencilFunc(GL_ALWAYS, 0x1, 0x1);
  glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
  //TODO clear
}

void
cgl_fbo_use_end()
{
  glBindFramebuffer(GL_FRAMEBUFFER,0);
}

void
cgl_fbo_resize(CglFbo* f, int w, int h)
{
  glBindTexture(GL_TEXTURE_2D, f->texture_depth_stencil_id);

  glTexImage2D(
        GL_TEXTURE_2D,
        0,
        GL_DEPTH_STENCIL_OES,
        w,
        h,
        0,
        GL_DEPTH_STENCIL_OES,
        GL_UNSIGNED_INT_24_8_OES,
        NULL);

  glBindTexture(GL_TEXTURE_2D, 0);

  if (f->has_color) {
    glBindTexture(GL_TEXTURE_2D, f->texture_color);

    glTexImage2D(
        GL_TEXTURE_2D,
        0,
        GL_RGB,
        w,
        h,
        0,
        GL_RGB,
        GL_UNSIGNED_SHORT_5_6_5,
        NULL);

    glBindTexture(GL_TEXTURE_2D, 0);
  }

  glBindRenderbuffer(GL_RENDERBUFFER, f->rb);
  glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA, w, h);
  //glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8_OES, w, h);
  glBindRenderbuffer(GL_RENDERBUFFER, 0);
}

void
cgl_fbo_destroy(CglFbo* s)
{
  //TODO
  printf("TODO, destroy fbo : %p \n", s);
}


CglFbo*
cgl_create_fbo_depth_only()
{
  CglFbo* f = calloc(1, sizeof *f);
  f->has_color = 0;

  glGenTextures(1, &f->texture_depth_stencil_id);
  glBindTexture(GL_TEXTURE_2D, f->texture_depth_stencil_id);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

  //TODO texture resolution
  int width = 1200;
  int height = 400;
  /*
  glTexImage2D(
        GL_TEXTURE_2D,
        0,
        GL_DEPTH_COMPONENT,
        width,
        height,
        0,
        GL_DEPTH_COMPONENT,
        GL_FLOAT,
        NULL);
        */
  glTexImage2D(
        GL_TEXTURE_2D,
        0,
        GL_DEPTH_STENCIL_OES,
        width,
        height,
        0,
        GL_DEPTH_STENCIL_OES,
        GL_UNSIGNED_INT_24_8_OES,
        NULL);

  glBindTexture(GL_TEXTURE_2D, 0);

  glGenFramebuffers(1, &f->fbo);
  glBindFramebuffer(GL_FRAMEBUFFER, f->fbo);

  glFramebufferTexture2D(
        GL_FRAMEBUFFER,
        GL_DEPTH_ATTACHMENT,
        GL_TEXTURE_2D,
        f->texture_depth_stencil_id,
        0);

  glFramebufferTexture2D(
        GL_FRAMEBUFFER,
        GL_STENCIL_ATTACHMENT,
        GL_TEXTURE_2D,
        f->texture_depth_stencil_id,
        0);

  GLenum e = glCheckFramebufferStatus(GL_FRAMEBUFFER);

  if (e == GL_FRAMEBUFFER_COMPLETE) {
    printf("---->>>>>buffer complete\n");
  }
  else
    printf("---->>>>>buffer NOOOOOOOOOOOOOOOT complete\n");

  glBindFramebuffer(GL_FRAMEBUFFER, 0);

  return f;
}

CglEglFbo* cgl_egl_fbo(void* egl_image)
{
  CglEglFbo* f = calloc(1, sizeof *f);

  GLuint rbo = 0;
  glGenRenderbuffers(1, &rbo);
  glBindRenderbuffer(GL_RENDERBUFFER, rbo);
  f->rbo = rbo;

  //PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC glEGLImageTargetRenderbufferStorageOES =
  //(PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC) eglGetProcAddress("glEGLImageTargetRenderbufferStorageOES");

  glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER, egl_image);
  glBindRenderbuffer(GL_RENDERBUFFER, 0);

  GLuint fbo = 0;
  glGenFramebuffers(1, &fbo);
  glBindFramebuffer(GL_FRAMEBUFFER, fbo);
  glFramebufferRenderbuffer(
      GL_FRAMEBUFFER,
      GL_COLOR_ATTACHMENT0,
      GL_RENDERBUFFER,
      rbo
      );
  //TODO do something with status or erase
  //GLuint status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
  f->fbo = fbo;
  glBindFramebuffer(GL_FRAMEBUFFER, 0);
  return f;
}

void cgl_egl_fbo_use(const CglEglFbo* f)
{
  glBindFramebuffer(GL_FRAMEBUFFER, f->fbo);
}


A  => src/fbo.h +34 -0
@@ 1,34 @@
#ifndef __fbo__
#define __fbo__
#include "gl.h"

typedef struct _CglFbo CglFbo;

struct _CglFbo {
  GLuint texture_depth_stencil_id;
  GLuint texture_color;
  GLuint fbo;
  GLuint rb;
  //bool
  int has_color;
};

CglFbo* cgl_create_fbo();
CglFbo* cgl_create_fbo_depth_only();
void cgl_fbo_use(CglFbo* fbo);
void cgl_fbo_use_end();
void cgl_fbo_resize(CglFbo* f, int w, int h);
void cgl_fbo_destroy(CglFbo* s);


typedef struct _CglEglFbo CglEglFbo;

struct _CglEglFbo {
  GLuint fbo;
  GLuint rbo;
};

CglEglFbo* cgl_egl_fbo(void* egl_image);
void cgl_egl_fbo_use(const CglEglFbo* fbo);

#endif

A  => src/gl.h +11 -0
@@ 1,11 @@
#ifndef __gl__
#define __gl__

#include "stdlib.h"
#define GL_GLEXT_PROTOTYPES 1
#include "GLES2/gl2.h"
#include "GLES2/gl2ext.h"
typedef unsigned int uint;

#endif


A  => src/lib.rs +1 -0
@@ 1,1 @@
//nothing here

A  => src/log.h +9 -0
@@ 1,9 @@
#ifndef __log__
#define __log__
#include <stdio.h>

#define LOG(str,...) do {printf("LOG : "); printf(str, ## __VA_ARGS__); printf("\n");} while (0)
#define ERR(str,...) do {printf("ERROR : "); printf(str, ## __VA_ARGS__); printf("\n");} while (0)


#endif

A  => src/shader.c +291 -0
@@ 1,291 @@
#include "shader.h"
#include "log.h"
#include "stdio.h"
#include "gl.h"

CglShader*
cgl_shader_init_string(const char* vert, const char* frag)
{
  CglShader* s = calloc(1, sizeof *s);
  //TODO factorize this by creating a function that get the shader id
  s->vert_shader = glCreateShader(GL_VERTEX_SHADER);
  if (s->vert_shader == 0)
    ERR("there was an error creating this vertex shader :\n%s\n", vert);

  s->frag_shader = glCreateShader(GL_FRAGMENT_SHADER);
  if (s->frag_shader == 0)
    ERR("there was an error creating this fragment shader :\n%s\n", frag);

  glShaderSource(s->vert_shader, 1, &vert, 0);
  glCompileShader(s->vert_shader);

  GLint status;
  GLint info_length;
  GLchar* message;

  glGetShaderiv(s->vert_shader, GL_COMPILE_STATUS, &status);
  if (status == GL_FALSE) {
    ERR("There was an error compiling this vertex shader :\n%s\n", vert);
    glGetShaderiv(s->vert_shader, GL_INFO_LOG_LENGTH, &info_length);
    message = malloc(info_length);
    glGetShaderInfoLog(s->vert_shader, info_length, 0, message);
    ERR("Message was : '%s'",message);
    free(message);
  }

  glShaderSource(s->frag_shader, 1, &frag, 0);
  glCompileShader(s->frag_shader);

  glGetShaderiv(s->frag_shader, GL_COMPILE_STATUS, &status);
  if (status == GL_FALSE) {
    ERR("There was an error compiling this fragment shader:\n%s\n", frag);
    glGetShaderiv(s->frag_shader, GL_INFO_LOG_LENGTH, &info_length);
    message = malloc(info_length);
    glGetShaderInfoLog(s->frag_shader, info_length, 0, message);
    ERR("Message was : '%s'",message);
    free(message);
  }

  s->program = glCreateProgram();
  glAttachShader(s->program, s->vert_shader);
  glAttachShader(s->program, s->frag_shader);
  glLinkProgram(s->program);

  glGetProgramiv(s->program, GL_LINK_STATUS, &status);
  if (status == GL_FALSE) {
    ERR("There was an error in linking the program, frag : \n%s\n", frag );
    glGetProgramiv(s->program, GL_INFO_LOG_LENGTH, &info_length);
    message = malloc(info_length);
    glGetProgramInfoLog(s->program, info_length, 0, message);
    ERR("Message was : '%s'",message);
    free(message);
  }

  return s;
}

static CglShaderAttribute*
_cgl_shader_attribute_new(CglShader *s, const char* name, uint size)
{
  GLint att_tmp = glGetAttribLocation(s->program, name);
  if (att_tmp == -1) {
    ERR("Error in getting attribute '%s' at line %d", name, __LINE__);
    return NULL;
  }
  else{
    CglShaderAttribute* cgl_att = calloc(1, sizeof *cgl_att);
    cgl_att->location = att_tmp;
    //TODO printf("cypher: attributes check, name : %s, size: %i \n", name, size);
    cgl_att->size = size;
    cgl_att->type = GL_FLOAT;

    return cgl_att;
  }
}

//index is for sampler/texture, if none then -1
CglShaderUniform*
cgl_shader_uniform_new(CglShader *s, const char* name, int index)
{
  GLint uni_tmp = glGetUniformLocation(s->program, name);
  if (uni_tmp == -1) {
    ERR("Error in getting uniform '%s' at line %d", name, __LINE__);
    return NULL;
  }
  else{
    CglShaderUniform* cgl_uni = calloc(1, sizeof *cgl_uni);
    cgl_uni->location = uni_tmp;
    cgl_uni->sampler_index = index;
    return cgl_uni;
  }
}

void
cgl_shader_use(CglShader* s)
{
  glUseProgram(s->program);
}

void
cgl_shader_attribute_send(CglShaderAttribute* att,  CglBuffer* buf)
{
  glBindBuffer(buf->target, buf->id);
  glEnableVertexAttribArray(att->location);

  glVertexAttribPointer(
        att->location,
        att->size,
        att->type,
        GL_FALSE,
        0,//buf->stride, //TODO
        0);

}

void
cgl_draw(uint vertex_count)
{
  glDrawArrays(GL_TRIANGLES, 0, vertex_count );
  glBindBuffer(GL_ARRAY_BUFFER, 0);
}

void
cgl_draw_lines(uint vertex_count)
{
  glDrawArrays(GL_LINES, 0, vertex_count );
  glBindBuffer(GL_ARRAY_BUFFER, 0);
}


void
cgl_draw_faces(const CglBuffer* buffer, uint index_count)
{
  glBindBuffer(buffer->target, buffer->id);
  glDrawElements(
        GL_TRIANGLES,
        index_count,
        GL_UNSIGNED_INT,
        0);

  glBindBuffer(buffer->target, 0);
}

void
cgl_draw_end()
{
  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
  glBindBuffer(GL_ARRAY_BUFFER, 0);
  //TODO glDisableVertexAttribArray?
}

void
cgl_shader_uniform_int_set(CglShaderUniform* uni, int i)
{
  glUniform1i(uni->location, i);
}

void
cgl_shader_uniform_float_set(CglShaderUniform* uni, float f)
{
  glUniform1f(uni->location, f);
}

void
cgl_shader_uniform_vec2_set(CglShaderUniform* uni, float x, float y)
{
  glUniform2f(uni->location, x, y);
}

void
cgl_shader_uniform_vec3_set(CglShaderUniform* uni, float x, float y, float z)
{
  glUniform3f(uni->location, x, y , z);
}

void
cgl_shader_uniform_vec4_set(CglShaderUniform* uni, float x, float y, float z, float w)
{
  glUniform4f(uni->location, x, y , z, w);
}

void
cgl_shader_uniform_mat4_set(CglShaderUniform* uni, const float* matrix)
{
  glUniformMatrix4fv(uni->location, 1, GL_FALSE, matrix);
}

void
cgl_shader_uniform_mat3_set(CglShaderUniform* uni, const float* matrix)
{
  glUniformMatrix3fv(uni->location, 1, GL_FALSE, matrix);
}

void
cgl_shader_uniform_texture_id_set(CglShaderUniform* uni, GLuint id, uint i)
{
  glUniform1i(uni->location, i);
  glActiveTexture(GL_TEXTURE0 + i);
  glBindTexture(GL_TEXTURE_2D, id);
}


void
cgl_shader_uniform_texture_set(CglShaderUniform* uni, const CglTexture* texture, uint i)
{
  cgl_shader_uniform_texture_id_set(uni, texture->id, i);
}


void
cgl_shader_uniform_fbo_depth_set(CglShaderUniform* uni, const CglFbo* fbo, uint i)
{
  glUniform1i(uni->location, i);
  glActiveTexture(GL_TEXTURE0 + i);
  glBindTexture(GL_TEXTURE_2D, fbo->texture_depth_stencil_id);
  //printf("uniform fbo send  id %d, index %d \n", fbo->texture_depth_stencil_id, i);
}

void
cgl_shader_uniform_fbo_color_set(CglShaderUniform* uni, const CglFbo* fbo, uint i)
{
  glUniform1i(uni->location, i);
  glActiveTexture(GL_TEXTURE0 + i);
  glBindTexture(GL_TEXTURE_2D, fbo->texture_color);
  //printf("uniform fbo send  id %d, index %d \n", fbo->texture_depth_stencil_id, i);
}

void
cgl_shader_uniforms_init(CglShader* s, uniform_set_cb cb, void* data)
{
  GLint num_uniforms;
  glGetProgramiv(s->program, GL_ACTIVE_UNIFORMS, &num_uniforms);
  GLchar uniform_name[256];
  GLsizei length;
  GLint size;
  GLenum type;

  int i = 0;
  int sampler_index = 0;
  for (i = 0; i < num_uniforms; i++){
    glGetActiveUniform(s->program, i, sizeof(uniform_name), &length, &size, &type, uniform_name);

    int index = -1;
    if (type == GL_SAMPLER_2D) {
      index = sampler_index;
      sampler_index++;
    }

    CglShaderUniform* uni = cgl_shader_uniform_new(s, uniform_name, index);
    cb(data, uniform_name, uni);
   }
}

void
cgl_shader_attributes_init(CglShader* s, attribute_set_cb cb, void* data)
{
  GLint num_attributes;
  glGetProgramiv(s->program, GL_ACTIVE_ATTRIBUTES, &num_attributes);
  GLchar attribute_name[256];
  GLsizei length;
  GLint size;
  GLenum type;
  int i = 0;
  for (i = 0; i < num_attributes; i++) {
    glGetActiveAttrib(s->program, i, sizeof(attribute_name), &length, &size, &type, attribute_name);

    //TODO printf("cypher: attributes check, type : %i, size : %i \n", type, size);
    if (type == GL_FLOAT_VEC2){
      size *= 2;
    }
    else if (type == GL_FLOAT_VEC3){
      size *= 3;
    }
    else if (type == GL_FLOAT_VEC4){
      size *= 4;
    }

    CglShaderAttribute* att = _cgl_shader_attribute_new(s, attribute_name, size);
    cb(data, attribute_name, att);
   }
}


A  => src/shader.h +83 -0
@@ 1,83 @@
#ifndef __shader__
#define __shader__
#include "gl.h"
#include "buffer.h"
#include "texture.h"
#include "fbo.h"

typedef struct _CglShaderAttribute CglShaderAttribute;

struct _CglShaderAttribute
{
  GLint location;
  GLint size;
  GLenum type;
};


typedef struct _CglShaderUniform CglShaderUniform;
struct _CglShaderUniform{
  GLint location;
  GLint sampler_index;
  //UniformType type;
};

typedef enum _CglUniformType CglUniformType;
enum _CglUniformType {
  CGL_UNIFORM_UNKNOWN,
  CGL_UNIFORM_TEXTURE,
  CGL_UNIFORM_INT,
  CGL_UNIFORM_FLOAT,
  CGL_UNIFORM_VEC2,
  CGL_UNIFORM_VEC3,
  CGL_UNIFORM_VEC4,
  CGL_UNIFORM_MAT3,
  CGL_UNIFORM_MAT4
};


typedef struct _CglShader CglShader;

struct _CglShader
{
  GLuint vert_shader;
  GLuint frag_shader;
  GLuint program;
};


typedef void (uniform_set_cb)(void* data, const char* name, CglShaderUniform* uni);
typedef void (attribute_set_cb)(void* data, const char* name, CglShaderAttribute* uni);

void cgl_shader_uniforms_init(CglShader* s, uniform_set_cb cb, void* data);
void cgl_shader_attributes_init(CglShader* s, attribute_set_cb cb, void* data);

CglShader* cgl_shader_init_string(const char* vert, const char* frag);

void cgl_shader_use(CglShader* s);


CglShaderAttribute* cgl_shader_attribute_new(CglShader *s, const char* name, uint size);
CglShaderUniform* cgl_shader_uniform_new(CglShader *s, const char* name, int index);

void cgl_shader_attribute_send(CglShaderAttribute* att,  CglBuffer* buf);
void cgl_draw(uint vertex_count);

void cgl_shader_uniform_int_set(CglShaderUniform* uni, int i);
void cgl_shader_uniform_float_set(CglShaderUniform* uni, float f);
void cgl_shader_uniform_vec2_set(CglShaderUniform* uni, float x, float y);
void cgl_shader_uniform_vec3_set(CglShaderUniform* uni, float x, float y, float z);
void cgl_shader_uniform_vec4_set(CglShaderUniform* uni, float x, float y, float z, float w);
void cgl_shader_uniform_mat4_set(CglShaderUniform* uni, const float* matrix);
void cgl_shader_uniform_texture_set(CglShaderUniform* uni, const CglTexture* texture, uint i);
void
cgl_shader_uniform_texture_id_set(CglShaderUniform* uni, GLuint id, uint i);

void cgl_shader_uniform_fbo_depth_set(CglShaderUniform* uni, const CglFbo* fbo, uint i);
void cgl_shader_uniform_fbo_color_set(CglShaderUniform* uni, const CglFbo* fbo, uint i);

void cgl_draw_faces(const CglBuffer* buffer, uint index_count);
void cgl_draw_lines(uint vertex_count);
void cgl_draw_end();

#endif

A  => src/texture.c +199 -0
@@ 1,199 @@
#include "texture.h"
#include "stdio.h"

// This enum must be exactly the same as the rust one used in dormin.
// at the time of writing it is at src/texture.rs
enum InternalFormat {
  Alpha,
  Rgb,
  Rgb8,
  Rgba,
  Rgba8
};


int get_gl_internal_format(int internal_format)
{
  int gl_internal_format = GL_RGBA;
  if (internal_format == Alpha) {
    gl_internal_format = GL_ALPHA;
  }
  else if (internal_format == Rgb) {
    gl_internal_format = GL_RGB;
  }
  else if (internal_format == Rgb8) {
    gl_internal_format = GL_RGB8_OES;
  }
  else if (internal_format == Rgba) {
    gl_internal_format = GL_RGBA;
  }
  else if (internal_format == Rgba8) {
    gl_internal_format = GL_RGBA8_OES;
  }
  else {
    //TODO
    printf("TODO: Texture internal format not implemented : %i \n", internal_format);
  }

  return gl_internal_format;
}

int get_gl_format_from_internal_format(int gl_internal_format)
{
  int gl_format = GL_RGBA;
  if (gl_internal_format == GL_ALPHA) {
    gl_format = GL_ALPHA;
  }
  else if (gl_internal_format == GL_RGB || gl_internal_format == GL_RGB8_OES) {
    gl_format = GL_RGB;
  }
  else if (gl_internal_format == GL_RGBA || gl_internal_format == GL_RGBA8_OES) {
    gl_format = GL_RGBA;
  }
  else {
    //TODO
    printf("TODO: Texture format not implemented : %i \n", gl_internal_format);
  }

  return gl_format;
}


CglTexture*
cgl_texture_init(const void* data, int internal_format, int width, int height, int filtering)
{
  CglTexture* t = cgl_texture_new(internal_format, filtering);
  int gl_internal_format = get_gl_internal_format(internal_format);
  int gl_format = get_gl_format_from_internal_format(gl_internal_format);

  glTexImage2D(
        GL_TEXTURE_2D,
        0,
        gl_internal_format,
        width,
        height,
        0,
        gl_format, //GL_RGBA, //TODO tex->format,
        GL_UNSIGNED_BYTE,
        data);

  return t;
}

void cgl_texture_update(
    CglTexture* t,
    int x,
    int y,
    int width,
    int height,
    int format,
    void *data
    )
{
  glBindTexture(GL_TEXTURE_2D, t->id);

  int unpack = 4;
  if (format == Alpha) {
    glGetIntegerv(GL_UNPACK_ALIGNMENT, &unpack);
    if (unpack != 1) {
      glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    }
  }

  int gl_internal_format = get_gl_internal_format(format);
  int gl_format = get_gl_format_from_internal_format(gl_internal_format);
  glTexSubImage2D(
      GL_TEXTURE_2D,
      0,
      x,
      y,
      width,
      height,
      gl_format,
      GL_UNSIGNED_BYTE,
      data);

  GLenum error = glGetError();

  if (error) {
    printf("there was an error with glTexSubImage2D\n");
  }

  if (format == Alpha && unpack != 1) {
    glPixelStorei(GL_UNPACK_ALIGNMENT, unpack);
  }
}

GLuint cgl_texture_id(const CglTexture* t)
{
  return t->id;
}

CglTexture* cgl_texture_from_id(const GLuint id)
{
  CglTexture* t = calloc(1, sizeof *t);
  t->id = id;
  return t;
}

CglTexture*
cgl_texture_new(int internal_format, int filtering)
{
  //TODO free
  CglTexture* t = calloc(1, sizeof *t);

  glGenTextures(1, &t->id);
  glBindTexture(GL_TEXTURE_2D, t->id);
  if (filtering) {
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  }
  else {
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  }

  int gl_format = get_gl_internal_format(internal_format);

  // default alignment is 4 so for rgb (3) we must set it to 1
  if (gl_format == GL_RGB || gl_format == GL_RGB8_OES) {
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  }

  return t;
}

CglTexture*
cgl_texture_from_egl_image(int is_external, void* image)
{
  CglTexture* t = calloc(1, sizeof *t);
  glGenTextures(1, &t->id);

  int target = GL_TEXTURE_2D;
  if (is_external) target = GL_TEXTURE_EXTERNAL_OES;

  glBindTexture(target, t->id);
  glEGLImageTargetTexture2DOES(target, image);

  //if you dont set the filters it does not work! (the texture is all black in the fragment shader...)
  glTexParameterf(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  glTexParameterf(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

  glBindTexture(target, 0);

  return t;
}

void cgl_texture_write(CglTexture* t, void* data, int w, int h)
{
    GLuint fbo = 0;
    glGenFramebuffers(1, &fbo);
    glBindFramebuffer(GL_FRAMEBUFFER, fbo);

    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, t->id, 0);
    glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, data);

    glBindFramebuffer(GL_FRAMEBUFFER, 0);
    glDeleteFramebuffers(1, &fbo);
}


A  => src/texture.h +39 -0
@@ 1,39 @@
#ifndef __texture__
#define __texture__
#include "gl.h"

typedef struct _CglTexture CglTexture;

struct _CglTexture
{
  GLuint id;
};

CglTexture* cgl_texture_new(
    int internal_format,
    int linear_filtering
    );

CglTexture* cgl_texture_init(
    const void* data,
    int internal_format,
    int width,
    int height,
    int linear_filtering
    );

void cgl_texture_update(
    CglTexture* t,
    int x,
    int y,
    int width,
    int height,
    int format,
    void *data
    );

GLuint cgl_texture_id(const CglTexture* t);

CglTexture* cgl_texture_from_id(const GLuint id);

#endif