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"
47 #include "c3program.h"
51 #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
63 c3program_p scene = NULL;
69 uniform_ShadowMap = 0,
74 const char *uniforms_scene[] = {
82 int glsl_version = 110;
84 extern reprap_t reprap;
86 static int dumpError(const char * what)
90 while ((e = glGetError()) != GL_NO_ERROR) {
91 printf("%s: %s\n", what, gluErrorString(e));
97 #define GLCHECK(_w) {_w; dumpError(#_w);}
101 _gl_reshape_cb(int w, int h)
106 c3vec2 size = c3vec2f(_w, _h);
108 glBindFramebuffer(GL_FRAMEBUFFER, 0);
109 glViewport(0, 0, _w, _h);
110 c3gl_fbo_resize(&fbo, size);
111 c3texture_resize(fbo_c3, size);
112 c3context_view_get_at(c3, 0)->size = size;
115 glUseProgram((GLuint)fxaa->pid);
116 GLCHECK(glUniform2fv((GLuint)fxaa->params.e[0].pid, 1, size.n));
127 int y) /* called on key press */
131 // avr_vcd_stop(&vcd_file);
132 c3context_dispose(c3);
136 printf("Starting VCD trace; press 's' to stop\n");
137 // avr_vcd_start(&vcd_file);
140 printf("Stopping VCD trace\n");
141 // avr_vcd_stop(&vcd_file);
144 if (fbo_c3->geometry.mat.program)
145 fbo_c3->geometry.mat.program = NULL;
147 fbo_c3->geometry.mat.program = fxaa;
154 _gl_display_cb(void) /* function called whenever redisplay needed */
156 int drawIndexes[] = { 1, 0 };
157 int drawViewStart = c3->root->dirty ? 0 : 1;
159 c3vec3 headp = c3vec3f(
160 stepper_get_position_mm(&reprap.step_x),
161 stepper_get_position_mm(&reprap.step_y),
162 stepper_get_position_mm(&reprap.step_z));
163 c3mat4 headmove = translation3D(headp);
164 c3transform_set(head->transform.e[0], &headmove);
166 for (int vi = drawViewStart; vi < 2; vi++) {
167 c3context_view_set(c3, drawIndexes[vi]);
172 c3context_view_p view = c3context_view_get(c3);
173 glBindFramebuffer(GL_FRAMEBUFFER, (GLuint)view->bid);
174 // draw (without glutSwapBuffers)
175 dumpError("glBindFramebuffer fbo");
176 glViewport(0, 0, view->size.x, view->size.y);
178 c3context_project(c3);
180 glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
181 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
183 // Set up projection matrix
184 glMatrixMode(GL_PROJECTION); // Select projection matrix
185 glLoadMatrixf(view->projection.n);
187 glEnable(GL_CULL_FACE);
188 glDepthMask(GL_TRUE);
189 glDepthFunc(GL_LEQUAL);
190 glEnable(GL_DEPTH_TEST);
191 // glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
193 //glEnable(GL_ALPHA_TEST);
194 //glAlphaFunc(GL_GREATER, 1.0f / 255.0f);
195 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // Type Of Blending To Use
197 glMatrixMode(GL_MODELVIEW);
200 if (view->type == C3_CONTEXT_VIEW_EYE) {
201 // glShadeModel(GL_SMOOTH);
202 // glEnable(GL_LIGHTING);
204 glEnable(GL_BLEND); // Enable Blending
206 c3context_view_p light = c3context_view_get_at(c3, 1);
208 // This is matrix transform every coordinate x,y,z
212 // Moving from unit cube [-1,1] to [0,1]
213 const c3f bias[16] = {
219 c3mat4 b = c3mat4_mul(&light->projection, (c3mat4p)bias);
220 c3mat4 tex = c3mat4_mul(&light->cam.mtx, &b);
222 GLCHECK(glUseProgram((GLuint)scene->pid));
224 (GLuint)scene->params.e[uniform_shadowMatrix].pid,
227 glCullFace(GL_FRONT);
228 glShadeModel(GL_FLAT);
229 glDisable(GL_LIGHTING);
230 glDisable(GL_BLEND); // Disable Blending
237 * Draw back FBO over the screen
239 glBindFramebuffer(GL_FRAMEBUFFER, 0);
240 dumpError("glBindFramebuffer 0");
241 glViewport(0, 0, _w, _h);
243 glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
244 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
246 glDisable(GL_DEPTH_TEST);
247 glDisable(GL_LIGHTING);
248 glDisable(GL_ALPHA_TEST);
249 glDisable(GL_CULL_FACE);
253 glMatrixMode(GL_PROJECTION); // Select projection matrix
254 glLoadIdentity(); // Start with an identity matrix
256 c3mat4 pro = screen_ortho3D(0, _w, 0, _h, 0, 10);
257 glLoadMatrixf(pro.n);
259 glMatrixMode(GL_MODELVIEW); // Select modelview matrix
261 if (hud->root->dirty) {
262 // printf("reproject head %.2f,%.2f,%.2f\n", headp.x, headp.y,headp.z);
263 c3context_project(hud);
270 #if !defined(GLUT_WHEEL_UP)
271 # define GLUT_WHEEL_UP 3
272 # define GLUT_WHEEL_DOWN 4
286 button = s == GLUT_DOWN ? b : 0;
287 move = c3vec2f(x, y);
288 c3context_view_p view = c3context_view_get_at(c3, 0);
289 // printf("button %d: %.1f,%.1f\n", b, move.x, move.y);
291 case GLUT_LEFT_BUTTON:
292 case GLUT_RIGHT_BUTTON: // call motion
295 case GLUT_WHEEL_DOWN:
296 if (view->cam.distance > 10) {
297 const float d = 0.004;
298 c3cam_set_distance(&view->cam,
299 view->cam.distance * ((b == GLUT_WHEEL_DOWN) ? (1.0+d) : (1.0-d)));
300 c3cam_update_matrix(&view->cam);
301 view->dirty = 1; // resort the array
312 c3vec2 m = c3vec2f(x, y);
313 c3vec2 delta = c3vec2_sub(move, m);
314 c3context_view_p view = c3context_view_get_at(c3, 0);
316 // printf("%s b%d click %.1f,%.1f now %d,%d delta %.1f,%.1f\n",
317 // __func__, button, move.n[0], move.n[1], x, y, delta.x, delta.y);
320 case GLUT_LEFT_BUTTON: {
321 c3mat4 rotx = rotation3D(view->cam.side, delta.n[1] / 4);
322 c3mat4 roty = rotation3D(c3vec3f(0.0, 0.0, 1.0), delta.n[0] / 4);
323 rotx = c3mat4_mul(&rotx, &roty);
324 c3cam_rot_about_lookat(&view->cam, &rotx);
325 c3cam_update_matrix(&view->cam);
327 view->dirty = 1; // resort the array
329 case GLUT_RIGHT_BUTTON: {
330 // offset both points, but following the plane
331 c3vec3 f = c3vec3_mulf(
332 c3vec3f(-view->cam.side.y, view->cam.side.x, 0),
334 view->cam.eye = c3vec3_add(view->cam.eye, f);
335 view->cam.lookat = c3vec3_add(view->cam.lookat, f);
336 c3cam_movef(&view->cam, delta.n[0] / 8, 0, 0);
337 c3cam_update_matrix(&view->cam);
339 view->dirty = 1; // resort the array
345 // gl timer. if the lcd is dirty, refresh display
350 glutTimerFunc(1000 / 24, _gl_timer_cb, 0);
354 const c3driver_context_t * c3_driver_list[3] = { NULL, NULL };
361 glutInit(&argc, argv); /* initialize GLUT system */
363 glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH | GLUT_ALPHA);
364 glutInitWindowSize(_w, _h); /* width=400pixels height=500pixels */
365 /*window =*/ glutCreateWindow("Press 'q' to quit"); /* create window */
367 glutDisplayFunc(_gl_display_cb); /* set window's display callback */
368 glutKeyboardFunc(_gl_key_cb); /* set window's key callback */
369 glutTimerFunc(1000 / 24, _gl_timer_cb, 0);
371 glutMouseFunc(_gl_button_cb);
372 glutMotionFunc(_gl_motion_cb);
373 glutReshapeFunc(_gl_reshape_cb);
375 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
376 glHint(GL_GENERATE_MIPMAP_HINT, GL_NICEST);
378 // enable color tracking
379 glEnable(GL_COLOR_MATERIAL);
380 // set material properties which will be assigned by glColor
381 glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
383 /* setup some lights */
384 GLfloat global_ambient[] = { 0.5f, 0.5f, 0.5f, 1.0f };
385 glLightModelfv(GL_LIGHT_MODEL_AMBIENT, global_ambient);
388 GLfloat specular[] = {1.0f, 1.0f, 1.0f , 0.8f};
389 GLfloat position[] = { 250.0f, -50.0f, 100.0f, 1.0f };
390 glLightfv(GL_LIGHT1, GL_SPECULAR, specular);
391 glLightfv(GL_LIGHT1, GL_POSITION, position);
396 * Extract the GLSL version as a numeric value for later
398 const char * glsl = (const char *)glGetString(GL_SHADING_LANGUAGE_VERSION);
401 if (sscanf(glsl, "%d.%d", &M, &m) == 2)
402 glsl_version = (M * 100) + m;
405 printf("GL_SHADING_LANGUAGE_VERSION %s = %d\n", glsl, glsl_version);
407 c3gl_fbo_create(&fbo, c3vec2f(_w, _h), (1 << C3GL_FBO_COLOR)|(1 << C3GL_FBO_DEPTH));
410 c3_driver_list[0] = c3gl_getdriver();
412 c3 = c3context_new(_w, _h);
413 c3->driver = c3_driver_list;
415 c3cam_p cam = &c3context_view_get_at(c3, 0)->cam;
416 cam->lookat = c3vec3f(100.0, 100.0, 0.0);
417 cam->eye = c3vec3f(100.0, -100.0, 100.0);
418 // associate the framebuffer object with this view
419 c3context_view_get_at(c3, 0)->bid = fbo.fbo;
421 * Create a light, attach it to a movable object, and attach a sphere
422 * to it too so it's visible.
425 c3object_p ligthhook = c3object_new(c3->root);
426 c3transform_p pos = c3transform_new(ligthhook);
428 pos->matrix = translation3D(c3vec3f(-30.0f, -30.0f, 200.0f));
430 c3light_p light = c3light_new(ligthhook);
431 light->geometry.name = str_new("light0");
432 light->color.specular = c3vec4f(1.0f, 1.0f, 1.0f , 0.8f);
433 light->position = c3vec4f(0, 0, 0, 1.0f );
436 c3geometry_p g = c3sphere_uv(ligthhook, c3vec3f(0, 0, 0), 3, 10, 10);
437 g->mat.color = c3vec4f(1.0, 1.0, 0.0, 1.0);
438 g->hidden = 0; // hidden from light scenes
442 c3vec2 size = c3vec2f(1024, 1024);
443 c3gl_fbo_create(&shadow, size, (1 << C3GL_FBO_DEPTH_TEX));
445 c3context_view_t v = {
446 .type = C3_CONTEXT_VIEW_LIGHT,
449 .index = c3->views.count,
453 c3vec3 listpos = c3vec3f(-30.0f, -30.0f, 200.0f);
455 v.cam.lookat = c3vec3f(100.0, 100.0, 0.0);
456 c3context_view_array_add(&c3->views, v);
460 const char *path = "gfx/hb.png";
461 cairo_surface_t * image = cairo_image_surface_create_from_png (path);
462 printf("image = %p %p\n", image, cairo_image_surface_get_data (image));
463 c3texture_p b = c3texture_new(c3->root);
465 c3pixels_p dst = c3pixels_new(
466 cairo_image_surface_get_width (image),
467 cairo_image_surface_get_height (image),
468 4, cairo_image_surface_get_stride(image),
469 cairo_image_surface_get_data (image));
470 dst->name = str_new(path);
472 b->geometry.mat.texture = dst;
473 b->size = c3vec2f(200, 200);
474 b->geometry.mat.color = c3vec4f(1.0, 1.0, 1.0, 1.0);
475 // c3transform_new(head);
477 c3pixels_p brass_tex = NULL;
479 const char *path = "gfx/brass.png";
480 cairo_surface_t * image = cairo_image_surface_create_from_png (path);
481 printf("image = %p %p\n", image, cairo_image_surface_get_data (image));
483 c3pixels_p dst = c3pixels_new(
484 cairo_image_surface_get_width (image),
485 cairo_image_surface_get_height (image),
486 4, cairo_image_surface_get_stride(image),
487 cairo_image_surface_get_data (image));
488 dst->name = str_new(path);
490 c3pixels_array_add(&c3->pixels, dst);
491 // c3transform_new(head);
494 c3pixels_p line_aa_tex = NULL;
496 const char *path = "gfx/BlurryCircle.png";
497 cairo_surface_t * image = cairo_image_surface_create_from_png (path);
498 printf("image = %p %p\n", image, cairo_image_surface_get_data (image));
501 c3pixels_p dst = &b->pixels;
503 cairo_image_surface_get_width (image),
504 cairo_image_surface_get_height (image),
505 1, cairo_image_surface_get_width (image),
508 b->size = c3vec2f(32, 32);
511 c3pixels_p src = c3pixels_new(
512 cairo_image_surface_get_width (image),
513 cairo_image_surface_get_height (image),
514 4, cairo_image_surface_get_stride(image),
515 cairo_image_surface_get_data (image));
517 uint32_t * _s = (uint32_t *)src->base;
518 uint8_t * _d = (uint8_t *)dst->base;
520 for (int i = 0; i < dst->h * dst->w; i++)
521 if ((_s[i] & 0xff) > max)
523 for (int i = 0; i < dst->h * dst->w; i++)
524 *_d++ = ((_s[i] & 0xff) * 255) / max;// + (0xff - max);
525 b->pixels.format = C3PIXEL_A;
527 c3pixels_p dst = c3pixels_new(
528 cairo_image_surface_get_width (image),
529 cairo_image_surface_get_height (image),
530 4, cairo_image_surface_get_stride(image),
531 cairo_image_surface_get_data (image));
532 dst->format = C3PIXEL_ARGB;
534 dst->name = str_new(path);
535 uint8_t * line = dst->base;
536 for (int y = 0; y < dst->h; y++, line += dst->row) {
537 uint32_t *p = (uint32_t *)line;
538 for (int x = 0; x < dst->w; x++, p++) {
540 *p = ((0xff - b) << 24);//|(b << 16)|(b << 8)|(b);
547 printf("struct { int w, h, stride, size, format; uint8_t pix[] } img = {\n"
548 "%d, %d, %d, %d, %d\n",
549 p->w, p->h, (int)p->row, p->psize, cairo_image_surface_get_format(image));
550 for (int i = 0; i < 32; i++)
551 printf("0x%08x ", ((uint32_t*)p->base)[i]);
555 c3object_p grid = c3object_new(c3->root);
557 for (int x = 0; x <= 20; x++) {
558 for (int y = 0; y <= 20; y++) {
560 c3vec3f(-1+x*10,y*10,0.01), c3vec3f(1+x*10,y*10,0.01),
561 c3vec3f(x*10,-1+y*10,0.02), c3vec3f(x*10,1+y*10,0.02),
563 c3geometry_p g = c3geometry_new(
564 c3geometry_type(C3_LINES_TYPE, 0), grid);
565 g->mat.color = c3vec4f(0.0, 0.0, 0.0, 0.8);
566 g->mat.texture = line_aa_tex;
567 c3lines_init(g, p, 4, 0.2);
574 c3vec3f(-5,-5,1), c3vec3f(205,-5,1),
576 c3geometry_p g = c3geometry_new(
577 c3geometry_type(C3_LINES_TYPE, 0), grid);
578 g->mat.color = c3vec4f(0.0, 0.0, 0.0, 1.0);
579 g->mat.texture = line_aa_tex;
582 c3vertex_array_insert(&g->vertice,
583 g->vertice.count, p, 2);
586 head = c3stl_load("gfx/buserror-nozzle-model.stl", c3->root);
587 c3transform_new(head);
588 if (head->geometry.count > 0) {
589 c3geometry_factor(head->geometry.e[0], 0.1, (20 * M_PI) / 180.0);
590 head->geometry.e[0]->mat.color = c3vec4f(0.6, 0.5, 0.0, 1.0);
591 head->geometry.e[0]->mat.texture = brass_tex;
595 c3texture_p b = c3texture_new(head);
596 c3pixels_init(&b->pixels, 64, 64, 4, 4 * 64, NULL);
597 b->geometry.dirty = 1;
598 memset(b->pixels.base, 0xff, 10 * b->pixels.row);
602 hud = c3context_new(_w, _h);
603 hud->driver = c3_driver_list;
606 * This is the offscreen framebuffer where the 3D scene is drawn
610 * need to insert a header since there is nothing to detect the version number
611 * reliably without it, and __VERSION__ returns idiocy
614 sprintf(head, "#version %d\n#define GLSL_VERSION %d\n", glsl_version, glsl_version);
616 const char *uniforms[] = { "g_Resolution", NULL };
617 fxaa = c3program_new("fxaa", uniforms);
618 c3program_array_add(&hud->programs, fxaa);
619 c3program_load_shader(fxaa, GL_VERTEX_SHADER, head,
620 "gfx/postproc.vs", C3_PROGRAM_LOAD_UNIFORM);
621 c3program_load_shader(fxaa, GL_FRAGMENT_SHADER, head,
622 "gfx/postproc.fs", C3_PROGRAM_LOAD_UNIFORM);
624 c3texture_p b = c3texture_new(hud->root);
626 c3pixels_p dst = c3pixels_new(_w, _h, 4, _w * 4, NULL);
627 dst->name = str_new("fbo");
628 dst->texture = fbo.buffers[C3GL_FBO_COLOR].bid;
632 b->geometry.mat.texture = dst;
633 b->geometry.mat.program = fxaa;
634 b->size = c3vec2f(_w, _h);
635 b->geometry.mat.color = c3vec4f(1.0, 1.0, 1.0, 1.0);
641 * need to insert a header since there is nothing to detect the version number
642 * reliably without it, and __VERSION__ returns idiocy
645 sprintf(head, "#version %d\n#define GLSL_VERSION %d\n", glsl_version, glsl_version);
647 scene = c3program_new("scene", uniforms_scene);
649 c3program_array_add(&c3->programs, scene);
650 c3program_load_shader(scene, GL_VERTEX_SHADER, head,
651 "gfx/scene.vs", C3_PROGRAM_LOAD_UNIFORM);
652 c3program_load_shader(scene, GL_FRAGMENT_SHADER, head,
653 "gfx/scene.fs", C3_PROGRAM_LOAD_UNIFORM);
654 c3gl_program_load(scene);
656 GLCHECK(glUseProgram((GLuint)scene->pid));
658 (GLuint)scene->params.e[uniform_ShadowMap].pid, 7));
660 (GLuint)scene->params.e[uniform_tex0].pid, 0));
661 c3vec2 isize = c3vec2f(1.0f / c3->views.e[1].size.x,
662 1.0f / c3->views.e[1].size.y);
663 GLCHECK(glUniform2fv(
664 (GLuint)scene->params.e[uniform_pixelOffset].pid, 1,
666 glActiveTexture(GL_TEXTURE7);
667 GLCHECK(glBindTexture(GL_TEXTURE_2D,
668 (GLuint)shadow.buffers[C3GL_FBO_DEPTH_TEX].bid));
669 glActiveTexture(GL_TEXTURE0);
673 c3vec3f(10,10,0), c3vec3f(800-10,10,0),
675 c3geometry_p g = c3geometry_new(
676 c3geometry_type(C3_LINES_TYPE, 0), hud->root);
677 g->mat.color = c3vec4f(0.5, 0.5, 1.0, .3f);
678 g->mat.texture = line_aa_tex;
679 c3lines_init(g, p, 2, 10);
687 c3context_dispose(c3);
688 c3context_dispose(hud);
689 c3gl_fbo_dispose(&fbo);