1 /* Freetype GL - A C OpenGL Freetype engine
2  *
3  * Distributed under the OSI-approved BSD 2-Clause License.  See accompanying
4  * file `LICENSE` for more details.
5  */
6 #include <stdio.h>
7 #include <string.h>
8 
9 #include "freetype-gl.h"
10 #include "vertex-buffer.h"
11 #include "markup.h"
12 #include "shader.h"
13 #include "mat4.h"
14 #include "screenshot-util.h"
15 
16 #include <GLFW/glfw3.h>
17 
18 
19 // -------------------------------------------------------------- constants ---
20 const int __SIGNAL_ACTIVATE__     = 0;
21 const int __SIGNAL_COMPLETE__     = 1;
22 const int __SIGNAL_HISTORY_NEXT__ = 2;
23 const int __SIGNAL_HISTORY_PREV__ = 3;
24 #define MAX_LINE_LENGTH  511
25 
26 
27 const int MARKUP_NORMAL      = 0;
28 const int MARKUP_DEFAULT     = 0;
29 const int MARKUP_ERROR       = 1;
30 const int MARKUP_WARNING     = 2;
31 const int MARKUP_OUTPUT      = 3;
32 const int MARKUP_BOLD        = 4;
33 const int MARKUP_ITALIC      = 5;
34 const int MARKUP_BOLD_ITALIC = 6;
35 const int MARKUP_FAINT       = 7;
36 #define   MARKUP_COUNT         8
37 
38 
39 // ------------------------------------------------------- typedef & struct ---
40 typedef struct {
41     float x, y, z;
42     float s, t;
43     float r, g, b, a;
44 } vertex_t;
45 
46 struct _console_t {
47     vector_t *     lines;
48     char *prompt;
49     char killring[MAX_LINE_LENGTH+1];
50     char input[MAX_LINE_LENGTH+1];
51     size_t         cursor;
52     markup_t       markup[MARKUP_COUNT];
53     vertex_buffer_t * buffer;
54     texture_atlas_t *atlas;
55     vec2           pen;
56     void (*handlers[4])( struct _console_t *, char * );
57 };
58 typedef struct _console_t console_t;
59 
60 
61 // ------------------------------------------------------- global variables ---
62 static console_t * console;
63 GLuint shader;
64 mat4   model, view, projection;
65 int control_key_handled;
66 
67 
68 // ------------------------------------------------------------ console_new ---
69 console_t *
console_new(float font_size)70 console_new( float font_size )
71 {
72     console_t *self = (console_t *) malloc( sizeof(console_t) );
73     if( !self )
74     {
75         return self;
76     }
77     self->lines = vector_new( sizeof(char *) );
78     self->prompt = strdup( ">>> " );
79     self->cursor = 0;
80     self->buffer = vertex_buffer_new( "vertex:3f,tex_coord:2f,color:4f" );
81     self->input[0] = '\0';
82     self->killring[0] = '\0';
83     self->handlers[__SIGNAL_ACTIVATE__]     = 0;
84     self->handlers[__SIGNAL_COMPLETE__]     = 0;
85     self->handlers[__SIGNAL_HISTORY_NEXT__] = 0;
86     self->handlers[__SIGNAL_HISTORY_PREV__] = 0;
87     self->pen.x = self->pen.y = 0;
88 
89     self->atlas = texture_atlas_new( 512, 512, 1 );
90     glGenTextures( 1, &self->atlas->id );
91 
92     vec4 white = {{1,1,1,1}};
93     vec4 black = {{0,0,0,1}};
94     vec4 none = {{0,0,1,0}};
95 
96     markup_t normal;
97     normal.family  = "fonts/VeraMono.ttf";
98     normal.size    = font_size;
99     normal.bold    = 0;
100     normal.italic  = 0;
101     normal.spacing = 0.0;
102     normal.gamma   = 1.0;
103     normal.foreground_color    = black;
104     normal.background_color    = none;
105     normal.underline           = 0;
106     normal.underline_color     = white;
107     normal.overline            = 0;
108     normal.overline_color      = white;
109     normal.strikethrough       = 0;
110     normal.strikethrough_color = white;
111 
112     normal.font = texture_font_new_from_file( self->atlas, font_size, "fonts/VeraMono.ttf" );
113 
114     markup_t bold = normal;
115     bold.bold = 1;
116     bold.font = texture_font_new_from_file( self->atlas, font_size, "fonts/VeraMoBd.ttf" );
117 
118     markup_t italic = normal;
119     italic.italic = 1;
120     bold.font = texture_font_new_from_file( self->atlas, font_size, "fonts/VeraMoIt.ttf" );
121 
122     markup_t bold_italic = normal;
123     bold.bold = 1;
124     italic.italic = 1;
125     italic.font = texture_font_new_from_file( self->atlas, font_size, "fonts/VeraMoBI.ttf" );
126 
127     markup_t faint = normal;
128     faint.foreground_color.r = 0.35;
129     faint.foreground_color.g = 0.35;
130     faint.foreground_color.b = 0.35;
131 
132     markup_t error = normal;
133     error.foreground_color.r = 1.00;
134     error.foreground_color.g = 0.00;
135     error.foreground_color.b = 0.00;
136 
137     markup_t warning = normal;
138     warning.foreground_color.r = 1.00;
139     warning.foreground_color.g = 0.50;
140     warning.foreground_color.b = 0.50;
141 
142     markup_t output = normal;
143     output.foreground_color.r = 0.00;
144     output.foreground_color.g = 0.00;
145     output.foreground_color.b = 1.00;
146 
147     self->markup[MARKUP_NORMAL] = normal;
148     self->markup[MARKUP_ERROR] = error;
149     self->markup[MARKUP_WARNING] = warning;
150     self->markup[MARKUP_OUTPUT] = output;
151     self->markup[MARKUP_FAINT] = faint;
152     self->markup[MARKUP_BOLD] = bold;
153     self->markup[MARKUP_ITALIC] = italic;
154     self->markup[MARKUP_BOLD_ITALIC] = bold_italic;
155 
156     return self;
157 }
158 
159 
160 
161 // -------------------------------------------------------- console_delete ---
162 void
console_delete(console_t * self)163 console_delete( console_t *self )
164 {
165     glDeleteTextures( 1, &self->atlas->id );
166     self->atlas->id = 0;
167     texture_atlas_delete( self->atlas );
168 }
169 
170 
171 
172 // ----------------------------------------------------- console_add_glyph ---
173 void
console_add_glyph(console_t * self,char * current,char * previous,markup_t * markup)174 console_add_glyph( console_t *self,
175                    char* current,
176                    char* previous,
177                    markup_t *markup )
178 {
179     texture_glyph_t *glyph  = texture_font_get_glyph( markup->font, current );
180     if( previous )
181     {
182         self->pen.x += texture_glyph_get_kerning( glyph, previous );
183     }
184     float r = markup->foreground_color.r;
185     float g = markup->foreground_color.g;
186     float b = markup->foreground_color.b;
187     float a = markup->foreground_color.a;
188     int x0  = self->pen.x + glyph->offset_x;
189     int y0  = self->pen.y + glyph->offset_y;
190     int x1  = x0 + glyph->width;
191     int y1  = y0 - glyph->height;
192     float s0 = glyph->s0;
193     float t0 = glyph->t0;
194     float s1 = glyph->s1;
195     float t1 = glyph->t1;
196 
197     GLuint indices[] = {0,1,2, 0,2,3};
198     vertex_t vertices[] = { { x0,y0,0,  s0,t0,  r,g,b,a },
199                             { x0,y1,0,  s0,t1,  r,g,b,a },
200                             { x1,y1,0,  s1,t1,  r,g,b,a },
201                             { x1,y0,0,  s1,t0,  r,g,b,a } };
202     vertex_buffer_push_back( self->buffer, vertices, 4, indices, 6 );
203 
204     self->pen.x += glyph->advance_x;
205     self->pen.y += glyph->advance_y;
206 }
207 
208 
209 
210 // -------------------------------------------------------- console_render ---
211 void
console_render(console_t * self)212 console_render( console_t *self )
213 {
214     char* cur_char;
215     char* prev_char;
216 
217     int viewport[4];
218     glGetIntegerv( GL_VIEWPORT, viewport );
219 
220     size_t i, index;
221     self->pen.x = 0;
222     self->pen.y = viewport[3];
223     vertex_buffer_clear( console->buffer );
224 
225     int cursor_x = self->pen.x;
226     int cursor_y = self->pen.y;
227 
228     markup_t markup;
229 
230     // console_t buffer
231     markup = self->markup[MARKUP_FAINT];
232     self->pen.y -= markup.font->height;
233 
234     for( i=0; i<self->lines->size; ++i )
235     {
236         char *text = * (char **) vector_get( self->lines, i ) ;
237         if( strlen(text) > 0 )
238         {
239             cur_char = text;
240             prev_char = NULL;
241             console_add_glyph( console, cur_char, prev_char, &markup );
242             prev_char = cur_char;
243             for( index=1; index < strlen(text)-1; ++index )
244             {
245                 cur_char = text + index;
246                 console_add_glyph( console, cur_char, prev_char, &markup );
247                 prev_char = cur_char;
248             }
249         }
250         self->pen.y -= markup.font->height - markup.font->linegap;
251         self->pen.x = 0;
252         cursor_x = self->pen.x;
253         cursor_y = self->pen.y;
254     }
255 
256     // Prompt
257     markup = self->markup[MARKUP_BOLD];
258     if( strlen( self->prompt ) > 0 )
259     {
260         cur_char = self->prompt;
261         prev_char = NULL;
262         console_add_glyph( console, cur_char, prev_char, &markup );
263         prev_char = cur_char;
264         for( index=1; index < strlen(self->prompt); ++index )
265         {
266             cur_char = self->prompt + index;
267             console_add_glyph( console, cur_char, prev_char, &markup );
268             prev_char = cur_char;
269         }
270     }
271     cursor_x = (int) self->pen.x;
272 
273     // Input
274     markup = self->markup[MARKUP_NORMAL];
275     if( strlen(self->input) > 0 )
276     {
277         cur_char = self->input;
278         prev_char = NULL;
279         console_add_glyph( console, cur_char, prev_char, &markup );
280         prev_char = cur_char;
281         if( self->cursor > 0)
282         {
283             cursor_x = (int) self->pen.x;
284         }
285         for( index=1; index < strlen(self->input); ++index )
286         {
287             cur_char = self->input + index;
288             console_add_glyph( console, cur_char, prev_char, &markup );
289             prev_char = cur_char;
290             if( index < self->cursor )
291             {
292                 cursor_x = (int) self->pen.x;
293             }
294         }
295     }
296 
297     if( self->lines->size || self->prompt[0] != '\0' || self->input[0] != '\0' )
298     {
299         glBindTexture( GL_TEXTURE_2D, self->atlas->id );
300         glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
301         glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
302         glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
303         glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
304         glTexImage2D( GL_TEXTURE_2D, 0, GL_RED, self->atlas->width,
305                       self->atlas->height, 0, GL_RED, GL_UNSIGNED_BYTE,
306                       self->atlas->data );
307     }
308 
309     // Cursor (we use the black character (NULL) as texture )
310     texture_glyph_t *glyph  = texture_font_get_glyph( markup.font, NULL );
311     float r = markup.foreground_color.r;
312     float g = markup.foreground_color.g;
313     float b = markup.foreground_color.b;
314     float a = markup.foreground_color.a;
315     int x0  = cursor_x+1;
316     int y0  = cursor_y + markup.font->descender;
317     int x1  = cursor_x+2;
318     int y1  = y0 + markup.font->height - markup.font->linegap;
319     float s0 = glyph->s0;
320     float t0 = glyph->t0;
321     float s1 = glyph->s1;
322     float t1 = glyph->t1;
323     GLuint indices[] = {0,1,2, 0,2,3};
324     vertex_t vertices[] = { { x0,y0,0,  s0,t0,  r,g,b,a },
325                             { x0,y1,0,  s0,t1,  r,g,b,a },
326                             { x1,y1,0,  s1,t1,  r,g,b,a },
327                             { x1,y0,0,  s1,t0,  r,g,b,a } };
328     vertex_buffer_push_back( self->buffer, vertices, 4, indices, 6 );
329     glEnable( GL_TEXTURE_2D );
330 
331     glUseProgram( shader );
332     {
333         glUniform1i( glGetUniformLocation( shader, "texture" ),
334                      0 );
335         glUniformMatrix4fv( glGetUniformLocation( shader, "model" ),
336                             1, 0, model.data);
337         glUniformMatrix4fv( glGetUniformLocation( shader, "view" ),
338                             1, 0, view.data);
339         glUniformMatrix4fv( glGetUniformLocation( shader, "projection" ),
340                             1, 0, projection.data);
341         vertex_buffer_render( console->buffer, GL_TRIANGLES );
342     }
343 }
344 
345 
346 // ------------------------------------------------------- console_connect ---
347 void
console_connect(console_t * self,const char * signal,void (* handler)(console_t *,char *))348 console_connect( console_t *self,
349                   const char *signal,
350                   void (*handler)(console_t *, char *))
351 {
352     if( strcmp( signal,"activate" ) == 0 )
353     {
354         self->handlers[__SIGNAL_ACTIVATE__] = handler;
355     }
356     else if( strcmp( signal,"complete" ) == 0 )
357     {
358         self->handlers[__SIGNAL_COMPLETE__] = handler;
359     }
360     else if( strcmp( signal,"history-next" ) == 0 )
361     {
362         self->handlers[__SIGNAL_HISTORY_NEXT__] = handler;
363     }
364     else if( strcmp( signal,"history-prev" ) == 0 )
365     {
366         self->handlers[__SIGNAL_HISTORY_PREV__] = handler;
367     }
368 }
369 
370 
371 // --------------------------------------------------------- console_print ---
372 void
console_print(console_t * self,char * text)373 console_print( console_t *self, char *text )
374 {
375     // Make sure there is at least one line
376     if( self->lines->size == 0 )
377     {
378         char *line = strdup( "" );
379         vector_push_back( self->lines, &line );
380     }
381 
382     // Make sure last line does not end with '\n'
383     char *last_line = *(char **) vector_get( self->lines, self->lines->size-1 ) ;
384     if( strlen( last_line ) != 0 )
385     {
386         if( last_line[strlen( last_line ) - 1] == '\n' )
387         {
388             char *line = strdup( "" );
389             vector_push_back( self->lines, &line );
390         }
391     }
392     last_line = *(char **) vector_get( self->lines, self->lines->size-1 ) ;
393 
394     char *start = text;
395     char *end   = strchr(start, '\n');
396     size_t len = strlen( last_line );
397     if( end != NULL)
398     {
399         char *line = (char *) malloc( (len + end - start + 2)*sizeof( char ) );
400         strncpy( line, last_line, len );
401         strncpy( line + len, text, end-start+1 );
402 
403         line[len+end-start+1] = '\0';
404 
405         vector_set( self->lines, self->lines->size-1, &line );
406         free( last_line );
407         if( (end-start)  < (strlen( text )-1) )
408         {
409             console_print(self, end+1 );
410         }
411         return;
412     }
413     else
414     {
415         char *line = (char *) malloc( (len + strlen(text) + 1) * sizeof( char ) );
416         strncpy( line, last_line, len );
417         strcpy( line + len, text );
418         vector_set( self->lines, self->lines->size-1, &line );
419         free( last_line );
420         return;
421     }
422 }
423 
424 
425 // ------------------------------------------------------- console_process ---
426 void
console_process(console_t * self,const char * action,const unsigned char key)427 console_process( console_t *self,
428                   const char *action,
429                   const unsigned char key )
430 {
431     size_t len = strlen(self->input);
432 
433     if( strcmp(action, "type") == 0 )
434     {
435         if( len < MAX_LINE_LENGTH )
436         {
437             memmove( self->input + self->cursor+1,
438                      self->input + self->cursor,
439                      (len - self->cursor+1)*sizeof(char) );
440             self->input[self->cursor] = key;
441             self->cursor++;
442         }
443         else
444         {
445             fprintf( stderr, "Input buffer is full\n" );
446         }
447     }
448     else
449     {
450         if( strcmp( action, "enter" ) == 0 )
451         {
452             if( console->handlers[__SIGNAL_ACTIVATE__] )
453             {
454                 (*console->handlers[__SIGNAL_ACTIVATE__])(console, console->input);
455             }
456             console_print( self, self->prompt );
457             console_print( self, self->input );
458             console_print( self, "\n" );
459             self->input[0] = '\0';
460             self->cursor = 0;
461         }
462         else if( strcmp( action, "right" ) == 0 )
463         {
464             if( self->cursor < strlen(self->input) )
465             {
466                 self->cursor += 1;
467             }
468         }
469         else if( strcmp( action, "left" ) == 0 )
470         {
471             if( self->cursor > 0 )
472             {
473                 self->cursor -= 1;
474             }
475         }
476         else if( strcmp( action, "delete" ) == 0 )
477         {
478             memmove( self->input + self->cursor,
479                      self->input + self->cursor+1,
480                      (len - self->cursor)*sizeof(char) );
481         }
482         else if( strcmp( action, "backspace" ) == 0 )
483         {
484             if( self->cursor > 0 )
485             {
486                 memmove( self->input + self->cursor-1,
487                          self->input + self->cursor,
488                          (len - self->cursor+1)*sizeof(char) );
489                 self->cursor--;
490             }
491         }
492         else if( strcmp( action, "kill" ) == 0 )
493         {
494             if( self->cursor < len )
495             {
496                 strcpy(self->killring, self->input);
497                 self->input[self->cursor] = '\0';
498                 fprintf(stderr, "Kill ring: %s\n", self->killring);
499             }
500 
501         }
502         else if( strcmp( action, "yank" ) == 0 )
503         {
504             size_t l = strlen(self->killring);
505             if( (len + l) < MAX_LINE_LENGTH )
506             {
507                 memmove( self->input + self->cursor + l,
508                          self->input + self->cursor,
509                          (len - self->cursor)*sizeof(char) );
510                 memcpy( self->input + self->cursor,
511                         self->killring, l*sizeof(char));
512                 self->cursor += l;
513             }
514         }
515         else if( strcmp( action, "home" ) == 0 )
516         {
517             self->cursor = 0;
518         }
519         else if( strcmp( action, "end" ) == 0 )
520         {
521             self->cursor = strlen( self->input );
522         }
523         else if( strcmp( action, "clear" ) == 0 )
524         {
525         }
526         else if( strcmp( action, "history-prev" ) == 0 )
527         {
528             if( console->handlers[__SIGNAL_HISTORY_PREV__] )
529             {
530                 (*console->handlers[__SIGNAL_HISTORY_PREV__])( console, console->input );
531             }
532         }
533         else if( strcmp( action, "history-next" ) == 0 )
534         {
535             if( console->handlers[__SIGNAL_HISTORY_NEXT__] )
536             {
537                 (*console->handlers[__SIGNAL_HISTORY_NEXT__])( console, console->input );
538             }
539         }
540         else if( strcmp( action, "complete" ) == 0 )
541         {
542             if( console->handlers[__SIGNAL_COMPLETE__] )
543             {
544                 (*console->handlers[__SIGNAL_COMPLETE__])( console, console->input );
545             }
546         }
547     }
548 }
549 
550 
551 // ------------------------------------------------------- console activate ---
console_activate(console_t * self,char * input)552 void console_activate( console_t *self, char *input )
553 {
554     //console_print( self, "Activate callback\n" );
555     fprintf( stderr, "Activate callback : %s\n", input );
556 }
557 
558 
559 // ------------------------------------------------------- console complete ---
console_complete(console_t * self,char * input)560 void console_complete( console_t *self, char *input )
561 {
562     // console_print( self, "Complete callback\n" );
563     fprintf( stderr, "Complete callback : %s\n", input );
564 }
565 
566 
567 // ----------------------------------------------- console previous history ---
console_history_prev(console_t * self,char * input)568 void console_history_prev( console_t *self, char *input )
569 {
570     // console_print( self, "History prev callback\n" );
571     fprintf( stderr, "History prev callback : %s\n", input );
572 }
573 
574 
575 // --------------------------------------------------- console next history ---
console_history_next(console_t * self,char * input)576 void console_history_next( console_t *self, char *input )
577 {
578     // console_print( self, "History next callback\n" );
579     fprintf( stderr, "History next callback : %s\n", input );
580 }
581 
582 
583 // ------------------------------------------------------------------- init ---
init(float font_size)584 void init( float font_size )
585 {
586     control_key_handled = 0;
587 
588     console = console_new( font_size );
589     console_print( console,
590                    "OpenGL Freetype console\n"
591                    "Copyright 2011 Nicolas P. Rougier. All rights reserved.\n \n" );
592     console_connect( console, "activate",     console_activate );
593     console_connect( console, "complete",     console_complete );
594     console_connect( console, "history-prev", console_history_prev );
595     console_connect( console, "history-next", console_history_next );
596 
597     glClearColor( 1.00, 1.00, 1.00, 1.00 );
598     glDisable( GL_DEPTH_TEST );
599     glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
600     glEnable( GL_TEXTURE_2D );
601     glEnable( GL_BLEND );
602 
603     shader = shader_load("shaders/v3f-t2f-c4f.vert",
604                          "shaders/v3f-t2f-c4f.frag");
605     mat4_set_identity( &projection );
606     mat4_set_identity( &model );
607     mat4_set_identity( &view );
608 }
609 
610 
611 // ---------------------------------------------------------------- display ---
display(GLFWwindow * window)612 void display( GLFWwindow* window )
613 {
614     glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
615     console_render( console );
616     glfwSwapBuffers( window );
617 }
618 
619 
620 // ---------------------------------------------------------------- reshape ---
reshape(GLFWwindow * window,int width,int height)621 void reshape( GLFWwindow* window, int width, int height )
622 {
623     glViewport(0, 0, width, height);
624     mat4_set_orthographic( &projection, 0, width, 0, height, -1, 1);
625 }
626 
627 
628 // ----------------------------------------------------------- on char input ---
char_input(GLFWwindow * window,unsigned int cp)629 void char_input( GLFWwindow* window, unsigned int cp )
630 {
631     if( control_key_handled )
632     {
633         control_key_handled = 0;
634         return;
635     }
636 
637     console_process( console, "type", cp );
638 }
639 
640 
641 // --------------------------------------------------------------- keyboard ---
keyboard(GLFWwindow * window,int key,int scancode,int action,int mods)642 void keyboard( GLFWwindow* window, int key, int scancode, int action, int mods )
643 {
644     if( GLFW_PRESS != action && GLFW_REPEAT != action )
645     {
646         return;
647     }
648 
649     switch( key )
650     {
651         case GLFW_KEY_HOME:
652             console_process( console, "home", 0 );
653             break;
654         case GLFW_KEY_DELETE:
655             console_process( console, "delete", 0 );
656             break;
657         case GLFW_KEY_END:
658             console_process( console, "end", 0 );
659             break;
660         case GLFW_KEY_BACKSPACE:
661             console_process( console, "backspace", 0 );
662             break;
663         case GLFW_KEY_TAB:
664             console_process( console, "complete", 0 );
665             break;
666         case GLFW_KEY_ENTER:
667             console_process( console, "enter", 0 );
668             break;
669         case GLFW_KEY_ESCAPE:
670             console_process( console, "escape", 0 );
671             break;
672         case GLFW_KEY_UP:
673             console_process( console, "history-prev", 0 );
674             break;
675         case GLFW_KEY_DOWN:
676             console_process( console, "history-next", 0 );
677             break;
678         case GLFW_KEY_LEFT:
679             console_process( console,  "left", 0 );
680             break;
681         case GLFW_KEY_RIGHT:
682             console_process( console, "right", 0 );
683             break;
684         default:
685             break;
686     }
687 
688     if( ( GLFW_MOD_CONTROL & mods ) == 0 )
689     {
690         return;
691     }
692 
693     switch( key )
694     {
695         case GLFW_KEY_K:
696             control_key_handled = 1;
697             console_process( console, "kill", 0 );
698             break;
699         case GLFW_KEY_L:
700             control_key_handled = 1;
701             console_process( console, "clear", 0 );
702             break;
703         case GLFW_KEY_Y:
704             control_key_handled = 1;
705             console_process( console, "yank", 0 );
706             break;
707         default:
708             break;
709     }
710 }
711 
712 
713 // --------------------------------------------------------- error-callback ---
error_callback(int error,const char * description)714 void error_callback( int error, const char* description )
715 {
716     fputs( description, stderr );
717 }
718 
719 
720 // ------------------------------------------------------------------- main ---
main(int argc,char ** argv)721 int main( int argc, char **argv )
722 {
723     GLFWwindow* window;
724     char* screenshot_path = NULL;
725 
726     if (argc > 1)
727     {
728         if (argc == 3 && 0 == strcmp( "--screenshot", argv[1] ))
729             screenshot_path = argv[2];
730         else
731         {
732             fprintf( stderr, "Unknown or incomplete parameters given\n" );
733             exit( EXIT_FAILURE );
734         }
735     }
736 
737     glfwSetErrorCallback( error_callback );
738 
739     if (!glfwInit( ))
740     {
741         exit( EXIT_FAILURE );
742     }
743 
744     glfwWindowHint( GLFW_VISIBLE, GL_FALSE );
745     glfwWindowHint( GLFW_RESIZABLE, GL_FALSE );
746 
747     window = glfwCreateWindow( 600,400, argv[0], NULL, NULL );
748 
749     if (!window)
750     {
751         glfwTerminate( );
752         exit( EXIT_FAILURE );
753     }
754 
755     glfwMakeContextCurrent( window );
756     glfwSwapInterval( 1 );
757 
758     glfwSetFramebufferSizeCallback( window, reshape );
759     glfwSetWindowRefreshCallback( window, display );
760     glfwSetKeyCallback( window, keyboard );
761     glfwSetCharCallback( window, char_input );
762 
763 #ifndef __APPLE__
764     glewExperimental = GL_TRUE;
765     GLenum err = glewInit();
766     if (GLEW_OK != err)
767     {
768         /* Problem: glewInit failed, something is seriously wrong. */
769         fprintf( stderr, "Error: %s\n", glewGetErrorString(err) );
770         exit( EXIT_FAILURE );
771     }
772     fprintf( stderr, "Using GLEW %s\n", glewGetString(GLEW_VERSION) );
773 #endif
774 
775     glfwShowWindow( window );
776     int pixWidth, pixHeight;
777     glfwGetFramebufferSize( window, &pixWidth, &pixHeight );
778 
779     init( 13.0 * pixWidth / 600 );
780 
781     reshape( window, pixWidth, pixHeight );
782 
783     while (!glfwWindowShouldClose( window ))
784     {
785         display( window );
786         glfwPollEvents( );
787 
788         if (screenshot_path)
789         {
790             screenshot( window, screenshot_path );
791             glfwSetWindowShouldClose( window, 1 );
792         }
793     }
794 
795     console_delete( console );
796 
797     glfwDestroyWindow( window );
798     glfwTerminate( );
799 
800     return EXIT_SUCCESS;
801 }
802