1 // Copyright (c) 2015 Sergio Gonzalez. All rights reserved.
2 // License: https://github.com/serge-rgb/milton#license
3
4
5 #include "gl_helpers.h"
6 #include "gl.h"
7
8 #include "memory.h"
9 #include "platform.h"
10
11
12
13 #if defined(_WIN32)
14 // Declaring glMinSampleShadingARB because we have a different path for loading it.
15 typedef void glMinSampleShadingARBProc(GLclampf value); glMinSampleShadingARBProc* glMinSampleShadingARB;
16 #endif //_WIN32
17
18
19 // Global variable that keeps track of Milton's GL configuration. See GLHelperFlags.
20 static int g_gl_helper_flags;
21
22 namespace gl {
23
24 // Static helpers
25 static void
query_error(const char * expr,const char * file,int line)26 query_error (const char* expr, const char* file, int line)
27 {
28 GLenum err = glGetError();
29 const char* str = "";
30 if ( err != GL_NO_ERROR ) {
31 char buffer[256];
32 switch( err ) {
33 #ifdef GL_INVALID_ENUM
34 case GL_INVALID_ENUM:
35 str = "GL_INVALID_ENUM";
36 break;
37 #endif
38 #ifdef GL_INVALID_VALUE
39 case GL_INVALID_VALUE:
40 str = "GL_INVALID_VALUE";
41 break;
42 #endif
43 #ifdef GL_INVALID_OPERATION
44 case GL_INVALID_OPERATION:
45 str = "GL_INVALID_OPERATION";
46 break;
47 #endif
48 #ifdef GL_INVALID_FRAMEBUFFER_OPERATION
49 case GL_INVALID_FRAMEBUFFER_OPERATION:
50 str = "GL_INVALID_FRAMEBUFFER_OPERATION";
51 break;
52 #endif
53 #ifdef GL_OUT_OF_MEMORY
54 case GL_OUT_OF_MEMORY:
55 str = "GL_OUT_OF_MEMORY";
56 break;
57 #endif
58 #ifdef GL_STACK_OVERFLOW
59 case GL_STACK_OVERFLOW:
60 str = "GL_STACK_OVERFLOW";
61 break;
62 #endif
63 #ifdef GL_STACK_UNDERFLOW
64 case GL_STACK_UNDERFLOW:
65 str = "GL_STACK_UNDERFLOW";
66 break;
67 #endif
68 default:
69 str = "SOME GL ERROR";
70 break;
71 }
72 snprintf(buffer, 256, "%s in: %s:%d\n", str, file, line);
73 gl::log(buffer);
74 snprintf(buffer, 256, " ---- Expression: %s\n", expr);
75 gl::log(buffer);
76 }
77 }
78
79 static void
set_flags(int flags)80 set_flags (int flags)
81 {
82 g_gl_helper_flags |= flags;
83 }
84
85 bool
check_flags(int flags)86 check_flags (int flags)
87 {
88 bool result = g_gl_helper_flags & flags;
89 return result;
90 }
91
92 bool
load()93 load ()
94 {
95 #define X(ret, func, ...) func = (decltype(func)) platform_get_gl_proc(#func);
96 GL_FUNCTIONS
97 #undef X
98
99 bool ok = true;
100 // Extension checking.
101
102 #if MULTISAMPLING_ENABLED
103 i64 num_extensions = 0;
104 glGetIntegerv(GL_NUM_EXTENSIONS, (GLint*)&num_extensions);
105
106 if ( num_extensions > 0 ) {
107 for ( i64 extension_i = 0; extension_i < num_extensions; ++extension_i ) {
108 char* extension_string = (char*)glGetStringi(GL_EXTENSIONS, (GLuint)extension_i);
109
110 if ( strcmp(extension_string, "GL_ARB_sample_shading") == 0 ) {
111 gl::set_flags(GLHelperFlags_SAMPLE_SHADING);
112 }
113 if ( strcmp(extension_string, "GL_ARB_texture_multisample") == 0 ) {
114 gl::set_flags(GLHelperFlags_TEXTURE_MULTISAMPLE);
115 }
116 }
117 }
118 // glGetStringi probably does not handle GL_EXTENSIONS
119 else if ( num_extensions == 0 ) {
120 const char* extensions = (const char*)glGetString(GL_EXTENSIONS);
121 #define MAX_EXTENSION_LEN 256
122 char ext[MAX_EXTENSION_LEN] = {};
123 const char* begin = extensions;
124 for ( const char* end = extensions;
125 *end != '\0';
126 ++end ) {
127 if ( *end == ' ' ) {
128 size_t len = (size_t)end - (size_t)begin;
129
130 if ( len < MAX_EXTENSION_LEN ) {
131 memcpy((void*)ext, (void*)begin, len);
132 ext[len]='\0';
133 if ( strcmp(ext, "GL_ARB_sample_shading") == 0 ) {
134 gl::set_flags(GLHelperFlags_SAMPLE_SHADING);
135 }
136 if ( strcmp(ext, "GL_ARB_texture_multisample") == 0 ) {
137 gl::set_flags(GLHelperFlags_TEXTURE_MULTISAMPLE);
138 }
139 begin = end+1;
140 }
141 else {
142 milton_log("WARNING: Extension too large (%d)\n", len);
143 }
144 }
145 }
146 }
147 #endif
148
149 #if defined(_WIN32)
150 #pragma warning(push, 0)
151 if ( !check_flags(GLHelperFlags_SAMPLE_SHADING) ) {
152 glMinSampleShadingARB = NULL;
153 }
154 #pragma warning(pop)
155 #undef GETADDRESS
156 #endif
157 return ok;
158 }
159
160 void
log(char * str)161 log (char* str)
162 {
163 #ifdef _WIN32
164 OutputDebugStringA(str);
165 #else
166 fprintf(stderr, "%s", str);
167 #endif
168 }
169
170 GLuint
compile_shader(const char * in_src,GLuint type,char * config,char * variation_config)171 compile_shader (const char* in_src, GLuint type, char* config, char* variation_config)
172 {
173 const char* sources[] = {
174 #if USE_GL_3_2
175 "#version 330 \n",
176 #else
177 "#version 120\n",
178 //"#extension GL_ARB_gpu_shader5 : disable \n",
179 // "#extension GL_ARB_gpu_shader4 : enable \n",
180 (type == GL_VERTEX_SHADER) ? "#define in attribute \n#define out varying\n"
181 : "#define in varying \n#define out\n#define out_color gl_FragColor\n",
182 "#define texture texture2D\n",
183 #endif
184 #if STROKE_DEBUG_VIZ
185 "#define STROKE_DEBUG_VIZ 1\n",
186 #else
187 "#define STROKE_DEBUG_VIZ 0\n",
188 #endif
189 (check_flags(GLHelperFlags_TEXTURE_MULTISAMPLE)) ? "#define HAS_TEXTURE_MULTISAMPLE 1\n"
190 : "#define HAS_TEXTURE_MULTISAMPLE 0\n",
191 "#if HAS_TEXTURE_MULTISAMPLE\n",
192 "#extension GL_ARB_sample_shading : enable\n",
193 //" #extension GL_ARB_texture_multisample : enable\n",
194 "#endif\n",
195 #if USE_GL_3_2
196 (type == GL_FRAGMENT_SHADER) ? "out vec4 out_color; \n" : "\n",
197 #endif
198
199 config,
200 variation_config,
201 in_src
202 };
203
204 GLuint obj = glCreateShader(type);
205
206 glShaderSource(obj, array_count(sources), sources, NULL);
207 glCompileShader(obj);
208 // ERROR CHECKING
209 int res = 0;
210 //glGetObjectParameteriv(obj, GL_COMPILE_STATUS, &res);
211 glGetShaderiv(obj, GL_COMPILE_STATUS, &res);
212
213 GLint length;
214 glGetShaderiv(obj, GL_INFO_LOG_LENGTH, &length);
215 if ( !res && length > 0 ) {
216 if ( !res ) {
217 milton_log("SHADER SOURCE:\n%s\n", sources[2]);
218 }
219 char* log = (char*)mlt_calloc(1, (size_t)length, "Strings");
220 GLsizei written_len;
221 // glGetShaderInfoLog(obj, length, &written_len, log);
222 glGetShaderInfoLog (obj, length, &written_len, (GLchar*)log);
223 gl::log("Shader compilation info. \n ---- Info log:\n");
224 gl::log(log);
225
226 if ( !res ) {
227 milton_die_gracefully("Shader compilation error\n");
228 }
229
230 mlt_free(log, "Strings");
231 }
232 return obj;
233 }
234
235 #if defined(__MACH__)
236 #undef glShaderSourceARB
237 #undef glCompileShaderARB
238 #undef glGetObjectParameterivARB
239 #undef glGetInfoLogARB
240 #define glGetObjectParameterivARB glGetProgramiv
241 #define glGetInfoLogARB glGetProgramInfoLog
242 #define glAttachObjectARB glAttachShader
243 #define glLinkProgramARB glLinkProgram
244 #define glValidateProgramARB glValidateProgram
245 #define glUseProgramObjectARB glUseProgram
246 #endif
247
248 void
link_program(GLuint obj,GLuint shaders[],int64_t num_shaders)249 link_program (GLuint obj, GLuint shaders[], int64_t num_shaders)
250 {
251 mlt_assert(glIsProgram (obj));
252 for ( int i = 0; i < num_shaders; ++i ) {
253 mlt_assert(glIsShader(shaders[i]));
254
255 glAttachShader(obj, shaders[i]);
256 }
257 glLinkProgram(obj);
258
259 // ERROR CHECKING
260 int res = 0;
261 glGetProgramiv(obj, GL_LINK_STATUS, &res);
262 if ( !res ) {
263 gl::log("ERROR: program did not link.\n");
264 GLint len;
265 glGetProgramiv(obj, GL_INFO_LOG_LENGTH, &len);
266 GLsizei written_len;
267 char* log = (char*)mlt_calloc(1, (size_t)len, "Strings");
268 glGetProgramInfoLog(obj, (GLsizei)len, &written_len, (GLchar*)log);
269 //glGetInfoLog(obj, (GLsizei)len, &written_len, log);
270 gl::log(log);
271 mlt_free(log, "Strings");
272 mlt_assert(!"program linking error");
273 }
274 glValidateProgram(obj);
275 }
276 #if defined(__MACH__)
277 #undef glGetObjectParameterivARB
278 #undef glGetInfoLogARB
279 #undef glAttachObjectARB
280 #undef glLinkProgramARB
281 #undef glValidateProgramARB
282 #undef glUseProgramObjectARB
283 #endif
284
285 bool
set_attribute_vec2(GLuint program,char * name,GLfloat * data,size_t data_sz)286 set_attribute_vec2(GLuint program, char* name, GLfloat* data, size_t data_sz)
287 {
288 bool ok = true;
289 GLint loc = glGetAttribLocation(program, (GLchar*)name);
290 ok = loc >= 0;
291 if ( ok ) {
292 glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)data_sz, data, GL_STATIC_DRAW);
293 }
294
295 return ok;
296 }
297
298 void
use_program(GLuint program)299 use_program(GLuint program)
300 {
301 static GLuint cached_program = 0;
302 if (program != cached_program) {
303 glUseProgram(program);
304 cached_program = program;
305 }
306 }
307
308 bool
set_uniform_vec4(GLuint program,char * name,size_t count,float * vals)309 set_uniform_vec4(GLuint program, char* name, size_t count, float* vals)
310 {
311 GLint last_program; glGetIntegerv(GL_CURRENT_PROGRAM, &last_program);
312 use_program(program);
313 bool ok = true;
314 GLint loc = glGetUniformLocation(program, (GLchar*)name);
315 ok = loc >= 0;
316
317 if ( ok ) {
318 glUniform4fv(loc, (GLsizei)count, vals);
319 }
320 use_program(last_program);
321 return ok;
322 }
323
324 bool
set_uniform_vec3i(GLuint program,char * name,size_t count,i32 * vals)325 set_uniform_vec3i(GLuint program, char* name, size_t count, i32* vals)
326 {
327 GLint last_program; glGetIntegerv(GL_CURRENT_PROGRAM, &last_program);
328 use_program(program);
329 bool ok = true;
330 GLint loc = glGetUniformLocation(program, (GLchar*)name);
331 ok = loc >= 0;
332
333 if ( ok ) {
334 glUniform3iv(loc, (GLsizei)count, vals);
335 }
336 use_program(last_program);
337 return ok;
338 }
339
340 bool
set_uniform_vec3(GLuint program,char * name,size_t count,float * vals)341 set_uniform_vec3(GLuint program, char* name, size_t count, float* vals)
342 {
343 GLint last_program; glGetIntegerv(GL_CURRENT_PROGRAM, &last_program);
344 use_program(program);
345 bool ok = true;
346 GLint loc = glGetUniformLocation(program, (GLchar*)name);
347 ok = loc >= 0;
348
349 if ( ok ) {
350 glUniform3fv(loc, (GLsizei)count, vals);
351 }
352 use_program(last_program);
353 return ok;
354 }
355
356 bool
set_uniform_vec2(GLuint program,char * name,size_t count,float * vals)357 set_uniform_vec2(GLuint program, char* name, size_t count, float* vals)
358 {
359 GLint last_program; glGetIntegerv(GL_CURRENT_PROGRAM, &last_program);
360 use_program(program);
361 bool ok = true;
362 GLint loc = glGetUniformLocation(program, (GLchar*)name);
363 ok = loc >= 0;
364 if ( ok ) {
365 glUniform2fv(loc, (GLsizei)count, vals);
366 }
367 use_program(last_program);
368 return ok;
369 }
370
371 bool
set_uniform_vec2(GLuint program,char * name,float x,float y)372 set_uniform_vec2(GLuint program, char* name, float x, float y)
373 {
374 GLint last_program; glGetIntegerv(GL_CURRENT_PROGRAM, &last_program);
375 use_program(program);
376 bool ok = true;
377 GLint loc = glGetUniformLocation(program, (GLchar*)name);
378 ok = loc >= 0;
379 if ( ok ) {
380 glUniform2f(loc, x, y);
381 }
382 use_program(last_program);
383 return ok;
384 }
385
386 bool
set_uniform_vec2i(GLuint program,char * name,size_t count,i32 * vals)387 set_uniform_vec2i(GLuint program, char* name, size_t count, i32* vals)
388 {
389 GLint last_program; glGetIntegerv(GL_CURRENT_PROGRAM, &last_program);
390 use_program(program);
391 bool ok = true;
392 GLint loc = glGetUniformLocation(program, (GLchar*)name);
393 ok = loc >= 0;
394 if ( ok ) {
395 glUniform2iv(loc, (GLsizei)count, vals);
396 }
397 use_program(last_program);
398 return ok;
399 }
400
401 bool
set_uniform_f(GLuint program,char * name,float val)402 set_uniform_f(GLuint program, char* name, float val)
403 {
404 GLint last_program; glGetIntegerv(GL_CURRENT_PROGRAM, &last_program);
405 use_program(program);
406 bool ok = true;
407 GLint loc = glGetUniformLocation(program, (GLchar*)name);
408 ok = loc >= 0;
409 if ( ok ) {
410 glUniform1f(loc, val);
411 }
412 use_program(last_program);
413 return ok;
414 }
415
416 bool
set_uniform_i(GLuint program,char * name,i32 val)417 set_uniform_i(GLuint program, char* name, i32 val)
418 {
419 GLint last_program; glGetIntegerv(GL_CURRENT_PROGRAM, &last_program);
420 use_program(program);
421 bool ok = true;
422 GLint loc = glGetUniformLocation(program, (GLchar*)name);
423 ok = loc >= 0;
424 if ( ok ) {
425 glUniform1i(loc, val);
426 }
427 use_program(last_program);
428 return ok;
429 }
430
431 bool
set_uniform_vec2i(GLuint program,char * name,i32 x,i32 y)432 set_uniform_vec2i(GLuint program, char* name, i32 x, i32 y)
433 {
434 GLint last_program; glGetIntegerv(GL_CURRENT_PROGRAM, &last_program);
435 use_program(program);
436 bool ok = true;
437 GLint loc = glGetUniformLocation(program, (GLchar*)name);
438 ok = loc >= 0;
439 if ( ok ) {
440 glUniform2i(loc, x, y);
441 }
442 use_program(last_program);
443 return ok;
444 }
445
446 bool
set_uniform_mat2(GLuint program,char * name,f32 * vals)447 set_uniform_mat2 (GLuint program, char* name, f32* vals)
448 {
449 GLint last_program; glGetIntegerv(GL_CURRENT_PROGRAM, &last_program);
450 use_program(program);
451 bool ok = true;
452 GLint loc = glGetUniformLocation(program, (GLchar*)name);
453 ok = loc >= 0;
454 if ( ok ) {
455 glUniformMatrix2fv(loc, 1, /*transpose*/false, vals);
456 }
457 use_program(last_program);
458 return ok;
459 }
460
461
462 GLuint
new_color_texture(int w,int h)463 new_color_texture(int w, int h)
464 {
465 GLuint t = 0;
466 glGenTextures(1, &t);
467 glBindTexture(GL_TEXTURE_2D, t);
468 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
469 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
470 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
471 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
472 glTexImage2D(GL_TEXTURE_2D, /*level = */ 0, /*internal_format = */ GL_RGBA8,
473 /*width, height = */ w, h,
474 /*border = */ 0,
475 /*format = */ GL_RGBA, /*type = */ GL_FLOAT,
476 /*data = */ NULL);
477 glBindTexture(GL_TEXTURE_2D, 0);
478 return t;
479 }
480
481 GLuint
new_depth_stencil_texture(int w,int h)482 new_depth_stencil_texture(int w, int h)
483 {
484 GLuint t = 0;
485 glGenTextures(1, &t);
486 glBindTexture(GL_TEXTURE_2D, t);
487 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
488 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
489 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
490 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
491 //glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_INTENSITY);
492 // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
493 // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
494 glTexImage2D(GL_TEXTURE_2D, /*level = */ 0, /*internal_format = */ GL_DEPTH24_STENCIL8,
495 /*width, height = */ w,h,
496 /*border = */ 0,
497 /*format = */ GL_DEPTH_STENCIL, /*type = */ GL_UNSIGNED_INT_24_8,
498 /*data = */ NULL);
499 glBindTexture(GL_TEXTURE_2D, 0);
500 return t;
501 }
502
503 GLuint
new_fbo(GLuint color_attachment,GLuint depth_stencil_attachment,GLenum texture_target)504 new_fbo(GLuint color_attachment, GLuint depth_stencil_attachment, GLenum texture_target)
505 {
506 GLuint fbo = 0;
507 glGenFramebuffersEXT(1, &fbo);
508 glBindFramebufferEXT(GL_FRAMEBUFFER, fbo);
509
510
511 glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture_target,
512 color_attachment, 0);
513 if ( depth_stencil_attachment ) {
514 glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, texture_target,
515 depth_stencil_attachment, 0);
516 }
517
518 glBindFramebufferEXT(GL_FRAMEBUFFER, 0);
519 return fbo;
520 }
521
522
523 GLuint
new_color_texture_multisample(int w,int h)524 new_color_texture_multisample(int w, int h)
525 {
526 #if MULTISAMPLING_ENABLED
527 GLuint t = 0;
528 glGenTextures(1, &t);
529 glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, t);
530
531 glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, MSAA_NUM_SAMPLES,
532 GL_RGBA,
533 w,h,
534 GL_TRUE);
535 glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0);
536
537 return t;
538 #else
539 return 0;
540 #endif
541 }
542
543 GLuint
new_depth_stencil_texture_multisample(int w,int h)544 new_depth_stencil_texture_multisample(int w, int h)
545 {
546 #if MULTISAMPLING_ENABLED
547 GLuint t = 0;
548 glGenTextures(1, &t);
549 glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, t);
550
551 glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, MSAA_NUM_SAMPLES,
552 /*internalFormat, num of components*/GL_DEPTH24_STENCIL8,
553 w,h,
554 GL_TRUE);
555
556
557 glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0);
558
559 return t;
560 #else
561 return 0;
562 #endif
563 }
564
565 void
resize_color_texture_multisample(GLuint t,int w,int h)566 resize_color_texture_multisample(GLuint t, int w, int h)
567 {
568 #if MULTISAMPLING_ENABLED
569 glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, t);
570 glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, MSAA_NUM_SAMPLES,
571 GL_RGBA,
572 w,h,
573 GL_TRUE);
574 #endif
575 }
576
577 void
resize_depth_stencil_texture_multisample(GLuint t,int w,int h)578 resize_depth_stencil_texture_multisample(GLuint t, int w, int h)
579 {
580 #if MULTISAMPLING_ENABLED
581 glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, t);
582 glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, MSAA_NUM_SAMPLES,
583 GL_DEPTH24_STENCIL8,
584 w,h,
585 GL_TRUE);
586
587 #endif
588 }
589
590 void
resize_color_texture(GLuint t,int w,int h)591 resize_color_texture(GLuint t, int w, int h)
592 {
593 glBindTexture(GL_TEXTURE_2D, t);
594 glTexImage2D(GL_TEXTURE_2D, /*level = */ 0, /*internal_format = */ GL_RGBA8,
595 /*width, height = */ w,h,
596 /*border = */ 0,
597 /*format = */ GL_RGBA, /*type = */ GL_UNSIGNED_BYTE,
598 /*data = */ NULL);
599 }
600
601
602 void
resize_depth_stencil_texture(GLuint t,int w,int h)603 resize_depth_stencil_texture(GLuint t, int w, int h)
604 {
605 glBindTexture(GL_TEXTURE_2D, t);
606 glTexImage2D(GL_TEXTURE_2D, /*level = */ 0, /*internal_format = */ GL_DEPTH24_STENCIL8,
607 /*width, height = */ w,h,
608 /*border = */ 0,
609 /*format = */ GL_DEPTH_STENCIL, /*type = */ GL_UNSIGNED_INT_24_8,
610 /*data = */ NULL);
611 }
612
613 void
vertex_attrib_v3f(GLuint program,char * name,GLuint vbo)614 vertex_attrib_v3f(GLuint program, char* name, GLuint vbo)
615 {
616 GLint loc = glGetAttribLocation(program, name);
617 if (loc >= 0) {
618 glBindBuffer(GL_ARRAY_BUFFER, vbo);
619 glEnableVertexAttribArray((GLuint)loc);
620 glVertexAttribPointer(/*attrib location*/ (GLuint)loc,
621 /*size*/ 3, GL_FLOAT, /*normalize*/ GL_FALSE,
622 /*stride*/ 0, /*ptr*/ 0);
623 }
624 }
625
626 void
vertex_attrib_v2f(GLuint program,char * name,GLuint vbo)627 vertex_attrib_v2f(GLuint program, char* name, GLuint vbo)
628 {
629 GLint loc = glGetAttribLocation(program, name);
630 if (loc >= 0) {
631 glBindBuffer(GL_ARRAY_BUFFER, vbo);
632 glEnableVertexAttribArray((GLuint)loc);
633 glVertexAttribPointer(/*attrib location*/ (GLuint)loc,
634 /*size*/ 2, GL_FLOAT, /*normalize*/ GL_FALSE,
635 /*stride*/ 0, /*ptr*/ 0);
636 }
637 }
638
639
640 } // namespace gl
641
642 #ifdef _WIN32
643
644 #endif // _WIN32
645
646