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

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

C5 port of ezxdisp

File size: 33.1 KB
Line 
1/*
2 * win32/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 <windows.h>
14#include <windowsx.h>
15#include <process.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  int quit;
24
25  HWND hWnd;
26  char *window_name;
27  HBITMAP hBitmap;
28  HDC hdcMem;
29  HFONT hFont;
30  CRITICAL_SECTION cSect;
31
32  HANDLE hThread;
33  HANDLE hWindowCreation;
34
35  int                 cur_layer;
36  struct ezx_figures *fig_head[EZX_NLAYER];
37  struct ezx_figures *fig_tail[EZX_NLAYER];
38
39  // 3d stuffs
40  double scrdist, mag;
41  double eye_x, eye_y, eye_z, eye_r;
42  double cmat[3][3];
43  double light_x, light_y, light_z;
44
45  struct event_queue_s *event_queue;
46};
47
48typedef struct ezx_figures {
49  enum {
50    FPOINT2D,
51    FLINE2D,
52    FLINES2D,
53    FLINE3D,
54    FPOLY2D,
55    FPOLY3D,
56    FSTR2D,
57    FSTR3D,
58    FRECT2D,
59    FFILLEDRECT2D,
60    FCIRCLE2D,
61    FFILLEDCIRCLE2D,
62    FFILLEDCIRCLE3D,
63    FARC2D,
64    FFILLEDARC2D,
65  } type;
66
67  int x0, y0, z0, x1, y1, z1, r;
68  double dx0, dy0, dz0, dx1, dy1, dz1, dr;
69  double angle1, angle2;
70  char  *str;
71
72  int npoints;
73  ezx_point2d_t *points_2d;
74  ezx_point3d_t *points_3d;
75
76  ezx_color_t         col;
77  int                 width;
78  struct ezx_figures *next;
79} ezx_figures;
80
81typedef struct ezx_pfigures {
82  double               z;
83  struct ezx_figures  *fig;
84  struct ezx_pfigures *next;
85} ezx_pfigures;
86
87#define QID_BUTTON_PRESS 0
88#define QID_OTHERS       1
89typedef struct event_queue_s {
90  int queue_num;
91  CRITICAL_SECTION cSect;
92  HANDLE *hEvent;
93  struct queue_s {
94    int size;
95    struct event_queue_elem_s {
96      unsigned int time;
97      ezx_event_t *event;
98      struct event_queue_elem_s *next;
99    } *head, *tail;
100  } *queue;
101} event_queue_t;
102
103const ezx_color_t ezx_black  = {0, 0, 0};
104const ezx_color_t ezx_white  = {1, 1, 1};
105const ezx_color_t ezx_grey25 = {0.25, 0.25, 0.25};
106const ezx_color_t ezx_grey50 = {0.5, 0.5, 0.5};
107const ezx_color_t ezx_grey75 = {0.75, 0.75, 0.75};
108const ezx_color_t ezx_blue   = {0, 0, 1};
109const ezx_color_t ezx_red    = {1, 0, 0};
110const ezx_color_t ezx_green  = {0, 1, 0};
111const ezx_color_t ezx_yellow = {1, 1, 0};
112const ezx_color_t ezx_purple = {1, 0, 1};
113const ezx_color_t ezx_pink   = {1, 0.5, 0.5};
114const ezx_color_t ezx_cyan   = {0.5, 0.5, 1};
115const ezx_color_t ezx_brown  = {0.5, 0, 0};
116const ezx_color_t ezx_orange = {1, 0.5, 0};
117
118static const char * const class_name = "ezx_window";
119
120static void error_exit(const char *fmt, ...)
121{
122  va_list params;
123
124  fprintf(stderr, "ezxdisp: ");
125  va_start(params, fmt);
126  vfprintf(stderr, fmt, params);
127  va_end(params);
128  fprintf(stderr, "\n");
129  fflush(stderr);
130  exit(EXIT_FAILURE);
131}
132
133static void sys_error_exit(const char *fmt, ...)
134{
135  int errno_save = errno;
136  va_list params;
137
138  fprintf(stderr, "ezxdisp: ");
139  va_start(params, fmt);
140  vfprintf(stderr, fmt, params);
141  va_end(params);
142  fprintf(stderr, ": %s\n", strerror(errno_save));
143  fflush(stderr);
144  exit(EXIT_FAILURE);
145}
146
147static inline void *xmalloc(size_t n)
148{
149  void *p;
150
151  p = malloc(n);
152  if (!p) sys_error_exit("malloc failed");
153 
154  return p;
155}
156
157static inline void *xcalloc(size_t n, size_t s)
158{
159  void *p;
160
161  p = calloc(n, s);
162  if (!p) sys_error_exit("calloc failed");
163
164  return p;
165}
166
167static void win32_error_exit(const char *str)
168{
169  LPVOID lpBuffer;
170  char *c;
171
172  FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
173                NULL, GetLastError(),
174                MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
175                         SORT_DEFAULT), (LPTSTR)&lpBuffer, 0, NULL);
176  if ((c = strchr(lpBuffer, '\n')) != NULL) *c = '\0';
177  error_exit("%s: %s", str, lpBuffer);
178}
179
180static event_queue_t *event_queue_new()
181{
182  int i;
183  event_queue_t *q;
184
185  q = xmalloc(sizeof(event_queue_t));
186  q->queue_num = 2; /* one is for EZX_BUTTON_PRESS, and the other is for
187                       other events */
188  InitializeCriticalSection(&q->cSect);
189  q->queue = xmalloc(sizeof(struct queue_s) * q->queue_num);
190  q->hEvent = xmalloc(sizeof(HANDLE) * q->queue_num);
191  for (i = 0; i < q->queue_num; i++) {
192    q->hEvent[i] = CreateEvent(NULL, TRUE, FALSE, NULL);
193    q->queue[i].size = 0;
194    q->queue[i].head = q->queue[i].tail = NULL;
195  }
196
197  return q;
198}
199
200static void event_queue_offer(event_queue_t *q, int id, ezx_event_t *event)
201{
202  struct queue_s *queue = &(q->queue[id]);
203  struct event_queue_elem_s *new = xmalloc(sizeof(struct event_queue_elem_s));
204
205  new->time = GetMessageTime();
206  new->event = event;
207  new->next = NULL;
208
209  EnterCriticalSection(&q->cSect);
210
211  if (queue->size == 0) queue->head = queue->tail = new;
212  else queue->tail = queue->tail->next = new;
213  (queue->size)++;
214  if (!SetEvent(q->hEvent[id]))
215    win32_error_exit("event_queue_offer: SetEvent failed");
216
217  LeaveCriticalSection(&q->cSect);
218}
219
220static ezx_event_t *event_queue_remove(event_queue_t *q, int id)
221{
222  struct queue_s *queue = &(q->queue[id]);
223  struct event_queue_elem_s *elem;
224  ezx_event_t *event;
225
226  if (WaitForSingleObject(q->hEvent[id], INFINITE) != WAIT_OBJECT_0)
227    win32_error_exit("event_queue_remove: WaitForSingleObject failed");
228 
229  EnterCriticalSection(&q->cSect);
230
231  elem = queue->head;
232  assert(queue->size > 0);
233  if (queue->size == 1) queue->head = queue->tail = NULL;
234  else queue->head = elem->next;
235  (queue->size)--;
236  if (queue->size == 0) {
237    if (!ResetEvent(q->hEvent[id]))
238      win32_error_exit("event_queue_remove: ResetEvent failed");
239  }
240
241  LeaveCriticalSection(&q->cSect);
242 
243  event = elem->event;
244  free(elem);
245  return event;
246}
247
248static ezx_event_t *event_queue_remove_oldest(event_queue_t *q)
249{
250  struct queue_s *queue;
251  struct event_queue_elem_s *elem;
252  ezx_event_t *event;
253  int i, oldest_id;
254  DWORD ret;
255  unsigned int min_time;
256
257  ret = WaitForMultipleObjects(q->queue_num, q->hEvent, FALSE, INFINITE);
258  if (ret < WAIT_OBJECT_0 || WAIT_OBJECT_0+q->queue_num <= ret)
259    win32_error_exit("event_queue_remove_oldest: WaitForMultipleObjects failed");
260
261  EnterCriticalSection(&q->cSect);
262
263  oldest_id = ret - WAIT_OBJECT_0;
264  assert(q->queue[oldest_id].size > 0);
265  min_time = q->queue[oldest_id].head->time;
266  for (i = oldest_id+1; i < q->queue_num; i++) {
267    if (q->queue[i].head != NULL && q->queue[i].head->time < min_time) {
268      oldest_id = i;
269      min_time = q->queue[i].head->time;
270    }
271  }
272
273  queue = &(q->queue[oldest_id]);
274  elem = queue->head;
275  if (queue->size == 1) queue->head = queue->tail = NULL;
276  else queue->head = elem->next;
277  (queue->size)--;
278  if (queue->size == 0) {
279    if (!ResetEvent(q->hEvent[oldest_id]))
280      win32_error_exit("event_queue_remove_oldest: ResetEvent failed");
281  }
282
283  LeaveCriticalSection(&q->cSect);
284
285  event = elem->event;
286  free(elem);
287  return event;
288}
289
290static void event_queue_free(event_queue_t *q)
291{
292  int i;
293  struct event_queue_elem_s *elem, *next;
294
295  for (i = 0; i < q->queue_num; i++) {
296    next = q->queue[i].head;
297    while (next) {
298      elem = next;
299      next = next->next;
300      free(elem->event);
301      free(elem);
302    }
303    CloseHandle(q->hEvent[i]);
304  }
305  free(q->queue);
306  free(q->hEvent);
307  DeleteCriticalSection(&q->cSect);
308  free(q);
309}
310
311void ezx_wipe(ezx_t *e)
312{
313  int i;
314  ezx_figures *f, *nf;
315
316  for (i = 0; i < EZX_NLAYER; i++) {
317    for (f = e->fig_head[i]; f != NULL; f = nf) {
318      nf = f->next;
319      if (f->type == FSTR3D) free(f->str);
320      if (f->type == FSTR2D) free(f->str);
321      free(f);
322    }
323
324    e->fig_head[i] = NULL;
325    e->fig_tail[i] = NULL;
326  }
327}
328
329void ezx_wipe_layer(ezx_t *e, int lay)
330{
331  ezx_figures *f, *nf;
332
333  if (lay < 0 || EZX_NLAYER <= lay)
334    error_exit("ezx_wipe_layer: invalid layer number %d", lay);
335 
336  for (f = e->fig_head[lay]; f != NULL; f = nf) {
337    nf = f->next;
338    if (f->type == FSTR3D) free(f->str);
339    if (f->type == FSTR2D) free(f->str);
340    free(f);
341  }
342
343  e->fig_head[lay] = NULL;
344  e->fig_tail[lay] = NULL;
345}
346
347void ezx_select_layer(ezx_t *e, int lay)
348{
349  if (lay < 0 || EZX_NLAYER <= lay)
350    error_exit("ezx_select_layer: invalid layer number %d", lay);
351
352  e->cur_layer = lay;
353}
354
355void ezx_set_light_3d(ezx_t *e, double ex, double ey, double ez)
356{
357  double s = sqrt(ex * ex + ey * ey + ez * ez);
358
359  if (s != 0) {
360    e->light_x = ex / s;
361    e->light_y = ey / s;
362    e->light_z = ez / s;
363  }
364}
365
366void ezx_set_view_3d(ezx_t *e, double ex, double ey, double ez, double vx,
367                     double vy, double vz, double m)
368{
369  double x = vx - ex, y = vy - ey, z = vz - ez;
370  double theta = atan2(y, x);
371  double tmp = x * x + y * y;
372  double phi;
373  double st, ct, sp, cp;
374
375  e->mag = m;
376
377  e->eye_x = ex;
378  e->eye_y = ey;
379  e->eye_z = ez;
380  e->eye_r = sqrt(x * x + y * y + z * z);
381
382  if (tmp == 0) phi = M_PI / 2;
383  else phi = acos(tmp / (sqrt(tmp) * e->eye_r));
384
385  if (z < 0) phi = -phi;
386
387  st = sin(theta);
388  ct = cos(theta);
389  sp = sin(phi);
390  cp = cos(phi);
391
392  e->cmat[0][0] = -st;
393  e->cmat[0][1] = -ct * sp;
394  e->cmat[0][2] = ct * cp;
395  e->cmat[1][0] = ct;
396  e->cmat[1][1] = -st * sp;
397  e->cmat[1][2] = st * cp;
398  e->cmat[2][0] = 0;
399  e->cmat[2][1] = cp;
400  e->cmat[2][2] = sp;
401}
402
403static double getz(ezx_t *e, double sx, double sy, double sz)
404{
405  sx -= e->eye_x;
406  sy -= e->eye_y;
407  sz -= e->eye_z;
408
409  return sx * e->cmat[0][2] + sy * e->cmat[1][2] + sz * e->cmat[2][2];
410}
411
412void ezx_c3d_to_2d(ezx_t *e, double sx, double sy, double sz, double *dx,
413                   double *dy)
414{
415  double x2, y2, z2, rz;
416
417  sx -= e->eye_x;
418  sy -= e->eye_y;
419  sz -= e->eye_z;
420
421  x2 = sx * e->cmat[0][0] + sy * e->cmat[1][0] + sz * e->cmat[2][0];
422  y2 = sx * e->cmat[0][1] + sy * e->cmat[1][1] + sz * e->cmat[2][1];
423  z2 = sx * e->cmat[0][2] + sy * e->cmat[1][2] + sz * e->cmat[2][2];
424
425  rz = e->scrdist - z2;
426  *dx = e->mag * e->scrdist * x2 / rz;
427  *dy = e->mag * e->scrdist * y2 / rz;
428}
429
430static void clip_line(int *x0, int *y0, int *x1, int *y1, int width, int height)
431{
432  if (*x0 > *x1) {
433    int t;
434    t = *x0;
435    *x0 = *x1;
436    *x1 = t;
437    t = *y0;
438    *y0 = *y1;
439    *y1 = t;
440  }
441
442  if (*x0 < 0 && *x1 >= 0) {
443    *y0 = *y1 + (*y0 - *y1) * (0 - *x1) / (*x0 - *x1);
444    *x0 = 0;
445  }
446  if (*x1 >= width && *x0 < width) {
447    *y1 = *y0 + (*y1 - *y0) * (width - *x0) / (*x1 - *x0);
448    *x1 = width;
449  }
450
451  if (*y0 > *y1) {
452    int t;
453    t = *x0;
454    *x0 = *x1;
455    *x1 = t;
456    t = *y0;
457    *y0 = *y1;
458    *y1 = t;
459  }
460
461  if (*y0 < 0 && *y1 >= 0) {
462    *x0 = *x1 + (*x0 - *x1) * (0 - *y1) / (*y0 - *y1);
463    *y0 = 0;
464  }
465  if (*y1 >= height && *y0 < height) {
466    *x1 = *x0 + (*x1 - *x0) * (height - *y0) / (*y1 - *y0);
467    *y1 = height;
468  }
469}
470
471static void figure_list_add_tail(ezx_t *e, ezx_figures *nf)
472{
473  int lay = e->cur_layer;
474 
475  if (e->fig_head[lay] == NULL)
476    e->fig_head[lay] = e->fig_tail[lay] = nf;
477  else {
478    e->fig_tail[lay]->next = nf;
479    e->fig_tail[lay] = nf;
480  }
481}
482
483void ezx_point_2d(ezx_t *e, int x, int y, const ezx_color_t *col)
484{
485  ezx_figures *nf = xcalloc(1, sizeof(ezx_figures));
486
487  nf->type = FPOINT2D;
488  nf->x0 = x;
489  nf->y0 = y;
490  nf->col = *col;
491
492  figure_list_add_tail(e, nf);
493}
494
495void ezx_line_2d(ezx_t *e, int x0, int y0, int x1, int y1, const ezx_color_t *col,
496                 int width)
497{
498  ezx_figures *nf = xcalloc(1, sizeof(ezx_figures));
499
500  nf->type = FLINE2D;
501  nf->x0 = x0;
502  nf->y0 = y0;
503  nf->x1 = x1;
504  nf->y1 = y1;
505  nf->col = *col;
506  nf->width = width;
507 
508  figure_list_add_tail(e, nf);
509}
510
511void ezx_lines_2d(ezx_t *e, ezx_point2d_t *points, int npoints,
512                  const ezx_color_t *col, int width)
513{
514  ezx_figures *nf = xcalloc(1, sizeof(ezx_figures));
515
516  nf->type = FLINES2D;
517  nf->points_2d = points;
518  nf->npoints = npoints;
519  nf->col = *col;
520  nf->width = width;
521 
522  figure_list_add_tail(e, nf);
523}
524
525void ezx_poly_2d(ezx_t *e,ezx_point2d_t *points, int npoints,
526                 const ezx_color_t *col)
527{
528  ezx_figures *nf = xcalloc(1, sizeof(ezx_figures));
529
530  nf->type = FPOLY2D;
531  nf->points_2d = points;
532  nf->npoints = npoints;
533  nf->col = *col;
534 
535  figure_list_add_tail(e, nf);
536}
537
538void ezx_arc_2d(ezx_t *e, int x0, int y0, int w, int h, double angle1,
539                double angle2, const ezx_color_t *col, int width)
540{
541  ezx_figures *nf = xcalloc(1, sizeof(ezx_figures));
542
543  nf->type = FARC2D;
544  nf->x0 = x0;
545  nf->y0 = y0;
546  nf->x1 = w;
547  nf->y1 = h;
548  nf->angle1 = angle1;
549  nf->angle2 = angle2;
550  nf->col = *col;
551  nf->width = width;
552
553  figure_list_add_tail(e, nf);
554}
555
556void ezx_fillarc_2d(ezx_t *e, int x0, int y0, int w, int h, double angle1,
557                    double angle2, const ezx_color_t *col)
558{
559  ezx_figures *nf = xcalloc(1, sizeof(ezx_figures));
560
561  nf->type = FFILLEDARC2D;
562  nf->x0 = x0;
563  nf->y0 = y0;
564  nf->x1 = w;
565  nf->y1 = h;
566  nf->angle1 = angle1;
567  nf->angle2 = angle2;
568  nf->col = *col;
569  nf->width = 0;
570
571  figure_list_add_tail(e, nf);
572}
573
574void ezx_line_3d(ezx_t *e, double x0, double y0, double z0, double x1,
575                 double y1, double z1, const ezx_color_t *col, int width)
576{
577  ezx_figures *nf = xcalloc(1, sizeof(ezx_figures));
578
579  nf->type = FLINE3D;
580  nf->dx0 = x0;
581  nf->dy0 = y0;
582  nf->dz0 = z0;
583  nf->dx1 = x1;
584  nf->dy1 = y1;
585  nf->dz1 = z1;
586  nf->col = *col;
587  nf->width = width;
588  nf->next = NULL;
589
590  figure_list_add_tail(e, nf);
591}
592
593void ezx_str_3d(ezx_t *e, double x0, double y0, double z0, char *str,
594                const ezx_color_t *col)
595{
596  ezx_figures *nf = xcalloc(1, sizeof(ezx_figures));
597
598  nf->type = FSTR3D;
599  nf->dx0 = x0;
600  nf->dy0 = y0;
601  nf->dz0 = z0;
602  nf->str = xcalloc(strlen(str) + 1, sizeof(char));
603  strcpy(nf->str, str);
604  nf->col = *col;
605  nf->next = NULL;
606
607  figure_list_add_tail(e, nf);
608}
609
610void ezx_str_2d(ezx_t *e, int x0, int y0, char *str, const ezx_color_t *col)
611{
612  ezx_figures *nf = xcalloc(1, sizeof(ezx_figures));
613
614  nf->type = FSTR2D;
615  nf->x0 = x0;
616  nf->y0 = y0;
617  nf->str = xcalloc(strlen(str) + 1, sizeof(char));
618  strcpy(nf->str, str);
619  nf->col = *col;
620  nf->width = 0;
621  nf->next = NULL;
622
623  figure_list_add_tail(e, nf);
624}
625
626void ezx_fillrect_2d(ezx_t *e, int x0, int y0, int x1, int y1,
627                     const ezx_color_t *col)
628{
629  ezx_figures *nf = xcalloc(1, sizeof(ezx_figures));
630
631  nf->type = FFILLEDRECT2D;
632  nf->x0 = x0;
633  nf->y0 = y0;
634  nf->x1 = x1;
635  nf->y1 = y1;
636  nf->col = *col;
637  nf->width = 0;
638  nf->next = NULL;
639
640  figure_list_add_tail(e, nf);
641}
642
643void ezx_rect_2d(ezx_t *e, int x0, int y0, int x1, int y1, const ezx_color_t *col,
644                 int width)
645{
646  ezx_figures *nf = xcalloc(1, sizeof(ezx_figures));
647
648  nf->type = FRECT2D;
649  nf->x0 = x0;
650  nf->y0 = y0;
651  nf->x1 = x1;
652  nf->y1 = y1;
653  nf->col = *col;
654  nf->width = width;
655  nf->next = NULL;
656
657  figure_list_add_tail(e, nf);
658}
659
660void ezx_poly_3d(ezx_t *e, ezx_point3d_t *points, double hx, double hy,
661                 double hz, int npoints, const ezx_color_t *col)
662{
663  ezx_figures *nf = xcalloc(1, sizeof(ezx_figures));
664  int i;
665
666  nf->type = FPOLY3D;
667  nf->points_3d = points;
668  nf->npoints = npoints;
669  nf->col = *col;
670  nf->next = NULL;
671  nf->dx0 = hx;
672  nf->dy0 = hy;
673  nf->dz0 = hz;
674
675  nf->dx1 = nf->dy1 = nf->dz1 = 0;
676  for (i = 0; i < npoints; i++) {
677    nf->dx1 += points[i].x;
678    nf->dy1 += points[i].y;
679    nf->dz1 += points[i].z;
680  }
681
682  nf->dx1 /= npoints;
683  nf->dy1 /= npoints;
684  nf->dz1 /= npoints;
685
686  figure_list_add_tail(e, nf);
687}
688
689void ezx_fillcircle_2d(ezx_t *e, int x0, int y0, int r, const ezx_color_t *col)
690{
691  ezx_figures *nf = xcalloc(1, sizeof(ezx_figures));
692
693  nf->type = FFILLEDCIRCLE2D;
694  nf->x0 = x0;
695  nf->y0 = y0;
696  nf->r = r;
697  nf->col = *col;
698  nf->width = 0;
699  nf->next = NULL;
700
701  figure_list_add_tail(e, nf);
702}
703
704void ezx_circle_2d(ezx_t *e, int x0, int y0, int r, const ezx_color_t *col,
705                   int width)
706{
707  ezx_figures *nf = xcalloc(1, sizeof(ezx_figures));
708
709  nf->type = FCIRCLE2D;
710  nf->x0 = x0;
711  nf->y0 = y0;
712  nf->r = r;
713  nf->col = *col;
714  nf->width = width;
715  nf->next = NULL;
716
717  figure_list_add_tail(e, nf);
718}
719
720void ezx_circle_3d(ezx_t *e, double x0, double y0, double z0, double r,
721                   const ezx_color_t *col)
722{
723  ezx_figures *nf = xcalloc(1, sizeof(ezx_figures));
724
725  nf->type = FFILLEDCIRCLE3D;
726  nf->dx0 = x0;
727  nf->dy0 = y0;
728  nf->dz0 = z0;
729  nf->dr = r;
730  nf->col = *col;
731  nf->next = NULL;
732
733  figure_list_add_tail(e, nf);
734}
735
736void ezx_set_background(ezx_t *e, const ezx_color_t *col)
737{
738  e->bgcolor = *col;
739}
740
741static inline COLORREF ecol2rgb(ezx_color_t col)
742{
743  return RGB((BYTE)(col.r * 255), (BYTE)(col.g * 255), (BYTE)(col.b * 255));
744}
745
746void ezx_redraw(ezx_t * e)
747{
748  ezx_figures  *f;
749  ezx_pfigures *p;
750  ezx_pfigures *pf;
751
752  HDC hdc = e->hdcMem;
753  RECT rect;
754
755  EnterCriticalSection(&e->cSect);
756
757  GetClientRect(e->hWnd, &rect);
758  SelectObject(hdc, CreateSolidBrush(ecol2rgb(e->bgcolor)));
759  PatBlt(e->hdcMem, rect.left, rect.top, rect.right, rect.bottom, PATCOPY);
760  DeleteObject(SelectObject(hdc, GetStockObject(NULL_BRUSH)));
761
762  // z-sorting
763  pf = NULL;
764  for (f = e->fig_head[e->cur_layer]; f != NULL; f = f->next) {
765    double z;
766    ezx_pfigures **p;
767
768    if (f->type != FPOLY3D) continue;
769
770    z = getz(e, f->dx1, f->dy1, f->dz1);
771
772    for (p = &pf; *p != NULL; p = &(*p)->next) {
773      ezx_pfigures *np;
774
775      if (z <= (*p)->z) continue;
776
777      np = xmalloc(sizeof(ezx_pfigures));
778      np->z = z;
779      np->fig = f;
780      np->next = *p;
781      *p = np;
782      break;
783    }
784
785    if (*p == NULL) {
786      ezx_pfigures *np = xmalloc(sizeof(ezx_pfigures));
787      np->z = z;
788      np->fig = f;
789      np->next = NULL;
790      *p = np;
791    }
792  }
793
794  for (p = pf; p != NULL; p = p->next) {
795    ezx_figures *f = p->fig;
796    double hx, hy, hz;
797    double cl, br;
798    int i;
799
800    if (f->dx0 != 0 || f->dy0 != 0 || f->dz0 != 0) {
801      hx = f->dx0;
802      hy = f->dy0;
803      hz = f->dz0;
804
805      if (hx * (e->eye_x - f->dx1) +
806          hy * (e->eye_y - f->dy1) +
807          hz * (e->eye_z - f->dz1) < 0) {
808        continue;
809      }
810    } else {
811      for (i = 2;; i++) {
812        double x0 = f->points_3d[1].x - f->points_3d[0].x;
813        double y0 = f->points_3d[1].y - f->points_3d[0].y;
814        double z0 = f->points_3d[1].z - f->points_3d[0].z;
815        double x1 = f->points_3d[i].x - f->points_3d[0].x;
816        double y1 = f->points_3d[i].y - f->points_3d[0].y;
817        double z1 = f->points_3d[i].z - f->points_3d[0].z;
818
819        hx = y0 * z1 - y1 * z0;
820        hy = z0 * x1 - z1 * x0;
821        hz = x0 * y1 - x1 * y0;
822
823        if (hx != 0 || hy != 0 || hz != 0) break;
824      }
825    }
826
827    cl = (e->light_x * f->dx0 + e->light_y * f->dy0 +
828          e->light_z * f->dz0) / sqrt(f->dx0 * f->dx0 +
829                                          f->dy0 * f->dy0 +
830                                          f->dz0 * f->dz0);
831    if (cl < 0) {
832      cl = -cl;
833      f->dx0 = -f->dx0;
834      f->dy0 = -f->dy0;
835      f->dz0 = -f->dz0;
836    }
837    if (f->dx0 * (e->eye_x - f->dx1) +
838        f->dy0 * (e->eye_y - f->dy1) +
839        f->dz0 * (e->eye_z - f->dz1) < 0)
840      cl = 0;
841    br = cl * 0.6 + 0.3;
842
843    POINT *points = xmalloc(sizeof(POINT) * f->npoints);
844    for (i = 0; i < f->npoints; i++) {
845      double sx0, sy0;
846      ezx_c3d_to_2d(e, f->points_3d[i].x, f->points_3d[i].y,
847                    f->points_3d[i].z, &sx0, &sy0);
848      points[i].x = (int)sx0 + (e->size_x / 2);
849      points[i].y = (int)sy0 + (e->size_y / 2);
850    }
851
852    SelectObject(hdc, CreateSolidBrush(ecol2rgb(f->col)));
853    Polygon(hdc, points, f->npoints);
854    DeleteObject(SelectObject(hdc, GetStockObject(NULL_BRUSH)));
855
856    free(points);
857  }
858
859  {
860    ezx_pfigures *np, *p;
861    for (p = pf; p != NULL; p = np) {
862      np = p->next;
863      free(p);
864    }
865
866    pf = NULL;
867  }
868
869  {
870    ezx_figures *f;
871    int i;
872
873    for (i = 0; i < EZX_NLAYER; i++) {
874      for (f = e->fig_head[i]; f != NULL; f = f->next) {
875        switch (f->type) {
876        case FPOINT2D:
877          SetPixel(hdc, f->x0, f->y0, ecol2rgb(f->col));
878          break;
879        case FLINE2D:
880          if (f->width <= 0) break;
881          SelectObject(hdc, CreatePen(PS_SOLID, f->width, ecol2rgb(f->col)));
882          MoveToEx(hdc, f->x0, f->y0, NULL);
883          LineTo(hdc, f->x1, f->y1);
884          DeleteObject(SelectObject(hdc, GetStockObject(NULL_PEN)));
885          break;
886        case FLINES2D:
887          {
888            int j;
889            if (f->width <= 0) break;
890            POINT *points = xmalloc(sizeof(POINT) * f->npoints);
891            for (j = 0; j < f->npoints; j++) {
892              points[j].x = f->points_2d[j].x;
893              points[j].y = f->points_2d[j].y;
894            }
895            SelectObject(hdc, CreatePen(PS_SOLID, f->width, ecol2rgb(f->col)));
896            Polyline(hdc, points, f->npoints);
897            DeleteObject(SelectObject(hdc, GetStockObject(NULL_PEN)));
898            free(points);
899          }
900          break;
901        case FPOLY2D:
902          {
903            int j;
904            POINT *points = xmalloc(sizeof(POINT) * f->npoints);
905            for (j = 0; j < f->npoints; j++) {
906              points[j].x = f->points_2d[j].x;
907              points[j].y = f->points_2d[j].y;
908            }
909            SelectObject(hdc, CreateSolidBrush(ecol2rgb(f->col)));
910            Polygon(hdc, points, f->npoints);
911            DeleteObject(SelectObject(hdc, GetStockObject(NULL_BRUSH)));
912            free(points);
913          }
914          break;
915        case FLINE3D:
916          {
917            if (f->width <= 0) break;
918            double sx0, sy0, sx1, sy1;
919            int x0, y0, x1, y1;
920            ezx_c3d_to_2d(e, f->dx0, f->dy0, f->dz0, &sx0, &sy0);
921            ezx_c3d_to_2d(e, f->dx1, f->dy1, f->dz1, &sx1, &sy1);
922            x0 = (int)sx0 + (e->size_x / 2);
923            y0 = (int)sy0 + (e->size_y / 2);
924            x1 = (int)sx1 + (e->size_x / 2);
925            y1 = (int)sy1 + (e->size_y / 2);
926            clip_line(&x0, &y0, &x1, &y1, e->size_x, e->size_y);
927            SelectObject(hdc, CreatePen(PS_SOLID, f->width, ecol2rgb(f->col)));
928            MoveToEx(hdc, x0, y0, NULL);
929            LineTo(hdc, x1, y1);
930            DeleteObject(SelectObject(hdc, GetStockObject(NULL_PEN)));
931          }
932          break;
933        case FCIRCLE2D:
934          if (f->width <= 0) break;
935          SelectObject(hdc, CreatePen(PS_SOLID, f->width, ecol2rgb(f->col)));
936          Ellipse(hdc, f->x0 - f->r, f->y0 - f->r, f->x0 + f->r, f->y0 + f->r);
937          DeleteObject(SelectObject(hdc, GetStockObject(NULL_PEN)));
938          break;
939        case FFILLEDCIRCLE2D:
940          SelectObject(hdc, CreateSolidBrush(ecol2rgb(f->col)));
941          Ellipse(hdc, f->x0 - f->r + 1, f->y0 - f->r + 1, f->x0 + f->r,
942                  f->y0 + f->r);
943          DeleteObject(SelectObject(hdc, GetStockObject(NULL_BRUSH)));
944          break;
945        case FFILLEDCIRCLE3D:
946          {
947            double sx0, sy0;
948            ezx_c3d_to_2d(e, f->dx0, f->dy0, f->dz0, &sx0, &sy0);
949            SelectObject(hdc, CreateSolidBrush(ecol2rgb(f->col)));
950            Ellipse(hdc,
951                    (int)sx0 + (e->size_x / 2) - (int)f->dr + 1,
952                    (int)sy0 + (e->size_y / 2) - (int)f->dr + 1,
953                    (int)sx0 + (e->size_x / 2) + (int)f->dr,
954                    (int)sy0 + (e->size_y / 2) + (int)f->dr);
955            DeleteObject(SelectObject(hdc, GetStockObject(NULL_BRUSH)));
956          }
957          break;
958        case FSTR2D:
959          {
960            TEXTMETRIC tm;
961            GetTextMetrics(hdc, &tm);
962            SetTextColor(hdc, ecol2rgb(f->col));
963            TextOut(hdc, f->x0, f->y0 - tm.tmAscent, f->str, strlen(f->str));
964          }
965          break;
966        case FSTR3D:
967          {
968            double sx0, sy0;
969            TEXTMETRIC tm;
970            ezx_c3d_to_2d(e, f->dx0, f->dy0, f->dz0, &sx0, &sy0);
971            GetTextMetrics(hdc, &tm);
972            SetTextColor(hdc, ecol2rgb(f->col));
973            TextOut(hdc, (int)sx0 + (e->size_x / 2),
974                    (int)sy0 + (e->size_y / 2) - tm.tmAscent,
975                    f->str, strlen(f->str));
976          }
977          break;
978        case FRECT2D:
979          if (f->width <= 0) break;
980          SelectObject(hdc, CreatePen(PS_SOLID, f->width, ecol2rgb(f->col)));
981          Rectangle(hdc, f->x0, f->y0, f->x1 + 1, f->y1 + 1);
982          DeleteObject(SelectObject(hdc, GetStockObject(NULL_PEN)));
983          break;
984        case FFILLEDRECT2D:
985          SelectObject(hdc, CreateSolidBrush(ecol2rgb(f->col)));
986          Rectangle(hdc, f->x0, f->y0, f->x1 + 1, f->y1 + 1);
987          DeleteObject(SelectObject(hdc, GetStockObject(NULL_BRUSH)));
988          break;
989        case FARC2D:
990          {
991            double r0, r1, t0, t1;
992            if (f->width <= 0) break;
993            r0 = f->x1 / 2;
994            r1 = f->y1 / 2;
995            t0 = f->angle1 * M_PI / 180.0;
996            t1 = t0 + f->angle2 * M_PI / 180.0;
997            SelectObject(hdc, CreatePen(PS_SOLID, f->width, ecol2rgb(f->col)));
998            Arc(hdc,
999                (f->x0 - r0), (f->y0 - r1) ,
1000                (f->x0 + r0) + 1, (f->y0 + r1) + 1,
1001                (f->x0 + r0*cos(t0)), (f->y0 - r1*sin(t0)),
1002                (f->x0 + r0*cos(t1)), (f->y0 - r1*sin(t1)));
1003            DeleteObject(SelectObject(hdc, GetStockObject(NULL_PEN)));
1004          }
1005          break;
1006        case FFILLEDARC2D:
1007          {
1008            double r0, r1, t0, t1;
1009            r0 = f->x1 / 2;
1010            r1 = f->y1 / 2;
1011            t0 = f->angle1 * M_PI / 180.0;
1012            t1 = t0 + f->angle2 * M_PI / 180.0;
1013            SelectObject(hdc, CreateSolidBrush(ecol2rgb(f->col)));
1014            Pie(hdc,
1015                (f->x0 - r0), (f->y0 - r1),
1016                (f->x0 + r0) + 2, (f->y0 + r1) + 2,
1017                (f->x0 + r0*cos(t0)), (f->y0 - r1*sin(t0)),
1018                (f->x0 + r0*cos(t1)), (f->y0 - r1*sin(t1)));
1019            DeleteObject(SelectObject(hdc, GetStockObject(NULL_BRUSH)));
1020          }
1021          break;
1022        case FPOLY3D:
1023          break;
1024        }
1025      }
1026    }
1027  }
1028
1029  InvalidateRect(e->hWnd, NULL, FALSE);
1030
1031  LeaveCriticalSection(&e->cSect);
1032
1033  Sleep(0);
1034}
1035
1036static inline unsigned int get_state_mask(WPARAM wParam)
1037{
1038  unsigned int state = 0;
1039
1040  if (wParam & MK_SHIFT) state |= EZX_SHIFT_MASK;
1041  if (wParam & MK_CONTROL) state |= EZX_CONTROL_MASK;
1042  if (wParam & MK_LBUTTON) state |= EZX_BUTTON_LMASK;
1043  if (wParam & MK_MBUTTON) state |= EZX_BUTTON_MMASK;
1044  if (wParam & MK_RBUTTON) state |= EZX_BUTTON_RMASK;
1045
1046  return state;
1047}
1048
1049static inline unsigned int get_current_state_mask()
1050{
1051  unsigned int state = 0;
1052 
1053  if (GetAsyncKeyState(VK_SHIFT) < 0) state |= EZX_SHIFT_MASK;
1054  if (GetAsyncKeyState(VK_CONTROL) < 0) state |= EZX_CONTROL_MASK;
1055  if (GetAsyncKeyState(VK_LBUTTON) < 0) state |= EZX_BUTTON_LMASK;
1056  if (GetAsyncKeyState(VK_MBUTTON) < 0) state |= EZX_BUTTON_MMASK;
1057  if (GetAsyncKeyState(VK_RBUTTON) < 0) state |= EZX_BUTTON_RMASK;
1058
1059  return state;
1060}
1061
1062static inline unsigned int get_message_state_mask()
1063{
1064  unsigned int state = 0;
1065 
1066  if (GetKeyState(VK_SHIFT) < 0) state |= EZX_SHIFT_MASK;
1067  if (GetKeyState(VK_CONTROL) < 0) state |= EZX_CONTROL_MASK;
1068  if (GetKeyState(VK_LBUTTON) < 0) state |= EZX_BUTTON_LMASK;
1069  if (GetKeyState(VK_MBUTTON) < 0) state |= EZX_BUTTON_MMASK;
1070  if (GetKeyState(VK_RBUTTON) < 0) state |= EZX_BUTTON_RMASK;
1071
1072  return state;
1073}
1074
1075static inline unsigned int get_key_code(WPARAM wParam, LPARAM lParam)
1076{
1077  unsigned int k = 0;
1078  static BYTE chars[2], keystate[256];
1079
1080  if (wParam == VK_HOME) return EZX_KEY_HOME;
1081  else if (wParam == VK_LEFT) return EZX_KEY_LEFT;
1082  else if (wParam == VK_RIGHT) return EZX_KEY_RIGHT;
1083  else if (wParam == VK_UP) return EZX_KEY_UP;
1084  else if (wParam == VK_DOWN) return EZX_KEY_DOWN;
1085  else {
1086    lParam &= 0x7fffffff;
1087    GetKeyboardState(keystate);
1088    if (ToAscii(wParam, HIWORD(lParam), keystate, (WORD *)chars, 0) == 1)
1089      k = chars[0];
1090  }
1091 
1092  return k;
1093}
1094
1095LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
1096{
1097  ezx_t *e = (ezx_t *)GetWindowLong(hWnd, GWL_USERDATA);
1098
1099  switch (message) {
1100  case WM_PAINT:
1101    {
1102      HDC hdc;
1103      PAINTSTRUCT ps;
1104      EnterCriticalSection(&e->cSect);
1105      hdc = BeginPaint(hWnd, &ps);
1106      if (!BitBlt(hdc, 0, 0, e->size_x, e->size_y, e->hdcMem, 0, 0, SRCCOPY))
1107        win32_error_exit("WndProc: BitBlt failed");
1108      EndPaint(hWnd, &ps);
1109      LeaveCriticalSection(&e->cSect);
1110    }
1111    return 0;
1112  case WM_LBUTTONUP:
1113  case WM_MBUTTONUP:
1114  case WM_RBUTTONUP:
1115  case WM_LBUTTONDOWN:
1116  case WM_MBUTTONDOWN:
1117  case WM_RBUTTONDOWN:
1118  case WM_MOUSEWHEEL:
1119    {
1120      ezx_event_t *event = xmalloc(sizeof(ezx_event_t));
1121      if (message == WM_LBUTTONDOWN || message == WM_LBUTTONUP)
1122        event->button.b = EZX_BUTTON_LEFT;
1123      else if (message == WM_RBUTTONDOWN || message == WM_RBUTTONUP)
1124        event->button.b = EZX_BUTTON_RIGHT;
1125      else if (message == WM_MBUTTONDOWN || message == WM_MBUTTONUP)
1126        event->button.b = EZX_BUTTON_MIDDLE;
1127      else {
1128        if ((short)HIWORD(wParam) >= 0) event->button.b = EZX_BUTTON_WHEELUP;
1129        else event->button.b = EZX_BUTTON_WHEELDOWN;
1130      }
1131      event->button.x = LOWORD(lParam);
1132      event->button.y = HIWORD(lParam);
1133      event->button.state = get_state_mask(wParam);
1134      if (message == WM_LBUTTONUP || message == WM_RBUTTONUP ||
1135          message == WM_MBUTTONUP) {
1136        ReleaseCapture();
1137        event->button.type = EZX_BUTTON_RELEASE;
1138        event_queue_offer(e->event_queue, QID_OTHERS, event);
1139      } else {
1140        SetCapture(e->hWnd);
1141        event->button.type = EZX_BUTTON_PRESS;
1142        event_queue_offer(e->event_queue, QID_BUTTON_PRESS, event);
1143      }
1144    }
1145    return 0;
1146  case WM_KEYDOWN:
1147  case WM_KEYUP:
1148    {
1149      unsigned int k = get_key_code(wParam, lParam);
1150      if (k) {
1151        ezx_event_t *event = xmalloc(sizeof(ezx_event_t));
1152        DWORD pos = GetMessagePos();
1153        if (message == WM_KEYDOWN) event->key.type = EZX_KEY_PRESS;
1154        else event->key.type = EZX_KEY_RELEASE;
1155        event->key.k = k;
1156        event->key.x = GET_X_LPARAM(pos);
1157        event->key.y = GET_Y_LPARAM(pos);
1158        event->key.state = get_message_state_mask();
1159        event_queue_offer(e->event_queue, QID_OTHERS, event);
1160      }
1161    }
1162    return 0;
1163  case WM_MOUSEMOVE:
1164    if (wParam & MK_LBUTTON || wParam & MK_RBUTTON || wParam & MK_MBUTTON) {
1165      ezx_event_t *event = xmalloc(sizeof(ezx_event_t));
1166      event->motion.type = EZX_MOTION_NOTIFY;
1167      event->motion.x = LOWORD(lParam);
1168      event->motion.y = HIWORD(lParam);
1169      event->motion.state = get_state_mask(wParam);
1170      event_queue_offer(e->event_queue, QID_OTHERS, event);
1171    }
1172    return 0;
1173  case WM_CLOSE:
1174    {
1175      int quit;
1176      ezx_event_t *event = xmalloc(sizeof(ezx_event_t));
1177      event->type = EZX_CLOSE;
1178      event_queue_offer(e->event_queue, QID_OTHERS, event);
1179      EnterCriticalSection(&e->cSect);
1180      e->closed = 1;
1181      quit = e->quit;
1182      LeaveCriticalSection(&e->cSect);
1183      if (quit) return  DefWindowProc(hWnd, message, wParam, lParam);
1184      else return 0;
1185    }
1186  case WM_DESTROY:
1187    PostQuitMessage(0);
1188    return 0;
1189  default:
1190    return DefWindowProc(hWnd, message, wParam, lParam);
1191  }
1192}
1193
1194static unsigned __stdcall window_thread(void *arg)
1195{
1196  ezx_t *e = (ezx_t *)arg;
1197  RECT rect;
1198  HDC hdc;
1199  MSG msg;
1200  BOOL bRet;
1201 
1202  rect.left = 0;
1203  rect.top = 0;
1204  rect.right = e->size_x-1;
1205  rect.bottom = e->size_y-1;
1206  AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE);
1207 
1208  e->hWnd = CreateWindow(class_name,
1209                         e->window_name,
1210                         WS_OVERLAPPEDWINDOW & ~WS_THICKFRAME & ~WS_MAXIMIZEBOX,
1211                         CW_USEDEFAULT,
1212                         CW_USEDEFAULT,
1213                         rect.right - rect.left,
1214                         rect.bottom - rect.top,
1215                         NULL, NULL, GetModuleHandle(NULL), NULL);
1216  if (!e->hWnd) win32_error_exit("window_thread: CreateWindow failed");
1217
1218  SetWindowLong(e->hWnd, GWL_USERDATA, (long)e);
1219 
1220  hdc = GetDC(e->hWnd);
1221  e->hBitmap = CreateCompatibleBitmap(hdc, e->size_x, e->size_y);
1222  e->hdcMem = CreateCompatibleDC(hdc);
1223  SelectObject(e->hdcMem, e->hBitmap);
1224  ReleaseDC(e->hWnd, hdc);
1225
1226  SetBkMode(e->hdcMem, TRANSPARENT);
1227
1228  SelectObject(e->hdcMem, GetStockObject(NULL_PEN));
1229  SelectObject(e->hdcMem, GetStockObject(NULL_BRUSH));
1230
1231  e->hFont = CreateFont(12, 0, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
1232                        DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
1233                        CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
1234                        FIXED_PITCH | FF_MODERN, NULL);
1235  SelectObject(e->hdcMem, e->hFont);
1236 
1237  ShowWindow(e->hWnd, SW_SHOWNORMAL);
1238  UpdateWindow(e->hWnd);
1239
1240  if (!SetEvent(e->hWindowCreation)) 
1241    win32_error_exit("window_thread: SetEvent failed");
1242
1243  while ((bRet = GetMessage(&msg, NULL, 0, 0)) != 0) {
1244    if (bRet == -1) win32_error_exit("window_thread: GetMessage failed");
1245    else {
1246      //TranslateMessage(&msg);
1247      DispatchMessage(&msg);
1248    }
1249  }
1250
1251  return 0;
1252}
1253
1254static void register_window_class()
1255{
1256  static int first = 1;
1257
1258  if (first) {
1259    WNDCLASSEX wcex;
1260   
1261    wcex.cbSize = sizeof(WNDCLASSEX);
1262    wcex.style = CS_HREDRAW | CS_VREDRAW;
1263    wcex.lpfnWndProc = (WNDPROC)WndProc;
1264    wcex.cbClsExtra = 0;
1265    wcex.cbWndExtra = 0;
1266    wcex.hInstance = GetModuleHandle(NULL);
1267    wcex.hIcon = LoadIcon(NULL, IDI_APPLICATION);
1268    wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
1269    wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
1270    wcex.lpszMenuName = NULL;
1271    wcex.lpszClassName = class_name;
1272    wcex.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
1273   
1274    RegisterClassEx(&wcex);
1275
1276    first = 0;
1277  }
1278}
1279
1280void ezx_window_name(ezx_t * e, char *window_name)
1281{
1282  e->window_name = window_name;
1283  SetWindowText(e->hWnd, e->window_name);
1284}
1285
1286int ezx_isclosed(ezx_t * e)
1287{
1288  int b;
1289 
1290  EnterCriticalSection(&e->cSect);
1291  b = e->closed;
1292  LeaveCriticalSection(&e->cSect);
1293
1294  return b;
1295}
1296
1297void ezx_quit(ezx_t * e)
1298{
1299  ezx_wipe(e);
1300
1301  EnterCriticalSection(&e->cSect);
1302  e->quit = 1;
1303  LeaveCriticalSection(&e->cSect);
1304
1305  SendMessage(e->hWnd, WM_CLOSE, 0, 0);
1306  if (WaitForSingleObject(e->hThread, INFINITE) != WAIT_OBJECT_0)
1307    win32_error_exit("ezx_quit: WaitForSingleObject failed");
1308
1309  event_queue_free(e->event_queue);
1310 
1311  DeleteDC(e->hdcMem);
1312  DeleteObject(e->hFont);
1313  DeleteObject(e->hBitmap);
1314  CloseHandle(e->hWindowCreation);
1315  CloseHandle(e->hThread);
1316  DeleteCriticalSection(&e->cSect);
1317  free(e);
1318}
1319
1320void ezx_resize(ezx_t *e, int size_x, int size_y)
1321{
1322  e->size_x = size_x;
1323  e->size_y = size_y; 
1324  SetWindowPos(e->hWnd, NULL, 0, 0, size_x, size_y, SWP_NOMOVE | SWP_NOZORDER);
1325}
1326
1327ezx_t *ezx_init(int size_x, int size_y, char *window_name)
1328{
1329  ezx_t *e;
1330  unsigned tid;
1331
1332  e = xcalloc(1, sizeof(ezx_t));
1333  e->size_x = size_x;
1334  e->size_y = size_y;
1335  e->cur_layer = 0;
1336  e->bgcolor = ezx_white;
1337  e->scrdist = 100;
1338  e->mag = 20;
1339  e->closed = 0;
1340  e->window_name = window_name;
1341  e->event_queue = event_queue_new();
1342  e->hWindowCreation = CreateEvent(NULL, FALSE, FALSE, NULL);
1343  InitializeCriticalSection(&e->cSect);
1344
1345  ezx_set_view_3d(e, 1000, 0, 0, 0, 0, 0, 5);
1346  ezx_set_light_3d(e, 1000, 900, 800);
1347
1348  register_window_class();
1349
1350  e->hThread = (HANDLE)_beginthreadex(NULL, 0, window_thread, e, 0, &tid);
1351  if (!e->hThread) sys_error_exit("ezx_init: _beginthreadex failed");
1352
1353  SetThreadPriority(e->hThread, THREAD_PRIORITY_ABOVE_NORMAL);
1354
1355  if (WaitForSingleObject(e->hWindowCreation, INFINITE) != WAIT_OBJECT_0)
1356    win32_error_exit("ezx_init: WaitForSingleObject failed");
1357
1358  ezx_redraw(e);
1359
1360  return e;
1361}
1362
1363int ezx_sensebutton(ezx_t *e, int *x, int *y)
1364{
1365  POINT pos;
1366  unsigned int s;
1367
1368  GetCursorPos(&pos);
1369  s = get_current_state_mask();
1370  ScreenToClient(e->hWnd, &pos);
1371  if (x != NULL) *x = pos.x;
1372  if (y != NULL) *y = pos.y;
1373
1374  return s;
1375}
1376
1377int ezx_pushbutton(ezx_t *e, int *x, int *y)
1378{
1379  ezx_event_t *event = event_queue_remove(e->event_queue, QID_BUTTON_PRESS);
1380  int b = event->button.b;
1381
1382  if (x != NULL) *x = event->button.x;
1383  if (y != NULL) *y = event->button.y;
1384
1385  free(event);
1386
1387  return b;
1388}
1389
1390void ezx_next_event(ezx_t *e, ezx_event_t *ezx_event)
1391{
1392  ezx_event_t *event = event_queue_remove_oldest(e->event_queue);
1393
1394  if (ezx_event) *ezx_event = *event;
1395 
1396  free(event);
1397}
Note: See TracBrowser for help on using the repository browser.