4 Copyright 2008-2012 Michel Pollet <buserror@gmail.com>
6 This file is part of simavr.
8 simavr is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
13 simavr is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with simavr. If not, see <http://www.gnu.org/licenses/>.
23 #define GL_GLEXT_PROTOTYPES
24 #include <GLUT/glut.h>
25 #include <OpenGL/gl.h>
26 #include <OpenGL/glext.h>
28 #define GL_GLEXT_PROTOTYPES
38 #include "reprap_gl.h"
42 #include "c3driver_context.h"
46 #include "c3program.h"
49 #include <cairo/cairo.h>
53 struct cairo_surface_t;
55 int _w = 800, _h = 600;
57 c3context_p c3 = NULL;
58 c3context_p hud = NULL;
60 c3object_p head = NULL; // hotend
61 c3texture_p fbo_c3; // frame buffer object texture
62 c3program_p fxaa = NULL; // full screen antialias shader
64 int glsl_version = 110;
66 extern reprap_t reprap;
68 static int dumpError(const char * what)
72 while ((e = glGetError()) != GL_NO_ERROR) {
73 printf("%s: %s\n", what, gluErrorString(e));
79 #define GLCHECK(_w) {_w; dumpError(#_w);}
82 GLuint fbo, fbo_texture, rbo_depth;
83 //GLuint vbo_fbo_vertices;
91 /* Create back-buffer, used for post-processing */
94 GLCHECK(glActiveTexture(GL_TEXTURE0));
95 glGenTextures(1, &fbo_texture);
96 glBindTexture(GL_TEXTURE_2D, fbo_texture);
97 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
98 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
99 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
100 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
101 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, screen_width, screen_height, 0,
102 GL_RGBA, GL_UNSIGNED_BYTE, NULL);
103 glBindTexture(GL_TEXTURE_2D, 0);
106 GLCHECK(glGenRenderbuffers(1, &rbo_depth));
107 glBindRenderbuffer(GL_RENDERBUFFER, rbo_depth);
108 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, screen_width,
110 glBindRenderbuffer(GL_RENDERBUFFER, 0);
112 /* Framebuffer to link everything together */
113 GLCHECK(glGenFramebuffers(1, &fbo));
114 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
115 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
117 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
118 GL_RENDERBUFFER, rbo_depth);
121 if ((status = glCheckFramebufferStatus(GL_FRAMEBUFFER))
122 != GL_FRAMEBUFFER_COMPLETE) {
123 fprintf(stderr, "glCheckFramebufferStatus: error %d", (int)status);
127 // Set the list of draw buffers.
128 GLenum DrawBuffers[2] = {GL_COLOR_ATTACHMENT0};
129 glDrawBuffers(1, DrawBuffers); // "1" is the size of DrawBuffers
130 glBindFramebuffer(GL_FRAMEBUFFER, 0);
139 // Rescale FBO and RBO as well
140 glBindTexture(GL_TEXTURE_2D, fbo_texture);
141 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, screen_width, screen_height, 0,
142 GL_RGBA, GL_UNSIGNED_BYTE, NULL);
143 glBindTexture(GL_TEXTURE_2D, 0);
145 glBindRenderbuffer(GL_RENDERBUFFER, rbo_depth);
146 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, screen_width,
148 glBindRenderbuffer(GL_RENDERBUFFER, 0);
151 void gl_offscreenFree()
154 glDeleteRenderbuffers(1, &rbo_depth);
155 glDeleteTextures(1, &fbo_texture);
156 glDeleteFramebuffers(1, &fbo);
160 _gl_reshape_cb(int w, int h)
165 glViewport(0, 0, _w, _h);
166 gl_offscreenReshape(_w, _h);
174 int y) /* called on key press */
178 // avr_vcd_stop(&vcd_file);
179 c3context_dispose(c3);
183 printf("Starting VCD trace; press 's' to stop\n");
184 // avr_vcd_start(&vcd_file);
187 printf("Stopping VCD trace\n");
188 // avr_vcd_stop(&vcd_file);
191 if (fbo_c3->geometry.mat.program)
192 fbo_c3->geometry.mat.program = NULL;
194 fbo_c3->geometry.mat.program = fxaa;
201 _gl_display_cb(void) /* function called whenever redisplay needed */
207 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
208 // draw (without glutSwapBuffers)
209 dumpError("glBindFramebuffer fbo");
210 glViewport(0, 0, _w, _h);
213 glBindFramebuffer(GL_FRAMEBUFFER, 0);
216 c3context_view_set(c3, 0);
217 c3vec3 headp = c3vec3f(
218 stepper_get_position_mm(&reprap.step_x),
219 stepper_get_position_mm(&reprap.step_y),
220 stepper_get_position_mm(&reprap.step_z));
221 c3mat4 headmove = translation3D(headp);
222 c3transform_set(head->transform.e[0], &headmove);
224 if (c3->root->dirty) {
225 // printf("reproject head %.2f,%.2f,%.2f\n", headp.x, headp.y,headp.z);
226 c3context_project(c3);
228 float z_min = c3context_view_get(c3)->z.min,
229 z_max = c3context_view_get(c3)->z.max;
233 if (z_max < z_min || z_max > 1000)
236 glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
237 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
239 // Set up projection matrix
240 glMatrixMode(GL_PROJECTION); // Select projection matrix
241 glLoadIdentity(); // Start with an identity matrix
243 gluPerspective(50, (float)_w / (float)_h, z_min, z_max);
246 glEnable(GL_CULL_FACE);
248 glDepthMask(GL_TRUE);
249 glDepthFunc(GL_LEQUAL);
250 glEnable(GL_DEPTH_TEST);
251 glEnable(GL_LIGHTING);
252 // glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
254 glEnable(GL_ALPHA_TEST);
255 glAlphaFunc(GL_GREATER, 1.0f / 255.0f);
256 glEnable(GL_BLEND); // Enable Blending
257 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // Type Of Blending To Use
259 glMatrixMode(GL_MODELVIEW);
262 glMultMatrixf(c3context_view_get(c3)->cam.mtx.n);
263 glTranslatef(-c3context_view_get(c3)->cam.eye.n[VX],
264 -c3context_view_get(c3)->cam.eye.n[VY],
265 -c3context_view_get(c3)->cam.eye.n[VZ]);
273 * Draw back FBO over the screen
275 glBindFramebuffer(GL_FRAMEBUFFER, 0);
276 dumpError("glBindFramebuffer 0");
278 glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
279 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
281 glDisable(GL_DEPTH_TEST);
282 glDisable(GL_LIGHTING);
283 glDisable(GL_ALPHA_TEST);
287 glMatrixMode(GL_PROJECTION); // Select projection matrix
288 glLoadIdentity(); // Start with an identity matrix
289 glOrtho(0, _w, 0, _h, 0, 10);
291 glTranslatef(0, -1 * _h, 0);
292 glMatrixMode(GL_MODELVIEW); // Select modelview matrix
293 glLoadIdentity(); // Start with an identity matrix
301 #if !defined(GLUT_WHEEL_UP)
302 # define GLUT_WHEEL_UP 3
303 # define GLUT_WHEEL_DOWN 4
317 button = s == GLUT_DOWN ? b : 0;
318 move = c3vec2f(x, y);
319 c3context_view_p view = c3context_view_get_at(c3, 0);
320 // printf("button %d: %.1f,%.1f\n", b, move.x, move.y);
322 case GLUT_LEFT_BUTTON:
323 case GLUT_RIGHT_BUTTON: // call motion
326 case GLUT_WHEEL_DOWN:
327 if (view->cam.distance > 10) {
328 const float d = 0.004;
329 c3cam_set_distance(&view->cam,
330 view->cam.distance * ((b == GLUT_WHEEL_DOWN) ? (1.0+d) : (1.0-d)));
331 c3cam_update_matrix(&view->cam);
332 view->dirty = 1; // resort the array
343 c3vec2 m = c3vec2f(x, y);
344 c3vec2 delta = c3vec2_sub(move, m);
345 c3context_view_p view = c3context_view_get_at(c3, 0);
347 // printf("%s b%d click %.1f,%.1f now %d,%d delta %.1f,%.1f\n",
348 // __func__, button, move.n[0], move.n[1], x, y, delta.x, delta.y);
351 case GLUT_LEFT_BUTTON: {
352 c3mat4 rotx = rotation3D(view->cam.side, delta.n[1] / 4);
353 c3mat4 roty = rotation3D(c3vec3f(0.0, 0.0, 1.0), delta.n[0] / 4);
354 rotx = c3mat4_mul(&rotx, &roty);
355 c3cam_rot_about_lookat(&view->cam, &rotx);
356 c3cam_update_matrix(&view->cam);
358 view->dirty = 1; // resort the array
360 case GLUT_RIGHT_BUTTON: {
361 // offset both points, but following the plane
362 c3vec3 f = c3vec3_mulf(
363 c3vec3f(-view->cam.side.y, view->cam.side.x, 0),
365 view->cam.eye = c3vec3_add(view->cam.eye, f);
366 view->cam.lookat = c3vec3_add(view->cam.lookat, f);
367 c3cam_movef(&view->cam, delta.n[0] / 8, 0, 0);
368 c3cam_update_matrix(&view->cam);
370 view->dirty = 1; // resort the array
376 // gl timer. if the lcd is dirty, refresh display
381 glutTimerFunc(1000 / 24, _gl_timer_cb, 0);
385 const c3driver_context_t * c3_driver_list[3] = { NULL, NULL };
392 glutInit(&argc, argv); /* initialize GLUT system */
394 glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH | GLUT_ALPHA);
395 glutInitWindowSize(_w, _h); /* width=400pixels height=500pixels */
396 /*window =*/ glutCreateWindow("Press 'q' to quit"); /* create window */
398 glutDisplayFunc(_gl_display_cb); /* set window's display callback */
399 glutKeyboardFunc(_gl_key_cb); /* set window's key callback */
400 glutTimerFunc(1000 / 24, _gl_timer_cb, 0);
402 glutMouseFunc(_gl_button_cb);
403 glutMotionFunc(_gl_motion_cb);
404 glutReshapeFunc(_gl_reshape_cb);
406 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
407 glHint(GL_GENERATE_MIPMAP_HINT, GL_NICEST);
409 glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
410 glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
411 glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
412 glEnable(GL_LINE_SMOOTH);
414 // enable color tracking
415 glEnable(GL_COLOR_MATERIAL);
416 // set material properties which will be assigned by glColor
417 glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
419 /* setup some lights */
420 glShadeModel(GL_SMOOTH);
421 glEnable(GL_LIGHTING);
422 GLfloat global_ambient[] = { 0.5f, 0.5f, 0.5f, 1.0f };
423 glLightModelfv(GL_LIGHT_MODEL_AMBIENT, global_ambient);
426 GLfloat specular[] = {1.0f, 1.0f, 1.0f , 0.8f};
427 GLfloat position[] = { -30.0f, -30.0f, 200.0f, 1.0f };
428 glLightfv(GL_LIGHT0, GL_SPECULAR, specular);
429 glLightfv(GL_LIGHT0, GL_POSITION, position);
433 GLfloat specular[] = {1.0f, 1.0f, 1.0f , 0.8f};
434 GLfloat position[] = { 250.0f, -50.0f, 100.0f, 1.0f };
435 glLightfv(GL_LIGHT0, GL_SPECULAR, specular);
436 glLightfv(GL_LIGHT0, GL_POSITION, position);
441 * Extract the GLSL version as a nuneric value for later
443 const char * glsl = (const char *)glGetString(GL_SHADING_LANGUAGE_VERSION);
446 if (sscanf(glsl, "%d.%d", &M, &m) == 2)
447 glsl_version = (M * 100) + m;
450 printf("GL_SHADING_LANGUAGE_VERSION %s = %d\n", glsl, glsl_version);
452 gl_offscreenInit(_w, _h);
454 c3_driver_list[0] = c3gl_getdriver();
456 c3 = c3context_new(_w, _h);
457 c3->driver = c3_driver_list;
459 c3cam_p cam = &c3context_view_get_at(c3, 0)->cam;
460 cam->lookat = c3vec3f(100.0, 100.0, 0.0);
461 cam->eye = c3vec3f(100.0, -100.0, 100.0);
464 const char *path = "gfx/hb.png";
465 cairo_surface_t * image = cairo_image_surface_create_from_png (path);
466 printf("image = %p %p\n", image, cairo_image_surface_get_data (image));
467 c3texture_p b = c3texture_new(c3->root);
469 c3pixels_p dst = c3pixels_new(
470 cairo_image_surface_get_width (image),
471 cairo_image_surface_get_height (image),
472 4, cairo_image_surface_get_stride(image),
473 cairo_image_surface_get_data (image));
474 dst->name = str_new(path);
475 b->geometry.mat.texture = dst;
476 b->size = c3vec2f(200, 200);
477 b->geometry.mat.color = c3vec4f(1.0, 1.0, 1.0, 1.0);
478 // c3transform_new(head);
480 c3pixels_p line_aa_tex = NULL;
482 const char *path = "gfx/BlurryCircle.png";
483 cairo_surface_t * image = cairo_image_surface_create_from_png (path);
484 printf("image = %p %p\n", image, cairo_image_surface_get_data (image));
487 c3pixels_p dst = &b->pixels;
489 cairo_image_surface_get_width (image),
490 cairo_image_surface_get_height (image),
491 1, cairo_image_surface_get_width (image),
494 b->size = c3vec2f(32, 32);
497 c3pixels_p src = c3pixels_new(
498 cairo_image_surface_get_width (image),
499 cairo_image_surface_get_height (image),
500 4, cairo_image_surface_get_stride(image),
501 cairo_image_surface_get_data (image));
503 uint32_t * _s = (uint32_t *)src->base;
504 uint8_t * _d = (uint8_t *)dst->base;
506 for (int i = 0; i < dst->h * dst->w; i++)
507 if ((_s[i] & 0xff) > max)
509 for (int i = 0; i < dst->h * dst->w; i++)
510 *_d++ = ((_s[i] & 0xff) * 255) / max;// + (0xff - max);
511 b->pixels.format = C3PIXEL_A;
513 c3pixels_p dst = c3pixels_new(
514 cairo_image_surface_get_width (image),
515 cairo_image_surface_get_height (image),
516 4, cairo_image_surface_get_stride(image),
517 cairo_image_surface_get_data (image));
518 dst->format = C3PIXEL_ARGB;
520 dst->name = str_new(path);
521 uint8_t * line = dst->base;
522 for (int y = 0; y < dst->h; y++, line += dst->row) {
523 uint32_t *p = (uint32_t *)line;
524 for (int x = 0; x < dst->w; x++, p++) {
526 *p = ((0xff - b) << 24);//|(b << 16)|(b << 8)|(b);
533 printf("struct { int w, h, stride, size, format; uint8_t pix[] } img = {\n"
534 "%d, %d, %d, %d, %d\n",
535 p->w, p->h, (int)p->row, p->psize, cairo_image_surface_get_format(image));
536 for (int i = 0; i < 32; i++)
537 printf("0x%08x ", ((uint32_t*)p->base)[i]);
541 c3object_p grid = c3object_new(c3->root);
543 for (int x = 0; x <= 20; x++) {
544 for (int y = 0; y <= 20; y++) {
546 c3vec3f(-1+x*10,y*10,0.01), c3vec3f(1+x*10,y*10,0.01),
547 c3vec3f(x*10,-1+y*10,0.02), c3vec3f(x*10,1+y*10,0.02),
549 c3geometry_p g = c3geometry_new(
550 c3geometry_type(C3_LINES_TYPE, 0), grid);
551 g->mat.color = c3vec4f(0.0, 0.0, 0.0, 0.8);
552 g->mat.texture = line_aa_tex;
553 c3lines_init(g, p, 4, 0.2);
558 c3geometry_p g = c3sphere_uv(c3->root, c3vec3f(-30.0f, -20.0f, 200.0f), 3, 10, 10);
559 g->mat.color = c3vec4f(1.0, 1.0, 0.0, 1.0);
564 c3vec3f(-5,-5,1), c3vec3f(205,-5,1),
566 c3geometry_p g = c3geometry_new(
567 c3geometry_type(C3_LINES_TYPE, 0), grid);
568 g->mat.color = c3vec4f(0.0, 0.0, 0.0, 1.0);
569 g->mat.texture = line_aa_tex;
572 c3vertex_array_insert(&g->vertice,
573 g->vertice.count, p, 2);
576 head = c3stl_load("gfx/buserror-nozzle-model.stl", c3->root);
577 //head = c3object_new(c3->root);
578 c3transform_new(head);
579 if (head->geometry.count > 0) {
580 c3geometry_factor(head->geometry.e[0], 0.1, (20 * M_PI) / 180.0);
581 head->geometry.e[0]->mat.color = c3vec4f(0.6, 0.5, 0.0, 1.0);
585 c3texture_p b = c3texture_new(head);
586 c3pixels_init(&b->pixels, 64, 64, 4, 4 * 64, NULL);
587 b->geometry.dirty = 1;
588 memset(b->pixels.base, 0xff, 10 * b->pixels.row);
592 hud = c3context_new(_w, _h);
593 hud->driver = c3_driver_list;
596 * This is the offscreen framebuffer where the 3D scene is drawn
600 * need to insert a header since there is nothing to detect the version number
601 * reliably without it, and __VERSION__ returns idiocy
604 sprintf(head, "#version %d\n#define GLSL_VERSION %d\n", glsl_version, glsl_version);
606 fxaa = c3program_new("fxaa");
607 c3program_array_add(&hud->programs, fxaa);
608 c3program_load_shader(fxaa, GL_VERTEX_SHADER, head,
609 "gfx/postproc.vs", C3_PROGRAM_LOAD_UNIFORM);
610 c3program_load_shader(fxaa, GL_FRAGMENT_SHADER, head,
611 "gfx/postproc.fs", C3_PROGRAM_LOAD_UNIFORM);
613 c3texture_p b = c3texture_new(hud->root);
615 c3pixels_p dst = c3pixels_new(_w, _h, 4, _w * 4, NULL);
616 dst->name = str_new("fbo");
617 dst->texture = (c3apiobject_t)fbo_texture;
621 b->geometry.mat.texture = dst;
622 b->geometry.mat.program = fxaa;
623 b->size = c3vec2f(_w, _h);
624 b->geometry.mat.color = c3vec4f(1.0, 1.0, 1.0, 1.0);
630 c3vec3f(10,10,0), c3vec3f(800-10,10,0),
632 c3geometry_p g = c3geometry_new(
633 c3geometry_type(C3_LINES_TYPE, 0), hud->root);
634 g->mat.color = c3vec4f(0.5, 0.5, 1.0, .3f);
635 g->mat.texture = line_aa_tex;
636 c3lines_init(g, p, 2, 10);
644 c3context_dispose(c3);