如何使用顶点缓冲对象将顶点数组转换为OpenGL代码?

时间:2012-02-08 12:58:57

标签: c opengl glut

这是我用C编写的draw()函数,使用顶点数组:

void draw(float x1, float x2, float y1, float y2)
{
    glPushMatrix(); 

    glScalef(1.0 / (x2 - x1), 1.0 / (y2 - y1), 1.0);
    glTranslatef(-x1, -y1, 0.0);
    glColor3f(1.0, 1.0, 1.0);

    if( pts.size > 0 )
    {
        glEnableClientState( GL_VERTEX_ARRAY );
        glVertexPointer( 2, GL_FLOAT, 0, (float*)pts.data );
        glDrawArrays( GL_LINE_STRIP, 0, pts.size / 2 );
        glDisableClientState( GL_VERTEX_ARRAY );
    }

    glPopMatrix();
};

在致电draw()之前,pts已在update()函数内更新:

void update(double (* func)(double x), float x1, float x2, int N)
{
    double x, dx = (double)1.0/(double)N;
    vector_cleanup( &pts );
    m = 0;
    for(x = x1; x < x2; x += dx)
    {
        vector_resize( &pts, pts.size + 2 );
        *(float*)vector_get( &pts, pts.size-2 ) = (float)x;
        *(float*)vector_get( &pts, pts.size-1 ) = (float)func3(x);
        m++;
    }
}

我希望通过将此代码转换为使用VBO,我的图形性能将会提高。

编辑: func3()可以是任何内容,例如sin(x)或只是一些线性映射。我现在要做的就是找出能够多快地绘制一堆积分。

1 个答案:

答案 0 :(得分:1)

使用GLEW进行扩展争论:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <GL/glew.h>
#include <GL/glut.h>

typedef struct vector /*dynamic vector of void* pointers. This one is used only by the deflate compressor*/
{
  void* data;
  size_t size; /*in groups of bytes depending on type*/
  size_t allocsize; /*in bytes*/
  unsigned typesize; /*sizeof the type you store in data*/
} vector;

static unsigned vector_resize(vector* p, size_t size) /*returns 1 if success, 0 if failure ==> nothing done*/
{
  if(size * p->typesize > p->allocsize)
  {
    size_t newsize = size * p->typesize * 2;
    void* data = realloc(p->data, newsize);
    if(data)
    {
      p->allocsize = newsize;
      p->data = data;
      p->size = size;
    }
    else return 0;
  }
  else p->size = size;
  return 1;
}

static void vector_cleanup(void* p)
{
  ((vector*)p)->size = ((vector*)p)->allocsize = 0;
  free(((vector*)p)->data);
  ((vector*)p)->data = NULL;
}

static void vector_init(vector* p, unsigned typesize)
{
  p->data = NULL;
  p->size = p->allocsize = 0;
  p->typesize = typesize;
}

static void* vector_get(vector* p, size_t index)
{
  return &((char*)p->data)[index * p->typesize];
}


/* function to calculate each data point */
float func(float x)
{
    return (float)sin(x);
}

GLuint vbo = 0;
GLsizei vertcount = 0;
void update(float (* func)(float x), float x1, float x2, int N)
{
    float x, dx = 1.0f/N;
    vector pts;

    vector_init( &pts, sizeof( float ) );
    for(x = x1; x < x2; x += dx)
    {
        vector_resize( &pts, pts.size + 2 );
        *(float*)vector_get( &pts, pts.size-2 ) = x;
        *(float*)vector_get( &pts, pts.size-1 ) = func(x);
    }

    vertcount = (GLsizei)( pts.size / 2 );
    glBindBuffer( GL_ARRAY_BUFFER, vbo );
    glBufferData( GL_ARRAY_BUFFER, pts.size * pts.typesize, pts.data, GL_DYNAMIC_DRAW );
    glBindBuffer( GL_ARRAY_BUFFER, 0 );

    vector_cleanup( &pts );
}

/* plotting function - very slow */
void draw(float x1, float x2, float y1, float y2)
{
    glPushMatrix(); 

    glScalef( 1.0f / (x2 - x1), 1.0f / (y2 - y1), 1.0f );
    glTranslatef( -x1, -y1, 0.0f );
    glColor3f( 1.0f, 1.0f, 1.0f );

    glBindBuffer( GL_ARRAY_BUFFER, vbo );
    glEnableClientState( GL_VERTEX_ARRAY );
    glVertexPointer( 2, GL_FLOAT, 0, 0 );
    glDrawArrays( GL_LINE_STRIP, 0, vertcount );
    glDisableClientState( GL_VERTEX_ARRAY );
    glBindBuffer( GL_ARRAY_BUFFER, 0 );

    glPopMatrix();
};

/* Redrawing func */
float xmin = -10, xmax = 10, ymin = -5, ymax = 5;
void redraw(void)
{
    glClearColor(0, 0, 0, 0);
    glClear(GL_COLOR_BUFFER_BIT);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    // -x, +x, -y, +y, number points
    draw(xmin, xmax, ymin, ymax);

    glutSwapBuffers();
};

/* Idle proc. Redisplays, if called. */
int nPoints = 3000;
void idle(void)
{
    // shift 'xmin' & 'xmax' by one.
    xmin++; 
    xmax++;

    update(func, xmin, xmax, nPoints);

    glutPostRedisplay();
};

/* Key press processing */
void key(unsigned char c, int x, int y)
{
    if(c == 27) exit(0);
};

/* Window reashape */
void reshape(int w, int h)
{
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(0, 1, 0, 1, -1, 1);
    glMatrixMode(GL_MODELVIEW);
};

/* Main function */
int main(int argc, char **argv)
{
    GLenum err;

    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
    glutCreateWindow("Graph plotter");
    glutReshapeWindow(1024, 800);

    // init GLEW and output some GL info
    err = glewInit();
    printf("GL_VERSION  : %s\n", glGetString(GL_VERSION)  );
    printf("GL_VENDOR   : %s\n", glGetString(GL_VENDOR)   );
    printf("GL_RENDERER : %s\n", glGetString(GL_RENDERER) );
    if( GLEW_OK != err )
    {
        printf("glewInit failed: %s", glewGetErrorString(err));
        return EXIT_FAILURE;
    }

    if( !glewIsSupported("GL_VERSION_1_5") )
    {
        printf("OpenGL version 1.5 or greater required.\n");
        return EXIT_FAILURE;
    }

    glGenBuffers( 1, &vbo );

    /* Register GLUT callbacks. */
    glutDisplayFunc(redraw);
    glutKeyboardFunc(key);
    glutReshapeFunc(reshape);
    glutIdleFunc(idle);

    /* Init the GL state */
    glLineWidth(2.0);

    /* Main loop */
    glutMainLoop();
    return 0;
}