1/* 2 * Test GL_ARB_vertex_buffer_object 3 * Also test GL_ARB_vertex_array_object if supported 4 * 5 * Brian Paul 6 * 16 Sep 2003 7 */ 8 9 10#include <assert.h> 11#include <stdio.h> 12#include <stdlib.h> 13#include <string.h> 14#include <math.h> 15#include <GL/glew.h> 16#include "glut_wrap.h" 17 18#define NUM_OBJECTS 10 19 20struct object 21{ 22 GLuint ArrayObjectID; /** GL_ARB_vertex_array_object */ 23 GLuint VertexBufferID; 24 GLuint ColorBufferID; 25 GLuint ElementsBufferID; 26 GLuint NumVerts; 27 GLuint VertexOffset; 28 GLuint ColorOffset; 29 GLuint VertexStride; 30 GLuint ColorStride; 31 GLuint NumElements; 32 GLuint MaxElement; 33}; 34 35static struct object Objects[NUM_OBJECTS]; 36static GLuint NumObjects; 37 38static GLuint Win; 39 40static GLfloat Xrot = 0, Yrot = 0, Zrot = 0; 41static GLboolean Anim = GL_TRUE; 42static GLboolean Have_ARB_vertex_array_object = GL_FALSE; 43 44 45static void CheckError(int line) 46{ 47 GLenum err = glGetError(); 48 if (err) { 49 printf("GL Error 0x%x at line %d\n", (int) err, line); 50 } 51} 52 53 54static void DrawObject( const struct object *obj ) 55{ 56 if (Have_ARB_vertex_array_object && obj->ArrayObjectID) { 57 glBindVertexArray(obj->ArrayObjectID); 58 59 if (obj->NumElements > 0) { 60 /* indexed arrays */ 61 glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, obj->ElementsBufferID); 62 glDrawRangeElements(GL_LINE_LOOP, 0, obj->MaxElement, 63 obj->NumElements, GL_UNSIGNED_INT, NULL); 64 } 65 else { 66 /* non-indexed arrays */ 67 glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); 68 glDrawArrays(GL_LINE_LOOP, 0, obj->NumVerts); 69 } 70 71 glBindVertexArray(0); 72 } 73 else { 74 /* no vertex array objects, must set vertex/color pointers per draw */ 75 76 glBindBufferARB(GL_ARRAY_BUFFER_ARB, obj->VertexBufferID); 77 glVertexPointer(3, GL_FLOAT, obj->VertexStride, (const void *) (size_t) obj->VertexOffset); 78 glEnableClientState(GL_VERTEX_ARRAY); 79 80 /* test push/pop attrib */ 81 /* XXX this leads to a segfault with NVIDIA's 53.36 driver */ 82#if 0 83 if (1) 84 { 85 glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT); 86 /*glVertexPointer(3, GL_FLOAT, 0, (const void *) (size_t) (obj->VertexOffset + 10000));*/ 87 glBindBufferARB(GL_ARRAY_BUFFER_ARB, 999999); 88 glPopClientAttrib(); 89 } 90#endif 91 glBindBufferARB(GL_ARRAY_BUFFER_ARB, obj->ColorBufferID); 92 glColorPointer(3, GL_FLOAT, obj->ColorStride, (const void *) (size_t) obj->ColorOffset); 93 glEnableClientState(GL_COLOR_ARRAY); 94 95 if (obj->NumElements > 0) { 96 /* indexed arrays */ 97 glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, obj->ElementsBufferID); 98 glDrawElements(GL_LINE_LOOP, obj->NumElements, GL_UNSIGNED_INT, NULL); 99 } 100 else { 101 /* non-indexed arrays */ 102 glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); 103 glDrawArrays(GL_LINE_LOOP, 0, obj->NumVerts); 104 } 105 } 106} 107 108 109static void Idle( void ) 110{ 111 Zrot = 0.05 * glutGet(GLUT_ELAPSED_TIME); 112 glutPostRedisplay(); 113} 114 115 116static void Display( void ) 117{ 118 int i; 119 120 glClear( GL_COLOR_BUFFER_BIT ); 121 122 for (i = 0; i < NumObjects; i++) { 123 float x = 7.0 * ((float) i / (NumObjects-1) - 0.5); 124 glPushMatrix(); 125 glTranslatef(x, 0, 0); 126 glRotatef(Xrot, 1, 0, 0); 127 glRotatef(Yrot, 0, 1, 0); 128 glRotatef(Zrot, 0, 0, 1); 129 130 DrawObject(Objects + i); 131 132 glPopMatrix(); 133 } 134 135 CheckError(__LINE__); 136 glutSwapBuffers(); 137} 138 139 140static void Reshape( int width, int height ) 141{ 142 float ar = (float) width / (float) height; 143 glViewport( 0, 0, width, height ); 144 glMatrixMode( GL_PROJECTION ); 145 glLoadIdentity(); 146 glFrustum( -ar, ar, -1.0, 1.0, 5.0, 25.0 ); 147 glMatrixMode( GL_MODELVIEW ); 148 glLoadIdentity(); 149 glTranslatef( 0.0, 0.0, -15.0 ); 150} 151 152 153static void FreeBuffers(void) 154{ 155 int i; 156 for (i = 0; i < NUM_OBJECTS; i++) { 157 glDeleteBuffersARB(1, &Objects[i].VertexBufferID); 158 glDeleteBuffersARB(1, &Objects[i].ColorBufferID); 159 glDeleteBuffersARB(1, &Objects[i].ElementsBufferID); 160 } 161} 162 163 164static void Key( unsigned char key, int x, int y ) 165{ 166 const GLfloat step = 3.0; 167 (void) x; 168 (void) y; 169 switch (key) { 170 case 'a': 171 Anim = !Anim; 172 if (Anim) 173 glutIdleFunc(Idle); 174 else 175 glutIdleFunc(NULL); 176 break; 177 case 'z': 178 Zrot -= step; 179 break; 180 case 'Z': 181 Zrot += step; 182 break; 183 case 27: 184 FreeBuffers(); 185 glutDestroyWindow(Win); 186 exit(0); 187 break; 188 } 189 glutPostRedisplay(); 190} 191 192 193static void SpecialKey( int key, int x, int y ) 194{ 195 const GLfloat step = 3.0; 196 (void) x; 197 (void) y; 198 switch (key) { 199 case GLUT_KEY_UP: 200 Xrot -= step; 201 break; 202 case GLUT_KEY_DOWN: 203 Xrot += step; 204 break; 205 case GLUT_KEY_LEFT: 206 Yrot -= step; 207 break; 208 case GLUT_KEY_RIGHT: 209 Yrot += step; 210 break; 211 } 212 glutPostRedisplay(); 213} 214 215 216/** 217 * If GL_ARB_vertex_array_object is supported, create an array object 218 * and set all the per-array state. 219 */ 220static void 221CreateVertexArrayObject(struct object *obj) 222{ 223 glGenVertexArrays(1, &obj->ArrayObjectID); 224 glBindVertexArray(obj->ArrayObjectID); 225 226 glBindBufferARB(GL_ARRAY_BUFFER_ARB, obj->VertexBufferID); 227 glVertexPointer(3, GL_FLOAT, obj->VertexStride, (const void *) (size_t) obj->VertexOffset); 228 glEnableClientState(GL_VERTEX_ARRAY); 229 230 glBindBufferARB(GL_ARRAY_BUFFER_ARB, obj->ColorBufferID); 231 glColorPointer(3, GL_FLOAT, obj->ColorStride, (const void *) (size_t) obj->ColorOffset); 232 glEnableClientState(GL_COLOR_ARRAY); 233 234 glBindVertexArray(0); 235} 236 237 238/* 239 * Non-interleaved position/color data. 240 */ 241static void MakeObject1(struct object *obj) 242{ 243 GLfloat *v, *c; 244 void *p; 245 int i; 246 GLubyte buffer[500]; 247 248 for (i = 0; i < 500; i++) 249 buffer[i] = i & 0xff; 250 251 obj->VertexBufferID = 0; 252 glGenBuffersARB(1, &obj->VertexBufferID); 253 obj->ColorBufferID = obj->VertexBufferID; 254 assert(obj->VertexBufferID != 0); 255 glBindBufferARB(GL_ARRAY_BUFFER_ARB, obj->VertexBufferID); 256 glBufferDataARB(GL_ARRAY_BUFFER_ARB, 500, buffer, GL_STATIC_DRAW_ARB); 257 258 for (i = 0; i < 500; i++) 259 buffer[i] = 0; 260 261 glGetBufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, 500, buffer); 262 263 for (i = 0; i < 500; i++) 264 assert(buffer[i] == (i & 0xff)); 265 266 glGetBufferParameterivARB(GL_ARRAY_BUFFER_ARB, GL_BUFFER_MAPPED_ARB, &i); 267 assert(!i); 268 269 glGetBufferParameterivARB(GL_ARRAY_BUFFER_ARB, GL_BUFFER_USAGE_ARB, &i); 270 271 v = (GLfloat *) glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); 272 273 /* do some sanity tests */ 274 glGetBufferPointervARB(GL_ARRAY_BUFFER_ARB, GL_BUFFER_MAP_POINTER_ARB, &p); 275 assert(p == v); 276 277 glGetBufferParameterivARB(GL_ARRAY_BUFFER_ARB, GL_BUFFER_SIZE_ARB, &i); 278 assert(i == 500); 279 280 glGetBufferParameterivARB(GL_ARRAY_BUFFER_ARB, GL_BUFFER_USAGE_ARB, &i); 281 assert(i == GL_STATIC_DRAW_ARB); 282 283 glGetBufferParameterivARB(GL_ARRAY_BUFFER_ARB, GL_BUFFER_ACCESS_ARB, &i); 284 assert(i == GL_WRITE_ONLY_ARB); 285 286 glGetBufferParameterivARB(GL_ARRAY_BUFFER_ARB, GL_BUFFER_MAPPED_ARB, &i); 287 assert(i); 288 289 /* Make rectangle */ 290 v[0] = -1; v[1] = -1; v[2] = 0; 291 v[3] = 1; v[4] = -1; v[5] = 0; 292 v[6] = 1; v[7] = 1; v[8] = 0; 293 v[9] = -1; v[10] = 1; v[11] = 0; 294 c = v + 12; 295 c[0] = 1; c[1] = 0; c[2] = 0; 296 c[3] = 1; c[4] = 0; c[5] = 0; 297 c[6] = 1; c[7] = 0; c[8] = 1; 298 c[9] = 1; c[10] = 0; c[11] = 1; 299 obj->NumVerts = 4; 300 obj->VertexOffset = 0; 301 obj->ColorOffset = 3 * sizeof(GLfloat) * obj->NumVerts; 302 obj->VertexStride = 0; 303 obj->ColorStride = 0; 304 obj->NumElements = 0; 305 obj->MaxElement = 0; 306 307 glUnmapBufferARB(GL_ARRAY_BUFFER_ARB); 308 309 glGetBufferPointervARB(GL_ARRAY_BUFFER_ARB, GL_BUFFER_MAP_POINTER_ARB, &p); 310 assert(!p); 311 312 glGetBufferParameterivARB(GL_ARRAY_BUFFER_ARB, GL_BUFFER_MAPPED_ARB, &i); 313 assert(!i); 314 315 if (Have_ARB_vertex_array_object) { 316 CreateVertexArrayObject(obj); 317 } 318} 319 320 321/* 322 * Interleaved position/color data. 323 */ 324static void MakeObject2(struct object *obj) 325{ 326 GLfloat *v; 327 int start = 40; /* bytes, to test non-zero array offsets */ 328 329 glGenBuffersARB(1, &obj->VertexBufferID); 330 obj->ColorBufferID = obj->VertexBufferID; 331 332 glBindBufferARB(GL_ARRAY_BUFFER_ARB, obj->VertexBufferID); 333 glBufferDataARB(GL_ARRAY_BUFFER_ARB, 1000, NULL, GL_STATIC_DRAW_ARB); 334 v = (GLfloat *) glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); 335 336 v += start / sizeof(GLfloat); 337 338 /* Make triangle: interleaved colors, then positions */ 339 /* R G B X Y Z */ 340 v[0] = 0; v[1] = 1; v[2] = 0; v[3] = -1; v[4] = -1; v[5] = 0; 341 v[6] = 0; v[7] = 1; v[8] = 0; v[9] = 1; v[10] = -1; v[11] = 0; 342 v[12] = 1; v[13] = 1; v[14] = 0; v[15] = 0; v[16] = 1; v[17] = 0; 343 344 obj->NumVerts = 3; 345 obj->VertexOffset = start + 3 * sizeof(GLfloat); 346 obj->ColorOffset = start; 347 obj->VertexStride = 6 * sizeof(GLfloat); 348 obj->ColorStride = 6 * sizeof(GLfloat); 349 350 obj->NumElements = 0; 351 obj->MaxElement = 0; 352 353 glUnmapBufferARB(GL_ARRAY_BUFFER_ARB); 354 355 if (Have_ARB_vertex_array_object) { 356 CreateVertexArrayObject(obj); 357 } 358} 359 360 361/* 362 * Use an index buffer and glDrawElements(). 363 */ 364static void MakeObject3(struct object *obj) 365{ 366 GLfloat vertexData[1000]; 367 GLfloat *v, *c; 368 GLuint *i; 369 int bytes; 370 371 /* Make rectangle */ 372 v = vertexData; 373 v[0] = -1; v[1] = -0.5; v[2] = 0; 374 v[3] = 1; v[4] = -0.5; v[5] = 0; 375 v[6] = 1; v[7] = 0.5; v[8] = 0; 376 v[9] = -1; v[10] = 0.5; v[11] = 0; 377 c = vertexData + 12; 378 c[0] = 0; c[1] = 0; c[2] = 1; 379 c[3] = 0; c[4] = 0; c[5] = 1; 380 c[6] = 0; c[7] = 1; c[8] = 1; 381 c[9] = 0; c[10] = 1; c[11] = 1; 382 obj->NumVerts = 4; 383 obj->VertexOffset = 0; 384 obj->ColorOffset = 3 * sizeof(GLfloat) * obj->NumVerts; 385 obj->VertexStride = 0; 386 obj->ColorStride = 0; 387 388 bytes = obj->NumVerts * (3 + 3) * sizeof(GLfloat); 389 390 /* Don't use glMap/UnmapBuffer for this object */ 391 glGenBuffersARB(1, &obj->VertexBufferID); 392 obj->ColorBufferID = obj->VertexBufferID; 393 394 glBindBufferARB(GL_ARRAY_BUFFER_ARB, obj->VertexBufferID); 395 glBufferDataARB(GL_ARRAY_BUFFER_ARB, bytes, vertexData, GL_STATIC_DRAW_ARB); 396 397 /* Setup a buffer of indices to test the ELEMENTS path */ 398 glGenBuffersARB(1, &obj->ElementsBufferID); 399 glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, obj->ElementsBufferID); 400 glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 100, NULL, GL_STATIC_DRAW_ARB); 401 i = (GLuint *) glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_READ_WRITE_ARB); 402 i[0] = 0; 403 i[1] = 1; 404 i[2] = 2; 405 i[3] = 3; 406 glUnmapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB); 407 obj->NumElements = 4; 408 obj->MaxElement = 3; 409 410 if (Have_ARB_vertex_array_object) { 411 CreateVertexArrayObject(obj); 412 } 413} 414 415 416/* 417 * Vertex and color data in different buffers. 418 */ 419static void MakeObject4(struct object *obj) 420{ 421 static const GLfloat vertexData[] = { 422 0, -1, 0, 423 0.5, 0, 0, 424 0, 1, 0, 425 -0.5, 0, 0 426 }; 427 static const GLfloat colorData[] = { 428 1, 1, 1, 429 1, 1, 0, 430 .5, .5, 0, 431 1, 1, 0 432 }; 433 434 obj->VertexOffset = 0; 435 obj->VertexStride = 0; 436 obj->ColorOffset = 0; 437 obj->ColorStride = 0; 438 obj->NumVerts = 4; 439 440 glGenBuffersARB(1, &obj->VertexBufferID); 441 glBindBufferARB(GL_ARRAY_BUFFER_ARB, obj->VertexBufferID); 442 glBufferDataARB(GL_ARRAY_BUFFER_ARB, sizeof(vertexData), vertexData, 443 GL_STATIC_DRAW_ARB); 444 445 glGenBuffersARB(1, &obj->ColorBufferID); 446 glBindBufferARB(GL_ARRAY_BUFFER_ARB, obj->ColorBufferID); 447 glBufferDataARB(GL_ARRAY_BUFFER_ARB, sizeof(colorData), colorData, 448 GL_STATIC_DRAW_ARB); 449 450 /* Setup a buffer of indices to test the ELEMENTS path */ 451 obj->ElementsBufferID = 0; 452 obj->NumElements = 0; 453 obj->MaxElement = 0; 454 455 if (Have_ARB_vertex_array_object) { 456 CreateVertexArrayObject(obj); 457 } 458} 459 460 461 462static void Init( void ) 463{ 464 if (!glutExtensionSupported("GL_ARB_vertex_buffer_object")) { 465 printf("GL_ARB_vertex_buffer_object not found!\n"); 466 exit(0); 467 } 468 printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER)); 469 470 Have_ARB_vertex_array_object = 471 glutExtensionSupported("GL_ARB_vertex_array_object"); 472 473 printf("Using GL_ARB_vertex_array_object: %s\n", 474 (Have_ARB_vertex_array_object ? "yes" : "no")); 475 476 477 /* Test buffer object deletion */ 478 if (1) { 479 static GLubyte data[1000]; 480 GLuint id = 999; 481 glBindBufferARB(GL_ARRAY_BUFFER_ARB, id); 482 glBufferDataARB(GL_ARRAY_BUFFER_ARB, 1000, data, GL_STATIC_DRAW_ARB); 483 glVertexPointer(3, GL_FLOAT, 0, (void *) 0); 484 glDeleteBuffersARB(1, &id); 485 assert(!glIsBufferARB(id)); 486 glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); 487 glVertexPointer(3, GL_FLOAT, 0, (void *) 0); 488 assert(!glIsBufferARB(id)); 489 } 490 491 memset(Objects, 0, sizeof(Objects)); 492 MakeObject1(Objects + 0); 493 MakeObject2(Objects + 1); 494 MakeObject3(Objects + 2); 495 MakeObject4(Objects + 3); 496 NumObjects = 4; 497} 498 499 500int main( int argc, char *argv[] ) 501{ 502 glutInit( &argc, argv ); 503 glutInitWindowPosition( 0, 0 ); 504 glutInitWindowSize( 600, 300 ); 505 glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE ); 506 Win = glutCreateWindow(argv[0]); 507 glewInit(); 508 glutReshapeFunc( Reshape ); 509 glutKeyboardFunc( Key ); 510 glutSpecialFunc( SpecialKey ); 511 glutDisplayFunc( Display ); 512 if (Anim) 513 glutIdleFunc(Idle); 514 Init(); 515 glutMainLoop(); 516 return 0; 517} 518