////////////////////////////////
// OpenGL Helper Functions

MR4TH_SYMBOL_STATIC GLuint
ogl_make_shader(char *src, GLenum kind){
  ArenaTemp scratch = arena_get_scratch(0, 0);
  
  // create shader
  GLuint shader = glCreateShader(kind);
  glShaderSource(shader, 1, (GLchar const*const*)&src, 0);
  glCompileShader(shader);
  
  // check status
  GLint compile_status = 0;
  glGetShaderiv(shader, GL_COMPILE_STATUS, &compile_status);
  
  if (compile_status == 0){
    // generate error message
    {
      String8 log = {0};
      GLint info_log_length = 0;
      glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &info_log_length);
      if (info_log_length > 0){
        char *buffer = push_array(scratch.arena, char, info_log_length + 1);
        GLint length = 0;
        glGetShaderInfoLog(shader, info_log_length + 1, &length, buffer);
        log = CLiteral(String8){(U8*)buffer, length};
      }
      
      const U8 *vendor       = glGetString(GL_VENDOR);
      const U8 *renderer     = glGetString(GL_RENDERER);
      const U8 *version      = glGetString(GL_VERSION);
      const U8 *glsl_version = glGetString(GL_SHADING_LANGUAGE_VERSION);
      
      er_emitf("%s\n%s\n%s\n%s\n"
               "Shader Errors:\n%S",
               vendor, renderer, version, glsl_version, log);
    }
    
    // cleanup
    glDeleteShader(shader);
    shader = 0;
  }
  
  // fill result
  arena_release_scratch(&scratch);
  
  return(shader);
}

MR4TH_SYMBOL_STATIC GLuint
ogl_make_program(GLuint *shaders, U32 count){
  ArenaTemp scratch = arena_get_scratch(0, 0);
  
  // link program
  GLuint program = glCreateProgram();
  for (U32 i = 0; i < count; i += 1){
    glAttachShader(program, shaders[i]);
  }
  glLinkProgram(program);
  
  // check status
  GLint link_status = 0;
  glGetProgramiv(program, GL_LINK_STATUS, &link_status);
  
  // handle error
  if (link_status == 0){
    // generate error message
    {
      String8 log = {0};
      GLint info_log_length = 0;
      glGetProgramiv(program, GL_INFO_LOG_LENGTH, &info_log_length);
      if (info_log_length > 0){
        char *buffer = push_array(scratch.arena, char, info_log_length + 1);
        GLint length = 0;
        glGetProgramInfoLog(program, info_log_length + 1, &length, buffer);
        log = CLiteral(String8){(U8*)buffer, length};
      }
      
      const U8 *vendor       = glGetString(GL_VENDOR);
      const U8 *renderer     = glGetString(GL_RENDERER);
      const U8 *version      = glGetString(GL_VERSION);
      const U8 *glsl_version = glGetString(GL_SHADING_LANGUAGE_VERSION);
      
      er_emitf("%s\n%s\n%s\n%s\n"
               "Shader Errors:\n%S",
               vendor, renderer, version, glsl_version, log);
    }
    
    // cleanup error
    glDeleteProgram(program);
    program = 0;
  }
  
  arena_release_scratch(&scratch);
  return(program);
}

// buffer copies

MR4TH_SYMBOL_STATIC void
ogl_buffer_sub_data_from_stream(GLenum target, U64 off, STREAM *stream){
  String8 chunk = {0};
  for (STREAM_Handle *h = stream_next_chunk(stream, 0, &chunk);
       h != 0;
       h = stream_next_chunk(stream, h, &chunk)){
    glBufferSubData(target, off, chunk.size, chunk.str);
    off += chunk.size;
  }
}
