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