Projeto Virtual Worlds

Computação Gráfica 3D em C

Um código de testes para VAOs, VBOs e Shaders mais ‘definitivo’…

Daqui para frente os códigos serão direcionados ao OpenGL e GLSL 4.3, core profile. Então, apresento a vocês uns códigos de exemplo que usarei como base, daqui pra frente. Primeiro, eis os shaders:

// Vertex Shader: test.vert
#version 430 core

layout(location=0) in vec3 vpos;
layout(location=1) in vec3 vcolor;

smooth out vec3 color;

void main()
{
  color = vcolor;
  gl_Position = vec4(vpos, 1.0);
}
// Fragment Shader: test.frag
#version 430 core

smooth in vec3 color;

void main()
{
  gl_FragColor = vec4(color,1);
}

Eis o makefile:

# Makefile
CC=gcc
CFLAGS=-O3 -march=native `pkg-config --cflags glfw2 gl` 
LDFLAGS=-O3 -s -lm `pkg-config --libs glfw2 gl`

test: test.o
  $(CC) -o $@ $^ $(LDFLAGS)

test.o: test.c

.PHONY: clean
clean:
  rm -f test.o

E, abaixo, o código de exemplo em C “genérico”, usando VAOs, VBOs e os Shaders acima, para mostrar um triângulo equilatero:

/* ==================================================
   example.c

   Código básico de uso de VBOs, VAOs e Shaders.
   ================================================== */
#include <stdio.h>
#include <setjmp.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#include <math.h>
#include <sys/time.h>
#include <GL/gl.h>
#include <GL/glext.h>
#include <GL/glfw.h>

#define WINDOW_WIDTH  1280
#define WINDOW_HEIGHT 720

static int finished = 0;

/* Vertex Array Object, Vertex Buffer Object e
   Program Object para OpenGL. */ < / span >
GLuint vao, vbo, prgo;

static void initGLFW(void);
static void initGL(void);
static void initModel(void);
static void initShaders(void);
static void destroyGLFW(void);
static void drawScene(void);
static void processEvents(void);

int main(int argc, char *argv[])
{
  initGLFW();
  initGL();
  initShaders();
  initModel();

  while (!finished)
  {
    drawScene();
    processEvents();
    glfwSwapBuffers();
  }

  destroyGLFW();

  return 0;
}

void processEvents(void)
{
  glfwPollEvents();

  if (glfwGetKey(GLFW_KEY_ESC))
    finished = 1;
}

/* Inicializa o GLFW. */
void initGLFW(void)
{
  if (!glfwInit())
  {
    fputs("Error initializing GLFW.\n", stderr);
    exit(1);
  }

  glfwDisable( GLFW_AUTO_POLL_EVENTS );

  glfwOpenWindowHint( GLFW_OPENGL_VERSION_MAJOR, 4 );
  glfwOpenWindowHint( GLFW_OPENGL_VERSION_MINOR, 3 );

  if (glfwExtensionSupported( "GLX_ARB_create_context_profile" ))
    glfwOpenWindowHint( GLFW_OPENGL_PROFILE,
                        GLFW_OPENGL_CORE_PROFILE );

  glfwOpenWindowHint( GLFW_FSAA_SAMPLES, 4 );

  if (!glfwOpenWindow( WINDOW_WIDTH, WINDOW_HEIGHT,
                       8, 8, 8, 8,
                       24,
                       0,
                       GLFW_WINDOW ))
  {
    glfwTerminate();
    fputs("Cannot create Window.\n", stderr);
    exit(1);
  }

  glfwDisable( GLFW_MOUSE_CURSOR );

  glfwSetWindowTitle( "GLSL Test" );
}

void destroyGLFW(void) { glfwTerminate(); }

void initGL(void)
{
  glViewport( 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT );

  glClearColor( 0, 0, 0, 1 );
  glClearDepth( 1.0f );

  glFrontFace( GL_CCW );
  glCullFace( GL_BACK );
  glEnable( GL_CULL_FACE );

  glDepthFunc( GL_LESS );
  glEnable( GL_DEPTH_TEST );
}

void initModel(void)
{
  struct tris_s
  {
    float pos[3];
    float color[3];
  };

  struct tris_s tris[] =
  {
    {{ 0.0f,  M_SQRT1_2, -1.0f}, {1.0f, 0.0f, 0.0f}},
    {{ -0.5f, -0.5f,      -1.0f}, {0.0f, 1.0f, 0.0f}},
    {{ 0.5f, -0.5f,      -1.0f}, {0.0f, 0.0f, 1.0f}}
  };

  glGenVertexArrays( 1, &amp; vao );
  glBindVertexArray( vao );

  glGenBuffers( 1, &amp; vbo );
  glBindBuffer( GL_ARRAY_BUFFER, vbo );
  glBufferData( GL_ARRAY_BUFFER, sizeof(tris), tris, GL_STATIC_DRAW );

  glVertexAttribPointer( 0, 3, GL_FLOAT, GL_FALSE, 
                         sizeof(struct tris_s), 
                         (void *)offsetof(struct tris_s, pos) );
  glVertexAttribPointer( 1, 3, GL_FLOAT, GL_FALSE, 
                         sizeof(struct tris_s), 
                         (void *)offsetof(struct tris_s, color) );

  glEnableVertexAttribArray( 0 );
  glEnableVertexAttribArray( 1 );

  glBindVertexArray( 0 );
  glBindBuffer( GL_ARRAY_BUFFER, 0 );
}

