FreeTypeGL-0.0.1: src/demo/demo-line-aa.c
/* =========================================================================
* Freetype GL - A C OpenGL Freetype engine
* Platform: Any
* WWW: http://code.google.com/p/freetype-gl/
* -------------------------------------------------------------------------
* Copyright 2011,2012 Nicolas P. Rougier. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY NICOLAS P. ROUGIER ''AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL NICOLAS P. ROUGIER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of Nicolas P. Rougier.
* ========================================================================= */
#if defined(__APPLE__)
#include <Glut/glut.h>
#else
#include <GL/glut.h>
#endif
#include <math.h>
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include "vertex-buffer.h"
// --------------------------------------------------- typedef & structures ---
typedef struct {
float x, y;
float u, v;
float r, g, b, a;
float thickness;}
vertex_t;
// ------------------------------------------------------- global variables ---
vertex_buffer_t * lines;
GLuint program = 0;
const char *vertex_shader_source =
"attribute float thickness; "
"varying float t; "
"void main() "
"{ "
" gl_FrontColor = gl_Color; "
" gl_TexCoord[0].xy = gl_MultiTexCoord0.xy; "
" gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; "
" t = thickness; "
"} ";
const char *fragment_shader_source =
"varying float t; "
"void main() "
"{ "
" vec4 color = gl_Color; "
" vec2 p = gl_TexCoord[0].st; "
" float dist = sqrt(p.x*p.x + p.y*p.y); "
" float width; "
" if (t < 1.0) width = dist; "
" else width = fwidth(dist); "
" float alpha = smoothstep(0.5-width,0.5+width, dist); "
" gl_FragColor = vec4(color.rgb, color.a*min((1.0-alpha), t) ); "
"} ";
// ---------------------------------------------------------------- display ---
void display( void )
{
glClear( GL_COLOR_BUFFER_BIT );
glColor4f( 0.0f, 0.0f, 0.0f, 1.0f);
glUseProgram( program );
vertex_buffer_render( lines, GL_TRIANGLES, "vtc" );
glUseProgram( 0 );
glutSwapBuffers( );
}
// ---------------------------------------------------------------- reshape ---
void reshape( int width, int height )
{
glViewport( 0, 0, width, height );
glMatrixMode( GL_PROJECTION );
glLoadIdentity( );
glOrtho( 0, width, 0, height, -1, 1 );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity( );
}
// --------------------------------------------------------------- keyboard ---
void
keyboard( unsigned char key, int x, int y )
{
if ( key == 27 )
{
exit( EXIT_SUCCESS );
}
}
// ----------------------------------------------------------- build_shader ---
GLuint
build_shader( const char* source, GLenum type )
{
GLuint handle = glCreateShader( type );
glShaderSource( handle, 1, &source, 0 );
glCompileShader( handle );
GLint compile_status;
glGetShaderiv( handle, GL_COMPILE_STATUS, &compile_status );
if( compile_status == GL_FALSE )
{
char messages[256];
glGetShaderInfoLog( handle, sizeof(messages), 0, &messages[0] );
fprintf( stderr, "%s\n", messages );
exit( EXIT_FAILURE );
}
return handle;
}
// ---------------------------------------------------------- build_program ---
GLuint
build_program( const char * vertex_source,
const char * fragment_source )
{
GLuint vertex_shader = build_shader( vertex_source, GL_VERTEX_SHADER);
GLuint fragment_shader = build_shader( fragment_source, GL_FRAGMENT_SHADER);
GLuint handle = glCreateProgram( );
glAttachShader( handle, vertex_shader);
glAttachShader( handle, fragment_shader);
glLinkProgram( handle);
GLint link_status;
glGetProgramiv( handle, GL_LINK_STATUS, &link_status );
if (link_status == GL_FALSE)
{
char messages[256];
glGetProgramInfoLog( handle, sizeof(messages), 0, &messages[0] );
fprintf( stderr, "%s\n", messages );
exit(1);
}
return handle;
}
// ----------------------------------------------------------- make_segment ---
void make_segment( vertex_buffer_t * buffer,
float x0, float y0,
float x1, float y1,
float thickness,
float r, float g, float b, float a )
{
assert( (x1 != x0) || (y1 != y0) );
assert( thickness != 0 );
float d = sqrt( (x1-x0)*(x1-x0) + (y1-y0)*(y1-y0) );
float dx, dy, t;
if (thickness < 2.0)
{
dx = (x1-x0)/d*0.5*2;
dy = (y1-y0)/d*0.5*2;
d = 2.0 - thickness/2.0;
t = thickness/2.0;
}
else if (thickness < 3.0)
{
dx = (x1-x0)/d*0.5*3;
dy = (y1-y0)/d*0.5*3;
d = 2.5 - thickness/2.0;
t = 1.0;
}
else
{
dx = (x1-x0)/d*0.5*thickness;
dy = (y1-y0)/d*0.5*thickness;
d = 1.0;
t = 1.0;
}
vertex_t body[6] = { {x0+dy,y0-dx, 0,-d, r,g,b,a, t},
{x0-dy,y0+dx, 0,+d, r,g,b,a, t},
{x1-dy,y1+dx, 0,+d, r,g,b,a, t},
{x0+dy,y0-dx, 0,-d, r,g,b,a, t},
{x1-dy,y1+dx, 0,+d, r,g,b,a, t},
{x1+dy,y1-dx, 0,-d, r,g,b,a, t} };
vertex_buffer_push_back_vertices ( buffer, body, 6);
// If line is too thin, no caps
if( thickness < 1.0 )
{
return;
}
// Line Cap 0
vertex_t cap0[6] = { {x0+dy, y0-dx, 0,-1, r,g,b,a, t},
{x0-dy, y0+dx, 0,+1, r,g,b,a, t},
{x0-dy-dx,y0+dx-dy, +1,+1, r,g,b,a, t},
{x0+dy, y0-dx, 0,-1, r,g,b,a, t},
{x0-dy-dx,y0+dx-dy, +1,+1, r,g,b,a, t},
{x0+dy-dx,y0-dx-dy, +1,-1, r,g,b,a, t} };
vertex_buffer_push_back_vertices ( buffer, cap0, 6);
// Line Cap 1
vertex_t cap1[6] = { {x1-dy, y1+dx, 0,-1, r,g,b,a, t},
{x1+dy, y1-dx, 0,+1, r,g,b,a, t},
{x1+dy+dx, y1-dx+dy, +1,+1, r,g,b,a, t},
{x1-dy, y1+dx, 0,-1, r,g,b,a, t},
{x1+dy+dx, y1-dx+dy, +1,+1, r,g,b,a, t},
{x1-dy+dx, y1+dx+dy, +1,-1, r,g,b,a, t} };
vertex_buffer_push_back_vertices ( buffer, cap1, 6);
}
// ------------------------------------------------------------------- init ---
void init( void )
{
glClearColor( 1.0f, 1.0f, 1.0f, 1.0f );
glDisable( GL_DEPTH_TEST );
glEnable( GL_BLEND );
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
// Make program
program = build_program( vertex_shader_source, fragment_shader_source );
//GLuint attrib = glGetAttribLocation(program, "thickness");
//printf("%d\n", attrib);
// Make lines
lines = vertex_buffer_new( "v2f:t2f:c4f:1g1f" );
float r=0.0f, g=0.0f, b=0.0f, a=1.0f;
size_t i;
for( i=0; i<57; ++i)
{
float thickness = (i+1)*0.2;
float x0 = 2+i*10+0.315;
float y0 = 5+0.315;
float x1 = 35+i*10+0.315;
float y1 = 170+0.315;
make_segment(lines, x0,y0, x1,y1, thickness, r,g,b,a);
}
}
// ------------------------------------------------------------------- main ---
int main( int argc, char **argv )
{
glutInit( &argc, argv );
glutInitWindowSize( 600, 175 );
glutInitDisplayMode( GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH );
glutCreateWindow( "OpenGL antialiased lines" );
glutReshapeFunc( reshape );
glutDisplayFunc( display );
glutKeyboardFunc( keyboard );
init();
glutMainLoop( );
return EXIT_SUCCESS;
}