Как преобразовать простой код для построения линий OpenGL в массив вершин - PullRequest
1 голос
/ 08 февраля 2012

Я написал простое приложение opengl на C, которое чертит sin (x). Это моя текущая функция draw, которая работает очень медленно. Как мне преобразовать этот код, чтобы использовать более быстрый режим «массив вершин»?

список используемых переменных и функций:

  • N = общее количество баллов
  • x1 = мин (х)
  • x2 = max (x)
  • y1 = мин (у)
  • y2 = max (y)
  • func (x) = sin (x)

и вот весь код:

/* to compile, do:

 $ gcc -o out simple.c -lglut

*/

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

float xmin = -10, xmax = 10, ymin = -5, ymax = 5;
int nPoints = 3000;

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

/* plotting function - very slow */
void draw(float (* func)(float x), float x1, float x2, float y1, float y2, int N)
{
    float x, dx = 1.0/N;

    glPushMatrix(); 

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

    glBegin(GL_LINE_STRIP);

    for(x = x1; x < x2; x += dx)
    {
        glVertex2f(x, func(x));
    }

    glEnd();

    glPopMatrix();
};

/* Redrawing func */
void redraw(void)
{

    clock_t start = clock();
    glClearColor(0, 0, 0, 0);
    glClear(GL_COLOR_BUFFER_BIT);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    // -x, +x, -y, +y, number points

    draw(func, xmin, xmax, ymin, ymax, nPoints);

    glutSwapBuffers();
    printf("Time elapsed: %f\n", ((double)clock() - start) / CLOCKS_PER_SEC);
};

/* Idle proc. Redisplays, if called. */
void idle(void)
{
    // shift 'xmin' & 'xmax' by one.
    xmin++; 
    xmax++;
    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)
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
    glutCreateWindow("Graph plotter");
    glutReshapeWindow(1024, 800);
    glutPostRedisplay(); // This call may or may not be necessary


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

    glutIdleFunc(idle);

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

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

1 Ответ

1 голос
/ 08 февраля 2012

В терминах в стиле C LodePNG vector структура / функции:

// shared
vector pts;
vector_init( &pts, sizeof( float ) );

// whenever x1, x2, or N changes
vector_cleanup( &pts );
float x, dx = 1.0/N;
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);
}

// whenever you want to draw
glPushMatrix();

glScalef(1.0 / (x2 - x1), 1.0 / (y2 - y1), 1.0);
glTranslatef(-x1, -y1, 0.0);
glColor3f(1.0, 1.0, 1.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();

РЕДАКТИРОВАТЬ: Полный код:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <GL/glut.h>
#include <time.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];
}

float xmin = -10, xmax = 10, ymin = -5, ymax = 5;
int nPoints = 3000;
vector pts;

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

void update(float (* func)(float x), float x1, float x2, int N)
{
    float x, dx = 1.0/N;
    vector_cleanup( &pts );
    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);
    }
}

/* plotting function - very slow */
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();
};

/* Redrawing func */
void redraw(void)
{
    clock_t start = clock();
    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();
    printf("Time elapsed: %f\n", ((double)clock() - start) / CLOCKS_PER_SEC);
};

/* Idle proc. Redisplays, if called. */
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)
{
    vector_init( &pts, sizeof( float ) );

    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
    glutCreateWindow("Graph plotter");
    glutReshapeWindow(1024, 800);
    glutPostRedisplay(); // This call may or may not be necessary


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

    glutIdleFunc(idle);

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

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