static char *LoadTextFile(const char *filename)
{
  char *buffer;
  FILE *fin;
  long size;
  jmp_buf jb;

  if ((fin = fopen(filename, "rb")) == NULL)
    return NULL;

  if (setjmp(jb))
  {
    fclose(fin);
    return NULL;
  }

  fseek(fin, 0L, SEEK_END);

  if ((size = ftell(fin)) < 0)
    longjmp(jb, 1);

  fseek(fin, 0L, SEEK_SET);

  if ((buffer = malloc(size + 1)) == NULL)
    longjmp(jb, 1);

  if (fread(buffer, size, 1, fin) < 1)
  {
    free(buffer);
    longjmp(jb, 1);
  }

  buffer[size] = '\0';

  fclose(fin);
  return buffer;
}

static GLuint LoadAndCompileShader(const char *filename, GLenum shadertype)
{
  GLuint shobj;

  if ((shobj = glCreateShader( shadertype )) != 0)
  {
    GLint status;
    GLint len;
    char *src;

    if ((src = LoadTextFile(filename)) == NULL)
    {
      glDeleteShader( shobj );
      return 0;
    }

    len = strlen(src);

    glShaderSource( shobj, 1, &amp; src, &amp; len );
    glCompileShader( shobj );

    free(src);

    glGetShaderiv( shobj, GL_COMPILE_STATUS, &amp; status );

    if (status == GL_FALSE)
    {
      GLint logsize;
      char *log;

      glGetShaderiv( shobj, GL_INFO_LOG_LENGTH, &amp; logsize );

      if ((log = malloc(logsize + 1)) != NULL)
      {
        glGetShaderInfoLog( shobj, logsize, &amp; len, log );
        log[len] = '\0';
        fprintf(stderr, "%s: %s\n", filename, log);
        free(log);
      }

      glDeleteShader( shobj );
      return 0;
    }
  }

  return shobj;
}

// Esta estrutura será usada para montar a tabela de
// shaders que usaremos para montar o programa.
struct shader_info_s
{
  char *filename;
  GLenum shadertype;
  GLuint shobj;
};

static void DeleteAllShadersOnList(GLuint prgobj, struct shader_info_s *shinf_ptr)
{
  for (; shinf_ptr - > filename; shinf_ptr++)
    if (shinf_ptr - > shobj)
    {
      if (prgobj)
        glDetachShader( prgobj, shinf_ptr - > shobj );

      glDeleteShader( shinf_ptr - > shobj );
      shinf_ptr - >
      shobj = 0;
    }
}

static GLuint CreateShadersProgram(struct shader_info_s *shinf_ptr)
{
  GLuint prgobj;
  struct shader_info_s *sptr = shinf_ptr;

  for (sptr = shinf_ptr; sptr - > filename; sptr++)
    if ((sptr - > shobj = LoadAndCompileShader(sptr - > filename, sptr - > shadertype)) == 0)
    {
      DeleteAllShadersOnList( 0, shinf_ptr );
      return 0;
    }

  if ((prgobj = glCreateProgram()) != 0)
  {
    GLint status;

    for (sptr = shinf_ptr; sptr - > shobj; sptr++)
      glAttachShader( prgobj, sptr - > shobj );

    glLinkProgram( prgobj );

    DeleteAllShadersOnList( prgobj, shinf_ptr );

    glGetProgramiv( prgobj, GL_LINK_STATUS, &amp; status );

    if (status == GL_FALSE)
    {
      GLint logsize, len;
      char *log;

      glGetProgramiv( prgobj, GL_INFO_LOG_LENGTH, &amp; logsize );

      if ((log = malloc(logsize + 1)) != NULL)
      {
        glGetProgramInfoLog( prgobj, logsize, &amp; len, log );
        log[len] = '\0';
        fprintf(stderr, "Link Error: %s\n", log);
        free(log);
      }

      glDeleteProgram( prgobj );

      return 0;
    }
  }

  return prgobj;
}

void initShaders(void)
{
  struct shader_info_s shaders[] =
  {
    { "test.vert", GL_VERTEX_SHADER, 0 },
    { "test.frag", GL_FRAGMENT_SHADER, 0 },
    { NULL, 0, 0 }
  };

  if ((prgo = CreateShadersProgram( shaders )) == 0)
  {
    fputs("Error creating shaders.\n", stderr);
    exit(1);
  }
}

void drawScene(void)
{
  glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

  glBindBuffer( GL_ARRAY_BUFFER, vbo );
  glBindVertexArray( vao );

  glUseProgram( prgo );
  glDrawArrays( GL_TRIANGLES, 0, 3 );
  glUseProgram( 0 );

  glBindVertexArray( 0 );
  glBindBuffer( GL_ARRAY_BUFFER, 0 );
}
Anúncios

Deixe um comentário

Faça o login usando um destes métodos para comentar:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s