// ---------------------------------------------------------------------------- // bind all kinds of buffer void vertex_buffer_render_setup ( vertex_buffer_t *self, GLenum mode ) { size_t i; if( self->state != CLEAN ) { vertex_buffer_upload( self ); self->state = CLEAN; } glBindBuffer( GL_ARRAY_BUFFER, self->vertices_id );// bind attribute as a whole for( i=0; i<MAX_VERTEX_ATTRIBUTE; ++i ) { vertex_attribute_t *attribute = self->attributes[i]; if ( attribute == 0 ) { continue; } else { vertex_attribute_enable( attribute ); } } if( self->indices->size ) { glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, self->indices_id );// index? } self->mode = mode; }
// ---------------------------------------------------------------------------- void vertex_buffer_render ( vertex_buffer_t *self, GLenum mode, const char *what ) { assert( self ); if( !self->vertices->size ) { return; } if( self->dirty ) { vertex_buffer_upload( self ); self->dirty = 0; } #ifdef GL_CLIENT_VERTEX_ARRAY_BIT glPushClientAttrib( GL_CLIENT_VERTEX_ARRAY_BIT ); #endif glBindBuffer( GL_ARRAY_BUFFER, self->vertices_id ); size_t i; for( i=0; i<MAX_VERTEX_ATTRIBUTE; ++i ) { vertex_attribute_t *attribute = self->attributes[i]; if ( attribute == 0 ) { break; } else { if (attribute->ctarget == 'g') { (*(attribute->enable))( attribute ); } else if ( strchr(what, attribute->ctarget) ) { (*(attribute->enable))( attribute ); } } } if( self->indices->size ) { glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, self->indices_id ); glDrawElements( mode, self->indices->size, GL_UNSIGNED_INT, 0 ); } else { glDrawArrays( mode, 0, self->vertices->size ); } glBindBuffer( GL_ARRAY_BUFFER, 0 ); glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 ); #ifdef GL_CLIENT_VERTEX_ARRAY_BIT glPopClientAttrib( ); #endif }
// ---------------------------------------------------------------------------- void vertex_buffer_render ( vertex_buffer_t *self, GLenum mode, const char *what ) { assert( self ); if( !self->vertices->size ) { return; } #ifdef GL_CLIENT_VERTEX_ARRAY_BIT glPushClientAttrib( GL_CLIENT_VERTEX_ARRAY_BIT ); #endif vertex_buffer_setup( self, what ); if( self->dirty ) { vertex_buffer_upload( self ); self->dirty = 0; } if( self->indices->size ) { glDrawElements( mode, self->indices->size, GL_UNSIGNED_SHORT, 0 ); } else { glDrawArrays( mode, 0, self->vertices->size ); } #ifdef BROKENVAO glBindVertexArray(0); // globalInfo.defaultVAOName glBindBuffer( GL_ARRAY_BUFFER, 0 ); glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 ); #else glBindBuffer( GL_ARRAY_BUFFER, 0 ); glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 ); #endif #ifdef GL_CLIENT_VERTEX_ARRAY_BIT glPopClientAttrib( ); #endif }
// ---------------------------------------------------------------------------- void vertex_buffer_render ( VertexBuffer *self, GLenum mode, const char *what ) { assert( self ); if( !self->vertices->size ) { return; } if( self->dirty ) { vertex_buffer_upload( self ); self->dirty = 0; } glBindBuffer( GL_ARRAY_BUFFER, self->vertices_id ); size_t i; for( i=0; i<MAX_VERTEX_ATTRIBUTE; ++i ) { VertexAttribute *attr = self->attributes[i]; if ( attr == 0 ) { break; } else { glEnableVertexAttribArray(attr->index); glVertexAttribPointer(attr->index, attr->size, attr->type, attr->normalized, attr->stride, attr->pointer); } } if( self->indices->size ) { glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, self->indices_id ); glDrawElements( mode, self->indices->size, GL_UNSIGNED_INT, 0 ); } else { glDrawArrays( mode, 0, self->vertices->size ); } glBindBuffer( GL_ARRAY_BUFFER, 0 ); glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 ); }
// ---------------------------------------------------------------------------- void vertex_buffer_render_setup ( vertex_buffer_t *self, GLenum mode, const char *what ) { if( self->state != CLEAN ) { vertex_buffer_upload( self ); self->state = CLEAN; } glPushClientAttrib( GL_CLIENT_VERTEX_ARRAY_BIT ); glBindBuffer( GL_ARRAY_BUFFER, self->vertices_id ); size_t i; for( i=0; i<MAX_VERTEX_ATTRIBUTE; ++i ) { vertex_attribute_t *attribute = self->attributes[i]; if ( attribute == 0 ) { break; } else { if (attribute->ctarget == 'g') { (*(attribute->enable))( attribute ); } else if ( strchr(what, attribute->ctarget) ) { (*(attribute->enable))( attribute ); } } } if( self->indices->size ) { glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, self->indices_id ); } self->mode = mode; }
// ---------------------------------------------------------------------------- void vertex_buffer_render_setup ( vertex_buffer_t *self, GLenum mode ) { size_t i; #ifdef FREETYPE_GL_USE_VAO // Unbind so no existing VAO-state is overwritten, // (e.g. the GL_ELEMENT_ARRAY_BUFFER-binding). glBindVertexArray( 0 ); #endif if( self->state != CLEAN ) { vertex_buffer_upload( self ); self->state = CLEAN; } #ifdef FREETYPE_GL_USE_VAO if( self->VAO_id == 0 ) { // Generate and set up VAO glGenVertexArrays( 1, &self->VAO_id ); glBindVertexArray( self->VAO_id ); glBindBuffer( GL_ARRAY_BUFFER, self->vertices_id ); for( i=0; i<MAX_VERTEX_ATTRIBUTE; ++i ) { vertex_attribute_t *attribute = self->attributes[i]; if( attribute == 0 ) { continue; } else { vertex_attribute_enable( attribute ); } } glBindBuffer( GL_ARRAY_BUFFER, 0 ); if( self->indices->size ) { glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, self->indices_id ); } } // Bind VAO for drawing glBindVertexArray( self->VAO_id ); #else glBindBuffer( GL_ARRAY_BUFFER, self->vertices_id ); for( i=0; i<MAX_VERTEX_ATTRIBUTE; ++i ) { vertex_attribute_t *attribute = self->attributes[i]; if ( attribute == 0 ) { continue; } else { vertex_attribute_enable( attribute ); } } if( self->indices->size ) { glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, self->indices_id ); } #endif self->mode = mode; }
// ------------------------------------------------------------------- main --- int main( int argc, char **argv ) { size_t i, j; GLFWwindow* window; glfwSetErrorCallback( error_callback ); if (!glfwInit( )) { exit( EXIT_FAILURE ); } glfwWindowHint( GLFW_VISIBLE, GL_TRUE ); glfwWindowHint( GLFW_RESIZABLE, GL_FALSE ); window = glfwCreateWindow( 1, 1, argv[0], NULL, NULL ); if (!window) { glfwTerminate( ); exit( EXIT_FAILURE ); } glfwMakeContextCurrent( window ); glfwSwapInterval( 1 ); glfwSetFramebufferSizeCallback( window, reshape ); glfwSetWindowRefreshCallback( window, display ); glfwSetKeyCallback( window, keyboard ); #ifndef __APPLE__ glewExperimental = GL_TRUE; GLenum err = glewInit(); if (GLEW_OK != err) { /* Problem: glewInit failed, something is seriously wrong. */ fprintf( stderr, "Error: %s\n", glewGetErrorString(err) ); exit( EXIT_FAILURE ); } fprintf( stderr, "Using GLEW %s\n", glewGetString(GLEW_VERSION) ); #endif texture_atlas_t * atlas = texture_atlas_new( 512, 512, 3 ); texture_font_t *fonts[20]; for ( i=0; i< 20; ++i ) { fonts[i] = texture_font_new_from_file(atlas, 12+i, font_filename), texture_font_load_glyphs(fonts[i], text, direction, language, script ); } typedef struct { float x,y,z, u,v, r,g,b,a, shift, gamma; } vertex_t; vbuffer = vertex_buffer_new( "vertex:3f,tex_coord:2f," "color:4f,ashift:1f,agamma:1f" ); /* Create a buffer for harfbuzz to use */ hb_buffer_t *buffer = hb_buffer_create(); for (i=0; i < 20; ++i) { hb_buffer_set_direction( buffer, direction ); hb_buffer_set_script( buffer, script ); hb_buffer_set_language( buffer, hb_language_from_string(language, strlen(language)) ); hb_buffer_add_utf8( buffer, text, strlen(text), 0, strlen(text) ); hb_shape( fonts[i]->hb_ft_font, buffer, NULL, 0 ); unsigned int glyph_count; hb_glyph_info_t *glyph_info = hb_buffer_get_glyph_infos(buffer, &glyph_count); hb_glyph_position_t *glyph_pos = hb_buffer_get_glyph_positions(buffer, &glyph_count); texture_font_load_glyphs( fonts[i], text, direction, language, script ); float gamma = 1.0; float shift = 0.0; float x = 0; float y = 600 - i * (10+i) - 15; float width = 0.0; float hres = fonts[i]->hres; for (j = 0; j < glyph_count; ++j) { int codepoint = glyph_info[j].codepoint; float x_advance = glyph_pos[j].x_advance/(float)(hres*64); float x_offset = glyph_pos[j].x_offset/(float)(hres*64); texture_glyph_t *glyph = texture_font_get_glyph(fonts[i], codepoint); if( i < (glyph_count-1) ) width += x_advance + x_offset; else width += glyph->offset_x + glyph->width; } x = 800 - width - 10 ; for (j = 0; j < glyph_count; ++j) { int codepoint = glyph_info[j].codepoint; // because of vhinting trick we need the extra 64 (hres) float x_advance = glyph_pos[j].x_advance/(float)(hres*64); float x_offset = glyph_pos[j].x_offset/(float)(hres*64); float y_advance = glyph_pos[j].y_advance/(float)(64); float y_offset = glyph_pos[j].y_offset/(float)(64); texture_glyph_t *glyph = texture_font_get_glyph(fonts[i], codepoint); float r = 0.0; float g = 0.0; float b = 0.0; float a = 1.0; float x0 = x + x_offset + glyph->offset_x; float x1 = x0 + glyph->width; float y0 = floor(y + y_offset + glyph->offset_y); float y1 = floor(y0 - glyph->height); float s0 = glyph->s0; float t0 = glyph->t0; float s1 = glyph->s1; float t1 = glyph->t1; vertex_t vertices[4] = { {x0,y0,0, s0,t0, r,g,b,a, shift, gamma}, {x0,y1,0, s0,t1, r,g,b,a, shift, gamma}, {x1,y1,0, s1,t1, r,g,b,a, shift, gamma}, {x1,y0,0, s1,t0, r,g,b,a, shift, gamma} }; GLushort indices[6] = { 0,1,2, 0,2,3 }; vertex_buffer_push_back( vbuffer, vertices, 4, indices, 6 ); x += x_advance; y += y_advance; } /* clean up the buffer, but don't kill it just yet */ hb_buffer_reset(buffer); } glClearColor(1,1,1,1); glEnable( GL_BLEND ); glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); glBindTexture( GL_TEXTURE_2D, atlas->id ); texture_atlas_upload( atlas ); vertex_buffer_upload( vbuffer ); shader = shader_load("shaders/text.vert", "shaders/text.frag"); mat4_set_identity( &projection ); mat4_set_identity( &model ); mat4_set_identity( &view ); glfwSetWindowSize( window, 800, 600 ); glfwShowWindow( window ); while(!glfwWindowShouldClose( window )) { display( window ); glfwPollEvents( ); } glfwDestroyWindow( window ); glfwTerminate( ); return 0; }
// ------------------------------------------------------------------- init --- void init( void ) { size_t i, j; texture_atlas_t * atlas = texture_atlas_new( 512, 512, 3 ); texture_font_t *fonts[20]; for ( i=0; i< 20; ++i ) { fonts[i] = texture_font_new_from_file(atlas, 12+i, font_filename), texture_font_load_glyphs(fonts[i], text, direction, language, script ); } typedef struct { float x,y,z, u,v, r,g,b,a, shift, gamma; } vertex_t; vbuffer = vertex_buffer_new( "vertex:3f,tex_coord:2f," "color:4f,ashift:1f,agamma:1f" ); /* Create a buffer for harfbuzz to use */ hb_buffer_t *buffer = hb_buffer_create(); for (i=0; i < 20; ++i) { hb_buffer_set_direction( buffer, direction ); hb_buffer_set_script( buffer, script ); hb_buffer_set_language( buffer, hb_language_from_string(language, strlen(language)) ); hb_buffer_add_utf8( buffer, text, strlen(text), 0, strlen(text) ); hb_shape( fonts[i]->hb_ft_font, buffer, NULL, 0 ); unsigned int glyph_count; hb_glyph_info_t *glyph_info = hb_buffer_get_glyph_infos(buffer, &glyph_count); hb_glyph_position_t *glyph_pos = hb_buffer_get_glyph_positions(buffer, &glyph_count); texture_font_load_glyphs( fonts[i], text, direction, language, script ); float gamma = 1.0; float shift = 0.0; float x = 0; float y = 600 - i * (10+i) - 15; float width = 0.0; float hres = fonts[i]->hres; for (j = 0; j < glyph_count; ++j) { int codepoint = glyph_info[j].codepoint; float x_advance = glyph_pos[j].x_advance/(float)(hres*64); float x_offset = glyph_pos[j].x_offset/(float)(hres*64); texture_glyph_t *glyph = texture_font_get_glyph(fonts[i], codepoint); if( i < (glyph_count-1) ) width += x_advance + x_offset; else width += glyph->offset_x + glyph->width; } x = 800 - width - 10 ; for (j = 0; j < glyph_count; ++j) { int codepoint = glyph_info[j].codepoint; // because of vhinting trick we need the extra 64 (hres) float x_advance = glyph_pos[j].x_advance/(float)(hres*64); float x_offset = glyph_pos[j].x_offset/(float)(hres*64); float y_advance = glyph_pos[j].y_advance/(float)(64); float y_offset = glyph_pos[j].y_offset/(float)(64); texture_glyph_t *glyph = texture_font_get_glyph(fonts[i], codepoint); float r = 0.0; float g = 0.0; float b = 0.0; float a = 1.0; float x0 = x + x_offset + glyph->offset_x; float x1 = x0 + glyph->width; float y0 = floor(y + y_offset + glyph->offset_y); float y1 = floor(y0 - glyph->height); float s0 = glyph->s0; float t0 = glyph->t0; float s1 = glyph->s1; float t1 = glyph->t1; vertex_t vertices[4] = { {x0,y0,0, s0,t0, r,g,b,a, shift, gamma}, {x0,y1,0, s0,t1, r,g,b,a, shift, gamma}, {x1,y1,0, s1,t1, r,g,b,a, shift, gamma}, {x1,y0,0, s1,t0, r,g,b,a, shift, gamma} }; GLuint indices[6] = { 0,1,2, 0,2,3 }; vertex_buffer_push_back( vbuffer, vertices, 4, indices, 6 ); x += x_advance; y += y_advance; } /* clean up the buffer, but don't kill it just yet */ hb_buffer_reset(buffer); } glClearColor(1,1,1,1); glEnable( GL_BLEND ); glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); glEnable( GL_TEXTURE_2D ); glBindTexture( GL_TEXTURE_2D, atlas->id ); texture_atlas_upload( atlas ); vertex_buffer_upload( vbuffer ); shader = shader_load("shaders/text.vert", "shaders/text.frag"); mat4_set_identity( &projection ); mat4_set_identity( &model ); mat4_set_identity( &view ); }