#include "stdlib.h"  
#include <OpenGL/glext.h>
#include <GLUT/GLUT.h>

#define BUFFER_OFFSET(bytes) ((GLubyte*) NULL + (bytes))
#define VERTICES 0
#define INDICES 1
#define NUM_BUFFERS 6
GLuint buffers[NUM_BUFFERS];

GLfloat vertices[][3] = {
{-1.0f,-1.0f,-1.0f},
{1.0f,-1.0f,-1.0f},
{1.0f,1.0f,-1.0f},
{-1.0f,1.0f,-1.0f},
{-1.0f,-1.0f,1.0f},
{1.0f,-1.0f,1.0f},
{1.0f,1.0f,1.0f},
{-1.0f,1.0f,1.0f}
};
GLubyte indices[][4] = {
{0,1,2,3},
{4,7,6,5},
{0,4,5,1},
{3,2,6,7},
{0,3,7,4},
{1,5,6,2}
};

GLfloat* bdata;

void changeSize(int w, int h)
{
glViewport(0,0,(GLsizei)w,(GLsizei)h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0,(double)w/(double)h,0.01,30);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}

void keyDown(unsigned char key, int x, int y)
{
switch (key)
{
case'b':
bdata = (GLfloat*)glMapBuffer(GL_ARRAY_BUFFER,GL_READ_WRITE);
for (int i =0; i <24; i ++)
{
*(bdata + i) *=1.1f;
}
glUnmapBuffer(GL_ARRAY_BUFFER);
glutPostRedisplay();
break;
}
}

void mouse(int button, int state, int x, int y)
{

}
void display(void)
{
glLoadIdentity();
glTranslatef(0.0f,0.0f,-5.0f);
glRotatef(30.0f,1.0f,1.0f,0.0f);

// 6. 绘制, 这个地方注意的是最后一个参数,这个与普通的非VBO最大的不同就在这里
glDrawElements(GL_QUADS,24,GL_UNSIGNED_BYTE,BUFFER_OFFSET(0));
//glDrawArrays(GL_TRIANGLE_FAN, 0, 8);
glutSwapBuffers();
}

void init(void)
{
glClearColor(0.0f,0.0f,0.0f,0.0f);
glShadeModel(GL_FLAT);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

//1. 创建缓冲区对象,系统会自动创建缓动区标示符放入到buffers中,可以使用glIsBuffer()函数,判断一个标示符是否被使用
glGenBuffers(NUM_BUFFERS ,buffers);
//2. 激活缓冲区对象,绑定缓冲区对象表示未来选择的操作将影响哪个缓冲区。 如果要金融缓冲区对象,可以用0来作为缓冲区对象的标示符, 第一个参数target可以为GL_ARRAY_BUFFER,GL_ELEMENT_ARRAY_FUFFER
glBindBuffer(GL_ARRAY_BUFFER,buffers[VERTICES]);
//3. 用数据分配和初始化缓冲区对象
glBufferData(GL_ARRAY_BUFFER,sizeof(vertices),vertices,GL_DYNAMIC_DRAW);
//4. 指定相对于缓冲区起始位置的偏移量
glVertexPointer(3,GL_FLOAT,0,BUFFER_OFFSET(0));
//5.一定不要忘记启动
glEnableClientState(GL_VERTEX_ARRAY);

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,buffers[INDICES]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER,sizeof(indices),indices,GL_STATIC_DRAW);
}

int main(int argc, char* argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GL_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
glutInitWindowSize(512, 512);
glutCreateWindow("Buffer Demo");
init();
glutReshapeFunc(changeSize);
glutMouseFunc(mouse);
glutKeyboardFunc(keyDown);
glutDisplayFunc(display);

glutMainLoop();
return 0;
}