misc: Fixes clang warnings
[simavr] / examples / board_reprap / src / reprap_gl.c
1 /*
2         reprap_gl.c
3
4         Copyright 2008-2012 Michel Pollet <buserror@gmail.com>
5
6         This file is part of simavr.
7
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.
12
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.
17
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/>.
20  */
21
22 #if __APPLE__
23 #include <GLUT/glut.h>
24 #else
25 #include <GL/glut.h>
26 #endif
27
28 #include <stdio.h>
29 #include <math.h>
30
31 #include "reprap.h"
32 #include "reprap_gl.h"
33
34 #include "c3/c3.h"
35 #include "c3/c3camera.h"
36 #include "c3/c3arcball.h"
37 #include "c3/c3driver_context.h"
38 #include "c3/c3stl.h"
39
40 int _w = 800, _h = 600;
41 c3cam cam;
42 c3arcball arcball;
43 c3context_p c3;
44 c3object_p head;
45
46 extern reprap_t reprap;
47
48 static int dumpError(const char * what)
49 {
50         GLenum e;
51         int count = 0;
52         while ((e = glGetError()) != GL_NO_ERROR) {
53                 printf("%s: %s\n", what, gluErrorString(e));
54                 count++;
55         }
56         return count;
57 }
58
59 static void
60 _gl_key_cb(
61                 unsigned char key,
62                 int x,
63                 int y)  /* called on key press */
64 {
65         switch (key) {
66                 case 'q':
67                 //      avr_vcd_stop(&vcd_file);
68                         c3context_dispose(c3);
69                         exit(0);
70                         break;
71                 case 'r':
72                         printf("Starting VCD trace; press 's' to stop\n");
73                 //      avr_vcd_start(&vcd_file);
74                         break;
75                 case 's':
76                         printf("Stopping VCD trace\n");
77                 //      avr_vcd_stop(&vcd_file);
78                         break;
79         }
80 }
81
82 static void
83 _c3_geometry_prepare(
84                 c3context_p c,
85                 const struct c3driver_context_t *d,
86                 c3geometry_p g)
87 {
88         switch(g->type.type) {
89                 case C3_TRIANGLE_TYPE: {
90                         g->type.subtype = GL_TRIANGLES;
91                         //g->mat.color = c3vec4f(0.0, 0.0, 1.0, 1.0);
92                 }       break;
93                 case C3_TEXTURE_TYPE: {
94                         c3texture_p t = (c3texture_p)g;
95                         g->type.subtype = GL_TRIANGLE_FAN;
96                         g->mat.color = c3vec4f(0.0, 1.0, 0.0, 0.5);
97                         printf("_c3_geometry_prepare xrure %d!\n", g->textures.count);
98                         if (!g->texture) {
99                                 GLuint texID = 0;
100                                 dumpError("cp_gl_texture_load_argb flush");
101
102                                 glEnable(GL_TEXTURE_RECTANGLE_ARB);
103                                 dumpError("cp_gl_texture_load_argb GL_TEXTURE_RECTANGLE_ARB");
104
105                                 glGenTextures(1, &texID);
106                                 dumpError("cp_gl_texture_load_argb glBindTexture GL_TEXTURE_RECTANGLE_ARB");
107
108                                 glPixelStorei(GL_UNPACK_ROW_LENGTH, t->pixels.row / 4);
109                                 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
110                                 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
111                                 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
112                                 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
113
114                                 g->mat.texture = texID;
115                                 g->texture = 1;
116                         }
117                         glBindTexture(GL_TEXTURE_RECTANGLE_ARB, g->mat.texture);
118                         glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8,
119                                         t->pixels.w, t->pixels.h, 0,
120                                         GL_RGBA, GL_UNSIGNED_BYTE,
121                                         t->pixels.base);
122                 }       break;
123                 default:
124                     break;
125         }
126 }
127
128 static void
129 _c3_geometry_draw(
130                 c3context_p c,
131                 const struct c3driver_context_t *d,
132                 c3geometry_p g )
133 {
134         glColor4fv(g->mat.color.n);
135 //      glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, g->mat.color.n);
136         glVertexPointer(3, GL_FLOAT, 0,
137                         g->projected.count ? g->projected.e : g->vertice.e);
138         glEnableClientState(GL_VERTEX_ARRAY);
139         if (g->textures.count && g->texture) {
140                 glDisable(GL_TEXTURE_2D);
141                 glEnable(GL_TEXTURE_RECTANGLE_ARB);
142                 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, g->mat.texture);
143                 glTexCoordPointer(2, GL_FLOAT, 0,
144                                 g->textures.e);
145                 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
146         } else
147                 glDisable(GL_TEXTURE_RECTANGLE_ARB);
148         if (g->normals.count) {
149                 glNormalPointer(GL_FLOAT, 0,
150                                 g->normals.e);
151                 glEnableClientState(GL_NORMAL_ARRAY);
152         }
153         glDrawArrays(g->type.subtype, 0, g->vertice.count);
154         glDisableClientState(GL_VERTEX_ARRAY);
155         glDisableClientState(GL_TEXTURE_COORD_ARRAY);
156         glDisableClientState(GL_NORMAL_ARRAY);
157 }
158
159 const c3driver_context_t c3context_driver = {
160                 .geometry_prepare = _c3_geometry_prepare,
161                 .geometry_draw = _c3_geometry_draw,
162 };
163
164 /*
165  * Computes the distance from the eye, sort by this value
166  */
167 static int
168 _c3_z_sorter(
169                 const void *_p1,
170                 const void *_p2)
171 {
172         c3geometry_p g1 = *(c3geometry_p*)_p1;
173         c3geometry_p g2 = *(c3geometry_p*)_p2;
174         // get center of bboxes
175         c3vec3 c1 = c3vec3_add(g1->bbox.min, c3vec3_divf(c3vec3_sub(g1->bbox.max, g1->bbox.min), 2));
176         c3vec3 c2 = c3vec3_add(g2->bbox.min, c3vec3_divf(c3vec3_sub(g2->bbox.max, g2->bbox.min), 2));
177
178         c3f d1 = c3vec3_length2(c3vec3_sub(c1, cam.eye));
179         c3f d2 = c3vec3_length2(c3vec3_sub(c2, cam.eye));
180
181         /*
182          * make sure transparent items are drawn after everyone else
183          */
184         if (g1->mat.color.n[3] < 1)
185                 d1 -= 100000.0;
186         if (g2->mat.color.n[3] < 1)
187                 d2 -= 100000.0;
188
189         return d1 < d2 ? 1 : d1 > d2 ? -1 : 0;
190 }
191
192 static void
193 _gl_display_cb(void)            /* function called whenever redisplay needed */
194 {
195         glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
196         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
197
198         // Set up projection matrix
199         glMatrixMode(GL_PROJECTION); // Select projection matrix
200         glLoadIdentity(); // Start with an identity matrix
201
202         gluPerspective(60, _w / _h, 60, 400);
203
204 //      glDepthMask(GL_TRUE);
205 //      glCullFace(GL_BACK);
206 //      glEnable(GL_CULL_FACE);
207         glEnable(GL_DEPTH_TEST);
208
209         glEnable(GL_BLEND);                         // Enable Blending
210         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);          // Type Of Blending To Use
211
212     glMatrixMode( GL_MODELVIEW );
213     glLoadIdentity();
214    // glMultMatrixf(arcball.rot.n);
215     glMultMatrixf(cam.mtx.n);
216     glTranslatef( -cam.eye.n[VX], -cam.eye.n[VY], -cam.eye.n[VZ] );
217   //  glMultMatrixf(arcball.rot.n);
218
219         c3vec3 headp = c3vec3f(
220                         stepper_get_position_mm(&reprap.step_x),
221                         stepper_get_position_mm(&reprap.step_y),
222                         stepper_get_position_mm(&reprap.step_z));
223         c3mat4 headmove = translation3D(headp);
224         c3transform_set(head->transform.e[0], &headmove);
225
226         if (c3->root->dirty) {
227         //      printf("reproject\n");
228                 c3context_prepare(c3);
229
230                 qsort(c3->projected.e, c3->projected.count,
231                                 sizeof(c3->projected.e[0]), _c3_z_sorter);
232         }
233         c3context_draw(c3);
234
235         glMatrixMode(GL_PROJECTION); // Select projection matrix
236         glLoadIdentity(); // Start with an identity matrix
237         glOrtho(0, _w, 0, _h, 0, 10);
238         glScalef(1,-1,1);
239         glTranslatef(0, -1 * _h, 0);
240
241         glMatrixMode(GL_MODELVIEW); // Select modelview matrix
242
243     glutSwapBuffers();
244 }
245
246 int button;
247 c3vec2 move;
248 c3cam startcam;
249
250 static
251 void _gl_button_cb(
252                 int b,
253                 int s,
254                 int x,
255                 int y)
256 {
257         button = s == GLUT_DOWN ? b : 0;
258         startcam = cam;
259         move = c3vec2f(x, y);
260         if (s == GLUT_DOWN)
261                 c3arcball_mouse_down(&arcball, x, y);
262         else
263                 c3arcball_mouse_up(&arcball);
264 }
265
266 void
267 _gl_motion_cb(
268                 int x,
269                 int y)
270 {
271         c3vec2 m = c3vec2f(x, y);
272         c3vec2 delta = c3vec2_sub(move, m);
273
274 //      printf("%s b%d click %.1f,%.1f now %d,%d\n",
275 //                      __func__, button, move.n[0], move.n[1], x, y);
276
277         switch (button) {
278                 case GLUT_LEFT_BUTTON: {
279
280                 //      c3cam_eye_yaw(&cam, delta.n[0] / 4);
281                 //      c3cam_eye_pitch(&cam, delta.n[1] / 4);
282
283                         c3mat4 rotx = rotation3D(c3vec3f(1.0, 0, 0), delta.n[1] / 4);
284                         c3mat4 roty = rotation3D(c3vec3f(0.0, 0.0, 1.0), delta.n[0] / 4);
285                         rotx = c3mat4_mul(&rotx, &roty);
286                         c3cam_rot_about_lookat(&cam, &rotx);
287
288                     c3cam_update_matrix(&cam);
289                     c3->root->dirty = 1;        // resort the array
290 //                  c3arcball_mouse_motion(&arcball, x, y, 0,0,0);
291                 }       break;
292                 case GLUT_RIGHT_BUTTON: {
293
294                 }       break;
295         }
296         move = m;
297 }
298
299 // gl timer. if the lcd is dirty, refresh display
300 static void
301 _gl_timer_cb(
302                 int i)
303 {
304         //static int oldstate = -1;
305         // restart timer
306         c3arcball_idle(&arcball);
307         glutTimerFunc(1000 / 24, _gl_timer_cb, 0);
308         glutPostRedisplay();
309 }
310
311 int
312 gl_init(
313                 int argc,
314                 char *argv[] )
315 {
316         glutInit(&argc, argv);          /* initialize GLUT system */
317
318         glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
319         glutInitWindowSize(_w, _h);             /* width=400pixels height=500pixels */
320         /*window =*/ glutCreateWindow("Press 'q' to quit");     /* create window */
321
322         glutDisplayFunc(_gl_display_cb);                /* set window's display callback */
323         glutKeyboardFunc(_gl_key_cb);           /* set window's key callback */
324         glutTimerFunc(1000 / 24, _gl_timer_cb, 0);
325
326         glutMouseFunc(_gl_button_cb);
327         glutMotionFunc(_gl_motion_cb);
328
329         glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
330         glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
331         glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
332         glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
333
334         glEnable(GL_LINE_SMOOTH);
335
336         // enable color tracking
337         glEnable(GL_COLOR_MATERIAL);
338         // set material properties which will be assigned by glColor
339         glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
340
341
342         glShadeModel(GL_SMOOTH);
343 #if 1
344 //      glEnable(GL_DEPTH_TEST);
345         glEnable(GL_LIGHTING);
346         GLfloat global_ambient[] = { 0.5f, 0.5f, 0.5f, 1.0f };
347         glLightModelfv(GL_LIGHT_MODEL_AMBIENT, global_ambient);
348
349         {
350                 GLfloat specular[] = {1.0f, 1.0f, 1.0f , 0.8f};
351                 GLfloat position[] = { -50.0f, -50.0f, 100.0f, 1.0f };
352                 glLightfv(GL_LIGHT0, GL_SPECULAR, specular);
353                 glLightfv(GL_LIGHT0, GL_POSITION, position);
354                 glEnable(GL_LIGHT0);
355         }
356         {
357                 GLfloat specular[] = {1.0f, 1.0f, 1.0f , 0.8f};
358                 GLfloat position[] = { 250.0f, -50.0f, 100.0f, 1.0f };
359                 glLightfv(GL_LIGHT0, GL_SPECULAR, specular);
360                 glLightfv(GL_LIGHT0, GL_POSITION, position);
361                 glEnable(GL_LIGHT0);
362         }
363 #endif
364 //      glEnable(GL_BLEND);
365         // Works for the UI !!
366 //      glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
367
368         cam = c3cam_new();
369         cam.lookat = c3vec3f(100.0, 100.0, 0.0);
370     cam.eye = c3vec3f(100.0, -100.0, 100.0);
371     c3cam_update_matrix(&cam);
372
373     c3arcball_init_center(&arcball, c3vec2f(_w/2, _h/2), 100);
374 //      hd44780_gl_init();
375
376     c3 = c3context_new(_w, _h);
377     static const c3driver_context_t * list[] = { &c3context_driver, NULL };
378     c3->driver = list;
379
380     c3object_p grid = c3object_new(c3->root);
381     {
382         for (int x = 0; x < 20; x++) {
383                 for (int y = 0; y < 20; y++) {
384                         c3vec3 p[4] = {
385                                 c3vec3f(-1+x*10,y*10,0), c3vec3f(1+x*10,y*10,0),
386                                 c3vec3f(x*10,-1+y*10,0), c3vec3f(x*10,1+y*10,0),
387                         };
388                 c3geometry_p g = c3geometry_new(
389                                 c3geometry_type(C3_RAW_TYPE, GL_LINES), grid);
390                 g->mat.color = c3vec4f(0.0, 0.0, 0.0, 1.0);
391                         c3vertex_array_insert(&g->vertice,
392                                         g->vertice.count, p, 4);
393                 }
394         }
395     }
396     head = c3stl_load("gfx/buserror-nozzle-model.stl", c3->root);
397     //head = c3object_new(c3->root);
398     c3transform_new(head);
399     if (head->geometry.count > 0) {
400         head->geometry.e[0]->mat.color = c3vec4f(0.6, 0.5, 0.0, 1.0);
401     }
402
403 #if 0
404     c3texture_p b = c3texture_new(head);
405     c3pixels_init(&b->pixels, 64, 64, 4, 4 * 64, NULL);
406     b->geometry.dirty = 1;
407     memset(b->pixels.base, 0xff, 10 * b->pixels.row);
408 #endif
409
410         return 1;
411 }
412
413 void
414 gl_dispose()
415 {
416         c3context_dispose(c3);
417 }
418
419 int
420 gl_runloop()
421 {
422         glutMainLoop();
423         gl_dispose();
424         return 0;
425 }