glx-multithread-texture: Avoid front-buffer rendering.
[piglit.git] / tests / util / piglit-vbo.cpp
blob3ef6b1107be161a5f481cd4489a2f444162653ad
1 /*
2 * Copyright © 2011, 2016 Intel Corporation
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
24 /**
25 * \file piglit-vbo.cpp
27 * This file adds the facility for specifying vertex data to piglit
28 * tests using a columnar text format, for example:
30 * \verbatim
31 * vertex/double/vec3 foo/uint/uint bar[0]/int/int bar[1]/int/int
32 * 0.0 0.0 0.0 10 0 0 # comment
33 * 0.0 1.0 0.0 5 1 1
34 * 1.0 1.0 0.0 0 0 1
35 * \endverbatim
37 * The format consists of a row of column headers followed by any
38 * number of rows of data. Each column header has the form
39 * "ATTRNAME[ARRAY_INDEX]/GL_TYPE/GLSL_TYPE/MATRIX_COLUMN", where
40 * ATTRNAME is the name of the vertex attribute to be bound to this
41 * column, ARRAY_INDEX is the index, GL_TYPE is the GL type of data
42 * that follows ("half", "float", "double", "byte", "ubyte", "short",
43 * "ushort", "int" or "uint"), GLSL_TYPE is the GLSL type of the data
44 * ("int", "uint", "float", "double", "ivec"*, "uvec"*, "vec"*,
45 * "dvec"*, "mat"*, "dmat"*) and MATRIX_COLUMN is the column number of
46 * the data in case of being a matrix. [ARRAY_INDEX] is optional and
47 * needs to be specified only in case of array
48 * attributes. MATRIX_COLUMN doesn't need to be specified if it is not
49 * a matrix column as in the example before. So another example, if
50 * you want to specify the data of a mat2x3:
52 * \verbatim
53 * foomatrix/float/mat2x3/0 foomatrix/float/mat2x3/1
54 * 0.0 1.0 2.0 3.0 4.0 5.0
55 * 6.0 7.0 8.0 9.0 10.0 11.0
56 * \endverbatim
58 * The same example, using the deprecated but compatible syntax would
59 * be:
61 * \verbatim
62 * foomatrix/float/3/0 foomatrix/float/3/1
63 * 0.0 1.0 2.0 3.0 4.0 5.0
64 * 6.0 7.0 8.0 9.0 10.0 11.0
65 * \endverbatim
67 * The data follows the column headers in space-separated form. "#"
68 * can be used for comments, as in shell scripts.
70 * To process textual vertex data, call the function
71 * setup_vbo_from_text(), passing the int identifying the linked
72 * program, and the string containing the vertex data. The return
73 * value is the number of rows of vertex data found.
75 * If an error occurs, setup_vbo_from_text() will print out a
76 * description of the error and exit with PIGLIT_FAIL.
78 * For the first example above, the call to setup_vbo_from_text() is
79 * roughly equivalent to the following GL operations:
81 * \code
82 * struct vertex_attributes {
83 * GLfloat vertex[3];
84 * GLuint foo;
85 * GLint bar[2];
86 * } vertex_data[] = {
87 * { { 0.0, 0.0, 0.0 }, 10, { 0, 0 } },
88 * { { 0.0, 1.0, 0.0 }, 5, { 1, 1 } },
89 * { { 1.0, 1.0, 0.0 }, 0, { 0, 1 } }
90 * };
91 * size_t stride = sizeof(vertex_data[0]);
92 * GLint vertex_index = glGetAttribLocation(prog, "vertex");
93 * GLint foo_index = glGetAttribLocation(prog, "foo");
94 * GLint bar_index = glGetAttribLocation(prog, "bar");
95 * GLuint buffer_handle;
96 * glGenBuffers(1, &buffer_handle);
97 * glBindBuffer(GL_ARRAY_BUFFER, buffer_handle);
98 * glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data), &vertex_data,
99 * GL_STATIC_DRAW);
100 * glVertexAttribPointer(vertex_index, 3, GL_FLOAT, GL_FALSE, stride,
101 * (void *) offsetof(vertex_attributes, vertex));
102 * glVertexAttribIPointer(foo_index, 3, GL_UNSIGNED_INT, stride,
103 * (void *) offsetof(vertex_attributes, foo));
104 * glVertexAttribIPointer(bar_index, 3, GL_INT, stride,
105 * (void *) offsetof(vertex_attributes, bar));
106 * glEnableVertexAttribArray(vertex_index);
107 * glEnableVertexAttribArray(foo_index);
108 * glEnableVertexAttribArray(bar_index);
109 * \endcode
111 * Which could correspond to a vertex shader of this type:
113 * \code
114 * in vec3 vertex;
115 * in uint foo;
116 * in int bar[2];
118 * void main()
120 * if (bar[0] + bar[1] == foo) {
121 * gl_Position = vec4(vertex, 1.0);
122 * } else {
123 * gl_Position = vec4(1.0, vertex);
126 * \endcode
129 #include <string>
130 #include <vector>
131 #include <errno.h>
132 #include <limits.h>
133 #include <ctype.h>
134 #include <stdlib.h>
136 #include "piglit-util.h"
137 #include "piglit-util-gl.h"
138 #include "piglit-vbo.h"
141 * Convert a type name string to a GLenum.
143 static bool
144 decode_type(const char *type,
145 GLenum *gl_type, size_t *gl_type_size, GLenum *glsl_type)
147 assert(type);
148 assert(gl_type);
149 assert(gl_type_size);
151 static struct type_table_entry {
152 const char *type; /* NULL means end of table */
153 GLenum gl_type;
154 size_t gl_type_size;
155 GLenum glsl_type;
156 } const type_table[] = {
157 { "byte", GL_BYTE, 1, GL_INT },
158 { "ubyte", GL_UNSIGNED_BYTE, 1, GL_UNSIGNED_INT },
159 { "short", GL_SHORT, 2, GL_INT },
160 { "ushort", GL_UNSIGNED_SHORT, 2, GL_UNSIGNED_INT },
161 { "int", GL_INT, 4, GL_INT },
162 { "uint", GL_UNSIGNED_INT, 4, GL_UNSIGNED_INT },
163 { "half", GL_HALF_FLOAT, 2, GL_FLOAT },
164 { "float", GL_FLOAT, 4, GL_FLOAT },
165 { "double", GL_DOUBLE, 8, GL_DOUBLE },
166 { NULL, 0, 0, 0 },
170 for (int i = 0; type_table[i].type; ++i) {
171 if (0 == strcmp(type, type_table[i].type)) {
172 *gl_type = type_table[i].gl_type;
173 *gl_type_size = type_table[i].gl_type_size;
174 if (glsl_type)
175 *glsl_type = type_table[i].glsl_type;
176 return true;
180 return false;
185 * Convert a GLSL type name string to its basic GLenum type.
187 static bool
188 decode_glsl_type(const char *type,
189 GLenum *glsl_type, size_t *rows, size_t *cols, char **endptr)
191 assert(glsl_type);
192 assert(rows);
193 assert(cols);
194 assert(endptr);
196 if (isdigit(type[0])) {
197 *rows = strtoul(type, endptr, 10);
198 *cols = 1;
199 *glsl_type = 0;
200 return true;
203 static struct type_table_entry {
204 const char *type; /* NULL means end of table */
205 GLenum glsl_type;
206 } const type_table[] = {
207 { "int", GL_INT },
208 { "uint", GL_UNSIGNED_INT },
209 { "float", GL_FLOAT },
210 { "double", GL_DOUBLE },
211 { "ivec", GL_INT },
212 { "uvec", GL_UNSIGNED_INT },
213 { "vec", GL_FLOAT },
214 { "dvec", GL_DOUBLE },
215 { "mat", GL_FLOAT },
216 { "dmat", GL_DOUBLE },
217 { NULL, 0 }
221 for (int i = 0; type_table[i].type; ++i) {
222 const size_t type_len = strlen(type_table[i].type);
223 if (0 == strncmp(type, type_table[i].type, type_len)) {
224 *endptr = const_cast<char *>(&type[type_len]);
226 /* In case of vectors or matrices, let's
227 * calculate rows and columns.
229 if (i > 3) {
230 if (!isdigit(**endptr))
231 goto cleanup;
232 *rows = **endptr - '0';
233 ++*endptr;
235 /* In case of matrices, let's
236 * calculate the rows.
238 if (i > 7) {
239 *cols = *rows;
240 if (**endptr == 'x') {
241 if (!isdigit(*(++*endptr)))
242 goto cleanup;
243 *rows = **endptr - '0';
244 ++*endptr;
246 } else {
247 *cols = 1;
249 } else {
250 *rows = 1;
251 *cols = 1;
253 *glsl_type = type_table[i].glsl_type;
254 return true;
258 cleanup:
259 *glsl_type = 0;
260 *endptr = const_cast<char *>(type);
261 return false;
266 * Description of a vertex attribute, built from its column header
268 class vertex_attrib_description
270 public:
271 vertex_attrib_description(GLuint prog, const char *text);
272 bool parse_datum(const char **text, void *data) const;
273 void setup(size_t *offset, size_t stride) const;
276 * GL data type of this attribute.
278 GLenum data_type;
281 * Size of the GL data type of this attribute.
283 size_t data_type_size;
286 * GLSL data type of this attribute.
288 GLenum glsl_data_type;
291 * Index of the array for this attribute.
293 size_t array_index;
296 * Number of columns of the GLSL data type of this attribute.
298 size_t cols;
301 * Number of rows of the GLSL data type of this attribute.
303 size_t rows;
306 * Index of the matrix column for this attribute.
308 size_t matrix_index;
311 * Index of this vertex attribute in the linked program.
313 GLuint index;
316 static bool
317 get_attrib_location(GLuint prog,
318 const std::string &name,
319 GLuint *index)
321 errno = 0;
323 char *end;
324 unsigned long ul = strtoul(name.c_str(), &end, 10);
326 if (errno == 0 && *end == '\0' && ul <= UINT_MAX) {
327 *index = ul;
328 return true;
331 GLint attrib_location = glGetAttribLocation(prog, name.c_str());
332 if (attrib_location == -1)
333 return false;
335 *index = attrib_location;
337 return true;
341 * Build a vertex_attrib_description from a column header, by looking
342 * up the vertex attribute in the linked program and interpreting the
343 * type, dimensions and mattrix_column parts of the header.
345 * If there is a parse failure, print a description of the problem and
346 * then exit with PIGLIT_FAIL.
348 vertex_attrib_description::vertex_attrib_description(GLuint prog,
349 const char *text)
351 /* Split the column header into
352 * name[array_index]/type/dimensions/matrix_column fields.
354 const char *first_slash = strchr(text, '/');
355 if (first_slash == NULL) {
356 printf("Column headers must be in the form"
357 " name[array_index]/type/dimensions/matrix_column.\n"
358 "Note: [array_index] and matrix_column are optional.\n"
359 "Got: %s\n",
360 text);
361 piglit_report_result(PIGLIT_FAIL);
364 std::string name(text, first_slash);
366 /* If the attrib is an array, strip the index */
367 if (name[name.size() - 1] == ']') {
368 std::string::size_type n = name.find('[');
369 if (n == std::string::npos) {
370 printf("Column header looked like an array"
371 " but couldn't parse it.\n"
372 "Got: %s\n",
373 text);
374 piglit_report_result(PIGLIT_FAIL);
375 } else {
376 this->array_index = strtoul(name.substr(n + 1).c_str(), NULL, 0);
377 name.resize(n);
379 } else {
380 this->array_index = 0;
383 const char *second_slash = strchr(first_slash + 1, '/');
384 if (second_slash == NULL) {
385 printf("Column headers must be in the form"
386 " name[array_index]/type/dimensions/matrix_column.\n"
387 "Note: [array_index] and matrix_column are optional.\n"
388 "Got: %s\n",
389 text);
390 piglit_report_result(PIGLIT_FAIL);
393 char *endptr;
394 if (!decode_glsl_type(second_slash + 1,
395 &this->glsl_data_type,
396 &this->rows, &this->cols,
397 &endptr)) {
398 printf("Unrecognized GLSL type: %s\n", second_slash + 1);
399 piglit_report_result(PIGLIT_FAIL);
402 std::string type_str(first_slash + 1, second_slash);
403 GLenum *glsl_data_type = this->glsl_data_type ? 0
404 : &this->glsl_data_type;
406 if (!decode_type(type_str.c_str(),
407 &this->data_type, &this->data_type_size,
408 glsl_data_type)) {
409 printf("Unrecognized GL type: %s\n", type_str.c_str());
410 piglit_report_result(PIGLIT_FAIL);
413 if (*endptr != '\0') {
414 const char *third_slash = strchr(second_slash + 1, '/');
415 this->matrix_index = strtoul(third_slash + 1, &endptr, 10);
417 if (this->matrix_index > 3) {
418 printf("Matrix column index must be between 0 and 3. Got: %lu\n",
419 (unsigned long) this->matrix_index);
420 piglit_report_result(PIGLIT_FAIL);
423 if (*endptr != '\0') {
424 printf("Column headers must be in the form"
425 " name[array_index]/type/dimensions/matrix_column.\n"
426 "Note: [array_index] and matrix_column are optional.\n"
427 "Got: %s\n",
428 text);
429 piglit_report_result(PIGLIT_FAIL);
431 } else {
432 this->matrix_index = 0;
435 if (!get_attrib_location(prog, name, &this->index)) {
436 printf("Unexpected vbo column name. Got: %s\n", name.c_str());
437 piglit_report_result(PIGLIT_FAIL);
439 /* If the type is integral, verify that integer vertex
440 * attribute support is present. Note: we treat it as a FAIL
441 * if support is not present, because it's up to the test to
442 * either (a) not require integer vertex attribute support, or
443 * (b) skip itself if integer vertex attribute support is not
444 * present.
446 if (this->glsl_data_type != GL_FLOAT &&
447 (piglit_is_gles() ||
448 (piglit_get_gl_version() < 30 &&
449 !piglit_is_extension_supported("GL_EXT_gpu_shader4")))) {
450 printf("Test uses glVertexAttribIPointer(),"
451 " which is unsupported.\n");
452 piglit_report_result(PIGLIT_FAIL);
455 if (this->rows < 1 || this->rows > 4) {
456 printf("Rows must be between 1 and 4. Got: %lu\n",
457 (unsigned long) this->rows);
458 piglit_report_result(PIGLIT_FAIL);
461 if (this->cols < 1 || this->cols > 4) {
462 printf("Columns must be between 1 and 4. Got: %lu\n",
463 (unsigned long) this->cols);
464 piglit_report_result(PIGLIT_FAIL);
470 * Parse a single number (floating point or integral) from one of the
471 * data rows, and store it in the location pointed to by \c data.
472 * Update \c text to point to the next character of input.
474 * If there is a parse failure, print a description of the problem and
475 * then return false. Otherwise return true.
477 bool
478 vertex_attrib_description::parse_datum(const char **text, void *data) const
480 char *endptr;
481 errno = 0;
482 switch (this->data_type) {
483 case GL_HALF_FLOAT: {
484 unsigned short value = strtohf_hex(*text, &endptr);
485 if (errno == ERANGE) {
486 printf("Could not parse as half float\n");
487 return false;
489 *((GLhalf *) data) = value;
490 break;
492 case GL_FLOAT: {
493 float value = strtof_hex(*text, &endptr);
494 if (errno == ERANGE) {
495 printf("Could not parse as float\n");
496 return false;
498 *((GLfloat *) data) = value;
499 break;
501 case GL_DOUBLE: {
502 double value = strtod_hex(*text, &endptr);
503 if (errno == ERANGE) {
504 printf("Could not parse as double\n");
505 return false;
507 *((GLdouble *) data) = value;
508 break;
510 case GL_BYTE: {
511 long value = strtol_hex(*text, &endptr);
512 if (errno == ERANGE || value < SCHAR_MIN || value > SCHAR_MAX) {
513 printf("Could not parse as signed byte\n");
514 return false;
516 *((GLbyte *) data) = (GLbyte) value;
517 break;
519 case GL_UNSIGNED_BYTE: {
520 unsigned long value = strtoul(*text, &endptr, 0);
521 if (errno == ERANGE || value > UCHAR_MAX) {
522 printf("Could not parse as unsigned byte\n");
523 return false;
525 *((GLubyte *) data) = (GLubyte) value;
526 break;
528 case GL_SHORT: {
529 long value = strtol_hex(*text, &endptr);
530 if (errno == ERANGE || value < SHRT_MIN || value > SHRT_MAX) {
531 printf("Could not parse as signed short\n");
532 return false;
534 *((GLshort *) data) = (GLshort) value;
535 break;
537 case GL_UNSIGNED_SHORT: {
538 unsigned long value = strtoul(*text, &endptr, 0);
539 if (errno == ERANGE || value > USHRT_MAX) {
540 printf("Could not parse as unsigned short\n");
541 return false;
543 *((GLushort *) data) = (GLushort) value;
544 break;
546 case GL_INT: {
547 long value = strtol_hex(*text, &endptr);
548 if (errno == ERANGE) {
549 printf("Could not parse as signed integer\n");
550 return false;
552 *((GLint *) data) = (GLint) value;
553 break;
555 case GL_UNSIGNED_INT: {
556 unsigned long value = strtoul(*text, &endptr, 0);
557 if (errno == ERANGE) {
558 printf("Could not parse as unsigned integer\n");
559 return false;
561 *((GLuint *) data) = (GLuint) value;
562 break;
564 default:
565 assert(!"Unexpected data type");
566 endptr = NULL;
567 break;
569 *text = endptr;
570 return true;
575 * Execute the necessary GL calls to bind this attribute to its data.
577 void
578 vertex_attrib_description::setup(size_t *offset, size_t stride) const
580 GLuint actual_index = this->index + this->matrix_index
581 + this->array_index * this->cols;
582 switch (this->glsl_data_type) {
583 case GL_FLOAT:
584 glVertexAttribPointer(actual_index, this->rows,
585 this->data_type, GL_FALSE, stride,
586 (void *) *offset);
587 break;
588 case GL_DOUBLE:
589 if (piglit_is_gles()
590 || !piglit_is_extension_supported("GL_ARB_vertex_attrib_64bit")) {
591 fprintf(stderr,"vertex_attrib_description fail. no 64-bit float support\n");
592 return;
594 if (this->data_type != GL_DOUBLE) {
595 fprintf(stderr,"vertex_attrib_description fail. the GL"
596 " type must be 'GL_DOUBLE' and it is '%s'\n",
597 piglit_get_prim_name(this->data_type));
598 return;
600 glVertexAttribLPointer(actual_index, this->rows,
601 this->data_type, stride,
602 (void *) *offset);
603 break;
604 default:
605 if (piglit_is_gles() && piglit_get_gl_version() < 30) {
606 fprintf(stderr,"vertex_attrib_description fail. no int support\n");
607 return;
609 switch (this->data_type) {
610 case GL_BYTE:
611 case GL_UNSIGNED_BYTE:
612 case GL_SHORT:
613 case GL_UNSIGNED_SHORT:
614 case GL_INT:
615 case GL_UNSIGNED_INT:
616 break;
617 default:
618 fprintf(stderr,"vertex_attrib_description fail. the GL"
619 " type '%s' is incompatible\n",
620 piglit_get_prim_name(this->data_type));
621 return;
623 glVertexAttribIPointer(actual_index, this->rows,
624 this->data_type, stride,
625 (void *) *offset);
626 break;
628 glEnableVertexAttribArray(actual_index);
629 *offset += this->rows * this->data_type_size;
634 * Data structure containing all of the data parsed from the text
635 * input, as well as the methods that parse it and convert it to GL
636 * calls.
638 class vbo_data
640 public:
641 vbo_data(std::string const &text, GLuint prog);
642 size_t setup() const;
644 private:
645 void parse_header_line(const std::string &line, GLuint prog);
646 void parse_data_line(const std::string &line, unsigned int line_num);
647 void parse_line(std::string line, unsigned int line_num, GLuint prog);
650 * True if the header line has already been parsed.
652 bool header_seen;
655 * Description of each attribute.
657 std::vector<vertex_attrib_description> attribs;
660 * Raw data buffer containing parsed numbers.
662 std::vector<char> raw_data;
665 * Number of bytes in each row of raw_data.
667 size_t stride;
670 * Number of rows in raw_data.
672 size_t num_rows;
677 static bool
678 is_blank_line(const std::string &line)
680 for (size_t i = 0; i < line.size(); ++i) {
681 if (!isspace(line[i]))
682 return false;
684 return true;
689 * Populate this->attribs and compute this->stride based on column
690 * headers.
692 * If there is a parse failure, print a description of the problem and
693 * then exit with PIGLIT_FAIL.
695 void
696 vbo_data::parse_header_line(const std::string &line, GLuint prog)
698 size_t pos = 0;
699 this->stride = 0;
700 while (pos < line.size()) {
701 if (isspace(line[pos])) {
702 ++pos;
703 } else {
704 size_t column_header_end = pos;
705 while (column_header_end < line.size() &&
706 !isspace(line[column_header_end]))
707 ++column_header_end;
708 std::string column_header = line.substr(
709 pos, column_header_end - pos);
710 vertex_attrib_description desc(
711 prog, column_header.c_str());
712 attribs.push_back(desc);
713 this->stride += desc.rows * desc.data_type_size;
714 pos = column_header_end + 1;
721 * Convert a data row into binary form and append it to this->raw_data.
723 * If there is a parse failure, print a description of the problem and
724 * then exit with PIGLIT_FAIL.
726 void
727 vbo_data::parse_data_line(const std::string &line, unsigned int line_num)
729 /* Allocate space in raw_data for this line */
730 size_t old_size = this->raw_data.size();
731 this->raw_data.resize(old_size + this->stride);
732 char *data_ptr = &this->raw_data[old_size];
734 const char *line_ptr = line.c_str();
735 for (size_t i = 0; i < this->attribs.size(); ++i) {
736 for (size_t j = 0; j < this->attribs[i].rows; ++j) {
737 if (!this->attribs[i].parse_datum(&line_ptr,
738 data_ptr)) {
739 printf("At line %u of [vertex data] section\n",
740 line_num);
741 printf("Offending text: %s\n", line_ptr);
742 piglit_report_result(PIGLIT_FAIL);
744 data_ptr += this->attribs[i].data_type_size;
748 ++this->num_rows;
753 * Parse a line of input text.
755 * If there is a parse failure, print a description of the problem and
756 * then exit with PIGLIT_FAIL.
758 void
759 vbo_data::parse_line(std::string line, unsigned int line_num, GLuint prog)
761 /* Ignore end-of-line comments */
762 line = line.substr(0, line.find('#'));
764 /* Ignore blank or comment-only lines */
765 if (is_blank_line(line))
766 return;
768 if (!this->header_seen) {
769 this->header_seen = true;
770 parse_header_line(line, prog);
771 } else {
772 parse_data_line(line, line_num);
778 * Parse the input but don't execute any GL commands.
780 * If there is a parse failure, print a description of the problem and
781 * then exit with PIGLIT_FAIL.
783 vbo_data::vbo_data(const std::string &text, GLuint prog)
784 : header_seen(false), stride(0), num_rows(0)
786 unsigned int line_num = 1;
788 size_t pos = 0;
789 while (pos < text.size()) {
790 size_t end_of_line = text.find('\n', pos);
791 if (end_of_line == std::string::npos)
792 end_of_line = text.size();
793 parse_line(text.substr(pos, end_of_line), line_num++, prog);
794 pos = end_of_line + 1;
800 * Execute the necessary GL commands to set up the vertex data passed
801 * to the constructor.
803 size_t
804 vbo_data::setup() const
806 GLuint buffer_handle;
807 glGenBuffers(1, &buffer_handle);
808 glBindBuffer(GL_ARRAY_BUFFER, buffer_handle);
809 glBufferData(GL_ARRAY_BUFFER, this->stride * this->num_rows,
810 &this->raw_data[0], GL_STATIC_DRAW);
812 size_t offset = 0;
813 for (size_t i = 0; i < attribs.size(); ++i)
814 attribs[i].setup(&offset, this->stride);
816 /* Leave buffer bound for later draw calls */
818 return this->num_rows;
823 * Set up a vertex buffer object for the program prog based on the
824 * data encoded in text_start. text_end indicates the end of the text
825 * string; if it is NULL, the string is assumed to be null-terminated.
827 * Return value is the number of rows of vertex data found.
829 * For details about the format of the text string, see the comment at
830 * the top of this file.
832 size_t
833 setup_vbo_from_text(GLuint prog, const char *text_start, const char *text_end)
835 if (text_end == NULL)
836 text_end = text_start + strlen(text_start);
837 std::string text(text_start, text_end);
838 return vbo_data(text, prog).setup();