source: project/release/5/ezxdisp/trunk/ezxdisp-x11.c @ 38155

Last change on this file since 38155 was 38155, checked in by Ivan Raikov, 6 months ago

C5 port of ezxdisp

File size: 27.7 KB
Line 
1/*
2 * x11/ezxdisp.c
3 * This file is part of the ezxdisp library.
4 */
5
6#include <stdio.h>
7#include <stdlib.h>
8#include <string.h>
9#include <errno.h>
10#include <stdarg.h>
11#include <assert.h>
12#include <math.h>
13#include <X11/Xlib.h>
14#include <X11/Xutil.h>
15#include <X11/keysym.h>
16
17#include "ezxdisp.h"
18
19struct ezx_s {
20  int size_x, size_y;
21  ezx_color_t bgcolor;
22  int closed;
23
24  Display     *display;
25  Window       top;
26  XFontStruct *fontst;
27  GC           gc;
28  Colormap     cmap;
29  XColor       black, white, rgb;
30  Pixmap       pixmap;
31  XSizeHints   size_hints;
32  Atom         wm_protocols, wm_delete_window;
33
34  int                 cur_layer;
35  struct ezx_figures *fig_head[EZX_NLAYER];
36  struct ezx_figures *fig_tail[EZX_NLAYER];
37
38  // 3d stuffs
39  double scrdist, mag;
40  double eye_x, eye_y, eye_z, eye_r;
41  double cmat[3][3];
42  double light_x, light_y, light_z;
43
44  struct color_table_s *color_table;
45};
46
47typedef struct ezx_figures {
48  enum {
49    FPOINT2D,
50    FLINE2D,
51    FLINES2D,
52    FLINE3D,
53    FPOLY2D,
54    FPOLY3D,
55    FSTR2D,
56    FSTR3D,
57    FRECT2D,
58    FFILLEDRECT2D,
59    FCIRCLE2D,
60    FFILLEDCIRCLE2D,
61    FFILLEDCIRCLE3D,
62    FARC2D,
63    FFILLEDARC2D,
64  } type;
65
66  int x0, y0, z0, x1, y1, z1, r;
67  double dx0, dy0, dz0, dx1, dy1, dz1, dr;
68  double angle1, angle2;
69  char *str;
70
71  int npoints;
72  ezx_point2d_t *points_2d;
73  ezx_point3d_t *points_3d;
74
75  ezx_color_t         col;
76  int                 width;
77  struct ezx_figures *next;
78} ezx_figures;
79
80typedef struct ezx_pfigures {
81  double               z;
82  struct ezx_figures  *fig;
83  struct ezx_pfigures *next;
84} ezx_pfigures;
85
86typedef struct color_table_entry_s {
87  unsigned short red, green, blue;
88  XColor *data;
89} color_table_entry_t;
90
91typedef struct color_table_s {
92  int size;
93  int maxsize;
94  struct color_table_entry_s *entry;
95} color_table_t;
96
97const ezx_color_t ezx_black  = {0, 0, 0};
98const ezx_color_t ezx_white  = {1, 1, 1};
99const ezx_color_t ezx_grey25 = {0.25, 0.25, 0.25};
100const ezx_color_t ezx_grey50 = {0.5, 0.5, 0.5};
101const ezx_color_t ezx_grey75 = {0.75, 0.75, 0.75};
102const ezx_color_t ezx_blue   = {0, 0, 1};
103const ezx_color_t ezx_red    = {1, 0, 0};
104const ezx_color_t ezx_green  = {0, 1, 0};
105const ezx_color_t ezx_yellow = {1, 1, 0};
106const ezx_color_t ezx_purple = {1, 0, 1};
107const ezx_color_t ezx_pink   = {1, 0.5, 0.5};
108const ezx_color_t ezx_cyan   = {0.5, 0.5, 1};
109const ezx_color_t ezx_brown  = {0.5, 0, 0};
110const ezx_color_t ezx_orange = {1, 0.5, 0};
111
112static const char * const fontname = "5x8";
113
114static void error_exit(const char *fmt, ...)
115{
116  va_list params;
117
118  fprintf(stderr, "ezxdisp: ");
119  va_start(params, fmt);
120  vfprintf(stderr, fmt, params);
121  va_end(params);
122  fprintf(stderr, "\n");
123  fflush(stderr);
124  exit(EXIT_FAILURE);
125}
126
127static void sys_error_exit(const char *fmt, ...)
128{
129  int errno_save = errno;
130  va_list params;
131
132  fprintf(stderr, "ezxdisp: ");
133  va_start(params, fmt);
134  vfprintf(stderr, fmt, params);
135  va_end(params);
136  fprintf(stderr, ": %s\n", strerror(errno_save));
137  fflush(stderr);
138  exit(EXIT_FAILURE);
139}
140
141static inline void *xmalloc(size_t n)
142{
143  void *p;
144
145  p = malloc(n);
146  if (!p) sys_error_exit("malloc failed");
147 
148  return p;
149}
150
151static inline void *xcalloc(size_t n, size_t s)
152{
153  void *p;
154
155  p = calloc(n, s);
156  if (!p) sys_error_exit("calloc failed");
157
158  return p;
159}
160
161static color_table_t *color_table_new()
162{
163  int i;
164  color_table_t *table;
165
166  table = xmalloc(sizeof(color_table_t));
167  table->size = 0;
168  table->maxsize = 8191;
169  //table->maxsize = 32749;
170  table->entry = xmalloc(sizeof(color_table_entry_t) * table->maxsize);
171  for (i = 0; i < table->maxsize; i++)
172    table->entry[i].data = NULL;
173
174  return table;
175}
176
177static int color_hash(unsigned short red, unsigned short green,
178                      unsigned short blue, int maxsize)
179{
180  long long hash = ((long long)red << 32) |
181    ((long long)green << 16) | ((long long)blue);
182  return hash % maxsize;
183}
184
185static void color_table_insert(color_table_t *table, unsigned short red,
186                               unsigned short green, unsigned short blue,
187                               Display *display, XColor *col)
188{
189  int i = color_hash(red, green, blue, table->maxsize);
190
191  if (table->size == table->maxsize) {
192    XFreeColors(display, DefaultColormap(display, DefaultScreen(display)),
193                &(table->entry[i].data->pixel), 1, 0);
194    free(table->entry[i].data);
195    table->entry[i].data = NULL;
196    table->size--;
197  }
198 
199  while (table->entry[i].data) i = (i+1) % table->maxsize;
200  table->entry[i].red = red;
201  table->entry[i].green = green;
202  table->entry[i].blue = blue;
203  table->entry[i].data = col;
204  table->size++;
205}
206
207static XColor *color_table_search(color_table_t *table, unsigned short red,
208                                  unsigned short green, unsigned short blue)
209{
210  int h, i;
211
212  h = i = color_hash(red, green, blue, table->maxsize);
213
214  while (table->entry[i].data) {
215    if (table->entry[i].red == red &&
216        table->entry[i].green == green &&
217        table->entry[i].blue == blue)
218      return table->entry[i].data;
219    else i = (i+1) % table->maxsize;
220   
221    if (h == i) break;
222  }
223
224  return NULL;
225}
226
227static void color_table_free(color_table_t *table)
228{
229  int i;
230 
231  for (i = 0; i < table->maxsize; i++)
232    if (table->entry[i].data) free(table->entry[i].data);
233  free(table->entry);
234  free(table);
235}
236
237static void set_fgcolor(ezx_t *e, const ezx_color_t *col)
238{
239  XColor lc={0}, *c;
240 
241  lc.red = (unsigned short) (col->r * 65535);
242  lc.green = (unsigned short) (col->g * 65535);
243  lc.blue = (unsigned short) (col->b * 65535);
244  lc.flags = DoRed | DoGreen | DoBlue;
245 
246  c = color_table_search(e->color_table, lc.red, lc.green, lc.blue);
247  if (!c) {
248    c = xmalloc(sizeof(XColor));
249    *c = lc;
250    XAllocColor(e->display, e->cmap, c);
251    color_table_insert(e->color_table, lc.red, lc.green, lc.blue, e->display, c);
252  }
253 
254  XSetForeground(e->display, e->gc, c->pixel);
255}
256
257void ezx_wipe(ezx_t *e)
258{
259  int i;
260  ezx_figures *f, *nf;
261
262  for (i = 0; i < EZX_NLAYER; i++) {
263    for (f = e->fig_head[i]; f != NULL; f = nf) {
264      nf = f->next;
265      if (f->type == FSTR3D) free(f->str);
266      if (f->type == FSTR2D) free(f->str);
267      free(f);
268    }
269
270    e->fig_head[i] = NULL;
271    e->fig_tail[i] = NULL;
272  }
273}
274
275void ezx_wipe_layer(ezx_t *e, int lay)
276{
277  ezx_figures *f, *nf;
278
279  if (lay < 0 || EZX_NLAYER <= lay)
280    error_exit("ezx_wipe_layer: invalid layer number %d", lay);
281 
282  for (f = e->fig_head[lay]; f != NULL; f = nf) {
283    nf = f->next;
284    if (f->type == FSTR3D) free(f->str);
285    if (f->type == FSTR2D) free(f->str);
286    free(f);
287  }
288
289  e->fig_head[lay] = NULL;
290  e->fig_tail[lay] = NULL;
291}
292
293void ezx_select_layer(ezx_t *e, int lay)
294{
295  if (lay < 0 || EZX_NLAYER <= lay)
296    error_exit("ezx_select_layer: invalid layer number %d", lay);
297
298  e->cur_layer = lay;
299}
300
301void ezx_set_light_3d(ezx_t *e, double ex, double ey, double ez)
302{
303  double s = sqrt(ex * ex + ey * ey + ez * ez);
304
305  if (s != 0) {
306    e->light_x = ex / s;
307    e->light_y = ey / s;
308    e->light_z = ez / s;
309  }
310}
311
312void ezx_set_view_3d(ezx_t *e, double ex, double ey, double ez, double vx,
313                     double vy, double vz, double m)
314{
315  double x = vx - ex, y = vy - ey, z = vz - ez;
316  double theta = atan2(y, x);
317  double tmp = x * x + y * y;
318  double phi;
319  double st, ct, sp, cp;
320
321  e->mag = m;
322
323  e->eye_x = ex;
324  e->eye_y = ey;
325  e->eye_z = ez;
326  e->eye_r = sqrt(x * x + y * y + z * z);
327
328  if (tmp == 0) phi = M_PI / 2;
329  else phi = acos(tmp / (sqrt(tmp) * e->eye_r));
330
331  if (z < 0) phi = -phi;
332
333  st = sin(theta);
334  ct = cos(theta);
335  sp = sin(phi);
336  cp = cos(phi);
337
338  e->cmat[0][0] = -st;
339  e->cmat[0][1] = -ct * sp;
340  e->cmat[0][2] = ct * cp;
341  e->cmat[1][0] = ct;
342  e->cmat[1][1] = -st * sp;
343  e->cmat[1][2] = st * cp;
344  e->cmat[2][0] = 0;
345  e->cmat[2][1] = cp;
346  e->cmat[2][2] = sp;
347}
348
349static double getz(ezx_t *e, double sx, double sy, double sz)
350{
351  sx -= e->eye_x;
352  sy -= e->eye_y;
353  sz -= e->eye_z;
354
355  return sx * e->cmat[0][2] + sy * e->cmat[1][2] + sz * e->cmat[2][2];
356}
357
358void ezx_c3d_to_2d(ezx_t *e, double sx, double sy, double sz, double *dx,
359                   double *dy)
360{
361  double x2, y2, z2, rz;
362
363  sx -= e->eye_x;
364  sy -= e->eye_y;
365  sz -= e->eye_z;
366
367  x2 = sx * e->cmat[0][0] + sy * e->cmat[1][0] + sz * e->cmat[2][0];
368  y2 = sx * e->cmat[0][1] + sy * e->cmat[1][1] + sz * e->cmat[2][1];
369  z2 = sx * e->cmat[0][2] + sy * e->cmat[1][2] + sz * e->cmat[2][2];
370
371  rz = e->scrdist - z2;
372  *dx = e->mag * e->scrdist * x2 / rz;
373  *dy = e->mag * e->scrdist * y2 / rz;
374}
375
376static void clip_line(int *x0, int *y0, int *x1, int *y1, int width, int height)
377{
378  if (*x0 > *x1) {
379    int t;
380    t = *x0;
381    *x0 = *x1;
382    *x1 = t;
383    t = *y0;
384    *y0 = *y1;
385    *y1 = t;
386  }
387
388  if (*x0 < 0 && *x1 >= 0) {
389    *y0 = *y1 + (*y0 - *y1) * (0 - *x1) / (*x0 - *x1);
390    *x0 = 0;
391  }
392  if (*x1 >= width && *x0 < width) {
393    *y1 = *y0 + (*y1 - *y0) * (width - *x0) / (*x1 - *x0);
394    *x1 = width;
395  }
396
397  if (*y0 > *y1) {
398    int t;
399    t = *x0;
400    *x0 = *x1;
401    *x1 = t;
402    t = *y0;
403    *y0 = *y1;
404    *y1 = t;
405  }
406
407  if (*y0 < 0 && *y1 >= 0) {
408    *x0 = *x1 + (*x0 - *x1) * (0 - *y1) / (*y0 - *y1);
409    *y0 = 0;
410  }
411  if (*y1 >= height && *y0 < height) {
412    *x1 = *x0 + (*x1 - *x0) * (height - *y0) / (*y1 - *y0);
413    *y1 = height;
414  }
415}
416
417static void figure_list_add_tail(ezx_t *e, ezx_figures *nf)
418{
419  int lay = e->cur_layer;
420 
421  if (e->fig_head[lay] == NULL)
422    e->fig_head[lay] = e->fig_tail[lay] = nf;
423  else {
424    e->fig_tail[lay]->next = nf;
425    e->fig_tail[lay] = nf;
426  }
427}
428
429void ezx_point_2d(ezx_t *e, int x, int y, const ezx_color_t *col)
430{
431  ezx_figures *nf = xcalloc(1, sizeof(ezx_figures));
432
433  nf->type = FPOINT2D;
434  nf->x0 = x;
435  nf->y0 = y;
436  nf->col = *col;
437
438  figure_list_add_tail(e, nf);
439}
440
441void ezx_line_2d(ezx_t *e, int x0, int y0, int x1, int y1, const ezx_color_t *col,
442                 int width)
443{
444  ezx_figures *nf = xcalloc(1, sizeof(ezx_figures));
445
446  nf->type = FLINE2D;
447  nf->x0 = x0;
448  nf->y0 = y0;
449  nf->x1 = x1;
450  nf->y1 = y1;
451  nf->col = *col;
452  nf->width = width;
453 
454  figure_list_add_tail(e, nf);
455}
456
457void ezx_lines_2d_lolevel (ezx_t *e, int *points, int npoints,
458                           const ezx_color_t *col, int width)
459{
460  int i=0, j=0, points_len=0;
461
462  ezx_figures *nf = xcalloc(1, sizeof(ezx_figures));
463  ezx_point2d_t *ps = xcalloc(npoints / 2, sizeof(ezx_point2d_t));
464 
465  for (i=0, j=0; i < npoints; i+=2, j++){
466    ps[j].x = points[i];
467    ps[j].y = points[i+1];
468  }
469
470  nf->type = FLINES2D;
471  nf->points_2d = ps;
472  nf->npoints = (npoints / 2);
473  nf->col = *col;
474  nf->width = width;
475 
476  figure_list_add_tail(e, nf);
477}
478
479void ezx_poly_2d_lolevel(ezx_t *e,int *points, int npoints,
480                         const ezx_color_t *col)
481{
482  int i = 0, j = 0;
483  ezx_figures *nf = xcalloc(1, sizeof(ezx_figures));
484  ezx_point2d_t *ps = xcalloc((npoints / 2), sizeof(ezx_point2d_t));
485
486  for (i=0, j=0; i<npoints; i+=2, j++){
487    ps[j].x = points[i];
488    ps[j].y = points[i+1];
489  }
490
491  nf->type = FPOLY2D;
492  nf->col = *col;
493  nf->points_2d = ps;
494  nf->npoints = (npoints / 2);
495  figure_list_add_tail(e, nf);
496}
497
498void ezx_arc_2d(ezx_t *e, int x0, int y0, int w, int h, double angle1,
499                double angle2, const ezx_color_t *col, int width)
500{
501  ezx_figures *nf = xcalloc(1, sizeof(ezx_figures));
502
503  nf->type = FARC2D;
504  nf->x0 = x0;
505  nf->y0 = y0;
506  nf->x1 = w;
507  nf->y1 = h;
508  nf->angle1 = angle1;
509  nf->angle2 = angle2;
510  nf->col = *col;
511  nf->width = width;
512
513  figure_list_add_tail(e, nf);
514}
515
516void ezx_fillarc_2d(ezx_t *e, int x0, int y0, int w, int h, double angle1,
517                    double angle2, const ezx_color_t *col)
518{
519  ezx_figures *nf = xcalloc(1, sizeof(ezx_figures));
520
521  nf->type = FFILLEDARC2D;
522  nf->x0 = x0;
523  nf->y0 = y0;
524  nf->x1 = w;
525  nf->y1 = h;
526  nf->angle1 = angle1;
527  nf->angle2 = angle2;
528  nf->col = *col;
529  nf->width = 0;
530
531  figure_list_add_tail(e, nf);
532}
533
534void ezx_line_3d(ezx_t *e, double x0, double y0, double z0, double x1,
535                 double y1, double z1, const ezx_color_t *col, int width)
536{
537  ezx_figures *nf = xcalloc(1, sizeof(ezx_figures));
538
539  nf->type = FLINE3D;
540  nf->dx0 = x0;
541  nf->dy0 = y0;
542  nf->dz0 = z0;
543  nf->dx1 = x1;
544  nf->dy1 = y1;
545  nf->dz1 = z1;
546  nf->col = *col;
547  nf->width = width;
548  nf->next = NULL;
549
550  figure_list_add_tail(e, nf);
551}
552
553void ezx_str_3d(ezx_t *e, double x0, double y0, double z0, char *str,
554                const ezx_color_t *col)
555{
556  ezx_figures *nf = xcalloc(1, sizeof(ezx_figures));
557
558  nf->type = FSTR3D;
559  nf->dx0 = x0;
560  nf->dy0 = y0;
561  nf->dz0 = z0;
562  nf->str = xcalloc(strlen(str) + 1, sizeof(char));
563  strcpy(nf->str, str);
564  nf->col = *col;
565  nf->next = NULL;
566
567  figure_list_add_tail(e, nf);
568}
569
570void ezx_str_2d(ezx_t *e, int x0, int y0, char *str, const ezx_color_t *col)
571{
572  ezx_figures *nf = xcalloc(1, sizeof(ezx_figures));
573
574  nf->type = FSTR2D;
575  nf->x0 = x0;
576  nf->y0 = y0;
577  nf->str = xcalloc(strlen(str) + 1, sizeof(char));
578  strcpy(nf->str, str);
579  nf->col = *col;
580  nf->width = 0;
581  nf->next = NULL;
582
583  figure_list_add_tail(e, nf);
584}
585
586void ezx_fillrect_2d(ezx_t *e, int x0, int y0, int x1, int y1,
587                     const ezx_color_t *col)
588{
589  ezx_figures *nf = xcalloc(1, sizeof(ezx_figures));
590
591  nf->type = FFILLEDRECT2D;
592  nf->x0 = x0;
593  nf->y0 = y0;
594  nf->x1 = x1;
595  nf->y1 = y1;
596  nf->col = *col;
597  nf->width = 0;
598  nf->next = NULL;
599
600  figure_list_add_tail(e, nf);
601}
602
603void ezx_rect_2d(ezx_t *e, int x0, int y0, int x1, int y1, const ezx_color_t *col,
604                 int width)
605{
606  ezx_figures *nf = xcalloc(1, sizeof(ezx_figures));
607
608  nf->type = FRECT2D;
609  nf->x0 = x0;
610  nf->y0 = y0;
611  nf->x1 = x1;
612  nf->y1 = y1;
613  nf->col = *col;
614  nf->width = width;
615  nf->next = NULL;
616
617  figure_list_add_tail(e, nf);
618}
619
620void ezx_poly_3d_lolevel (ezx_t *e, double *points, double hx, double hy,
621                          double hz, int npoints, const ezx_color_t *col)
622{
623  ezx_figures *nf = xcalloc(1, sizeof(ezx_figures));
624  ezx_point3d_t *ps = xcalloc((npoints / 3), sizeof(ezx_point3d_t));
625  int i, j=0;
626
627  for (i=0, j=0;i<npoints;i+=3, j++){
628    ps[j].x = points[i];
629    ps[j].y = points[i+1];
630    ps[j].z = points[i+2];
631  }
632
633  nf->type = FPOLY3D;
634  nf->points_3d = ps;
635  nf->npoints = (npoints / 3);
636  nf->col = *col;
637  nf->next = NULL;
638  nf->dx0 = hx;
639  nf->dy0 = hy;
640  nf->dz0 = hz;
641
642  nf->dx1 = nf->dy1 = nf->dz1 = 0;
643  for (i = 0; i < npoints; i++) {
644    nf->dx1 += ps[i].x;
645    nf->dy1 += ps[i].y;
646    nf->dz1 += ps[i].z;
647  }
648
649  nf->dx1 /= nf->npoints;
650  nf->dy1 /= nf->npoints;
651  nf->dz1 /= nf->npoints;
652
653  figure_list_add_tail(e, nf);
654}
655
656void ezx_fillcircle_2d(ezx_t *e, int x0, int y0, int r, const ezx_color_t *col)
657{
658  ezx_figures *nf = xcalloc(1, sizeof(ezx_figures));
659
660  nf->type = FFILLEDCIRCLE2D;
661  nf->x0 = x0;
662  nf->y0 = y0;
663  nf->r = r;
664  nf->col = *col;
665  nf->width = 0;
666  nf->next = NULL;
667
668  figure_list_add_tail(e, nf);
669}
670
671void ezx_circle_2d(ezx_t *e, int x0, int y0, int r, const ezx_color_t *col,
672                   int width)
673{
674  ezx_figures *nf = xcalloc(1, sizeof(ezx_figures));
675
676  nf->type = FCIRCLE2D;
677  nf->x0 = x0;
678  nf->y0 = y0;
679  nf->r = r;
680  nf->col = *col;
681  nf->width = width;
682  nf->next = NULL;
683
684  figure_list_add_tail(e, nf);
685}
686
687void ezx_circle_3d(ezx_t *e, double x0, double y0, double z0, double r,
688                   const ezx_color_t *col)
689{
690  ezx_figures *nf = xcalloc(1, sizeof(ezx_figures));
691
692  nf->type = FFILLEDCIRCLE3D;
693  nf->dx0 = x0;
694  nf->dy0 = y0;
695  nf->dz0 = z0;
696  nf->dr = r;
697  nf->col = *col;
698  nf->next = NULL;
699
700  figure_list_add_tail(e, nf);
701}
702
703void ezx_set_background(ezx_t *e, const ezx_color_t *col)
704{
705  e->bgcolor = *col;
706}
707
708void ezx_redraw(ezx_t *e)
709{
710  ezx_figures  *f;
711  ezx_pfigures *p;
712  ezx_pfigures *pf;
713
714  XSetBackground(e->display, e->gc, e->black.pixel);
715  set_fgcolor(e, &e->bgcolor);
716  XFillRectangle(e->display, e->pixmap, e->gc, 0, 0, e->size_x, e->size_y);
717
718  // z-sorting
719  pf = NULL;
720  for (f = e->fig_head[e->cur_layer]; f != NULL; f = f->next) {
721    double z;
722    ezx_pfigures **p;
723
724    if (f->type != FPOLY3D) continue;
725
726    z = getz(e, f->dx1, f->dy1, f->dz1);
727
728    for (p = &pf; *p != NULL; p = &(*p)->next) {
729      ezx_pfigures *np;
730
731      if (z <= (*p)->z) continue;
732
733      np = xmalloc(sizeof(ezx_pfigures));
734      np->z = z;
735      np->fig = f;
736      np->next = *p;
737      *p = np;
738      break;
739    }
740
741    if (*p == NULL) {
742      ezx_pfigures *np = xmalloc(sizeof(ezx_pfigures));
743      np->z = z;
744      np->fig = f;
745      np->next = NULL;
746      *p = np;
747    }
748  }
749
750  for (p = pf; p != NULL; p = p->next) {
751    ezx_figures *f = p->fig;
752    double hx, hy, hz;
753    double cl, br;
754    XPoint *xp;
755    int i;
756
757    if (f->dx0 != 0 || f->dy0 != 0 || f->dz0 != 0) {
758      hx = f->dx0;
759      hy = f->dy0;
760      hz = f->dz0;
761
762      if (hx * (e->eye_x - f->dx1) +
763          hy * (e->eye_y - f->dy1) +
764          hz * (e->eye_z - f->dz1) < 0) {
765        continue;
766      }
767    } else {
768      for (i = 2;; i++) {
769        double x0 = f->points_3d[1].x - f->points_3d[0].x;
770        double y0 = f->points_3d[1].y - f->points_3d[0].y;
771        double z0 = f->points_3d[1].z - f->points_3d[0].z;
772        double x1 = f->points_3d[i].x - f->points_3d[0].x;
773        double y1 = f->points_3d[i].y - f->points_3d[0].y;
774        double z1 = f->points_3d[i].z - f->points_3d[0].z;
775
776        hx = y0 * z1 - y1 * z0;
777        hy = z0 * x1 - z1 * x0;
778        hz = x0 * y1 - x1 * y0;
779
780        if (hx != 0 || hy != 0 || hz != 0) break;
781      }
782    }
783
784    cl = (e->light_x * f->dx0 + e->light_y * f->dy0 +
785          e->light_z * f->dz0) / sqrt(f->dx0 * f->dx0 +
786                                          f->dy0 * f->dy0 +
787                                          f->dz0 * f->dz0);
788    if (cl < 0) {
789      cl = -cl;
790      f->dx0 = -f->dx0;
791      f->dy0 = -f->dy0;
792      f->dz0 = -f->dz0;
793    }
794    if (f->dx0 * (e->eye_x - f->dx1) +
795        f->dy0 * (e->eye_y - f->dy1) +
796        f->dz0 * (e->eye_z - f->dz1) < 0)
797      cl = 0;
798    br = cl * 0.6 + 0.3;
799
800    xp = xmalloc(sizeof(XPoint) * f->npoints);
801    for (i = 0; i < f->npoints; i++) {
802      double sx0, sy0;
803      ezx_c3d_to_2d(e, f->points_3d[i].x, f->points_3d[i].y,
804                    f->points_3d[i].z, &sx0, &sy0);
805      xp[i].x = (int)sx0 + (e->size_x / 2);
806      xp[i].y = (int)sy0 + (e->size_y / 2);
807    }
808
809    set_fgcolor(e, &f->col);
810   
811    XFillPolygon(e->display, e->pixmap, e->gc, xp, f->npoints,
812                 Complex, CoordModeOrigin);
813
814    free(xp);
815  }
816
817  {
818    ezx_pfigures *np, *p;
819    for (p = pf; p != NULL; p = np) {
820      np = p->next;
821      free(p);
822    }
823
824    pf = NULL;
825  }
826
827  {
828    ezx_figures *f;
829    int i;
830
831    for (i = 0; i < EZX_NLAYER; i++) {
832      for (f = e->fig_head[i]; f != NULL; f = f->next) {
833        set_fgcolor(e, &f->col);
834
835        switch (f->type) {
836        case FPOINT2D:
837          XDrawPoint(e->display, e->pixmap, e->gc, f->x0, f->y0);
838          break;
839        case FLINE2D:
840          {
841            int width = f->width;
842            if (width <= 0) break;
843            if (width == 1) width = 0;
844            XSetLineAttributes(e->display, e->gc, width, LineSolid,
845                               CapRound, JoinRound);
846            XDrawLine(e->display, e->pixmap, e->gc, f->x0, f->y0, f->x1, f->y1);
847          }
848          break;
849        case FLINES2D:
850          {
851            int j, width = f->width;
852            if (width <= 0) break;
853            if (width == 1) width = 0;
854            XSetLineAttributes(e->display, e->gc, width, LineSolid,
855                               CapRound, JoinRound);
856            XPoint *xp = xmalloc(sizeof(XPoint) * f->npoints);
857            for (j = 0; j < f->npoints; j++) {
858              xp[j].x = f->points_2d[j].x;
859              xp[j].y = f->points_2d[j].y;
860            }
861            XDrawLines(e->display, e->pixmap, e->gc, xp, f->npoints,
862                       CoordModeOrigin);
863            free(xp);
864          }
865          break;
866        case FPOLY2D:
867          {
868            int j;
869            XPoint *xp = xmalloc(sizeof(XPoint) * f->npoints);
870            for (j = 0; j < f->npoints; j++) {
871              xp[j].x = f->points_2d[j].x;
872              xp[j].y = f->points_2d[j].y;
873            }
874            XFillPolygon(e->display, e->pixmap, e->gc, xp, f->npoints,
875                         Complex, CoordModeOrigin);
876            free(xp);
877          }
878          break;
879        case FLINE3D:
880          {
881            int width = f->width;
882            double sx0, sy0, sx1, sy1;
883            int x0, y0, x1, y1;
884            if (width <= 0) break;
885            if (width == 1) width = 0;
886            ezx_c3d_to_2d(e, f->dx0, f->dy0, f->dz0, &sx0, &sy0);
887            ezx_c3d_to_2d(e, f->dx1, f->dy1, f->dz1, &sx1, &sy1);
888            x0 = (int)sx0 + (e->size_x / 2);
889            y0 = (int)sy0 + (e->size_y / 2);
890            x1 = (int)sx1 + (e->size_x / 2);
891            y1 = (int)sy1 + (e->size_y / 2);
892            clip_line(&x0, &y0, &x1, &y1, e->size_x, e->size_y);
893            XSetLineAttributes(e->display, e->gc, width, LineSolid,
894                               CapRound, JoinRound);
895            XDrawLine(e->display, e->pixmap, e->gc, x0, y0, x1, y1);
896          }
897          break;
898        case FCIRCLE2D:
899          {
900            int width = f->width;
901            if (width <= 0) break;
902            if (width == 1) width = 0;
903            XSetLineAttributes(e->display, e->gc, width, LineSolid,
904                               CapRound, JoinRound);
905            XDrawArc(e->display, e->pixmap, e->gc, f->x0 - f->r, f->y0 - f->r,
906                     f->r * 2, f->r * 2, 0, 64 * 360);
907          }
908          break;
909        case FFILLEDCIRCLE2D:
910          XFillArc(e->display, e->pixmap, e->gc, f->x0 - f->r, f->y0 - f->r,
911                   f->r * 2, f->r * 2, 0, 64 * 360);
912          break;
913        case FFILLEDCIRCLE3D:
914          {
915            double sx0, sy0;
916            ezx_c3d_to_2d(e, f->dx0, f->dy0, f->dz0, &sx0, &sy0);
917            XFillArc(e->display, e->pixmap, e->gc,
918                     (int)sx0 + (e->size_x / 2) - (int)f->dr,
919                     (int)sy0 + (e->size_y / 2) - (int)f->dr,
920                     (int)f->dr * 2, (int)f->dr * 2, 0, 64 * 360);
921          }
922          break;
923        case FSTR2D:
924          XDrawString(e->display, e->pixmap, e->gc, f->x0, f->y0, f->str,
925                      strlen(f->str));
926          break;
927        case FSTR3D:
928          {
929            double sx0, sy0;
930            ezx_c3d_to_2d(e, f->dx0, f->dy0, f->dz0, &sx0, &sy0);
931            XDrawString(e->display, e->pixmap, e->gc,
932                        (int)sx0 + (e->size_x / 2), (int)sy0 + (e->size_y / 2),
933                        f->str, strlen(f->str));
934          }
935          break;
936        case FRECT2D:
937          {
938            int width = f->width;
939            if (width <= 0) break;
940            if (width == 1) width = 0;
941            XSetLineAttributes(e->display, e->gc, width, LineSolid,
942                               CapRound, JoinRound);
943            XDrawRectangle(e->display, e->pixmap, e->gc, f->x0, f->y0,
944                           f->x1 - f->x0, f->y1 - f->y0);
945          }
946          break;
947        case FFILLEDRECT2D:
948          XFillRectangle(e->display, e->pixmap, e->gc, f->x0, f->y0,
949                         f->x1 - f->x0, f->y1 - f->y0);
950          break;
951        case FARC2D:
952          {
953            int width = f->width;
954            if (width <= 0) break;
955            if (width == 1) width = 0;
956            XSetLineAttributes(e->display, e->gc, width, LineSolid,
957                               CapRound, JoinRound);
958            XDrawArc(e->display, e->pixmap, e->gc, f->x0 - f->x1/2, f->y0 - f->y1/2,
959                     f->x1, f->y1, f->angle1 * 64, f->angle2 * 64);
960          }
961          break;
962        case FFILLEDARC2D:
963          XFillArc(e->display, e->pixmap, e->gc, f->x0 - f->x1/2, f->y0 - f->y1/2,
964                   f->x1, f->y1, f->angle1 * 64, f->angle2 * 64);
965          break;
966        case FPOLY3D:
967          break;
968        }
969      }
970    }
971  }
972
973  XCopyArea(e->display, e->pixmap, e->top, e->gc, 0, 0, e->size_x, e->size_y,
974            0, 0);
975
976  XFlush(e->display);
977}
978
979void ezx_window_name(ezx_t *e, char *window_name)
980{
981  if (window_name != NULL)
982    XStoreName(e->display, e->top, window_name);
983}
984
985int ezx_isclosed(ezx_t *e)
986{
987  XEvent event;
988
989  if (!e->closed &&
990      XCheckTypedWindowEvent(e->display, e->top, ClientMessage, &event) != 0) {
991    if (event.xclient.message_type == e->wm_protocols &&
992        event.xclient.data.l[0] == e->wm_delete_window) {
993      e->closed = 1;
994    }     
995  }
996
997  return e->closed;
998}
999
1000void ezx_quit(ezx_t *e)
1001{
1002  ezx_wipe(e);
1003
1004  XFreeFont(e->display, e->fontst);
1005  XFreeGC(e->display, e->gc);
1006  XCloseDisplay(e->display);
1007
1008  color_table_free(e->color_table);
1009
1010  free(e);
1011}
1012
1013void ezx_resize(ezx_t *e, int size_x, int size_y)
1014{
1015  e->size_x = size_x;
1016  e->size_y = size_y; 
1017  XResizeWindow(e->display, e->top, e->size_x, e->size_y);
1018}
1019
1020ezx_t *ezx_init(int size_x, int size_y, char *window_name)
1021{
1022  char  *server;
1023  ezx_t *e;
1024  XSetWindowAttributes atr;
1025
1026  e = xcalloc(1, sizeof(ezx_t));
1027
1028  server = (char *)getenv("DISPLAY");
1029  if (server == NULL) server = "localhost:0.0";
1030
1031  e->display = XOpenDisplay(server);
1032  if (e->display == NULL) error_exit("can't open display \"%s\"", server);
1033
1034  e->size_x = size_x;
1035  e->size_y = size_y;
1036  e->closed = 0;
1037  e->scrdist = 100;
1038  e->mag = 20;
1039  e->cmap = DefaultColormap(e->display, DefaultScreen(e->display));
1040
1041  e->color_table = color_table_new();
1042
1043  XAllocNamedColor(e->display, e->cmap, "black", &e->black, &e->rgb);
1044  XAllocNamedColor(e->display, e->cmap, "white", &e->white, &e->rgb);
1045
1046  e->fontst = XLoadQueryFont(e->display, fontname);
1047  if (e->fontst == NULL) error_exit("can't load font \"%s\"", fontname);
1048
1049  e->top =
1050    XCreateSimpleWindow(e->display, DefaultRootWindow(e->display), 0,
1051                        0, e->size_x, e->size_y, 2,
1052                        BlackPixel(e->display, DefaultScreen(e->display)),
1053                        WhitePixel(e->display, DefaultScreen(e->display)));
1054
1055  if (window_name != NULL)
1056    XStoreName(e->display, e->top, window_name);
1057
1058  e->pixmap = XCreatePixmap(e->display, e->top, e->size_x, e->size_y, 
1059                            DefaultDepth(e->display, DefaultScreen(e->display)));
1060 
1061  e->gc = XCreateGC(e->display, e->top, 0, 0);
1062  XSetGraphicsExposures(e->display, e->gc, False);
1063
1064  e->wm_protocols = XInternAtom(e->display, "WM_PROTOCOLS", True);
1065  e->wm_delete_window = XInternAtom(e->display, "WM_DELETE_WINDOW", True);
1066  XSetWMProtocols(e->display, e->top, &e->wm_delete_window, 1);
1067 
1068  e->size_hints.flags = PMinSize | PMaxSize;
1069  e->size_hints.min_width = e->size_x;
1070  e->size_hints.min_height = e->size_y;
1071  e->size_hints.max_width = e->size_x;
1072  e->size_hints.max_height = e->size_y;
1073  XSetNormalHints(e->display, e->top, &e->size_hints);
1074
1075  atr.backing_store = WhenMapped;
1076  XChangeWindowAttributes(e->display, e->top, CWBackingStore, &atr);
1077
1078  XSetWindowBackgroundPixmap(e->display, e->top, e->pixmap);
1079
1080  XSelectInput(e->display, e->top,
1081               ExposureMask | KeyPressMask | KeyReleaseMask | ButtonMotionMask |
1082               OwnerGrabButtonMask | ButtonPressMask | ButtonReleaseMask);
1083
1084  XResizeWindow(e->display, e->top, e->size_x, e->size_y);
1085
1086  XMapWindow(e->display, e->top);
1087
1088  XFlush(e->display);
1089
1090  {
1091    XEvent ev;
1092    do {
1093      XNextEvent(e->display, &ev);
1094    } while (ev.type != Expose);
1095  }
1096
1097  ezx_set_background(e, &ezx_white);
1098  ezx_set_view_3d(e, 1000, 0, 0, 0, 0, 0, 5);
1099  ezx_set_light_3d(e, 1000, 900, 800);
1100  ezx_redraw(e);
1101 
1102  return e;
1103}
1104
1105static inline unsigned int get_state_mask(unsigned int xstate)
1106{
1107  unsigned int state = 0;
1108
1109  if (xstate & ShiftMask) state |= EZX_SHIFT_MASK;
1110  if (xstate & ControlMask) state |= EZX_CONTROL_MASK;
1111  if (xstate & Button1Mask) state |= EZX_BUTTON_LMASK;
1112  if (xstate & Button2Mask) state |= EZX_BUTTON_MMASK;
1113  if (xstate & Button3Mask) state |= EZX_BUTTON_RMASK;
1114
1115  return state;
1116}
1117
1118int ezx_sensebutton(ezx_t *e, int *x, int *y)
1119{
1120  Window root, child;
1121  int root_x, root_y, win_x, win_y;
1122  unsigned int s;
1123
1124  if (x == NULL) x = &win_x;
1125  if (y == NULL) y = &win_y;
1126
1127  XQueryPointer(e->display, e->top, &root, &child, &root_x, &root_y, x, y, &s);
1128 
1129  return get_state_mask(s);
1130}
1131
1132int ezx_pushbutton(ezx_t *e, int *x, int *y)
1133{
1134  XEvent xevent;
1135
1136  for (;;) {
1137    XMaskEvent(e->display, ExposureMask | ButtonPressMask, &xevent);
1138   
1139    if (xevent.type == Expose) {
1140      ezx_redraw(e);
1141    } else if (xevent.type == ButtonPress) {
1142      if (x) *x = xevent.xbutton.x;
1143      if (y) *y = xevent.xbutton.y;
1144      return xevent.xbutton.button;
1145    }
1146  }
1147}
1148
1149void ezx_next_event(ezx_t *e, ezx_event_t *event)
1150{
1151  XEvent xevent;
1152
1153  for (;;) {
1154    XNextEvent(e->display, &xevent);
1155   
1156    if (xevent.type == Expose) {
1157      ezx_redraw(e);
1158    } else if (xevent.type == ButtonPress || xevent.type == ButtonRelease) {
1159      if (event) {
1160        if (xevent.type == ButtonPress) event->button.type = EZX_BUTTON_PRESS;
1161        else event->button.type = EZX_BUTTON_RELEASE;
1162        event->button.b = xevent.xbutton.button;
1163        event->button.x = xevent.xbutton.x;
1164        event->button.y = xevent.xbutton.y;
1165        event->button.state = get_state_mask(xevent.xbutton.state);
1166      }
1167      break;
1168    } else if (xevent.type == KeyPress || xevent.type == KeyRelease) {
1169      int ret;
1170      char c;
1171      KeySym keysym;
1172      if ((ret=XLookupString((XKeyEvent *)&xevent, &c, 1, &keysym, NULL)) == 1 ||
1173          (XK_Home <= keysym && keysym <= XK_Down)) {
1174        if (event) {
1175          if (xevent.type == KeyPress) event->key.type = EZX_KEY_PRESS;
1176          else event->key.type = EZX_KEY_RELEASE;
1177          if (ret == 1) event->key.k = c;
1178          else event->key.k = keysym;
1179          event->key.x = xevent.xkey.x;
1180          event->key.y = xevent.xkey.y;
1181          event->key.state = get_state_mask(xevent.xkey.state);
1182        }
1183        break;
1184      }
1185    } else if (xevent.type == MotionNotify) {
1186      if (event) {
1187        event->motion.type = EZX_MOTION_NOTIFY;
1188        event->motion.x = xevent.xmotion.x;
1189        event->motion.y = xevent.xmotion.y;
1190        event->motion.state = get_state_mask(xevent.xmotion.state);
1191      }
1192      break;
1193    } else if (xevent.type == ClientMessage) {
1194      if (xevent.xclient.message_type == e->wm_protocols &&
1195          xevent.xclient.data.l[0] == e->wm_delete_window) {
1196        e->closed = 1;
1197        if (event) event->type = EZX_CLOSE;
1198        break;
1199      }
1200    }
1201  }
1202}
Note: See TracBrowser for help on using the repository browser.